Skip to content

Commit 9b5cfce

Browse files
committed
(sudo) add data endpoint and transfer groups
1 parent 02e6fd2 commit 9b5cfce

File tree

12 files changed

+389
-8
lines changed

12 files changed

+389
-8
lines changed

src/api/sudo.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ struct LimitOffsetQuery {
4141
s: i64,
4242
}
4343

44+
#[derive(Deserialize)]
45+
pub struct TransferMemberShip {
46+
group_name: String,
47+
old_user_uuid: Uuid,
48+
new_user_uuid: Uuid,
49+
}
50+
4451
fn default_groups_list_size() -> i64 {
4552
20
4653
}
@@ -288,8 +295,44 @@ async fn delete_user(
288295
.map_err(Into::into)
289296
}
290297

298+
#[guard(Staff, Admin, Medium)]
299+
async fn transfer_membership<T: AsyncCisClientTrait>(
300+
pool: web::Data<Pool>,
301+
transfer: web::Json<TransferMemberShip>,
302+
scope_and_user: ScopeAndUser,
303+
cis_client: web::Data<T>,
304+
) -> Result<HttpResponse, ApiError> {
305+
operations::members::transfer(
306+
&pool,
307+
&scope_and_user,
308+
&transfer.group_name,
309+
&User {
310+
user_uuid: transfer.old_user_uuid,
311+
},
312+
&User {
313+
user_uuid: transfer.new_user_uuid,
314+
},
315+
Arc::clone(&*cis_client),
316+
)
317+
.await
318+
.map(|_| HttpResponse::Ok().json(""))
319+
.map_err(Into::into)
320+
}
321+
322+
#[guard(Staff, Admin, Medium)]
323+
async fn raw_data(
324+
pool: web::Data<Pool>,
325+
scope_and_user: ScopeAndUser,
326+
user_uuid: web::Path<Uuid>,
327+
) -> Result<HttpResponse, ApiError> {
328+
operations::raws::raw_user_data(&pool, &scope_and_user, Some(user_uuid.into_inner()))
329+
.map(|data| HttpResponse::Ok().json(data))
330+
.map_err(Into::into)
331+
}
332+
291333
pub fn sudo_app<T: AsyncCisClientTrait + 'static>() -> impl HttpServiceFactory {
292334
web::scope("/sudo")
335+
.service(web::resource("/transfer").route(web::post().to(transfer_membership::<T>)))
293336
.service(web::resource("/groups/reserve/{group_name}").route(web::post().to(reserve_group)))
294337
.service(
295338
web::resource("/groups/inactive/{group_name}")
@@ -304,6 +347,7 @@ pub fn sudo_app<T: AsyncCisClientTrait + 'static>() -> impl HttpServiceFactory {
304347
.route(web::delete().to(remove_member::<T>)),
305348
)
306349
.service(web::resource("/member/{group_name}").route(web::post().to(add_member::<T>)))
350+
.service(web::resource("/user/data/{user_uuid}").route(web::get().to(raw_data)))
307351
.service(web::resource("/user/uuids/staff").route(web::get().to(all_staff_uuids)))
308352
.service(web::resource("/user/uuids/members").route(web::get().to(all_member_uuids)))
309353
.service(

src/db/internal/member.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ scoped_members_and_host_for!(users_public, hosts_public, public_scoped_members_a
311311

312312
membership_and_scoped_host_for!(hosts_staff, membership_and_staff_host);
313313
membership_and_scoped_host_for!(hosts_ndaed, membership_and_ndaed_host);
314+
membership_and_scoped_host_for!(hosts_vouched, membership_and_vouched_host);
315+
membership_and_scoped_host_for!(hosts_authenticated, membership_and_authenticated_host);
314316

315317
pub fn add_member_role(
316318
host_uuid: &Uuid,
@@ -430,6 +432,44 @@ pub fn add_to_group(
430432
.map_err(Into::into)
431433
}
432434

435+
pub fn transfer_membership(
436+
connection: &PgConnection,
437+
group_name: &str,
438+
host: &User,
439+
old_member: &User,
440+
new_member: &User,
441+
) -> Result<(), Error> {
442+
let group = internal::group::get_group(connection, group_name)?;
443+
let log_ctx_old = LogContext::with(group.id, host.user_uuid).with_user(old_member.user_uuid);
444+
let log_ctx_new = LogContext::with(group.id, host.user_uuid).with_user(new_member.user_uuid);
445+
diesel::update(
446+
schema::memberships::table.filter(
447+
schema::memberships::group_id
448+
.eq(group.id)
449+
.and(schema::memberships::user_uuid.eq(old_member.user_uuid)),
450+
),
451+
)
452+
.set(schema::memberships::user_uuid.eq(new_member.user_uuid))
453+
.execute(connection)
454+
.map(|_| {
455+
internal::log::db_log(
456+
connection,
457+
&log_ctx_old,
458+
LogTargetType::Membership,
459+
LogOperationType::Updated,
460+
log_comment_body(&format!("moved to {}", new_member.user_uuid)),
461+
);
462+
internal::log::db_log(
463+
connection,
464+
&log_ctx_new,
465+
LogTargetType::Membership,
466+
LogOperationType::Updated,
467+
log_comment_body(&format!("moved from {}", old_member.user_uuid)),
468+
);
469+
})
470+
.map_err(Into::into)
471+
}
472+
433473
pub fn renew(
434474
host_uuid: &Uuid,
435475
connection: &PgConnection,

src/db/internal/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod group;
44
pub mod invitation;
55
pub mod log;
66
pub mod member;
7+
pub mod raw;
78
pub mod request;
89
pub mod terms;
910
pub mod user;

src/db/internal/raw.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::db::logs::Log;
2+
use crate::db::model::*;
3+
use crate::db::schema;
4+
use crate::db::users::UserProfile;
5+
use crate::db::users::UserProfileValue;
6+
use diesel::prelude::*;
7+
use failure::Error;
8+
use std::convert::TryInto;
9+
use uuid::Uuid;
10+
11+
pub fn raw_memberships_for_user(
12+
connection: &PgConnection,
13+
user_uuid: &Uuid,
14+
) -> Result<Vec<Membership>, Error> {
15+
use schema::memberships as m;
16+
17+
m::table
18+
.filter(m::user_uuid.eq(user_uuid))
19+
.get_results(connection)
20+
.map_err(Into::into)
21+
}
22+
23+
pub fn raw_invitations_for_user(
24+
connection: &PgConnection,
25+
user_uuid: &Uuid,
26+
) -> Result<Vec<Invitation>, Error> {
27+
use schema::invitations as i;
28+
29+
i::table
30+
.filter(i::user_uuid.eq(user_uuid).or(i::added_by.eq(user_uuid)))
31+
.get_results(connection)
32+
.map_err(Into::into)
33+
}
34+
35+
pub fn raw_requests_for_user(
36+
connection: &PgConnection,
37+
user_uuid: &Uuid,
38+
) -> Result<Vec<Request>, Error> {
39+
use schema::requests as r;
40+
41+
r::table
42+
.filter(r::user_uuid.eq(user_uuid))
43+
.get_results(connection)
44+
.map_err(Into::into)
45+
}
46+
47+
pub fn raw_user_for_user(
48+
connection: &PgConnection,
49+
user_uuid: &Uuid,
50+
) -> Result<UserProfile, Error> {
51+
use schema::profiles as p;
52+
53+
p::table
54+
.filter(p::user_uuid.eq(user_uuid))
55+
.get_result::<UserProfileValue>(connection)
56+
.map_err(Error::from)
57+
.and_then(TryInto::try_into)
58+
}
59+
60+
pub fn raw_logs_for_user(connection: &PgConnection, user_uuid: &Uuid) -> Result<Vec<Log>, Error> {
61+
use schema::logs as l;
62+
63+
l::table
64+
.filter(l::user_uuid.eq(user_uuid).or(l::host_uuid.eq(user_uuid)))
65+
.get_results(connection)
66+
.map_err(Into::into)
67+
}

src/db/model.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct Role {
3737
pub permissions: Vec<PermissionType>,
3838
}
3939

40-
#[derive(Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset)]
40+
#[derive(Serialize, Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset)]
4141
#[belongs_to(Group)]
4242
#[primary_key(group_id, user_uuid)]
4343
pub struct Membership {
@@ -49,7 +49,9 @@ pub struct Membership {
4949
pub added_ts: NaiveDateTime,
5050
}
5151

52-
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset)]
52+
#[derive(
53+
Serialize, Identifiable, Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset,
54+
)]
5355
#[belongs_to(Group)]
5456
#[primary_key(group_id, user_uuid)]
5557
pub struct Invitation {
@@ -68,7 +70,9 @@ pub struct Invitationtext {
6870
pub body: String,
6971
}
7072

71-
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset)]
73+
#[derive(
74+
Serialize, Identifiable, Queryable, Associations, PartialEq, Debug, Insertable, AsChangeset,
75+
)]
7276
#[belongs_to(Group)]
7377
#[primary_key(group_id, user_uuid)]
7478
pub struct Request {

src/db/operations/members.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::mail::manager::send_emails;
1414
use crate::mail::manager::subscribe_nda;
1515
use crate::mail::manager::unsubscribe_nda;
1616
use crate::mail::templates::Template;
17+
use crate::rules::engine::ADMIN_CAN_ADD_MEMBER;
1718
use crate::rules::engine::ONLY_ADMINS;
1819
use crate::rules::engine::REMOVE_MEMBER;
1920
use crate::rules::engine::RENEW_MEMBER;
@@ -52,6 +53,14 @@ pub fn membership_and_scoped_host(
5253
Trust::Ndaed => {
5354
internal::member::membership_and_ndaed_host(&connection, group.id, user.user_uuid)
5455
}
56+
Trust::Vouched => {
57+
internal::member::membership_and_vouched_host(&connection, group.id, user.user_uuid)
58+
}
59+
Trust::Authenticated => internal::member::membership_and_authenticated_host(
60+
&connection,
61+
group.id,
62+
user.user_uuid,
63+
),
5564
_ => Ok(None),
5665
}
5766
}
@@ -141,6 +150,37 @@ fn db_leave(
141150
)
142151
}
143152

153+
pub async fn transfer(
154+
pool: &Pool,
155+
scope_and_user: &ScopeAndUser,
156+
group_name: &str,
157+
old_user: &User,
158+
new_user: &User,
159+
cis_client: Arc<impl AsyncCisClientTrait>,
160+
) -> Result<(), Error> {
161+
let connection = pool.get()?;
162+
let host = internal::user::user_by_id(&connection, &scope_and_user.user_id)?;
163+
ADMIN_CAN_ADD_MEMBER.run(&RuleContext::minimal_with_member_uuid(
164+
&pool.clone(),
165+
scope_and_user,
166+
&group_name,
167+
&host.user_uuid,
168+
&new_user.user_uuid,
169+
))?;
170+
internal::member::transfer_membership(&connection, &group_name, &host, &old_user, &new_user)?;
171+
if group_name == "nda" {
172+
let old_user_profile =
173+
internal::user::slim_user_profile_by_uuid(&connection, &old_user.user_uuid)?;
174+
let new_user_profile =
175+
internal::user::slim_user_profile_by_uuid(&connection, &old_user.user_uuid)?;
176+
unsubscribe_nda(&old_user_profile.email);
177+
subscribe_nda(&new_user_profile.email);
178+
}
179+
drop(connection);
180+
send_groups_to_cis(pool, Arc::clone(&cis_client), &old_user.user_uuid).await?;
181+
send_groups_to_cis(pool, cis_client, &new_user.user_uuid).await
182+
}
183+
144184
pub async fn add(
145185
pool: &Pool,
146186
scope_and_user: &ScopeAndUser,
@@ -150,11 +190,12 @@ pub async fn add(
150190
expiration: Option<i32>,
151191
cis_client: Arc<impl AsyncCisClientTrait>,
152192
) -> Result<(), Error> {
153-
ONLY_ADMINS.run(&RuleContext::minimal(
193+
ADMIN_CAN_ADD_MEMBER.run(&RuleContext::minimal_with_member_uuid(
154194
&pool.clone(),
155195
scope_and_user,
156196
&group_name,
157197
&host.user_uuid,
198+
&user.user_uuid,
158199
))?;
159200
let connection = pool.get()?;
160201
let expiration = if expiration.is_none() {

src/db/operations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod invitations;
55
pub mod logs;
66
pub mod members;
77
pub mod models;
8+
pub mod raws;
89
pub mod requests;
910
pub mod terms;
1011
pub mod users;

src/db/operations/models.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
use crate::db::logs::Log;
12
use crate::db::model::Group;
23
use crate::db::model::GroupsList;
4+
use crate::db::model::Invitation;
5+
use crate::db::model::Membership;
6+
use crate::db::model::Request;
37
use crate::db::types::*;
8+
use crate::db::users::UserProfile;
49
use crate::error::PacksError;
510
use crate::user::User;
611
use crate::utils::maybe_to_utc;
@@ -501,6 +506,15 @@ pub struct InvitationEmail {
501506
pub body: Option<String>,
502507
}
503508

509+
#[derive(Serialize)]
510+
pub struct RawUserData {
511+
pub user_profile: UserProfile,
512+
pub memberships: Vec<Membership>,
513+
pub invitations: Vec<Invitation>,
514+
pub requests: Vec<Request>,
515+
pub logs: Vec<Log>,
516+
}
517+
504518
#[cfg(test)]
505519
mod test {
506520
use super::*;

src/db/operations/raws.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use crate::db::internal;
2+
use crate::db::internal::raw::*;
3+
use crate::db::operations::models::RawUserData;
4+
use crate::db::Pool;
5+
use dino_park_gate::scope::ScopeAndUser;
6+
use failure::Error;
7+
use uuid::Uuid;
8+
9+
pub fn raw_user_data(
10+
pool: &Pool,
11+
scope_and_user: &ScopeAndUser,
12+
user_uuid: Option<Uuid>,
13+
) -> Result<RawUserData, Error> {
14+
let connection = pool.get()?;
15+
let user_uuid = match user_uuid {
16+
Some(user_uuid) => user_uuid,
17+
_ => internal::user::user_by_id(&connection, &scope_and_user.user_id)?.user_uuid,
18+
};
19+
20+
let user_profile = raw_user_for_user(&connection, &user_uuid)?;
21+
let memberships = raw_memberships_for_user(&connection, &user_uuid)?;
22+
let invitations = raw_invitations_for_user(&connection, &user_uuid)?;
23+
let requests = raw_requests_for_user(&connection, &user_uuid)?;
24+
let logs = raw_logs_for_user(&connection, &user_uuid)?;
25+
26+
Ok(RawUserData {
27+
user_profile,
28+
memberships,
29+
invitations,
30+
requests,
31+
logs,
32+
})
33+
}

0 commit comments

Comments
 (0)