* chore(clippy): enable and fix many stricter lints These ensure that the codebase uses more idiomatic, performant, and concise language constructions. * chore: make non-Clippy compiler warnings also deny by default
1365 lines
50 KiB
Rust
1365 lines
50 KiB
Rust
use actix_http::StatusCode;
|
|
use actix_web::test;
|
|
use common::api_v3::ApiV3;
|
|
use common::database::*;
|
|
use common::dummy_data::DUMMY_CATEGORIES;
|
|
|
|
use crate::common::api_common::models::CommonProject;
|
|
use crate::common::api_common::request_data::ProjectCreationRequestData;
|
|
use crate::common::api_common::{ApiProject, ApiTeams, ApiVersion};
|
|
use crate::common::dummy_data::{
|
|
DummyImage, DummyOrganizationZeta, DummyProjectAlpha, DummyProjectBeta,
|
|
TestFile,
|
|
};
|
|
use ariadne::ids::base62_impl::parse_base62;
|
|
use common::environment::{
|
|
TestEnvironment, with_test_environment, with_test_environment_all,
|
|
};
|
|
use common::permissions::{PermissionsTest, PermissionsTestContext};
|
|
use futures::StreamExt;
|
|
use hex::ToHex;
|
|
use labrinth::database::models::project_item::{
|
|
PROJECTS_NAMESPACE, PROJECTS_SLUGS_NAMESPACE,
|
|
};
|
|
use labrinth::models::ids::ProjectId;
|
|
use labrinth::models::teams::ProjectPermissions;
|
|
use labrinth::util::actix::{MultipartSegment, MultipartSegmentData};
|
|
use serde_json::json;
|
|
use sha1::Digest;
|
|
|
|
pub mod common;
|
|
|
|
#[actix_rt::test]
|
|
async fn test_get_project() {
|
|
// Test setup and dummy data
|
|
with_test_environment_all(None, |test_env| async move {
|
|
let DummyProjectAlpha {
|
|
project_id: alpha_project_id,
|
|
project_slug: alpha_project_slug,
|
|
version_id: alpha_version_id,
|
|
..
|
|
} = &test_env.dummy.project_alpha;
|
|
let DummyProjectBeta {
|
|
project_id: beta_project_id,
|
|
..
|
|
} = &test_env.dummy.project_beta;
|
|
|
|
let api = &test_env.api;
|
|
|
|
// Perform request on dummy data
|
|
let resp = api.get_project(alpha_project_id, USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::OK);
|
|
let body: serde_json::Value = test::read_body_json(resp).await;
|
|
|
|
assert_eq!(body["id"], json!(alpha_project_id));
|
|
assert_eq!(body["slug"], json!(alpha_project_slug));
|
|
let versions = body["versions"].as_array().unwrap();
|
|
assert_eq!(versions[0], json!(alpha_version_id));
|
|
|
|
// Confirm that the request was cached
|
|
let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap();
|
|
assert_eq!(
|
|
redis_pool
|
|
.get(PROJECTS_SLUGS_NAMESPACE, alpha_project_slug)
|
|
.await
|
|
.unwrap()
|
|
.and_then(|x| x.parse::<i64>().ok()),
|
|
Some(parse_base62(alpha_project_id).unwrap() as i64)
|
|
);
|
|
|
|
let cached_project = redis_pool
|
|
.get(
|
|
PROJECTS_NAMESPACE,
|
|
&parse_base62(alpha_project_id).unwrap().to_string(),
|
|
)
|
|
.await
|
|
.unwrap()
|
|
.unwrap();
|
|
let cached_project: serde_json::Value =
|
|
serde_json::from_str(&cached_project).unwrap();
|
|
assert_eq!(
|
|
cached_project["val"]["inner"]["slug"],
|
|
json!(alpha_project_slug)
|
|
);
|
|
|
|
// Make the request again, this time it should be cached
|
|
let resp = api.get_project(alpha_project_id, USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::OK);
|
|
|
|
let body: serde_json::Value = test::read_body_json(resp).await;
|
|
assert_eq!(body["id"], json!(alpha_project_id));
|
|
assert_eq!(body["slug"], json!(alpha_project_slug));
|
|
|
|
// Request should fail on non-existent project
|
|
let resp = api.get_project("nonexistent", USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NOT_FOUND);
|
|
|
|
// Similarly, request should fail on non-authorized user, on a yet-to-be-approved or hidden project, with a 404 (hiding the existence of the project)
|
|
let resp = api.get_project(beta_project_id, ENEMY_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NOT_FOUND);
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn test_add_remove_project() {
|
|
// Test setup and dummy data
|
|
with_test_environment(
|
|
None,
|
|
|test_env: TestEnvironment<ApiV3>| async move {
|
|
let api = &test_env.api;
|
|
|
|
// Generate test project data.
|
|
let mut json_data = api
|
|
.get_public_project_creation_data_json(
|
|
"demo",
|
|
Some(&TestFile::BasicMod),
|
|
)
|
|
.await;
|
|
|
|
// Basic json
|
|
let json_segment = MultipartSegment {
|
|
name: "data".to_string(),
|
|
filename: None,
|
|
content_type: Some("application/json".to_string()),
|
|
data: MultipartSegmentData::Text(
|
|
serde_json::to_string(&json_data).unwrap(),
|
|
),
|
|
};
|
|
|
|
// Basic json, with a different file
|
|
json_data["initial_versions"][0]["file_parts"][0] =
|
|
json!("basic-mod-different.jar");
|
|
let json_diff_file_segment = MultipartSegment {
|
|
data: MultipartSegmentData::Text(
|
|
serde_json::to_string(&json_data).unwrap(),
|
|
),
|
|
..json_segment.clone()
|
|
};
|
|
|
|
// Basic json, with a different file, and a different slug
|
|
json_data["slug"] = json!("new_demo");
|
|
json_data["initial_versions"][0]["file_parts"][0] =
|
|
json!("basic-mod-different.jar");
|
|
let json_diff_slug_file_segment = MultipartSegment {
|
|
data: MultipartSegmentData::Text(
|
|
serde_json::to_string(&json_data).unwrap(),
|
|
),
|
|
..json_segment.clone()
|
|
};
|
|
|
|
let basic_mod_file = TestFile::BasicMod;
|
|
let basic_mod_different_file = TestFile::BasicModDifferent;
|
|
|
|
// Basic file
|
|
let file_segment = MultipartSegment {
|
|
// 'Basic'
|
|
name: basic_mod_file.filename(),
|
|
filename: Some(basic_mod_file.filename()),
|
|
content_type: basic_mod_file.content_type(),
|
|
data: MultipartSegmentData::Binary(basic_mod_file.bytes()),
|
|
};
|
|
|
|
// Differently named file, with the SAME content (for hash testing)
|
|
let file_diff_name_segment = MultipartSegment {
|
|
// 'Different'
|
|
name: basic_mod_different_file.filename(),
|
|
filename: Some(basic_mod_different_file.filename()),
|
|
content_type: basic_mod_different_file.content_type(),
|
|
// 'Basic'
|
|
data: MultipartSegmentData::Binary(basic_mod_file.bytes()),
|
|
};
|
|
|
|
// Differently named file, with different content
|
|
let file_diff_name_content_segment = MultipartSegment {
|
|
// 'Different'
|
|
name: basic_mod_different_file.filename(),
|
|
filename: Some(basic_mod_different_file.filename()),
|
|
content_type: basic_mod_different_file.content_type(),
|
|
data: MultipartSegmentData::Binary(
|
|
basic_mod_different_file.bytes(),
|
|
),
|
|
};
|
|
|
|
// Add a project- simple, should work.
|
|
let resp = api
|
|
.create_project(
|
|
ProjectCreationRequestData {
|
|
slug: "demo".to_string(),
|
|
segment_data: vec![
|
|
json_segment.clone(),
|
|
file_segment.clone(),
|
|
],
|
|
jar: None, // File not needed at this point
|
|
},
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
|
|
assert_status!(&resp, StatusCode::OK);
|
|
|
|
// Get the project we just made, and confirm that it's correct
|
|
let project = api
|
|
.get_project_deserialized_common("demo", USER_USER_PAT)
|
|
.await;
|
|
assert!(project.versions.len() == 1);
|
|
let uploaded_version_id = project.versions[0];
|
|
|
|
// Checks files to ensure they were uploaded and correctly identify the file
|
|
let hash = sha1::Sha1::digest(basic_mod_file.bytes())
|
|
.encode_hex::<String>();
|
|
let version = api
|
|
.get_version_from_hash_deserialized_common(
|
|
&hash,
|
|
"sha1",
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_eq!(version.id, uploaded_version_id);
|
|
|
|
// Reusing with a different slug and the same file should fail
|
|
// Even if that file is named differently
|
|
let resp = api
|
|
.create_project(
|
|
ProjectCreationRequestData {
|
|
slug: "demo".to_string(),
|
|
segment_data: vec![
|
|
json_diff_slug_file_segment.clone(),
|
|
file_diff_name_segment.clone(),
|
|
],
|
|
jar: None, // File not needed at this point
|
|
},
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
|
|
|
// Reusing with the same slug and a different file should fail
|
|
let resp = api
|
|
.create_project(
|
|
ProjectCreationRequestData {
|
|
slug: "demo".to_string(),
|
|
segment_data: vec![
|
|
json_diff_file_segment.clone(),
|
|
file_diff_name_content_segment.clone(),
|
|
],
|
|
jar: None, // File not needed at this point
|
|
},
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
|
|
|
// Different slug, different file should succeed
|
|
let resp = api
|
|
.create_project(
|
|
ProjectCreationRequestData {
|
|
slug: "demo".to_string(),
|
|
segment_data: vec![
|
|
json_diff_slug_file_segment.clone(),
|
|
file_diff_name_content_segment.clone(),
|
|
],
|
|
jar: None, // File not needed at this point
|
|
},
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::OK);
|
|
|
|
// Get
|
|
let project = api
|
|
.get_project_deserialized_common("demo", USER_USER_PAT)
|
|
.await;
|
|
let id = project.id.to_string();
|
|
|
|
// Remove the project
|
|
let resp = test_env.api.remove_project("demo", USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
// Confirm that the project is gone from the cache
|
|
let mut redis_pool =
|
|
test_env.db.redis_pool.connect().await.unwrap();
|
|
assert_eq!(
|
|
redis_pool
|
|
.get(PROJECTS_SLUGS_NAMESPACE, "demo")
|
|
.await
|
|
.unwrap()
|
|
.and_then(|x| x.parse::<i64>().ok()),
|
|
None
|
|
);
|
|
assert_eq!(
|
|
redis_pool
|
|
.get(PROJECTS_SLUGS_NAMESPACE, &id)
|
|
.await
|
|
.unwrap()
|
|
.and_then(|x| x.parse::<i64>().ok()),
|
|
None
|
|
);
|
|
|
|
// Old slug no longer works
|
|
let resp = api.get_project("demo", USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NOT_FOUND);
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
pub async fn test_patch_project() {
|
|
with_test_environment(
|
|
None,
|
|
|test_env: TestEnvironment<ApiV3>| async move {
|
|
let api = &test_env.api;
|
|
|
|
let alpha_project_slug = &test_env.dummy.project_alpha.project_slug;
|
|
let beta_project_slug = &test_env.dummy.project_beta.project_slug;
|
|
|
|
// First, we do some patch requests that should fail.
|
|
// Failure because the user is not authorized.
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"name": "Test_Add_Project project - test 1",
|
|
}),
|
|
ENEMY_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
|
|
|
// Failure because we are setting URL fields to invalid urls.
|
|
for url_type in ["issues", "source", "wiki", "discord"] {
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"link_urls": {
|
|
url_type: "not a url",
|
|
},
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
|
}
|
|
|
|
// Failure because these are illegal requested statuses for a normal user.
|
|
for req in ["unknown", "processing", "withheld", "scheduled"] {
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"requested_status": req,
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
|
}
|
|
|
|
// Failure because these should not be able to be set by a non-mod
|
|
for key in ["moderation_message", "moderation_message_body"] {
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
key: "test",
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
|
|
|
// (should work for a mod, though)
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
key: "test",
|
|
}),
|
|
MOD_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
}
|
|
|
|
// Failed patch to alpha slug:
|
|
// - slug collision with beta
|
|
// - too short slug
|
|
// - too long slug
|
|
// - not url safe slug
|
|
// - not url safe slug
|
|
for slug in [
|
|
beta_project_slug,
|
|
"a",
|
|
&"a".repeat(100),
|
|
"not url safe%&^!#$##!@#$%^&*()",
|
|
] {
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"slug": slug, // the other dummy project has this slug
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::BAD_REQUEST);
|
|
}
|
|
|
|
// Not allowed to directly set status, as 'beta_project_slug' (the other project) is "processing" and cannot have its status changed like this.
|
|
let resp = api
|
|
.edit_project(
|
|
beta_project_slug,
|
|
json!({
|
|
"status": "private"
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
|
|
|
// Sucessful request to patch many fields.
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"slug": "newslug",
|
|
"categories": [DUMMY_CATEGORIES[0]],
|
|
"license_id": "MIT",
|
|
"link_urls":
|
|
{
|
|
"patreon": "https://patreon.com",
|
|
"issues": "https://github.com",
|
|
"discord": "https://discord.gg",
|
|
"wiki": "https://wiki.com"
|
|
}
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
// Old slug no longer works
|
|
let resp = api.get_project(alpha_project_slug, USER_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NOT_FOUND);
|
|
|
|
// New slug does work
|
|
let project =
|
|
api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
|
|
|
assert_eq!(project.slug.unwrap(), "newslug");
|
|
assert_eq!(project.categories, vec![DUMMY_CATEGORIES[0]]);
|
|
assert_eq!(project.license.id, "MIT");
|
|
|
|
let link_urls = project.link_urls;
|
|
assert_eq!(link_urls.len(), 4);
|
|
assert_eq!(link_urls["patreon"].platform, "patreon");
|
|
assert_eq!(link_urls["patreon"].url, "https://patreon.com");
|
|
assert!(link_urls["patreon"].donation);
|
|
assert_eq!(link_urls["issues"].platform, "issues");
|
|
assert_eq!(link_urls["issues"].url, "https://github.com");
|
|
assert!(!link_urls["issues"].donation);
|
|
assert_eq!(link_urls["discord"].platform, "discord");
|
|
assert_eq!(link_urls["discord"].url, "https://discord.gg");
|
|
assert!(!link_urls["discord"].donation);
|
|
assert_eq!(link_urls["wiki"].platform, "wiki");
|
|
assert_eq!(link_urls["wiki"].url, "https://wiki.com");
|
|
assert!(!link_urls["wiki"].donation);
|
|
|
|
// Unset the set link_urls
|
|
let resp = api
|
|
.edit_project(
|
|
"newslug",
|
|
json!({
|
|
"link_urls":
|
|
{
|
|
"issues": null,
|
|
}
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
let project =
|
|
api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
|
assert_eq!(project.link_urls.len(), 3);
|
|
assert!(!project.link_urls.contains_key("issues"));
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
pub async fn test_patch_v3() {
|
|
// Hits V3-specific patchable fields
|
|
with_test_environment(
|
|
None,
|
|
|test_env: TestEnvironment<ApiV3>| async move {
|
|
let api = &test_env.api;
|
|
|
|
let alpha_project_slug = &test_env.dummy.project_alpha.project_slug;
|
|
|
|
// Sucessful request to patch many fields.
|
|
let resp = api
|
|
.edit_project(
|
|
alpha_project_slug,
|
|
json!({
|
|
"name": "New successful title",
|
|
"summary": "New successful summary",
|
|
"description": "New successful description",
|
|
}),
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
let project = api
|
|
.get_project_deserialized(alpha_project_slug, USER_USER_PAT)
|
|
.await;
|
|
|
|
assert_eq!(project.name, "New successful title");
|
|
assert_eq!(project.summary, "New successful summary");
|
|
assert_eq!(project.description, "New successful description");
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
pub async fn test_bulk_edit_categories() {
|
|
with_test_environment_all(None, |test_env| async move {
|
|
let api = &test_env.api;
|
|
let alpha_project_id: &str = &test_env.dummy.project_alpha.project_id;
|
|
let beta_project_id: &str = &test_env.dummy.project_beta.project_id;
|
|
|
|
let resp = api
|
|
.edit_project_bulk(
|
|
&[alpha_project_id, beta_project_id],
|
|
json!({
|
|
"categories": [DUMMY_CATEGORIES[0], DUMMY_CATEGORIES[3]],
|
|
"add_categories": [DUMMY_CATEGORIES[1], DUMMY_CATEGORIES[2]],
|
|
"remove_categories": [DUMMY_CATEGORIES[3]],
|
|
"additional_categories": [DUMMY_CATEGORIES[4], DUMMY_CATEGORIES[6]],
|
|
"add_additional_categories": [DUMMY_CATEGORIES[5]],
|
|
"remove_additional_categories": [DUMMY_CATEGORIES[6]],
|
|
}),
|
|
ADMIN_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
let alpha_body = api
|
|
.get_project_deserialized_common(alpha_project_id, ADMIN_USER_PAT)
|
|
.await;
|
|
assert_eq!(alpha_body.categories, DUMMY_CATEGORIES[0..=2]);
|
|
assert_eq!(alpha_body.additional_categories, DUMMY_CATEGORIES[4..=5]);
|
|
|
|
let beta_body = api
|
|
.get_project_deserialized_common(beta_project_id, ADMIN_USER_PAT)
|
|
.await;
|
|
assert_eq!(beta_body.categories, alpha_body.categories);
|
|
assert_eq!(
|
|
beta_body.additional_categories,
|
|
alpha_body.additional_categories,
|
|
);
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
pub async fn test_bulk_edit_links() {
|
|
with_test_environment(
|
|
None,
|
|
|test_env: TestEnvironment<ApiV3>| async move {
|
|
let api = &test_env.api;
|
|
let alpha_project_id: &str =
|
|
&test_env.dummy.project_alpha.project_id;
|
|
let beta_project_id: &str = &test_env.dummy.project_beta.project_id;
|
|
|
|
// Sets links for issue, source, wiki, and patreon for all projects
|
|
// The first loop, sets issue, the second, clears it for all projects.
|
|
for issues in [Some("https://www.issues.com"), None] {
|
|
let resp = api
|
|
.edit_project_bulk(
|
|
&[alpha_project_id, beta_project_id],
|
|
json!({
|
|
"link_urls": {
|
|
"issues": issues,
|
|
"wiki": "https://wiki.com",
|
|
"patreon": "https://patreon.com",
|
|
},
|
|
}),
|
|
ADMIN_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
let alpha_body = api
|
|
.get_project_deserialized(alpha_project_id, ADMIN_USER_PAT)
|
|
.await;
|
|
if let Some(issues) = issues {
|
|
assert_eq!(alpha_body.link_urls.len(), 3);
|
|
assert_eq!(alpha_body.link_urls["issues"].url, issues);
|
|
} else {
|
|
assert_eq!(alpha_body.link_urls.len(), 2);
|
|
assert!(!alpha_body.link_urls.contains_key("issues"));
|
|
}
|
|
assert_eq!(
|
|
alpha_body.link_urls["wiki"].url,
|
|
"https://wiki.com"
|
|
);
|
|
assert_eq!(
|
|
alpha_body.link_urls["patreon"].url,
|
|
"https://patreon.com"
|
|
);
|
|
|
|
let beta_body = api
|
|
.get_project_deserialized(beta_project_id, ADMIN_USER_PAT)
|
|
.await;
|
|
assert_eq!(beta_body.categories, alpha_body.categories);
|
|
assert_eq!(
|
|
beta_body.additional_categories,
|
|
alpha_body.additional_categories,
|
|
);
|
|
}
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn permissions_patch_project_v3() {
|
|
with_test_environment(Some(8), |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 api = &test_env.api;
|
|
// TODO: This should be a separate test from v3
|
|
// - only a couple of these fields are v3-specific
|
|
// once we have permissions/scope tests setup to not just take closures, we can split this up
|
|
|
|
// For each permission covered by EDIT_DETAILS, ensure the permission is required
|
|
let edit_details = ProjectPermissions::EDIT_DETAILS;
|
|
let test_pairs = [
|
|
// Body, status, requested_status tested separately
|
|
("slug", json!("")), // generated in the test to not collide slugs
|
|
("name", json!("randomname")),
|
|
("description", json!("randomdescription")),
|
|
("categories", json!(["combat", "economy"])),
|
|
("additional_categories", json!(["decoration"])),
|
|
(
|
|
"links",
|
|
json!({
|
|
"issues": "https://issues.com",
|
|
"source": "https://source.com",
|
|
}),
|
|
),
|
|
("license_id", json!("MIT")),
|
|
];
|
|
|
|
futures::stream::iter(test_pairs)
|
|
.map(|(key, value)| {
|
|
let test_env = test_env.clone();
|
|
async move {
|
|
let req_gen = |ctx: PermissionsTestContext| {
|
|
let value = value.clone();
|
|
async move {
|
|
api.edit_project(
|
|
&ctx.project_id.unwrap(),
|
|
json!({
|
|
key: if key == "slug" {
|
|
json!(generate_random_name("randomslug"))
|
|
} else {
|
|
value.clone()
|
|
},
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
}
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.into_iter();
|
|
}
|
|
})
|
|
.buffer_unordered(4)
|
|
.collect::<Vec<_>>()
|
|
.await;
|
|
|
|
// Test with status and requested_status
|
|
// This requires a project with a version, so we use alpha_project_id
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project(
|
|
&ctx.project_id.unwrap(),
|
|
json!({
|
|
"status": "private",
|
|
"requested_status": "private",
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Bulk patch projects
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project_bulk(
|
|
&[&ctx.project_id.unwrap()],
|
|
json!({
|
|
"name": "randomname",
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Edit body
|
|
// Cannot bulk edit body
|
|
let edit_body = ProjectPermissions::EDIT_BODY;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project(
|
|
&ctx.project_id.unwrap(),
|
|
json!({
|
|
"description": "new description!",
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.simple_project_permissions_test(edit_body, req_gen)
|
|
.await
|
|
.unwrap();
|
|
})
|
|
.await;
|
|
}
|
|
|
|
// TODO: Project scheduling has been temporarily disabled, so this test is disabled as well
|
|
// #[actix_rt::test]
|
|
// async fn permissions_schedule() {
|
|
// with_test_environment(None, |test_env : TestEnvironment<ApiV3>| async move {
|
|
// let DummyProjectAlpha {
|
|
// project_id: alpha_project_id,
|
|
// team_id: alpha_team_id,
|
|
// ..
|
|
// } = &test_env.dummy.project_alpha;
|
|
// let DummyProjectBeta {
|
|
// project_id: beta_project_id,
|
|
// version_id: beta_version_id,
|
|
// team_id: beta_team_id,
|
|
// ..
|
|
// } = &test_env.dummy.project_beta;
|
|
|
|
// let edit_details = ProjectPermissions::EDIT_DETAILS;
|
|
// let api = &test_env.api;
|
|
|
|
// // Approve beta version as private so we can schedule it
|
|
// let resp = api
|
|
// .edit_version(
|
|
// beta_version_id,
|
|
// json!({
|
|
// "status": "unlisted"
|
|
// }),
|
|
// MOD_USER_PAT,
|
|
// )
|
|
// .await;
|
|
// assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
// // Schedule version
|
|
// let req_gen = |ctx: PermissionsTestContext| async move {
|
|
// api.schedule_version(
|
|
// beta_version_id,
|
|
// "archived",
|
|
// Utc::now() + Duration::days(1),
|
|
// ctx.test_pat.as_deref(),
|
|
// )
|
|
// .await
|
|
// };
|
|
// PermissionsTest::new(&test_env)
|
|
// .with_existing_project(beta_project_id, beta_team_id)
|
|
// .with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
// .simple_project_permissions_test(edit_details, req_gen)
|
|
// .await
|
|
// .unwrap();
|
|
// }).await
|
|
// }
|
|
|
|
// Not covered by PATCH /project
|
|
#[actix_rt::test]
|
|
async fn permissions_edit_details() {
|
|
with_test_environment_all(Some(10), |test_env| async move {
|
|
let DummyProjectAlpha {
|
|
project_id: alpha_project_id,
|
|
team_id: alpha_team_id,
|
|
..
|
|
} = &test_env.dummy.project_alpha;
|
|
|
|
let edit_details = ProjectPermissions::EDIT_DETAILS;
|
|
let api = &test_env.api;
|
|
|
|
// Icon edit
|
|
// Uses alpha project to delete this icon
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project_icon(
|
|
&ctx.project_id.unwrap(),
|
|
Some(DummyImage::SmallIcon.get_icon_data()),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Icon delete
|
|
// Uses alpha project to delete added icon
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project_icon(
|
|
&ctx.project_id.unwrap(),
|
|
None,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Add gallery item
|
|
// Uses alpha project to add gallery item so we can get its url
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.add_gallery_item(
|
|
&ctx.project_id.unwrap(),
|
|
DummyImage::SmallIcon.get_icon_data(),
|
|
true,
|
|
None,
|
|
None,
|
|
None,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
// Get project, as we need the gallery image url
|
|
let resp = api.get_project(alpha_project_id, USER_USER_PAT).await;
|
|
let project: serde_json::Value = test::read_body_json(resp).await;
|
|
let gallery_url = project["gallery"][0]["url"].as_str().unwrap();
|
|
|
|
// Edit gallery item
|
|
// Uses alpha project to edit gallery item
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_gallery_item(
|
|
&ctx.project_id.unwrap(),
|
|
gallery_url,
|
|
vec![("description".to_string(), "new caption!".to_string())]
|
|
.into_iter()
|
|
.collect(),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Remove gallery item
|
|
// Uses alpha project to remove gallery item
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_gallery_item(
|
|
&ctx.project_id.unwrap(),
|
|
gallery_url,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_details, req_gen)
|
|
.await
|
|
.unwrap();
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn permissions_upload_version() {
|
|
with_test_environment(
|
|
None,
|
|
|test_env: TestEnvironment<ApiV3>| async move {
|
|
let alpha_project_id = &test_env.dummy.project_alpha.project_id;
|
|
let alpha_version_id = &test_env.dummy.project_alpha.version_id;
|
|
let alpha_team_id = &test_env.dummy.project_alpha.team_id;
|
|
let alpha_file_hash = &test_env.dummy.project_alpha.file_hash;
|
|
|
|
let api = &test_env.api;
|
|
|
|
let upload_version = ProjectPermissions::UPLOAD_VERSION;
|
|
// Upload version with basic-mod.jar
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
let project_id = ctx.project_id.unwrap();
|
|
let project_id = ProjectId(parse_base62(&project_id).unwrap());
|
|
api.add_public_version(
|
|
project_id,
|
|
"1.0.0",
|
|
TestFile::BasicMod,
|
|
None,
|
|
None,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.simple_project_permissions_test(upload_version, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Upload file to existing version
|
|
// Uses alpha project, as it has an existing version
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.upload_file_to_version(
|
|
alpha_version_id,
|
|
&TestFile::BasicModDifferent,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(upload_version, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Patch version
|
|
// Uses alpha project, as it has an existing version
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_version(
|
|
alpha_version_id,
|
|
json!({
|
|
"name": "Basic Mod",
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(upload_version, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Delete version file
|
|
// Uses alpha project, as it has an existing version
|
|
let delete_version = ProjectPermissions::DELETE_VERSION;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_version_file(
|
|
alpha_file_hash,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(delete_version, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Delete version
|
|
// Uses alpha project, as it has an existing version
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_version(alpha_version_id, ctx.test_pat.as_deref())
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(delete_version, req_gen)
|
|
.await
|
|
.unwrap();
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn permissions_manage_invites() {
|
|
// Add member, remove member, edit member
|
|
with_test_environment_all(None, |test_env| 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 api = &test_env.api;
|
|
let manage_invites = ProjectPermissions::MANAGE_INVITES;
|
|
|
|
// Add member
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.add_user_to_team(
|
|
&ctx.team_id.unwrap(),
|
|
MOD_USER_ID,
|
|
Some(ProjectPermissions::empty()),
|
|
None,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(manage_invites, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Edit member
|
|
let edit_member = ProjectPermissions::EDIT_MEMBER;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_team_member(
|
|
&ctx.team_id.unwrap(),
|
|
MOD_USER_ID,
|
|
json!({
|
|
"permissions": 0,
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(edit_member, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// remove member
|
|
// requires manage_invites if they have not yet accepted the invite
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_from_team(
|
|
&ctx.team_id.unwrap(),
|
|
MOD_USER_ID,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(manage_invites, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// re-add member for testing
|
|
let resp = api
|
|
.add_user_to_team(
|
|
alpha_team_id,
|
|
MOD_USER_ID,
|
|
Some(ProjectPermissions::empty()),
|
|
None,
|
|
ADMIN_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
// Accept invite
|
|
let resp = api.join_team(alpha_team_id, MOD_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
// remove existing member (requires remove_member)
|
|
let remove_member = ProjectPermissions::REMOVE_MEMBER;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_from_team(
|
|
&ctx.team_id.unwrap(),
|
|
MOD_USER_ID,
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
|
|
PermissionsTest::new(&test_env)
|
|
.with_existing_project(alpha_project_id, alpha_team_id)
|
|
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
|
.simple_project_permissions_test(remove_member, req_gen)
|
|
.await
|
|
.unwrap();
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn permissions_delete_project() {
|
|
// Add member, remove member, edit member
|
|
with_test_environment_all(None, |test_env| async move {
|
|
let delete_project = ProjectPermissions::DELETE_PROJECT;
|
|
let api = &test_env.api;
|
|
// Delete project
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.remove_project(
|
|
&ctx.project_id.unwrap(),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.simple_project_permissions_test(delete_project, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
test_env.cleanup().await;
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn project_permissions_consistency_test() {
|
|
with_test_environment_all(Some(10), |test_env| async move {
|
|
// Test that the permissions are consistent with each other
|
|
// For example, if we get the projectpermissions directly, from an organization's defaults, overriden, etc, they should all be correct & consistent
|
|
let api = &test_env.api;
|
|
// Full project permissions test with EDIT_DETAILS
|
|
let success_permissions = ProjectPermissions::EDIT_DETAILS;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project(
|
|
&ctx.project_id.unwrap(),
|
|
json!({
|
|
"categories": [],
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.full_project_permissions_test(success_permissions, req_gen)
|
|
.await
|
|
.unwrap();
|
|
|
|
// We do a test with more specific permissions, to ensure that *exactly* the permissions at each step are as expected
|
|
let success_permissions = ProjectPermissions::EDIT_DETAILS
|
|
| ProjectPermissions::REMOVE_MEMBER
|
|
| ProjectPermissions::DELETE_VERSION
|
|
| ProjectPermissions::VIEW_PAYOUTS;
|
|
let req_gen = |ctx: PermissionsTestContext| async move {
|
|
api.edit_project(
|
|
&ctx.project_id.unwrap(),
|
|
json!({
|
|
"categories": [],
|
|
}),
|
|
ctx.test_pat.as_deref(),
|
|
)
|
|
.await
|
|
};
|
|
PermissionsTest::new(&test_env)
|
|
.full_project_permissions_test(success_permissions, req_gen)
|
|
.await
|
|
.unwrap();
|
|
})
|
|
.await;
|
|
}
|
|
|
|
// TODO: Re-add this if we want to match v3 Projects structure to v3 Search Result structure, otherwise, delete
|
|
// #[actix_rt::test]
|
|
// async fn align_search_projects() {
|
|
// // Test setup and dummy data
|
|
// with_test_environment(Some(10), |test_env: TestEnvironment<ApiV3>| async move {
|
|
// setup_search_projects(&test_env).await;
|
|
|
|
// let api = &test_env.api;
|
|
// let test_name = test_env.db.database_name.clone();
|
|
|
|
// let projects = api
|
|
// .search_deserialized(
|
|
// Some(&format!("\"&{test_name}\"")),
|
|
// Some(json!([["categories:fabric"]])),
|
|
// USER_USER_PAT,
|
|
// )
|
|
// .await;
|
|
|
|
// for project in projects.hits {
|
|
// let project_model = api
|
|
// .get_project(&project.id.to_string(), USER_USER_PAT)
|
|
// .await;
|
|
// assert_status!(&project_model, StatusCode::OK);
|
|
// let mut project_model: Project = test::read_body_json(project_model).await;
|
|
|
|
// // Body/description is huge- don't store it in search, so it's StatusCode::OK if they differ here
|
|
// // (Search should return "")
|
|
// project_model.description = "".into();
|
|
|
|
// let project_model = serde_json::to_value(project_model).unwrap();
|
|
// let searched_project_serialized = serde_json::to_value(project).unwrap();
|
|
// assert_eq!(project_model, searched_project_serialized);
|
|
// }
|
|
// })
|
|
// .await
|
|
// }
|
|
|
|
#[actix_rt::test]
|
|
async fn projects_various_visibility() {
|
|
// For testing the filter_visible_projects and is_visible_project
|
|
with_test_environment(
|
|
None,
|
|
|env: common::environment::TestEnvironment<ApiV3>| async move {
|
|
let DummyProjectAlpha {
|
|
project_id: alpha_project_id,
|
|
project_id_parsed: alpha_project_id_parsed,
|
|
..
|
|
} = &env.dummy.project_alpha;
|
|
let DummyProjectBeta {
|
|
project_id: beta_project_id,
|
|
project_id_parsed: beta_project_id_parsed,
|
|
..
|
|
} = &env.dummy.project_beta;
|
|
let DummyOrganizationZeta {
|
|
organization_id: zeta_organization_id,
|
|
team_id: zeta_team_id,
|
|
..
|
|
} = &env.dummy.organization_zeta;
|
|
|
|
// Invite friend to org zeta and accept it
|
|
let resp = env
|
|
.api
|
|
.add_user_to_team(
|
|
zeta_team_id,
|
|
FRIEND_USER_ID,
|
|
Some(ProjectPermissions::empty()),
|
|
None,
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
let resp = env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
|
assert_status!(&resp, StatusCode::NO_CONTENT);
|
|
|
|
let visible_pat_pairs = vec![
|
|
(&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
|
(&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
|
(&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK),
|
|
(&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
|
(
|
|
&beta_project_id_parsed,
|
|
FRIEND_USER_PAT,
|
|
StatusCode::NOT_FOUND,
|
|
),
|
|
(
|
|
&beta_project_id_parsed,
|
|
ENEMY_USER_PAT,
|
|
StatusCode::NOT_FOUND,
|
|
),
|
|
];
|
|
|
|
// Tests get_project, a route that uses is_visible_project
|
|
for (project_id, pat, expected_status) in visible_pat_pairs {
|
|
let resp =
|
|
env.api.get_project(&project_id.to_string(), pat).await;
|
|
assert_status!(&resp, expected_status);
|
|
}
|
|
|
|
// Test get_user_projects, a route that uses filter_visible_projects
|
|
let visible_pat_pairs = vec![
|
|
(USER_USER_PAT, 2),
|
|
(FRIEND_USER_PAT, 1),
|
|
(ENEMY_USER_PAT, 1),
|
|
];
|
|
for (pat, expected_count) in visible_pat_pairs {
|
|
let projects = env
|
|
.api
|
|
.get_user_projects_deserialized_common(USER_USER_ID, pat)
|
|
.await;
|
|
assert_eq!(projects.len(), expected_count);
|
|
}
|
|
|
|
// Add projects to org zeta
|
|
let resp = env
|
|
.api
|
|
.organization_add_project(
|
|
zeta_organization_id,
|
|
alpha_project_id,
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::OK);
|
|
let resp = env
|
|
.api
|
|
.organization_add_project(
|
|
zeta_organization_id,
|
|
beta_project_id,
|
|
USER_USER_PAT,
|
|
)
|
|
.await;
|
|
assert_status!(&resp, StatusCode::OK);
|
|
|
|
// Test get_project, a route that uses is_visible_project
|
|
let visible_pat_pairs = vec![
|
|
(&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
|
(&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
|
(&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK),
|
|
(&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
|
(&beta_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
|
(
|
|
&beta_project_id_parsed,
|
|
ENEMY_USER_PAT,
|
|
StatusCode::NOT_FOUND,
|
|
),
|
|
];
|
|
|
|
for (project_id, pat, expected_status) in visible_pat_pairs {
|
|
let resp =
|
|
env.api.get_project(&project_id.to_string(), pat).await;
|
|
assert_status!(&resp, expected_status);
|
|
}
|
|
|
|
// Test get_user_projects, a route that uses filter_visible_projects
|
|
let visible_pat_pairs = vec![
|
|
(USER_USER_PAT, 2),
|
|
(FRIEND_USER_PAT, 2),
|
|
(ENEMY_USER_PAT, 1),
|
|
];
|
|
for (pat, expected_count) in visible_pat_pairs {
|
|
let projects = env
|
|
.api
|
|
.get_projects(&[alpha_project_id, beta_project_id], pat)
|
|
.await;
|
|
let projects: Vec<CommonProject> =
|
|
test::read_body_json(projects).await;
|
|
assert_eq!(projects.len(), expected_count);
|
|
}
|
|
},
|
|
)
|
|
.await;
|
|
}
|
|
|
|
// Route tests:
|
|
// TODO: Missing routes on projects
|
|
// TODO: using permissions/scopes, can we SEE projects existence that we are not allowed to? (ie 401 instead of 404)
|
|
|
|
// Permissions:
|
|
// TODO: permissions VIEW_PAYOUTS currently is unused. Add tests when it is used.
|
|
// TODO: permissions VIEW_ANALYTICS currently is unused. Add tests when it is used.
|