Implement more mutations
Implement mutations: - create language - delete language - user follows a language - user unfollows a language - new word Context's user_auth now contains either the user's ID or nothing if not authentificated.
This commit is contained in:
parent
51f0fc3108
commit
a624636939
@ -27,6 +27,12 @@ pub enum Release {
|
|||||||
Private,
|
Private,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Release {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Public
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, GraphQLEnum,
|
||||||
)]
|
)]
|
||||||
@ -50,6 +56,91 @@ pub enum AgentLanguageRelation {
|
|||||||
Author,
|
Author,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, juniper::GraphQLInputObject)]
|
||||||
|
pub struct NewLanguage {
|
||||||
|
name: String,
|
||||||
|
native: Option<String>,
|
||||||
|
release: Option<Release>,
|
||||||
|
genre: Vec<DictGenre>,
|
||||||
|
abstract_: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
rights: Option<String>,
|
||||||
|
license: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable, Debug, Clone)]
|
||||||
|
#[diesel(table_name = languages)]
|
||||||
|
struct NewLanguageInternal {
|
||||||
|
name: String,
|
||||||
|
native: Option<String>,
|
||||||
|
release: Release,
|
||||||
|
genre: Vec<DictGenre>,
|
||||||
|
abstract_: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
rights: Option<String>,
|
||||||
|
license: Option<String>,
|
||||||
|
owner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NewLanguage> for NewLanguageInternal {
|
||||||
|
fn from(val: NewLanguage) -> Self {
|
||||||
|
NewLanguageInternal {
|
||||||
|
name: val.name,
|
||||||
|
native: val.native,
|
||||||
|
release: if let Some(release) = val.release {
|
||||||
|
release
|
||||||
|
} else {
|
||||||
|
Release::default()
|
||||||
|
},
|
||||||
|
genre: val.genre,
|
||||||
|
abstract_: val.abstract_,
|
||||||
|
description: val.description,
|
||||||
|
rights: val.rights,
|
||||||
|
license: val.license,
|
||||||
|
owner: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewLanguage {
|
||||||
|
pub fn insert_db(
|
||||||
|
&self,
|
||||||
|
db: &Database,
|
||||||
|
owner: &str,
|
||||||
|
) -> Result<Language, DatabaseError> {
|
||||||
|
use languages::dsl;
|
||||||
|
let conn = &mut db.conn()?;
|
||||||
|
match diesel::insert_into(dsl::languages)
|
||||||
|
.values(NewLanguageInternal {
|
||||||
|
owner: owner.to_string(),
|
||||||
|
..self.clone().into()
|
||||||
|
})
|
||||||
|
.execute(conn)
|
||||||
|
{
|
||||||
|
Ok(_) => dsl::languages
|
||||||
|
.filter(dsl::name.eq(self.name.clone()))
|
||||||
|
.filter(dsl::owner.eq(owner))
|
||||||
|
.first::<Language>(conn)
|
||||||
|
.map_err(|e| {
|
||||||
|
DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Failed to find language {} by user {owner}: {e:?}",
|
||||||
|
self.name
|
||||||
|
),
|
||||||
|
"Database Error",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Failed to insert language {} by user {owner}: {e:?}",
|
||||||
|
self.name
|
||||||
|
),
|
||||||
|
"Database Error",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone)]
|
#[derive(Queryable, Insertable, Debug, Clone)]
|
||||||
pub struct Language {
|
pub struct Language {
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
@ -66,6 +157,59 @@ pub struct Language {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Language {
|
impl Language {
|
||||||
|
pub fn find(
|
||||||
|
db: &Database,
|
||||||
|
language: Uuid,
|
||||||
|
) -> Result<Language, DatabaseError> {
|
||||||
|
use languages::dsl;
|
||||||
|
dsl::languages.find(language).first::<Language>(&mut db.conn()?).map_err(|e| match e {
|
||||||
|
diesel::NotFound => DatabaseError::new(
|
||||||
|
format!("Language {language} not found"),
|
||||||
|
"Not Found"
|
||||||
|
),
|
||||||
|
e => DatabaseError::new(
|
||||||
|
format!("Error fetching language {language} from database: {e:?}"),
|
||||||
|
"Database Error"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(
|
||||||
|
context: &Context,
|
||||||
|
language_id: Uuid,
|
||||||
|
) -> Result<(), DatabaseError> {
|
||||||
|
use languages::dsl;
|
||||||
|
let conn = &mut context.db.conn()?;
|
||||||
|
match dsl::languages.find(language_id)
|
||||||
|
.first::<Language>(conn)
|
||||||
|
{
|
||||||
|
Ok(language) if context.user_auth == Some(language.owner.clone()) => {
|
||||||
|
match diesel::delete(dsl::languages.find(language_id))
|
||||||
|
.execute(conn) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to delete language {language_id}: {e:?}"),
|
||||||
|
"Database Error"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(language) => {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"User {} not allowed to delete other user's language {language_id}",
|
||||||
|
language.owner),
|
||||||
|
"Unauthorized"
|
||||||
|
))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
format!("Failed to delete language {language_id}: {e:?}"),
|
||||||
|
"Database Error"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn relationship(
|
fn relationship(
|
||||||
&self,
|
&self,
|
||||||
db: &Database,
|
db: &Database,
|
||||||
@ -290,6 +434,13 @@ pub struct LangTranslatesTo {
|
|||||||
langto: Uuid,
|
langto: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[diesel(table_name = userfollowlanguage)]
|
||||||
|
pub struct UserFollowLanguageInsert {
|
||||||
|
pub lang: Uuid,
|
||||||
|
pub userid: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
#[diesel(table_name = userfollowlanguage)]
|
#[diesel(table_name = userfollowlanguage)]
|
||||||
pub struct UserFollowLanguage {
|
pub struct UserFollowLanguage {
|
||||||
@ -297,3 +448,71 @@ pub struct UserFollowLanguage {
|
|||||||
pub lang: Uuid,
|
pub lang: Uuid,
|
||||||
pub userid: String,
|
pub userid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UserFollowLanguage {
|
||||||
|
pub fn user_follow_language(
|
||||||
|
context: &Context,
|
||||||
|
userid: &str,
|
||||||
|
lang: Uuid,
|
||||||
|
) -> Result<Language, DatabaseError> {
|
||||||
|
let conn = &mut context.db.conn()?;
|
||||||
|
match languages::dsl::languages.find(lang).first::<Language>(conn) {
|
||||||
|
Err(diesel::NotFound) => Err(DatabaseError::new(
|
||||||
|
format!("Cannot follow non-existing language {lang}"),
|
||||||
|
"Invalid Language",
|
||||||
|
)),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Could not retrieve language {lang} from database: {e:?}"
|
||||||
|
),
|
||||||
|
"Database error",
|
||||||
|
)),
|
||||||
|
Ok(language) => {
|
||||||
|
use userfollowlanguage::dsl;
|
||||||
|
match diesel::insert_into(dsl::userfollowlanguage)
|
||||||
|
.values(UserFollowLanguageInsert { lang, userid: userid.to_string() })
|
||||||
|
.execute(conn) {
|
||||||
|
Ok(_) => Ok(language),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to follow language {lang} as user {userid}: {e:?}"),
|
||||||
|
"Database Error"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_unfollow_language(
|
||||||
|
context: &Context,
|
||||||
|
userid: &str,
|
||||||
|
lang: Uuid,
|
||||||
|
) -> Result<Language, DatabaseError> {
|
||||||
|
use userfollowlanguage::dsl;
|
||||||
|
let conn = &mut context.db.conn()?;
|
||||||
|
match dsl::userfollowlanguage
|
||||||
|
.filter(dsl::userid.eq(userid.to_string()))
|
||||||
|
.filter(dsl::lang.eq(lang))
|
||||||
|
.first::<UserFollowLanguage>(conn) {
|
||||||
|
Ok(relationship) => {
|
||||||
|
match diesel::delete(dsl::userfollowlanguage.find(relationship.id))
|
||||||
|
.execute(conn) {
|
||||||
|
Ok(_) => Language::find(&context.db, lang),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to make user {userid} unfollow language {lang}: {e:?}"),
|
||||||
|
"Database Error"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(diesel::NotFound) => {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
format!("User {userid} does not follow language {lang}"),
|
||||||
|
"Invalid",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!("Failed to retrieve relationship between user {userid} and language {lang} from database: {e:?}"),
|
||||||
|
"Database Error",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,11 +5,11 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use juniper::{FieldResult, GraphQLEnum};
|
use juniper::{FieldResult, GraphQLEnum};
|
||||||
use schema::{wordrelation, words, wordlearning};
|
use schema::{wordlearning, wordrelation, words};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use std::convert::Into;
|
use std::{convert::Into, str::FromStr};
|
||||||
|
|
||||||
use super::languages::Language;
|
use super::languages::Language;
|
||||||
|
|
||||||
@ -20,11 +20,18 @@ pub enum WordRelationship {
|
|||||||
Related,
|
Related,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq, juniper::GraphQLEnum)]
|
#[derive(
|
||||||
|
diesel_derive_enum::DbEnum,
|
||||||
|
Debug,
|
||||||
|
Clone,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
juniper::GraphQLEnum,
|
||||||
|
)]
|
||||||
#[DieselTypePath = "crate::db::schema::sql_types::Wordlearningstatus"]
|
#[DieselTypePath = "crate::db::schema::sql_types::Wordlearningstatus"]
|
||||||
pub enum WordLearningStatus {
|
pub enum WordLearningStatus {
|
||||||
Learning,
|
Learning,
|
||||||
Learned
|
Learned,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -54,6 +61,72 @@ pub enum PartOfSpeech {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for PartOfSpeech {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Noun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, juniper::GraphQLInputObject)]
|
||||||
|
pub struct NewWord {
|
||||||
|
norm: String,
|
||||||
|
native: Option<String>,
|
||||||
|
lemma: Option<String>,
|
||||||
|
language: String,
|
||||||
|
partofspeech: PartOfSpeech,
|
||||||
|
audio: Option<String>,
|
||||||
|
video: Option<String>,
|
||||||
|
image: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
etymology: Option<String>,
|
||||||
|
lusage: Option<String>,
|
||||||
|
morphology: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Insertable)]
|
||||||
|
#[diesel(table_name = words)]
|
||||||
|
struct NewWordInternal {
|
||||||
|
norm: String,
|
||||||
|
native: Option<String>,
|
||||||
|
lemma: Option<Uuid>,
|
||||||
|
language: Uuid,
|
||||||
|
partofspeech: PartOfSpeech,
|
||||||
|
audio: Option<String>,
|
||||||
|
video: Option<String>,
|
||||||
|
image: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
etymology: Option<String>,
|
||||||
|
lusage: Option<String>,
|
||||||
|
morphology: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<NewWord> for NewWordInternal {
|
||||||
|
type Error = uuid::Error;
|
||||||
|
|
||||||
|
fn try_from(value: NewWord) -> Result<Self, Self::Error> {
|
||||||
|
let language = Uuid::from_str(&value.language)?;
|
||||||
|
let lemma = if let Some(original_lemma) = value.lemma {
|
||||||
|
Some(Uuid::from_str(&original_lemma)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
norm: value.norm,
|
||||||
|
native: value.native,
|
||||||
|
lemma,
|
||||||
|
language,
|
||||||
|
partofspeech: value.partofspeech,
|
||||||
|
audio: value.audio,
|
||||||
|
video: value.video,
|
||||||
|
image: value.image,
|
||||||
|
description: value.description,
|
||||||
|
etymology: value.etymology,
|
||||||
|
lusage: value.lusage,
|
||||||
|
morphology: value.morphology,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
#[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Word {
|
pub struct Word {
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
@ -229,5 +302,5 @@ pub struct WordLearning {
|
|||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub word: Uuid,
|
pub word: Uuid,
|
||||||
pub userid: String,
|
pub userid: String,
|
||||||
pub status: WordLearningStatus
|
pub status: WordLearningStatus,
|
||||||
}
|
}
|
||||||
|
@ -27,35 +27,42 @@ impl Default for OtherEnvVar {
|
|||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub db: Database,
|
pub db: Database,
|
||||||
pub appwrite: APVariables,
|
pub appwrite: APVariables,
|
||||||
pub user_auth: bool,
|
pub user_auth: Option<String>,
|
||||||
pub other_vars: OtherEnvVar,
|
pub other_vars: OtherEnvVar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
/// HTTP header for a user's session
|
/// Check if a request is performed by an autentificated user.
|
||||||
///
|
///
|
||||||
/// This header `Authorization` must be a single string in the
|
/// The HTTP header `Authorization` must be a single string in the
|
||||||
/// form `userId;userSessionId` with `userId` and `userSessionId`
|
/// form `userId;userSessionId` with `userId` and `userSessionId`
|
||||||
/// being variables given by Appwrite to users that are logged in.
|
/// being variables given by Appwrite to users that are logged in.
|
||||||
pub async fn user_auth<'r>(&self, auth_token: Option<&'r str>) -> bool {
|
///
|
||||||
|
/// The function returns either the user's ID if the user is
|
||||||
|
/// authentified or `None`.
|
||||||
|
pub async fn user_auth<'r>(
|
||||||
|
&self,
|
||||||
|
auth_token: Option<&'r str>,
|
||||||
|
) -> Option<String> {
|
||||||
if let Some(token) = auth_token {
|
if let Some(token) = auth_token {
|
||||||
let key = token.split(';').collect::<Vec<_>>();
|
let key = token.split(';').collect::<Vec<_>>();
|
||||||
if key.len() == 2 {
|
if key.len() == 2 {
|
||||||
let user_id = key[0];
|
let user_id = key[0];
|
||||||
let session_id = key[1];
|
let session_id = key[1];
|
||||||
match self.appwrite.check_session(session_id, user_id).await {
|
match self.appwrite.check_session(session_id, user_id).await {
|
||||||
Ok(val) => val,
|
Ok(true) => Some(key[0].to_string()),
|
||||||
|
Ok(false) => None,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
info!("Error checking user session: {:?}", e);
|
info!("Error checking user session: {:?}", e);
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("Invalid session key: {}", token);
|
info!("Invalid session key: {}", token);
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
use juniper::FieldResult;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::db::{models::users::User, DatabaseError};
|
use juniper::FieldResult;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::db::{
|
||||||
|
models::{
|
||||||
|
languages::{Language, NewLanguage, UserFollowLanguage},
|
||||||
|
users::User,
|
||||||
|
},
|
||||||
|
DatabaseError,
|
||||||
|
};
|
||||||
|
|
||||||
use super::Context;
|
use super::Context;
|
||||||
|
|
||||||
@ -9,7 +18,7 @@ pub struct Mutation;
|
|||||||
#[juniper::graphql_object(Context = Context)]
|
#[juniper::graphql_object(Context = Context)]
|
||||||
impl Mutation {
|
impl Mutation {
|
||||||
fn api_version(context: &Context) -> String {
|
fn api_version(context: &Context) -> String {
|
||||||
if context.user_auth {
|
if context.user_auth.is_some() {
|
||||||
"0.1 (authentified)"
|
"0.1 (authentified)"
|
||||||
} else {
|
} else {
|
||||||
"0.1 (not authentified)"
|
"0.1 (not authentified)"
|
||||||
@ -49,4 +58,103 @@ impl Mutation {
|
|||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn user_follow_language(
|
||||||
|
context: &Context,
|
||||||
|
language: String,
|
||||||
|
) -> FieldResult<Language> {
|
||||||
|
if let Some(userid) = &context.user_auth {
|
||||||
|
match Uuid::from_str(&language) {
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Could not parse {language} as a valid UUID: {e:?}"
|
||||||
|
),
|
||||||
|
"Bad Request",
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
Ok(lang) => UserFollowLanguage::user_follow_language(
|
||||||
|
context,
|
||||||
|
&userid.to_string(),
|
||||||
|
lang,
|
||||||
|
)
|
||||||
|
.map_err(Into::into),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
"User not authentificated, cannot proceed",
|
||||||
|
"Unauthorized",
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_unfollow_language(
|
||||||
|
context: &Context,
|
||||||
|
language: String,
|
||||||
|
) -> FieldResult<Language> {
|
||||||
|
if let Some(userid) = &context.user_auth {
|
||||||
|
match Uuid::from_str(&language) {
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Could not parse {language} as a valid UUID: {e:?}"
|
||||||
|
),
|
||||||
|
"Bad Request",
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
Ok(lang) => UserFollowLanguage::user_unfollow_language(
|
||||||
|
context,
|
||||||
|
&userid.to_string(),
|
||||||
|
lang,
|
||||||
|
)
|
||||||
|
.map_err(Into::into),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
"User not authentificated, cannot proceed",
|
||||||
|
"Unauthorized",
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_language(
|
||||||
|
context: &Context,
|
||||||
|
language: NewLanguage,
|
||||||
|
) -> FieldResult<Language> {
|
||||||
|
if let Some(owner) = &context.user_auth {
|
||||||
|
language.insert_db(&context.db, owner).map_err(Into::into)
|
||||||
|
} else {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
"User not authentificated, cannot create new language",
|
||||||
|
"Unauthorized",
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_language(
|
||||||
|
context: &Context,
|
||||||
|
language: String,
|
||||||
|
) -> FieldResult<Option<Language>> {
|
||||||
|
if context.user_auth.is_some() {
|
||||||
|
match Uuid::from_str(&language) {
|
||||||
|
Ok(uuid) => Language::delete(context, uuid)
|
||||||
|
.map(|_| None)
|
||||||
|
.map_err(Into::into),
|
||||||
|
Err(e) => Err(DatabaseError::new(
|
||||||
|
format!(
|
||||||
|
"Could not parse {language} as a valid UUID: {e:?}"
|
||||||
|
),
|
||||||
|
"Bad Request",
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(DatabaseError::new(
|
||||||
|
"User not authentificated, cannot create new language",
|
||||||
|
"Unauthorized",
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user