update commands
This commit is contained in:
parent
27ac44182d
commit
e89b0fe30e
|
@ -1,2 +1,4 @@
|
||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
|
*.db
|
||||||
|
*.wal
|
|
@ -1,9 +1,6 @@
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use poise::command;
|
use poise::command;
|
||||||
|
|
||||||
use crate::database::Database;
|
use crate::database::*;
|
||||||
|
|
||||||
const HELP_MESSAGE: &str = "
|
const HELP_MESSAGE: &str = "
|
||||||
Hello fellow human! I am a bot that can help you adding new technologies to a git repository.
|
Hello fellow human! I am a bot that can help you adding new technologies to a git repository.
|
||||||
|
@ -34,15 +31,12 @@ To get help, just type:
|
||||||
/help
|
/help
|
||||||
```
|
```
|
||||||
";
|
";
|
||||||
const AUTHORIZED_USERS: [u64; 1] = [252497456447750144];
|
|
||||||
|
|
||||||
type Error = Box<dyn std::error::Error + Send + Sync>;
|
type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
type Context<'a> = poise::Context<'a, MsgData, Error>;
|
type Context<'a> = poise::Context<'a, MsgData, Error>;
|
||||||
|
|
||||||
pub struct MsgData {}
|
pub struct MsgData {}
|
||||||
|
|
||||||
pub static DB: OnceCell<Mutex<Database>> = OnceCell::new();
|
|
||||||
|
|
||||||
/// Show help for all commands
|
/// Show help for all commands
|
||||||
#[command(slash_command, prefix_command)]
|
#[command(slash_command, prefix_command)]
|
||||||
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
@ -58,7 +52,9 @@ pub async fn add(
|
||||||
#[description = "Technology name"] technology: String,
|
#[description = "Technology name"] technology: String,
|
||||||
#[description = "Git repository link"] link: String,
|
#[description = "Git repository link"] link: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
ctx.say(format!("Added {technology} with link {link}"))
|
add_tech(link.clone(), technology.clone())?;
|
||||||
|
|
||||||
|
ctx.say(format!("Added {technology} with link {link}",))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -67,7 +63,21 @@ pub async fn add(
|
||||||
/// List all available technologies
|
/// List all available technologies
|
||||||
#[command(slash_command, prefix_command)]
|
#[command(slash_command, prefix_command)]
|
||||||
pub async fn list(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn list(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
ctx.say("Listed all technologies").await?;
|
let techs = list_tech()?;
|
||||||
|
if techs.len() == 0 {
|
||||||
|
ctx.say("No technologies saved").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.say(format!(
|
||||||
|
"Saved technologies: {}",
|
||||||
|
techs
|
||||||
|
.iter()
|
||||||
|
.map(|tech| format!("[{}]({})", tech.name, tech.link))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -78,7 +88,12 @@ pub async fn search(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "Technology name"] technology: String,
|
#[description = "Technology name"] technology: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
ctx.say(format!("Found {technology}")).await?;
|
if let Some(tech) = search_tech(technology.clone())? {
|
||||||
|
ctx.say(format!("Name: {}\nLink: {}", tech.name, tech.link))
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
ctx.say("No technology found").await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -89,13 +104,37 @@ pub async fn remove(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "Technology name"] technology: String,
|
#[description = "Technology name"] technology: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if !AUTHORIZED_USERS.contains(&ctx.author().id.0) {
|
if is_auth_user(ctx.author().id.to_string())? {
|
||||||
ctx.say("You don't have permission to remove a technology")
|
ctx.say("You don't have permission to remove a technology")
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.say(format!("Removed {technology}")).await?;
|
remove_tech(technology)?;
|
||||||
|
|
||||||
|
ctx.say("Technology removed").await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a technology from the technologies list
|
||||||
|
#[command(slash_command, prefix_command)]
|
||||||
|
pub async fn add_auth_user(
|
||||||
|
ctx: Context<'_>,
|
||||||
|
#[description = "Discord user ID"] id: String,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if !std::env::var("ADMIN_USERS")
|
||||||
|
.expect("missing ADMIN_USERS")
|
||||||
|
.contains(&ctx.author().id.to_string())
|
||||||
|
{
|
||||||
|
ctx.say("You don't have permission to add a new user")
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
set_auth_user(id)?;
|
||||||
|
|
||||||
|
ctx.say("User added!").await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
134
src/database.rs
134
src/database.rs
|
@ -1,78 +1,88 @@
|
||||||
use polodb_core::{
|
use once_cell::sync::OnceCell;
|
||||||
bson::{doc, oid::ObjectId},
|
use polodb_core::{bson::doc, Database};
|
||||||
Database as DB,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::io::{Error, ErrorKind};
|
||||||
io::{Error, ErrorKind},
|
|
||||||
str::FromStr,
|
pub static DB: OnceCell<Database> = OnceCell::new();
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||||
struct Technology {
|
pub struct Technology {
|
||||||
link: String,
|
pub link: String,
|
||||||
name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct AuthorizedUser {
|
struct AuthorizedUser {
|
||||||
name: String,
|
discord_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Database {
|
/// Add a new technology to the database.
|
||||||
pub db: DB,
|
pub fn add_tech(link: String, name: String) -> Result<(), Error> {
|
||||||
|
DB.get()
|
||||||
|
.unwrap()
|
||||||
|
.collection::<Technology>("technologies")
|
||||||
|
.insert_one(Technology { link, name })
|
||||||
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
pub fn remove_tech(name: String) -> Result<(), Error> {
|
||||||
/// Create a new database instance.
|
DB.get()
|
||||||
pub fn new() -> Self {
|
.unwrap()
|
||||||
Self {
|
.collection::<Technology>("technologies")
|
||||||
db: DB::open_file("test-polo.db").expect("failed to initialize database"),
|
.delete_one(doc! { "name": name })
|
||||||
}
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?;
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a new technology to the database.
|
Ok(())
|
||||||
pub fn add_tech(&self, link: String, name: String) -> Result<String, Error> {
|
}
|
||||||
Ok(self
|
|
||||||
.db
|
|
||||||
.collection::<Technology>("technologies")
|
|
||||||
.insert_one(Technology { link, name })
|
|
||||||
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
|
||||||
.inserted_id
|
|
||||||
.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_tech(&self, id: &str) -> Result<(), Error> {
|
pub fn list_tech() -> Result<Vec<Technology>, Error> {
|
||||||
self.db
|
Ok(DB
|
||||||
.collection::<Technology>("technologies")
|
.get()
|
||||||
.delete_one(doc! { "_id": Some(ObjectId::from_str(id).map_err(|err| Error::new(ErrorKind::InvalidInput, err))?) })
|
.unwrap()
|
||||||
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?;
|
.collection("technologies")
|
||||||
|
.find(None)
|
||||||
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
||||||
|
.filter(|doc| doc.is_ok())
|
||||||
|
.map(|doc| doc.unwrap())
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
pub fn search_tech(name: String) -> Result<Option<Technology>, Error> {
|
||||||
}
|
if let Some(tech) = DB
|
||||||
|
.get()
|
||||||
pub fn list_tech(&self) -> Result<Vec<Technology>, Error> {
|
.unwrap()
|
||||||
Ok(self
|
.collection::<Technology>("technologies")
|
||||||
.db
|
.find(doc! { "name": {"$eq": name} })
|
||||||
.collection("technologies")
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
||||||
.find(None)
|
.next()
|
||||||
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
{
|
||||||
.filter(|doc| doc.is_ok())
|
Ok(Some(
|
||||||
.map(|doc| doc.unwrap())
|
tech.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?,
|
||||||
.collect())
|
))
|
||||||
}
|
} else {
|
||||||
|
Ok(None)
|
||||||
pub fn search_tech(&self, name: String) -> Result<Technology, Error> {
|
|
||||||
if let Some(tech) = self
|
|
||||||
.db
|
|
||||||
.collection::<Technology>("technologies")
|
|
||||||
.find(doc! { "$eq": [{"name": name}] })
|
|
||||||
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
|
||||||
.next()
|
|
||||||
{
|
|
||||||
Ok(tech.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?)
|
|
||||||
} else {
|
|
||||||
Err(Error::new(ErrorKind::NotFound, "Technology not found"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_auth_user(discord_id: String) -> Result<(), Error> {
|
||||||
|
DB.get()
|
||||||
|
.unwrap()
|
||||||
|
.collection("authorized_users")
|
||||||
|
.insert_one(AuthorizedUser { discord_id })
|
||||||
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_auth_user(discord_id: String) -> Result<bool, Error> {
|
||||||
|
Ok(DB
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.collection::<AuthorizedUser>("authorized_users")
|
||||||
|
.find(doc! { "$eq": [{"discord_id": discord_id}] })
|
||||||
|
.map_err(|err| Error::new(ErrorKind::InvalidInput, err))?
|
||||||
|
.next()
|
||||||
|
.is_some())
|
||||||
|
}
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -3,15 +3,15 @@ mod database;
|
||||||
|
|
||||||
use poise::serenity_prelude as serenity;
|
use poise::serenity_prelude as serenity;
|
||||||
|
|
||||||
use commands::{add, help, list, remove, search, MsgData, DB};
|
use commands::{add, add_auth_user, help, list, remove, search, MsgData};
|
||||||
|
use database::DB;
|
||||||
|
use polodb_core::Database;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
DB.set(Mutex)
|
|
||||||
|
|
||||||
let framework = poise::Framework::builder()
|
let framework = poise::Framework::builder()
|
||||||
.options(poise::FrameworkOptions {
|
.options(poise::FrameworkOptions {
|
||||||
commands: vec![help(), add(), list(), search(), remove()],
|
commands: vec![help(), add(), list(), search(), remove(), add_auth_user()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.token(std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN"))
|
.token(std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN"))
|
||||||
|
@ -25,5 +25,9 @@ async fn main() {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DB.get_or_init(|| {
|
||||||
|
Database::open_file(std::env::var("DB_PATH").expect("missing DB_PATH"))
|
||||||
|
.expect("failed to initialize database")
|
||||||
|
});
|
||||||
framework.run().await.unwrap();
|
framework.run().await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue