#[derive(Debug, Clone)]
pub struct ResourceSummary {
pub label: String,
pub iri: String,
pub ark_url: Option<String>,
pub creation_date: Option<String>,
pub last_modified: Option<String>,
pub resource_type: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ResourceVisibility {
Public,
PublicRestricted,
LoggedInUsers,
ProjectMembers,
}
impl ResourceVisibility {
pub fn as_str(&self) -> &'static str {
match self {
ResourceVisibility::Public => "public",
ResourceVisibility::PublicRestricted => "public (restricted view)",
ResourceVisibility::LoggedInUsers => "logged-in users",
ResourceVisibility::ProjectMembers => "project members only",
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ResourceAccess {
RestrictedView,
View,
Edit,
Delete,
Manage,
}
impl ResourceAccess {
pub fn as_str(&self) -> &'static str {
match self {
ResourceAccess::RestrictedView => "restricted view",
ResourceAccess::View => "view",
ResourceAccess::Edit => "edit",
ResourceAccess::Delete => "delete",
ResourceAccess::Manage => "manage",
}
}
}
#[derive(Debug, Clone)]
pub struct ResourceDetail {
pub label: String,
pub iri: String,
pub resource_type: String,
pub ark_url: Option<String>,
pub creation_date: Option<String>,
pub last_modified: Option<String>,
pub attached_project: Option<String>,
pub owner: Option<String>,
pub visibility: Option<ResourceVisibility>,
pub your_access: Option<ResourceAccess>,
pub values: Option<Vec<FieldValues>>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Value {
pub content: ValueContent,
pub comment: Option<String>,
}
impl From<ValueContent> for Value {
fn from(content: ValueContent) -> Self {
Value {
content,
comment: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FieldValues {
pub name: String,
pub label: Option<String>,
pub values: Vec<Value>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ValueContent {
Text(String),
Integer(i64),
Decimal(String),
Boolean(bool),
Date(DateValue),
Time(String),
Uri(String),
Color(String),
Geoname(String),
ListItem {
node_iri: String,
label: Option<String>,
},
Link {
target_iri: String,
target_label: Option<String>,
},
File(FileValue),
Raw {
value_type: String,
text: String,
},
}
impl ValueContent {
pub fn value_type_token(&self) -> &str {
match self {
ValueContent::Text(_) => "text",
ValueContent::Integer(_) => "integer",
ValueContent::Decimal(_) => "decimal",
ValueContent::Boolean(_) => "boolean",
ValueContent::Date(_) => "date",
ValueContent::Time(_) => "time",
ValueContent::Uri(_) => "uri",
ValueContent::Color(_) => "color",
ValueContent::Geoname(_) => "geoname",
ValueContent::ListItem { .. } => "list-item",
ValueContent::Link { .. } => "link",
ValueContent::File(fv) => fv.value_type.as_token(),
ValueContent::Raw { value_type, .. } => value_type.as_str(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DateValue {
pub calendar: String,
pub start: DatePoint,
pub end: DatePoint,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DatePoint {
pub year: Option<i32>,
pub month: Option<u32>,
pub day: Option<u32>,
pub era: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FileValue {
pub value_type: crate::model::resource_type::ValueType,
pub filename: String,
pub url: String,
pub width: Option<u32>,
pub height: Option<u32>,
}
#[derive(Debug, Clone)]
pub struct ResourcePage {
pub resources: Vec<ResourceSummary>,
pub may_have_more_results: bool,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::resource_type::ValueType;
#[test]
fn value_type_token_text() {
assert_eq!(
ValueContent::Text("hello".into()).value_type_token(),
"text"
);
}
#[test]
fn value_type_token_integer() {
assert_eq!(ValueContent::Integer(42).value_type_token(), "integer");
}
#[test]
fn value_type_token_decimal() {
assert_eq!(
ValueContent::Decimal("3.14".into()).value_type_token(),
"decimal"
);
}
#[test]
fn value_type_token_boolean() {
assert_eq!(ValueContent::Boolean(true).value_type_token(), "boolean");
}
#[test]
fn value_type_token_date() {
let dv = DateValue {
calendar: "GREGORIAN".into(),
start: DatePoint {
year: Some(1489),
month: None,
day: None,
era: Some("CE".into()),
},
end: DatePoint {
year: Some(1489),
month: None,
day: None,
era: Some("CE".into()),
},
};
assert_eq!(ValueContent::Date(dv).value_type_token(), "date");
}
#[test]
fn value_type_token_time() {
assert_eq!(
ValueContent::Time("2021-01-01T00:00:00Z".into()).value_type_token(),
"time"
);
}
#[test]
fn value_type_token_uri() {
assert_eq!(
ValueContent::Uri("https://example.com".into()).value_type_token(),
"uri"
);
}
#[test]
fn value_type_token_color() {
assert_eq!(
ValueContent::Color("#ff0000".into()).value_type_token(),
"color"
);
}
#[test]
fn value_type_token_geoname() {
assert_eq!(
ValueContent::Geoname("2661552".into()).value_type_token(),
"geoname"
);
}
#[test]
fn value_type_token_list_item() {
assert_eq!(
ValueContent::ListItem {
node_iri: "http://rdfh.ch/lists/0001/node1".into(),
label: Some("Leaf node".into()),
}
.value_type_token(),
"list-item"
);
}
#[test]
fn value_type_token_link() {
assert_eq!(
ValueContent::Link {
target_iri: "http://rdfh.ch/0803/res1".into(),
target_label: None,
}
.value_type_token(),
"link"
);
}
#[test]
fn value_type_token_file_still_image() {
let fv = FileValue {
value_type: ValueType::StillImage,
filename: "image.jp2".into(),
url: "https://iiif.example.com/image.jp2/full/max/0/default.jpg".into(),
width: Some(1200),
height: Some(800),
};
assert_eq!(ValueContent::File(fv).value_type_token(), "still-image");
}
#[test]
fn value_type_token_file_moving_image() {
let fv = FileValue {
value_type: ValueType::MovingImage,
filename: "video.mp4".into(),
url: "https://example.com/video.mp4".into(),
width: None,
height: None,
};
assert_eq!(ValueContent::File(fv).value_type_token(), "moving-image");
}
#[test]
fn value_type_token_file_audio() {
let fv = FileValue {
value_type: ValueType::Audio,
filename: "sound.wav".into(),
url: "https://example.com/sound.wav".into(),
width: None,
height: None,
};
assert_eq!(ValueContent::File(fv).value_type_token(), "audio");
}
#[test]
fn value_type_token_file_document() {
let fv = FileValue {
value_type: ValueType::Document,
filename: "doc.pdf".into(),
url: "https://example.com/doc.pdf".into(),
width: None,
height: None,
};
assert_eq!(ValueContent::File(fv).value_type_token(), "document");
}
#[test]
fn value_type_token_file_archive() {
let fv = FileValue {
value_type: ValueType::Archive,
filename: "data.zip".into(),
url: "https://example.com/data.zip".into(),
width: None,
height: None,
};
assert_eq!(ValueContent::File(fv).value_type_token(), "archive");
}
#[test]
fn value_type_token_raw() {
assert_eq!(
ValueContent::Raw {
value_type: "interval".into(),
text: "PT10S".into(),
}
.value_type_token(),
"interval"
);
}
#[test]
fn field_values_construction_and_equality() {
let fv = FieldValues {
name: "hasTitle".into(),
label: Some("Title".into()),
values: vec![ValueContent::Text("Incunabula".into()).into()],
};
let cloned = fv.clone();
assert_eq!(fv, cloned);
assert_eq!(fv.name, "hasTitle");
assert_eq!(fv.label.as_deref(), Some("Title"));
assert_eq!(fv.values.len(), 1);
}
#[test]
fn date_value_point_equality() {
let pt = DatePoint {
year: Some(1489),
month: None,
day: None,
era: Some("CE".into()),
};
let dv = DateValue {
calendar: "GREGORIAN".into(),
start: pt.clone(),
end: pt.clone(),
};
assert_eq!(dv.start, dv.end, "single-point date must have start == end");
}
#[test]
fn date_value_range_not_equal() {
let start = DatePoint {
year: Some(1489),
month: None,
day: None,
era: Some("CE".into()),
};
let end = DatePoint {
year: Some(1490),
month: None,
day: None,
era: Some("CE".into()),
};
let dv = DateValue {
calendar: "GREGORIAN".into(),
start: start.clone(),
end: end.clone(),
};
assert_ne!(dv.start, dv.end, "range date must have start != end");
}
}