-
Notifications
You must be signed in to change notification settings - Fork 641
/
Copy pathowner.rs
130 lines (117 loc) · 3.88 KB
/
owner.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use diesel::pg::Pg;
use diesel::prelude::*;
use crate::util::errors::{cargo_err, AppResult};
use crate::{app::App, schema::teams};
use crate::models::{Crate, Team, User};
use crate::schema::{crate_owners, users};
use crate::sql::lower;
#[derive(Insertable, Associations, Identifiable, Debug, Clone, Copy)]
#[diesel(
table_name = crate_owners,
check_for_backend(diesel::pg::Pg),
primary_key(crate_id, owner_id, owner_kind),
belongs_to(Crate),
belongs_to(User, foreign_key = owner_id),
belongs_to(Team, foreign_key = owner_id),
)]
pub struct CrateOwner {
pub crate_id: i32,
pub owner_id: i32,
pub created_by: i32,
pub owner_kind: i32,
pub email_notifications: bool,
}
type BoxedQuery<'a> = crate_owners::BoxedQuery<'a, Pg, crate_owners::SqlType>;
impl CrateOwner {
/// Returns a base crate owner query filtered by the owner kind argument. This query also
/// filters out deleted records.
pub fn by_owner_kind(kind: OwnerKind) -> BoxedQuery<'static> {
use self::crate_owners::dsl::*;
crate_owners
.filter(deleted.eq(false))
.filter(owner_kind.eq(kind as i32))
.into_boxed()
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum OwnerKind {
User = 0,
Team = 1,
}
/// Unifies the notion of a User or a Team.
#[derive(Debug)]
pub enum Owner {
User(User),
Team(Team),
}
impl Owner {
/// Finds the owner by name. Always recreates teams to get the most
/// up-to-date GitHub ID. Fails out if the user isn't found in the
/// database, the team isn't found on GitHub, or if the user isn't a member
/// of the team on GitHub.
///
/// May be a user's GH login or a full team name. This is case
/// sensitive.
pub fn find_or_create_by_login(
app: &App,
conn: &mut PgConnection,
req_user: &User,
name: &str,
) -> AppResult<Owner> {
if name.contains(':') {
Ok(Owner::Team(Team::create_or_update(
app, conn, name, req_user,
)?))
} else {
users::table
.filter(lower(users::gh_login).eq(name.to_lowercase()))
.filter(users::gh_id.ne(-1))
.order(users::gh_id.desc())
.first(conn)
.map(Owner::User)
.map_err(|_| cargo_err(&format_args!("could not find user with login `{name}`")))
}
}
/// Finds the owner by name. Never recreates a team, to ensure that
/// organizations that were deleted after they were added can still be
/// removed.
///
/// May be a user's GH login or a full team name. This is case
/// sensitive.
pub fn find_by_login(conn: &mut PgConnection, name: &str) -> AppResult<Owner> {
if name.contains(':') {
teams::table
.filter(lower(teams::login).eq(&name.to_lowercase()))
.first(conn)
.map(Owner::Team)
.map_err(|_| cargo_err(&format_args!("could not find team with login `{name}`")))
} else {
users::table
.filter(lower(users::gh_login).eq(name.to_lowercase()))
.filter(users::gh_id.ne(-1))
.order(users::gh_id.desc())
.first(conn)
.map(Owner::User)
.map_err(|_| cargo_err(&format_args!("could not find user with login `{name}`")))
}
}
pub fn kind(&self) -> i32 {
match *self {
Owner::User(_) => OwnerKind::User as i32,
Owner::Team(_) => OwnerKind::Team as i32,
}
}
pub fn login(&self) -> &str {
match *self {
Owner::User(ref user) => &user.gh_login,
Owner::Team(ref team) => &team.login,
}
}
pub fn id(&self) -> i32 {
match *self {
Owner::User(ref user) => user.id,
Owner::Team(ref team) => team.id,
}
}
}