feat(service): expand service layer with new domain operations

- Add IM service modules: audit, channel roles, custom emojis, forum
  tags, integrations, invitations, repo links, slash commands, stages,
  voice, webhooks
- Add PR service modules: review requests, templates
- Add repo service modules: contributors, release assets, git extras
  (archive, branch rename, commit extras, diff/merge, tag, tree)
- Add user service: social (follow/block)
- Add internal auth service
- Update existing service modules with expanded functionality
- Remove deleted IM modules: articles, delivery trace, drafts,
  follows, messages, polls, presence, reactions, threads
This commit is contained in:
zhenyi
2026-06-10 18:49:32 +08:00
parent cec6dce955
commit 420dedbc1e
100 changed files with 3797 additions and 3839 deletions
+2 -56
View File
@@ -1,5 +1,6 @@
pub use crate::service::util::{
clamp_limit_offset, ensure_affected, merge_optional_text, parse_enum, required_text, role_level,
clamp_limit_offset, ensure_affected, merge_optional_text, parse_enum, required_text,
role_level, set_local_user_id,
};
/// Maximum length for a channel name.
@@ -7,58 +8,3 @@ pub const MAX_CHANNEL_NAME: usize = 100;
/// Maximum length for a channel topic.
pub const MAX_CHANNEL_TOPIC: usize = 1024;
/// Maximum length for a message body.
pub const MAX_MESSAGE_BODY: usize = 4096;
/// Maximum length for an article title.
pub const MAX_ARTICLE_TITLE: usize = 256;
/// Maximum number of poll options.
pub const MAX_POLL_OPTIONS: usize = 10;
/// Maximum length for a poll option text.
pub const MAX_POLL_OPTION_TEXT: usize = 100;
/// Redis key prefix for typing indicators.
pub const TYPING_PREFIX: &str = "im:typing:";
/// Redis key prefix for user presence.
pub const PRESENCE_PREFIX: &str = "im:presence:";
/// Redis TTL for typing indicators (seconds).
pub const TYPING_TTL_SECS: usize = 8;
/// Redis TTL for presence heartbeats (seconds).
pub const PRESENCE_TTL_SECS: usize = 120;
/// Maximum length for generated slugs.
pub const MAX_SLUG_LEN: usize = 128;
/// Generate a slug from a title string.
pub fn slugify(title: &str) -> String {
let slug: String = title
.to_lowercase()
.chars()
.filter_map(|c| {
if c.is_ascii_alphanumeric() {
Some(c)
} else if c.is_whitespace() || !c.is_ascii() {
Some('-')
} else {
None
}
})
.collect::<String>()
.split('-')
.filter(|s| !s.is_empty())
.collect::<Vec<_>>()
.join("-");
let mut result = slug;
result.truncate(MAX_SLUG_LEN);
if result.ends_with('-') {
result.pop();
}
result
}