You've already forked AstralRinth
forked from didirus/AstralRinth
Fix clippy errors + lint, use turbo CI
This commit is contained in:
@@ -16,125 +16,137 @@ mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn analytics_revenue() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_project_id = test_env.dummy.project_alpha.project_id.clone();
|
||||
let alpha_project_id =
|
||||
test_env.dummy.project_alpha.project_id.clone();
|
||||
|
||||
let pool = test_env.db.pool.clone();
|
||||
let pool = test_env.db.pool.clone();
|
||||
|
||||
// Generate sample revenue data- directly insert into sql
|
||||
let (
|
||||
mut insert_user_ids,
|
||||
mut insert_project_ids,
|
||||
mut insert_payouts,
|
||||
mut insert_starts,
|
||||
mut insert_availables,
|
||||
) = (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
||||
// Generate sample revenue data- directly insert into sql
|
||||
let (
|
||||
mut insert_user_ids,
|
||||
mut insert_project_ids,
|
||||
mut insert_payouts,
|
||||
mut insert_starts,
|
||||
mut insert_availables,
|
||||
) = (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
||||
|
||||
// Note: these go from most recent to least recent
|
||||
let money_time_pairs: [(f64, DateTime<Utc>); 10] = [
|
||||
(50.0, Utc::now() - Duration::minutes(5)),
|
||||
(50.1, Utc::now() - Duration::minutes(10)),
|
||||
(101.0, Utc::now() - Duration::days(1)),
|
||||
(200.0, Utc::now() - Duration::days(2)),
|
||||
(311.0, Utc::now() - Duration::days(3)),
|
||||
(400.0, Utc::now() - Duration::days(4)),
|
||||
(526.0, Utc::now() - Duration::days(5)),
|
||||
(633.0, Utc::now() - Duration::days(6)),
|
||||
(800.0, Utc::now() - Duration::days(14)),
|
||||
(800.0, Utc::now() - Duration::days(800)),
|
||||
];
|
||||
// Note: these go from most recent to least recent
|
||||
let money_time_pairs: [(f64, DateTime<Utc>); 10] = [
|
||||
(50.0, Utc::now() - Duration::minutes(5)),
|
||||
(50.1, Utc::now() - Duration::minutes(10)),
|
||||
(101.0, Utc::now() - Duration::days(1)),
|
||||
(200.0, Utc::now() - Duration::days(2)),
|
||||
(311.0, Utc::now() - Duration::days(3)),
|
||||
(400.0, Utc::now() - Duration::days(4)),
|
||||
(526.0, Utc::now() - Duration::days(5)),
|
||||
(633.0, Utc::now() - Duration::days(6)),
|
||||
(800.0, Utc::now() - Duration::days(14)),
|
||||
(800.0, Utc::now() - Duration::days(800)),
|
||||
];
|
||||
|
||||
let project_id = parse_base62(&alpha_project_id).unwrap() as i64;
|
||||
for (money, time) in money_time_pairs.iter() {
|
||||
insert_user_ids.push(USER_USER_ID_PARSED);
|
||||
insert_project_ids.push(project_id);
|
||||
insert_payouts.push(Decimal::from_f64_retain(*money).unwrap());
|
||||
insert_starts.push(*time);
|
||||
insert_availables.push(*time);
|
||||
}
|
||||
let project_id = parse_base62(&alpha_project_id).unwrap() as i64;
|
||||
for (money, time) in money_time_pairs.iter() {
|
||||
insert_user_ids.push(USER_USER_ID_PARSED);
|
||||
insert_project_ids.push(project_id);
|
||||
insert_payouts.push(Decimal::from_f64_retain(*money).unwrap());
|
||||
insert_starts.push(*time);
|
||||
insert_availables.push(*time);
|
||||
}
|
||||
|
||||
let mut transaction = pool.begin().await.unwrap();
|
||||
payouts::insert_payouts(
|
||||
insert_user_ids,
|
||||
insert_project_ids,
|
||||
insert_payouts,
|
||||
insert_starts,
|
||||
insert_availables,
|
||||
&mut transaction,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
transaction.commit().await.unwrap();
|
||||
|
||||
let day = 86400;
|
||||
|
||||
// Test analytics endpoint with default values
|
||||
// - all time points in the last 2 weeks
|
||||
// - 1 day resolution
|
||||
let analytics = api
|
||||
.get_analytics_revenue_deserialized(
|
||||
vec![&alpha_project_id],
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
let mut transaction = pool.begin().await.unwrap();
|
||||
payouts::insert_payouts(
|
||||
insert_user_ids,
|
||||
insert_project_ids,
|
||||
insert_payouts,
|
||||
insert_starts,
|
||||
insert_availables,
|
||||
&mut transaction,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(analytics.len(), 1); // 1 project
|
||||
let project_analytics = analytics.get(&alpha_project_id).unwrap();
|
||||
assert_eq!(project_analytics.len(), 8); // 1 days cut off, and 2 points take place on the same day. note that the day exactly 14 days ago is included
|
||||
// sorted_by_key, values in the order of smallest to largest key
|
||||
let (sorted_keys, sorted_by_key): (Vec<i64>, Vec<Decimal>) = project_analytics
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.rev()
|
||||
.unzip();
|
||||
assert_eq!(
|
||||
vec![100.1, 101.0, 200.0, 311.0, 400.0, 526.0, 633.0, 800.0],
|
||||
to_f64_vec_rounded_up(sorted_by_key)
|
||||
);
|
||||
// Ensure that the keys are in multiples of 1 day
|
||||
for k in sorted_keys {
|
||||
assert_eq!(k % day, 0);
|
||||
}
|
||||
.await
|
||||
.unwrap();
|
||||
transaction.commit().await.unwrap();
|
||||
|
||||
// Test analytics with last 900 days to include all data
|
||||
// keep resolution at default
|
||||
let analytics = api
|
||||
.get_analytics_revenue_deserialized(
|
||||
vec![&alpha_project_id],
|
||||
false,
|
||||
Some(Utc::now() - Duration::days(801)),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let project_analytics = analytics.get(&alpha_project_id).unwrap();
|
||||
assert_eq!(project_analytics.len(), 9); // and 2 points take place on the same day
|
||||
let (sorted_keys, sorted_by_key): (Vec<i64>, Vec<Decimal>) = project_analytics
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.rev()
|
||||
.unzip();
|
||||
assert_eq!(
|
||||
vec![100.1, 101.0, 200.0, 311.0, 400.0, 526.0, 633.0, 800.0, 800.0],
|
||||
to_f64_vec_rounded_up(sorted_by_key)
|
||||
);
|
||||
for k in sorted_keys {
|
||||
assert_eq!(k % day, 0);
|
||||
}
|
||||
})
|
||||
let day = 86400;
|
||||
|
||||
// Test analytics endpoint with default values
|
||||
// - all time points in the last 2 weeks
|
||||
// - 1 day resolution
|
||||
let analytics = api
|
||||
.get_analytics_revenue_deserialized(
|
||||
vec![&alpha_project_id],
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(analytics.len(), 1); // 1 project
|
||||
let project_analytics = analytics.get(&alpha_project_id).unwrap();
|
||||
assert_eq!(project_analytics.len(), 8); // 1 days cut off, and 2 points take place on the same day. note that the day exactly 14 days ago is included
|
||||
// sorted_by_key, values in the order of smallest to largest key
|
||||
let (sorted_keys, sorted_by_key): (Vec<i64>, Vec<Decimal>) =
|
||||
project_analytics
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.rev()
|
||||
.unzip();
|
||||
assert_eq!(
|
||||
vec![100.1, 101.0, 200.0, 311.0, 400.0, 526.0, 633.0, 800.0],
|
||||
to_f64_vec_rounded_up(sorted_by_key)
|
||||
);
|
||||
// Ensure that the keys are in multiples of 1 day
|
||||
for k in sorted_keys {
|
||||
assert_eq!(k % day, 0);
|
||||
}
|
||||
|
||||
// Test analytics with last 900 days to include all data
|
||||
// keep resolution at default
|
||||
let analytics = api
|
||||
.get_analytics_revenue_deserialized(
|
||||
vec![&alpha_project_id],
|
||||
false,
|
||||
Some(Utc::now() - Duration::days(801)),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let project_analytics = analytics.get(&alpha_project_id).unwrap();
|
||||
assert_eq!(project_analytics.len(), 9); // and 2 points take place on the same day
|
||||
let (sorted_keys, sorted_by_key): (Vec<i64>, Vec<Decimal>) =
|
||||
project_analytics
|
||||
.iter()
|
||||
.sorted_by_key(|(k, _)| *k)
|
||||
.rev()
|
||||
.unzip();
|
||||
assert_eq!(
|
||||
vec![
|
||||
100.1, 101.0, 200.0, 311.0, 400.0, 526.0, 633.0, 800.0,
|
||||
800.0
|
||||
],
|
||||
to_f64_vec_rounded_up(sorted_by_key)
|
||||
);
|
||||
for k in sorted_keys {
|
||||
assert_eq!(k % day, 0);
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
fn to_f64_rounded_up(d: Decimal) -> f64 {
|
||||
d.round_dp_with_strategy(1, rust_decimal::RoundingStrategy::MidpointAwayFromZero)
|
||||
.to_f64()
|
||||
.unwrap()
|
||||
d.round_dp_with_strategy(
|
||||
1,
|
||||
rust_decimal::RoundingStrategy::MidpointAwayFromZero,
|
||||
)
|
||||
.to_f64()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn to_f64_vec_rounded_up(d: Vec<Decimal>) -> Vec<f64> {
|
||||
@@ -143,88 +155,93 @@ fn to_f64_vec_rounded_up(d: Vec<Decimal>) -> Vec<f64> {
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn permissions_analytics_revenue() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let alpha_project_id = test_env.dummy.project_alpha.project_id.clone();
|
||||
let alpha_version_id = test_env.dummy.project_alpha.version_id.clone();
|
||||
let alpha_team_id = test_env.dummy.project_alpha.team_id.clone();
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let alpha_project_id =
|
||||
test_env.dummy.project_alpha.project_id.clone();
|
||||
let alpha_version_id =
|
||||
test_env.dummy.project_alpha.version_id.clone();
|
||||
let alpha_team_id = test_env.dummy.project_alpha.team_id.clone();
|
||||
|
||||
let api = &test_env.api;
|
||||
let api = &test_env.api;
|
||||
|
||||
let view_analytics = ProjectPermissions::VIEW_ANALYTICS;
|
||||
let view_analytics = ProjectPermissions::VIEW_ANALYTICS;
|
||||
|
||||
// first, do check with a project
|
||||
let req_gen = |ctx: PermissionsTestContext| async move {
|
||||
let project_id = ctx.project_id.unwrap();
|
||||
let ids_or_slugs = vec![project_id.as_str()];
|
||||
api.get_analytics_revenue(
|
||||
ids_or_slugs,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
Some(5),
|
||||
ctx.test_pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_failure_codes(vec![200, 401])
|
||||
.with_200_json_checks(
|
||||
// On failure, should have 0 projects returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
// On success, should have 1 project returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 1);
|
||||
},
|
||||
)
|
||||
.simple_project_permissions_test(view_analytics, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Now with a version
|
||||
// Need to use alpha
|
||||
let req_gen = |ctx: PermissionsTestContext| {
|
||||
let alpha_version_id = alpha_version_id.clone();
|
||||
async move {
|
||||
let ids_or_slugs = vec![alpha_version_id.as_str()];
|
||||
// first, do check with a project
|
||||
let req_gen = |ctx: PermissionsTestContext| async move {
|
||||
let project_id = ctx.project_id.unwrap();
|
||||
let ids_or_slugs = vec![project_id.as_str()];
|
||||
api.get_analytics_revenue(
|
||||
ids_or_slugs,
|
||||
true,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
Some(5),
|
||||
ctx.test_pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_failure_codes(vec![200, 401])
|
||||
.with_existing_project(&alpha_project_id, &alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.with_200_json_checks(
|
||||
// On failure, should have 0 versions returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
// On success, should have 1 versions returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
)
|
||||
.simple_project_permissions_test(view_analytics, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_failure_codes(vec![200, 401])
|
||||
.with_200_json_checks(
|
||||
// On failure, should have 0 projects returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
// On success, should have 1 project returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 1);
|
||||
},
|
||||
)
|
||||
.simple_project_permissions_test(view_analytics, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
})
|
||||
// Now with a version
|
||||
// Need to use alpha
|
||||
let req_gen = |ctx: PermissionsTestContext| {
|
||||
let alpha_version_id = alpha_version_id.clone();
|
||||
async move {
|
||||
let ids_or_slugs = vec![alpha_version_id.as_str()];
|
||||
api.get_analytics_revenue(
|
||||
ids_or_slugs,
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
Some(5),
|
||||
ctx.test_pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_failure_codes(vec![200, 401])
|
||||
.with_existing_project(&alpha_project_id, &alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.with_200_json_checks(
|
||||
// On failure, should have 0 versions returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
// On success, should have 1 versions returned
|
||||
|value: &serde_json::Value| {
|
||||
let value = value.as_object().unwrap();
|
||||
assert_eq!(value.len(), 0);
|
||||
},
|
||||
)
|
||||
.simple_project_permissions_test(view_analytics, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use self::models::{
|
||||
CommonCategoryData, CommonItemType, CommonLoaderData, CommonNotification, CommonProject,
|
||||
CommonTeamMember, CommonVersion,
|
||||
CommonCategoryData, CommonItemType, CommonLoaderData, CommonNotification,
|
||||
CommonProject, CommonTeamMember, CommonVersion,
|
||||
};
|
||||
use self::request_data::{ImageData, ProjectCreationRequestData};
|
||||
use actix_web::dev::ServiceResponse;
|
||||
@@ -51,14 +51,26 @@ pub trait ApiProject {
|
||||
version_jar: Option<&TestFile>,
|
||||
) -> serde_json::Value;
|
||||
|
||||
async fn remove_project(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_project(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn remove_project(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_project(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_project_deserialized_common(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> CommonProject;
|
||||
async fn get_projects(&self, ids_or_slugs: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_projects(
|
||||
&self,
|
||||
ids_or_slugs: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_project_dependencies(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
@@ -125,7 +137,11 @@ pub trait ApiProject {
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_reports(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_reports(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_user_reports(&self, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn edit_report(
|
||||
&self,
|
||||
@@ -133,9 +149,17 @@ pub trait ApiProject {
|
||||
patch: serde_json::Value,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn delete_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn delete_report(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_thread(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_threads(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_threads(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn write_to_thread(
|
||||
&self,
|
||||
id: &str,
|
||||
@@ -144,8 +168,13 @@ pub trait ApiProject {
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_moderation_inbox(&self, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn read_thread(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn delete_thread_message(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn read_thread(&self, id: &str, pat: Option<&str>)
|
||||
-> ServiceResponse;
|
||||
async fn delete_thread_message(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -153,19 +182,33 @@ pub trait ApiTags {
|
||||
async fn get_loaders(&self) -> ServiceResponse;
|
||||
async fn get_loaders_deserialized_common(&self) -> Vec<CommonLoaderData>;
|
||||
async fn get_categories(&self) -> ServiceResponse;
|
||||
async fn get_categories_deserialized_common(&self) -> Vec<CommonCategoryData>;
|
||||
async fn get_categories_deserialized_common(
|
||||
&self,
|
||||
) -> Vec<CommonCategoryData>;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait ApiTeams {
|
||||
async fn get_team_members(&self, team_id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_team_members(
|
||||
&self,
|
||||
team_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_team_members_deserialized_common(
|
||||
&self,
|
||||
team_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember>;
|
||||
async fn get_teams_members(&self, team_ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_project_members(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_teams_members(
|
||||
&self,
|
||||
team_ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_project_members(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_project_members_deserialized_common(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
@@ -181,7 +224,11 @@ pub trait ApiTeams {
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember>;
|
||||
async fn join_team(&self, team_id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn join_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn remove_from_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
@@ -201,20 +248,36 @@ pub trait ApiTeams {
|
||||
user_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_user_notifications(&self, user_id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_user_notifications(
|
||||
&self,
|
||||
user_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_user_notifications_deserialized_common(
|
||||
&self,
|
||||
user_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonNotification>;
|
||||
async fn get_notification(&self, notification_id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_notifications(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_notification(
|
||||
&self,
|
||||
notification_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_notifications(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn mark_notification_read(
|
||||
&self,
|
||||
notification_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn mark_notifications_read(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn mark_notifications_read(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn add_user_to_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
@@ -228,12 +291,20 @@ pub trait ApiTeams {
|
||||
notification_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn delete_notifications(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse;
|
||||
async fn delete_notifications(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait ApiUser {
|
||||
async fn get_user(&self, id_or_username: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_user(
|
||||
&self,
|
||||
id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_current_user(&self, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn edit_user(
|
||||
&self,
|
||||
@@ -241,7 +312,11 @@ pub trait ApiUser {
|
||||
patch: serde_json::Value,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn delete_user(&self, id_or_username: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn delete_user(
|
||||
&self,
|
||||
id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -264,13 +339,18 @@ pub trait ApiVersion {
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion;
|
||||
async fn get_version(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_version(&self, id: &str, pat: Option<&str>)
|
||||
-> ServiceResponse;
|
||||
async fn get_version_deserialized_common(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion;
|
||||
async fn get_versions(&self, ids: Vec<String>, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn get_versions(
|
||||
&self,
|
||||
ids: Vec<String>,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn get_versions_deserialized_common(
|
||||
&self,
|
||||
ids: Vec<String>,
|
||||
@@ -384,8 +464,16 @@ pub trait ApiVersion {
|
||||
file: &TestFile,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn remove_version(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn remove_version_file(&self, hash: &str, pat: Option<&str>) -> ServiceResponse;
|
||||
async fn remove_version(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
async fn remove_version_file(
|
||||
&self,
|
||||
hash: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse;
|
||||
}
|
||||
|
||||
pub trait AppendsOptionalPat {
|
||||
|
||||
@@ -6,8 +6,9 @@ use labrinth::{
|
||||
notifications::NotificationId,
|
||||
organizations::OrganizationId,
|
||||
projects::{
|
||||
Dependency, GalleryItem, License, ModeratorMessage, MonetizationStatus, ProjectId,
|
||||
ProjectStatus, VersionFile, VersionId, VersionStatus, VersionType,
|
||||
Dependency, GalleryItem, License, ModeratorMessage,
|
||||
MonetizationStatus, ProjectId, ProjectStatus, VersionFile,
|
||||
VersionId, VersionStatus, VersionType,
|
||||
},
|
||||
reports::ReportId,
|
||||
teams::{ProjectPermissions, TeamId},
|
||||
|
||||
@@ -24,8 +24,11 @@ pub struct ApiV2 {
|
||||
#[async_trait(?Send)]
|
||||
impl ApiBuildable for ApiV2 {
|
||||
async fn build(labrinth_config: LabrinthConfig) -> Self {
|
||||
let app = App::new().configure(|cfg| labrinth::app_config(cfg, labrinth_config.clone()));
|
||||
let test_app: Rc<dyn LocalService> = Rc::new(test::init_service(app).await);
|
||||
let app = App::new().configure(|cfg| {
|
||||
labrinth::app_config(cfg, labrinth_config.clone())
|
||||
});
|
||||
let test_app: Rc<dyn LocalService> =
|
||||
Rc::new(test::init_service(app).await);
|
||||
|
||||
Self { test_app }
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ impl ApiProject for ApiV2 {
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
pat: Option<&str>,
|
||||
) -> (CommonProject, Vec<CommonVersion>) {
|
||||
let creation_data = get_public_project_creation_data(slug, version_jar, modify_json);
|
||||
let creation_data =
|
||||
get_public_project_creation_data(slug, version_jar, modify_json);
|
||||
|
||||
// Add a project.
|
||||
let slug = creation_data.slug.clone();
|
||||
@@ -143,7 +144,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn remove_project(&self, project_slug_or_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_project(
|
||||
&self,
|
||||
project_slug_or_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/project/{project_slug_or_id}"))
|
||||
.append_pat(pat)
|
||||
@@ -152,7 +157,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_project(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_project(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v2/project/{id_or_slug}"))
|
||||
.append_pat(pat)
|
||||
@@ -174,7 +183,11 @@ impl ApiProject for ApiV2 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_projects(&self, ids_or_slugs: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_projects(
|
||||
&self,
|
||||
ids_or_slugs: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_or_slugs = serde_json::to_string(ids_or_slugs).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -324,7 +337,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_reports(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_reports(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_str = serde_json::to_string(ids).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -346,7 +363,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_report(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/report/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -379,7 +400,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_threads(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_threads(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_str = serde_json::to_string(ids).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -422,7 +447,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn read_thread(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn read_thread(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v2/thread/{id}/read"))
|
||||
.append_pat(pat)
|
||||
@@ -431,7 +460,11 @@ impl ApiProject for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_thread_message(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_thread_message(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/message/{id}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::{
|
||||
api_common::request_data::{ProjectCreationRequestData, VersionCreationRequestData},
|
||||
api_common::request_data::{
|
||||
ProjectCreationRequestData, VersionCreationRequestData,
|
||||
},
|
||||
dummy_data::TestFile,
|
||||
};
|
||||
use labrinth::{
|
||||
@@ -15,11 +17,13 @@ pub fn get_public_project_creation_data(
|
||||
version_jar: Option<TestFile>,
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
) -> ProjectCreationRequestData {
|
||||
let mut json_data = get_public_project_creation_data_json(slug, version_jar.as_ref());
|
||||
let mut json_data =
|
||||
get_public_project_creation_data_json(slug, version_jar.as_ref());
|
||||
if let Some(modify_json) = modify_json {
|
||||
json_patch::patch(&mut json_data, &modify_json).unwrap();
|
||||
}
|
||||
let multipart_data = get_public_creation_data_multipart(&json_data, version_jar.as_ref());
|
||||
let multipart_data =
|
||||
get_public_creation_data_multipart(&json_data, version_jar.as_ref());
|
||||
ProjectCreationRequestData {
|
||||
slug: slug.to_string(),
|
||||
jar: version_jar,
|
||||
@@ -34,13 +38,17 @@ pub fn get_public_version_creation_data(
|
||||
ordering: Option<i32>,
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
) -> VersionCreationRequestData {
|
||||
let mut json_data =
|
||||
get_public_version_creation_data_json(version_number, ordering, &version_jar);
|
||||
let mut json_data = get_public_version_creation_data_json(
|
||||
version_number,
|
||||
ordering,
|
||||
&version_jar,
|
||||
);
|
||||
json_data["project_id"] = json!(project_id);
|
||||
if let Some(modify_json) = modify_json {
|
||||
json_patch::patch(&mut json_data, &modify_json).unwrap();
|
||||
}
|
||||
let multipart_data = get_public_creation_data_multipart(&json_data, Some(&version_jar));
|
||||
let multipart_data =
|
||||
get_public_creation_data_multipart(&json_data, Some(&version_jar));
|
||||
VersionCreationRequestData {
|
||||
version: version_number.to_string(),
|
||||
jar: Some(version_jar),
|
||||
@@ -106,7 +114,9 @@ pub fn get_public_creation_data_multipart(
|
||||
name: "data".to_string(),
|
||||
filename: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(json_data).unwrap()),
|
||||
data: MultipartSegmentData::Text(
|
||||
serde_json::to_string(json_data).unwrap(),
|
||||
),
|
||||
};
|
||||
|
||||
if let Some(jar) = version_jar {
|
||||
|
||||
@@ -44,7 +44,9 @@ impl ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_game_versions_deserialized(&self) -> Vec<GameVersionQueryData> {
|
||||
pub async fn get_game_versions_deserialized(
|
||||
&self,
|
||||
) -> Vec<GameVersionQueryData> {
|
||||
let resp = self.get_game_versions().await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
@@ -70,7 +72,9 @@ impl ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_donation_platforms_deserialized(&self) -> Vec<DonationPlatformQueryData> {
|
||||
pub async fn get_donation_platforms_deserialized(
|
||||
&self,
|
||||
) -> Vec<DonationPlatformQueryData> {
|
||||
let resp = self.get_donation_platforms().await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
@@ -105,7 +109,9 @@ impl ApiTags for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_categories_deserialized_common(&self) -> Vec<CommonCategoryData> {
|
||||
async fn get_categories_deserialized_common(
|
||||
&self,
|
||||
) -> Vec<CommonCategoryData> {
|
||||
let resp = self.get_categories().await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
|
||||
@@ -51,7 +51,11 @@ impl ApiV2 {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl ApiTeams for ApiV2 {
|
||||
async fn get_team_members(&self, id_or_title: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_team_members(
|
||||
&self,
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/team/{id_or_title}/members"))
|
||||
.append_pat(pat)
|
||||
@@ -89,7 +93,11 @@ impl ApiTeams for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_project_members(&self, id_or_title: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_project_members(
|
||||
&self,
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/project/{id_or_title}/members"))
|
||||
.append_pat(pat)
|
||||
@@ -137,7 +145,11 @@ impl ApiTeams for ApiV2 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn join_team(&self, team_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn join_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v2/team/{team_id}/join"))
|
||||
.append_pat(pat)
|
||||
@@ -189,7 +201,11 @@ impl ApiTeams for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_user_notifications(&self, user_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_user_notifications(
|
||||
&self,
|
||||
user_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/user/{user_id}/notifications"))
|
||||
.append_pat(pat)
|
||||
@@ -211,7 +227,11 @@ impl ApiTeams for ApiV2 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_notification(&self, notification_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_notification(
|
||||
&self,
|
||||
notification_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/notification/{notification_id}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -5,7 +5,11 @@ use async_trait::async_trait;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl ApiUser for ApiV2 {
|
||||
async fn get_user(&self, user_id_or_username: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_user(
|
||||
&self,
|
||||
user_id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/user/{}", user_id_or_username))
|
||||
.append_pat(pat)
|
||||
@@ -36,7 +40,11 @@ impl ApiUser for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_user(&self, user_id_or_username: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_user(
|
||||
&self,
|
||||
user_id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/user/{}", user_id_or_username))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -7,7 +7,9 @@ use super::{
|
||||
use crate::{
|
||||
assert_status,
|
||||
common::{
|
||||
api_common::{models::CommonVersion, Api, ApiVersion, AppendsOptionalPat},
|
||||
api_common::{
|
||||
models::CommonVersion, Api, ApiVersion, AppendsOptionalPat,
|
||||
},
|
||||
dummy_data::TestFile,
|
||||
},
|
||||
};
|
||||
@@ -33,7 +35,11 @@ pub fn url_encode_json_serialized_vec(elements: &[String]) -> String {
|
||||
}
|
||||
|
||||
impl ApiV2 {
|
||||
pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> LegacyVersion {
|
||||
pub async fn get_version_deserialized(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> LegacyVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
@@ -145,7 +151,11 @@ impl ApiVersion for ApiV2 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_version(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_version(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v2/version/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -153,7 +163,11 @@ impl ApiVersion for ApiV2 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion {
|
||||
async fn get_version_deserialized_common(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
@@ -248,7 +262,8 @@ impl ApiVersion for ApiV2 {
|
||||
let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, LegacyVersion> = test::read_body_json(resp).await;
|
||||
let v: HashMap<String, LegacyVersion> =
|
||||
test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
let value = serde_json::to_value(v).unwrap();
|
||||
serde_json::from_value(value).unwrap()
|
||||
@@ -287,7 +302,14 @@ impl ApiVersion for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self
|
||||
.get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat)
|
||||
.get_update_from_hash(
|
||||
hash,
|
||||
algorithm,
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types,
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
@@ -341,7 +363,8 @@ impl ApiVersion for ApiV2 {
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, LegacyVersion> = test::read_body_json(resp).await;
|
||||
let v: HashMap<String, LegacyVersion> =
|
||||
test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
let value = serde_json::to_value(v).unwrap();
|
||||
serde_json::from_value(value).unwrap()
|
||||
@@ -364,7 +387,9 @@ impl ApiVersion for ApiV2 {
|
||||
if let Some(game_versions) = game_versions {
|
||||
query_string.push_str(&format!(
|
||||
"&game_versions={}",
|
||||
urlencoding::encode(&serde_json::to_string(&game_versions).unwrap())
|
||||
urlencoding::encode(
|
||||
&serde_json::to_string(&game_versions).unwrap()
|
||||
)
|
||||
));
|
||||
}
|
||||
if let Some(loaders) = loaders {
|
||||
@@ -448,7 +473,11 @@ impl ApiVersion for ApiV2 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn get_versions(&self, version_ids: Vec<String>, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_versions(
|
||||
&self,
|
||||
version_ids: Vec<String>,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids = url_encode_json_serialized_vec(&version_ids);
|
||||
let request = test::TestRequest::get()
|
||||
.uri(&format!("/v2/versions?ids={}", ids))
|
||||
@@ -491,7 +520,11 @@ impl ApiVersion for ApiV2 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn remove_version(&self, version_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_version(
|
||||
&self,
|
||||
version_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let request = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/version/{version_id}"))
|
||||
.append_pat(pat)
|
||||
@@ -499,7 +532,11 @@ impl ApiVersion for ApiV2 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn remove_version_file(&self, hash: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_version_file(
|
||||
&self,
|
||||
hash: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let request = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/version_file/{hash}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -34,7 +34,11 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_collection(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn get_collection(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v3/collection/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -42,13 +46,21 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_collection_deserialized(&self, id: &str, pat: Option<&str>) -> Collection {
|
||||
pub async fn get_collection_deserialized(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Collection {
|
||||
let resp = self.get_collection(id, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_collections(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn get_collections(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids = serde_json::to_string(ids).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -60,7 +72,11 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_collection_projects(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn get_collection_projects(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/collection/{id}/projects"))
|
||||
.append_pat(pat)
|
||||
@@ -122,7 +138,11 @@ impl ApiV3 {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_collection(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn delete_collection(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/collection/{id}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -28,8 +28,11 @@ pub struct ApiV3 {
|
||||
#[async_trait(?Send)]
|
||||
impl ApiBuildable for ApiV3 {
|
||||
async fn build(labrinth_config: LabrinthConfig) -> Self {
|
||||
let app = App::new().configure(|cfg| labrinth::app_config(cfg, labrinth_config.clone()));
|
||||
let test_app: Rc<dyn LocalService> = Rc::new(test::init_service(app).await);
|
||||
let app = App::new().configure(|cfg| {
|
||||
labrinth::app_config(cfg, labrinth_config.clone())
|
||||
});
|
||||
let test_app: Rc<dyn LocalService> =
|
||||
Rc::new(test::init_service(app).await);
|
||||
|
||||
Self { test_app }
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ use actix_web::{
|
||||
test::{self, TestRequest},
|
||||
};
|
||||
use labrinth::auth::oauth::{
|
||||
OAuthClientAccessRequest, RespondToOAuthClientScopes, TokenRequest, TokenResponse,
|
||||
OAuthClientAccessRequest, RespondToOAuthClientScopes, TokenRequest,
|
||||
TokenResponse,
|
||||
};
|
||||
use reqwest::header::{AUTHORIZATION, LOCATION};
|
||||
|
||||
@@ -32,7 +33,8 @@ impl ApiV3 {
|
||||
.await;
|
||||
let flow_id = get_authorize_accept_flow_id(auth_resp).await;
|
||||
let redirect_resp = self.oauth_accept(&flow_id, user_pat).await;
|
||||
let auth_code = get_auth_code_from_redirect_params(&redirect_resp).await;
|
||||
let auth_code =
|
||||
get_auth_code_from_redirect_params(&redirect_resp).await;
|
||||
let token_resp = self
|
||||
.oauth_token(auth_code, None, client_id.to_string(), client_secret)
|
||||
.await;
|
||||
@@ -52,7 +54,11 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn oauth_accept(&self, flow: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn oauth_accept(
|
||||
&self,
|
||||
flow: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
self.call(
|
||||
TestRequest::post()
|
||||
.uri("/_internal/oauth/accept")
|
||||
@@ -65,7 +71,11 @@ impl ApiV3 {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn oauth_reject(&self, flow: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn oauth_reject(
|
||||
&self,
|
||||
flow: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
self.call(
|
||||
TestRequest::post()
|
||||
.uri("/_internal/oauth/reject")
|
||||
@@ -93,7 +103,11 @@ impl ApiV3 {
|
||||
grant_type: "authorization_code".to_string(),
|
||||
code: auth_code,
|
||||
redirect_uri: original_redirect_uri,
|
||||
client_id: serde_json::from_str(&format!("\"{}\"", client_id)).unwrap(),
|
||||
client_id: serde_json::from_str(&format!(
|
||||
"\"{}\"",
|
||||
client_id
|
||||
))
|
||||
.unwrap(),
|
||||
})
|
||||
.to_request(),
|
||||
)
|
||||
@@ -123,7 +137,9 @@ pub async fn get_authorize_accept_flow_id(response: ServiceResponse) -> String {
|
||||
.flow_id
|
||||
}
|
||||
|
||||
pub async fn get_auth_code_from_redirect_params(response: &ServiceResponse) -> String {
|
||||
pub async fn get_auth_code_from_redirect_params(
|
||||
response: &ServiceResponse,
|
||||
) -> String {
|
||||
assert_status!(response, StatusCode::OK);
|
||||
let query_params = get_redirect_location_query_params(response);
|
||||
query_params.get("code").unwrap().to_string()
|
||||
|
||||
@@ -56,7 +56,11 @@ impl ApiV3 {
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_oauth_client(&self, client_id: String, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn get_oauth_client(
|
||||
&self,
|
||||
client_id: String,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/_internal/oauth/app/{}", client_id))
|
||||
.append_pat(pat)
|
||||
@@ -83,7 +87,11 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn delete_oauth_client(&self, client_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn delete_oauth_client(
|
||||
&self,
|
||||
client_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::delete()
|
||||
.uri(&format!("/_internal/oauth/app/{}", client_id))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -4,7 +4,9 @@ use actix_web::{
|
||||
test::{self, TestRequest},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use labrinth::models::{organizations::Organization, users::UserId, v3::projects::Project};
|
||||
use labrinth::models::{
|
||||
organizations::Organization, users::UserId, v3::projects::Project,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
@@ -34,7 +36,11 @@ impl ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_organization(&self, id_or_title: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
pub async fn get_organization(
|
||||
&self,
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v3/organization/{id_or_title}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -43,7 +43,8 @@ impl ApiProject for ApiV3 {
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
pat: Option<&str>,
|
||||
) -> (CommonProject, Vec<CommonVersion>) {
|
||||
let creation_data = get_public_project_creation_data(slug, version_jar, modify_json);
|
||||
let creation_data =
|
||||
get_public_project_creation_data(slug, version_jar, modify_json);
|
||||
|
||||
// Add a project.
|
||||
let slug = creation_data.slug.clone();
|
||||
@@ -98,7 +99,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn remove_project(&self, project_slug_or_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_project(
|
||||
&self,
|
||||
project_slug_or_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/project/{project_slug_or_id}"))
|
||||
.append_pat(pat)
|
||||
@@ -107,7 +112,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_project(&self, id_or_slug: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_project(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v3/project/{id_or_slug}"))
|
||||
.append_pat(pat)
|
||||
@@ -129,7 +138,11 @@ impl ApiProject for ApiV3 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_projects(&self, ids_or_slugs: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_projects(
|
||||
&self,
|
||||
ids_or_slugs: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_or_slugs = serde_json::to_string(ids_or_slugs).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -279,7 +292,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_reports(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_reports(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_str = serde_json::to_string(ids).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -316,7 +333,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_report(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/report/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -414,7 +435,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_threads(&self, ids: &[&str], pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_threads(
|
||||
&self,
|
||||
ids: &[&str],
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids_str = serde_json::to_string(ids).unwrap();
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!(
|
||||
@@ -457,7 +482,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn read_thread(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn read_thread(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v3/thread/{id}/read"))
|
||||
.append_pat(pat)
|
||||
@@ -466,7 +495,11 @@ impl ApiProject for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_thread_message(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_thread_message(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/message/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -477,7 +510,11 @@ impl ApiProject for ApiV3 {
|
||||
}
|
||||
|
||||
impl ApiV3 {
|
||||
pub async fn get_project_deserialized(&self, id_or_slug: &str, pat: Option<&str>) -> Project {
|
||||
pub async fn get_project_deserialized(
|
||||
&self,
|
||||
id_or_slug: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Project {
|
||||
let resp = self.get_project(id_or_slug, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
@@ -543,11 +580,13 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let pv_string = if ids_are_version_ids {
|
||||
let version_string: String = serde_json::to_string(&id_or_slugs).unwrap();
|
||||
let version_string: String =
|
||||
serde_json::to_string(&id_or_slugs).unwrap();
|
||||
let version_string = urlencoding::encode(&version_string);
|
||||
format!("version_ids={}", version_string)
|
||||
} else {
|
||||
let projects_string: String = serde_json::to_string(&id_or_slugs).unwrap();
|
||||
let projects_string: String =
|
||||
serde_json::to_string(&id_or_slugs).unwrap();
|
||||
let projects_string = urlencoding::encode(&projects_string);
|
||||
format!("project_ids={}", projects_string)
|
||||
};
|
||||
@@ -566,7 +605,10 @@ impl ApiV3 {
|
||||
extra_args.push_str(&format!("&end_date={end_date}"));
|
||||
}
|
||||
if let Some(resolution_minutes) = resolution_minutes {
|
||||
extra_args.push_str(&format!("&resolution_minutes={}", resolution_minutes));
|
||||
extra_args.push_str(&format!(
|
||||
"&resolution_minutes={}",
|
||||
resolution_minutes
|
||||
));
|
||||
}
|
||||
|
||||
let req = test::TestRequest::get()
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::{
|
||||
api_common::request_data::{ProjectCreationRequestData, VersionCreationRequestData},
|
||||
api_common::request_data::{
|
||||
ProjectCreationRequestData, VersionCreationRequestData,
|
||||
},
|
||||
dummy_data::TestFile,
|
||||
};
|
||||
use labrinth::{
|
||||
@@ -15,11 +17,13 @@ pub fn get_public_project_creation_data(
|
||||
version_jar: Option<TestFile>,
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
) -> ProjectCreationRequestData {
|
||||
let mut json_data = get_public_project_creation_data_json(slug, version_jar.as_ref());
|
||||
let mut json_data =
|
||||
get_public_project_creation_data_json(slug, version_jar.as_ref());
|
||||
if let Some(modify_json) = modify_json {
|
||||
json_patch::patch(&mut json_data, &modify_json).unwrap();
|
||||
}
|
||||
let multipart_data = get_public_creation_data_multipart(&json_data, version_jar.as_ref());
|
||||
let multipart_data =
|
||||
get_public_creation_data_multipart(&json_data, version_jar.as_ref());
|
||||
ProjectCreationRequestData {
|
||||
slug: slug.to_string(),
|
||||
jar: version_jar,
|
||||
@@ -36,14 +40,18 @@ pub fn get_public_version_creation_data(
|
||||
// and modifies it before it is serialized and sent
|
||||
modify_json: Option<json_patch::Patch>,
|
||||
) -> VersionCreationRequestData {
|
||||
let mut json_data =
|
||||
get_public_version_creation_data_json(version_number, ordering, &version_jar);
|
||||
let mut json_data = get_public_version_creation_data_json(
|
||||
version_number,
|
||||
ordering,
|
||||
&version_jar,
|
||||
);
|
||||
json_data["project_id"] = json!(project_id);
|
||||
if let Some(modify_json) = modify_json {
|
||||
json_patch::patch(&mut json_data, &modify_json).unwrap();
|
||||
}
|
||||
|
||||
let multipart_data = get_public_creation_data_multipart(&json_data, Some(&version_jar));
|
||||
let multipart_data =
|
||||
get_public_creation_data_multipart(&json_data, Some(&version_jar));
|
||||
VersionCreationRequestData {
|
||||
version: version_number.to_string(),
|
||||
jar: Some(version_jar),
|
||||
@@ -116,7 +124,9 @@ pub fn get_public_creation_data_multipart(
|
||||
name: "data".to_string(),
|
||||
filename: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(json_data).unwrap()),
|
||||
data: MultipartSegmentData::Text(
|
||||
serde_json::to_string(json_data).unwrap(),
|
||||
),
|
||||
};
|
||||
|
||||
if let Some(jar) = version_jar {
|
||||
|
||||
@@ -6,7 +6,8 @@ use actix_web::{
|
||||
use async_trait::async_trait;
|
||||
use labrinth::routes::v3::tags::{GameData, LoaderData};
|
||||
use labrinth::{
|
||||
database::models::loader_fields::LoaderFieldEnumValue, routes::v3::tags::CategoryData,
|
||||
database::models::loader_fields::LoaderFieldEnumValue,
|
||||
routes::v3::tags::CategoryData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -50,7 +51,9 @@ impl ApiTags for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_categories_deserialized_common(&self) -> Vec<CommonCategoryData> {
|
||||
async fn get_categories_deserialized_common(
|
||||
&self,
|
||||
) -> Vec<CommonCategoryData> {
|
||||
let resp = self.get_categories().await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
@@ -68,7 +71,10 @@ impl ApiV3 {
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_loader_field_variants(&self, loader_field: &str) -> ServiceResponse {
|
||||
pub async fn get_loader_field_variants(
|
||||
&self,
|
||||
loader_field: &str,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v3/loader_field?loader_field={}", loader_field))
|
||||
.append_pat(ADMIN_USER_PAT)
|
||||
|
||||
@@ -51,7 +51,11 @@ impl ApiV3 {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl ApiTeams for ApiV3 {
|
||||
async fn get_team_members(&self, id_or_title: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_team_members(
|
||||
&self,
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/team/{id_or_title}/members"))
|
||||
.append_pat(pat)
|
||||
@@ -89,7 +93,11 @@ impl ApiTeams for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_project_members(&self, id_or_title: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_project_members(
|
||||
&self,
|
||||
id_or_title: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/project/{id_or_title}/members"))
|
||||
.append_pat(pat)
|
||||
@@ -137,7 +145,11 @@ impl ApiTeams for ApiV3 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn join_team(&self, team_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn join_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v3/team/{team_id}/join"))
|
||||
.append_pat(pat)
|
||||
@@ -189,7 +201,11 @@ impl ApiTeams for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_user_notifications(&self, user_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_user_notifications(
|
||||
&self,
|
||||
user_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/user/{user_id}/notifications"))
|
||||
.append_pat(pat)
|
||||
@@ -211,7 +227,11 @@ impl ApiTeams for ApiV3 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_notification(&self, notification_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_notification(
|
||||
&self,
|
||||
notification_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/notification/{notification_id}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -7,7 +7,11 @@ use super::ApiV3;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl ApiUser for ApiV3 {
|
||||
async fn get_user(&self, user_id_or_username: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_user(
|
||||
&self,
|
||||
user_id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v3/user/{}", user_id_or_username))
|
||||
.append_pat(pat)
|
||||
@@ -38,7 +42,11 @@ impl ApiUser for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn delete_user(&self, user_id_or_username: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn delete_user(
|
||||
&self,
|
||||
user_id_or_username: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/user/{}", user_id_or_username))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -7,7 +7,9 @@ use super::{
|
||||
use crate::{
|
||||
assert_status,
|
||||
common::{
|
||||
api_common::{models::CommonVersion, Api, ApiVersion, AppendsOptionalPat},
|
||||
api_common::{
|
||||
models::CommonVersion, Api, ApiVersion, AppendsOptionalPat,
|
||||
},
|
||||
dummy_data::TestFile,
|
||||
},
|
||||
};
|
||||
@@ -60,7 +62,11 @@ impl ApiV3 {
|
||||
test::read_body_json(version).await
|
||||
}
|
||||
|
||||
pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> Version {
|
||||
pub async fn get_version_deserialized(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> Version {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
@@ -160,7 +166,11 @@ impl ApiVersion for ApiV3 {
|
||||
serde_json::from_value(value).unwrap()
|
||||
}
|
||||
|
||||
async fn get_version(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_version(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v3/version/{id}"))
|
||||
.append_pat(pat)
|
||||
@@ -168,7 +178,11 @@ impl ApiVersion for ApiV3 {
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion {
|
||||
async fn get_version_deserialized_common(
|
||||
&self,
|
||||
id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
@@ -288,7 +302,8 @@ impl ApiVersion for ApiV3 {
|
||||
});
|
||||
}
|
||||
if let Some(version_types) = version_types {
|
||||
json["version_types"] = serde_json::to_value(version_types).unwrap();
|
||||
json["version_types"] =
|
||||
serde_json::to_value(version_types).unwrap();
|
||||
}
|
||||
|
||||
let req = test::TestRequest::post()
|
||||
@@ -311,7 +326,14 @@ impl ApiVersion for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self
|
||||
.get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat)
|
||||
.get_update_from_hash(
|
||||
hash,
|
||||
algorithm,
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types,
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
@@ -338,10 +360,12 @@ impl ApiVersion for ApiV3 {
|
||||
json["loaders"] = serde_json::to_value(loaders).unwrap();
|
||||
}
|
||||
if let Some(game_versions) = game_versions {
|
||||
json["game_versions"] = serde_json::to_value(game_versions).unwrap();
|
||||
json["game_versions"] =
|
||||
serde_json::to_value(game_versions).unwrap();
|
||||
}
|
||||
if let Some(version_types) = version_types {
|
||||
json["version_types"] = serde_json::to_value(version_types).unwrap();
|
||||
json["version_types"] =
|
||||
serde_json::to_value(version_types).unwrap();
|
||||
}
|
||||
|
||||
let req = test::TestRequest::post()
|
||||
@@ -396,7 +420,9 @@ impl ApiVersion for ApiV3 {
|
||||
if let Some(game_versions) = game_versions {
|
||||
query_string.push_str(&format!(
|
||||
"&game_versions={}",
|
||||
urlencoding::encode(&serde_json::to_string(&game_versions).unwrap())
|
||||
urlencoding::encode(
|
||||
&serde_json::to_string(&game_versions).unwrap()
|
||||
)
|
||||
));
|
||||
}
|
||||
if let Some(loaders) = loaders {
|
||||
@@ -480,7 +506,11 @@ impl ApiVersion for ApiV3 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn get_versions(&self, version_ids: Vec<String>, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn get_versions(
|
||||
&self,
|
||||
version_ids: Vec<String>,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let ids = url_encode_json_serialized_vec(&version_ids);
|
||||
let request = test::TestRequest::get()
|
||||
.uri(&format!("/v3/versions?ids={}", ids))
|
||||
@@ -526,7 +556,11 @@ impl ApiVersion for ApiV3 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn remove_version(&self, version_id: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_version(
|
||||
&self,
|
||||
version_id: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let request = test::TestRequest::delete()
|
||||
.uri(&format!(
|
||||
"/v3/version/{version_id}",
|
||||
@@ -537,7 +571,11 @@ impl ApiVersion for ApiV3 {
|
||||
self.call(request).await
|
||||
}
|
||||
|
||||
async fn remove_version_file(&self, hash: &str, pat: Option<&str>) -> ServiceResponse {
|
||||
async fn remove_version_file(
|
||||
&self,
|
||||
hash: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
let request = test::TestRequest::delete()
|
||||
.uri(&format!("/v3/version_file/{hash}"))
|
||||
.append_pat(pat)
|
||||
|
||||
@@ -38,7 +38,10 @@ pub fn assert_version_ids(versions: &[Version], expected_ids: Vec<String>) {
|
||||
assert_eq!(version_ids, expected_ids);
|
||||
}
|
||||
|
||||
pub fn assert_common_version_ids(versions: &[CommonVersion], expected_ids: Vec<String>) {
|
||||
pub fn assert_common_version_ids(
|
||||
versions: &[CommonVersion],
|
||||
expected_ids: Vec<String>,
|
||||
) {
|
||||
let version_ids = versions
|
||||
.iter()
|
||||
.map(|v| get_json_val_str(v.id))
|
||||
|
||||
@@ -55,13 +55,15 @@ impl TemporaryDatabase {
|
||||
let temp_database_name = generate_random_name("labrinth_tests_db_");
|
||||
println!("Creating temporary database: {}", &temp_database_name);
|
||||
|
||||
let database_url = dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
let database_url =
|
||||
dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
|
||||
// Create the temporary (and template datbase, if needed)
|
||||
Self::create_temporary(&database_url, &temp_database_name).await;
|
||||
|
||||
// Pool to the temporary database
|
||||
let mut temporary_url = Url::parse(&database_url).expect("Invalid database URL");
|
||||
let mut temporary_url =
|
||||
Url::parse(&database_url).expect("Invalid database URL");
|
||||
|
||||
temporary_url.set_path(&format!("/{}", &temp_database_name));
|
||||
let temp_db_url = temporary_url.to_string();
|
||||
@@ -86,7 +88,8 @@ impl TemporaryDatabase {
|
||||
let redis_pool = RedisPool::new(Some(temp_database_name.clone()));
|
||||
|
||||
// Create new meilisearch config
|
||||
let search_config = search::SearchConfig::new(Some(temp_database_name.clone()));
|
||||
let search_config =
|
||||
search::SearchConfig::new(Some(temp_database_name.clone()));
|
||||
Self {
|
||||
pool,
|
||||
database_name: temp_database_name,
|
||||
@@ -110,10 +113,11 @@ impl TemporaryDatabase {
|
||||
|
||||
loop {
|
||||
// Try to acquire an advisory lock
|
||||
let lock_acquired: bool = sqlx::query_scalar("SELECT pg_try_advisory_lock(1)")
|
||||
.fetch_one(&main_pool)
|
||||
.await
|
||||
.unwrap();
|
||||
let lock_acquired: bool =
|
||||
sqlx::query_scalar("SELECT pg_try_advisory_lock(1)")
|
||||
.fetch_one(&main_pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if lock_acquired {
|
||||
// Create the db template if it doesn't exist
|
||||
@@ -129,8 +133,10 @@ impl TemporaryDatabase {
|
||||
}
|
||||
|
||||
// Switch to template
|
||||
let url = dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
let mut template_url = Url::parse(&url).expect("Invalid database URL");
|
||||
let url =
|
||||
dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
let mut template_url =
|
||||
Url::parse(&url).expect("Invalid database URL");
|
||||
template_url.set_path(&format!("/{}", TEMPLATE_DATABASE_NAME));
|
||||
|
||||
let pool = PgPool::connect(template_url.as_str())
|
||||
@@ -138,19 +144,22 @@ impl TemporaryDatabase {
|
||||
.expect("Connection to database failed");
|
||||
|
||||
// Check if dummy data exists- a fake 'dummy_data' table is created if it does
|
||||
let mut dummy_data_exists: bool =
|
||||
sqlx::query_scalar("SELECT to_regclass('dummy_data') IS NOT NULL")
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut dummy_data_exists: bool = sqlx::query_scalar(
|
||||
"SELECT to_regclass('dummy_data') IS NOT NULL",
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
if dummy_data_exists {
|
||||
// Check if the dummy data needs to be updated
|
||||
let dummy_data_update =
|
||||
sqlx::query_scalar::<_, i64>("SELECT update_id FROM dummy_data")
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
let needs_update = !dummy_data_update.is_some_and(|d| d == DUMMY_DATA_UPDATE);
|
||||
let dummy_data_update = sqlx::query_scalar::<_, i64>(
|
||||
"SELECT update_id FROM dummy_data",
|
||||
)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
let needs_update = !dummy_data_update
|
||||
.is_some_and(|d| d == DUMMY_DATA_UPDATE);
|
||||
if needs_update {
|
||||
println!("Dummy data updated, so template DB tables will be dropped and re-created");
|
||||
// Drop all tables in the database so they can be re-created and later filled with updated dummy data
|
||||
@@ -179,7 +188,8 @@ impl TemporaryDatabase {
|
||||
redis_pool: RedisPool::new(Some(name.clone())),
|
||||
search_config: search::SearchConfig::new(Some(name)),
|
||||
};
|
||||
let setup_api = TestEnvironment::<ApiV3>::build_setup_api(&db).await;
|
||||
let setup_api =
|
||||
TestEnvironment::<ApiV3>::build_setup_api(&db).await;
|
||||
dummy_data::add_dummy_data(&setup_api, db.clone()).await;
|
||||
db.pool.close().await;
|
||||
}
|
||||
@@ -215,7 +225,8 @@ impl TemporaryDatabase {
|
||||
// If a temporary db is created, it must be cleaned up with cleanup.
|
||||
// This means that dbs will only 'remain' if a test fails (for examination of the db), and will be cleaned up otherwise.
|
||||
pub async fn cleanup(mut self) {
|
||||
let database_url = dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
let database_url =
|
||||
dotenvy::var("DATABASE_URL").expect("No database URL");
|
||||
self.pool.close().await;
|
||||
|
||||
self.pool = PgPool::connect(&database_url)
|
||||
@@ -234,7 +245,8 @@ impl TemporaryDatabase {
|
||||
.unwrap();
|
||||
|
||||
// Execute the deletion query asynchronously
|
||||
let drop_db_query = format!("DROP DATABASE IF EXISTS {}", &self.database_name);
|
||||
let drop_db_query =
|
||||
format!("DROP DATABASE IF EXISTS {}", &self.database_name);
|
||||
sqlx::query(&drop_db_query)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
|
||||
@@ -98,14 +98,16 @@ impl TestFile {
|
||||
let mut zip = ZipWriter::new(&mut cursor);
|
||||
zip.start_file(
|
||||
"fabric.mod.json",
|
||||
FileOptions::default().compression_method(CompressionMethod::Stored),
|
||||
FileOptions::default()
|
||||
.compression_method(CompressionMethod::Stored),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(fabric_mod_json.as_bytes()).unwrap();
|
||||
|
||||
zip.start_file(
|
||||
"META-INF/mods.toml",
|
||||
FileOptions::default().compression_method(CompressionMethod::Stored),
|
||||
FileOptions::default()
|
||||
.compression_method(CompressionMethod::Stored),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(fabric_mod_json.as_bytes()).unwrap();
|
||||
@@ -118,7 +120,8 @@ impl TestFile {
|
||||
}
|
||||
|
||||
pub fn build_random_mrpack() -> Self {
|
||||
let filename = format!("random-modpack-{}.mrpack", rand::random::<u64>());
|
||||
let filename =
|
||||
format!("random-modpack-{}.mrpack", rand::random::<u64>());
|
||||
|
||||
let modrinth_index_json = serde_json::json!({
|
||||
"formatVersion": 1,
|
||||
@@ -156,7 +159,8 @@ impl TestFile {
|
||||
let mut zip = ZipWriter::new(&mut cursor);
|
||||
zip.start_file(
|
||||
"modrinth.index.json",
|
||||
FileOptions::default().compression_method(CompressionMethod::Stored),
|
||||
FileOptions::default()
|
||||
.compression_method(CompressionMethod::Stored),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(modrinth_index_json.as_bytes()).unwrap();
|
||||
@@ -217,7 +221,8 @@ impl DummyData {
|
||||
project_id_parsed: project_alpha.id,
|
||||
version_id: project_alpha_version.id.to_string(),
|
||||
thread_id: project_alpha.thread_id.to_string(),
|
||||
file_hash: project_alpha_version.files[0].hashes["sha1"].clone(),
|
||||
file_hash: project_alpha_version.files[0].hashes["sha1"]
|
||||
.clone(),
|
||||
},
|
||||
|
||||
project_beta: DummyProjectBeta {
|
||||
@@ -349,7 +354,10 @@ pub async fn add_project_alpha(api: &ApiV3) -> (Project, Version) {
|
||||
)
|
||||
.await;
|
||||
let alpha_project = api
|
||||
.get_project_deserialized(project.id.to_string().as_str(), USER_USER_PAT)
|
||||
.get_project_deserialized(
|
||||
project.id.to_string().as_str(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let alpha_version = api
|
||||
.get_version_deserialized(
|
||||
@@ -484,15 +492,22 @@ impl TestFile {
|
||||
pub fn bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
TestFile::DummyProjectAlpha => {
|
||||
include_bytes!("../../tests/files/dummy-project-alpha.jar").to_vec()
|
||||
include_bytes!("../../tests/files/dummy-project-alpha.jar")
|
||||
.to_vec()
|
||||
}
|
||||
TestFile::DummyProjectBeta => {
|
||||
include_bytes!("../../tests/files/dummy-project-beta.jar").to_vec()
|
||||
include_bytes!("../../tests/files/dummy-project-beta.jar")
|
||||
.to_vec()
|
||||
}
|
||||
TestFile::BasicMod => {
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec()
|
||||
}
|
||||
TestFile::BasicZip => {
|
||||
include_bytes!("../../tests/files/simple-zip.zip").to_vec()
|
||||
}
|
||||
TestFile::BasicMod => include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
TestFile::BasicZip => include_bytes!("../../tests/files/simple-zip.zip").to_vec(),
|
||||
TestFile::BasicModDifferent => {
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec()
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar")
|
||||
.to_vec()
|
||||
}
|
||||
TestFile::BasicModRandom { bytes, .. } => bytes.clone(),
|
||||
TestFile::BasicModpackRandom { bytes, .. } => bytes.clone(),
|
||||
@@ -524,7 +539,9 @@ impl TestFile {
|
||||
|
||||
TestFile::BasicZip => Some("application/zip"),
|
||||
|
||||
TestFile::BasicModpackRandom { .. } => Some("application/x-modrinth-modpack+zip"),
|
||||
TestFile::BasicModpackRandom { .. } => {
|
||||
Some("application/x-modrinth-modpack+zip")
|
||||
}
|
||||
}
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
@@ -547,7 +564,9 @@ impl DummyImage {
|
||||
|
||||
pub fn bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
DummyImage::SmallIcon => include_bytes!("../../tests/files/200x200.png").to_vec(),
|
||||
DummyImage::SmallIcon => {
|
||||
include_bytes!("../../tests/files/200x200.png").to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,19 +19,23 @@ pub async fn with_test_environment<Fut, A>(
|
||||
Fut: Future<Output = ()>,
|
||||
A: ApiBuildable + 'static,
|
||||
{
|
||||
let test_env: TestEnvironment<A> = TestEnvironment::build(max_connections).await;
|
||||
let test_env: TestEnvironment<A> =
|
||||
TestEnvironment::build(max_connections).await;
|
||||
let db = test_env.db.clone();
|
||||
f(test_env).await;
|
||||
db.cleanup().await;
|
||||
}
|
||||
|
||||
pub async fn with_test_environment_all<Fut, F>(max_connections: Option<u32>, f: F)
|
||||
where
|
||||
pub async fn with_test_environment_all<Fut, F>(
|
||||
max_connections: Option<u32>,
|
||||
f: F,
|
||||
) where
|
||||
Fut: Future<Output = ()>,
|
||||
F: Fn(TestEnvironment<GenericApi>) -> Fut,
|
||||
{
|
||||
println!("Test environment: API v3");
|
||||
let test_env_api_v3 = TestEnvironment::<ApiV3>::build(max_connections).await;
|
||||
let test_env_api_v3 =
|
||||
TestEnvironment::<ApiV3>::build(max_connections).await;
|
||||
let test_env_api_v3 = TestEnvironment {
|
||||
db: test_env_api_v3.db.clone(),
|
||||
api: GenericApi::V3(test_env_api_v3.api),
|
||||
@@ -43,7 +47,8 @@ where
|
||||
db.cleanup().await;
|
||||
|
||||
println!("Test environment: API v2");
|
||||
let test_env_api_v2 = TestEnvironment::<ApiV2>::build(max_connections).await;
|
||||
let test_env_api_v2 =
|
||||
TestEnvironment::<ApiV2>::build(max_connections).await;
|
||||
let test_env_api_v2 = TestEnvironment {
|
||||
db: test_env_api_v2.db.clone(),
|
||||
api: GenericApi::V2(test_env_api_v2.api),
|
||||
@@ -139,7 +144,11 @@ pub trait LocalService {
|
||||
&self,
|
||||
req: actix_http::Request,
|
||||
) -> std::pin::Pin<
|
||||
Box<dyn std::future::Future<Output = Result<ServiceResponse, actix_web::Error>>>,
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = Result<ServiceResponse, actix_web::Error>,
|
||||
>,
|
||||
>,
|
||||
>;
|
||||
}
|
||||
impl<S> LocalService for S
|
||||
@@ -155,7 +164,11 @@ where
|
||||
&self,
|
||||
req: actix_http::Request,
|
||||
) -> std::pin::Pin<
|
||||
Box<dyn std::future::Future<Output = Result<ServiceResponse, actix_web::Error>>>,
|
||||
Box<
|
||||
dyn std::future::Future<
|
||||
Output = Result<ServiceResponse, actix_web::Error>,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
Box::pin(self.call(req))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig {
|
||||
Arc::new(file_hosting::MockHost::new());
|
||||
let mut clickhouse = clickhouse::init_client().await.unwrap();
|
||||
|
||||
let maxmind_reader = Arc::new(queue::maxmind::MaxMindIndexer::new().await.unwrap());
|
||||
let maxmind_reader =
|
||||
Arc::new(queue::maxmind::MaxMindIndexer::new().await.unwrap());
|
||||
|
||||
labrinth::app_setup(
|
||||
pool.clone(),
|
||||
|
||||
@@ -11,7 +11,11 @@ use super::database::TemporaryDatabase;
|
||||
// Creates a PAT with the given scopes, and returns the access token
|
||||
// Interfacing with the db directly, rather than using a ourte,
|
||||
// allows us to test with scopes that are not allowed to be created by PATs
|
||||
pub async fn create_test_pat(scopes: Scopes, user_id: i64, db: &TemporaryDatabase) -> String {
|
||||
pub async fn create_test_pat(
|
||||
scopes: Scopes,
|
||||
user_id: i64,
|
||||
db: &TemporaryDatabase,
|
||||
) -> String {
|
||||
let mut transaction = db.pool.begin().await.unwrap();
|
||||
let id = generate_pat_id(&mut transaction).await.unwrap();
|
||||
let pat = database::models::pat_item::PersonalAccessToken {
|
||||
|
||||
@@ -97,7 +97,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
failure_organization_permissions: Option<OrganizationPermissions>,
|
||||
) -> Self {
|
||||
self.failure_project_permissions = failure_project_permissions;
|
||||
self.failure_organization_permissions = failure_organization_permissions;
|
||||
self.failure_organization_permissions =
|
||||
failure_organization_permissions;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -136,19 +137,28 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
mut self,
|
||||
allowed_failure_codes: impl IntoIterator<Item = u16>,
|
||||
) -> Self {
|
||||
self.allowed_failure_codes = allowed_failure_codes.into_iter().collect();
|
||||
self.allowed_failure_codes =
|
||||
allowed_failure_codes.into_iter().collect();
|
||||
self
|
||||
}
|
||||
|
||||
// If an existing project or organization is intended to be used
|
||||
// We will not create a new project, and will use the given project ID
|
||||
// (But will still add the user to the project's team)
|
||||
pub fn with_existing_project(mut self, project_id: &str, team_id: &str) -> Self {
|
||||
pub fn with_existing_project(
|
||||
mut self,
|
||||
project_id: &str,
|
||||
team_id: &str,
|
||||
) -> Self {
|
||||
self.project_id = Some(project_id.to_string());
|
||||
self.project_team_id = Some(team_id.to_string());
|
||||
self
|
||||
}
|
||||
pub fn with_existing_organization(mut self, organization_id: &str, team_id: &str) -> Self {
|
||||
pub fn with_existing_organization(
|
||||
mut self,
|
||||
organization_id: &str,
|
||||
team_id: &str,
|
||||
) -> Self {
|
||||
self.organization_id = Some(organization_id.to_string());
|
||||
self.organization_team_id = Some(team_id.to_string());
|
||||
self
|
||||
@@ -176,14 +186,15 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
organization_team_id: None,
|
||||
};
|
||||
|
||||
let (project_id, team_id) = if self.project_id.is_some() && self.project_team_id.is_some() {
|
||||
(
|
||||
self.project_id.clone().unwrap(),
|
||||
self.project_team_id.clone().unwrap(),
|
||||
)
|
||||
} else {
|
||||
create_dummy_project(&test_env.setup_api).await
|
||||
};
|
||||
let (project_id, team_id) =
|
||||
if self.project_id.is_some() && self.project_team_id.is_some() {
|
||||
(
|
||||
self.project_id.clone().unwrap(),
|
||||
self.project_team_id.clone().unwrap(),
|
||||
)
|
||||
} else {
|
||||
create_dummy_project(&test_env.setup_api).await
|
||||
};
|
||||
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
@@ -299,7 +310,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// If the remove_user flag is set, remove the user from the project
|
||||
// Relevant for existing projects/users
|
||||
if self.remove_user {
|
||||
remove_user_from_team(self.user_id, &team_id, &test_env.setup_api).await;
|
||||
remove_user_from_team(self.user_id, &team_id, &test_env.setup_api)
|
||||
.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -326,15 +338,16 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
organization_team_id: None,
|
||||
};
|
||||
|
||||
let (organization_id, team_id) =
|
||||
if self.organization_id.is_some() && self.organization_team_id.is_some() {
|
||||
(
|
||||
self.organization_id.clone().unwrap(),
|
||||
self.organization_team_id.clone().unwrap(),
|
||||
)
|
||||
} else {
|
||||
create_dummy_org(&test_env.setup_api).await
|
||||
};
|
||||
let (organization_id, team_id) = if self.organization_id.is_some()
|
||||
&& self.organization_team_id.is_some()
|
||||
{
|
||||
(
|
||||
self.organization_id.clone().unwrap(),
|
||||
self.organization_team_id.clone().unwrap(),
|
||||
)
|
||||
} else {
|
||||
create_dummy_org(&test_env.setup_api).await
|
||||
};
|
||||
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
@@ -395,7 +408,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// If the remove_user flag is set, remove the user from the organization
|
||||
// Relevant for existing projects/users
|
||||
if self.remove_user {
|
||||
remove_user_from_team(self.user_id, &team_id, &test_env.setup_api).await;
|
||||
remove_user_from_team(self.user_id, &team_id, &test_env.setup_api)
|
||||
.await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -426,7 +440,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// This should always fail, regardless of permissions
|
||||
// (As we are testing permissions-based failures)
|
||||
let test_1 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
|
||||
let resp = req_gen(PermissionsTestContext {
|
||||
test_pat: None,
|
||||
@@ -466,7 +481,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// TEST 2: Failure
|
||||
// Random user, unaffiliated with the project, with no permissions
|
||||
let test_2 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
|
||||
let resp = req_gen(PermissionsTestContext {
|
||||
test_pat: self.user_pat.map(|s| s.to_string()),
|
||||
@@ -506,7 +522,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// TEST 3: Failure
|
||||
// User affiliated with the project, with failure permissions
|
||||
let test_3 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -555,7 +572,8 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// TEST 4: Success
|
||||
// User affiliated with the project, with the given permissions
|
||||
let test_4 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -601,10 +619,16 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// Project has an organization
|
||||
// User affiliated with the project's org, with default failure permissions
|
||||
let test_5 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
let (organization_id, organization_team_id) =
|
||||
create_dummy_org(&test_env.setup_api).await;
|
||||
add_project_to_org(&test_env.setup_api, &project_id, &organization_id).await;
|
||||
add_project_to_org(
|
||||
&test_env.setup_api,
|
||||
&project_id,
|
||||
&organization_id,
|
||||
)
|
||||
.await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -654,10 +678,16 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// Project has an organization
|
||||
// User affiliated with the project's org, with the default success
|
||||
let test_6 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
let (organization_id, organization_team_id) =
|
||||
create_dummy_org(&test_env.setup_api).await;
|
||||
add_project_to_org(&test_env.setup_api, &project_id, &organization_id).await;
|
||||
add_project_to_org(
|
||||
&test_env.setup_api,
|
||||
&project_id,
|
||||
&organization_id,
|
||||
)
|
||||
.await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -704,10 +734,16 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// User affiliated with the project's org (even can have successful permissions!)
|
||||
// User overwritten on the project team with failure permissions
|
||||
let test_7 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
let (organization_id, organization_team_id) =
|
||||
create_dummy_org(&test_env.setup_api).await;
|
||||
add_project_to_org(&test_env.setup_api, &project_id, &organization_id).await;
|
||||
add_project_to_org(
|
||||
&test_env.setup_api,
|
||||
&project_id,
|
||||
&organization_id,
|
||||
)
|
||||
.await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -767,10 +803,16 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
// User affiliated with the project's org with default failure permissions
|
||||
// User overwritten to the project with the success permissions
|
||||
let test_8 = async {
|
||||
let (project_id, team_id) = create_dummy_project(&test_env.setup_api).await;
|
||||
let (project_id, team_id) =
|
||||
create_dummy_project(&test_env.setup_api).await;
|
||||
let (organization_id, organization_team_id) =
|
||||
create_dummy_org(&test_env.setup_api).await;
|
||||
add_project_to_org(&test_env.setup_api, &project_id, &organization_id).await;
|
||||
add_project_to_org(
|
||||
&test_env.setup_api,
|
||||
&project_id,
|
||||
&organization_id,
|
||||
)
|
||||
.await;
|
||||
add_user_to_team(
|
||||
self.user_id,
|
||||
self.user_pat,
|
||||
@@ -822,8 +864,10 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
Ok(())
|
||||
};
|
||||
|
||||
tokio::try_join!(test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8)
|
||||
.map_err(|e| e)?;
|
||||
tokio::try_join!(
|
||||
test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8
|
||||
)
|
||||
.map_err(|e| e)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1012,7 +1056,12 @@ async fn create_dummy_org(setup_api: &ApiV3) -> (String, String) {
|
||||
let slug = generate_random_name("test_org");
|
||||
|
||||
let resp = setup_api
|
||||
.create_organization("Example org", &slug, "Example description.", ADMIN_USER_PAT)
|
||||
.create_organization(
|
||||
"Example org",
|
||||
&slug,
|
||||
"Example description.",
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
@@ -1025,7 +1074,11 @@ async fn create_dummy_org(setup_api: &ApiV3) -> (String, String) {
|
||||
(organizaion_id, team_id)
|
||||
}
|
||||
|
||||
async fn add_project_to_org(setup_api: &ApiV3, project_id: &str, organization_id: &str) {
|
||||
async fn add_project_to_org(
|
||||
setup_api: &ApiV3,
|
||||
project_id: &str,
|
||||
organization_id: &str,
|
||||
) {
|
||||
let resp = setup_api
|
||||
.organization_add_project(organization_id, project_id, ADMIN_USER_PAT)
|
||||
.await;
|
||||
@@ -1081,7 +1134,11 @@ async fn modify_user_team_permissions(
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
|
||||
async fn remove_user_from_team(user_id: &str, team_id: &str, setup_api: &ApiV3) {
|
||||
async fn remove_user_from_team(
|
||||
user_id: &str,
|
||||
team_id: &str,
|
||||
setup_api: &ApiV3,
|
||||
) {
|
||||
// Send invitation to user
|
||||
let resp = setup_api
|
||||
.remove_from_team(team_id, user_id, ADMIN_USER_PAT)
|
||||
@@ -1102,7 +1159,9 @@ async fn get_project_permissions(
|
||||
let organization_id = project.organization.map(|id| id.to_string());
|
||||
|
||||
let organization = match organization_id {
|
||||
Some(id) => Some(setup_api.get_organization_deserialized(&id, user_pat).await),
|
||||
Some(id) => {
|
||||
Some(setup_api.get_organization_deserialized(&id, user_pat).await)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
@@ -1117,7 +1176,10 @@ async fn get_project_permissions(
|
||||
let organization_members = match organization {
|
||||
Some(org) => Some(
|
||||
setup_api
|
||||
.get_team_members_deserialized(&org.team_id.to_string(), user_pat)
|
||||
.get_team_members_deserialized(
|
||||
&org.team_id.to_string(),
|
||||
user_pat,
|
||||
)
|
||||
.await,
|
||||
),
|
||||
None => None,
|
||||
|
||||
@@ -4,8 +4,8 @@ use futures::Future;
|
||||
use labrinth::models::pats::Scopes;
|
||||
|
||||
use super::{
|
||||
api_common::Api, database::USER_USER_ID_PARSED, environment::TestEnvironment,
|
||||
pats::create_test_pat,
|
||||
api_common::Api, database::USER_USER_ID_PARSED,
|
||||
environment::TestEnvironment, pats::create_test_pat,
|
||||
};
|
||||
|
||||
// A reusable test type that works for any scope test testing an endpoint that:
|
||||
@@ -74,10 +74,13 @@ impl<'a, A: Api> ScopeTest<'a, A> {
|
||||
.failure_scopes
|
||||
.unwrap_or(Scopes::all() ^ success_scopes);
|
||||
let access_token_all_others =
|
||||
create_test_pat(failure_scopes, self.user_id, &self.test_env.db).await;
|
||||
create_test_pat(failure_scopes, self.user_id, &self.test_env.db)
|
||||
.await;
|
||||
|
||||
// Create a PAT with the success scopes
|
||||
let access_token = create_test_pat(success_scopes, self.user_id, &self.test_env.db).await;
|
||||
let access_token =
|
||||
create_test_pat(success_scopes, self.user_id, &self.test_env.db)
|
||||
.await;
|
||||
|
||||
// Perform test twice, once with each PAT
|
||||
// the first time, we expect a 401 (or known failure code)
|
||||
|
||||
@@ -16,11 +16,14 @@ use crate::{
|
||||
|
||||
use super::{api_v3::ApiV3, environment::TestEnvironment};
|
||||
|
||||
pub async fn setup_search_projects(test_env: &TestEnvironment<ApiV3>) -> Arc<HashMap<u64, u64>> {
|
||||
pub async fn setup_search_projects(
|
||||
test_env: &TestEnvironment<ApiV3>,
|
||||
) -> Arc<HashMap<u64, u64>> {
|
||||
// Test setup and dummy data
|
||||
let api = &test_env.api;
|
||||
let test_name = test_env.db.database_name.clone();
|
||||
let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_organization_id =
|
||||
&test_env.dummy.organization_zeta.organization_id;
|
||||
|
||||
// Add dummy projects of various categories for searchability
|
||||
let mut project_creation_futures = vec![];
|
||||
@@ -39,7 +42,8 @@ pub async fn setup_search_projects(test_env: &TestEnvironment<ApiV3>) -> Arc<Has
|
||||
};
|
||||
async move {
|
||||
// Add a project- simple, should work.
|
||||
let req = api.add_public_project(&slug, Some(jar), modify_json, pat);
|
||||
let req =
|
||||
api.add_public_project(&slug, Some(jar), modify_json, pat);
|
||||
let (project, _) = req.await;
|
||||
|
||||
// Approve, so that the project is searchable
|
||||
|
||||
@@ -11,14 +11,17 @@ mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn error_404_body() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
// 3 errors should have 404 as non-blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_ne!(body, empty_bytes);
|
||||
})
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
// 3 errors should have 404 as non-blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_ne!(body, empty_bytes);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -9,18 +9,21 @@ mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_games() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = test_env.api;
|
||||
|
||||
let games = api.get_games_deserialized().await;
|
||||
let games = api.get_games_deserialized().await;
|
||||
|
||||
// There should be 2 games in the dummy data
|
||||
assert_eq!(games.len(), 2);
|
||||
assert_eq!(games[0].name, "minecraft-java");
|
||||
assert_eq!(games[1].name, "minecraft-bedrock");
|
||||
// There should be 2 games in the dummy data
|
||||
assert_eq!(games.len(), 2);
|
||||
assert_eq!(games[0].name, "minecraft-java");
|
||||
assert_eq!(games[1].name, "minecraft-bedrock");
|
||||
|
||||
assert_eq!(games[0].slug, "minecraft-java");
|
||||
assert_eq!(games[1].slug, "minecraft-bedrock");
|
||||
})
|
||||
assert_eq!(games[0].slug, "minecraft-java");
|
||||
assert_eq!(games[1].slug, "minecraft-bedrock");
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ use crate::common::api_common::{ApiProject, ApiVersion};
|
||||
use crate::common::api_v3::request_data::get_public_project_creation_data;
|
||||
use crate::common::database::*;
|
||||
|
||||
use crate::common::dummy_data::{DummyProjectAlpha, DummyProjectBeta, TestFile};
|
||||
use crate::common::dummy_data::{
|
||||
DummyProjectAlpha, DummyProjectBeta, TestFile,
|
||||
};
|
||||
|
||||
// importing common module.
|
||||
mod common;
|
||||
@@ -353,7 +355,10 @@ async fn creating_loader_fields() {
|
||||
.await;
|
||||
|
||||
let project = api
|
||||
.get_project_deserialized(&alpha_project_id.to_string(), USER_USER_PAT)
|
||||
.get_project_deserialized(
|
||||
&alpha_project_id.to_string(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(
|
||||
project.fields.get("game_versions").unwrap(),
|
||||
@@ -413,57 +418,60 @@ async fn get_loader_fields_variants() {
|
||||
async fn get_available_loader_fields() {
|
||||
// Get available loader fields for a given loader
|
||||
// (ie: which fields are relevant for 'fabric', etc)
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
|
||||
let fabric_loader_fields = loaders
|
||||
.iter()
|
||||
.find(|x| x.name == "fabric")
|
||||
.unwrap()
|
||||
.supported_fields
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
fabric_loader_fields,
|
||||
[
|
||||
"game_versions",
|
||||
"singleplayer",
|
||||
"client_and_server",
|
||||
"client_only",
|
||||
"server_only",
|
||||
"test_fabric_optional" // exists for testing
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
let fabric_loader_fields = loaders
|
||||
.iter()
|
||||
.find(|x| x.name == "fabric")
|
||||
.unwrap()
|
||||
.supported_fields
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
fabric_loader_fields,
|
||||
[
|
||||
"game_versions",
|
||||
"singleplayer",
|
||||
"client_and_server",
|
||||
"client_only",
|
||||
"server_only",
|
||||
"test_fabric_optional" // exists for testing
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let mrpack_loader_fields = loaders
|
||||
.iter()
|
||||
.find(|x| x.name == "mrpack")
|
||||
.unwrap()
|
||||
.supported_fields
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
mrpack_loader_fields,
|
||||
[
|
||||
"game_versions",
|
||||
"singleplayer",
|
||||
"client_and_server",
|
||||
"client_only",
|
||||
"server_only",
|
||||
// mrpack has all the general fields as well as this
|
||||
"mrpack_loaders"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
})
|
||||
let mrpack_loader_fields = loaders
|
||||
.iter()
|
||||
.find(|x| x.name == "mrpack")
|
||||
.unwrap()
|
||||
.supported_fields
|
||||
.clone()
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
mrpack_loader_fields,
|
||||
[
|
||||
"game_versions",
|
||||
"singleplayer",
|
||||
"client_and_server",
|
||||
"client_only",
|
||||
"server_only",
|
||||
// mrpack has all the general fields as well as this
|
||||
"mrpack_loaders"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -471,90 +479,100 @@ async fn get_available_loader_fields() {
|
||||
async fn test_multi_get_redis_cache() {
|
||||
// Ensures a multi-project get including both modpacks and mods ddoes not
|
||||
// incorrectly cache loader fields
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
// Create 5 modpacks
|
||||
let mut modpacks = Vec::new();
|
||||
for i in 0..5 {
|
||||
let slug = format!("test-modpack-{}", i);
|
||||
// Create 5 modpacks
|
||||
let mut modpacks = Vec::new();
|
||||
for i in 0..5 {
|
||||
let slug = format!("test-modpack-{}", i);
|
||||
|
||||
let creation_data = get_public_project_creation_data(
|
||||
&slug,
|
||||
Some(TestFile::build_random_mrpack()),
|
||||
None,
|
||||
);
|
||||
let resp = api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
modpacks.push(slug);
|
||||
}
|
||||
|
||||
// Create 5 mods
|
||||
let mut mods = Vec::new();
|
||||
for i in 0..5 {
|
||||
let slug = format!("test-mod-{}", i);
|
||||
|
||||
let creation_data =
|
||||
get_public_project_creation_data(&slug, Some(TestFile::build_random_jar()), None);
|
||||
let resp = api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
mods.push(slug);
|
||||
}
|
||||
|
||||
// Get all 10 projects
|
||||
let project_slugs = modpacks
|
||||
.iter()
|
||||
.map(|x| x.as_str())
|
||||
.chain(mods.iter().map(|x| x.as_str()))
|
||||
.collect_vec();
|
||||
let resp = api.get_projects(&project_slugs, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let projects: Vec<v3::projects::Project> = test::read_body_json(resp).await;
|
||||
assert_eq!(projects.len(), 10);
|
||||
|
||||
// Ensure all 5 modpacks have 'mrpack_loaders', and all 5 mods do not
|
||||
for project in projects.iter() {
|
||||
if modpacks.contains(project.slug.as_ref().unwrap()) {
|
||||
assert!(project.fields.contains_key("mrpack_loaders"));
|
||||
} else if mods.contains(project.slug.as_ref().unwrap()) {
|
||||
assert!(!project.fields.contains_key("mrpack_loaders"));
|
||||
} else {
|
||||
panic!("Unexpected project slug: {:?}", project.slug);
|
||||
let creation_data = get_public_project_creation_data(
|
||||
&slug,
|
||||
Some(TestFile::build_random_mrpack()),
|
||||
None,
|
||||
);
|
||||
let resp =
|
||||
api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
modpacks.push(slug);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a version from each project
|
||||
let version_ids_modpacks = projects
|
||||
.iter()
|
||||
.filter(|x| modpacks.contains(x.slug.as_ref().unwrap()))
|
||||
.map(|x| x.versions[0])
|
||||
.collect_vec();
|
||||
let version_ids_mods = projects
|
||||
.iter()
|
||||
.filter(|x| mods.contains(x.slug.as_ref().unwrap()))
|
||||
.map(|x| x.versions[0])
|
||||
.collect_vec();
|
||||
let version_ids = version_ids_modpacks
|
||||
.iter()
|
||||
.chain(version_ids_mods.iter())
|
||||
.map(|x| x.to_string())
|
||||
.collect_vec();
|
||||
let resp = api.get_versions(version_ids, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let versions: Vec<v3::projects::Version> = test::read_body_json(resp).await;
|
||||
assert_eq!(versions.len(), 10);
|
||||
// Create 5 mods
|
||||
let mut mods = Vec::new();
|
||||
for i in 0..5 {
|
||||
let slug = format!("test-mod-{}", i);
|
||||
|
||||
// Ensure all 5 versions from modpacks have 'mrpack_loaders', and all 5 versions from mods do not
|
||||
for version in versions.iter() {
|
||||
if version_ids_modpacks.contains(&version.id) {
|
||||
assert!(version.fields.contains_key("mrpack_loaders"));
|
||||
} else if version_ids_mods.contains(&version.id) {
|
||||
assert!(!version.fields.contains_key("mrpack_loaders"));
|
||||
} else {
|
||||
panic!("Unexpected version id: {:?}", version.id);
|
||||
let creation_data = get_public_project_creation_data(
|
||||
&slug,
|
||||
Some(TestFile::build_random_jar()),
|
||||
None,
|
||||
);
|
||||
let resp =
|
||||
api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
mods.push(slug);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Get all 10 projects
|
||||
let project_slugs = modpacks
|
||||
.iter()
|
||||
.map(|x| x.as_str())
|
||||
.chain(mods.iter().map(|x| x.as_str()))
|
||||
.collect_vec();
|
||||
let resp = api.get_projects(&project_slugs, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let projects: Vec<v3::projects::Project> =
|
||||
test::read_body_json(resp).await;
|
||||
assert_eq!(projects.len(), 10);
|
||||
|
||||
// Ensure all 5 modpacks have 'mrpack_loaders', and all 5 mods do not
|
||||
for project in projects.iter() {
|
||||
if modpacks.contains(project.slug.as_ref().unwrap()) {
|
||||
assert!(project.fields.contains_key("mrpack_loaders"));
|
||||
} else if mods.contains(project.slug.as_ref().unwrap()) {
|
||||
assert!(!project.fields.contains_key("mrpack_loaders"));
|
||||
} else {
|
||||
panic!("Unexpected project slug: {:?}", project.slug);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a version from each project
|
||||
let version_ids_modpacks = projects
|
||||
.iter()
|
||||
.filter(|x| modpacks.contains(x.slug.as_ref().unwrap()))
|
||||
.map(|x| x.versions[0])
|
||||
.collect_vec();
|
||||
let version_ids_mods = projects
|
||||
.iter()
|
||||
.filter(|x| mods.contains(x.slug.as_ref().unwrap()))
|
||||
.map(|x| x.versions[0])
|
||||
.collect_vec();
|
||||
let version_ids = version_ids_modpacks
|
||||
.iter()
|
||||
.chain(version_ids_mods.iter())
|
||||
.map(|x| x.to_string())
|
||||
.collect_vec();
|
||||
let resp = api.get_versions(version_ids, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let versions: Vec<v3::projects::Version> =
|
||||
test::read_body_json(resp).await;
|
||||
assert_eq!(versions.len(), 10);
|
||||
|
||||
// Ensure all 5 versions from modpacks have 'mrpack_loaders', and all 5 versions from mods do not
|
||||
for version in versions.iter() {
|
||||
if version_ids_modpacks.contains(&version.id) {
|
||||
assert!(version.fields.contains_key("mrpack_loaders"));
|
||||
} else if version_ids_mods.contains(&version.id) {
|
||||
assert!(!version.fields.contains_key("mrpack_loaders"));
|
||||
} else {
|
||||
panic!("Unexpected version id: {:?}", version.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,18 +8,31 @@ use crate::common::api_common::ApiTeams;
|
||||
mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_team_invitation_returns_notification() {
|
||||
pub async fn get_user_notifications_after_team_invitation_returns_notification()
|
||||
{
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
let alpha_team_id = test_env.dummy.project_alpha.team_id.clone();
|
||||
let api = test_env.api;
|
||||
api.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
api.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
api.add_user_to_team(&alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
api.add_user_to_team(
|
||||
&alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
})
|
||||
@@ -27,12 +40,16 @@ pub async fn get_user_notifications_after_team_invitation_returns_notification()
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_reading_indicates_notification_read() {
|
||||
pub async fn get_user_notifications_after_reading_indicates_notification_read()
|
||||
{
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
test_env.generate_friend_user_notification().await;
|
||||
let api = test_env.api;
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
let notification_id = notifications[0].id.to_string();
|
||||
@@ -41,7 +58,10 @@ pub async fn get_user_notifications_after_reading_indicates_notification_read()
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
assert!(notifications[0].read);
|
||||
@@ -50,12 +70,16 @@ pub async fn get_user_notifications_after_reading_indicates_notification_read()
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_deleting_does_not_show_notification() {
|
||||
pub async fn get_user_notifications_after_deleting_does_not_show_notification()
|
||||
{
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
test_env.generate_friend_user_notification().await;
|
||||
let api = test_env.api;
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
let notification_id = notifications[0].id.to_string();
|
||||
@@ -64,7 +88,10 @@ pub async fn get_user_notifications_after_deleting_does_not_show_notification()
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_notifications_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(0, notifications.len());
|
||||
})
|
||||
|
||||
@@ -3,7 +3,9 @@ use actix_web::test;
|
||||
use common::{
|
||||
api_v3::oauth::get_redirect_location_query_params,
|
||||
api_v3::{
|
||||
oauth::{get_auth_code_from_redirect_params, get_authorize_accept_flow_id},
|
||||
oauth::{
|
||||
get_auth_code_from_redirect_params, get_authorize_accept_flow_id,
|
||||
},
|
||||
ApiV3,
|
||||
},
|
||||
database::FRIEND_USER_ID,
|
||||
@@ -81,7 +83,8 @@ async fn oauth_flow_happy_path() {
|
||||
#[actix_rt::test]
|
||||
async fn oauth_authorize_for_already_authorized_scopes_returns_auth_code() {
|
||||
with_test_environment(None, |env: TestEnvironment<ApiV3>| async move {
|
||||
let DummyOAuthClientAlpha { client_id, .. } = env.dummy.oauth_client_alpha;
|
||||
let DummyOAuthClientAlpha { client_id, .. } =
|
||||
env.dummy.oauth_client_alpha;
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
@@ -131,7 +134,12 @@ async fn get_oauth_token_with_already_used_auth_code_fails() {
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
.oauth_token(auth_code.clone(), None, client_id.clone(), &client_secret)
|
||||
.oauth_token(
|
||||
auth_code.clone(),
|
||||
None,
|
||||
client_id.clone(),
|
||||
&client_secret,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
|
||||
@@ -211,7 +219,13 @@ async fn oauth_authorize_with_broader_scopes_requires_user_accept() {
|
||||
let client_id = env.dummy.oauth_client_alpha.client_id;
|
||||
let resp = env
|
||||
.api
|
||||
.oauth_authorize(&client_id, Some("USER_READ"), None, None, USER_USER_PAT)
|
||||
.oauth_authorize(
|
||||
&client_id,
|
||||
Some("USER_READ"),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let flow_id = get_authorize_accept_flow_id(resp).await;
|
||||
env.api.oauth_accept(&flow_id, USER_USER_PAT).await;
|
||||
@@ -289,8 +303,12 @@ async fn revoke_authorization_after_issuing_token_revokes_token() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
env.assert_read_notifications_status(USER_USER_ID, Some(&access_token), StatusCode::OK)
|
||||
.await;
|
||||
env.assert_read_notifications_status(
|
||||
USER_USER_ID,
|
||||
Some(&access_token),
|
||||
StatusCode::OK,
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
|
||||
@@ -37,7 +37,8 @@ async fn can_create_edit_get_oauth_client() {
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let creation_result: OAuthClientCreationResult = test::read_body_json(resp).await;
|
||||
let creation_result: OAuthClientCreationResult =
|
||||
test::read_body_json(resp).await;
|
||||
let client_id = get_json_val_str(creation_result.client.id);
|
||||
|
||||
let url = Some("https://modrinth.com".to_string());
|
||||
@@ -95,7 +96,8 @@ async fn create_oauth_client_with_restricted_scopes_fails() {
|
||||
#[actix_rt::test]
|
||||
async fn get_oauth_client_for_client_creator_succeeds() {
|
||||
with_test_environment(None, |env: TestEnvironment<ApiV3>| async move {
|
||||
let DummyOAuthClientAlpha { client_id, .. } = env.dummy.oauth_client_alpha.clone();
|
||||
let DummyOAuthClientAlpha { client_id, .. } =
|
||||
env.dummy.oauth_client_alpha.clone();
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
@@ -176,7 +178,8 @@ async fn can_list_user_oauth_authorizations() {
|
||||
)
|
||||
.await;
|
||||
|
||||
let authorizations = env.api.get_user_oauth_authorizations(USER_USER_PAT).await;
|
||||
let authorizations =
|
||||
env.api.get_user_oauth_authorizations(USER_USER_PAT).await;
|
||||
assert_eq!(1, authorizations.len());
|
||||
assert_eq!(USER_USER_ID_PARSED, authorizations[0].user_id.0 as i64);
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::common::api_common::{ApiProject, ApiTeams, ApiUser, ApiVersion, AppendsOptionalPat};
|
||||
use crate::common::dummy_data::{DummyImage, DummyProjectAlpha, DummyProjectBeta};
|
||||
use crate::common::api_common::{
|
||||
ApiProject, ApiTeams, ApiUser, ApiVersion, AppendsOptionalPat,
|
||||
};
|
||||
use crate::common::dummy_data::{
|
||||
DummyImage, DummyProjectAlpha, DummyProjectBeta,
|
||||
};
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use chrono::{Duration, Utc};
|
||||
@@ -10,7 +14,9 @@ use common::api_common::Api;
|
||||
use common::api_v3::request_data::get_public_project_creation_data;
|
||||
use common::api_v3::ApiV3;
|
||||
use common::dummy_data::TestFile;
|
||||
use common::environment::{with_test_environment, with_test_environment_all, TestEnvironment};
|
||||
use common::environment::{
|
||||
with_test_environment, with_test_environment_all, TestEnvironment,
|
||||
};
|
||||
use common::{database::*, scopes::ScopeTest};
|
||||
use labrinth::models::ids::base62_impl::parse_base62;
|
||||
use labrinth::models::pats::Scopes;
|
||||
@@ -34,8 +40,9 @@ async fn user_scopes() {
|
||||
let api = &test_env.api;
|
||||
// User reading
|
||||
let read_user = Scopes::USER_READ;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.get_current_user(pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_current_user(pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, read_user)
|
||||
.await
|
||||
@@ -45,8 +52,9 @@ async fn user_scopes() {
|
||||
|
||||
// Email reading
|
||||
let read_email = Scopes::USER_READ | Scopes::USER_READ_EMAIL;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.get_current_user(pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_current_user(pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, read_email)
|
||||
.await
|
||||
@@ -55,8 +63,9 @@ async fn user_scopes() {
|
||||
|
||||
// Payout reading
|
||||
let read_payout = Scopes::USER_READ | Scopes::PAYOUTS_READ;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.get_current_user(pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_current_user(pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, read_payout)
|
||||
.await
|
||||
@@ -91,8 +100,9 @@ async fn user_scopes() {
|
||||
// User deletion
|
||||
// (The failure is first, and this is the last test for this test function, we can delete it and use the same PAT for both tests)
|
||||
let delete_user = Scopes::USER_DELETE;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.delete_user("enemy", pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.delete_user("enemy", pat.as_deref()).await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_user_id(ENEMY_USER_ID_PARSED)
|
||||
.test(req_gen, delete_user)
|
||||
@@ -113,7 +123,13 @@ pub async fn notifications_scopes() {
|
||||
// Get notifications
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
@@ -186,7 +202,13 @@ pub async fn notifications_scopes() {
|
||||
// We invite mod, get the notification ID, and do mass delete using that
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, MOD_USER_ID, None, None, USER_USER_PAT)
|
||||
.add_user_to_team(
|
||||
alpha_team_id,
|
||||
MOD_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let read_notifications = Scopes::NOTIFICATION_READ;
|
||||
@@ -217,41 +239,47 @@ pub async fn notifications_scopes() {
|
||||
// Project version creation scopes
|
||||
#[actix_rt::test]
|
||||
pub async fn project_version_create_scopes_v3() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
let creation_data =
|
||||
get_public_project_creation_data("demo", Some(TestFile::BasicMod), None);
|
||||
api.create_project(creation_data, pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
let project_id = ProjectId(parse_base62(project_id).unwrap());
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
let creation_data = get_public_project_creation_data(
|
||||
"demo",
|
||||
Some(TestFile::BasicMod),
|
||||
None,
|
||||
);
|
||||
api.create_project(creation_data, pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
let project_id = ProjectId(parse_base62(project_id).unwrap());
|
||||
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.add_public_version(
|
||||
project_id,
|
||||
"1.2.3.4",
|
||||
TestFile::BasicModDifferent,
|
||||
None,
|
||||
None,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.add_public_version(
|
||||
project_id,
|
||||
"1.2.3.4",
|
||||
TestFile::BasicModDifferent,
|
||||
None,
|
||||
None,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -384,7 +412,11 @@ pub async fn project_version_reads_scopes() {
|
||||
let read_version = Scopes::VERSION_READ;
|
||||
let resp = test_env
|
||||
.api
|
||||
.edit_version(beta_version_id, json!({ "status": "draft" }), USER_USER_PAT)
|
||||
.edit_version(
|
||||
beta_version_id,
|
||||
json!({ "status": "draft" }),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
@@ -399,8 +431,12 @@ pub async fn project_version_reads_scopes() {
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.download_version_redirect(beta_file_hash, "sha1", pat.as_deref())
|
||||
.await
|
||||
api.download_version_redirect(
|
||||
beta_file_hash,
|
||||
"sha1",
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_code(404)
|
||||
@@ -417,8 +453,12 @@ pub async fn project_version_reads_scopes() {
|
||||
// ScopeTest::new(&test_env).with_failure_code(404).test(req_gen, read_version).await.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_versions_from_hashes(&[beta_file_hash], "sha1", pat.as_deref())
|
||||
.await
|
||||
api.get_versions_from_hashes(
|
||||
&[beta_file_hash],
|
||||
"sha1",
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
@@ -439,7 +479,8 @@ pub async fn project_version_reads_scopes() {
|
||||
// assert!(success.as_object().unwrap().contains_key(beta_file_hash));
|
||||
|
||||
// Both project and version reading
|
||||
let read_project_and_version = Scopes::PROJECT_READ | Scopes::VERSION_READ;
|
||||
let read_project_and_version =
|
||||
Scopes::PROJECT_READ | Scopes::VERSION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_project_versions(
|
||||
beta_project_id,
|
||||
@@ -681,8 +722,12 @@ pub async fn version_write_scopes() {
|
||||
|
||||
// Upload version file
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.upload_file_to_version(alpha_version_id, &TestFile::BasicZip, pat.as_deref())
|
||||
.await
|
||||
api.upload_file_to_version(
|
||||
alpha_version_id,
|
||||
&TestFile::BasicZip,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, write_version)
|
||||
@@ -740,16 +785,18 @@ pub async fn report_scopes() {
|
||||
|
||||
// Get reports
|
||||
let report_read = Scopes::REPORT_READ;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.get_user_reports(pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_user_reports(pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, report_read)
|
||||
.await
|
||||
.unwrap();
|
||||
let report_id = success[0]["id"].as_str().unwrap();
|
||||
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.get_report(report_id, pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_report(report_id, pat.as_deref()).await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, report_read)
|
||||
.await
|
||||
@@ -781,8 +828,9 @@ pub async fn report_scopes() {
|
||||
// Delete report
|
||||
// We use a moderator PAT here, as only moderators can delete reports
|
||||
let report_delete = Scopes::REPORT_DELETE;
|
||||
let req_gen =
|
||||
|pat: Option<String>| async move { api.delete_report(report_id, pat.as_deref()).await };
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.delete_report(report_id, pat.as_deref()).await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_user_id(MOD_USER_ID_PARSED)
|
||||
.test(req_gen, report_delete)
|
||||
@@ -915,101 +963,104 @@ pub async fn pat_scopes() {
|
||||
#[actix_rt::test]
|
||||
pub async fn collections_scopes() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
|
||||
// Create collection
|
||||
let collection_create = Scopes::COLLECTION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.create_collection(
|
||||
"Test Collection",
|
||||
"Test Collection Description",
|
||||
&[alpha_project_id.as_str()],
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_create)
|
||||
.await
|
||||
.unwrap();
|
||||
let collection_id = success["id"].as_str().unwrap();
|
||||
|
||||
// Patch collection
|
||||
// Collections always initialize to public, so we do patch before Get testing
|
||||
let collection_write = Scopes::COLLECTION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection(
|
||||
collection_id,
|
||||
json!({
|
||||
"name": "Test Collection patch",
|
||||
"status": "private",
|
||||
}),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Read collection
|
||||
let collection_read = Scopes::COLLECTION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_collection(collection_id, pat.as_deref()).await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_code(404)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_collections(&[collection_id], pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(failure.as_array().unwrap().len(), 0);
|
||||
assert_eq!(success.as_array().unwrap().len(), 1);
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_user_collections(USER_USER_ID, pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(failure.as_array().unwrap().len(), 0);
|
||||
assert_eq!(success.as_array().unwrap().len(), 1);
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection_icon(
|
||||
collection_id,
|
||||
Some(DummyImage::SmallIcon.get_icon_data()),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection_icon(collection_id, None, pat.as_deref())
|
||||
// Create collection
|
||||
let collection_create = Scopes::COLLECTION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.create_collection(
|
||||
"Test Collection",
|
||||
"Test Collection Description",
|
||||
&[alpha_project_id.as_str()],
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_create)
|
||||
.await
|
||||
.unwrap();
|
||||
let collection_id = success["id"].as_str().unwrap();
|
||||
|
||||
// Patch collection
|
||||
// Collections always initialize to public, so we do patch before Get testing
|
||||
let collection_write = Scopes::COLLECTION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection(
|
||||
collection_id,
|
||||
json!({
|
||||
"name": "Test Collection patch",
|
||||
"status": "private",
|
||||
}),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Read collection
|
||||
let collection_read = Scopes::COLLECTION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_collection(collection_id, pat.as_deref()).await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_code(404)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_collections(&[collection_id], pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(failure.as_array().unwrap().len(), 0);
|
||||
assert_eq!(success.as_array().unwrap().len(), 1);
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_user_collections(USER_USER_ID, pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, collection_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(failure.as_array().unwrap().len(), 0);
|
||||
assert_eq!(success.as_array().unwrap().len(), 1);
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection_icon(
|
||||
collection_id,
|
||||
Some(DummyImage::SmallIcon.get_icon_data()),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_collection_icon(collection_id, None, pat.as_deref())
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, collection_write)
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1017,140 +1068,158 @@ pub async fn collections_scopes() {
|
||||
#[actix_rt::test]
|
||||
pub async fn organization_scopes() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let beta_project_id = &test_env.dummy.project_beta.project_id;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let beta_project_id = &test_env.dummy.project_beta.project_id;
|
||||
|
||||
// Create organization
|
||||
let organization_create = Scopes::ORGANIZATION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.create_organization("Test Org", "TestOrg", "TestOrg Description", pat.as_deref())
|
||||
// Create organization
|
||||
let organization_create = Scopes::ORGANIZATION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.create_organization(
|
||||
"Test Org",
|
||||
"TestOrg",
|
||||
"TestOrg Description",
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_create)
|
||||
.await
|
||||
.unwrap();
|
||||
let organization_id = success["id"].as_str().unwrap();
|
||||
|
||||
// Patch organization
|
||||
let organization_edit = Scopes::ORGANIZATION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization(
|
||||
organization_id,
|
||||
json!({
|
||||
"description": "TestOrg Patch Description",
|
||||
}),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization_icon(
|
||||
organization_id,
|
||||
Some(DummyImage::SmallIcon.get_icon_data()),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization_icon(organization_id, None, pat.as_deref())
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_create)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
let organization_id = success["id"].as_str().unwrap();
|
||||
|
||||
// add project
|
||||
let organization_project_edit = Scopes::PROJECT_WRITE | Scopes::ORGANIZATION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.organization_add_project(organization_id, beta_project_id, pat.as_deref())
|
||||
// Patch organization
|
||||
let organization_edit = Scopes::ORGANIZATION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization(
|
||||
organization_id,
|
||||
json!({
|
||||
"description": "TestOrg Patch Description",
|
||||
}),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_WRITE)
|
||||
.test(req_gen, organization_project_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Organization reads
|
||||
let organization_read = Scopes::ORGANIZATION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organization(organization_id, pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, organization_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure["members"][0]["permissions"].is_null());
|
||||
assert!(!success["members"][0]["permissions"].is_null());
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organizations(&[organization_id], pat.as_deref())
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
};
|
||||
.unwrap();
|
||||
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, organization_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure[0]["members"][0]["permissions"].is_null());
|
||||
assert!(!success[0]["members"][0]["permissions"].is_null());
|
||||
|
||||
let organization_project_read = Scopes::PROJECT_READ | Scopes::ORGANIZATION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organization_projects(organization_id, pat.as_deref())
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization_icon(
|
||||
organization_id,
|
||||
Some(DummyImage::SmallIcon.get_icon_data()),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_READ)
|
||||
.test(req_gen, organization_project_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure.as_array().unwrap().is_empty());
|
||||
assert!(!success.as_array().unwrap().is_empty());
|
||||
|
||||
// remove project (now that we've checked)
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.organization_remove_project(
|
||||
organization_id,
|
||||
beta_project_id,
|
||||
UserId(USER_USER_ID_PARSED as u64),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_WRITE)
|
||||
.test(req_gen, organization_project_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Delete organization
|
||||
let organization_delete = Scopes::ORGANIZATION_DELETE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.delete_organization(organization_id, pat.as_deref())
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_delete)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.edit_organization_icon(
|
||||
organization_id,
|
||||
None,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// add project
|
||||
let organization_project_edit =
|
||||
Scopes::PROJECT_WRITE | Scopes::ORGANIZATION_WRITE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.organization_add_project(
|
||||
organization_id,
|
||||
beta_project_id,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_WRITE)
|
||||
.test(req_gen, organization_project_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Organization reads
|
||||
let organization_read = Scopes::ORGANIZATION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organization(organization_id, pat.as_deref()).await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, organization_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure["members"][0]["permissions"].is_null());
|
||||
assert!(!success["members"][0]["permissions"].is_null());
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organizations(&[organization_id], pat.as_deref())
|
||||
.await
|
||||
};
|
||||
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.test(req_gen, organization_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure[0]["members"][0]["permissions"].is_null());
|
||||
assert!(!success[0]["members"][0]["permissions"].is_null());
|
||||
|
||||
let organization_project_read =
|
||||
Scopes::PROJECT_READ | Scopes::ORGANIZATION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_organization_projects(organization_id, pat.as_deref())
|
||||
.await
|
||||
};
|
||||
let (failure, success) = ScopeTest::new(&test_env)
|
||||
.with_failure_code(200)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_READ)
|
||||
.test(req_gen, organization_project_read)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(failure.as_array().unwrap().is_empty());
|
||||
assert!(!success.as_array().unwrap().is_empty());
|
||||
|
||||
// remove project (now that we've checked)
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.organization_remove_project(
|
||||
organization_id,
|
||||
beta_project_id,
|
||||
UserId(USER_USER_ID_PARSED as u64),
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.with_failure_scopes(Scopes::all() ^ Scopes::ORGANIZATION_WRITE)
|
||||
.test(req_gen, organization_project_edit)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Delete organization
|
||||
let organization_delete = Scopes::ORGANIZATION_DELETE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.delete_organization(organization_id, pat.as_deref())
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, organization_delete)
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,148 +22,174 @@ mod common;
|
||||
#[actix_rt::test]
|
||||
async fn search_projects() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(Some(10), |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let id_conversion = setup_search_projects(&test_env).await;
|
||||
with_test_environment(
|
||||
Some(10),
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let id_conversion = setup_search_projects(&test_env).await;
|
||||
|
||||
let api = &test_env.api;
|
||||
let test_name = test_env.db.database_name.clone();
|
||||
let api = &test_env.api;
|
||||
let test_name = test_env.db.database_name.clone();
|
||||
|
||||
// Pairs of:
|
||||
// 1. vec of search facets
|
||||
// 2. expected project ids to be returned by this search
|
||||
let pairs = vec![
|
||||
(
|
||||
json!([["categories:fabric"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 9],
|
||||
),
|
||||
(json!([["categories:forge"]]), vec![7]),
|
||||
(
|
||||
json!([["categories:fabric", "categories:forge"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 9],
|
||||
),
|
||||
(json!([["categories:fabric"], ["categories:forge"]]), vec![]),
|
||||
(
|
||||
json!([
|
||||
["categories:fabric"],
|
||||
[&format!("categories:{}", DUMMY_CATEGORIES[0])],
|
||||
]),
|
||||
vec![1, 2, 3, 4],
|
||||
),
|
||||
(json!([["project_types:modpack"]]), vec![4]),
|
||||
(json!([["client_only:true"]]), vec![0, 2, 3, 7, 9]),
|
||||
(json!([["server_only:true"]]), vec![0, 2, 3, 6, 7]),
|
||||
(json!([["open_source:true"]]), vec![0, 1, 2, 4, 5, 6, 7, 9]),
|
||||
(json!([["license:MIT"]]), vec![1, 2, 4, 9]),
|
||||
(json!([[r#"name:'Mysterious Project'"#]]), vec![2, 3]),
|
||||
(json!([["author:user"]]), vec![0, 1, 2, 4, 5, 7, 9]), // Organization test '9' is included here as user is owner of org
|
||||
(json!([["game_versions:1.20.5"]]), vec![4, 5]),
|
||||
// bug fix
|
||||
(
|
||||
json!([
|
||||
// Only the forge one has 1.20.2, so its true that this project 'has'
|
||||
// 1.20.2 and a fabric version, but not true that it has a 1.20.2 fabric version.
|
||||
["categories:fabric"],
|
||||
["game_versions:1.20.2"]
|
||||
]),
|
||||
vec![],
|
||||
),
|
||||
// Project type change
|
||||
// Modpack should still be able to search based on former loader, even though technically the loader is 'mrpack'
|
||||
// (json!([["categories:mrpack"]]), vec![4]),
|
||||
// (
|
||||
// json!([["categories:fabric"]]),
|
||||
// vec![4],
|
||||
// ),
|
||||
(
|
||||
json!([["categories:fabric"], ["project_types:modpack"]]),
|
||||
vec![4],
|
||||
),
|
||||
];
|
||||
// TODO: versions, game versions
|
||||
// Untested:
|
||||
// - downloads (not varied)
|
||||
// - color (not varied)
|
||||
// - created_timestamp (not varied)
|
||||
// - modified_timestamp (not varied)
|
||||
// TODO: multiple different project types test
|
||||
// Pairs of:
|
||||
// 1. vec of search facets
|
||||
// 2. expected project ids to be returned by this search
|
||||
let pairs = vec![
|
||||
(
|
||||
json!([["categories:fabric"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 9],
|
||||
),
|
||||
(json!([["categories:forge"]]), vec![7]),
|
||||
(
|
||||
json!([["categories:fabric", "categories:forge"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 9],
|
||||
),
|
||||
(json!([["categories:fabric"], ["categories:forge"]]), vec![]),
|
||||
(
|
||||
json!([
|
||||
["categories:fabric"],
|
||||
[&format!("categories:{}", DUMMY_CATEGORIES[0])],
|
||||
]),
|
||||
vec![1, 2, 3, 4],
|
||||
),
|
||||
(json!([["project_types:modpack"]]), vec![4]),
|
||||
(json!([["client_only:true"]]), vec![0, 2, 3, 7, 9]),
|
||||
(json!([["server_only:true"]]), vec![0, 2, 3, 6, 7]),
|
||||
(json!([["open_source:true"]]), vec![0, 1, 2, 4, 5, 6, 7, 9]),
|
||||
(json!([["license:MIT"]]), vec![1, 2, 4, 9]),
|
||||
(json!([[r#"name:'Mysterious Project'"#]]), vec![2, 3]),
|
||||
(json!([["author:user"]]), vec![0, 1, 2, 4, 5, 7, 9]), // Organization test '9' is included here as user is owner of org
|
||||
(json!([["game_versions:1.20.5"]]), vec![4, 5]),
|
||||
// bug fix
|
||||
(
|
||||
json!([
|
||||
// Only the forge one has 1.20.2, so its true that this project 'has'
|
||||
// 1.20.2 and a fabric version, but not true that it has a 1.20.2 fabric version.
|
||||
["categories:fabric"],
|
||||
["game_versions:1.20.2"]
|
||||
]),
|
||||
vec![],
|
||||
),
|
||||
// Project type change
|
||||
// Modpack should still be able to search based on former loader, even though technically the loader is 'mrpack'
|
||||
// (json!([["categories:mrpack"]]), vec![4]),
|
||||
// (
|
||||
// json!([["categories:fabric"]]),
|
||||
// vec![4],
|
||||
// ),
|
||||
(
|
||||
json!([["categories:fabric"], ["project_types:modpack"]]),
|
||||
vec![4],
|
||||
),
|
||||
];
|
||||
// TODO: versions, game versions
|
||||
// Untested:
|
||||
// - downloads (not varied)
|
||||
// - color (not varied)
|
||||
// - created_timestamp (not varied)
|
||||
// - modified_timestamp (not varied)
|
||||
// TODO: multiple different project types test
|
||||
|
||||
// Test searches
|
||||
let stream = futures::stream::iter(pairs);
|
||||
stream
|
||||
.for_each_concurrent(1, |(facets, mut expected_project_ids)| {
|
||||
let id_conversion = id_conversion.clone();
|
||||
let test_name = test_name.clone();
|
||||
async move {
|
||||
let projects = api
|
||||
.search_deserialized(
|
||||
Some(&format!("\"&{test_name}\"")),
|
||||
Some(facets.clone()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let mut found_project_ids: Vec<u64> = projects
|
||||
.hits
|
||||
.into_iter()
|
||||
.map(|p| id_conversion[&parse_base62(&p.project_id).unwrap()])
|
||||
.collect();
|
||||
let num_hits = projects.total_hits;
|
||||
expected_project_ids.sort();
|
||||
found_project_ids.sort();
|
||||
println!("Facets: {:?}", facets);
|
||||
assert_eq!(found_project_ids, expected_project_ids);
|
||||
assert_eq!(num_hits, { expected_project_ids.len() });
|
||||
}
|
||||
})
|
||||
.await;
|
||||
})
|
||||
// Test searches
|
||||
let stream = futures::stream::iter(pairs);
|
||||
stream
|
||||
.for_each_concurrent(1, |(facets, mut expected_project_ids)| {
|
||||
let id_conversion = id_conversion.clone();
|
||||
let test_name = test_name.clone();
|
||||
async move {
|
||||
let projects = api
|
||||
.search_deserialized(
|
||||
Some(&format!("\"&{test_name}\"")),
|
||||
Some(facets.clone()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let mut found_project_ids: Vec<u64> = projects
|
||||
.hits
|
||||
.into_iter()
|
||||
.map(|p| {
|
||||
id_conversion
|
||||
[&parse_base62(&p.project_id).unwrap()]
|
||||
})
|
||||
.collect();
|
||||
let num_hits = projects.total_hits;
|
||||
expected_project_ids.sort();
|
||||
found_project_ids.sort();
|
||||
println!("Facets: {:?}", facets);
|
||||
assert_eq!(found_project_ids, expected_project_ids);
|
||||
assert_eq!(num_hits, { expected_project_ids.len() });
|
||||
}
|
||||
})
|
||||
.await;
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn index_swaps() {
|
||||
with_test_environment(Some(10), |test_env: TestEnvironment<ApiV3>| async move {
|
||||
// Reindex
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
with_test_environment(
|
||||
Some(10),
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
// Reindex
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Now we should get results
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(None, Some(json!([["categories:fabric"]])), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 1);
|
||||
assert!(projects.hits[0].slug.as_ref().unwrap().contains("alpha"));
|
||||
// Now we should get results
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(
|
||||
None,
|
||||
Some(json!([["categories:fabric"]])),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 1);
|
||||
assert!(projects.hits[0].slug.as_ref().unwrap().contains("alpha"));
|
||||
|
||||
// Delete the project
|
||||
let resp = test_env.api.remove_project("alpha", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// Delete the project
|
||||
let resp =
|
||||
test_env.api.remove_project("alpha", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// We should not get any results, because the project has been deleted
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(None, Some(json!([["categories:fabric"]])), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
// We should not get any results, because the project has been deleted
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(
|
||||
None,
|
||||
Some(json!([["categories:fabric"]])),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
|
||||
// But when we reindex, it should be gone
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// But when we reindex, it should be gone
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(None, Some(json!([["categories:fabric"]])), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(
|
||||
None,
|
||||
Some(json!([["categories:fabric"]])),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
|
||||
// Reindex again, should still be gone
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// Reindex again, should still be gone
|
||||
let resp = test_env.api.reset_search_index().await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(None, Some(json!([["categories:fabric"]])), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
})
|
||||
let projects = test_env
|
||||
.api
|
||||
.search_deserialized(
|
||||
None,
|
||||
Some(json!([["categories:fabric"]])),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(projects.total_hits, 0);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::collections::{HashMap, HashSet};
|
||||
|
||||
use common::{
|
||||
api_v3::ApiV3,
|
||||
environment::{with_test_environment, with_test_environment_all, TestEnvironment},
|
||||
environment::{
|
||||
with_test_environment, with_test_environment_all, TestEnvironment,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::common::api_common::ApiTags;
|
||||
@@ -40,25 +42,34 @@ async fn get_tags() {
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_tags_v3() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
|
||||
let loader_metadata = loaders
|
||||
.into_iter()
|
||||
.map(|x| (x.name, x.metadata.get("platform").and_then(|x| x.as_bool())))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let loader_names = loader_metadata.keys().cloned().collect::<HashSet<String>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "mrpack", "bukkit", "waterfall"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
assert_eq!(loader_metadata["fabric"], None);
|
||||
assert_eq!(loader_metadata["bukkit"], Some(false));
|
||||
assert_eq!(loader_metadata["waterfall"], Some(true));
|
||||
})
|
||||
let loader_metadata = loaders
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
(
|
||||
x.name,
|
||||
x.metadata.get("platform").and_then(|x| x.as_bool()),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
let loader_names =
|
||||
loader_metadata.keys().cloned().collect::<HashSet<String>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "mrpack", "bukkit", "waterfall"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
assert_eq!(loader_metadata["fabric"], None);
|
||||
assert_eq!(loader_metadata["bukkit"], Some(false));
|
||||
assert_eq!(loader_metadata["waterfall"], Some(true));
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ use crate::common::{api_common::ApiTeams, database::*};
|
||||
use actix_http::StatusCode;
|
||||
use common::{
|
||||
api_v3::ApiV3,
|
||||
environment::{with_test_environment, with_test_environment_all, TestEnvironment},
|
||||
environment::{
|
||||
with_test_environment, with_test_environment_all, TestEnvironment,
|
||||
},
|
||||
};
|
||||
use labrinth::models::teams::{OrganizationPermissions, ProjectPermissions};
|
||||
use rust_decimal::Decimal;
|
||||
@@ -22,14 +24,20 @@ async fn test_get_team() {
|
||||
|
||||
// A non-member of the team should get basic info but not be able to see private data
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT)
|
||||
.get_team_members_deserialized_common(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(members[0].permissions.is_none());
|
||||
|
||||
let members = api
|
||||
.get_project_members_deserialized_common(alpha_project_id, FRIEND_USER_PAT)
|
||||
.get_project_members_deserialized_common(
|
||||
alpha_project_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
@@ -38,13 +46,22 @@ async fn test_get_team() {
|
||||
// - not be able to see private data about the team, but see all members including themselves
|
||||
// - should not appear in the team members list to enemy users
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT)
|
||||
.get_team_members_deserialized_common(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
@@ -62,7 +79,10 @@ async fn test_get_team() {
|
||||
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_project_members_deserialized_common(alpha_project_id, FRIEND_USER_PAT)
|
||||
.get_project_members_deserialized_common(
|
||||
alpha_project_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
@@ -86,7 +106,10 @@ async fn test_get_team() {
|
||||
|
||||
// enemy team check via association
|
||||
let members = api
|
||||
.get_project_members_deserialized_common(alpha_project_id, ENEMY_USER_PAT)
|
||||
.get_project_members_deserialized_common(
|
||||
alpha_project_id,
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1); // Only USER_USER_ID should be in the team
|
||||
|
||||
@@ -97,7 +120,10 @@ async fn test_get_team() {
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT)
|
||||
.get_team_members_deserialized_common(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
@@ -115,7 +141,10 @@ async fn test_get_team() {
|
||||
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_project_members_deserialized_common(alpha_project_id, FRIEND_USER_PAT)
|
||||
.get_project_members_deserialized_common(
|
||||
alpha_project_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
@@ -139,169 +168,224 @@ async fn test_get_team_organization() {
|
||||
// Test setup and dummy data
|
||||
// Perform get_team related tests for an organization team
|
||||
//TODO: This needs to consider users in organizations now and how they perceive as well
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_team_id = &test_env.dummy.organization_zeta.team_id;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let zeta_organization_id =
|
||||
&test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_team_id = &test_env.dummy.organization_zeta.team_id;
|
||||
|
||||
// A non-member of the team should get basic info but not be able to see private data
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(zeta_team_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(members[0].permissions.is_none());
|
||||
// A non-member of the team should get basic info but not be able to see private data
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(members[0].permissions.is_none());
|
||||
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(zeta_organization_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(
|
||||
zeta_organization_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1);
|
||||
assert_eq!(members[0].user.id.0, USER_USER_ID_PARSED as u64);
|
||||
|
||||
// A non-accepted member of the team should:
|
||||
// - not be able to see private data about the team, but see all members including themselves
|
||||
// - should not appear in the team members list to enemy users
|
||||
let resp = api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// A non-accepted member of the team should:
|
||||
// - not be able to see private data about the team, but see all members including themselves
|
||||
// - should not appear in the team members list to enemy users
|
||||
let resp = api
|
||||
.add_user_to_team(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(zeta_team_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_none()); // Should not see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_none());
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_none()); // Should not see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_none());
|
||||
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(zeta_organization_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(
|
||||
zeta_organization_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_none()); // Should not see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_none());
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_none()); // Should not see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_none());
|
||||
|
||||
// enemy team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(zeta_team_id, ENEMY_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1); // Only USER_USER_ID should be in the team
|
||||
// enemy team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(
|
||||
zeta_team_id,
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1); // Only USER_USER_ID should be in the team
|
||||
|
||||
// enemy team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(zeta_organization_id, ENEMY_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1); // Only USER_USER_ID should be in the team
|
||||
// enemy team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(
|
||||
zeta_organization_id,
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 1); // Only USER_USER_ID should be in the team
|
||||
|
||||
// An accepted member of the team should appear in the team members list
|
||||
// and should be able to see private data about the team
|
||||
let resp = api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// An accepted member of the team should appear in the team members list
|
||||
// and should be able to see private data about the team
|
||||
let resp = api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(zeta_team_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_some()); // SHOULD see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_some());
|
||||
// Team check directly
|
||||
let members = api
|
||||
.get_team_members_deserialized_common(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_some()); // SHOULD see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_some());
|
||||
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(zeta_organization_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_some()); // SHOULD see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_some());
|
||||
})
|
||||
// team check via association
|
||||
let members = api
|
||||
.get_organization_members_deserialized_common(
|
||||
zeta_organization_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(members.len() == 2); // USER_USER_ID and FRIEND_USER_ID should be in the team
|
||||
let user_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
let friend_user = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_user.user.id.0, USER_USER_ID_PARSED as u64);
|
||||
assert!(user_user.permissions.is_some()); // SHOULD see private data of the team
|
||||
assert_eq!(friend_user.user.id.0, FRIEND_USER_ID_PARSED as u64);
|
||||
assert!(friend_user.permissions.is_some());
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_get_team_project_orgs() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_team_id = &test_env.dummy.organization_zeta.team_id;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let zeta_organization_id =
|
||||
&test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_team_id = &test_env.dummy.organization_zeta.team_id;
|
||||
|
||||
// Attach alpha to zeta
|
||||
let resp = test_env
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// Attach alpha to zeta
|
||||
let resp = test_env
|
||||
.api
|
||||
.organization_add_project(
|
||||
zeta_organization_id,
|
||||
alpha_project_id,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
|
||||
// Invite and add friend to zeta
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// Invite and add friend to zeta
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let resp =
|
||||
test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// The team members route from teams (on a project's team):
|
||||
// - the members of the project team specifically
|
||||
// - not the ones from the organization
|
||||
// - Remember: the owner of an org will not be included in the org's team members list
|
||||
let members = test_env
|
||||
.api
|
||||
.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 0);
|
||||
// The team members route from teams (on a project's team):
|
||||
// - the members of the project team specifically
|
||||
// - not the ones from the organization
|
||||
// - Remember: the owner of an org will not be included in the org's team members list
|
||||
let members = test_env
|
||||
.api
|
||||
.get_team_members_deserialized_common(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 0);
|
||||
|
||||
// The team members route from project should show the same!
|
||||
let members = test_env
|
||||
.api
|
||||
.get_project_members_deserialized_common(alpha_project_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(members.len(), 0);
|
||||
})
|
||||
// The team members route from project should show the same!
|
||||
let members = test_env
|
||||
.api
|
||||
.get_project_members_deserialized_common(
|
||||
alpha_project_id,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(members.len(), 0);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -473,101 +557,133 @@ async fn test_patch_organization_team_member() {
|
||||
#[actix_rt::test]
|
||||
async fn transfer_ownership_v3() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
|
||||
// Cannot set friend as owner (not a member)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
// Cannot set friend as owner (not a member)
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Member"); // her role does not actually change, but is_owner is set to true
|
||||
assert!(friend_member.is_owner);
|
||||
assert_eq!(
|
||||
friend_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
// Check
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Member"); // her role does not actually change, but is_owner is set to true
|
||||
assert!(friend_member.is_owner);
|
||||
assert_eq!(
|
||||
friend_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
|
||||
let user_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_member.role, "Member"); // We are the 'owner', but we are not actually the owner!
|
||||
assert!(!user_member.is_owner);
|
||||
assert_eq!(user_member.permissions.unwrap(), ProjectPermissions::all());
|
||||
let user_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_member.role, "Member"); // We are the 'owner', but we are not actually the owner!
|
||||
assert!(!user_member.is_owner);
|
||||
assert_eq!(
|
||||
user_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
|
||||
// Confirm that user, a user who still has full permissions, cannot then remove the owner
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
// Confirm that user, a user who still has full permissions, cannot then remove the owner
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// V3 only- confirm the owner can change their role without losing ownership
|
||||
let resp = api
|
||||
.edit_team_member(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
json!({
|
||||
"role": "Member"
|
||||
}),
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// V3 only- confirm the owner can change their role without losing ownership
|
||||
let resp = api
|
||||
.edit_team_member(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
json!({
|
||||
"role": "Member"
|
||||
}),
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Member");
|
||||
assert!(friend_member.is_owner);
|
||||
})
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Member");
|
||||
assert!(friend_member.is_owner);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,12 @@ pub async fn get_user_projects_after_creating_project_returns_new_project() {
|
||||
.await;
|
||||
|
||||
let (project, _) = api
|
||||
.add_public_project("slug", Some(TestFile::BasicMod), None, USER_USER_PAT)
|
||||
.add_public_project(
|
||||
"slug",
|
||||
Some(TestFile::BasicMod),
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp_projects = api
|
||||
@@ -40,7 +45,12 @@ pub async fn get_user_projects_after_deleting_project_shows_removal() {
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
let api = test_env.api;
|
||||
let (project, _) = api
|
||||
.add_public_project("iota", Some(TestFile::BasicMod), None, USER_USER_PAT)
|
||||
.add_public_project(
|
||||
"iota",
|
||||
Some(TestFile::BasicMod),
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
api.get_user_projects_deserialized_common(USER_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
@@ -62,15 +72,27 @@ pub async fn get_user_projects_after_joining_team_shows_team_projects() {
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
let api = test_env.api;
|
||||
api.get_user_projects_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
api.get_user_projects_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
api.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
api.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
|
||||
let projects = api
|
||||
.get_user_projects_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_projects_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(projects
|
||||
.iter()
|
||||
@@ -85,17 +107,29 @@ pub async fn get_user_projects_after_leaving_team_shows_no_team_projects() {
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
||||
let api = test_env.api;
|
||||
api.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
api.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
api.get_user_projects_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
api.get_user_projects_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
api.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
let projects = api
|
||||
.get_user_projects_deserialized_common(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.get_user_projects_deserialized_common(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert!(!projects
|
||||
.iter()
|
||||
|
||||
@@ -12,14 +12,17 @@ use crate::common::{
|
||||
};
|
||||
#[actix_rt::test]
|
||||
pub async fn error_404_empty() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
// V2 errors should have 404 as blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_eq!(body, empty_bytes);
|
||||
})
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
// V2 errors should have 404 as blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_eq!(body, empty_bytes);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -6,20 +6,33 @@ use crate::common::{
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_team_invitation_returns_notification() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let alpha_team_id = test_env.dummy.project_alpha.team_id.clone();
|
||||
let api = test_env.api;
|
||||
api.add_user_to_team(&alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
pub async fn get_user_notifications_after_team_invitation_returns_notification()
|
||||
{
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let alpha_team_id = test_env.dummy.project_alpha.team_id.clone();
|
||||
let api = test_env.api;
|
||||
api.add_user_to_team(
|
||||
&alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
|
||||
// Check to make sure type_ is correct
|
||||
assert_eq!(notifications[0].type_.as_ref().unwrap(), "team_invite");
|
||||
})
|
||||
// Check to make sure type_ is correct
|
||||
assert_eq!(notifications[0].type_.as_ref().unwrap(), "team_invite");
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,69 +13,78 @@ use labrinth::models::projects::ProjectId;
|
||||
// Project version creation scopes
|
||||
#[actix_rt::test]
|
||||
pub async fn project_version_create_scopes() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
let creation_data =
|
||||
get_public_project_creation_data("demo", Some(TestFile::BasicMod), None);
|
||||
api.create_project(creation_data, pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
let project_id = ProjectId(parse_base62(project_id).unwrap());
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
let creation_data = get_public_project_creation_data(
|
||||
"demo",
|
||||
Some(TestFile::BasicMod),
|
||||
None,
|
||||
);
|
||||
api.create_project(creation_data, pat.as_deref()).await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
let project_id = ProjectId(parse_base62(project_id).unwrap());
|
||||
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.add_public_version(
|
||||
project_id,
|
||||
"1.2.3.4",
|
||||
TestFile::BasicModDifferent,
|
||||
None,
|
||||
None,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.add_public_version(
|
||||
project_id,
|
||||
"1.2.3.4",
|
||||
TestFile::BasicModDifferent,
|
||||
None,
|
||||
None,
|
||||
pat.as_deref(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn project_version_reads_scopes() {
|
||||
with_test_environment(None, |_test_env: TestEnvironment<ApiV2>| async move {
|
||||
// let api = &test_env.api;
|
||||
// let beta_file_hash = &test_env.dummy.project_beta.file_hash;
|
||||
with_test_environment(
|
||||
None,
|
||||
|_test_env: TestEnvironment<ApiV2>| async move {
|
||||
// let api = &test_env.api;
|
||||
// let beta_file_hash = &test_env.dummy.project_beta.file_hash;
|
||||
|
||||
// let read_version = Scopes::VERSION_READ;
|
||||
// let read_version = Scopes::VERSION_READ;
|
||||
|
||||
// Update individual version file
|
||||
// TODO: This scope currently fails still as the 'version' field of QueryProject only allows public versions.
|
||||
// TODO: This will be fixed when the 'extracts_versions' PR is merged.
|
||||
// let req_gen = |pat : Option<String>| async move {
|
||||
// api.update_individual_files("sha1", vec![
|
||||
// FileUpdateData {
|
||||
// hash: beta_file_hash.clone(),
|
||||
// loaders: None,
|
||||
// game_versions: None,
|
||||
// version_types: None
|
||||
// }
|
||||
// ], pat.as_deref())
|
||||
// .await
|
||||
// };
|
||||
// let (failure, success) = ScopeTest::new(&test_env).with_failure_code(200).test(req_gen, read_version).await.unwrap();
|
||||
// assert!(!failure.as_object().unwrap().contains_key(beta_file_hash));
|
||||
// assert!(success.as_object().unwrap().contains_key(beta_file_hash));
|
||||
})
|
||||
// Update individual version file
|
||||
// TODO: This scope currently fails still as the 'version' field of QueryProject only allows public versions.
|
||||
// TODO: This will be fixed when the 'extracts_versions' PR is merged.
|
||||
// let req_gen = |pat : Option<String>| async move {
|
||||
// api.update_individual_files("sha1", vec![
|
||||
// FileUpdateData {
|
||||
// hash: beta_file_hash.clone(),
|
||||
// loaders: None,
|
||||
// game_versions: None,
|
||||
// version_types: None
|
||||
// }
|
||||
// ], pat.as_deref())
|
||||
// .await
|
||||
// };
|
||||
// let (failure, success) = ScopeTest::new(&test_env).with_failure_code(200).test(req_gen, read_version).await.unwrap();
|
||||
// assert!(!failure.as_object().unwrap().contains_key(beta_file_hash));
|
||||
// assert!(success.as_object().unwrap().contains_key(beta_file_hash));
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -10,98 +10,107 @@ use crate::common::{
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_tags() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let game_versions = api.get_game_versions_deserialized().await;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
let side_types = api.get_side_types_deserialized().await;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let game_versions = api.get_game_versions_deserialized().await;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
let side_types = api.get_side_types_deserialized().await;
|
||||
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes
|
||||
// Versions should be ordered by:
|
||||
// - ordering
|
||||
// - ordering ties settled by date added to database
|
||||
// - We also expect presentation of NEWEST to OLDEST
|
||||
// - All null orderings are treated as older than any non-null ordering
|
||||
// (for this test, the 1.20.1, etc, versions are all null ordering)
|
||||
let game_version_versions = game_versions
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
game_version_versions,
|
||||
[
|
||||
"Ordering_Negative1",
|
||||
"Ordering_Positive100",
|
||||
"1.20.5",
|
||||
"1.20.4",
|
||||
"1.20.3",
|
||||
"1.20.2",
|
||||
"1.20.1"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect_vec()
|
||||
);
|
||||
|
||||
let loader_names = loaders.into_iter().map(|x| x.name).collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "bukkit", "waterfall"]
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes
|
||||
// Versions should be ordered by:
|
||||
// - ordering
|
||||
// - ordering ties settled by date added to database
|
||||
// - We also expect presentation of NEWEST to OLDEST
|
||||
// - All null orderings are treated as older than any non-null ordering
|
||||
// (for this test, the 1.20.1, etc, versions are all null ordering)
|
||||
let game_version_versions = game_versions
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
game_version_versions,
|
||||
[
|
||||
"Ordering_Negative1",
|
||||
"Ordering_Positive100",
|
||||
"1.20.5",
|
||||
"1.20.4",
|
||||
"1.20.3",
|
||||
"1.20.2",
|
||||
"1.20.1"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
.collect_vec()
|
||||
);
|
||||
|
||||
let side_type_names = side_types.into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
side_type_names,
|
||||
["unknown", "required", "optional", "unsupported"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
})
|
||||
let loader_names =
|
||||
loaders.into_iter().map(|x| x.name).collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "bukkit", "waterfall"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let side_type_names =
|
||||
side_types.into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
side_type_names,
|
||||
["unknown", "required", "optional", "unsupported"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_donation_platforms() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let mut donation_platforms_unsorted = api.get_donation_platforms_deserialized().await;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let mut donation_platforms_unsorted =
|
||||
api.get_donation_platforms_deserialized().await;
|
||||
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes
|
||||
let mut included = vec![
|
||||
DonationPlatformQueryData {
|
||||
short: "patreon".to_string(),
|
||||
name: "Patreon".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "ko-fi".to_string(),
|
||||
name: "Ko-fi".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "paypal".to_string(),
|
||||
name: "PayPal".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "bmac".to_string(),
|
||||
name: "Buy Me A Coffee".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "github".to_string(),
|
||||
name: "GitHub Sponsors".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "other".to_string(),
|
||||
name: "Other".to_string(),
|
||||
},
|
||||
];
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes
|
||||
let mut included = vec![
|
||||
DonationPlatformQueryData {
|
||||
short: "patreon".to_string(),
|
||||
name: "Patreon".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "ko-fi".to_string(),
|
||||
name: "Ko-fi".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "paypal".to_string(),
|
||||
name: "PayPal".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "bmac".to_string(),
|
||||
name: "Buy Me A Coffee".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "github".to_string(),
|
||||
name: "GitHub Sponsors".to_string(),
|
||||
},
|
||||
DonationPlatformQueryData {
|
||||
short: "other".to_string(),
|
||||
name: "Other".to_string(),
|
||||
},
|
||||
];
|
||||
|
||||
included.sort_by(|a, b| a.short.cmp(&b.short));
|
||||
donation_platforms_unsorted.sort_by(|a, b| a.short.cmp(&b.short));
|
||||
included.sort_by(|a, b| a.short.cmp(&b.short));
|
||||
donation_platforms_unsorted.sort_by(|a, b| a.short.cmp(&b.short));
|
||||
|
||||
assert_eq!(donation_platforms_unsorted, included);
|
||||
})
|
||||
assert_eq!(donation_platforms_unsorted, included);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::{
|
||||
api_common::ApiTeams,
|
||||
api_v2::ApiV2,
|
||||
database::{
|
||||
FRIEND_USER_ID, FRIEND_USER_ID_PARSED, FRIEND_USER_PAT, USER_USER_ID_PARSED,
|
||||
USER_USER_PAT,
|
||||
FRIEND_USER_ID, FRIEND_USER_ID_PARSED, FRIEND_USER_PAT,
|
||||
USER_USER_ID_PARSED, USER_USER_PAT,
|
||||
},
|
||||
environment::{with_test_environment, TestEnvironment},
|
||||
},
|
||||
@@ -19,92 +19,120 @@ use crate::{
|
||||
#[actix_rt::test]
|
||||
async fn transfer_ownership_v2() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
||||
|
||||
// Cannot set friend as owner (not a member)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
// Cannot set friend as owner (not a member)
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Owner");
|
||||
assert_eq!(
|
||||
friend_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
// Check
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Owner");
|
||||
assert_eq!(
|
||||
friend_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
|
||||
let user_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_member.role, "Member");
|
||||
assert_eq!(user_member.permissions.unwrap(), ProjectPermissions::all());
|
||||
let user_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == USER_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(user_member.role, "Member");
|
||||
assert_eq!(
|
||||
user_member.permissions.unwrap(),
|
||||
ProjectPermissions::all()
|
||||
);
|
||||
|
||||
// Confirm that user, a user who still has full permissions, cannot then remove the owner
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
// Confirm that user, a user who still has full permissions, cannot then remove the owner
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// V2 only- confirm the owner changing the role to member does nothing
|
||||
let resp = api
|
||||
.edit_team_member(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
json!({
|
||||
"role": "Member"
|
||||
}),
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Owner");
|
||||
})
|
||||
// V2 only- confirm the owner changing the role to member does nothing
|
||||
let resp = api
|
||||
.edit_team_member(
|
||||
alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
json!({
|
||||
"role": "Member"
|
||||
}),
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
let friend_member = members
|
||||
.iter()
|
||||
.find(|x| x.user.id.0 == FRIEND_USER_ID_PARSED as u64)
|
||||
.unwrap();
|
||||
assert_eq!(friend_member.role, "Owner");
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -22,452 +22,499 @@ use crate::common::{
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn test_patch_version() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_version_id = &test_env.dummy.project_alpha.version_id;
|
||||
let alpha_version_id = &test_env.dummy.project_alpha.version_id;
|
||||
|
||||
// // First, we do some patch requests that should fail.
|
||||
// // Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "test 1",
|
||||
}),
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
// // First, we do some patch requests that should fail.
|
||||
// // Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"status": req,
|
||||
// requested status it not set here, but in /schedule
|
||||
"name": "test 1",
|
||||
}),
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"status": req,
|
||||
// requested status it not set here, but in /schedule
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "new version name",
|
||||
"version_number": "1.3.0",
|
||||
"changelog": "new changelog",
|
||||
"version_type": "beta",
|
||||
// // "dependencies": [], TODO: test this
|
||||
"game_versions": ["1.20.5"],
|
||||
"loaders": ["forge"],
|
||||
"featured": false,
|
||||
// "primary_file": [], TODO: test this
|
||||
// // "downloads": 0, TODO: moderator exclusive
|
||||
"status": "draft",
|
||||
// // "filetypes": ["jar"], TODO: test this
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "new version name",
|
||||
"version_number": "1.3.0",
|
||||
"changelog": "new changelog",
|
||||
"version_type": "beta",
|
||||
// // "dependencies": [], TODO: test this
|
||||
"game_versions": ["1.20.5"],
|
||||
"loaders": ["forge"],
|
||||
"featured": false,
|
||||
// "primary_file": [], TODO: test this
|
||||
// // "downloads": 0, TODO: moderator exclusive
|
||||
"status": "draft",
|
||||
// // "filetypes": ["jar"], TODO: test this
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.name, "new version name");
|
||||
assert_eq!(version.version_number, "1.3.0");
|
||||
assert_eq!(version.changelog, "new changelog");
|
||||
assert_eq!(
|
||||
version.version_type,
|
||||
serde_json::from_str::<VersionType>("\"beta\"").unwrap()
|
||||
);
|
||||
assert_eq!(version.game_versions, vec!["1.20.5"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]);
|
||||
assert!(!version.featured);
|
||||
assert_eq!(version.status, VersionStatus::from_string("draft"));
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.name, "new version name");
|
||||
assert_eq!(version.version_number, "1.3.0");
|
||||
assert_eq!(version.changelog, "new changelog");
|
||||
assert_eq!(
|
||||
version.version_type,
|
||||
serde_json::from_str::<VersionType>("\"beta\"").unwrap()
|
||||
);
|
||||
assert_eq!(version.game_versions, vec!["1.20.5"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]);
|
||||
assert!(!version.featured);
|
||||
assert_eq!(version.status, VersionStatus::from_string("draft"));
|
||||
// These ones are checking the v2-v3 rerouting, we eneusre that only 'game_versions'
|
||||
// works as expected, as well as only 'loaders'
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"game_versions": ["1.20.1", "1.20.2", "1.20.4"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// These ones are checking the v2-v3 rerouting, we eneusre that only 'game_versions'
|
||||
// works as expected, as well as only 'loaders'
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"game_versions": ["1.20.1", "1.20.2", "1.20.4"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(
|
||||
version.game_versions,
|
||||
vec!["1.20.1", "1.20.2", "1.20.4"]
|
||||
);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]); // From last patch
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]); // From last patch
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]); // From last patch
|
||||
assert_eq!(version.loaders, vec![Loader("fabric".to_string())]);
|
||||
})
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(
|
||||
version.game_versions,
|
||||
vec!["1.20.1", "1.20.2", "1.20.4"]
|
||||
); // From last patch
|
||||
assert_eq!(version.loaders, vec![Loader("fabric".to_string())]);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn version_updates() {
|
||||
// Test setup and dummy data
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let DummyProjectAlpha {
|
||||
project_id: alpha_project_id,
|
||||
project_id_parsed: alpha_project_id_parsed,
|
||||
version_id: alpha_version_id,
|
||||
file_hash: alpha_version_hash,
|
||||
..
|
||||
} = &test_env.dummy.project_alpha;
|
||||
let DummyProjectBeta {
|
||||
version_id: beta_version_id,
|
||||
file_hash: beta_version_hash,
|
||||
..
|
||||
} = &test_env.dummy.project_beta;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let DummyProjectAlpha {
|
||||
project_id: alpha_project_id,
|
||||
project_id_parsed: alpha_project_id_parsed,
|
||||
version_id: alpha_version_id,
|
||||
file_hash: alpha_version_hash,
|
||||
..
|
||||
} = &test_env.dummy.project_alpha;
|
||||
let DummyProjectBeta {
|
||||
version_id: beta_version_id,
|
||||
file_hash: beta_version_hash,
|
||||
..
|
||||
} = &test_env.dummy.project_beta;
|
||||
|
||||
// Quick test, using get version from hash
|
||||
let version = api
|
||||
.get_version_from_hash_deserialized(alpha_version_hash, "sha1", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// Get versions from hash
|
||||
let versions = api
|
||||
.get_versions_from_hashes_deserialized(
|
||||
&[alpha_version_hash.as_str(), beta_version_hash.as_str()],
|
||||
"sha1",
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 2);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
assert_eq!(&versions[beta_version_hash].id.to_string(), beta_version_id);
|
||||
|
||||
// When there is only the one version, there should be no updates
|
||||
let version = api
|
||||
.get_update_from_hash_deserialized_common(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
|
||||
// Add 3 new versions, 1 before, and 2 after, with differing game_version/version_types/loaders
|
||||
let mut update_ids = vec![];
|
||||
for (version_number, patch_value) in [
|
||||
(
|
||||
"0.9.9",
|
||||
json!({
|
||||
"game_versions": ["1.20.1"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.0",
|
||||
json!({
|
||||
"game_versions": ["1.20.3"],
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.1",
|
||||
json!({
|
||||
"game_versions": ["1.20.4"],
|
||||
"loaders": ["forge"],
|
||||
"version_type": "beta"
|
||||
}),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
// Quick test, using get version from hash
|
||||
let version = api
|
||||
.add_public_version_deserialized_common(
|
||||
*alpha_project_id_parsed,
|
||||
version_number,
|
||||
TestFile::build_random_jar(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
update_ids.push(version.id);
|
||||
|
||||
// Patch using json
|
||||
api.edit_version(&version.id.to_string(), patch_value.clone(), USER_USER_PAT)
|
||||
.await;
|
||||
}
|
||||
|
||||
let check_expected = |game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
.get_version_from_hash_deserialized(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let body: serde_json::Value = test::read_body_json(resp).await;
|
||||
let id = body["id"].as_str().unwrap();
|
||||
assert_eq!(id, &result_id.to_string());
|
||||
} else {
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// Get versions from hash
|
||||
let versions = api
|
||||
.get_versions_from_hashes_deserialized(
|
||||
&[alpha_version_hash.as_str(), beta_version_hash.as_str()],
|
||||
"sha1",
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 2);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
assert_eq!(
|
||||
&versions[beta_version_hash].id.to_string(),
|
||||
beta_version_id
|
||||
);
|
||||
|
||||
// When there is only the one version, there should be no updates
|
||||
let version = api
|
||||
.get_update_from_hash_deserialized_common(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
assert_eq!(versions.len(), 1);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
|
||||
// update_individual_files
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| serde_json::from_str(&format!("\"{v}\"")).unwrap())
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized("sha1", hashes, USER_USER_PAT)
|
||||
// Add 3 new versions, 1 before, and 2 after, with differing game_version/version_types/loaders
|
||||
let mut update_ids = vec![];
|
||||
for (version_number, patch_value) in [
|
||||
(
|
||||
"0.9.9",
|
||||
json!({
|
||||
"game_versions": ["1.20.1"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.0",
|
||||
json!({
|
||||
"game_versions": ["1.20.3"],
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.1",
|
||||
json!({
|
||||
"game_versions": ["1.20.4"],
|
||||
"loaders": ["forge"],
|
||||
"version_type": "beta"
|
||||
}),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
let version = api
|
||||
.add_public_version_deserialized_common(
|
||||
*alpha_project_id_parsed,
|
||||
version_number,
|
||||
TestFile::build_random_jar(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
update_ids.push(version.id);
|
||||
|
||||
// Patch using json
|
||||
api.edit_version(
|
||||
&version.id.to_string(),
|
||||
patch_value.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let tests = vec![
|
||||
check_expected(
|
||||
Some(vec!["1.20.1".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[0]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.3".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.4".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Loader restrictions
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Version type restrictions
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["beta".to_string()]),
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Specific combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
// Impossible combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["beta".to_string()]),
|
||||
None,
|
||||
),
|
||||
// No restrictions, should do the last one
|
||||
check_expected(None, None, None, Some(update_ids[2])),
|
||||
];
|
||||
let check_expected =
|
||||
|game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let body: serde_json::Value =
|
||||
test::read_body_json(resp).await;
|
||||
let id = body["id"].as_str().unwrap();
|
||||
assert_eq!(id, &result_id.to_string());
|
||||
} else {
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
// Wait on all tests, 4 at a time
|
||||
futures::stream::iter(tests)
|
||||
.buffer_unordered(4)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
|
||||
// We do a couple small tests for get_project_versions_deserialized as well
|
||||
// TODO: expand this more.
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 4);
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
})
|
||||
// update_individual_files
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| {
|
||||
serde_json::from_str(&format!("\"{v}\""))
|
||||
.unwrap()
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized(
|
||||
"sha1",
|
||||
hashes,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let tests = vec![
|
||||
check_expected(
|
||||
Some(vec!["1.20.1".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[0]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.3".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.4".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Loader restrictions
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Version type restrictions
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["beta".to_string()]),
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Specific combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
// Impossible combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["beta".to_string()]),
|
||||
None,
|
||||
),
|
||||
// No restrictions, should do the last one
|
||||
check_expected(None, None, None, Some(update_ids[2])),
|
||||
];
|
||||
|
||||
// Wait on all tests, 4 at a time
|
||||
futures::stream::iter(tests)
|
||||
.buffer_unordered(4)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
|
||||
// We do a couple small tests for get_project_versions_deserialized as well
|
||||
// TODO: expand this more.
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 4);
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn add_version_project_types_v2() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
// Since v2 no longer keeps project_type at the project level but the version level,
|
||||
// we have to test that the project_type is set correctly when adding a version, if its done in separate requests.
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
// Since v2 no longer keeps project_type at the project level but the version level,
|
||||
// we have to test that the project_type is set correctly when adding a version, if its done in separate requests.
|
||||
let api = &test_env.api;
|
||||
|
||||
// Create a project in v2 with project_type = modpack, and no initial version set.
|
||||
let (test_project, test_versions) = api
|
||||
.add_public_project("test-modpack", None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_versions.len(), 0); // No initial version set
|
||||
// Create a project in v2 with project_type = modpack, and no initial version set.
|
||||
let (test_project, test_versions) = api
|
||||
.add_public_project("test-modpack", None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_versions.len(), 0); // No initial version set
|
||||
|
||||
// Get as v2 project
|
||||
let test_project = api
|
||||
.get_project_deserialized(&test_project.slug.unwrap(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, "project"); // No project_type set, as no versions are set
|
||||
// Default to 'project' if none are found
|
||||
// This is a known difference between older v2 ,but is acceptable.
|
||||
// This would be the appropriate test on older v2:
|
||||
// assert_eq!(test_project.project_type, "modpack");
|
||||
// Get as v2 project
|
||||
let test_project = api
|
||||
.get_project_deserialized(
|
||||
&test_project.slug.unwrap(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, "project"); // No project_type set, as no versions are set
|
||||
// Default to 'project' if none are found
|
||||
// This is a known difference between older v2 ,but is acceptable.
|
||||
// This would be the appropriate test on older v2:
|
||||
// assert_eq!(test_project.project_type, "modpack");
|
||||
|
||||
// Create a version with a modpack file attached
|
||||
let test_version = api
|
||||
.add_public_version_deserialized_common(
|
||||
test_project.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_mrpack(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
// Create a version with a modpack file attached
|
||||
let test_version = api
|
||||
.add_public_version_deserialized_common(
|
||||
test_project.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_mrpack(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
// When we get the version as v2, it should display 'fabric' as the loader (and no project_type)
|
||||
let test_version = api
|
||||
.get_version_deserialized(&test_version.id.to_string(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_version.loaders, vec![Loader("fabric".to_string())]);
|
||||
// When we get the version as v2, it should display 'fabric' as the loader (and no project_type)
|
||||
let test_version = api
|
||||
.get_version_deserialized(
|
||||
&test_version.id.to_string(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(
|
||||
test_version.loaders,
|
||||
vec![Loader("fabric".to_string())]
|
||||
);
|
||||
|
||||
// When we get the project as v2, it should display 'modpack' as the project_type, and 'fabric' as the loader
|
||||
let test_project = api
|
||||
.get_project_deserialized(&test_project.slug.unwrap(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, "modpack");
|
||||
assert_eq!(test_project.loaders, vec!["fabric"]);
|
||||
// When we get the project as v2, it should display 'modpack' as the project_type, and 'fabric' as the loader
|
||||
let test_project = api
|
||||
.get_project_deserialized(
|
||||
&test_project.slug.unwrap(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, "modpack");
|
||||
assert_eq!(test_project.loaders, vec!["fabric"]);
|
||||
|
||||
// When we get the version as v3, it should display 'mrpack' as the loader, and 'modpack' as the project_type
|
||||
// When we get the project as v3, it should display 'modpack' as the project_type, and 'mrpack' as the loader
|
||||
// When we get the version as v3, it should display 'mrpack' as the loader, and 'modpack' as the project_type
|
||||
// When we get the project as v3, it should display 'modpack' as the project_type, and 'mrpack' as the loader
|
||||
|
||||
// The project should be a modpack project
|
||||
})
|
||||
// The project should be a modpack project
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -475,43 +522,49 @@ async fn add_version_project_types_v2() {
|
||||
async fn test_incorrect_file_parts() {
|
||||
// Ensures that a version get that 'should' have mrpack_loaders does still display them
|
||||
// if the file is 'mrpack' but the file_parts are incorrect
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
// Patch to set the file_parts to something incorrect
|
||||
let patch = json!([{
|
||||
"op": "add",
|
||||
"path": "/file_parts",
|
||||
"value": ["invalid.zip"] // one file, wrong non-mrpack extension
|
||||
}]);
|
||||
// Patch to set the file_parts to something incorrect
|
||||
let patch = json!([{
|
||||
"op": "add",
|
||||
"path": "/file_parts",
|
||||
"value": ["invalid.zip"] // one file, wrong non-mrpack extension
|
||||
}]);
|
||||
|
||||
// Create an empty project
|
||||
let slug = "test-project";
|
||||
let creation_data = get_public_project_creation_data(slug, None, None);
|
||||
let resp = api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// Create an empty project
|
||||
let slug = "test-project";
|
||||
let creation_data =
|
||||
get_public_project_creation_data(slug, None, None);
|
||||
let resp = api.create_project(creation_data, USER_USER_PAT).await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
|
||||
// Get the project
|
||||
let project = api.get_project_deserialized(slug, USER_USER_PAT).await;
|
||||
assert_eq!(project.project_type, "project");
|
||||
// Get the project
|
||||
let project =
|
||||
api.get_project_deserialized(slug, USER_USER_PAT).await;
|
||||
assert_eq!(project.project_type, "project");
|
||||
|
||||
// Create a version with a mrpack file, but incorrect file_parts
|
||||
let resp = api
|
||||
.add_public_version(
|
||||
project.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_mrpack(),
|
||||
None,
|
||||
Some(serde_json::from_value(patch).unwrap()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
// Create a version with a mrpack file, but incorrect file_parts
|
||||
let resp = api
|
||||
.add_public_version(
|
||||
project.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_mrpack(),
|
||||
None,
|
||||
Some(serde_json::from_value(patch).unwrap()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
|
||||
// Get the project now, which should be now correctly identified as a modpack
|
||||
let project = api.get_project_deserialized(slug, USER_USER_PAT).await;
|
||||
assert_eq!(project.project_type, "modpack");
|
||||
assert_eq!(project.loaders, vec!["fabric"]);
|
||||
})
|
||||
// Get the project now, which should be now correctly identified as a modpack
|
||||
let project =
|
||||
api.get_project_deserialized(slug, USER_USER_PAT).await;
|
||||
assert_eq!(project.project_type, "modpack");
|
||||
assert_eq!(project.loaders, vec!["fabric"]);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::common::api_common::ApiVersion;
|
||||
use crate::common::database::*;
|
||||
use crate::common::dummy_data::{DummyProjectAlpha, DummyProjectBeta, TestFile};
|
||||
use crate::common::dummy_data::{
|
||||
DummyProjectAlpha, DummyProjectBeta, TestFile,
|
||||
};
|
||||
use crate::common::get_json_val_str;
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
@@ -53,7 +55,8 @@ async fn test_get_version() {
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let cached_project: serde_json::Value = serde_json::from_str(&cached_project).unwrap();
|
||||
let cached_project: serde_json::Value =
|
||||
serde_json::from_str(&cached_project).unwrap();
|
||||
assert_eq!(
|
||||
cached_project["val"]["inner"]["project_id"],
|
||||
json!(parse_base62(alpha_project_id).unwrap())
|
||||
@@ -124,7 +127,10 @@ async fn version_updates() {
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
assert_eq!(&versions[beta_version_hash].id.to_string(), beta_version_id);
|
||||
assert_eq!(
|
||||
&versions[beta_version_hash].id.to_string(),
|
||||
beta_version_id
|
||||
);
|
||||
|
||||
// When there is only the one version, there should be no updates
|
||||
let version = api
|
||||
@@ -195,90 +201,103 @@ async fn version_updates() {
|
||||
update_ids.push(version.id);
|
||||
|
||||
// Patch using json
|
||||
api.edit_version(&version.id.to_string(), patch_value.clone(), USER_USER_PAT)
|
||||
.await;
|
||||
api.edit_version(
|
||||
&version.id.to_string(),
|
||||
patch_value.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
let check_expected = |game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
let check_expected =
|
||||
|game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let body: serde_json::Value =
|
||||
test::read_body_json(resp).await;
|
||||
let id = body["id"].as_str().unwrap();
|
||||
assert_eq!(id, &result_id.to_string());
|
||||
} else {
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
|
||||
// update_individual_files
|
||||
let mut loader_fields = HashMap::new();
|
||||
if let Some(game_versions) = game_versions {
|
||||
loader_fields.insert(
|
||||
"game_versions".to_string(),
|
||||
game_versions
|
||||
.into_iter()
|
||||
.map(|v| json!(v))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
loader_fields: Some(loader_fields),
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| {
|
||||
serde_json::from_str(&format!("\"{v}\""))
|
||||
.unwrap()
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized(
|
||||
"sha1",
|
||||
hashes,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_status!(&resp, StatusCode::OK);
|
||||
let body: serde_json::Value = test::read_body_json(resp).await;
|
||||
let id = body["id"].as_str().unwrap();
|
||||
assert_eq!(id, &result_id.to_string());
|
||||
} else {
|
||||
assert_status!(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
|
||||
// update_individual_files
|
||||
let mut loader_fields = HashMap::new();
|
||||
if let Some(game_versions) = game_versions {
|
||||
loader_fields.insert(
|
||||
"game_versions".to_string(),
|
||||
game_versions
|
||||
.into_iter()
|
||||
.map(|v| json!(v))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
loader_fields: Some(loader_fields),
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| serde_json::from_str(&format!("\"{v}\"")).unwrap())
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized("sha1", hashes, USER_USER_PAT)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let tests = vec![
|
||||
check_expected(
|
||||
@@ -513,7 +532,8 @@ pub async fn test_patch_version() {
|
||||
pub async fn test_project_versions() {
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
let api = &test_env.api;
|
||||
let alpha_project_id: &String = &test_env.dummy.project_alpha.project_id;
|
||||
let alpha_project_id: &String =
|
||||
&test_env.dummy.project_alpha.project_id;
|
||||
let alpha_version_id = &test_env.dummy.project_alpha.version_id;
|
||||
|
||||
let versions = api
|
||||
@@ -539,7 +559,8 @@ async fn can_create_version_with_ordering() {
|
||||
with_test_environment(
|
||||
None,
|
||||
|env: common::environment::TestEnvironment<ApiV3>| async move {
|
||||
let alpha_project_id_parsed = env.dummy.project_alpha.project_id_parsed;
|
||||
let alpha_project_id_parsed =
|
||||
env.dummy.project_alpha.project_id_parsed;
|
||||
|
||||
let new_version_id = get_json_val_str(
|
||||
env.api
|
||||
@@ -557,7 +578,10 @@ async fn can_create_version_with_ordering() {
|
||||
|
||||
let versions = env
|
||||
.api
|
||||
.get_versions_deserialized(vec![new_version_id.clone()], USER_USER_PAT)
|
||||
.get_versions_deserialized(
|
||||
vec![new_version_id.clone()],
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions[0].ordering, Some(1));
|
||||
},
|
||||
@@ -574,13 +598,20 @@ async fn edit_version_ordering_works() {
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
.edit_version_ordering(&alpha_version_id, Some(10), USER_USER_PAT)
|
||||
.edit_version_ordering(
|
||||
&alpha_version_id,
|
||||
Some(10),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status!(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let versions = env
|
||||
.api
|
||||
.get_versions_deserialized(vec![alpha_version_id.clone()], USER_USER_PAT)
|
||||
.get_versions_deserialized(
|
||||
vec![alpha_version_id.clone()],
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions[0].ordering, Some(10));
|
||||
},
|
||||
@@ -618,7 +649,10 @@ async fn version_ordering_for_specified_orderings_orders_lower_order_first() {
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_common_version_ids(&versions, vec![new_version_id, alpha_version_id]);
|
||||
assert_common_version_ids(
|
||||
&versions,
|
||||
vec![new_version_id, alpha_version_id],
|
||||
);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -627,7 +661,8 @@ async fn version_ordering_for_specified_orderings_orders_lower_order_first() {
|
||||
async fn version_ordering_when_unspecified_orders_oldest_first() {
|
||||
with_test_environment_all(None, |env| async move {
|
||||
let alpha_project_id_parsed = env.dummy.project_alpha.project_id_parsed;
|
||||
let alpha_version_id: String = env.dummy.project_alpha.version_id.clone();
|
||||
let alpha_version_id: String =
|
||||
env.dummy.project_alpha.version_id.clone();
|
||||
let new_version_id = get_json_val_str(
|
||||
env.api
|
||||
.add_public_version_deserialized_common(
|
||||
@@ -649,7 +684,10 @@ async fn version_ordering_when_unspecified_orders_oldest_first() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_common_version_ids(&versions, vec![alpha_version_id, new_version_id]);
|
||||
assert_common_version_ids(
|
||||
&versions,
|
||||
vec![alpha_version_id, new_version_id],
|
||||
);
|
||||
})
|
||||
.await
|
||||
}
|
||||
@@ -683,7 +721,10 @@ async fn version_ordering_when_specified_orders_specified_before_unspecified() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_common_version_ids(&versions, vec![new_version_id, alpha_version_id]);
|
||||
assert_common_version_ids(
|
||||
&versions,
|
||||
vec![new_version_id, alpha_version_id],
|
||||
);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user