add: markdown emoji parsing
This commit is contained in:
parent
d9234bf656
commit
af67077ae7
8 changed files with 243 additions and 46 deletions
|
@ -54,40 +54,30 @@ impl DataManager {
|
|||
Ok(res.unwrap())
|
||||
}
|
||||
|
||||
/// Get all emojis by user.
|
||||
/// Get an emoji by community and name.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `user` - the ID of the user to fetch emojis for
|
||||
pub async fn get_emojis_by_user(&self, user: usize) -> Result<Vec<CustomEmoji>> {
|
||||
let conn = match self.connect().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||
};
|
||||
|
||||
let res = query_rows!(
|
||||
&conn,
|
||||
"SELECT * FROM emojis WHERE (owner = $1 OR members LIKE $2) AND community = 0 ORDER BY created DESC",
|
||||
params![&(user as i64), &format!("%{user}%")],
|
||||
|x| { Self::get_emoji_from_row(x) }
|
||||
);
|
||||
|
||||
if res.is_err() {
|
||||
return Err(Error::GeneralNotFound("emoji".to_string()));
|
||||
/// * `community` - the ID of the community to fetch emoji from
|
||||
/// * `name` - the name of the emoji
|
||||
///
|
||||
/// # Returns
|
||||
/// `(custom emoji, emoji string)`
|
||||
///
|
||||
/// Custom emoji will be none if emoji string is some, and vice versa. Emoji string
|
||||
/// will only be some if the community is 0 (no community ID in parsed string, or `0.emoji_name`)
|
||||
///
|
||||
/// Regular unicode emojis should have a community ID of 0, since they don't belong
|
||||
/// to any community and can be used by anyone.
|
||||
pub async fn get_emoji_by_community_name(
|
||||
&self,
|
||||
community: usize,
|
||||
name: &str,
|
||||
) -> Result<(Option<CustomEmoji>, Option<String>)> {
|
||||
if community == 0 {
|
||||
return Ok((None, Some("🐇".to_string())));
|
||||
}
|
||||
|
||||
Ok(res.unwrap())
|
||||
}
|
||||
|
||||
/// Get a emoji given its `owner` and a member.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `owner` - the ID of the owner
|
||||
/// * `member` - the ID of the member
|
||||
pub async fn get_emoji_by_owner_member(
|
||||
&self,
|
||||
owner: usize,
|
||||
member: usize,
|
||||
) -> Result<CustomEmoji> {
|
||||
// ...
|
||||
let conn = match self.connect().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||
|
@ -95,9 +85,9 @@ impl DataManager {
|
|||
|
||||
let res = query_row!(
|
||||
&conn,
|
||||
"SELECT * FROM emojis WHERE owner = $1 AND members = $2 AND community = 0 ORDER BY created DESC",
|
||||
params![&(owner as i64), &format!("[{member}]")],
|
||||
|x| { Ok(Self::get_emoji_from_row(x)) }
|
||||
"SELECT * FROM emojis WHERE community = $1 AND name = $2 ORDER BY name ASC",
|
||||
params![&(community as i64), &name],
|
||||
|x| { Ok((Some(Self::get_emoji_from_row(x)), None)) }
|
||||
);
|
||||
|
||||
if res.is_err() {
|
||||
|
|
|
@ -48,6 +48,8 @@ pub struct CustomEmoji {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
pub type EmojiParserResult = Vec<(String, usize, String)>;
|
||||
|
||||
impl CustomEmoji {
|
||||
/// Create a new [`CustomEmoji`].
|
||||
pub fn new(owner: usize, community: usize, upload_id: usize, name: String) -> Self {
|
||||
|
@ -63,4 +65,105 @@ impl CustomEmoji {
|
|||
name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace emojis in the given input string.
|
||||
pub fn replace(input: &str) -> String {
|
||||
let res = Self::parse(input);
|
||||
let mut out = input.to_string();
|
||||
|
||||
for emoji in res {
|
||||
if emoji.1 == 0 {
|
||||
out = out.replace(
|
||||
&emoji.0,
|
||||
match emojis::get_by_shortcode(&emoji.2) {
|
||||
Some(e) => e.as_str(),
|
||||
None => &emoji.0,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
out = out.replace(
|
||||
&emoji.0,
|
||||
&format!(
|
||||
"<img class=\"emoji\" src=\"/api/v1/communities/{}/emoji/{}\" />",
|
||||
emoji.1, emoji.2
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Parse text for emojis.
|
||||
///
|
||||
/// Another "great" parser, just like the mentions parser.
|
||||
///
|
||||
/// # Returns
|
||||
/// `(capture, community id, emoji name)`
|
||||
pub fn parse(input: &str) -> EmojiParserResult {
|
||||
let mut out = Vec::new();
|
||||
let mut buffer: String = String::new();
|
||||
|
||||
let mut escape: bool = false;
|
||||
let mut in_emoji: bool = false;
|
||||
|
||||
let mut chars = input.chars();
|
||||
while let Some(char) = chars.next() {
|
||||
if escape == true {
|
||||
buffer.push(char);
|
||||
continue;
|
||||
}
|
||||
|
||||
if char == '\\' && escape == false {
|
||||
escape = true;
|
||||
continue;
|
||||
} else if char == ':' {
|
||||
let mut community_id: String = String::new();
|
||||
let mut accepting_community_id_chars: bool = true;
|
||||
let mut emoji_name: String = String::new();
|
||||
|
||||
let mut char_count: u32 = 0; // if we're past the first 4 characters and we haven't hit a digit, stop accepting community id
|
||||
while let Some(char) = chars.next() {
|
||||
if (char == ':') | (char == ' ') {
|
||||
in_emoji = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if char.is_digit(10) && accepting_community_id_chars {
|
||||
community_id.push(char);
|
||||
} else if char == '.' {
|
||||
// the period closes the community id
|
||||
accepting_community_id_chars = false;
|
||||
} else {
|
||||
emoji_name.push(char);
|
||||
}
|
||||
|
||||
if char_count >= 4 && community_id.is_empty() {
|
||||
accepting_community_id_chars = false;
|
||||
}
|
||||
|
||||
char_count += 1;
|
||||
}
|
||||
|
||||
out.push((
|
||||
format!(
|
||||
":{}{emoji_name}:",
|
||||
if !community_id.is_empty() {
|
||||
format!("{community_id}.")
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
),
|
||||
community_id.parse::<usize>().unwrap_or(0),
|
||||
emoji_name,
|
||||
));
|
||||
|
||||
continue;
|
||||
} else if in_emoji {
|
||||
buffer.push(char);
|
||||
}
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue