Skip to content

Commit 57b53e7

Browse files
committed
more progress
1 parent 2fc417f commit 57b53e7

File tree

8 files changed

+331
-64
lines changed

8 files changed

+331
-64
lines changed

src/bin/migrate.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ fn migrations() -> Vec<Migration> {
463463
"ALTER TABLE crate_owners RENAME user_id TO owner_id",
464464
"ALTER TABLE crate_owners RENAME owner_id TO user_id",
465465
),
466+
undo_foreign_key(20150804170130, "crate_owners", "user_id", "users (id)"),
466467
];
467468
// NOTE: Generate a new id via `date +"%Y%m%d%H%M%S"`
468469

@@ -484,6 +485,16 @@ fn migrations() -> Vec<Migration> {
484485
Migration::run(id, &add, &rm)
485486
}
486487

488+
fn undo_foreign_key(id: i64, table: &str, column: &str,
489+
references: &str) -> Migration {
490+
let add = format!("ALTER TABLE {table} ADD CONSTRAINT fk_{table}_{col}
491+
FOREIGN KEY ({col}) REFERENCES {reference}",
492+
table = table, col = column, reference = references);
493+
let rm = format!("ALTER TABLE {table} DROP CONSTRAINT fk_{table}_{col}",
494+
table = table, col = column);
495+
Migration::run(id, &rm, &add)
496+
}
497+
487498
fn index(id: i64, table: &str, column: &str) -> Migration {
488499
let add = format!("CREATE INDEX index_{table}_{column}
489500
ON {table} ({column})",

src/http.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use curl;
2+
use oauth2::*;
3+
4+
pub fn github(url: &str, auth: &Token)
5+
-> Result<curl::http::Response, curl::ErrCode> {
6+
curl::http::handle()
7+
.get(url)
8+
.header("Accept", "application/vnd.github.v3+json")
9+
.header("User-Agent", "hello!")
10+
.auth_with(auth)
11+
.exec()
12+
}
13+
14+
pub fn token(token: String) -> Token {
15+
Token {
16+
access_token: token,
17+
scopes: Vec::new(),
18+
token_type: String::new(),
19+
}
20+
}

src/krate.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl Crate {
178178
(crate_id, owner_id, created_by, created_at,
179179
updated_at, deleted, owner_kind)
180180
VALUES ($1, $2, $2, $3, $3, FALSE, $4)",
181-
&[&ret.id, &user_id, &now, &(OwnerKind::User as u32)]));
181+
&[&ret.id, &user_id, &now, &(OwnerKind::User as i32)]));
182182
return Ok(ret);
183183

184184
fn validate_url(url: Option<&str>, field: &str) -> CargoResult<()> {
@@ -299,15 +299,15 @@ impl Crate {
299299
WHERE crate_owners.crate_id = $1
300300
AND crate_owners.deleted = FALSE
301301
AND crate_owners.owner_kind = $2"));
302-
let user_rows = try!(stmt.query(&[&self.id, &(OwnerKind::User as u32)]));
302+
let user_rows = try!(stmt.query(&[&self.id, &(OwnerKind::User as i32)]));
303303

304304
let stmt = try!(conn.prepare("SELECT * FROM teams
305305
INNER JOIN crate_owners
306306
ON crate_owners.owner_id = teams.id
307307
WHERE crate_owners.crate_id = $1
308308
AND crate_owners.deleted = FALSE
309309
AND crate_owners.owner_kind = $2"));
310-
let team_rows = try!(stmt.query(&[&self.id, &(OwnerKind::Team as u32)]));
310+
let team_rows = try!(stmt.query(&[&self.id, &(OwnerKind::Team as i32)]));
311311

312312
let mut owners = vec![];
313313
owners.extend(user_rows.iter().map(|r| Owner::User(Model::from_row(&r))));

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub mod user;
5757
pub mod owner;
5858
pub mod util;
5959
pub mod version;
60+
pub mod http;
6061
mod licenses;
6162

6263
#[derive(PartialEq, Eq, Clone, Copy)]

src/owner.rs

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
use {Model, User};
22
use util::{RequestUtils, CargoResult, internal, ChainError, human};
33
use db::Connection;
4-
use curl;
54
use pg::rows::Row;
65
use rustc_serialize::json;
76
use util::errors::NotFound;
87
use std::str;
9-
10-
pub fn json_http(url: &str, auth_token: &str)
11-
-> Result<curl::http::Response, curl::ErrCode> {
12-
curl::http::handle()
13-
.get(url)
14-
.header("Accept", "application/vnd.github.v3+json")
15-
.header("User-Agent", "hello!")
16-
.header("Authorization", &format!("token {}", auth_token))
17-
.exec()
18-
}
8+
use http;
199

2010
#[repr(u32)]
2111
pub enum OwnerKind {
@@ -45,6 +35,7 @@ pub struct Team {
4535
#[derive(RustcDecodable, RustcEncodable)]
4636
pub struct EncodableOwner {
4737
pub id: i32,
38+
// TODO: duplicate this field with better name
4839
pub login: String,
4940
pub kind: String,
5041
pub email: Option<String>,
@@ -114,8 +105,9 @@ impl Team {
114105
c)));
115106
}
116107

117-
let resp = try!(json_http(&format!("https://api.github.com/orgs/{}/teams", org_name),
118-
&req_user.gh_access_token));
108+
let resp = try!(http::github(
109+
&format!("https://api.github.com/orgs/{}/teams", org_name),
110+
&http::token(req_user.gh_access_token.clone())));
119111

120112
match resp.get_code() {
121113
200 => {} // Ok!
@@ -159,9 +151,7 @@ impl Team {
159151
human(format!("could not find the github team {}/{}", org_name, team_name))
160152
}));
161153

162-
// mock Team (only need github_id to check team status)
163-
let team = Team { github_id: github_id, id: 0, name: String::new() };
164-
if !try!(team.contains_user(req_user)) {
154+
if !try!(team_with_gh_id_contains_user(github_id, req_user)) {
165155
return Err(human("only members of a team can add it as an owner"));
166156
}
167157

@@ -185,48 +175,52 @@ impl Team {
185175
/// the answer. If this is not the case, then we could accidentally leak
186176
/// private membership information here.
187177
pub fn contains_user(&self, user: &User) -> CargoResult<bool> {
188-
// GET teams/:team_id/memberships/:user_name
189-
// check that "state": "active"
178+
team_with_gh_id_contains_user(self.github_id, user)
179+
}
180+
}
190181

191-
let resp = try!(json_http(&format!("https://api.github.com/teams/{}/memberships/{}",
192-
self.github_id, &user.gh_login),
193-
&user.gh_access_token));
182+
fn team_with_gh_id_contains_user(github_id: i32, user: &User) -> CargoResult<bool> {
183+
// GET teams/:team_id/memberships/:user_name
184+
// check that "state": "active"
194185

195-
match resp.get_code() {
196-
200 => {} // Ok!
197-
404 => {
198-
// Yes, this is actually how "no membership" is signaled
199-
return Ok(false);
200-
}
201-
403 => {
202-
return Err(human("It looks like you don't have permission \
203-
to query an organization that owns this \
204-
crate. You may need to re-authenticate on \
205-
crates.io to grant permission to read \
206-
github org memberships. Just go to \
207-
https://crates.io/login"));
208-
}
209-
_ => {
210-
return Err(internal(format!("didn't get a 200 result from github: {}",
211-
resp)))
212-
}
213-
}
186+
let resp = try!(http::github(
187+
&format!("https://api.github.com/teams/{}/memberships/{}", &github_id, &user.gh_login),
188+
&http::token(user.gh_access_token.clone())));
214189

215-
#[derive(RustcDecodable)]
216-
struct Membership {
217-
state: String,
190+
match resp.get_code() {
191+
200 => {} // Ok!
192+
404 => {
193+
// Yes, this is actually how "no membership" is signaled
194+
return Ok(false);
218195
}
219-
let json = try!(str::from_utf8(resp.get_body()).ok().chain_error(||{
220-
internal("github didn't send a utf8-response")
221-
}));
222-
let membership: Membership = try!(json::decode(json).chain_error(|| {
223-
internal("github didn't send a valid json response")
224-
}));
196+
403 => {
197+
return Err(human("It looks like you don't have permission \
198+
to query an organization that owns this \
199+
crate. You may need to re-authenticate on \
200+
crates.io to grant permission to read \
201+
github org memberships. Just go to \
202+
https://crates.io/login"));
203+
}
204+
_ => {
205+
return Err(internal(format!("didn't get a 200 result from github: {}",
206+
resp)))
207+
}
208+
}
225209

226-
// There is also `state: pending` for which we could possibly give
227-
// some feedback, but it's not obvious how that should work.
228-
Ok(membership.state == "active")
210+
#[derive(RustcDecodable)]
211+
struct Membership {
212+
state: String,
229213
}
214+
let json = try!(str::from_utf8(resp.get_body()).ok().chain_error(||{
215+
internal("github didn't send a utf8-response")
216+
}));
217+
let membership: Membership = try!(json::decode(json).chain_error(|| {
218+
internal("github didn't send a valid json response")
219+
}));
220+
221+
// There is also `state: pending` for which we could possibly give
222+
// some feedback, but it's not obvious how that should work.
223+
Ok(membership.state == "active")
230224
}
231225

232226
impl Model for Team {
@@ -293,8 +287,8 @@ impl Owner {
293287

294288
pub fn kind(&self) -> i32 {
295289
match *self {
296-
Owner::User(_) => 0,
297-
Owner::Team(_) => 1,
290+
Owner::User(_) => OwnerKind::User as i32,
291+
Owner::Team(_) => OwnerKind::Team as i32,
298292
}
299293
}
300294

src/tests/all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod user;
6464
mod record;
6565
mod git;
6666
mod version;
67+
mod team;
6768

6869
fn app() -> (record::Bomb, Arc<App>, conduit_middleware::MiddlewareBuilder) {
6970
struct NoCommit;

0 commit comments

Comments
 (0)