diff options
Diffstat (limited to 'pkgs/by-name/ba/back/src/web/issue/raw.rs')
-rw-r--r-- | pkgs/by-name/ba/back/src/web/issue/raw.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/pkgs/by-name/ba/back/src/web/issue/raw.rs b/pkgs/by-name/ba/back/src/web/issue/raw.rs new file mode 100644 index 0000000..bb447ec --- /dev/null +++ b/pkgs/by-name/ba/back/src/web/issue/raw.rs @@ -0,0 +1,145 @@ +// Back - An extremely simple git issue tracking system. Inspired by tvix's +// panettone +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This file is part of Back. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/agpl.txt>. + +use gix::{bstr::ByteSlice, Repository}; +use serde::Deserialize; +use serde_json::Value; + +use crate::web::format::BackString; + +use super::{Author, Status}; + +macro_rules! get { + ($value:expr, $name:expr, $type_fun:ident) => { + $value + .get($name) + .expect(concat!( + "Expected field ", + stringify!($name), + "to exists, but was missing." + )) + .$type_fun() + .expect(concat!( + "Failed to interpret field ", + stringify!($name), + " as ", + stringify!($type), + "!" + )) + }; +} + +#[derive(Deserialize)] +pub(super) struct RawIssue { + pub(super) author: RawAuthor, + + #[serde(alias = "ops")] + pub(super) operations: Vec<Operation>, +} + +#[derive(Deserialize, Clone, Default, Debug)] +pub(super) struct RawAuthor { + id: String, +} + +impl RawAuthor { + pub fn load_identity(&self, repo: &Repository) -> Author { + let commit_obj = repo + .find_reference(&format!("refs/identities/{}", self.id)) + .expect("All authors should also have identities") + .peel_to_commit() + .expect("All identities should be commits"); + let tree_obj = repo + .find_tree( + commit_obj + .tree() + .expect("The commit should have an tree associated with it") + .id, + ) + .expect("This should be a tree"); + let data = repo + .find_blob( + tree_obj + .find_entry("version") + .expect("This entry should exist") + .object() + .expect("This should point to a blob entry") + .id, + ) + .expect("This blob should exist") + .data + .clone(); + + let json: Value = serde_json::from_str(data.to_str().expect("This is encoded json")) + .expect("This is valid json"); + + Author { + name: BackString::from(get! {json, "name", as_str}.to_owned()), + email: BackString::from(get! {json, "email", as_str}.to_owned()), + } + } +} + +#[derive(Deserialize)] +#[serde(from = "Value")] +pub(super) enum Operation { + AddComment { + timestamp: u64, + message: String, + // files: Option<String>, TODO + }, + SetStatus { + timestamp: u64, + status: Status, + }, + Create { + timestamp: u64, + title: String, + message: String, + // files: Option<String>, TODO + }, +} + +impl From<u64> for Status { + fn from(value: u64) -> Self { + match value { + 1 => Status::Open, + 2 => Status::Closed, + other => todo!("The status ({other}) is not yet implemented."), + } + } +} + +impl From<Value> for Operation { + fn from(value: Value) -> Self { + match value + .get("type") + .expect("Should exist") + .as_u64() + .expect("This should work") + { + 1 => Self::Create { + title: get! {value, "title", as_str}.to_owned(), + message: get! {value, "message", as_str}.to_owned(), + timestamp: get! {value, "timestamp", as_u64}, + }, + 3 => Self::AddComment { + message: get! {value, "message", as_str}.to_owned(), + timestamp: get! {value, "timestamp", as_u64}, + }, + 4 => Self::SetStatus { + status: Status::from(get! {value, "status", as_u64}), + timestamp: get! {value, "timestamp", as_u64}, + }, + other => todo!("The type ({other}) is not yet added as a a valid operation. It's value is: '{value}''"), + } + } +} |