Skip to content

Commit f3aca6c

Browse files
committed
support staff only group import
1 parent 57a889c commit f3aca6c

File tree

8 files changed

+217
-27
lines changed

8 files changed

+217
-27
lines changed

scripts/upload.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
#!/bin/bash
22
HOST=${HOST:-localhost:8085}
3-
curl -v -F "group=@/tmp/$1/g.tsv" -F "memberships=@/tmp/$1/m.tsv" -F "curators=@/tmp/$1/c.tsv" http://$HOST/import/group/full
3+
STAFF_ONLY=${2:-false}
4+
curl -v -F "group=@/tmp/$1/g.tsv" -F "memberships=@/tmp/$1/m.tsv" -F "curators=@/tmp/$1/c.tsv" http://$HOST/import/group/full?staff_only=${STAFF_ONLY}

src/db/internal/member.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -409,20 +409,6 @@ pub fn get_memberships_expire_between(
409409
.map_err(Into::into)
410410
}
411411

412-
pub fn get_curator_emails(connection: &PgConnection, group_id: i32) -> Result<Vec<String>, Error> {
413-
use schema::memberships as m;
414-
use schema::profiles as p;
415-
use schema::roles as r;
416-
m::table
417-
.filter(m::group_id.eq(group_id))
418-
.inner_join(r::table)
419-
.filter(r::typ.eq_any(&[RoleType::Admin, RoleType::Curator]))
420-
.inner_join(p::table.on(m::user_uuid.eq(p::user_uuid)))
421-
.select(p::email)
422-
.get_results::<String>(connection)
423-
.map_err(Into::into)
424-
}
425-
426412
pub fn get_member_emails_by_group_name(
427413
connection: &PgConnection,
428414
group_name: &str,
@@ -439,6 +425,20 @@ pub fn get_member_emails_by_group_name(
439425
.map_err(Into::into)
440426
}
441427

428+
pub fn get_curator_emails(connection: &PgConnection, group_id: i32) -> Result<Vec<String>, Error> {
429+
use schema::memberships as m;
430+
use schema::profiles as p;
431+
use schema::roles as r;
432+
m::table
433+
.filter(m::group_id.eq(group_id))
434+
.inner_join(r::table.on(r::role_id.eq(m::role_id)))
435+
.filter(r::typ.eq_any(&[RoleType::Admin, RoleType::Curator]))
436+
.inner_join(p::table.on(m::user_uuid.eq(p::user_uuid)))
437+
.select(p::email)
438+
.get_results::<String>(connection)
439+
.map_err(Into::into)
440+
}
441+
442442
pub fn get_curator_emails_by_group_name(
443443
connection: &PgConnection,
444444
group_name: &str,
@@ -450,7 +450,7 @@ pub fn get_curator_emails_by_group_name(
450450
g::table
451451
.filter(g::name.eq(group_name))
452452
.inner_join(m::table)
453-
.inner_join(r::table)
453+
.inner_join(r::table.on(r::role_id.eq(m::role_id)))
454454
.filter(r::typ.eq_any(&[RoleType::Admin, RoleType::Curator]))
455455
.inner_join(p::table.on(m::user_uuid.eq(p::user_uuid)))
456456
.select(p::email)

src/db/operations/members.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ pub fn get_curator_emails(
300300
&group_name,
301301
&user.user_uuid,
302302
))?;
303+
// let group = internal::group::get_group(&connection, group_name)?;
304+
// internal::member::get_curator_emails(&connection, group.id)
303305

304306
internal::member::get_curator_emails_by_group_name(&connection, group_name)
305307
}

src/import/api.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use csv::ReaderBuilder;
1313
use futures::StreamExt;
1414
use futures::TryFutureExt;
1515
use futures::TryStreamExt;
16+
use serde::Deserialize;
1617
use std::sync::Arc;
1718

1819
#[derive(Debug, Default)]
@@ -22,11 +23,18 @@ struct GroupImportOption {
2223
pub curators: Option<Vec<MozilliansGroupCurator>>,
2324
}
2425

26+
#[derive(Debug, Deserialize, Default)]
27+
struct GroupImportQuery {
28+
staff_only: bool,
29+
}
30+
2531
async fn full_group_import<T: AsyncCisClientTrait>(
2632
mut multipart: Multipart,
2733
pool: web::Data<Pool>,
2834
cis_client: web::Data<T>,
35+
query: web::Query<GroupImportQuery>,
2936
) -> Result<HttpResponse, ApiError> {
37+
let GroupImportQuery { staff_only } = query.into_inner();
3038
let mut group_import = GroupImportOption {
3139
..Default::default()
3240
};
@@ -87,6 +95,7 @@ async fn full_group_import<T: AsyncCisClientTrait>(
8795
group,
8896
curators,
8997
memberships,
98+
staff_only,
9099
};
91100
import(&pool, group_import, Arc::clone(&*cis_client)).await?
92101
}

src/import/ops.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub struct GroupImport {
4141
pub group: MozilliansGroup,
4242
pub memberships: Vec<MozilliansGroupMembership>,
4343
pub curators: Vec<MozilliansGroupCurator>,
44+
pub staff_only: bool,
4445
}
4546

4647
pub fn import_group(connection: &PgConnection, moz_group: MozilliansGroup) -> Result<(), Error> {
@@ -115,13 +116,24 @@ async fn import_curator(
115116
connection: &PgConnection,
116117
group_name: &str,
117118
curator: MozilliansGroupCurator,
119+
staff_only: bool,
118120
cis_client: Arc<impl AsyncCisClientTrait>,
119121
) -> Result<(), Error> {
120122
let user_profile =
121123
get_user_profile(connection, &curator.auth0_user_id, cis_client.clone()).await?;
122124
let user = User {
123125
user_uuid: user_profile.user_uuid,
124126
};
127+
if staff_only
128+
&& !user_profile
129+
.profile
130+
.staff_information
131+
.staff
132+
.value
133+
.unwrap_or_default()
134+
{
135+
return Ok(());
136+
}
125137
internal::admin::add_admin(&connection, group_name, &User::default(), &user)?;
126138
drop(connection);
127139
add_group_to_profile(cis_client, group_name.to_owned(), user_profile.profile).await?;
@@ -132,11 +144,20 @@ pub async fn import_curators(
132144
connection: &PgConnection,
133145
group_name: &str,
134146
moz_curators: Vec<MozilliansGroupCurator>,
147+
staff_only: bool,
135148
cis_client: Arc<impl AsyncCisClientTrait>,
136149
) -> Result<(), Error> {
137150
for curator in moz_curators {
138151
let user_id = curator.auth0_user_id.clone();
139-
match import_curator(connection, group_name, curator, cis_client.clone()).await {
152+
match import_curator(
153+
connection,
154+
group_name,
155+
curator,
156+
staff_only,
157+
cis_client.clone(),
158+
)
159+
.await
160+
{
140161
Ok(()) => {}
141162
Err(e) => warn!(
142163
"unable to add curator {} for group {}: {}",
@@ -151,16 +172,29 @@ pub async fn import_member(
151172
connection: &PgConnection,
152173
group_name: &str,
153174
member: MozilliansGroupMembership,
175+
staff_only: bool,
154176
cis_client: Arc<impl AsyncCisClientTrait>,
155177
) -> Result<(), Error> {
156178
use schema::memberships as m;
157-
let group = internal::group::get_group(connection, group_name)?;
158-
let expiration = calc_expiration(member.expiration, member.updated_on);
179+
159180
let user_profile =
160181
get_user_profile(connection, &member.auth0_user_id, cis_client.clone()).await?;
182+
if staff_only
183+
&& !user_profile
184+
.profile
185+
.staff_information
186+
.staff
187+
.value
188+
.unwrap_or_default()
189+
{
190+
return Ok(());
191+
}
192+
161193
let user = User {
162194
user_uuid: user_profile.user_uuid,
163195
};
196+
let group = internal::group::get_group(connection, group_name)?;
197+
let expiration = calc_expiration(member.expiration, member.updated_on);
164198
let role = internal::member::role_for(connection, &user.user_uuid, group_name)?;
165199
if role.is_some() {
166200
diesel::update(m::table)
@@ -202,6 +236,7 @@ pub async fn import_members(
202236
connection: &PgConnection,
203237
group_name: &str,
204238
moz_members: Vec<MozilliansGroupMembership>,
239+
staff_only: bool,
205240
cis_client: Arc<impl AsyncCisClientTrait>,
206241
) -> Result<(), Error> {
207242
use schema::groups as g;
@@ -213,7 +248,15 @@ pub async fn import_members(
213248
created = joined;
214249
}
215250
let user_id = member.auth0_user_id.clone();
216-
match import_member(connection, group_name, member, cis_client.clone()).await {
251+
match import_member(
252+
connection,
253+
group_name,
254+
member,
255+
staff_only,
256+
cis_client.clone(),
257+
)
258+
.await
259+
{
217260
Ok(()) => {}
218261
Err(e) => warn!(
219262
"unable to add member {} for group {}: {}",
@@ -241,13 +284,15 @@ pub async fn import(
241284
&connection,
242285
&group_name,
243286
group_import.curators,
287+
group_import.staff_only,
244288
cis_client.clone(),
245289
)
246290
.await?;
247291
import_members(
248292
&connection,
249293
&group_name,
250294
group_import.memberships,
295+
group_import.staff_only,
251296
cis_client.clone(),
252297
)
253298
.await?;

tests/api/import.rs

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn group() -> Result<MozilliansGroup, Error> {
4848
}
4949

5050
#[actix_rt::test]
51-
async fn create() -> Result<(), Error> {
51+
async fn import() -> Result<(), Error> {
5252
reset()?;
5353
let (service, cis_client) = test_app_and_cis().await;
5454
let cis_client = Arc::new(cis_client);
@@ -60,7 +60,14 @@ async fn create() -> Result<(), Error> {
6060
let members = members()?;
6161
let connection = get_pool().get()?;
6262
import_group(&connection, group)?;
63-
import_curators(&connection, "import-test", curators, cis_client.clone()).await?;
63+
import_curators(
64+
&connection,
65+
"import-test",
66+
curators,
67+
false,
68+
cis_client.clone(),
69+
)
70+
.await?;
6471

6572
let res = get(&mut app, "/groups/api/v1/groups", &creator).await;
6673
assert!(res.status().is_success());
@@ -113,7 +120,14 @@ async fn create() -> Result<(), Error> {
113120
Some(0)
114121
);
115122

116-
import_members(&connection, "import-test", members, cis_client.clone()).await?;
123+
import_members(
124+
&connection,
125+
"import-test",
126+
members,
127+
false,
128+
cis_client.clone(),
129+
)
130+
.await?;
117131

118132
let res = get(
119133
&mut app,
@@ -151,3 +165,122 @@ async fn create() -> Result<(), Error> {
151165

152166
Ok(())
153167
}
168+
169+
#[actix_rt::test]
170+
async fn import_staff_only() -> Result<(), Error> {
171+
reset()?;
172+
let (service, cis_client) = test_app_and_cis().await;
173+
let cis_client = Arc::new(cis_client);
174+
let app = App::new().service(service);
175+
let mut app = test::init_service(app).await;
176+
let creator = Soa::from(&basic_user(1, true)).creator().aal_medium();
177+
let group = group()?;
178+
let curators = curators()?;
179+
let members = members()?;
180+
let connection = get_pool().get()?;
181+
import_group(&connection, group)?;
182+
import_curators(
183+
&connection,
184+
"import-test",
185+
curators,
186+
true,
187+
cis_client.clone(),
188+
)
189+
.await?;
190+
191+
let res = get(&mut app, "/groups/api/v1/groups", &creator).await;
192+
assert!(res.status().is_success());
193+
assert_eq!(read_json(res).await["groups"][0]["name"], "import-test");
194+
195+
let res = get(
196+
&mut app,
197+
"/groups/api/v1/groups/import-test/details",
198+
&creator,
199+
)
200+
.await;
201+
assert!(res.status().is_success());
202+
let j = read_json(res).await;
203+
assert_eq!(j["group"]["terms"], true);
204+
assert_eq!(
205+
j["group"]["description"],
206+
"import test group\n\n**Website:** [https://example.com/](https://example.com/)"
207+
);
208+
209+
let res = get(
210+
&mut app,
211+
"/groups/api/v1/invitations/import-test/email",
212+
&creator,
213+
)
214+
.await;
215+
assert!(res.status().is_success());
216+
assert_eq!(read_json(res).await["body"], "some \ninvitation email");
217+
218+
let res = get(
219+
&mut app,
220+
"/groups/api/v1/members/import-test?r=Curator",
221+
&creator,
222+
)
223+
.await;
224+
assert!(res.status().is_success());
225+
assert_eq!(
226+
read_json(res).await["members"].as_array().map(|a| a.len()),
227+
Some(2)
228+
);
229+
230+
let res = get(
231+
&mut app,
232+
"/groups/api/v1/members/import-test?r=Member",
233+
&creator,
234+
)
235+
.await;
236+
assert!(res.status().is_success());
237+
assert_eq!(
238+
read_json(res).await["members"].as_array().map(|a| a.len()),
239+
Some(0)
240+
);
241+
242+
import_members(
243+
&connection,
244+
"import-test",
245+
members,
246+
true,
247+
cis_client.clone(),
248+
)
249+
.await?;
250+
251+
let res = get(
252+
&mut app,
253+
"/groups/api/v1/members/import-test?r=Curator",
254+
&creator,
255+
)
256+
.await;
257+
assert!(res.status().is_success());
258+
assert_eq!(
259+
read_json(res).await["members"].as_array().map(|a| a.len()),
260+
Some(2)
261+
);
262+
263+
let res = get(
264+
&mut app,
265+
"/groups/api/v1/members/import-test?r=Member",
266+
&creator,
267+
)
268+
.await;
269+
assert!(res.status().is_success());
270+
assert_eq!(
271+
read_json(res).await["members"].as_array().map(|a| a.len()),
272+
Some(4)
273+
);
274+
275+
let res = get(
276+
&mut app,
277+
"/groups/api/v1/groups/import-test/details",
278+
&creator,
279+
)
280+
.await;
281+
assert!(res.status().is_success());
282+
let j = read_json(res).await;
283+
assert_eq!(j["group"]["created"], "2019-10-24T17:56:21Z");
284+
285+
Ok(())
286+
}

0 commit comments

Comments
 (0)