about summary refs log tree commit diff stats
path: root/pkgs/by-name/ba/back/src/git_bug/issue/operation/mod.rs
blob: 7f861a72dff2724a404dc83a7c9ebcfbe7bde1a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 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 std::convert::Infallible;

use operation_type::OperationType;
use serde::Deserialize;
use serde_json::Value;

use crate::{
    get,
    git_bug::format::{MarkDown, TimeStamp},
};

use super::{entity, label::Label, Status};

pub mod operation_type;

#[derive(Deserialize, Debug)]
#[serde(try_from = "Value")]
pub enum Operation {
    AddComment {
        timestamp: TimeStamp,
        message: MarkDown,
    },
    Create {
        timestamp: TimeStamp,
        title: MarkDown,
        message: MarkDown,
    },
    EditComment {
        timestamp: TimeStamp,
        target: entity::Id,
        message: MarkDown,
    },
    LabelChange {
        timestamp: TimeStamp,
        added: Vec<Label>,
        removed: Vec<Label>,
    },
    SetStatus {
        timestamp: TimeStamp,
        status: Status,
    },
    SetTitle {
        timestamp: TimeStamp,
        title: MarkDown,
        was: MarkDown,
    },

    // These seem to be just weird non-operation, operations.
    // defined in: git-bug/entities/bug/operation.go
    NoOp {},
    SetMetadata {},
}

impl TryFrom<Value> for Operation {
    type Error = Infallible;

    fn try_from(value: Value) -> Result<Self, Self::Error> {
        let operation_type = OperationType::from_json_int(
            value
                .get("type")
                .expect("Should exist")
                .as_u64()
                .expect("This should work"),
        );

        let op = match operation_type {
            OperationType::AddComment => Self::AddComment {
                timestamp: get! {value, "timestamp" },
                message: get! {value, "message"},
            },
            OperationType::Create => Self::Create {
                timestamp: get! {value, "timestamp"},
                title: get! {value, "title"},
                message: get! {value, "message"},
            },
            OperationType::EditComment => Self::EditComment {
                timestamp: get! {value, "timestamp"},
                target: get! {value, "target"},
                message: get! {value, "message"},
            },
            OperationType::LabelChange => Self::LabelChange {
                timestamp: get! {value, "timestamp"},
                added: serde_json::from_value(
                    value
                        .get("added")
                        .expect("This should be available")
                        .to_owned(),
                )
                .expect("This should be parsable"),
                removed: serde_json::from_value(
                    value
                        .get("removed")
                        .expect("This should be available")
                        .to_owned(),
                )
                .expect("This should be parsable"),
            },
            OperationType::SetStatus => Self::SetStatus {
                timestamp: get! {value, "timestamp"},
                status: get! {value, "status"},
            },
            OperationType::SetTitle => Self::SetTitle {
                timestamp: get! {value, "timestamp"},
                title: get! {value, "title"},
                was: get! {value, "was"},
            },
            OperationType::NoOp => Self::NoOp {},
            OperationType::SetMetadata => Self::SetMetadata {},
        };

        Ok(op)
    }
}