dailp/
person.rs

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
use std::{fmt, str::FromStr};

use crate::{user::User, Database, PersonFullName};
use async_graphql::{SimpleObject, Union};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, Type};

/// Record for a DAILP admin
#[derive(Clone, Debug, Serialize, Deserialize, async_graphql::SimpleObject)]
pub struct Admin {
    /// Inherits from User
    pub user: User,
}

/// An individual or organization that contributed to the creation or analysis
/// of a particular document or source. Each contributor has a name and a role
/// that specifies the type of their contributions.
#[derive(Clone, Debug, Serialize, Deserialize, async_graphql::SimpleObject, PartialEq, Eq)]
#[graphql(complex)]
pub struct Contributor {
    /// UUID of the contributor
    pub id: uuid::Uuid,
    /// Full name of the contributor
    pub name: String,
    /// The role that defines most of their contributions to the associated item
    pub role: Option<ContributorRole>,
}

/// Input Object for Contributor
#[derive(async_graphql::InputObject, Clone, Debug, Serialize, Deserialize)]
pub struct ContributorInput {
    /// Full name of the contributor
    pub name: String,
    /// The role that defines most of their contributions to the associated item
    pub role: String,
}

#[async_graphql::ComplexObject]
impl Contributor {
    async fn details(
        &self,
        ctx: &async_graphql::Context<'_>,
    ) -> async_graphql::FieldResult<Option<ContributorDetails>> {
        use async_graphql::dataloader::*;
        Ok(ctx
            .data::<DataLoader<Database>>()?
            .load_one(PersonFullName(self.name.clone()))
            .await?)
    }
}

/// Basic personal details of an individual contributor, which can be retrieved
/// from a particular instance of [`Contributor`].
///
/// They may have transcribed a handwritten manuscript, translated it into
/// English, or analyzed it for linguistic information.
/// This information can be used to track who contributed to the development of
/// each individual document, and track contributions to the archive as a whole.
#[derive(async_graphql::SimpleObject, Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ContributorDetails {
    /// Full name of this person, this exact string must be used to identify
    /// them elsewhere, like in the attribution for a particular document.
    pub full_name: String,
    /// Alternate name of this person, may be in a different language or writing
    /// system. Used only for descriptive purposes.
    pub alternate_name: Option<String>,
    /// The optional date that this contributor was born on.
    pub birth_date: Option<crate::Date>,
    /// Whether or not the contributor's profile is linked to their contributions
    pub is_visible: bool,
}

/// A contributor can have to any number of roles, which define most of their
/// contributions to the associated item (add or revise as needed)
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, async_graphql::Enum, Type)]
#[sqlx(type_name = "contributor_role")]
#[sqlx(rename_all = "snake_case")]
pub enum ContributorRole {
    /// Typed or transcribed handwritten materials
    Transcriber,
    /// Translated text into another language
    Translator,
    /// Added linguistic, cultural, etc. annotations
    Annotator,
    /// Provided cultural context for a document
    CulturalAdvisor,
    /// Author of a document
    Author,
    /// Edited a document
    Editor,
}

impl From<String> for ContributorRole {
    //type Err = String;

    fn from(s: String) -> Self {
        match s.to_lowercase().as_str() {
            "transcriber" => ContributorRole::Transcriber,
            "translator" => ContributorRole::Translator,
            "annotator" => ContributorRole::Annotator,
            "culturaladvisor" => ContributorRole::CulturalAdvisor,
            "author" => ContributorRole::Author,
            "editor" => ContributorRole::Editor,
            other => panic!("{} is not a valid contributor role", s),
        }
    }
}

impl fmt::Display for ContributorRole {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            ContributorRole::Transcriber => "Transcriber",
            ContributorRole::Translator => "Translator",
            ContributorRole::Annotator => "Annotator",
            ContributorRole::CulturalAdvisor => "CulturalAdvisor",
            ContributorRole::Author => "Author",
            ContributorRole::Editor => "Editor",
        };
        write!(f, "{}", s)
    }
}

impl ContributorRole {
    /// Attempts to parse a string into a ContributorRole, returning None if parsing fails
    pub fn from_option_str(s: &str) -> Option<Self> {
        // TODO: Make ContributorRole::from return a ContributorRole instead of a panic
        Some(ContributorRole::from(s.to_string()))
    }

    /// Converts a ContributorRole into its string representation
    pub fn to_option_string(role: &Option<ContributorRole>) -> Option<String> {
        role.as_ref().map(|r| r.to_string())
    }
}

#[derive(async_graphql::InputObject, Debug, Clone)]
pub struct ContributorAttributionInput {
    pub name: String,
    pub role: Option<ContributorRole>,
}

/// The creator of a document
#[derive(async_graphql::SimpleObject, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[graphql(complex)]
pub struct Creator {
    /// UUID of the creator
    pub id: uuid::Uuid,
    /// Name of the creator
    pub name: String,
}

// For updating creators
#[derive(async_graphql::InputObject, Clone, Debug)]
pub struct CreatorUpdate {
    /// UUID for the creator
    pub id: uuid::Uuid,
    /// Name of the creator
    pub name: String,
}

#[async_graphql::ComplexObject]
impl Creator {}

/// Attribution for a particular source, whether an institution or an individual.
/// Most commonly, this will represent the details of a library or archive that
/// houses documents used elsewhere.
#[derive(async_graphql::SimpleObject, Clone, Debug, Serialize, Deserialize)]
pub struct SourceAttribution {
    /// Name of the source, i.e. "The Newberry Library"
    pub name: String,
    /// URL of this source's homepage, i.e. "https://www.newberry.org/"
    pub link: String,
}