This commit is contained in:
parent
a624636939
commit
c618bd9667
@ -11,7 +11,7 @@ use uuid::Uuid;
|
|||||||
use super::super::schema;
|
use super::super::schema;
|
||||||
use super::users::User;
|
use super::users::User;
|
||||||
|
|
||||||
use std::convert::Into;
|
use std::{convert::Into, fmt::Display};
|
||||||
|
|
||||||
use schema::{langandagents, langtranslatesto, languages, userfollowlanguage};
|
use schema::{langandagents, langtranslatesto, languages, userfollowlanguage};
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ impl From<NewLanguage> for NewLanguageInternal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewLanguage {
|
impl NewLanguage {
|
||||||
pub fn insert_db(
|
pub fn insert(
|
||||||
&self,
|
&self,
|
||||||
db: &Database,
|
db: &Database,
|
||||||
owner: &str,
|
owner: &str,
|
||||||
@ -156,7 +156,17 @@ pub struct Language {
|
|||||||
owner: String,
|
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 {
|
impl Language {
|
||||||
|
pub fn is_owned_by(&self, owner: &str) -> bool {
|
||||||
|
self.owner == owner
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find(
|
pub fn find(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
language: Uuid,
|
language: Uuid,
|
||||||
|
@ -83,6 +83,60 @@ pub struct NewWord {
|
|||||||
morphology: Option<String>,
|
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)]
|
#[derive(Debug, Clone, Insertable)]
|
||||||
#[diesel(table_name = words)]
|
#[diesel(table_name = words)]
|
||||||
struct NewWordInternal {
|
struct NewWordInternal {
|
||||||
@ -145,6 +199,65 @@ pub struct Word {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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(
|
fn relationship(
|
||||||
&self,
|
&self,
|
||||||
db: &Database,
|
db: &Database,
|
||||||
|
@ -7,6 +7,7 @@ use crate::db::{
|
|||||||
models::{
|
models::{
|
||||||
languages::{Language, NewLanguage, UserFollowLanguage},
|
languages::{Language, NewLanguage, UserFollowLanguage},
|
||||||
users::User,
|
users::User,
|
||||||
|
words::{NewWord, Word},
|
||||||
},
|
},
|
||||||
DatabaseError,
|
DatabaseError,
|
||||||
};
|
};
|
||||||
@ -122,7 +123,7 @@ impl Mutation {
|
|||||||
language: NewLanguage,
|
language: NewLanguage,
|
||||||
) -> FieldResult<Language> {
|
) -> FieldResult<Language> {
|
||||||
if let Some(owner) = &context.user_auth {
|
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 {
|
} else {
|
||||||
Err(DatabaseError::new(
|
Err(DatabaseError::new(
|
||||||
"User not authentificated, cannot create new language",
|
"User not authentificated, cannot create new language",
|
||||||
@ -157,4 +158,40 @@ impl Mutation {
|
|||||||
.into())
|
.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())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user