Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(org): suport get, remove, add, update #71

Merged
merged 8 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"algohub",
"chrono",
"covector",
"farmfe",
"ICPC",
"serde",
"dtolnay",
"farmfe",
"ICPC",
"jbolda",
"nnyaku",
"serde",
"signin",
"surrealdb"
]
Expand Down
23 changes: 23 additions & 0 deletions .zsh_history
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cargo test
cargo test
cargo test
cargo fmt --all -- --check && cargo clippy --all-features -- -D warnings\

cargo test
git commit -m "feat: suport get, remove, add, update"
git add .
git commit -m "feat: suport get, remove, add, update"
git push
git push
git push
git push
git push
git push
git push
git push
git push
git push
git push
git push
git push
git push
8 changes: 8 additions & 0 deletions 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
surreal start --user root --pass root --bind 127.0.0.1:5176\

surreal start --user root --pass root --bind 127.0.0.1:5176\

surreal start --user root --pass root --bind 127.0.0.1:5176\

surreal start --user root --pass root --bind 127.0.0.1:5176\

2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 73 additions & 2 deletions src/models/organization.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::vec;

use serde::{Deserialize, Serialize};
use surrealdb::sql::Thing;

Expand All @@ -11,8 +13,7 @@ pub struct Organization {

pub owners: Vec<Thing>,
pub members: Vec<Thing>,

pub creator: String,
pub creator: Option<Thing>,

pub created_at: chrono::NaiveDateTime,
pub updated_at: chrono::NaiveDateTime,
Expand All @@ -26,6 +27,14 @@ pub struct OrganizationData<'c> {
pub description: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct UpdateOrg {
pub name: String,
pub display_name: Option<String>,
pub description: Option<String>,
}

#[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct CreateOrganization<'r> {
Expand All @@ -34,3 +43,65 @@ pub struct CreateOrganization<'r> {

pub org: OrganizationData<'r>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct UserOrganization {
pub name: String,
pub display_name: Option<String>,
pub description: Option<String>,

pub owners: Vec<String>,
pub members: Vec<String>,

pub created_at: chrono::NaiveDateTime,
pub updated_at: chrono::NaiveDateTime,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct ChangeMember<'r> {
pub id: &'r str,
pub token: &'r str,
pub members: Vec<String>,
}

impl From<CreateOrganization<'_>> for Organization {
fn from(val: CreateOrganization) -> Self {
Organization {
id: None,
name: val.org.name.to_string(),
display_name: val.org.display_name,
description: val.org.description,
owners: vec![("account", val.id).into()],
members: vec![],
creator: Some(("account".to_string(), val.id.to_string()).into()),
created_at: chrono::Utc::now().naive_utc(),
updated_at: chrono::Utc::now().naive_utc(),
}
}
}

impl From<Organization> for UserOrganization {
fn from(val: Organization) -> Self {
UserOrganization {
name: val.name,
display_name: val.display_name,
description: val.description,
owners: val.owners.iter().map(|x| x.to_string()).collect(),
members: val.members.iter().map(|x| x.to_string()).collect(),
created_at: val.created_at,
updated_at: val.updated_at,
}
}
}

impl From<OrganizationData<'_>> for UpdateOrg {
fn from(val: OrganizationData) -> Self {
UpdateOrg {
name: val.name.to_string(),
display_name: val.display_name,
description: val.description,
}
}
}
110 changes: 107 additions & 3 deletions src/routes/organization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use surrealdb::{engine::remote::ws::Client, Surreal};
use crate::{
models::{
error::Error,
organization::CreateOrganization,
organization::{ChangeMember, CreateOrganization, Organization, UserOrganization},
response::{Empty, Response},
Credentials, OwnedId,
},
Expand All @@ -24,7 +24,7 @@ pub async fn create(
)));
}

let org = organization::create(db, org.id, org.into_inner().org)
let org = organization::create(db, org.into_inner())
.await?
.ok_or(Error::ServerError(Json(
"Failed to create a new organization".into(),
Expand All @@ -39,6 +39,110 @@ pub async fn create(
}))
}

#[post("/get/<id>", data = "<auth>")]
pub async fn get(
db: &State<Surreal<Client>>,
id: &str,
auth: Json<Option<Credentials<'_>>>,
) -> Result<UserOrganization> {
if let Some(auth) = auth.into_inner() {
if !session::verify(db, auth.id, auth.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}
} else {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}

let org = organization::get_by_id::<Organization>(db, id)
.await?
.ok_or(Error::NotFound(Json("Organization not found".into())))?;

Ok(Json(Response {
success: true,
message: "Organization found".to_string(),
data: Some(org.into()),
}))
}

#[post("/add/<id>", data = "<member>")]
pub async fn add(
db: &State<Surreal<Client>>,
id: &str,
member: Json<ChangeMember<'_>>,
) -> Result<Empty> {
if !session::verify(db, member.id, member.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}

organization::add(db, id, member.into_inner().members)
.await?
.ok_or(Error::ServerError(Json(
"Failed to add members to the organization".into(),
)))?;

Ok(Json(Response {
success: true,
message: "Members added successfully".into(),
data: None,
}))
}

#[post("/remove/<id>", data = "<member>")]
pub async fn remove(
db: &State<Surreal<Client>>,
id: &str,
member: Json<ChangeMember<'_>>,
) -> Result<Empty> {
if !session::verify(db, member.id, member.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}

organization::remove(db, id, member.into_inner().members)
.await?
.ok_or(Error::ServerError(Json(
"Failed to remove members to the organization".into(),
)))?;

Ok(Json(Response {
success: true,
message: "Members removed successfully".into(),
data: None,
}))
}

#[post("/update/<id>", data = "<org>")]
pub async fn update(
db: &State<Surreal<Client>>,
id: &str,
org: Json<CreateOrganization<'_>>,
) -> Result<Empty> {
if !session::verify(db, org.id, org.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}

organization::update(db, id, org.into_inner().org)
.await?
.ok_or(Error::ServerError(Json(
"Failed to update the organization".into(),
)))?;

Ok(Json(Response {
success: true,
message: "Organization updated successfully".to_string(),
data: None,
}))
}

#[post("/delete/<id>", data = "<org>")]
pub async fn delete(
db: &State<Surreal<Client>>,
Expand All @@ -64,5 +168,5 @@ pub async fn delete(

pub fn routes() -> Vec<rocket::Route> {
use rocket::routes;
routes![create, delete]
routes![create, add, update, get, delete, remove]
}
73 changes: 58 additions & 15 deletions src/utils/organization.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
use anyhow::Result;
use serde::Deserialize;
use surrealdb::{engine::remote::ws::Client, Surreal};
use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};

use crate::models::organization::{Organization, OrganizationData};
use crate::models::organization::{CreateOrganization, Organization, OrganizationData, UpdateOrg};

pub async fn create(
db: &Surreal<Client>,
id: &str,
org: OrganizationData<'_>,
org: CreateOrganization<'_>,
) -> Result<Option<Organization>> {
Ok(db
.create("organization")
.content(Organization {
id: None,
name: org.name.to_string(),
display_name: org.display_name,
description: org.description,
owners: vec![("account", id).into()],
members: vec![],
creator: id.to_string(),
created_at: chrono::Local::now().naive_local(),
updated_at: chrono::Local::now().naive_local(),
})
.content(Into::<Organization>::into(org))
.await?)
}

Expand All @@ -32,6 +21,60 @@ where
Ok(db.select(("organization", id)).await?)
}

pub async fn update(
db: &Surreal<Client>,
id: &str,
org: OrganizationData<'_>,
) -> Result<Option<Organization>> {
Ok(db
.update(("organization", id))
.merge(Into::<UpdateOrg>::into(org))
.await?)
}

const ADD_MEMBERS_QUERY: &str = r#"
UPDATE type::thing("organization", $id)
SET members = array::union(members, $new_members)
"#;
pub async fn add(
db: &Surreal<Client>,
id: &str,
member: Vec<String>,
) -> Result<Option<Organization>> {
let members_to_add: Vec<Thing> = member
.into_iter()
.map(|id| ("account", id.as_str()).into())
.collect();

Ok(db
.query(ADD_MEMBERS_QUERY)
.bind(("id", id.to_string()))
.bind(("new_members", members_to_add))
.await?
.take(0)?)
}

const REMOVE_MEMBERS_QUERY: &str = r#"
UPDATE type::thing("organization", $id)
SET members = array::complement(members, $new_members)
"#;
pub async fn remove(
db: &Surreal<Client>,
id: &str,
member: Vec<String>,
) -> Result<Option<Organization>> {
let members_to_remove: Vec<Thing> = member
.into_iter()
.map(|id| ("account".to_string(), id).into())
.collect();
Ok(db
.query(REMOVE_MEMBERS_QUERY)
.bind(("id", id.to_string()))
.bind(("new_members", members_to_remove))
.await?
.take(0)?)
}

pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<Option<Organization>> {
Ok(db.delete(("organization", id)).await?)
}
Loading
Loading