117 lines
3.2 KiB
Rust
117 lines
3.2 KiB
Rust
|
use crate::user::User;
|
||
|
use derive_more::{Display, Error};
|
||
|
use serde::{Deserialize, Serialize};
|
||
|
|
||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||
|
pub struct Project {
|
||
|
id: usize,
|
||
|
name: String,
|
||
|
description: Option<String>,
|
||
|
members: Vec<User>,
|
||
|
}
|
||
|
|
||
|
pub mod services {
|
||
|
use super::*;
|
||
|
|
||
|
pub fn get_projects_belonging_to_user(
|
||
|
project_adapter: &dyn SecondaryPortProject,
|
||
|
owner: &User,
|
||
|
) -> ProjectResult<Vec<Project>> {
|
||
|
project_adapter.get_projects_belonging_to_user(owner.id())
|
||
|
}
|
||
|
|
||
|
pub fn create(
|
||
|
project_adapter: &dyn SecondaryPortProject,
|
||
|
owner: User,
|
||
|
name: String,
|
||
|
description: Option<String>,
|
||
|
) -> ProjectResult<Project> {
|
||
|
let id = project_adapter.create_project(&name, description.as_deref(), owner.id())?;
|
||
|
Ok(Project::new(id, name, description, vec![owner]))
|
||
|
}
|
||
|
|
||
|
fn doer_is_member(
|
||
|
project_adapter: &dyn SecondaryPortProject,
|
||
|
project_id: usize,
|
||
|
doer: &User,
|
||
|
) -> ProjectResult<bool> {
|
||
|
let p = project_adapter.get_project_by_id(project_id)?;
|
||
|
Ok(p.doer_is_member(doer))
|
||
|
}
|
||
|
pub fn update_description(
|
||
|
project_adapter: &dyn SecondaryPortProject,
|
||
|
project_id: usize,
|
||
|
doer: &User,
|
||
|
new_description: String,
|
||
|
) -> ProjectResult<Project> {
|
||
|
if doer_is_member(project_adapter, project_id, doer)? {
|
||
|
let mut p = project_adapter.get_project_by_id(project_id)?;
|
||
|
project_adapter.update_description(p.id, &new_description)?;
|
||
|
p.update_description(new_description);
|
||
|
Ok(p)
|
||
|
} else {
|
||
|
Err(ProjectError::Unauthorized)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Project {
|
||
|
// getters
|
||
|
pub fn id(&self) -> usize {
|
||
|
self.id
|
||
|
}
|
||
|
|
||
|
pub fn name(&self) -> &str {
|
||
|
&self.name
|
||
|
}
|
||
|
|
||
|
pub fn description(&self) -> Option<&str> {
|
||
|
self.description.as_deref()
|
||
|
}
|
||
|
pub fn email(&self) -> &[User] {
|
||
|
&self.members
|
||
|
}
|
||
|
|
||
|
fn new(id: usize, name: String, description: Option<String>, members: Vec<User>) -> Self {
|
||
|
Self {
|
||
|
id,
|
||
|
name,
|
||
|
description,
|
||
|
members,
|
||
|
}
|
||
|
}
|
||
|
fn update_description(&mut self, new_description: String) {
|
||
|
self.description = Some(new_description)
|
||
|
}
|
||
|
|
||
|
fn doer_is_member(&self, doer: &User) -> bool {
|
||
|
self.members.contains(doer)
|
||
|
}
|
||
|
|
||
|
pub fn load(id: usize, name: String, description: Option<String>, members: Vec<User>) -> Self {
|
||
|
Self::new(id, name, description, members)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub type ProjectResult<V> = Result<V, ProjectError>;
|
||
|
|
||
|
#[derive(Debug, Display, Error)]
|
||
|
pub enum ProjectError {
|
||
|
Unauthorized,
|
||
|
}
|
||
|
|
||
|
pub trait SecondaryPortProject {
|
||
|
// returns ID of newly created Project
|
||
|
fn create_project(
|
||
|
&self,
|
||
|
name: &str,
|
||
|
description: Option<&str>,
|
||
|
owner_id: usize,
|
||
|
) -> ProjectResult<usize>;
|
||
|
fn update_description(&self, id: usize, new_description: &str) -> ProjectResult<Project>;
|
||
|
|
||
|
// get user from DB
|
||
|
fn get_project_by_id(&self, id: usize) -> ProjectResult<Project>;
|
||
|
fn get_projects_belonging_to_user(&self, user_id: usize) -> ProjectResult<Vec<Project>>;
|
||
|
}
|