use crates::chrono::{DateTime, Utc};
use crates::serde::de::{Error, Unexpected};
use crates::serde::{Deserialize, Deserializer, Serialize, Serializer};
use crates::serde_json::{self, Value};
use types::{AccessLevel, GroupId, ObjectId, ProjectId, SshKeyId, UserId};
use webhooks::{CommitHookAttrs, ProjectHookAttrs};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectEvent {
Create,
Destroy,
Rename,
Transfer,
}
enum_serialize!(ProjectEvent -> "project event",
Create => "project_create",
Destroy => "project_destroy",
Rename => "project_rename",
Transfer => "project_transfer",
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectVisibility {
Internal,
Private,
Public,
}
enum_serialize!(ProjectVisibility -> "project visibility",
Internal => "internal" ; "visibilitylevel|internal",
Private => "private" ; "visibilitylevel|private",
Public => "public" ; "visibilitylevel|public",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectSystemHook {
pub event_name: ProjectEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub name: String,
pub owner_email: String,
pub owner_name: String,
pub path: String,
pub path_with_namespace: String,
pub project_id: ProjectId,
pub project_visibility: ProjectVisibility,
pub old_path_with_namespace: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectMemberEvent {
Add,
Remove,
}
enum_serialize!(ProjectMemberEvent -> "project member event",
Add => "user_add_to_team",
Remove => "user_remove_from_team",
);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum HumanAccessLevel {
Guest,
Reporter,
Developer,
Maintainer,
Owner,
}
enum_serialize!(HumanAccessLevel -> "human access level",
Guest => "Guest",
Reporter => "Reporter",
Developer => "Developer",
Maintainer => "Maintainer",
Owner => "Owner",
);
impl From<HumanAccessLevel> for AccessLevel {
fn from(access: HumanAccessLevel) -> Self {
match access {
HumanAccessLevel::Guest => AccessLevel::Guest,
HumanAccessLevel::Reporter => AccessLevel::Reporter,
HumanAccessLevel::Developer => AccessLevel::Developer,
HumanAccessLevel::Maintainer => AccessLevel::Maintainer,
HumanAccessLevel::Owner => AccessLevel::Owner,
}
}
}
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectMemberSystemHook {
pub event_name: ProjectMemberEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub project_name: String,
pub project_path: String,
pub project_path_with_namespace: String,
pub project_id: ProjectId,
pub user_username: String,
pub user_name: String,
pub user_email: String,
pub user_id: UserId,
pub access_level: HumanAccessLevel,
pub project_visibility: ProjectVisibility,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UserEvent {
Create,
Destroy,
}
enum_serialize!(UserEvent -> "user event",
Create => "user_create",
Destroy => "user_destroy",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserSystemHook {
pub event_name: UserEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub name: String,
pub email: String,
pub user_id: UserId,
pub username: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyEvent {
Create,
Destroy,
}
enum_serialize!(KeyEvent -> "key event",
Create => "key_create",
Destroy => "key_destroy",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct KeySystemHook {
pub event_name: KeyEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub username: String,
pub key: String,
pub id: SshKeyId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GroupEvent {
Create,
Destroy,
}
enum_serialize!(GroupEvent -> "group event",
Create => "group_create",
Destroy => "group_destroy",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GroupSystemHook {
pub event_name: GroupEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub name: String,
pub path: String,
pub group_id: GroupId,
pub owner_email: Option<String>,
pub owner_name: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GroupMemberEvent {
Add,
Remove,
}
enum_serialize!(GroupMemberEvent -> "group member event",
Add => "user_add_to_group",
Remove => "user_remove_from_group",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GroupMemberSystemHook {
pub event_name: GroupMemberEvent,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub group_name: String,
pub group_path: String,
pub group_id: GroupId,
pub user_username: String,
pub user_name: String,
pub user_email: String,
pub user_id: UserId,
pub group_access: HumanAccessLevel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PushEvent {
Push,
TagPush,
}
enum_serialize!(PushEvent -> "push event",
Push => "push",
TagPush => "tag_push",
);
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PushSystemHook {
pub event_name: PushEvent,
object_kind: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub before: ObjectId,
pub after: ObjectId,
#[serde(rename = "ref")]
pub ref_: String,
pub checkout_sha: ObjectId,
pub message: Option<String>,
pub user_id: UserId,
pub user_name: String,
pub user_email: String,
pub user_avatar: String,
pub project_id: ProjectId,
pub project: ProjectHookAttrs,
pub commits: Vec<CommitHookAttrs>,
pub total_commits_count: u64,
repository: Value,
}
#[derive(Debug, Clone)]
pub enum SystemHook {
Project(ProjectSystemHook),
ProjectMember(ProjectMemberSystemHook),
User(UserSystemHook),
Key(KeySystemHook),
Group(GroupSystemHook),
GroupMember(GroupMemberSystemHook),
Push(PushSystemHook),
}
impl<'de> Deserialize<'de> for SystemHook {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let val = <Value as Deserialize>::deserialize(deserializer)?;
let event_name = match val.pointer("/event_name") {
Some(&Value::String(ref name)) => name.to_string(),
Some(_) => {
return Err(D::Error::invalid_type(
Unexpected::Other("JSON value"),
&"a string",
));
},
None => {
return Err(D::Error::missing_field("event_name"));
},
};
let hook_res = match event_name.as_str() {
"project_create" | "project_destroy" | "project_rename" | "project_transfer" => {
serde_json::from_value(val).map(SystemHook::Project)
},
"user_add_to_team" | "user_remove_from_team" => {
serde_json::from_value(val).map(SystemHook::ProjectMember)
},
"user_create" | "user_destroy" => serde_json::from_value(val).map(SystemHook::User),
"key_create" | "key_destroy" => serde_json::from_value(val).map(SystemHook::Key),
"group_create" | "group_destroy" => serde_json::from_value(val).map(SystemHook::Group),
"user_add_to_group" | "user_remove_from_group" => {
serde_json::from_value(val).map(SystemHook::GroupMember)
},
"push" | "tag_push" => serde_json::from_value(val).map(SystemHook::Push),
_ => {
return Err(D::Error::custom(format!(
"unrecognized system event name: {}",
event_name,
)));
},
};
hook_res.map_err(|err| {
D::Error::custom(format!("failed to deserialize a system hook: {:?}", err))
})
}
}