use chrono::{DateTime, Utc};
use derive_builder::Builder;
use crate::api::common::{AccessLevel, NameOrId, SortOrder, VisibilityLevel};
use crate::api::endpoint_prelude::*;
use crate::api::ParamValue;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum UserProjectsOrderBy {
Id,
Name,
Path,
#[default]
CreatedAt,
UpdatedAt,
Similarity,
LastActivityAt,
StarCount,
}
impl UserProjectsOrderBy {
fn as_str(self) -> &'static str {
match self {
UserProjectsOrderBy::Id => "id",
UserProjectsOrderBy::Name => "name",
UserProjectsOrderBy::Path => "path",
UserProjectsOrderBy::CreatedAt => "created_at",
UserProjectsOrderBy::UpdatedAt => "updated_at",
UserProjectsOrderBy::Similarity => "similarity",
UserProjectsOrderBy::LastActivityAt => "last_activity_at",
UserProjectsOrderBy::StarCount => "star_count",
}
}
fn use_keyset_pagination(self) -> bool {
matches!(self, Self::Id)
}
}
impl ParamValue<'static> for UserProjectsOrderBy {
fn as_value(&self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[derive(Debug, Clone, Builder)]
#[builder(setter(strip_option))]
pub struct UserProjects<'a> {
#[builder(setter(into))]
user: NameOrId<'a>,
#[builder(default)]
archived: Option<bool>,
#[builder(default)]
visibility: Option<VisibilityLevel>,
#[builder(default)]
order_by: Option<UserProjectsOrderBy>,
#[builder(default)]
sort: Option<SortOrder>,
#[builder(setter(into), default)]
search: Option<Cow<'a, str>>,
#[builder(default)]
simple: Option<bool>,
#[builder(default)]
owned: Option<bool>,
#[builder(default)]
starred: Option<bool>,
#[builder(default)]
with_issues_enabled: Option<bool>,
#[builder(default)]
with_merge_requests_enabled: Option<bool>,
#[builder(setter(into), default)]
with_programming_language: Option<Cow<'a, str>>,
#[builder(default)]
min_access_level: Option<AccessLevel>,
#[builder(default)]
with_custom_attributes: Option<bool>,
#[builder(default)]
id_after: Option<u64>,
#[builder(default)]
id_before: Option<u64>,
#[builder(default)]
membership: Option<bool>,
#[builder(default)]
statistics: Option<bool>,
#[builder(default)]
updated_after: Option<DateTime<Utc>>,
#[builder(default)]
updated_before: Option<DateTime<Utc>>,
}
impl<'a> UserProjects<'a> {
pub fn builder() -> UserProjectsBuilder<'a> {
UserProjectsBuilder::default()
}
}
impl Endpoint for UserProjects<'_> {
fn method(&self) -> Method {
Method::GET
}
fn endpoint(&self) -> Cow<'static, str> {
format!("users/{}/projects", self.user).into()
}
fn parameters(&self) -> QueryParams<'_> {
let mut params = QueryParams::default();
params
.push_opt("archived", self.archived)
.push_opt("visibility", self.visibility)
.push_opt("order_by", self.order_by)
.push_opt("sort", self.sort)
.push_opt("search", self.search.as_ref())
.push_opt("simple", self.simple)
.push_opt("owned", self.owned)
.push_opt("starred", self.starred)
.push_opt("with_issues_enabled", self.with_issues_enabled)
.push_opt(
"with_merge_requests_enabled",
self.with_merge_requests_enabled,
)
.push_opt(
"with_programming_language",
self.with_programming_language.as_ref(),
)
.push_opt(
"min_access_level",
self.min_access_level.map(AccessLevel::as_u64),
)
.push_opt("with_custom_attributes", self.with_custom_attributes)
.push_opt("id_after", self.id_after)
.push_opt("id_before", self.id_before)
.push_opt("membership", self.membership)
.push_opt("statistics", self.statistics)
.push_opt("updated_after", self.updated_after)
.push_opt("updated_before", self.updated_before);
params
}
}
impl Pageable for UserProjects<'_> {
fn use_keyset_pagination(&self) -> bool {
self.order_by.unwrap_or_default().use_keyset_pagination()
}
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use crate::api::common::{AccessLevel, SortOrder, VisibilityLevel};
use crate::api::users::projects::{
UserProjects, UserProjectsBuilderError, UserProjectsOrderBy,
};
use crate::api::{self, Pageable, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
#[test]
fn order_by_default() {
assert_eq!(
UserProjectsOrderBy::default(),
UserProjectsOrderBy::CreatedAt,
);
}
#[test]
fn order_by_as_str() {
let items = &[
(UserProjectsOrderBy::Id, "id"),
(UserProjectsOrderBy::Name, "name"),
(UserProjectsOrderBy::Path, "path"),
(UserProjectsOrderBy::CreatedAt, "created_at"),
(UserProjectsOrderBy::UpdatedAt, "updated_at"),
(UserProjectsOrderBy::Similarity, "similarity"),
(UserProjectsOrderBy::LastActivityAt, "last_activity_at"),
(UserProjectsOrderBy::StarCount, "star_count"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn order_by_use_keyset_pagination() {
let items = &[
(UserProjectsOrderBy::Id, true),
(UserProjectsOrderBy::Name, false),
(UserProjectsOrderBy::Path, false),
(UserProjectsOrderBy::CreatedAt, false),
(UserProjectsOrderBy::UpdatedAt, false),
(UserProjectsOrderBy::Similarity, false),
(UserProjectsOrderBy::LastActivityAt, false),
];
for (i, k) in items {
assert_eq!(i.use_keyset_pagination(), *k);
}
}
#[test]
fn user_is_needed() {
let err = UserProjects::builder().build().unwrap_err();
crate::test::assert_missing_field!(err, UserProjectsBuilderError, "user");
}
#[test]
fn user_is_sufficient() {
UserProjects::builder().user(1).build().unwrap();
}
#[test]
fn endpoint_use_keyset_pagination() {
let items = &[
(UserProjectsOrderBy::Id, true),
(UserProjectsOrderBy::Name, false),
(UserProjectsOrderBy::Path, false),
(UserProjectsOrderBy::CreatedAt, false),
(UserProjectsOrderBy::UpdatedAt, false),
(UserProjectsOrderBy::Similarity, false),
(UserProjectsOrderBy::LastActivityAt, false),
];
for (i, k) in items {
let endpoint = UserProjects::builder()
.user(1)
.order_by(*i)
.build()
.unwrap();
assert_eq!(endpoint.use_keyset_pagination(), *k);
}
}
#[test]
fn endpoint() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder().user("user").build().unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_archived() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("archived", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.archived(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_visibility() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("visibility", "private")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.visibility(VisibilityLevel::Private)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_order_by() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("order_by", "id")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.order_by(UserProjectsOrderBy::Id)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_sort() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("sort", "asc")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.sort(SortOrder::Ascending)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_search() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("search", "name")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.search("name")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_simple() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("simple", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.simple(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_owned() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("owned", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.owned(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_starred() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("starred", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.starred(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_with_issues_enabled() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("with_issues_enabled", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.with_issues_enabled(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_with_merge_requests_enabled() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("with_merge_requests_enabled", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.with_merge_requests_enabled(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_with_programming_language() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("with_programming_language", "rust")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.with_programming_language("rust")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_min_access_level() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("min_access_level", "30")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.min_access_level(AccessLevel::Developer)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_with_custom_attributes() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("with_custom_attributes", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.with_custom_attributes(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_id_after() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("id_after", "100")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.id_after(100)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_id_before() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("id_before", "200")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.id_before(200)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_membership() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("membership", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.membership(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_statistics() {
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("statistics", "true")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.statistics(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_updated_after() {
let time = Utc.with_ymd_and_hms(2023, 10, 20, 5, 0, 0).unwrap();
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("updated_after", "2023-10-20T05:00:00Z")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.updated_after(time)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_updated_before() {
let time = Utc.with_ymd_and_hms(2023, 10, 21, 15, 30, 0).unwrap();
let endpoint = ExpectedUrl::builder()
.endpoint("users/user/projects")
.add_query_params(&[("updated_before", "2023-10-21T15:30:00Z")])
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = UserProjects::builder()
.user("user")
.updated_before(time)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}