mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26ace18837 | ||
|
|
c0e3dee692 |
Generated
-22
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT status FROM mods WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "status",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "91d2ce7ee6a29a47a20655fef577c42f1cbb2f8de4d9ea8ab361fc210f08aa20"
|
||||
}
|
||||
Generated
-14
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE mods\n SET status = 'rejected'\n WHERE id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "95e17b2512494ffcbfe6278b87aa273edc5729633aeaa87f6239667d2f861e68"
|
||||
}
|
||||
@@ -20,7 +20,6 @@ use crate::background_task::update_versions;
|
||||
use crate::database::{PgPool, ReadOnlyPgPool};
|
||||
use crate::env::ENV;
|
||||
use crate::queue::billing::{index_billing, index_subscriptions};
|
||||
use crate::queue::moderation::AutomatedModerationQueue;
|
||||
use crate::routes::internal::delphi::rescan::rescan_projects_in_queue;
|
||||
use crate::util::anrok;
|
||||
use crate::util::archon::ArchonClient;
|
||||
@@ -68,7 +67,6 @@ pub struct LabrinthConfig {
|
||||
pub payouts_queue: web::Data<PayoutsQueue>,
|
||||
pub analytics_queue: Arc<AnalyticsQueue>,
|
||||
pub active_sockets: web::Data<ActiveSockets>,
|
||||
pub automated_moderation_queue: web::Data<AutomatedModerationQueue>,
|
||||
pub rate_limiter: web::Data<AsyncRateLimiter>,
|
||||
pub stripe_client: stripe::Client,
|
||||
pub anrok_client: anrok::Client,
|
||||
@@ -98,21 +96,6 @@ pub fn app_setup(
|
||||
) -> LabrinthConfig {
|
||||
info!("Starting labrinth on {}", &ENV.BIND_ADDR);
|
||||
|
||||
let automated_moderation_queue =
|
||||
web::Data::new(AutomatedModerationQueue::default());
|
||||
|
||||
{
|
||||
let automated_moderation_queue_ref = automated_moderation_queue.clone();
|
||||
let pool_ref = pool.clone();
|
||||
let ro_pool_ref = ro_pool.clone();
|
||||
let redis_pool_ref = redis_pool.clone();
|
||||
actix_rt::spawn(async move {
|
||||
automated_moderation_queue_ref
|
||||
.task(pool_ref, ro_pool_ref, redis_pool_ref)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
|
||||
let scheduler = scheduler::Scheduler::new();
|
||||
|
||||
let http_client = web::Data::new(HttpClient::new());
|
||||
@@ -341,7 +324,6 @@ pub fn app_setup(
|
||||
payouts_queue: web::Data::new(PayoutsQueue::new()),
|
||||
analytics_queue,
|
||||
active_sockets,
|
||||
automated_moderation_queue,
|
||||
rate_limiter: limiter,
|
||||
stripe_client,
|
||||
anrok_client,
|
||||
@@ -391,7 +373,6 @@ pub fn app_config(
|
||||
.app_data(web::Data::new(labrinth_config.analytics_queue.clone()))
|
||||
.app_data(web::Data::new(labrinth_config.clickhouse.clone()))
|
||||
.app_data(labrinth_config.active_sockets.clone())
|
||||
.app_data(labrinth_config.automated_moderation_queue.clone())
|
||||
.app_data(labrinth_config.archon_client.clone())
|
||||
.app_data(web::Data::new(labrinth_config.stripe_client.clone()))
|
||||
.app_data(web::Data::new(labrinth_config.anrok_client.clone()))
|
||||
|
||||
@@ -1,456 +1,5 @@
|
||||
use crate::database;
|
||||
use crate::database::models::notification_item::NotificationBuilder;
|
||||
use crate::database::models::thread_item::ThreadMessageBuilder;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::database::{PgPool, ReadOnlyPgPool};
|
||||
use crate::env::ENV;
|
||||
use crate::models::ids::ProjectId;
|
||||
use crate::models::notifications::NotificationBody;
|
||||
use crate::models::projects::ProjectStatus;
|
||||
use crate::models::threads::MessageBody;
|
||||
use crate::routes::ApiError;
|
||||
use dashmap::DashSet;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::time::Duration;
|
||||
|
||||
pub const AUTOMOD_ID: i64 = 0;
|
||||
|
||||
pub struct ModerationMessages {
|
||||
pub messages: Vec<ModerationMessage>,
|
||||
pub version_specific: HashMap<String, Vec<ModerationMessage>>,
|
||||
}
|
||||
|
||||
impl ModerationMessages {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.messages.is_empty() && self.version_specific.is_empty()
|
||||
}
|
||||
|
||||
pub fn markdown(&self, auto_mod: bool) -> String {
|
||||
let mut str = String::new();
|
||||
|
||||
for message in &self.messages {
|
||||
write!(&mut str, "## {}\n{}\n\n", message.header(), message.body())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
for (version_num, messages) in &self.version_specific {
|
||||
for message in messages {
|
||||
write!(
|
||||
&mut str,
|
||||
"### Version {}: {}\n{}\n\n",
|
||||
version_num,
|
||||
message.header(),
|
||||
message.body()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if auto_mod {
|
||||
str.push_str(
|
||||
"<hr />\n\n\
|
||||
🤖 This is an automated message generated by AutoMod (BETA). If you are facing issues, please [contact support](https://support.modrinth.com)."
|
||||
);
|
||||
}
|
||||
|
||||
str
|
||||
}
|
||||
|
||||
pub fn should_reject(&self, first_time: bool) -> bool {
|
||||
self.messages.iter().any(|x| x.rejectable(first_time))
|
||||
|| self
|
||||
.version_specific
|
||||
.values()
|
||||
.any(|x| x.iter().any(|x| x.rejectable(first_time)))
|
||||
}
|
||||
|
||||
pub fn approvable(&self) -> bool {
|
||||
self.messages.iter().all(|x| x.approvable())
|
||||
&& self
|
||||
.version_specific
|
||||
.values()
|
||||
.all(|x| x.iter().all(|x| x.approvable()))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ModerationMessage {
|
||||
MissingGalleryImage,
|
||||
NoPrimaryFile,
|
||||
NoSideTypes,
|
||||
PackFilesNotAllowed {
|
||||
files: HashMap<String, IdentifiedFile>,
|
||||
incomplete: bool,
|
||||
},
|
||||
MissingLicense,
|
||||
MissingCustomLicenseUrl {
|
||||
license: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl ModerationMessage {
|
||||
pub fn rejectable(&self, first_time: bool) -> bool {
|
||||
match self {
|
||||
ModerationMessage::NoPrimaryFile => true,
|
||||
ModerationMessage::PackFilesNotAllowed { files, incomplete } => {
|
||||
(!incomplete || first_time)
|
||||
&& files.values().any(|x| match x.status {
|
||||
ApprovalType::Yes => false,
|
||||
ApprovalType::WithAttributionAndSource => false,
|
||||
ApprovalType::WithAttribution => false,
|
||||
ApprovalType::No => first_time,
|
||||
ApprovalType::PermanentNo => true,
|
||||
ApprovalType::Unidentified => first_time,
|
||||
})
|
||||
}
|
||||
ModerationMessage::MissingGalleryImage => true,
|
||||
ModerationMessage::MissingLicense => true,
|
||||
ModerationMessage::MissingCustomLicenseUrl { .. } => true,
|
||||
ModerationMessage::NoSideTypes => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn approvable(&self) -> bool {
|
||||
match self {
|
||||
ModerationMessage::NoPrimaryFile => false,
|
||||
ModerationMessage::PackFilesNotAllowed { files, .. } => {
|
||||
files.values().all(|x| x.status.approved())
|
||||
}
|
||||
ModerationMessage::MissingGalleryImage => false,
|
||||
ModerationMessage::MissingLicense => false,
|
||||
ModerationMessage::MissingCustomLicenseUrl { .. } => false,
|
||||
ModerationMessage::NoSideTypes => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header(&self) -> &'static str {
|
||||
match self {
|
||||
ModerationMessage::NoPrimaryFile => "No primary files",
|
||||
ModerationMessage::PackFilesNotAllowed { .. } => {
|
||||
"Copyrighted Content"
|
||||
}
|
||||
ModerationMessage::MissingGalleryImage => "Missing Gallery Images",
|
||||
ModerationMessage::MissingLicense => "Missing License",
|
||||
ModerationMessage::MissingCustomLicenseUrl { .. } => {
|
||||
"Missing License URL"
|
||||
}
|
||||
ModerationMessage::NoSideTypes => "Missing Environment Information",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body(&self) -> String {
|
||||
match self {
|
||||
ModerationMessage::NoPrimaryFile => "Please attach a file to this version. All files on Modrinth must have files associated with their versions.\n".to_string(),
|
||||
ModerationMessage::PackFilesNotAllowed { files, .. } => {
|
||||
let mut str = String::from("This pack redistributes copyrighted material. Please refer to [Modrinth's guide on obtaining modpack permissions](https://support.modrinth.com/en/articles/8797527-obtaining-modpack-permissions) for more information.\n\n");
|
||||
|
||||
let mut attribute_mods = Vec::new();
|
||||
let mut no_mods = Vec::new();
|
||||
let mut permanent_no_mods = Vec::new();
|
||||
let mut unidentified_mods = Vec::new();
|
||||
for approval in files.values() {
|
||||
match approval.status {
|
||||
ApprovalType::Yes | ApprovalType::WithAttributionAndSource => {}
|
||||
ApprovalType::WithAttribution => attribute_mods.push(&approval.file_name),
|
||||
ApprovalType::No => no_mods.push(&approval.file_name),
|
||||
ApprovalType::PermanentNo => permanent_no_mods.push(&approval.file_name),
|
||||
ApprovalType::Unidentified => unidentified_mods.push(&approval.file_name),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_mods(projects: Vec<&String>, headline: &str, val: &mut String) {
|
||||
if projects.is_empty() { return }
|
||||
|
||||
write!(val, "{headline}\n\n").unwrap();
|
||||
|
||||
for project in &projects {
|
||||
let additional_text = if project.contains("ftb-quests") {
|
||||
Some(("Odyssey Quests", "lo90fZoB"))
|
||||
} else if project.contains("ftb-ranks") || project.contains("ftb-essentials") {
|
||||
Some(("Odyssey Roles", "iYcNKH7W"))
|
||||
} else if project.contains("ftb-teams") {
|
||||
Some(("Odyssey Guilds", "bb2EpKpx"))
|
||||
} else if project.contains("ftb-chunks") {
|
||||
Some(("Odyssey Claims", "fEWKxVzh"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(additional_text) = additional_text {
|
||||
writeln!(val, "- {project} (consider using [{}](https://modrinth.com/project/{}) instead)", additional_text.0, additional_text.1).unwrap();
|
||||
} else {
|
||||
writeln!(val, "- {project}").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if !projects.is_empty() {
|
||||
val.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
print_mods(attribute_mods, "The following content has attribution requirements, meaning that you must link back to the page where you originally found this content in your modpack description or version changelog (e.g. linking a mod's CurseForge page if you got it from CurseForge):", &mut str);
|
||||
print_mods(no_mods, "The following content is not allowed in Modrinth modpacks due to licensing restrictions. Please contact the author(s) directly for permission or remove the content from your modpack:", &mut str);
|
||||
print_mods(permanent_no_mods, "The following content is not allowed in Modrinth modpacks, regardless of permission obtained. This may be because it breaks Modrinth's content rules or because the authors, upon being contacted for permission, have declined. Please remove the content from your modpack:", &mut str);
|
||||
print_mods(unidentified_mods, "The following content could not be identified. Please provide proof of its origin along with proof that you have permission to include it:", &mut str);
|
||||
|
||||
str
|
||||
},
|
||||
ModerationMessage::MissingGalleryImage => "We ask that resource packs like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of the content in your pack per section 2.1 of [Modrinth's content rules](https://modrinth.com/legal/rules#general-expectations).\n
|
||||
Keep in mind that you should:\n
|
||||
- Set a featured image that best represents your pack.
|
||||
- Ensure all your images have titles that accurately label the image, and optionally, details on the contents of the image in the images Description.
|
||||
- Upload any relevant images in your Description to your Gallery tab for best results.".to_string(),
|
||||
ModerationMessage::MissingLicense => "You must select a License before your project can be published publicly, having a License associated with your project is important to protecting your rights and allowing others to use your content as you intend. For more information, you can see our [Guide to Licensing Mods](<https://modrinth.com/news/article/licensing-guide/>).".to_string(),
|
||||
ModerationMessage::MissingCustomLicenseUrl { license } => format!("It looks like you've selected the License \"{license}\" without providing a valid License link. When using a custom License you must provide a link directly to the License in the License Link field."),
|
||||
ModerationMessage::NoSideTypes => "Your project's side types are currently set to Unknown on both sides. Please set accurate side types!".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AutomatedModerationQueue {
|
||||
pub projects: DashSet<ProjectId>,
|
||||
}
|
||||
|
||||
impl Default for AutomatedModerationQueue {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
projects: DashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AutomatedModerationQueue {
|
||||
pub async fn task(
|
||||
&self,
|
||||
pool: PgPool,
|
||||
ro_pool: ReadOnlyPgPool,
|
||||
redis: RedisPool,
|
||||
) {
|
||||
loop {
|
||||
let projects = self.projects.clone();
|
||||
self.projects.clear();
|
||||
|
||||
for project in projects {
|
||||
async {
|
||||
let project =
|
||||
database::DBProject::get_id((project).into(), &*ro_pool, &redis)
|
||||
.await?;
|
||||
|
||||
if let Some(project) = project {
|
||||
let res = async {
|
||||
let mut mod_messages = ModerationMessages {
|
||||
messages: vec![],
|
||||
version_specific: HashMap::new(),
|
||||
};
|
||||
|
||||
if project.project_types.iter().any(|x| ["mod", "modpack"].contains(&&**x)) && !project.aggregate_version_fields.iter().any(|x| x.field_name == "environment") {
|
||||
mod_messages.messages.push(ModerationMessage::NoSideTypes);
|
||||
}
|
||||
|
||||
if project.inner.components.minecraft_server.is_none() {
|
||||
let license = &project.inner.license;
|
||||
if license == "LicenseRef-Unknown" || license == "LicenseRef-" {
|
||||
mod_messages
|
||||
.messages
|
||||
.push(ModerationMessage::MissingLicense);
|
||||
} else if license.starts_with("LicenseRef-")
|
||||
&& license != "LicenseRef-All-Rights-Reserved"
|
||||
&& project.inner.license_url.is_none()
|
||||
{
|
||||
mod_messages.messages.push(
|
||||
ModerationMessage::MissingCustomLicenseUrl {
|
||||
license: project.inner.license.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (project.project_types.contains(&"resourcepack".to_string()) || project.project_types.contains(&"shader".to_string())) &&
|
||||
project.gallery_items.is_empty() &&
|
||||
!project.categories.contains(&"audio".to_string()) &&
|
||||
!project.categories.contains(&"locale".to_string())
|
||||
{
|
||||
mod_messages.messages.push(ModerationMessage::MissingGalleryImage);
|
||||
}
|
||||
|
||||
let versions =
|
||||
database::DBVersion::get_many(&project.versions, &*ro_pool, &redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
// we only support modpacks at this time
|
||||
.filter(|x| x.project_types.contains(&"modpack".to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for version in versions {
|
||||
let primary_file = version.files.iter().find_or_first(|x| x.primary);
|
||||
|
||||
if primary_file.is_none() {
|
||||
let val = mod_messages.version_specific.entry(version.inner.version_number).or_default();
|
||||
val.push(ModerationMessage::NoPrimaryFile);
|
||||
}
|
||||
}
|
||||
|
||||
if !mod_messages.is_empty() {
|
||||
let is_server_project =
|
||||
project.inner.components.minecraft_server.is_some();
|
||||
let first_time = database::models::DBThread::get(project.thread_id, &pool).await?
|
||||
.is_none_or(|x| x.messages.iter().all(|x| x.author_id == Some(database::models::DBUserId(AUTOMOD_ID)) || x.hide_identity));
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
let id = ThreadMessageBuilder {
|
||||
author_id: Some(database::models::DBUserId(AUTOMOD_ID)),
|
||||
body: MessageBody::Text {
|
||||
body: mod_messages.markdown(true),
|
||||
private: is_server_project,
|
||||
replying_to: None,
|
||||
associated_images: vec![],
|
||||
},
|
||||
thread_id: project.thread_id,
|
||||
hide_identity: false,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
let members = database::models::DBTeamMember::get_from_team_full(
|
||||
project.inner.team_id,
|
||||
&pool,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if mod_messages.should_reject(first_time) && !is_server_project {
|
||||
ThreadMessageBuilder {
|
||||
author_id: Some(database::models::DBUserId(AUTOMOD_ID)),
|
||||
body: MessageBody::StatusChange {
|
||||
new_status: ProjectStatus::Rejected,
|
||||
old_status: project.inner.status,
|
||||
},
|
||||
thread_id: project.thread_id,
|
||||
hide_identity: false,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::StatusChange {
|
||||
project_id: project.inner.id.into(),
|
||||
old_status: project.inner.status,
|
||||
new_status: ProjectStatus::Rejected,
|
||||
},
|
||||
}
|
||||
.insert_many(members.into_iter().map(|x| x.user_id).collect(), &mut transaction, &redis)
|
||||
.await?;
|
||||
|
||||
if !ENV.MODERATION_SLACK_WEBHOOK.is_empty() {
|
||||
crate::util::webhook::send_slack_project_webhook(
|
||||
project.inner.id.into(),
|
||||
&pool,
|
||||
&redis,
|
||||
&ENV.MODERATION_SLACK_WEBHOOK,
|
||||
Some(
|
||||
format!(
|
||||
"*<{}/user/AutoMod|AutoMod>* changed project status from *{}* to *Rejected*",
|
||||
ENV.SITE_URL,
|
||||
&project.inner.status.as_friendly_str(),
|
||||
)
|
||||
.to_string(),
|
||||
),
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE mods
|
||||
SET status = 'rejected'
|
||||
WHERE id = $1
|
||||
",
|
||||
project.inner.id.0
|
||||
)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
|
||||
database::models::DBProject::clear_cache(
|
||||
project.inner.id,
|
||||
project.inner.slug.clone(),
|
||||
None,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::ModeratorMessage {
|
||||
thread_id: project.thread_id.into(),
|
||||
message_id: id.into(),
|
||||
project_id: Some(project.inner.id.into()),
|
||||
report_id: None,
|
||||
},
|
||||
}
|
||||
.insert_many(
|
||||
members.iter().map(|x| x.user_id).collect(),
|
||||
&mut transaction,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::ModerationMessageReceived {
|
||||
project_id: project.inner.id.into(),
|
||||
},
|
||||
}
|
||||
.insert_many(
|
||||
members.iter().map(|x| x.user_id).collect(),
|
||||
&mut transaction,
|
||||
&redis,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
transaction.commit().await?;
|
||||
}
|
||||
|
||||
Ok::<(), ApiError>(())
|
||||
}.await;
|
||||
|
||||
if let Err(err) = res {
|
||||
let err = err.as_api_error();
|
||||
|
||||
let str = format!(
|
||||
"## Internal AutoMod Error\n\n\
|
||||
Error code: {}\n\n\
|
||||
Error description: {}\n\n",
|
||||
err.error, err.description
|
||||
);
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
ThreadMessageBuilder {
|
||||
author_id: Some(database::models::DBUserId(AUTOMOD_ID)),
|
||||
body: MessageBody::Text {
|
||||
body: str,
|
||||
private: true,
|
||||
replying_to: None,
|
||||
associated_images: vec![],
|
||||
},
|
||||
thread_id: project.thread_id,
|
||||
hide_identity: false,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
transaction.commit().await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<(), ApiError>(())
|
||||
}.await.ok();
|
||||
}
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(5)).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct MissingMetadata {
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::models::v2::projects::{
|
||||
DonationLink, LegacyProject, LegacySideType, LegacyVersion,
|
||||
};
|
||||
use crate::models::v2::search::LegacySearchResults;
|
||||
use crate::queue::moderation::AutomatedModerationQueue;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::v3::projects::ProjectIds;
|
||||
use crate::routes::{ApiError, v2_reroute, v3};
|
||||
@@ -536,7 +535,6 @@ pub async fn project_edit(
|
||||
new_project: web::Json<EditProject>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
moderation_queue: web::Data<AutomatedModerationQueue>,
|
||||
search_state: web::Data<SearchState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let v2_new_project = new_project.into_inner();
|
||||
@@ -650,7 +648,6 @@ pub async fn project_edit(
|
||||
web::Json(new_project),
|
||||
redis.clone(),
|
||||
session_queue.clone(),
|
||||
moderation_queue,
|
||||
search_state.clone(),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -8,7 +8,6 @@ use crate::models::projects::{
|
||||
Dependency, FileType, Loader, Version, VersionStatus, VersionType,
|
||||
};
|
||||
use crate::models::v2::projects::LegacyVersion;
|
||||
use crate::queue::moderation::AutomatedModerationQueue;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::v3::project_creation::CreateError;
|
||||
use crate::routes::v3::version_creation;
|
||||
@@ -102,7 +101,6 @@ pub async fn version_create(
|
||||
redis: Data<RedisPool>,
|
||||
file_host: Data<dyn FileHost>,
|
||||
session_queue: Data<AuthQueue>,
|
||||
moderation_queue: Data<AutomatedModerationQueue>,
|
||||
http: Data<HttpClient>,
|
||||
search_state: Data<SearchState>,
|
||||
) -> Result<HttpResponse, CreateError> {
|
||||
@@ -262,7 +260,6 @@ pub async fn version_create(
|
||||
redis.clone(),
|
||||
file_host,
|
||||
session_queue,
|
||||
moderation_queue,
|
||||
http,
|
||||
search_state,
|
||||
)
|
||||
|
||||
@@ -25,7 +25,6 @@ use crate::models::projects::{
|
||||
use crate::models::teams::ProjectPermissions;
|
||||
use crate::models::threads::MessageBody;
|
||||
use crate::models::{self, exp};
|
||||
use crate::queue::moderation::AutomatedModerationQueue;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::ApiError;
|
||||
use crate::routes::internal::delphi;
|
||||
@@ -315,7 +314,6 @@ async fn project_edit(
|
||||
web::Json(new_project): web::Json<EditProject>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
moderation_queue: web::Data<AutomatedModerationQueue>,
|
||||
search_state: web::Data<SearchState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
project_edit_internal(
|
||||
@@ -325,7 +323,6 @@ async fn project_edit(
|
||||
web::Json(new_project),
|
||||
redis,
|
||||
session_queue,
|
||||
moderation_queue,
|
||||
search_state,
|
||||
)
|
||||
.await
|
||||
@@ -338,7 +335,6 @@ pub async fn project_edit_internal(
|
||||
web::Json(new_project): web::Json<EditProject>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
moderation_queue: web::Data<AutomatedModerationQueue>,
|
||||
search_state: web::Data<SearchState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let user = get_user_from_headers(
|
||||
@@ -480,10 +476,6 @@ pub async fn project_edit_internal(
|
||||
)
|
||||
.execute(&mut transaction)
|
||||
.await?;
|
||||
|
||||
moderation_queue
|
||||
.projects
|
||||
.insert(project_item.inner.id.into());
|
||||
}
|
||||
|
||||
if status.is_approved() && !project_item.inner.status.is_approved() {
|
||||
|
||||
@@ -23,9 +23,8 @@ use crate::models::projects::{
|
||||
Dependency, FileType, Loader, Version, VersionFile, VersionStatus,
|
||||
VersionType,
|
||||
};
|
||||
use crate::models::projects::{DependencyType, ProjectStatus, skip_nulls};
|
||||
use crate::models::projects::{DependencyType, skip_nulls};
|
||||
use crate::models::teams::ProjectPermissions;
|
||||
use crate::queue::moderation::AutomatedModerationQueue;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::search::SearchState;
|
||||
use crate::util::http::HttpClient;
|
||||
@@ -112,7 +111,6 @@ pub async fn version_create(
|
||||
redis: Data<RedisPool>,
|
||||
file_host: Data<dyn FileHost>,
|
||||
session_queue: Data<AuthQueue>,
|
||||
moderation_queue: web::Data<AutomatedModerationQueue>,
|
||||
http: web::Data<HttpClient>,
|
||||
search_state: Data<SearchState>,
|
||||
) -> Result<HttpResponse, CreateError> {
|
||||
@@ -128,7 +126,6 @@ pub async fn version_create(
|
||||
&mut uploaded_files,
|
||||
&client,
|
||||
&session_queue,
|
||||
&moderation_queue,
|
||||
&http,
|
||||
)
|
||||
.await;
|
||||
@@ -170,7 +167,6 @@ async fn version_create_inner(
|
||||
uploaded_files: &mut Vec<UploadedFile>,
|
||||
pool: &PgPool,
|
||||
session_queue: &AuthQueue,
|
||||
moderation_queue: &AutomatedModerationQueue,
|
||||
http: &reqwest::Client,
|
||||
) -> Result<(HttpResponse, models::DBProjectId), CreateError> {
|
||||
let mut initial_version_data = None;
|
||||
@@ -530,19 +526,6 @@ async fn version_create_inner(
|
||||
}
|
||||
}
|
||||
|
||||
let project_status = sqlx::query!(
|
||||
"SELECT status FROM mods WHERE id = $1",
|
||||
project_id as models::DBProjectId,
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
if let Some(project_status) = project_status
|
||||
&& project_status.status == ProjectStatus::Processing.as_str()
|
||||
{
|
||||
moderation_queue.projects.insert(project_id.into());
|
||||
}
|
||||
|
||||
Ok((HttpResponse::Ok().json(response), project_id))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user