Add server emoji picker
This commit is contained in:
parent
2861cdda0b
commit
b0f932445c
@ -59,6 +59,11 @@ type RoleInfo = {
|
|||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type EmojiInfo = {
|
||||||
|
fmt: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
type Template = {
|
type Template = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
@ -125,6 +130,15 @@ export const fetchGuildRoles = (guild: string) => ({
|
|||||||
staleTime: GUILD_INFO_STALE_TIME,
|
staleTime: GUILD_INFO_STALE_TIME,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fetchGuildEmojis = (guild: string) => ({
|
||||||
|
queryKey: ["GUILD_EMOJIS", guild],
|
||||||
|
queryFn: () =>
|
||||||
|
axios.get(`/dashboard/api/guild/${guild}/emojis`).then((resp) => resp.data) as Promise<
|
||||||
|
EmojiInfo[]
|
||||||
|
>,
|
||||||
|
staleTime: GUILD_INFO_STALE_TIME,
|
||||||
|
});
|
||||||
|
|
||||||
export const fetchGuildReminders = (guild: string) => ({
|
export const fetchGuildReminders = (guild: string) => ({
|
||||||
queryKey: ["GUILD_REMINDERS", guild],
|
queryKey: ["GUILD_REMINDERS", guild],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useMemo } from "preact/hooks";
|
import { useEffect, useMemo } from "preact/hooks";
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
import { fetchGuildChannels, fetchGuildRoles } from "../../api";
|
import { fetchGuildChannels, fetchGuildRoles, fetchGuildEmojis } from "../../api";
|
||||||
import Tribute from "tributejs";
|
import Tribute from "tributejs";
|
||||||
import { useGuild } from "./useGuild";
|
import { useGuild } from "./useGuild";
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ export const Mentions = ({ input }) => {
|
|||||||
|
|
||||||
const { data: roles } = useQuery(fetchGuildRoles(guild));
|
const { data: roles } = useQuery(fetchGuildRoles(guild));
|
||||||
const { data: channels } = useQuery(fetchGuildChannels(guild));
|
const { data: channels } = useQuery(fetchGuildChannels(guild));
|
||||||
|
const { data: emojis } = useQuery(fetchGuildEmojis(guild));
|
||||||
|
|
||||||
const tribute = useMemo(() => {
|
const tribute = useMemo(() => {
|
||||||
return new Tribute({
|
return new Tribute({
|
||||||
@ -27,9 +28,16 @@ export const Mentions = ({ input }) => {
|
|||||||
selectTemplate: (item) => `<#${item.original.value}>`,
|
selectTemplate: (item) => `<#${item.original.value}>`,
|
||||||
menuItemTemplate: (item) => `#${item.original.key}`,
|
menuItemTemplate: (item) => `#${item.original.key}`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
trigger: ":",
|
||||||
|
values: (emojis || []).map(({ fmt, name }) => ({ key: name, value: fmt })),
|
||||||
|
allowSpaces: true,
|
||||||
|
selectTemplate: (item) => item.original.value,
|
||||||
|
menuItemTemplate: (item) => `:${item.original.key}:`,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}, [roles, channels]);
|
}, [roles, channels, emojis]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tribute.detach(input.current);
|
tribute.detach(input.current);
|
||||||
|
@ -8,6 +8,7 @@ export const GuildError = () => {
|
|||||||
The bot may have just been restarted, in which case please try again in a
|
The bot may have just been restarted, in which case please try again in a
|
||||||
few minutes.
|
few minutes.
|
||||||
<br />
|
<br />
|
||||||
|
<br />
|
||||||
Otherwise, please check Reminder Bot is in the server, and has correct
|
Otherwise, please check Reminder Bot is in the server, and has correct
|
||||||
permissions.
|
permissions.
|
||||||
</p>
|
</p>
|
||||||
|
@ -138,6 +138,7 @@ pub async fn initialize(
|
|||||||
routes::dashboard::api::guild::get_guild_info,
|
routes::dashboard::api::guild::get_guild_info,
|
||||||
routes::dashboard::api::guild::get_guild_channels,
|
routes::dashboard::api::guild::get_guild_channels,
|
||||||
routes::dashboard::api::guild::get_guild_roles,
|
routes::dashboard::api::guild::get_guild_roles,
|
||||||
|
routes::dashboard::api::guild::get_guild_emojis,
|
||||||
routes::dashboard::api::guild::get_reminder_templates,
|
routes::dashboard::api::guild::get_reminder_templates,
|
||||||
routes::dashboard::api::guild::create_reminder_template,
|
routes::dashboard::api::guild::create_reminder_template,
|
||||||
routes::dashboard::api::guild::delete_reminder_template,
|
routes::dashboard::api::guild::delete_reminder_template,
|
||||||
|
84
src/web/routes/dashboard/api/guild/emojis.rs
Normal file
84
src/web/routes/dashboard/api/guild/emojis.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use std::{collections::HashMap, sync::OnceLock, time::Instant};
|
||||||
|
|
||||||
|
use log::{info, warn};
|
||||||
|
use rocket::{get, http::CookieJar, serde::json::json, State};
|
||||||
|
use serde::Serialize;
|
||||||
|
use serenity::{client::Context, model::id::GuildId};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::web::{check_authorization, routes::JsonResult};
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
struct EmojiInfo {
|
||||||
|
fmt: String,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct EmojiCache {
|
||||||
|
emojis: Vec<EmojiInfo>,
|
||||||
|
timestamp: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CACHE_LENGTH: u64 = 120;
|
||||||
|
|
||||||
|
static EMOJI_CACHE: OnceLock<RwLock<HashMap<GuildId, EmojiCache>>> = OnceLock::new();
|
||||||
|
|
||||||
|
#[get("/api/guild/<id>/emojis")]
|
||||||
|
pub async fn get_guild_emojis(
|
||||||
|
id: u64,
|
||||||
|
cookies: &CookieJar<'_>,
|
||||||
|
ctx: &State<Context>,
|
||||||
|
) -> JsonResult {
|
||||||
|
offline!(Ok(json!(vec![] as Vec<EmojiInfo>)));
|
||||||
|
check_authorization(cookies, ctx.inner(), id).await?;
|
||||||
|
|
||||||
|
let cache_value = {
|
||||||
|
let cache = EMOJI_CACHE.get_or_init(|| RwLock::new(HashMap::new()));
|
||||||
|
let read_lock = cache.read().await;
|
||||||
|
read_lock.get(&GuildId::new(id)).cloned()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(emojis) = cache_value
|
||||||
|
.map(|v| {
|
||||||
|
if Instant::now().duration_since(v.timestamp).as_secs() < CACHE_LENGTH {
|
||||||
|
Some(v.emojis)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
Ok(json!(emojis))
|
||||||
|
} else {
|
||||||
|
let emojis_res = ctx.http.get_emojis(GuildId::new(id)).await;
|
||||||
|
|
||||||
|
match emojis_res {
|
||||||
|
Ok(emojis) => {
|
||||||
|
let emojis = emojis
|
||||||
|
.iter()
|
||||||
|
.map(|emoji| EmojiInfo {
|
||||||
|
fmt: format!("{}", emoji),
|
||||||
|
name: emoji.name.to_string(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<EmojiInfo>>();
|
||||||
|
|
||||||
|
{
|
||||||
|
let cache = EMOJI_CACHE.get_or_init(|| RwLock::new(HashMap::new()));
|
||||||
|
let mut write_lock = cache.write().await;
|
||||||
|
write_lock.insert(
|
||||||
|
GuildId::new(id),
|
||||||
|
EmojiCache { emojis: emojis.clone(), timestamp: Instant::now() },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(emojis))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Could not fetch emojis from {}: {:?}", id, e);
|
||||||
|
|
||||||
|
json_err!("Could not get emojis")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,16 @@
|
|||||||
mod channels;
|
mod channels;
|
||||||
|
mod emojis;
|
||||||
mod reminders;
|
mod reminders;
|
||||||
mod roles;
|
mod roles;
|
||||||
mod templates;
|
mod templates;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
pub use channels::*;
|
pub use channels::get_guild_channels;
|
||||||
|
pub use emojis::get_guild_emojis;
|
||||||
pub use reminders::*;
|
pub use reminders::*;
|
||||||
use rocket::{get, http::CookieJar, serde::json::json, State};
|
use rocket::{get, http::CookieJar, serde::json::json, State};
|
||||||
pub use roles::*;
|
pub use roles::get_guild_roles;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::Context,
|
client::Context,
|
||||||
model::id::{GuildId, RoleId},
|
model::id::{GuildId, RoleId},
|
||||||
|
Loading…
Reference in New Issue
Block a user