Skip to content

Commit

Permalink
feat(api): add endpoint for adding members to kits
Browse files Browse the repository at this point in the history
  • Loading branch information
tomcur committed Jan 16, 2024
1 parent 0638c7e commit fe8660f
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
1 change: 1 addition & 0 deletions astroplant-api/src/bin/astroplant-api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ async fn main() -> anyhow::Result<()> {
.route("/kits/:kit_serial", patch(kit::patch_kit))
.route("/kits/:kit_serial", delete(kit::delete_kit))
.route("/kits/:kit_serial/members", get(kit::get_members))
.route("/kits/:kit_serial/members", post(kit::add_member))
.route(
"/kits/:kit_serial/member-suggestions",
get(kit::get_member_suggestions),
Expand Down
85 changes: 85 additions & 0 deletions astroplant-api/src/controllers/kit/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use axum::extract::Path;
use axum::Extension;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::authorization::KitAction;
Expand Down Expand Up @@ -291,6 +292,90 @@ pub async fn get_members(
Ok(ResponseBuilder::ok().body(v))
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddMember {
username: String,
access_configure: bool,
access_super: bool,
}

/// Handles the `POST /kits/{kitSerial}/members` route.
pub async fn add_member(
Extension(pg): Extension<PgPool>,
Path(kit_serial): Path<String>,
user_id: Option<models::UserId>,
crate::extract::Json(member): crate::extract::Json<AddMember>,
) -> Result<Response, Problem> {
let action = if member.access_super {
crate::authorization::KitAction::EditSuperMembers
} else {
crate::authorization::KitAction::EditMembers
};
let (_, _, kit) =
helpers::fut_kit_permission_or_forbidden(pg.clone(), user_id, kit_serial, action).await?;

let conn = pg.get().await?;

let kit_id = kit.id;
let membership = conn
.interact_flatten_err(move |conn| {
use diesel::prelude::*;
use schema::kit_memberships;
use schema::users;

conn.build_transaction().serializable().run(move |conn| {
let user: User = users::table
.filter(users::username.eq(&member.username))
.first(conn)?;

let existing_membership: Option<KitMembership> = kit_memberships::table
.filter(kit_memberships::kit_id.eq(kit_id))
.filter(kit_memberships::user_id.eq(user.id))
.get_result(conn)
.optional()?;

if let Some(existing_membership) = existing_membership {
// This membership already exists, do nothing
return Ok::<_, Problem>(
views::KitMembership::from(existing_membership)
.with_user(views::User::from(user))
.with_kit(views::Kit::from(kit)),
);
}

#[derive(Insertable)]
#[diesel(table_name = kit_memberships)]
struct NewKitMembership {
user_id: i32,
kit_id: i32,
access_super: bool,
access_configure: bool,
datetime_linked: DateTime<Utc>,
}

let membership = NewKitMembership {
user_id: user.id,
kit_id,
access_super: member.access_super,
access_configure: member.access_configure,
datetime_linked: Utc::now(),
};
let membership: KitMembership = membership
.insert_into(kit_memberships::table)
.get_result(conn)?;

Ok::<_, Problem>(
views::KitMembership::from(membership)
.with_user(views::User::from(user))
.with_kit(views::Kit::from(kit)),
)
})
})
.await?;

Ok(ResponseBuilder::ok().body(membership))
}

#[derive(Deserialize)]
pub struct MemberSuggestions {
Expand Down
49 changes: 49 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,42 @@ paths:
description: The serial of the kit to get the members of.
schema:
type: string
responses:
'200':
description: The kit's members.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/KitMembership"
'401':
$ref: "#/components/responses/ErrorUnauthorized"
'429':
$ref: "#/components/responses/ErrorRateLimit"
'500':
$ref: "#/components/responses/ErrorInternalServer"
post:
summary: Add a membership to a kit.
operationId: addKitMember
security:
- bearerAuth: []
tags:
- kits
parameters:
- name: kitSerial
in: path
required: true
description: The serial of the kit to add a membership to.
schema:
type: string
requestBody:
description: The membership to add.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NewKitMembership"
responses:
'200':
description: The kit's members.
Expand Down Expand Up @@ -1406,6 +1442,19 @@ components:
datetimeLinked:
type: string
format: "date-time"
NewKitMembership:
type: object
required:
- username
- accessConfigure
- accessSuper
properties:
username:
type: string
accessConfigure:
type: boolean
accessSuper:
type: boolean
PatchKitMembership:
type: object
properties:
Expand Down

0 comments on commit fe8660f

Please sign in to comment.