You've already forked AstralRinth
forked from didirus/AstralRinth
Fix affiliate PUT API (#4456)
* Fix affiliate PUT API * PR fixes * wip: merge affiliate code endpoints
This commit is contained in:
@@ -10,8 +10,15 @@ Before a pull request can be opened, run `cargo clippy -p labrinth --all-targets
|
|||||||
|
|
||||||
Use `cargo test -p labrinth --all-targets` to test your changes. All tests must pass, otherwise CI will fail.
|
Use `cargo test -p labrinth --all-targets` to test your changes. All tests must pass, otherwise CI will fail.
|
||||||
|
|
||||||
|
To prepare the sqlx cache, cd into `apps/labrinth` and run `cargo sqlx prepare`. Make sure to NEVER run `cargo sqlx prepare --workspace`.
|
||||||
|
|
||||||
Read the root `docker-compose.yml` to see what running services are available while developing. Use `docker exec` to access these services.
|
Read the root `docker-compose.yml` to see what running services are available while developing. Use `docker exec` to access these services.
|
||||||
|
|
||||||
|
When the user refers to "performing pre-PR checks", do the following:
|
||||||
|
- Run clippy as described above
|
||||||
|
- DO NOT run tests unless explicitly requested (they take a long time)
|
||||||
|
- Prepare the sqlx cache
|
||||||
|
|
||||||
### Clickhouse
|
### Clickhouse
|
||||||
|
|
||||||
Use `docker exec labrinth-clickhouse clickhouse-client` to access the Clickhouse instance. We use the `staging_ariadne` database to store data in testing.
|
Use `docker exec labrinth-clickhouse clickhouse-client` to access the Clickhouse instance. We use the `staging_ariadne` database to store data in testing.
|
||||||
|
|||||||
@@ -19,6 +19,25 @@ pub struct AdminAffiliateCode {
|
|||||||
pub created_by: UserId,
|
pub created_by: UserId,
|
||||||
/// User who refers the purchaser.
|
/// User who refers the purchaser.
|
||||||
pub affiliate: UserId,
|
pub affiliate: UserId,
|
||||||
|
/// Affiliate-defined name for this affiliate code - where the click came
|
||||||
|
/// from.
|
||||||
|
pub source_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crate::database::models::affiliate_code_item::DBAffiliateCode>
|
||||||
|
for AdminAffiliateCode
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
data: crate::database::models::affiliate_code_item::DBAffiliateCode,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id: data.id.into(),
|
||||||
|
created_at: data.created_at,
|
||||||
|
created_by: data.created_by.into(),
|
||||||
|
affiliate: data.affiliate.into(),
|
||||||
|
source_name: data.source_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Affiliate code used to track referral purchases.
|
/// Affiliate code used to track referral purchases.
|
||||||
@@ -36,21 +55,9 @@ pub struct AffiliateCode {
|
|||||||
pub id: AffiliateCodeId,
|
pub id: AffiliateCodeId,
|
||||||
/// User who refers the purchaser.
|
/// User who refers the purchaser.
|
||||||
pub affiliate: UserId,
|
pub affiliate: UserId,
|
||||||
}
|
/// Affiliate-defined name for this affiliate code - where the click came
|
||||||
|
/// from.
|
||||||
impl From<crate::database::models::affiliate_code_item::DBAffiliateCode>
|
pub source_name: String,
|
||||||
for AdminAffiliateCode
|
|
||||||
{
|
|
||||||
fn from(
|
|
||||||
data: crate::database::models::affiliate_code_item::DBAffiliateCode,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
id: data.id.into(),
|
|
||||||
created_at: data.created_at,
|
|
||||||
created_by: data.created_by.into(),
|
|
||||||
affiliate: data.affiliate.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::database::models::affiliate_code_item::DBAffiliateCode>
|
impl From<crate::database::models::affiliate_code_item::DBAffiliateCode>
|
||||||
@@ -62,6 +69,7 @@ impl From<crate::database::models::affiliate_code_item::DBAffiliateCode>
|
|||||||
Self {
|
Self {
|
||||||
id: data.id.into(),
|
id: data.id.into(),
|
||||||
affiliate: data.affiliate.into(),
|
affiliate: data.affiliate.into(),
|
||||||
|
source_name: data.source_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,10 @@ use crate::{
|
|||||||
},
|
},
|
||||||
queue::session::AuthQueue,
|
queue::session::AuthQueue,
|
||||||
};
|
};
|
||||||
use actix_web::{
|
use actix_web::{HttpRequest, HttpResponse, web};
|
||||||
HttpRequest, HttpResponse,
|
|
||||||
web::{self, Json},
|
|
||||||
};
|
|
||||||
use ariadne::ids::UserId;
|
use ariadne::ids::UserId;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Deserialize;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::routes::ApiError;
|
use crate::routes::ApiError;
|
||||||
@@ -26,25 +23,20 @@ use crate::routes::ApiError;
|
|||||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
web::scope("affiliate")
|
web::scope("affiliate")
|
||||||
.route("/admin", web::get().to(admin_get_all))
|
.route("", web::get().to(get_all))
|
||||||
.route("/admin", web::put().to(admin_create))
|
.route("", web::put().to(create))
|
||||||
.route("/admin/{id}", web::get().to(admin_get))
|
.route("/{id}", web::get().to(get))
|
||||||
.route("/admin/{id}", web::delete().to(admin_delete))
|
.route("/{id}", web::delete().to(delete))
|
||||||
.route("/self", web::get().to(self_get_all))
|
.route("/{id}", web::patch().to(patch)),
|
||||||
.route("/self", web::put().to(self_patch))
|
|
||||||
.route("/self/{id}", web::delete().to(self_delete)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
async fn get_all(
|
||||||
struct AdminGetAllResponse(Vec<AdminAffiliateCode>);
|
|
||||||
|
|
||||||
async fn admin_get_all(
|
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
redis: web::Data<RedisPool>,
|
redis: web::Data<RedisPool>,
|
||||||
session_queue: web::Data<AuthQueue>,
|
session_queue: web::Data<AuthQueue>,
|
||||||
) -> Result<Json<AdminGetAllResponse>, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let (_, user) = get_user_from_headers(
|
let (_, user) = get_user_from_headers(
|
||||||
&req,
|
&req,
|
||||||
&**pool,
|
&**pool,
|
||||||
@@ -54,38 +46,42 @@ async fn admin_get_all(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !user.role.is_admin() {
|
if user.role.is_admin() {
|
||||||
return Err(ApiError::CustomAuthentication(
|
let codes = DBAffiliateCode::get_all(&**pool).await?;
|
||||||
"You do not have permission to read all affiliate codes!"
|
let codes = codes
|
||||||
.to_string(),
|
.into_iter()
|
||||||
));
|
.map(AdminAffiliateCode::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ok(HttpResponse::Ok().json(codes))
|
||||||
|
} else if user.badges.contains(Badges::AFFILIATE) {
|
||||||
|
let codes =
|
||||||
|
DBAffiliateCode::get_by_affiliate(DBUserId::from(user.id), &**pool)
|
||||||
|
.await?;
|
||||||
|
let codes = codes
|
||||||
|
.into_iter()
|
||||||
|
.map(AffiliateCode::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ok(HttpResponse::Ok().json(codes))
|
||||||
|
} else {
|
||||||
|
Err(ApiError::CustomAuthentication(
|
||||||
|
"You do not have permission to view affiliate codes!".to_string(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
let codes = DBAffiliateCode::get_all(&**pool).await?;
|
|
||||||
let codes = codes
|
|
||||||
.into_iter()
|
|
||||||
.map(AdminAffiliateCode::from)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Ok(Json(AdminGetAllResponse(codes)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct AdminCreateRequest {
|
struct CreateRequest {
|
||||||
affiliate: UserId,
|
affiliate: Option<UserId>,
|
||||||
source_name: String,
|
source_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
async fn create(
|
||||||
struct AdminCreateResponse(AdminAffiliateCode);
|
|
||||||
|
|
||||||
async fn admin_create(
|
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
redis: web::Data<RedisPool>,
|
redis: web::Data<RedisPool>,
|
||||||
session_queue: web::Data<AuthQueue>,
|
session_queue: web::Data<AuthQueue>,
|
||||||
body: web::Json<AdminCreateRequest>,
|
body: web::Json<CreateRequest>,
|
||||||
) -> Result<Json<AdminCreateResponse>, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let (_, creator) = get_user_from_headers(
|
let (_, creator) = get_user_from_headers(
|
||||||
&req,
|
&req,
|
||||||
&**pool,
|
&**pool,
|
||||||
@@ -95,7 +91,10 @@ async fn admin_create(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !creator.role.is_admin() {
|
let is_admin = creator.role.is_admin();
|
||||||
|
let is_affiliate = creator.badges.contains(Badges::AFFILIATE);
|
||||||
|
|
||||||
|
if !is_admin && !is_affiliate {
|
||||||
return Err(ApiError::CustomAuthentication(
|
return Err(ApiError::CustomAuthentication(
|
||||||
"You do not have permission to create an affiliate code!"
|
"You do not have permission to create an affiliate code!"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
@@ -103,15 +102,26 @@ async fn admin_create(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let creator_id = DBUserId::from(creator.id);
|
let creator_id = DBUserId::from(creator.id);
|
||||||
let affiliate_id = DBUserId::from(body.affiliate);
|
let affiliate_id = if is_admin {
|
||||||
let Some(_affiliate_user) =
|
if let Some(affiliate) = body.affiliate {
|
||||||
DBUser::get_id(affiliate_id, &**pool, &redis).await?
|
DBUserId::from(affiliate)
|
||||||
else {
|
} else {
|
||||||
return Err(ApiError::CustomAuthentication(
|
creator_id
|
||||||
"Affiliate user not found!".to_string(),
|
}
|
||||||
));
|
} else {
|
||||||
|
creator_id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if affiliate_id != creator_id {
|
||||||
|
let Some(_affiliate_user) =
|
||||||
|
DBUser::get_id(affiliate_id, &**pool, &redis).await?
|
||||||
|
else {
|
||||||
|
return Err(ApiError::CustomAuthentication(
|
||||||
|
"Affiliate user not found!".to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let mut transaction = pool.begin().await?;
|
let mut transaction = pool.begin().await?;
|
||||||
|
|
||||||
let affiliate_code_id =
|
let affiliate_code_id =
|
||||||
@@ -129,19 +139,20 @@ async fn admin_create(
|
|||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
|
|
||||||
Ok(Json(AdminCreateResponse(AdminAffiliateCode::from(code))))
|
if is_admin {
|
||||||
|
Ok(HttpResponse::Created().json(AdminAffiliateCode::from(code)))
|
||||||
|
} else {
|
||||||
|
Ok(HttpResponse::Created().json(AffiliateCode::from(code)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
async fn get(
|
||||||
struct AdminGetResponse(AdminAffiliateCode);
|
|
||||||
|
|
||||||
async fn admin_get(
|
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<(AffiliateCodeId,)>,
|
path: web::Path<(AffiliateCodeId,)>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
redis: web::Data<RedisPool>,
|
redis: web::Data<RedisPool>,
|
||||||
session_queue: web::Data<AuthQueue>,
|
session_queue: web::Data<AuthQueue>,
|
||||||
) -> Result<Json<AdminGetResponse>, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let (_, user) = get_user_from_headers(
|
let (_, user) = get_user_from_headers(
|
||||||
&req,
|
&req,
|
||||||
&**pool,
|
&**pool,
|
||||||
@@ -151,26 +162,30 @@ async fn admin_get(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !user.role.is_admin() {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have permission to read an affiliate code!".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (affiliate_code_id,) = path.into_inner();
|
let (affiliate_code_id,) = path.into_inner();
|
||||||
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
||||||
|
|
||||||
if let Some(model) =
|
if let Some(model) =
|
||||||
DBAffiliateCode::get_by_id(affiliate_code_id, &**pool).await?
|
DBAffiliateCode::get_by_id(affiliate_code_id, &**pool).await?
|
||||||
{
|
{
|
||||||
let model = AdminAffiliateCode::from(model);
|
let is_admin = user.role.is_admin();
|
||||||
Ok(Json(AdminGetResponse(model)))
|
let is_owner = model.affiliate == DBUserId::from(user.id);
|
||||||
|
|
||||||
|
if is_admin || is_owner {
|
||||||
|
if is_admin {
|
||||||
|
Ok(HttpResponse::Ok().json(AdminAffiliateCode::from(model)))
|
||||||
|
} else {
|
||||||
|
Ok(HttpResponse::Ok().json(AffiliateCode::from(model)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ApiError::NotFound)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::NotFound)
|
Err(ApiError::NotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn admin_delete(
|
async fn delete(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
path: web::Path<(AffiliateCodeId,)>,
|
path: web::Path<(AffiliateCodeId,)>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
@@ -186,74 +201,43 @@ async fn admin_delete(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !user.role.is_admin() {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have permission to delete an affiliate code!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (affiliate_code_id,) = path.into_inner();
|
let (affiliate_code_id,) = path.into_inner();
|
||||||
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
||||||
|
|
||||||
let result = DBAffiliateCode::remove(affiliate_code_id, &**pool).await?;
|
if let Some(model) =
|
||||||
|
DBAffiliateCode::get_by_id(affiliate_code_id, &**pool).await?
|
||||||
|
{
|
||||||
|
let is_admin = user.role.is_admin();
|
||||||
|
let is_owner = model.affiliate == DBUserId::from(user.id);
|
||||||
|
|
||||||
if result.is_some() {
|
if is_admin || is_owner {
|
||||||
Ok(HttpResponse::NoContent().finish())
|
let result =
|
||||||
|
DBAffiliateCode::remove(affiliate_code_id, &**pool).await?;
|
||||||
|
if result.is_some() {
|
||||||
|
Ok(HttpResponse::NoContent().finish())
|
||||||
|
} else {
|
||||||
|
Err(ApiError::NotFound)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ApiError::NotFound)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::NotFound)
|
Err(ApiError::NotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct SelfGetAllResponse(Vec<AffiliateCode>);
|
|
||||||
|
|
||||||
async fn self_get_all(
|
|
||||||
req: HttpRequest,
|
|
||||||
pool: web::Data<PgPool>,
|
|
||||||
redis: web::Data<RedisPool>,
|
|
||||||
session_queue: web::Data<AuthQueue>,
|
|
||||||
) -> Result<Json<SelfGetAllResponse>, ApiError> {
|
|
||||||
let (_, user) = get_user_from_headers(
|
|
||||||
&req,
|
|
||||||
&**pool,
|
|
||||||
&redis,
|
|
||||||
&session_queue,
|
|
||||||
Scopes::SESSION_ACCESS,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !user.badges.contains(Badges::AFFILIATE) {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have permission to view your affiliate codes!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let codes =
|
|
||||||
DBAffiliateCode::get_by_affiliate(DBUserId::from(user.id), &**pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let codes = codes
|
|
||||||
.into_iter()
|
|
||||||
.map(AffiliateCode::from)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Ok(Json(SelfGetAllResponse(codes)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct SelfPatchRequest {
|
struct PatchRequest {
|
||||||
id: AffiliateCodeId,
|
|
||||||
source_name: String,
|
source_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn self_patch(
|
async fn patch(
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
|
path: web::Path<(AffiliateCodeId,)>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
redis: web::Data<RedisPool>,
|
redis: web::Data<RedisPool>,
|
||||||
session_queue: web::Data<AuthQueue>,
|
session_queue: web::Data<AuthQueue>,
|
||||||
body: web::Json<SelfPatchRequest>,
|
body: web::Json<PatchRequest>,
|
||||||
) -> Result<HttpResponse, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let (_, user) = get_user_from_headers(
|
let (_, user) = get_user_from_headers(
|
||||||
&req,
|
&req,
|
||||||
@@ -264,23 +248,26 @@ async fn self_patch(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !user.badges.contains(Badges::AFFILIATE) {
|
let (affiliate_code_id,) = path.into_inner();
|
||||||
return Err(ApiError::CustomAuthentication(
|
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
||||||
"You do not have permission to update your affiliate codes!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let affiliate_code_id = DBAffiliateCodeId::from(body.id);
|
|
||||||
|
|
||||||
let existing_code = DBAffiliateCode::get_by_id(affiliate_code_id, &**pool)
|
let existing_code = DBAffiliateCode::get_by_id(affiliate_code_id, &**pool)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(ApiError::NotFound)?;
|
.ok_or(ApiError::NotFound)?;
|
||||||
|
|
||||||
if existing_code.affiliate != DBUserId::from(user.id) {
|
let is_admin = user.role.is_admin();
|
||||||
|
let is_owner = existing_code.affiliate == DBUserId::from(user.id);
|
||||||
|
|
||||||
|
if !is_admin && !is_owner {
|
||||||
return Err(ApiError::NotFound);
|
return Err(ApiError::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !is_admin && !user.badges.contains(Badges::AFFILIATE) {
|
||||||
|
return Err(ApiError::CustomAuthentication(
|
||||||
|
"You do not have permission to update affiliate codes!".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
DBAffiliateCode::update_source_name(
|
DBAffiliateCode::update_source_name(
|
||||||
affiliate_code_id,
|
affiliate_code_id,
|
||||||
&body.source_name,
|
&body.source_name,
|
||||||
@@ -290,45 +277,3 @@ async fn self_patch(
|
|||||||
|
|
||||||
Ok(HttpResponse::NoContent().finish())
|
Ok(HttpResponse::NoContent().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn self_delete(
|
|
||||||
req: HttpRequest,
|
|
||||||
path: web::Path<(AffiliateCodeId,)>,
|
|
||||||
pool: web::Data<PgPool>,
|
|
||||||
redis: web::Data<RedisPool>,
|
|
||||||
session_queue: web::Data<AuthQueue>,
|
|
||||||
) -> Result<HttpResponse, ApiError> {
|
|
||||||
let (_, user) = get_user_from_headers(
|
|
||||||
&req,
|
|
||||||
&**pool,
|
|
||||||
&redis,
|
|
||||||
&session_queue,
|
|
||||||
Scopes::SESSION_ACCESS,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !user.badges.contains(Badges::AFFILIATE) {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have permission to delete your affiliate codes!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (affiliate_code_id,) = path.into_inner();
|
|
||||||
let affiliate_code_id = DBAffiliateCodeId::from(affiliate_code_id);
|
|
||||||
|
|
||||||
let code = DBAffiliateCode::get_by_id(affiliate_code_id, &**pool)
|
|
||||||
.await?
|
|
||||||
.ok_or(ApiError::NotFound)?;
|
|
||||||
|
|
||||||
if code.affiliate != DBUserId::from(user.id) {
|
|
||||||
return Err(ApiError::NotFound);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = DBAffiliateCode::remove(affiliate_code_id, &**pool).await?;
|
|
||||||
if result.is_some() {
|
|
||||||
Ok(HttpResponse::NoContent().finish())
|
|
||||||
} else {
|
|
||||||
Err(ApiError::NotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user