From d084d8bbc5c1dc5da2998d9a979ef68008b37507 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 26 Sep 2021 16:36:34 +0100 Subject: [PATCH] Dynamically load organisations from API --- chartered-db/src/organisations.rs | 31 +++++++++++++++++++++++++++++++ chartered-web/src/main.rs | 4 ++++ chartered-frontend/src/pages/crate/OrganisationView.tsx | 50 +++++++++++++++++++++++++++++++------------------- chartered-frontend/src/pages/organisations/ListOrganisations.tsx | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- chartered-web/src/endpoints/web_api/organisations/list.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ chartered-web/src/endpoints/web_api/organisations/mod.rs | 2 ++ 6 files changed, 167 insertions(+), 64 deletions(-) diff --git a/chartered-db/src/organisations.rs b/chartered-db/src/organisations.rs index b8b774c..aadf4b9 100644 --- a/chartered-db/src/organisations.rs +++ a/chartered-db/src/organisations.rs @@ -1,4 +1,6 @@ -use crate::{crates::Crate, permissions::UserPermission, users::User, Error}; +use crate::{ + crates::Crate, permissions::UserPermission, users::User, BitwiseExpressionMethods, Error, +}; use super::{ schema::{organisations, user_organisation_permissions, users}, @@ -19,6 +21,33 @@ } impl Organisation { + pub async fn list(conn: ConnectionPool, requesting_user_id: i32) -> Result> { + use user_organisation_permissions::dsl::permissions; + + tokio::task::spawn_blocking(move || { + let conn = conn.get()?; + + organisations::table + .inner_join( + user_organisation_permissions::table.on(user_organisation_permissions::user_id + .eq(requesting_user_id) + .and( + user_organisation_permissions::organisation_id + .eq(organisations::dsl::id), + )), + ) + .filter( + permissions + .bitwise_and(UserPermission::VISIBLE.bits()) + .eq(UserPermission::VISIBLE.bits()), + ) + .select(organisations::all_columns) + .load(&conn) + .map_err(Into::into) + }) + .await? + } + pub async fn find_by_name( conn: ConnectionPool, requesting_user_id: i32, diff --git a/chartered-web/src/main.rs b/chartered-web/src/main.rs index 1b46c75..21ea132 100644 --- a/chartered-web/src/main.rs +++ a/chartered-web/src/main.rs @@ -72,6 +72,10 @@ let web_authenticated = axum_box_after_every_route!(Router::new() // organisations endpoints .route( + "/organisations", + get(endpoints::web_api::organisations::list) + ) + .route( "/organisations/:org", get(endpoints::web_api::organisations::info) ) diff --git a/chartered-frontend/src/pages/crate/OrganisationView.tsx b/chartered-frontend/src/pages/crate/OrganisationView.tsx index 935c1e6..1e69361 100644 --- a/chartered-frontend/src/pages/crate/OrganisationView.tsx +++ a/chartered-frontend/src/pages/crate/OrganisationView.tsx @@ -113,30 +113,24 @@ -
-
- {activeTab == "crates" ? ( - - ) : ( - <> - )} - {activeTab == "members" ? ( - setReload(reload + 1)} - /> - ) : ( - <> - )} -
-
+ {activeTab == "crates" ? ( + + ) : ( + <> + )} + {activeTab == "members" ? ( + setReload(reload + 1)} + /> + ) : ( + <> + )} @@ -152,6 +146,14 @@ organisation: string; crates: Crate[]; }) { + if (crates.length === 0) { + return ( +
+ This organisation doesn't have any crates yet. +
+ ); + } + return (
diff --git a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx b/chartered-frontend/src/pages/organisations/ListOrganisations.tsx index e3be293..d878cc7 100644 --- a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx +++ a/chartered-frontend/src/pages/organisations/ListOrganisations.tsx @@ -1,24 +1,35 @@ import React = require("react"); -import { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import Nav from "../../sections/Nav"; import { useAuth } from "../../useAuth"; -import { useAuthenticatedRequest, authenticatedEndpoint } from "../../util"; - -import { Plus, Trash } from "react-bootstrap-icons"; -import { - Button, - Dropdown, - Modal, - OverlayTrigger, - Tooltip, -} from "react-bootstrap"; -import HumanTime from "react-human-time"; +import { useAuthenticatedRequest } from "../../util"; import ErrorPage from "../ErrorPage"; import Loading from "../Loading"; +interface Response { + organisations: ResponseOrganisations[]; +} + +interface ResponseOrganisations { + name: string; + description: string; +} + export default function ListOrganisations() { + const auth = useAuth(); + + const { response: list, error } = useAuthenticatedRequest({ + auth, + endpoint: "organisations", + }); + + if (error) { + return ; + } else if (!list) { + return ; + } + return (
- - - - - - - - - -
- - - core - - - - - - Members - Crates - - -
+ {list.organisations.length === 0 ? ( +
+ You don't belong to any organisations yet. +
+ ) : ( + + + {list.organisations.map((v, i) => ( + + + + + + ))} + +
+ + +
+ {v.name} +
+
+ + {v.description} + +
+
+ )}
diff --git a/chartered-web/src/endpoints/web_api/organisations/list.rs b/chartered-web/src/endpoints/web_api/organisations/list.rs new file mode 100644 index 0000000..cf973cf 100644 --- /dev/null +++ a/chartered-web/src/endpoints/web_api/organisations/list.rs @@ -1,0 +1,51 @@ +use axum::{extract, Json}; +use chartered_db::{ + organisations::Organisation, users::User, ConnectionPool, +}; +use serde::Serialize; +use std::sync::Arc; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("{0}")] + Database(#[from] chartered_db::Error), +} + +impl Error { + pub fn status_code(&self) -> axum::http::StatusCode { + match self { + Self::Database(e) => e.status_code(), + } + } +} + +define_error_response!(Error); + +pub async fn handle_get( + extract::Extension(db): extract::Extension, + extract::Extension(user): extract::Extension>, +) -> Result, Error> { + let organisations = Organisation::list(db.clone(), user.id).await?; + + Ok(Json(Response { + organisations: organisations + .into_iter() + .map(|v| ResponseOrganisation { + name: v.name, + description: v.description, + }) + .collect(), + })) +} + +#[derive(Serialize)] +pub struct Response { + organisations: Vec, +} + +#[derive(Serialize)] +pub struct ResponseOrganisation { + name: String, + description: String, +} diff --git a/chartered-web/src/endpoints/web_api/organisations/mod.rs b/chartered-web/src/endpoints/web_api/organisations/mod.rs index b5ec7cc..5a50049 100644 --- a/chartered-web/src/endpoints/web_api/organisations/mod.rs +++ a/chartered-web/src/endpoints/web_api/organisations/mod.rs @@ -1,7 +1,9 @@ mod info; +mod list; mod members; pub use info::handle_get as info; +pub use list::handle_get as list; pub use members::{ handle_delete as delete_member, handle_patch as update_member, handle_put as insert_member, }; -- rgit 0.1.3