Skip to main content

bugzilla_query/
bug_model.rs

1/*
2Copyright 2022 Marek Suchánek <msuchane@redhat.com>
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17//! This module replicates the fields in a Bugzilla bug as strongly typed structs.
18//! Any extra fields that come from a custom Bugzilla configuration are captured
19//! in the `extra` hash map in the parent struct.
20
21use std::fmt;
22
23use chrono::{DateTime, NaiveDate, Utc};
24use serde::Deserialize;
25use serde_json::Value;
26
27/// The response from Bugzilla, which includes the list of requested bugs
28/// and some additional metadata.
29#[derive(Clone, Debug, Deserialize)]
30pub struct Response {
31    pub offset: Option<u32>,
32    pub limit: Option<String>,
33    pub total_matches: Option<u32>,
34    pub bugs: Vec<Bug>,
35    #[serde(flatten)]
36    pub extra: Value,
37}
38
39/// An error report from Bugzilla.
40#[derive(Clone, Debug, Deserialize)]
41pub struct BugzillaError {
42    pub error: bool,
43    pub message: String,
44    pub code: i32,
45    #[serde(flatten)]
46    pub extra: Value,
47}
48
49/// Certain fields can appear as a single, optional string or a list of strings based on the Bugzilla instance and its configuration.
50#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
51#[serde(untagged)]
52pub enum OneOrMany {
53    None,
54    One(String),
55    Many(Vec<String>),
56}
57
58impl OneOrMany {
59    /// Regardless of the Bugzilla instance configuration, list all items in a vector: empty, one item, or more items.
60    pub fn into_vec(self) -> Vec<String> {
61        match self {
62            Self::None => Vec::new(),
63            Self::One(s) => vec![s],
64            Self::Many(v) => v,
65        }
66    }
67}
68
69/// Some Bugzilla instances set the component as a single string, some use a list of components.
70pub type Component = OneOrMany;
71
72/// Some Bugzilla instances set the version as a single string, some use a list of versions.
73pub type Version = OneOrMany;
74
75/// Some Bugzilla instances set the alias as a single string, some use a list of aliases.
76pub type Alias = OneOrMany;
77
78/// The representation of a single Bugzilla bug with all its fields.
79#[allow(clippy::struct_excessive_bools)]
80#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
81pub struct Bug {
82    pub alias: Alias,
83    pub op_sys: String,
84    pub classification: String,
85    pub id: i32,
86    pub url: String,
87    pub creator: String,
88    pub creator_detail: User,
89    pub summary: String,
90    pub status: String,
91    pub estimated_time: Option<i64>,
92    pub target_milestone: String,
93    pub cc: Vec<String>,
94    pub cc_detail: Vec<User>,
95    pub is_open: bool,
96    pub is_creator_accessible: bool,
97    pub docs_contact: Option<String>,
98    pub docs_contact_detail: Option<User>,
99    pub assigned_to: String,
100    pub assigned_to_detail: User,
101    pub resolution: String,
102    pub severity: String,
103    pub product: String,
104    pub platform: String,
105    pub last_change_time: DateTime<Utc>,
106    pub remaining_time: Option<i64>,
107    pub priority: String,
108    pub whiteboard: String,
109    pub creation_time: DateTime<Utc>,
110    pub is_confirmed: bool,
111    pub qa_contact: String,
112    pub qa_contact_detail: Option<User>,
113    pub dupe_of: Option<i32>,
114    pub target_release: Option<Version>,
115    pub actual_time: Option<i64>,
116    pub component: Component,
117    pub is_cc_accessible: bool,
118    pub version: Version,
119    pub keywords: Vec<String>,
120    pub depends_on: Vec<i32>,
121    pub blocks: Vec<i32>,
122    pub see_also: Option<Vec<String>>,
123    pub groups: Vec<String>,
124    /// Bugzilla stores `deadline` only as `YYYY-MM-DD`, so it can't deserialize to full `DateTime`.
125    pub deadline: Option<NaiveDate>,
126    pub update_token: Option<String>,
127    pub work_time: Option<i64>,
128    // Not part of the default response:
129    pub flags: Option<Vec<Flag>>,
130    pub tags: Option<Vec<String>>,
131    pub dependent_products: Option<Vec<String>>,
132    #[serde(flatten)]
133    pub extra: Value,
134}
135
136/// The representation of a Bugzilla user account.
137#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
138pub struct User {
139    pub email: String,
140    pub id: i32,
141    pub name: String,
142    pub real_name: String,
143    #[serde(flatten)]
144    pub extra: Value,
145}
146
147/// The representation of a flag in a bug.
148/// A flag resembles a hash map entry, where `flag.name` is the key
149/// and `flag.status` is the value.
150#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
151pub struct Flag {
152    pub id: i32,
153    pub type_id: i32,
154    pub creation_date: DateTime<Utc>,
155    pub modification_date: DateTime<Utc>,
156    pub name: String,
157    pub status: String,
158    pub setter: String,
159    pub requestee: Option<String>,
160    #[serde(flatten)]
161    pub extra: Value,
162}
163
164impl fmt::Display for Flag {
165    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166        // Displays the flag in the format of `name: value`.
167        write!(f, "{}: {}", self.name, self.status)
168    }
169}