shared/domain/resource/
curation.rs

1//! Types for Resource short codes for sharing
2use chrono::{DateTime, Utc};
3use macros::make_path_parts;
4use serde::{Deserialize, Serialize};
5
6use crate::api::endpoints::PathPart;
7
8use super::{report::ResourceReport, ResourceId, UserId};
9
10wrap_uuid! {
11    /// Wrapper type around [`Uuid`](Uuid), represents the ID of a curation comment.
12    pub struct CommentId
13}
14
15make_path_parts!(ResourceCurationPath => "/v1/resource/{}/curation" => ResourceId);
16
17/// Curation data for Resources
18#[derive(Serialize, Deserialize, Clone, Debug)]
19#[serde(rename_all = "camelCase")]
20pub struct ResourceCurationData {
21    /// Resource ID for curation
22    pub resource_id: ResourceId,
23
24    /// Fields curated by Admin
25    pub fields_done: ResourceCurationFieldsDone,
26
27    /// Status for curation
28    pub curation_status: ResourceCurationStatus,
29
30    /// Comments from curator (not updatable)
31    pub comments: Vec<ResourceCurationComment>,
32
33    /// Reports for Resource from users (not updatable)
34    pub reports: Vec<ResourceReport>,
35}
36
37/// Curation fields that have been completed
38///
39/// Authorization:
40/// Admin
41#[derive(Serialize, Deserialize, Clone, Debug)]
42#[serde(rename_all = "camelCase")]
43pub struct ResourceCurationFieldsDone {
44    /// Display name of Resource
45    pub display_name: bool,
46
47    /// Language of Resource
48    pub language: bool,
49
50    /// Categories of Resource
51    pub categories: bool,
52
53    /// Descriptions of Resource
54    pub description: bool,
55
56    /// Age ranges of Resource
57    pub age_ranges: bool,
58
59    /// Affiliations of Resource
60    pub affiliations: bool,
61
62    /// Addtional resources of Resource
63    pub additional_resources: bool,
64}
65
66impl Default for ResourceCurationFieldsDone {
67    fn default() -> Self {
68        Self {
69            display_name: false,
70            language: false,
71            categories: false,
72            description: false,
73            age_ranges: false,
74            affiliations: false,
75            additional_resources: false,
76        }
77    }
78}
79
80/// Status of Curation
81#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Debug)]
82#[cfg_attr(feature = "backend", derive(sqlx::Type))]
83#[serde(rename_all = "camelCase")]
84#[repr(i16)]
85pub enum ResourceCurationStatus {
86    /// Resources first curation
87    New = 0,
88
89    /// Resource has been updated by user
90    NewVersion = 1,
91
92    /// Admin is reviewing Resource
93    InProgress = 2,
94
95    /// Curation of Resource completed
96    Done = 3,
97}
98
99impl Default for ResourceCurationStatus {
100    fn default() -> Self {
101        Self::New
102    }
103}
104
105make_path_parts!(ResourceCurationUpdatePath => "/v1/resource/{}/curation" => ResourceId);
106
107/// Curation data for ResourceS
108#[derive(Serialize, Deserialize, Clone, Debug, Default)]
109#[serde(rename_all = "camelCase")]
110pub struct ResourceCurationUpdateRequest {
111    /// Display name of Resource
112    #[serde(default)]
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub display_name: Option<bool>,
115
116    /// Language of Resource
117    #[serde(default)]
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub language: Option<bool>,
120
121    /// Categories of Resource
122    #[serde(default)]
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub categories: Option<bool>,
125
126    /// Descriptions of Resource
127    #[serde(default)]
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub description: Option<bool>,
130
131    /// Age ranges of Resource
132    #[serde(default)]
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub age_ranges: Option<bool>,
135
136    /// Affiliations of Resource
137    #[serde(default)]
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub affiliations: Option<bool>,
140
141    /// Addtional resources of Resource
142    #[serde(default)]
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub additional_resources: Option<bool>,
145
146    /// Curation status of Resource
147    #[serde(default)]
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub curation_status: Option<ResourceCurationStatus>,
150}
151
152make_path_parts!(ResourceCurationCommentCreatePath => "/v1/resource/{}/curation/comment" => ResourceId);
153
154/// Curation data for ResourceS
155#[derive(Serialize, Deserialize, Clone, Debug)]
156#[cfg_attr(feature = "backend", derive(sqlx::Type))]
157#[serde(rename_all = "camelCase")]
158pub struct ResourceCurationComment {
159    /// Comment ID
160    pub id: CommentId,
161
162    /// Resource ID for comment
163    pub resource_id: ResourceId,
164
165    /// Comment
166    pub value: String,
167
168    /// When comment was submitted
169    pub created_at: DateTime<Utc>,
170
171    /// ID of commenter
172    pub author_id: UserId,
173}
174
175/// Request to comment on Resource
176#[derive(Serialize, Deserialize, Debug)]
177#[serde(rename_all = "camelCase")]
178pub struct ResourceCurationCommentRequest {
179    /// Display name of Resource
180    pub value: String,
181}
182
183make_path_parts!(ResourceCurationCommentGetPath => "/v1/resource/{}/curation/comment/{}" => ResourceId, CommentId);
184
185/// Curation data for ResourceS
186#[derive(Serialize, Deserialize, Debug)]
187#[serde(rename_all = "camelCase")]
188pub struct ResourceCurationCommentResponse {
189    /// ID of comment
190    pub id: CommentId,
191
192    /// ID of Resource
193    pub resource_id: ResourceId,
194
195    /// Curator comment
196    pub value: String,
197
198    /// When comment was submitted
199    pub created_at: Option<DateTime<Utc>>,
200
201    /// ID of commenter
202    pub author_id: UserId,
203
204    /// Name of commenter
205    pub author_name: String,
206}