Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Group & GroupAuditLogs model & query #7

Merged
merged 8 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ serde = { version = "1", features = ["derive"] }
serde_with = { version = "3", features = ["time_0_3"] }
time = { version = "0.3", default-features = false, features = ["macros", "serde-well-known"] }
serde_json = { version = "1" }
strum = { version = "0.25", features = ["derive"] }
strum = { version = "0.26", features = ["derive"] }

# API client specifics
racal = "0.3"
Expand All @@ -40,7 +40,7 @@ percent-encoding = { version = "2", optional = true }
base64 = { version = "0.21", optional = true }

async-trait = { version = "0.1", optional = true }
# either = { version = "1", features = ["serde"] }
either = { version = "1", features = ["serde"] }
url = { version = "2", features = ["serde"] }
[dependencies.reqwest]
optional = true
Expand Down
20 changes: 12 additions & 8 deletions src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ macro_rules! add_id {
}

add_id!(Avatar);
add_id!(User);
add_id!(Group);
add_id!(Instance);
add_id!(World);
add_id!(UnityPackage);
add_id!(User);
add_id!(World);

/// Offline or the id of the world or whatever type T is
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
Expand Down Expand Up @@ -137,14 +138,16 @@ impl<T> OfflineOrPrivateOr<T> {
pub enum Any {
/// An avatar ID
Avatar(Avatar),
/// An user ID
User(User),
/// An group ID
Group(Group),
/// An instance ID
Instance(Instance),
/// A world ID
World(World),
/// An ID for an Unity package
UnityPackage(UnityPackage),
/// An user ID
User(User),
/// A world ID
World(World),
}

impl AsRef<str> for Any {
Expand All @@ -153,10 +156,11 @@ impl AsRef<str> for Any {
fn as_ref(&self) -> &str {
match self {
Self::Avatar(v) => v.as_ref(),
Self::User(v) => v.as_ref(),
Self::Group(v) => v.as_ref(),
Self::Instance(v) => v.as_ref(),
Self::World(v) => v.as_ref(),
Self::UnityPackage(v) => v.as_ref(),
Self::User(v) => v.as_ref(),
Self::World(v) => v.as_ref(),
}
}
}
Expand Down
136 changes: 136 additions & 0 deletions src/model/groups.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use either::Either;
use serde::{Deserialize, Serialize};

use crate::id::User;

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Details about a VRC group
pub struct Group {
/// The unique identifier for the group.
pub id: String,
/// The name of the group.
pub name: String,
/// The short code associated with the group.
pub short_code: String,
/// The discriminator for the group.
pub discriminator: String,
/// The description of the group.
pub description: String,
/// The unique identifier for the group's icon.
pub icon_id: String,
/// The URL of the group's icon.
pub icon_url: String,
/// The unique identifier for the group's banner.
pub banner_id: String,
/// The URL of the group's banner.
pub banner_url: String,
/// The privacy setting of the group.
pub privacy: String,
/// The unique identifier of the owner of the group.
pub owner_id: String,
/// The rules associated with the group.
pub rules: String,
/// The list of links associated with the group.
pub links: Vec<String>,
/// The list of languages associated with the group.
pub languages: Vec<String>,
/// The count of members in the group.
pub member_count: i64,
/// The times tamp when the member count was last synchronized.
pub member_count_synced_at: String,
/// Indicates whether the group is verified.
pub is_verified: bool,
/// The join state of the group.
pub join_state: String,
// pub tags: Vec<Value>,
// pub galleries: Vec<Value>,
/// The time stamp when the group was created.
pub created_at: String,
/// The count of online members in the group.
pub online_member_count: i64,
Comment on lines +39 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...I guess it indeed is better to support a case where the member counts are negative for whatever reason, even though on first thought it seemed wrong 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol I think that's just what Json -> Serde defaulted to

/// The membership status of the user.
pub membership_status: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents a collection of group audit logs.
pub struct GroupAuditLogs {
/// The list of group audit logs.
pub results: Vec<GroupAuditLog>,
/// The total count of audit logs.
pub total_count: usize,
/// Indicates whether there are more audit logs.
pub has_next: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents a single group audit log entry.
pub struct GroupAuditLog {
/// The unique identifier for the audit log entry.
pub id: String,
/// The time stamp when the audit log entry was created.
#[serde(rename = "created_at")]
pub created_at: String,
/// The unique identifier of the group associated with the audit log.
pub group_id: String,
/// The unique identifier of the actor who performed the action.
pub actor_id: User,
/// The display name of the actor.
pub actor_displayname: Option<String>,
/// The unique identifier of the target of the action.
pub target_id: Option<User>,
/// The type of event captured in the audit log.
pub event_type: String,
/// The description of the event captured in the audit log.
pub description: String,
/// Additional data associated with the audit log entry.
pub data: Data,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents additional data associated with a group audit log entry.
pub struct Data {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is just re-exported from vrc::model, should be called GroupAuuditLogData or something similar instead of just Data.

/// The description change associated with the audit log entry.
#[serde(default, with = "either::serde_untagged_optional")]
pub description: Option<Either<DescriptionChange, String>>,
/// The join state change associated with the audit log entry.
#[serde(default, with = "either::serde_untagged_optional")]
pub join_state: Option<Either<JoinStateChange, String>>,
/// The order change associated with the audit log entry.
#[serde(default, with = "either::serde_untagged_optional")]
pub order: Option<Either<OrderChange, u32>>,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents a change in description associated with a group audit log entry.
pub struct DescriptionChange {
/// The old description before the change.
pub old: String,
/// The new description after the change.
pub new: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents a change in join state associated with a group audit log entry.
pub struct JoinStateChange {
/// The old join state before the change.
pub old: String,
/// The new join state after the change.
pub new: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
/// Represents a change in order associated with a group audit log entry.
pub struct OrderChange {
/// The old order before the change.
pub old: u32,
/// The new order after the change.
pub new: u32,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't these be unified under a common ChangeEntry<T> or such type?

2 changes: 2 additions & 0 deletions src/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod assets;
pub use assets::*;
mod auth;
pub use auth::*;
mod groups;
pub use groups::*;
mod instances;
pub use instances::*;
mod notifications;
Expand Down
3 changes: 2 additions & 1 deletion src/model/users.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use either::Either;
use serde::{Deserialize, Serialize};
use time::{serde::rfc3339, OffsetDateTime};
use url::Url;
Expand Down Expand Up @@ -280,7 +281,7 @@ pub struct CurrentAccountData {
pub obfuscated_pending_email: String,
/// Can be empty
#[serde(default)]
pub past_display_names: Vec<PastDisplayName>,
pub past_display_names: Vec<Either<PastDisplayName, String>>,
/// If hasn't set status yet
pub status_first_time: bool,
/// History of statuses (VRC pre-populates some for new accounts)
Expand Down
50 changes: 50 additions & 0 deletions src/query/groups.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use racal::Queryable;
use serde::{Deserialize, Serialize};

use super::Authentication;

/// Gets information about a specific group
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct Group {
/// The ID of the group to get information about
pub id: crate::id::Group,
}

impl Queryable<Authentication, crate::model::Group> for Group {
fn url(&self, _: &Authentication) -> String {
format!("{}/groups/{}", crate::API_BASE_URI, self.id.as_ref())
}
}

/// Gets audit logs from a specific group
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct GroupAuditLogs {
/// The ID of the group to get audit logs from
pub id: crate::id::Group,
/// The count of how many logs to get (1 - 100)
pub n: Option<u8>,
/// The offset of how many logs to get
pub offset: Option<usize>,
// TODO: startDate & endDate
}

impl Queryable<Authentication, crate::model::GroupAuditLogs>
for GroupAuditLogs
{
fn url(&self, _: &Authentication) -> String {
let mut query =
format!("{}/groups/{}/auditLogs?", crate::API_BASE_URI, self.id.as_ref());

if let Some(n) = self.n {
let param = format!("&n={n}");
query.push_str(&param);
}

if let Some(offset) = self.offset {
let param = format!("&offset={offset}");
query.push_str(&param);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This'd result in .../auditLogs?&n=... Should only add the &/? when required... Could for example turn the optional params into a vec, join with & and then if there's results prefix with ? before constructing the query with format!.


query
}
}
2 changes: 2 additions & 0 deletions src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ mod auth;
pub use auth::*;
mod friends;
pub use friends::*;
mod groups;
pub use groups::*;
mod instances;
pub use instances::*;
mod users;
Expand Down
Loading