Skip to content
Snippets Groups Projects
Commit 9fafa97a authored by stephen's avatar stephen
Browse files

Merge pull request 'DIR and publishable programs' (#3) from more_features into master

parents 10f035d1 7db2fe39
No related branches found
No related tags found
No related merge requests found
-- This file should undo anything in `up.sql`
ALTER TABLE user_programs DROP COLUMN published;
\ No newline at end of file
ALTER TABLE user_programs ADD COLUMN published INT NOT NULL DEFAULT 0;
\ No newline at end of file
...@@ -8,7 +8,7 @@ use serenity::model::channel::{Message, ReactionType}; ...@@ -8,7 +8,7 @@ use serenity::model::channel::{Message, ReactionType};
use serenity::model::id::UserId; use serenity::model::id::UserId;
use serenity::model::prelude::Ready; use serenity::model::prelude::Ready;
use serenity::prelude::*; use serenity::prelude::*;
use std::borrow::Cow; use std::borrow::{Borrow, Cow};
use std::collections::HashMap; use std::collections::HashMap;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
...@@ -86,6 +86,25 @@ impl Handler { ...@@ -86,6 +86,25 @@ impl Handler {
"LIST" => { "LIST" => {
self.interpreter_list(msg, ctx).await; self.interpreter_list(msg, ctx).await;
} }
"DIR" => {
if self.list_saved_programs(msg, ctx).await.is_none() {
msg.channel_id
.say(&ctx, "Could not get list of programs from database.")
.await
.unwrap();
}
}
"PUBDIR" => {
if self.list_published_programs(msg, ctx).await.is_none() {
msg.channel_id
.say(
&ctx,
"Could not get list of published programs from database.",
)
.await
.unwrap();
}
}
_ => { _ => {
if let Some(name) = line.strip_prefix("SAVE ") { if let Some(name) = line.strip_prefix("SAVE ") {
self.interpreter_save(name, msg, ctx).await; self.interpreter_save(name, msg, ctx).await;
...@@ -95,6 +114,43 @@ impl Handler { ...@@ -95,6 +114,43 @@ impl Handler {
self.interpreter_load(name, msg, ctx).await; self.interpreter_load(name, msg, ctx).await;
} }
if let Some(name) = line.strip_prefix("PUB ") {
if self.publish_program(name, msg, ctx).await.is_none() {
msg.channel_id
.say(&ctx, format!("Could not publish {}.", name))
.await
.unwrap();
}
}
if let Some(name) = line.strip_prefix("UNPUB ") {
if self.unpublish_program(name, msg, ctx).await.is_none() {
msg.channel_id
.say(&ctx, &format!("Could not unpublish {}.", name))
.await
.unwrap();
}
}
if let Some(id_str) = line.strip_prefix("PUBLOAD ") {
match id_str.parse::<i32>() {
Ok(id) => {
if self.load_published_program(msg, ctx, id).await.is_none() {
msg.channel_id
.say(&ctx, format!("Could not load {}.", id))
.await
.unwrap();
}
}
Err(_) => {
msg.channel_id
.say(&ctx, "PUBLOAD requires a numerical ID.")
.await
.unwrap();
}
}
}
let mut split = line.splitn(2, ' '); let mut split = line.splitn(2, ' ');
let first = split.next().unwrap(); let first = split.next().unwrap();
if let Ok(num) = first.parse::<u32>() { if let Ok(num) = first.parse::<u32>() {
...@@ -139,6 +195,84 @@ impl Handler { ...@@ -139,6 +195,84 @@ impl Handler {
.insert(msg.author.id, Program::new()); .insert(msg.author.id, Program::new());
} }
async fn list_saved_programs(&self, msg: &Message, ctx: &Context) -> Option<()> {
let program_names =
Program::list_programs_by_user(self.conn.lock().ok()?.borrow(), msg.author.id)?;
msg.channel_id
.say(
&ctx,
format!(
"You have {} programs saved:\r\n```\r\n{}\r\n```",
program_names.len(),
program_names.join("\r\n")
),
)
.await
.ok()?;
Some(())
}
async fn list_published_programs(&self, msg: &Message, ctx: &Context) -> Option<()> {
let program_names: Vec<String> =
Program::list_published_programs(self.conn.lock().ok()?.borrow())?
.iter()
.map(|row| format!("{}\t{}", row.0, row.1))
.collect();
msg.channel_id
.say(
&ctx,
format!(
"Found {} public programs:\r\n```\r\nid\tname\r\n{}\r\n```\r\n Load one with `PUBLOAD <id>`",
program_names.len(),
program_names.join("\r\n")),
)
.await
.unwrap();
Some(())
}
async fn publish_program(&self, name: &str, msg: &Message, ctx: &Context) -> Option<()> {
Program::set_program_published(self.conn.lock().ok()?.borrow(), name, msg.author.id, true)?;
msg.channel_id
.say(&ctx, format!("Published {}.", name))
.await
.unwrap();
Some(())
}
async fn unpublish_program(&self, name: &str, msg: &Message, ctx: &Context) -> Option<()> {
Program::set_program_published(
self.conn.lock().ok()?.borrow(),
name,
msg.author.id,
false,
)?;
msg.channel_id
.say(&ctx, format!("Published {}.", name))
.await
.unwrap();
Some(())
}
async fn load_published_program(&self, msg: &Message, ctx: &Context, id: i32) -> Option<()> {
let name = get_user_programs!(&self, &msg.author.id)
.load_published_program(&self.conn.lock().ok()?.borrow(), id)?;
msg.channel_id
.say(&ctx, format!("Loaded {} (\"{}\") into memory.", id, name))
.await
.unwrap();
Some(())
}
async fn interpreter_list(&self, msg: &Message, ctx: &Context) { async fn interpreter_list(&self, msg: &Message, ctx: &Context) {
msg.channel_id msg.channel_id
.say( .say(
......
...@@ -18,6 +18,65 @@ impl Program { ...@@ -18,6 +18,65 @@ impl Program {
} }
} }
pub fn list_programs_by_user(conn: &PgConnection, user_id: UserId) -> Option<Vec<String>> {
user_programs
.filter(columns::discord_user_id.eq(BigDecimal::from_u64(*user_id.as_u64()).unwrap()))
.select(columns::name)
.get_results(conn)
.ok()
}
pub fn list_published_programs(conn: &PgConnection) -> Option<Vec<(i32, String)>> {
user_programs
.filter(columns::published.eq(1))
.select((columns::id, columns::name))
.load(conn)
.ok()
}
pub fn load_published_program(&mut self, conn: &PgConnection, id: i32) -> Option<String> {
let program: Vec<(String, String)> = user_programs
.filter(columns::id.eq(id).and(columns::published.eq(1)))
.limit(1)
.select((columns::name, columns::code))
.get_results(conn)
.ok()?;
if program.is_empty() {
return None;
}
let name = &program[0].0;
let code = &program[0].1;
self.parse_string(code)?;
Some(name.to_string())
}
pub fn set_program_published(
conn: &PgConnection,
name: &str,
user_id: UserId,
published: bool,
) -> Option<()> {
if diesel::update(
user_programs.filter(
columns::discord_user_id
.eq(BigDecimal::from_u64(*user_id.as_u64()).unwrap())
.and(columns::name.eq(name)),
),
)
.set(columns::published.eq(if published { 1 } else { 0 }))
.execute(conn)
.ok()? == 1
{
Some(())
} else {
None
}
}
pub fn stringify(&self) -> String { pub fn stringify(&self) -> String {
let mut code: Vec<(u32, String)> = let mut code: Vec<(u32, String)> =
self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect(); self.code.iter().map(|(a, b)| (*a, b.to_owned())).collect();
......
table! { table! {
user_programs (id) { user_programs (id) {
id -> Int4, id -> Int4,
discord_user_id -> Numeric, discord_user_id -> Numeric,
name -> Varchar, name -> Varchar,
code -> Text, code -> Text,
} published -> Int4,
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment