This repository has been archived on 2024-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
hexagonal-arch-sandbox/src/project.rs
2024-04-23 14:10:05 +05:30

116 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>>;
}