mirror of
https://github.com/System-End/plura.git
synced 2026-04-19 18:35:12 +00:00
feat(sync): add /sync from-pk command to import members from PluralKit
This commit is contained in:
parent
555dafc0af
commit
7673dbdde9
2 changed files with 112 additions and 5 deletions
|
|
@ -9,6 +9,7 @@ use std::sync::Arc;
|
|||
|
||||
mod alias;
|
||||
mod member;
|
||||
mod sync;
|
||||
mod system;
|
||||
mod trigger;
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ use slack_morphism::prelude::*;
|
|||
use tracing::{Level, debug, error, trace};
|
||||
|
||||
use member::Member;
|
||||
use sync::Sync;
|
||||
use system::System;
|
||||
use trigger::Trigger;
|
||||
|
||||
|
|
@ -36,6 +38,8 @@ enum Command {
|
|||
Triggers(Trigger),
|
||||
#[clap(subcommand)]
|
||||
Aliases(Alias),
|
||||
#[clap(subcommand)]
|
||||
Sync(Sync),
|
||||
/// Provides an explanation of this bot.
|
||||
Explain,
|
||||
}
|
||||
|
|
@ -65,6 +69,10 @@ impl Command {
|
|||
.run(event, state)
|
||||
.await
|
||||
.change_context(CommandError::Aliases),
|
||||
Self::Sync(sync) => sync
|
||||
.run(event, client, state)
|
||||
.await
|
||||
.change_context(CommandError::Sync),
|
||||
Self::Explain => Ok(Self::explain()),
|
||||
}
|
||||
}
|
||||
|
|
@ -73,13 +81,13 @@ impl Command {
|
|||
SlackCommandEventResponse::new(
|
||||
SlackMessageContent::new().with_text(
|
||||
indoc::indoc! {r#"
|
||||
Slack System Bot is a bot that can replace user-sent messages under a "pseudo-account" of a systems member profile using custom display information.
|
||||
Plura is a bot that can replace user-sent messages under a "pseudo-account" of a systems member profile using custom display information.
|
||||
|
||||
This is useful for multiple people sharing one body (aka. systems), people who wish to role-play as different characters without having multiple Slack profiles, or anyone else who may want to post messages under a different identity from the same Slack account.
|
||||
|
||||
Due to Slack's limitations, these messages will show up with the [APP] tag - however, they are not apps/bots. You can use message actions to find who the message was sent by.
|
||||
|
||||
If you wish to use the bot yourself, you can start with `/system help` and `/members help`.
|
||||
If you wish to use the bot yourself, you can start with `/system help` and `/members help`. Other commands: `/triggers help`, `/aliases help`, `/sync help`.
|
||||
"#}.into(),
|
||||
),
|
||||
).with_response_type(SlackMessageResponseType::InChannel)
|
||||
|
|
@ -96,9 +104,10 @@ enum CommandError {
|
|||
System,
|
||||
/// Error running the aliases command
|
||||
Aliases,
|
||||
/// Error running the sync command
|
||||
Sync,
|
||||
}
|
||||
|
||||
// TO-DO: figure out error handling
|
||||
#[tracing::instrument(skip(environment, event))]
|
||||
pub async fn process_command_event(
|
||||
Extension(environment): Extension<Arc<SlackHyperListenerEnvironment>>,
|
||||
|
|
@ -110,7 +119,7 @@ pub async fn process_command_event(
|
|||
match command_event_callback(event, client, state).await {
|
||||
Ok(response) => Json(response),
|
||||
Err(e) => {
|
||||
error!(error = ?e, "Error processing command event");
|
||||
tracing::error!(error = ?e, "Error processing command event");
|
||||
Json(SlackCommandEventResponse::new(
|
||||
SlackMessageContent::new()
|
||||
.with_text("Error processing command! Logged to developers".into()),
|
||||
|
|
@ -150,7 +159,7 @@ async fn command_event_callback(
|
|||
error!(error = ?e, "Error running command");
|
||||
Ok(SlackCommandEventResponse::new(
|
||||
SlackMessageContent::new().with_text(
|
||||
"Error running command! TODO: show error info on slack".into(),
|
||||
format!("Error running command: {e}").into(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
98
src/commands/sync.rs
Executable file
98
src/commands/sync.rs
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use error_stack::{Result, ResultExt};
|
||||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
use slack_morphism::prelude::*;
|
||||
|
||||
use crate::{
|
||||
fetch_system,
|
||||
models::{member, user},
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, displaydoc::Display, Debug)]
|
||||
pub enum CommandError {
|
||||
/// Error calling the database
|
||||
Sqlx,
|
||||
/// Error calling the PluralKit API
|
||||
PluralKit,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand, Debug)]
|
||||
pub enum Sync {
|
||||
/// Import members from PluralKit. Run in a DM to keep your token private.
|
||||
FromPk {
|
||||
/// Your PluralKit token (from pluralkit.me/settings)
|
||||
token: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct PkMember {
|
||||
name: String,
|
||||
display_name: Option<String>,
|
||||
avatar_url: Option<String>,
|
||||
pronouns: Option<String>,
|
||||
}
|
||||
|
||||
impl Sync {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn run(
|
||||
self,
|
||||
event: SlackCommandEvent,
|
||||
_client: Arc<SlackHyperClient>,
|
||||
state: SlackClientEventsUserState,
|
||||
) -> Result<SlackCommandEventResponse, CommandError> {
|
||||
let states = state.read().await;
|
||||
let user_state = states.get_user_state::<user::State>().unwrap();
|
||||
|
||||
match self {
|
||||
Self::FromPk { token } => {
|
||||
fetch_system!(event, user_state => system_id);
|
||||
|
||||
let http = Client::new();
|
||||
let pk_members = http
|
||||
.get("https://api.pluralkit.me/v2/systems/@me/members")
|
||||
.header("User-Agent", "Plura/0.1 (https://github.com/Suya1671/plura)")
|
||||
.header("Authorization", token.trim())
|
||||
.send()
|
||||
.await
|
||||
.change_context(CommandError::PluralKit)
|
||||
.attach_printable("Failed to reach PluralKit API")?
|
||||
.error_for_status()
|
||||
.change_context(CommandError::PluralKit)
|
||||
.attach_printable("PluralKit API returned an error — is your token correct?")?
|
||||
.json::<Vec<PkMember>>()
|
||||
.await
|
||||
.change_context(CommandError::PluralKit)
|
||||
.attach_printable("Failed to parse PluralKit API response")?;
|
||||
|
||||
let count = pk_members.len();
|
||||
|
||||
for pk_member in pk_members {
|
||||
let display_name = pk_member
|
||||
.display_name
|
||||
.unwrap_or_else(|| pk_member.name.clone());
|
||||
member::View {
|
||||
full_name: pk_member.name,
|
||||
display_name,
|
||||
profile_picture_url: pk_member.avatar_url,
|
||||
pronouns: pk_member.pronouns,
|
||||
title: None,
|
||||
name_pronunciation: None,
|
||||
name_recording_url: None,
|
||||
}
|
||||
.add(system_id, &user_state.db)
|
||||
.await
|
||||
.change_context(CommandError::Sqlx)?;
|
||||
}
|
||||
|
||||
Ok(SlackCommandEventResponse::new(
|
||||
SlackMessageContent::new().with_text(
|
||||
format!("Imported {count} member(s) from PluralKit!").into(),
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue