Fix primary files, file deletion, checks for mod following, fix user following route (#175)

This commit is contained in:
Geometrically
2021-03-08 12:52:48 -07:00
committed by GitHub
parent 9f7813622d
commit 38802d3522
6 changed files with 253 additions and 169 deletions

View File

@@ -186,7 +186,11 @@ impl User {
Ok(users)
}
pub async fn get_mods<'a, E>(user_id: UserId, exec: E) -> Result<Vec<ModId>, sqlx::Error>
pub async fn get_mods<'a, E>(
user_id: UserId,
status: &str,
exec: E,
) -> Result<Vec<ModId>, sqlx::Error>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
{
@@ -196,9 +200,10 @@ impl User {
"
SELECT m.id FROM mods m
INNER JOIN team_members tm ON tm.team_id = m.team_id
WHERE tm.user_id = $1
WHERE tm.user_id = $1 AND m.status = (SELECT s.id FROM statuses s WHERE s.status = $2)
",
user_id as UserId,
status,
)
.fetch_many(exec)
.try_filter_map(|e| async { Ok(e.right().map(|m| ModId(m.id))) })

View File

@@ -543,7 +543,7 @@ impl Version {
url: file[3].to_string(),
filename: file[1].to_string(),
hashes: file_hashes,
primary: file[3].parse().unwrap_or(false),
primary: file[2].parse().unwrap_or(false),
})
}
});

View File

@@ -8,7 +8,7 @@ use crate::routes::ApiError;
use crate::search::indexing::queue::CreationQueue;
use crate::search::{search_for_mod, SearchConfig, SearchError};
use actix_web::web::Data;
use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse};
use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse};
use futures::StreamExt;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
@@ -986,7 +986,7 @@ pub async fn mod_delete(
}
}
#[get("{id}/follow")]
#[post("{id}/follow")]
pub async fn mod_follow(
req: HttpRequest,
info: web::Path<(models::ids::ModId,)>,
@@ -1003,31 +1003,50 @@ pub async fn mod_follow(
let user_id: database::models::ids::UserId = user.id.into();
let mod_id: database::models::ids::ModId = id.into();
sqlx::query!(
let following = sqlx::query!(
"
UPDATE mods
SET follows = follows + 1
WHERE id = $1
",
mod_id as database::models::ids::ModId,
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
sqlx::query!(
"
INSERT INTO mod_follows (follower_id, mod_id)
VALUES ($1, $2)
SELECT EXISTS(SELECT 1 FROM mod_follows mf WHERE mf.follower_id = $1 AND mf.mod_id = $2)
",
user_id as database::models::ids::UserId,
mod_id as database::models::ids::ModId
)
.execute(&**pool)
.fetch_one(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
.map_err(|e| ApiError::DatabaseError(e.into()))?
.exists
.unwrap_or(false);
Ok(HttpResponse::Ok().body(""))
if !following {
sqlx::query!(
"
UPDATE mods
SET follows = follows + 1
WHERE id = $1
",
mod_id as database::models::ids::ModId,
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
sqlx::query!(
"
INSERT INTO mod_follows (follower_id, mod_id)
VALUES ($1, $2)
",
user_id as database::models::ids::UserId,
mod_id as database::models::ids::ModId
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
Ok(HttpResponse::Ok().body(""))
} else {
Err(ApiError::InvalidInputError(
"You are already following this mod!".to_string(),
))
}
}
#[delete("{id}/follow")]
@@ -1042,31 +1061,50 @@ pub async fn mod_unfollow(
let user_id: database::models::ids::UserId = user.id.into();
let mod_id: database::models::ids::ModId = id.into();
sqlx::query!(
let following = sqlx::query!(
"
UPDATE mods
SET follows = follows - 1
WHERE id = $1
",
mod_id as database::models::ids::ModId,
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
sqlx::query!(
"
DELETE FROM mod_follows
WHERE follower_id = $1 AND mod_id = $2
SELECT EXISTS(SELECT 1 FROM mod_follows mf WHERE mf.follower_id = $1 AND mf.mod_id = $2)
",
user_id as database::models::ids::UserId,
mod_id as database::models::ids::ModId
)
.execute(&**pool)
.fetch_one(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
.map_err(|e| ApiError::DatabaseError(e.into()))?
.exists
.unwrap_or(false);
Ok(HttpResponse::Ok().body(""))
if following {
sqlx::query!(
"
UPDATE mods
SET follows = follows - 1
WHERE id = $1
",
mod_id as database::models::ids::ModId,
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
sqlx::query!(
"
DELETE FROM mod_follows
WHERE follower_id = $1 AND mod_id = $2
",
user_id as database::models::ids::UserId,
mod_id as database::models::ids::ModId
)
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
Ok(HttpResponse::Ok().body(""))
} else {
Err(ApiError::InvalidInputError(
"You are not following this mod!".to_string(),
))
}
}
pub async fn delete_from_index(

View File

@@ -1,7 +1,8 @@
use crate::auth::get_user_from_headers;
use crate::database::models::User;
use crate::file_hosting::FileHost;
use crate::models::ids::NotificationId;
use crate::models::ids::ModId;
use crate::models::mods::ModStatus;
use crate::models::notifications::Notification;
use crate::models::users::{Role, UserId};
use crate::routes::notifications::convert_notification;
@@ -136,7 +137,7 @@ pub async fn mods_list(
.exists;
if user_exists.unwrap_or(false) {
let mod_data = User::get_mods(id, &**pool)
let mod_data = User::get_mods(id, ModStatus::Approved.as_str(), &**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
@@ -371,7 +372,6 @@ pub async fn user_icon_edit(
.execute(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
Ok(HttpResponse::Ok().body(""))
} else {
Err(ApiError::InvalidInputError(format!(
@@ -443,20 +443,20 @@ pub async fn user_follows(
use futures::TryStreamExt;
let user_id: crate::database::models::UserId = id.into();
let notifications: Vec<NotificationId> = sqlx::query!(
let mods: Vec<ModId> = sqlx::query!(
"
SELECT n.id FROM notifications n
WHERE n.user_id = $1
",
SELECT mf.mod_id FROM mod_follows mf
WHERE mf.follower_id = $1
",
user_id as crate::database::models::ids::UserId,
)
.fetch_many(&**pool)
.try_filter_map(|e| async { Ok(e.right().map(|m| NotificationId(m.id as u64))) })
.try_collect::<Vec<NotificationId>>()
.try_filter_map(|e| async { Ok(e.right().map(|m| ModId(m.mod_id as u64))) })
.try_collect::<Vec<ModId>>()
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
Ok(HttpResponse::Ok().json(notifications))
Ok(HttpResponse::Ok().json(mods))
}
#[get("{id}/notifications")]

View File

@@ -450,8 +450,9 @@ pub async fn version_edit(
if let Some(primary_file) = &new_version.primary_file {
let result = sqlx::query!(
"
SELECT f.id FROM files f
INNER JOIN hashes h ON h.hash = $1 AND h.algorithm = $2
SELECT f.id id FROM hashes h
INNER JOIN files f ON h.file_id = f.id
WHERE h.algorithm = $2 AND h.hash = $1
",
primary_file.1.as_bytes(),
primary_file.0
@@ -779,11 +780,10 @@ pub async fn delete_file(
sqlx::query!(
"
DELETE FROM hashes
WHERE hash = $1 AND algorithm = $2
",
hash.as_bytes(),
algorithm.algorithm
DELETE FROM hashes
WHERE file_id = $1
",
row.id
)
.execute(&mut *transaction)
.await
@@ -791,9 +791,9 @@ pub async fn delete_file(
sqlx::query!(
"
DELETE FROM files
WHERE files.id = $1
",
DELETE FROM files
WHERE files.id = $1
",
row.id,
)
.execute(&mut *transaction)