Compare commits
No commits in common. "d24cc900d0edcabf07e95cd9413109beae068776" and "46c92f5a5954e205ef24b19c51db427c4748e226" have entirely different histories.
d24cc900d0
...
46c92f5a59
8 changed files with 29 additions and 396 deletions
|
|
@ -1,46 +0,0 @@
|
||||||
name: CI
|
|
||||||
|
|
||||||
# pull_request_target always runs this file from the base branch. A pull request
|
|
||||||
# cannot replace these steps, which is what `pull_request` would allow after
|
|
||||||
# someone clicks Approve on a fork.
|
|
||||||
#
|
|
||||||
# Forks still are not compiled until a maintainer adds the `ci` label. `cargo
|
|
||||||
# check` executes build scripts, so review Cargo.toml, Cargo.lock, build.rs,
|
|
||||||
# and .cargo/config.toml before adding it. New commits do not reuse that label;
|
|
||||||
# remove it and add it again after reviewing them.
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, synchronize, reopened, labeled]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check:
|
|
||||||
if: |
|
|
||||||
forgejo.event.pull_request.head.repo.full_name == forgejo.repository ||
|
|
||||||
(forgejo.event.action == 'label_updated' && forgejo.event.label.name == 'ci')
|
|
||||||
runs-on: native
|
|
||||||
steps:
|
|
||||||
- name: Checkout pull request
|
|
||||||
uses: https://data.forgejo.org/actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ forgejo.event.pull_request.head.repo.full_name }}
|
|
||||||
ref: ${{ forgejo.event.pull_request.head.sha }}
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Cargo check
|
|
||||||
run: |
|
|
||||||
docker run --rm \
|
|
||||||
--read-only \
|
|
||||||
--network bridge \
|
|
||||||
--cap-drop ALL \
|
|
||||||
--security-opt no-new-privileges \
|
|
||||||
--pids-limit 512 \
|
|
||||||
--memory 4g \
|
|
||||||
--tmpfs /tmp:rw,exec,nosuid,nodev,size=2g \
|
|
||||||
--user "$(id -u):$(id -g)" \
|
|
||||||
-e CARGO_HOME=/tmp/cargo \
|
|
||||||
-e CARGO_TARGET_DIR=/tmp/target \
|
|
||||||
-e PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
|
||||||
-v "$PWD:/src:ro" \
|
|
||||||
-w /src \
|
|
||||||
rust:1.98-bookworm \
|
|
||||||
cargo check --locked --manifest-path /src/Cargo.toml
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod faq;
|
pub mod faq;
|
||||||
pub mod forum;
|
pub mod forum;
|
||||||
pub mod info;
|
pub mod info;
|
||||||
pub mod lock;
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::utils::format::format_embed_description;
|
|
||||||
use crate::{Context, Error};
|
use crate::{Context, Error};
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
|
|
@ -11,6 +10,11 @@ struct Faq {
|
||||||
description: String,
|
description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_embed_description<S: Into<String>>(description: S) -> Result<String, Error> {
|
||||||
|
let string_val = description.into();
|
||||||
|
Ok(str::replace(&string_val, "\\n", "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
fn faq_exists(conn: &Connection, faq: &str, guild_id: &u64) -> Result<bool, Error> {
|
fn faq_exists(conn: &Connection, faq: &str, guild_id: &u64) -> Result<bool, Error> {
|
||||||
let guild_id = guild_id.to_string();
|
let guild_id = guild_id.to_string();
|
||||||
let exists: bool = conn.query_row(
|
let exists: bool = conn.query_row(
|
||||||
|
|
@ -89,33 +93,26 @@ pub async fn view(
|
||||||
let guild_id = server_guild_id.to_string();
|
let guild_id = server_guild_id.to_string();
|
||||||
|
|
||||||
move |conn| {
|
move |conn| {
|
||||||
let mut stmt = conn.prepare(
|
let mut stmt = conn.prepare(
|
||||||
"SELECT title, description FROM faqs WHERE title = ?1 AND guild_id = ?2",
|
"SELECT id, guild_id, title, description FROM faqs WHERE title = ?1 AND guild_id = ?2"
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let faqs: Vec<Faq> = stmt
|
let faqs: Vec<Faq> = stmt
|
||||||
.query_map([&faq_title, &guild_id], |row| {
|
.query_map([&faq_title, &guild_id], |row| {
|
||||||
Ok(Faq {
|
Ok(Faq {
|
||||||
title: row.get(0)?,
|
// id: row.get(0)?,
|
||||||
description: row.get(1)?,
|
// guild_id: row.get(1)?,
|
||||||
})
|
title: row.get(2)?,
|
||||||
})?
|
description: row.get(3)?,
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
})
|
||||||
|
})?
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Ok(faqs)
|
Ok(faqs)
|
||||||
}
|
}})
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let Some(faq) = faqs.first() else {
|
let faq = faqs.first().unwrap();
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title("Error 404")
|
|
||||||
.description("FAQ not found");
|
|
||||||
|
|
||||||
ctx.send(CreateReply::default().ephemeral(true).embed(embed))
|
|
||||||
.await?;
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let embed_description = format_embed_description(&faq.description).expect("Format error");
|
let embed_description = format_embed_description(&faq.description).expect("Format error");
|
||||||
let embed = CreateEmbed::new()
|
let embed = CreateEmbed::new()
|
||||||
|
|
@ -146,7 +143,6 @@ pub async fn preview(
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
||||||
let guild_id = server_guild_id.to_string();
|
let guild_id = server_guild_id.to_string();
|
||||||
|
|
||||||
|
|
||||||
move |conn| {
|
move |conn| {
|
||||||
let mut stmt = conn.prepare(
|
let mut stmt = conn.prepare(
|
||||||
"SELECT id, guild_id, title, description FROM faqs WHERE title = ?1 AND guild_id = ?2"
|
"SELECT id, guild_id, title, description FROM faqs WHERE title = ?1 AND guild_id = ?2"
|
||||||
|
|
@ -167,21 +163,15 @@ pub async fn preview(
|
||||||
}})
|
}})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let faq = faqs.first().expect("FAQ not found");
|
let faq = faqs.first().unwrap();
|
||||||
let embed_description = format_embed_description(&faq.description).expect("Format error");
|
|
||||||
|
|
||||||
let embed = CreateEmbed::new()
|
// let embed_description = format_embed_description(&faq.description).expect("Format error");
|
||||||
.title(format!("Title: {}", &faq.title))
|
let embed = CreateEmbed::new().title(&faq.title).description(format!(
|
||||||
.description(format!(
|
"```
|
||||||
"\
|
{}
|
||||||
**Raw Text**\n\
|
```",
|
||||||
```\n\
|
&faq.description
|
||||||
{}\
|
));
|
||||||
```\n\
|
|
||||||
**Preview:**\n\
|
|
||||||
{}",
|
|
||||||
&faq.description, embed_description
|
|
||||||
));
|
|
||||||
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
ctx.send(CreateReply::default().embed(embed)).await?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,287 +0,0 @@
|
||||||
use crate::utils::format::format_embed_description;
|
|
||||||
use crate::{Context, Error};
|
|
||||||
use poise::CreateReply;
|
|
||||||
use rusqlite::Connection;
|
|
||||||
use serenity::all::CreateEmbed;
|
|
||||||
use serenity::builder::EditThread;
|
|
||||||
|
|
||||||
struct LockEmbed {
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lock_message_exists(conn: &Connection, guild_id: &u64) -> Result<bool, Error> {
|
|
||||||
let guild_id = guild_id.to_string();
|
|
||||||
let exists: bool = conn.query_row(
|
|
||||||
"SELECT EXISTS(SELECT 1 FROM lock WHERE guild_id = ?1)",
|
|
||||||
[&guild_id],
|
|
||||||
|row| row.get(0),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(exists)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[poise::command(
|
|
||||||
slash_command,
|
|
||||||
subcommands("vibecoded", "preview", "add", "edit", "delete"),
|
|
||||||
guild_only
|
|
||||||
)]
|
|
||||||
pub async fn lock(_ctx: Context<'_>) -> Result<(), Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Post the vibe coded slop embed message
|
|
||||||
#[poise::command(
|
|
||||||
prefix_command,
|
|
||||||
slash_command,
|
|
||||||
required_permissions = "MANAGE_MESSAGES" // mod only
|
|
||||||
)]
|
|
||||||
pub async fn vibecoded(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "additional comment"] comment_option: Option<String>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let data = ctx.data();
|
|
||||||
|
|
||||||
// lock thread, if it's a thread in a forum
|
|
||||||
|
|
||||||
// let thread_lock = EditThread::new().locked(true);
|
|
||||||
let mut channel = ctx.guild_channel().await.expect("Not a thread");
|
|
||||||
channel
|
|
||||||
.edit_thread(ctx, EditThread::new().locked(true))
|
|
||||||
.await
|
|
||||||
.expect("Failed to lock thread, check permissions");
|
|
||||||
|
|
||||||
let lock_messages = data
|
|
||||||
.execute_db({
|
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
|
||||||
let guild_id = server_guild_id.to_string();
|
|
||||||
|
|
||||||
move |conn| {
|
|
||||||
let mut stmt =
|
|
||||||
conn.prepare("SELECT title, description FROM lock WHERE guild_id = ?1")?;
|
|
||||||
|
|
||||||
let lock_messages: Vec<LockEmbed> = stmt
|
|
||||||
.query_map([&guild_id], |row| {
|
|
||||||
Ok(LockEmbed {
|
|
||||||
title: row.get(0)?,
|
|
||||||
description: row.get(1)?,
|
|
||||||
})
|
|
||||||
})?
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
Ok(lock_messages)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let Some(lock_message) = lock_messages.first() else {
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title("Error 404")
|
|
||||||
.description("Lock message not found");
|
|
||||||
|
|
||||||
ctx.send(CreateReply::default().embed(embed).ephemeral(true))
|
|
||||||
.await?;
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut embed_description =
|
|
||||||
format_embed_description(&lock_message.description).expect("Format error");
|
|
||||||
if !comment_option.is_none() {
|
|
||||||
let comment = comment_option.expect("Comment error");
|
|
||||||
let new_description = format!(
|
|
||||||
"{}\n\n**Additional Comment(s)**\n{}",
|
|
||||||
&lock_message.description, comment
|
|
||||||
);
|
|
||||||
embed_description = format_embed_description(new_description).expect("Format error");
|
|
||||||
}
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(&lock_message.title)
|
|
||||||
.description(embed_description)
|
|
||||||
.color(0xff0000);
|
|
||||||
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add vibe coded slop embed message
|
|
||||||
#[poise::command(
|
|
||||||
prefix_command,
|
|
||||||
slash_command,
|
|
||||||
required_permissions = "MANAGE_MESSAGES" // mod only
|
|
||||||
)]
|
|
||||||
pub async fn add(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "Lock message title"] title: String,
|
|
||||||
#[description = "Lock message description"] description: String,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let data: &crate::Data = ctx.data();
|
|
||||||
|
|
||||||
let result = data
|
|
||||||
.execute_db({
|
|
||||||
let title = title.clone();
|
|
||||||
let description = description.clone();
|
|
||||||
|
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
|
||||||
let guild_id = server_guild_id.get();
|
|
||||||
move |conn| {
|
|
||||||
let exists = lock_message_exists(conn, &guild_id).unwrap_or(false);
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
conn.execute(
|
|
||||||
"INSERT INTO lock (guild_id, title, description) VALUES (?1, ?2, ?3)",
|
|
||||||
[guild_id.to_string(), title, description],
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if result == 1 {
|
|
||||||
let embed_description = format_embed_description(description).expect("Format error");
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Added Lock Message: {}", &title))
|
|
||||||
.description(embed_description);
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
} else {
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Error adding lock message: {}", &title))
|
|
||||||
.description("Lock message already exists!");
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Preview lock message
|
|
||||||
#[poise::command(
|
|
||||||
prefix_command,
|
|
||||||
slash_command,
|
|
||||||
required_permissions = "MANAGE_MESSAGES" // mod only
|
|
||||||
)]
|
|
||||||
pub async fn preview(ctx: Context<'_>) -> Result<(), Error> {
|
|
||||||
let data = ctx.data();
|
|
||||||
|
|
||||||
let lock_messages = data
|
|
||||||
.execute_db({
|
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
|
||||||
let guild_id = server_guild_id.to_string();
|
|
||||||
|
|
||||||
move |conn| {
|
|
||||||
let mut stmt =
|
|
||||||
conn.prepare("SELECT title, description FROM lock WHERE guild_id = ?1")?;
|
|
||||||
|
|
||||||
let lock_messages: Vec<LockEmbed> = stmt
|
|
||||||
.query_map([&guild_id], |row| {
|
|
||||||
Ok(LockEmbed {
|
|
||||||
title: row.get(0)?,
|
|
||||||
description: row.get(1)?,
|
|
||||||
})
|
|
||||||
})?
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
Ok(lock_messages)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let lock_message = lock_messages.first().expect("Lock message not found");
|
|
||||||
let embed_description =
|
|
||||||
format_embed_description(&lock_message.description).expect("Format error");
|
|
||||||
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Title: {}", &lock_message.title))
|
|
||||||
.description(format!(
|
|
||||||
"\
|
|
||||||
**Raw Text**\n\
|
|
||||||
```\n\
|
|
||||||
{}\
|
|
||||||
```\n\
|
|
||||||
**Preview:**\n\
|
|
||||||
{}",
|
|
||||||
&lock_message.description, embed_description
|
|
||||||
));
|
|
||||||
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Edit lock message
|
|
||||||
#[poise::command(
|
|
||||||
prefix_command,
|
|
||||||
slash_command,
|
|
||||||
required_permissions = "MANAGE_MESSAGES"
|
|
||||||
)]
|
|
||||||
pub async fn edit(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "Title"] title: String,
|
|
||||||
#[description = "Description"] description: String,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let data = ctx.data();
|
|
||||||
|
|
||||||
let result = data
|
|
||||||
.execute_db({
|
|
||||||
let title = title.clone();
|
|
||||||
let description = description.clone();
|
|
||||||
|
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
|
||||||
let guild_id = server_guild_id.get();
|
|
||||||
|
|
||||||
move |conn| {
|
|
||||||
conn.execute(
|
|
||||||
"UPDATE lock SET description = ?3, title = ?2 WHERE guild_id = ?1",
|
|
||||||
[guild_id.to_string(), title, description],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let embed_description = format_embed_description(description).expect("Format error");
|
|
||||||
|
|
||||||
if result == 1 {
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Edited lock message: {}", &title))
|
|
||||||
.description(&embed_description);
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
} else {
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Error editing lock message: {}", &title))
|
|
||||||
.description(format!("{} rows were affected", result));
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete lock message
|
|
||||||
#[poise::command(
|
|
||||||
prefix_command,
|
|
||||||
slash_command,
|
|
||||||
required_permissions = "MANAGE_MESSAGES"
|
|
||||||
)]
|
|
||||||
pub async fn delete(ctx: Context<'_>) -> Result<(), Error> {
|
|
||||||
let data = ctx.data();
|
|
||||||
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
|
|
||||||
let guild_id = server_guild_id.to_string();
|
|
||||||
|
|
||||||
let result = data
|
|
||||||
.execute_db({
|
|
||||||
move |conn| conn.execute("DELETE FROM lock WHERE guild_id = ?1", [guild_id])
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if result == 1 {
|
|
||||||
let embed = CreateEmbed::new().title(format!("Deleted lock message for this server"));
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
} else {
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(format!("Error deleting lock message, ask Ryan"))
|
|
||||||
.description(format!("{} rows were affected", result));
|
|
||||||
ctx.send(CreateReply::default().embed(embed)).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
@ -62,20 +62,6 @@ pub fn init_tables(conn: &Connection) -> Result<()> {
|
||||||
.expect("Forum Channels Table Creation error");
|
.expect("Forum Channels Table Creation error");
|
||||||
}
|
}
|
||||||
|
|
||||||
let lock_table_exists = table_exists(conn, "lock").expect("Lock table exists error");
|
|
||||||
if !lock_table_exists {
|
|
||||||
conn.execute(
|
|
||||||
"CREATE TABLE lock (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
guild_id TEXT NOT NULL UNIQUE,
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
description TEXT NOT NULL
|
|
||||||
)",
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.expect("Lock Table Creation error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we need to create more tables we'll use this function
|
// if we need to create more tables we'll use this function
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use tokio::sync::Mutex;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod database;
|
mod database;
|
||||||
mod events;
|
mod events;
|
||||||
mod utils;
|
|
||||||
use crate::database::database::{init_db, init_tables};
|
use crate::database::database::{init_db, init_tables};
|
||||||
|
|
||||||
// Types used by all command functions
|
// Types used by all command functions
|
||||||
|
|
@ -90,7 +89,6 @@ async fn main() {
|
||||||
commands::info::help(),
|
commands::info::help(),
|
||||||
commands::faq::faq(),
|
commands::faq::faq(),
|
||||||
commands::forum::forum(),
|
commands::forum::forum(),
|
||||||
commands::lock::lock(),
|
|
||||||
],
|
],
|
||||||
event_handler: |ctx, event, framework, data| {
|
event_handler: |ctx, event, framework, data| {
|
||||||
Box::pin(event_handler(ctx, event, framework, data))
|
Box::pin(event_handler(ctx, event, framework, data))
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pub mod format;
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
use crate::Error;
|
|
||||||
|
|
||||||
pub fn format_embed_description<S: Into<String>>(description: S) -> Result<String, Error> {
|
|
||||||
let string_val = description.into();
|
|
||||||
Ok(str::replace(&string_val, "\\n", "\n"))
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue