use derive_builder::Builder;
use reqwest::Method;
use std::borrow::Cow;
use crate::api::{Endpoint, NoPagination, ReturnsJsonResponse};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct RoleEssentials {
pub id: u64,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub inherited: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum IssuesVisibility {
#[serde(rename = "all")]
All,
#[serde(rename = "default")]
AllNonPrivate,
#[serde(rename = "own")]
Own,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum TimeEntriesVisibility {
#[serde(rename = "all")]
All,
#[serde(rename = "own")]
Own,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum UsersVisibility {
#[serde(rename = "all")]
All,
#[serde(rename = "members_of_visible_projects")]
MembersOfVisibleProjects,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize_repr, Deserialize_repr,
)]
#[repr(u8)]
pub enum BuiltinRole {
Custom = 0,
NonMember = 1,
Anonymous = 2,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Role {
pub id: u64,
pub name: String,
pub assignable: bool,
pub issues_visibility: IssuesVisibility,
pub time_entries_visibility: TimeEntriesVisibility,
pub users_visibility: UsersVisibility,
pub permissions: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub position: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub builtin: Option<BuiltinRole>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub settings: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_time_entry_activity_id: Option<u64>,
}
#[derive(Debug, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct ListRoles {
#[builder(default)]
givable: Option<bool>,
}
impl ReturnsJsonResponse for ListRoles {}
impl NoPagination for ListRoles {}
impl ListRoles {
#[must_use]
pub fn builder() -> ListRolesBuilder {
ListRolesBuilder::default()
}
}
impl Endpoint for ListRoles {
fn method(&self) -> Method {
Method::GET
}
fn endpoint(&self) -> Cow<'static, str> {
"roles.json".into()
}
fn parameters(&self) -> crate::api::QueryParams<'_> {
let mut params = crate::api::QueryParams::default();
params.push_opt("givable", self.givable);
params
}
}
#[derive(Debug, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct GetRole {
id: u64,
}
impl ReturnsJsonResponse for GetRole {}
impl NoPagination for GetRole {}
impl GetRole {
#[must_use]
pub fn builder() -> GetRoleBuilder {
GetRoleBuilder::default()
}
}
impl Endpoint for GetRole {
fn method(&self) -> Method {
Method::GET
}
fn endpoint(&self) -> Cow<'static, str> {
format!("roles/{}.json", self.id).into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct RolesWrapper<T> {
pub roles: Vec<T>,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct RoleWrapper<T> {
pub role: T,
}
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
use std::error::Error;
use tracing_test::traced_test;
#[traced_test]
#[test]
fn test_list_roles_no_pagination() -> Result<(), Box<dyn Error>> {
dotenvy::dotenv()?;
let redmine = crate::api::Redmine::from_env(
reqwest::blocking::Client::builder()
.tls_backend_rustls()
.build()?,
)?;
let endpoint = ListRoles::builder().build()?;
redmine.json_response_body::<_, RolesWrapper<RoleEssentials>>(&endpoint)?;
Ok(())
}
#[traced_test]
#[test]
fn test_list_roles_givable_filter() -> Result<(), Box<dyn Error>> {
dotenvy::dotenv()?;
let redmine = crate::api::Redmine::from_env(
reqwest::blocking::Client::builder()
.tls_backend_rustls()
.build()?,
)?;
let endpoint = ListRoles::builder().givable(true).build()?;
redmine.json_response_body::<_, RolesWrapper<RoleEssentials>>(&endpoint)?;
Ok(())
}
#[test]
fn test_get_role() -> Result<(), Box<dyn Error>> {
dotenvy::dotenv()?;
let redmine = crate::api::Redmine::from_env(
reqwest::blocking::Client::builder()
.tls_backend_rustls()
.build()?,
)?;
let endpoint = GetRole::builder().id(8).build()?;
redmine.json_response_body::<_, RoleWrapper<Role>>(&endpoint)?;
Ok(())
}
#[traced_test]
#[test]
fn test_completeness_role_type() -> Result<(), Box<dyn Error>> {
dotenvy::dotenv()?;
let redmine = crate::api::Redmine::from_env(
reqwest::blocking::Client::builder()
.tls_backend_rustls()
.build()?,
)?;
let list_endpoint = ListRoles::builder().build()?;
let RolesWrapper { roles } =
redmine.json_response_body::<_, RolesWrapper<RoleEssentials>>(&list_endpoint)?;
for role in roles {
let endpoint = GetRole::builder().id(role.id).build()?;
let RoleWrapper { role: value } =
redmine.json_response_body::<_, RoleWrapper<serde_json::Value>>(&endpoint)?;
let o: Role = serde_json::from_value(value.clone())?;
let reserialized = serde_json::to_value(o)?;
assert_eq!(value, reserialized);
}
Ok(())
}
}