Add and remove words
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Lucien Cartier-Tilet 2023-01-24 03:51:31 +01:00
parent a624636939
commit c618bd9667
Signed by: phundrak
GPG Key ID: BD7789E705CB8DCA
3 changed files with 171 additions and 11 deletions

View File

@ -11,7 +11,7 @@ use uuid::Uuid;
use super::super::schema;
use super::users::User;
use std::convert::Into;
use std::{convert::Into, fmt::Display};
use schema::{langandagents, langtranslatesto, languages, userfollowlanguage};
@ -103,7 +103,7 @@ impl From<NewLanguage> for NewLanguageInternal {
}
impl NewLanguage {
pub fn insert_db(
pub fn insert(
&self,
db: &Database,
owner: &str,
@ -156,7 +156,17 @@ pub struct Language {
owner: String,
}
impl Display for Language {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{} ({})", self.owner, self.name, self.id)
}
}
impl Language {
pub fn is_owned_by(&self, owner: &str) -> bool {
self.owner == owner
}
pub fn find(
db: &Database,
language: Uuid,
@ -184,14 +194,14 @@ impl Language {
.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"
))
}
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(

View File

@ -83,6 +83,60 @@ pub struct NewWord {
morphology: Option<String>,
}
impl NewWord {
pub fn insert(
&self,
context: &Context,
user: &str,
) -> Result<Word, DatabaseError> {
use words::dsl;
let conn = &mut context.db.conn()?;
let mut word: NewWordInternal =
self.clone().try_into().map_err(|e| {
DatabaseError::new(
format!("Failed to parse string as uuid: {e:?}"),
"Invalid Input",
)
})?;
match Language::find(&context.db, word.language) {
Ok(language) if language.is_owned_by(<&str>::clone(&user)) => {
// Check lemma exists
word.lemma = if let Some(id) = word.lemma {
match dsl::words.find(id).first::<Word>(conn) {
Ok(_) => Some(id),
Err(_) => None,
}
} else {
None
};
match diesel::insert_into(dsl::words)
.values(word.clone())
.execute(conn)
{
Ok(_) => dsl::words.filter(dsl::norm.eq(word.norm.clone()))
.filter(dsl::language.eq(word.language))
.first::<Word>(conn)
.map_err(|e| DatabaseError::new(
format!("Failed to find word {word:?} in database: {e:?}"),
"Database Error"
)),
Err(e) => Err(DatabaseError::new(
format!(
"Failed to insert word {word:?} in database: {e:?}"
),
"Database Error",
)),
}
}
Ok(language) => Err(DatabaseError::new(
format!("Language {language} is not owned by user {user}"),
"Forbidden",
)),
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Insertable)]
#[diesel(table_name = words)]
struct NewWordInternal {
@ -145,6 +199,65 @@ pub struct Word {
}
impl Word {
pub fn find(db: &Database, word: Uuid) -> Result<Word, DatabaseError> {
use words::dsl;
dsl::words
.find(word)
.first::<Word>(&mut db.conn()?)
.map_err(|e| match e {
diesel::NotFound => DatabaseError::new(
format!("Word {word} not found"),
"Not Found",
),
e => DatabaseError::new(
format!("Error fetching word {word} from database: {e:?}"),
"Database Error",
),
})
}
pub fn is_owned_by(
&self,
db: &Database,
user: &str,
) -> Result<bool, DatabaseError> {
let language: Language = Language::find(db, self.language)?;
Ok(language.is_owned_by(user))
}
pub fn delete(
context: &Context,
id: Uuid,
user: &str,
) -> Result<(), DatabaseError> {
use words::dsl;
let conn = &mut context.db.conn()?;
match dsl::words.find(id).first::<Word>(conn) {
Ok(word) => {
if let Ok(true) = word.is_owned_by(&context.db, user) {
match diesel::delete(dsl::words.find(id))
.execute(&mut context.db.conn()?)
{
Ok(_) => Ok(()),
Err(e) => Err(DatabaseError::new(
format!("Failed to delete word {id} from database: {e:?}"),
"Database Error",
)),
}
} else {
Err(DatabaseError::new(
format!("User {user} cannot delete word from language he doesn't own"),
"Forbidden"
))
}
}
Err(e) => Err(DatabaseError::new(
format!("Failed to find word {id} in database: {e:?}"),
"Database Error",
)),
}
}
fn relationship(
&self,
db: &Database,

View File

@ -7,6 +7,7 @@ use crate::db::{
models::{
languages::{Language, NewLanguage, UserFollowLanguage},
users::User,
words::{NewWord, Word},
},
DatabaseError,
};
@ -122,7 +123,7 @@ impl Mutation {
language: NewLanguage,
) -> FieldResult<Language> {
if let Some(owner) = &context.user_auth {
language.insert_db(&context.db, owner).map_err(Into::into)
language.insert(&context.db, owner).map_err(Into::into)
} else {
Err(DatabaseError::new(
"User not authentificated, cannot create new language",
@ -157,4 +158,40 @@ impl Mutation {
.into())
}
}
pub fn new_word(context: &Context, word: NewWord) -> FieldResult<Word> {
if let Some(user) = &context.user_auth {
word.insert(context, user).map_err(Into::into)
} else {
Err(DatabaseError::new(
"User not authentificated, cannot create new language",
"Unauthorized",
)
.into())
}
}
pub fn delete_word(
context: &Context,
word: String,
) -> FieldResult<Option<Word>> {
if let Some(user) = &context.user_auth {
match Uuid::from_str(&word) {
Ok(id) => Word::delete(context, id, user)
.map(|_| None)
.map_err(Into::into),
Err(e) => Err(DatabaseError::new(
format!("Could not parse {word} as a valid UUID: {e:?}"),
"Bad Request",
)
.into()),
}
} else {
Err(DatabaseError::new(
"User not authentificated, cannot create new language",
"Unauthorized",
)
.into())
}
}
}