create & getall for tags

This commit is contained in:
2026-03-06 15:33:39 +01:00
parent 2ebbc88c0a
commit 9931bbe306
4 changed files with 49 additions and 0 deletions

View File

@@ -33,6 +33,8 @@ pub fn api_router() -> Router {
.route("/api/sessions/{id}", get(sessions::get_by_id))
.route("/api/sessions/{id}/revoke", post(sessions::revoke_by_id))
//
.route("/api/tags", get(tags::get_all))
.route("/api/tags", post(tags::create))
.route("/api/tags/{id}", get(tags::get_by_id))
.route("/api/tags/#{name}", get(tags::get_by_name))
}

View File

@@ -4,6 +4,7 @@ use axum::{
http::HeaderMap,
response::{IntoResponse, Response},
};
use serde::Deserialize;
use uuid::Uuid;
use crate::{
@@ -15,6 +16,11 @@ use crate::{
},
};
pub async fn get_all(headers: HeaderMap) -> Result<Response, CompositeError> {
User::authenticate(&headers)?.required()?;
Ok(Json(Tag::get_all()?).into_response())
}
pub async fn get_by_id(
Path(id): Path<Uuid>,
headers: HeaderMap,
@@ -30,3 +36,15 @@ pub async fn get_by_name(
User::authenticate(&headers)?.required()?;
Ok(Json(Tag::get_by_name(name)?).into_response())
}
#[derive(Deserialize)]
pub struct NewTag {
name: TagName,
}
pub async fn create(
headers: HeaderMap,
Json(form): Json<NewTag>,
) -> Result<Response, CompositeError> {
User::authenticate(&headers)?.required()?;
Ok(Json(Tag::create(form.name)?).into_response())
}

View File

@@ -6,6 +6,7 @@ use axum::{
};
use rusqlite::{
OptionalExtension, Result as RusqliteResult, ToSql,
ffi::SQLITE_CONSTRAINT_UNIQUE,
types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef},
};
use serde::{Deserialize, Serialize};
@@ -20,6 +21,17 @@ pub struct Tag {
}
impl Tag {
pub fn get_all() -> Result<Vec<Tag>, TagError> {
Ok(database::conn()?
.prepare("SELECT id, tagname FROM tags")?
.query_map((), |r| {
Ok(Tag {
id: r.get(0)?,
name: r.get(1)?,
})
})?
.collect::<Result<Vec<Tag>, _>>()?)
}
pub fn get_by_id(id: Uuid) -> Result<Tag, TagError> {
let res = database::conn()?
.prepare("SELECT tagname FROM tags WHERE id = ?1")?
@@ -50,6 +62,13 @@ impl Tag {
None => Err(TagError::NoTagWithName(name)),
}
}
pub fn create(name: TagName) -> Result<Tag, TagError> {
let id = Uuid::now_v7();
database::conn()?
.prepare("INSERT INTO tags(id, tagname) VALUES (?1, ?2)")?
.execute((id, &name))?;
Ok(Tag { id, name })
}
}
#[derive(Debug, thiserror::Error)]
@@ -60,11 +79,19 @@ pub enum TagError {
NoTagWithId(Uuid),
#[error("No tag found with name {0}")]
NoTagWithName(TagName),
#[error("A tag with this name already exists")]
TagAlreadyExists,
#[error("Database error: {0}")]
DatabaseError(#[from] DatabaseError),
}
impl From<rusqlite::Error> for TagError {
fn from(error: rusqlite::Error) -> Self {
if let rusqlite::Error::SqliteFailure(e, Some(msg)) = &error
&& e.extended_code == SQLITE_CONSTRAINT_UNIQUE
&& msg.contains("tagname")
{
return TagError::TagAlreadyExists;
}
TagError::DatabaseError(DatabaseError::from(error))
}
}
@@ -72,6 +99,7 @@ impl IntoResponse for TagError {
fn into_response(self) -> Response {
match self {
Self::DatabaseError(e) => e.into_response(),
Self::TagAlreadyExists => (StatusCode::CONFLICT, self.to_string()).into_response(),
Self::TagNameError(_) => (StatusCode::BAD_REQUEST, self.to_string()).into_response(),
Self::NoTagWithId(_) => (StatusCode::BAD_REQUEST, self.to_string()).into_response(),
Self::NoTagWithName(_) => (StatusCode::BAD_REQUEST, self.to_string()).into_response(),

View File

@@ -11,6 +11,7 @@ pub enum Permission {
// All Users have the right to change their own handle
ChangeOthersHandles,
ManuallyCreateUsers,
CreateTags,
}
impl User {