diff --git a/service/src/bot/api/model.rs b/service/src/bot/api/model.rs deleted file mode 100644 index e69de29..0000000 diff --git a/service/src/bot/commands/audio/play.rs b/service/src/bot/commands/audio/play.rs index b4ffbae..4eb53f5 100644 --- a/service/src/bot/commands/audio/play.rs +++ b/service/src/bot/commands/audio/play.rs @@ -9,8 +9,7 @@ use serenity::model::application::interaction::application_command::ApplicationC use siren::ServiceError; use songbird::{EventHandler, Songbird}; -use crate::bot::commands::audio::{leave, add_song, get_songbird}; -use crate::storage::guilds::QueryGuild; +use crate::bot::{guilds::QueryGuild, commands::audio::{leave, add_song, get_songbird}}; use super::{create_response, edit_response, join_by_user}; diff --git a/service/src/bot/commands/audio/volume.rs b/service/src/bot/commands/audio/volume.rs index 7bf96ec..5a60c0e 100644 --- a/service/src/bot/commands/audio/volume.rs +++ b/service/src/bot/commands/audio/volume.rs @@ -7,7 +7,7 @@ use serenity::builder::CreateApplicationCommand; use serenity::model::application::interaction::application_command::ApplicationCommandInteraction; use songbird::Songbird; -use crate::storage::guilds::InsertGuild; +use crate::bot::guilds::InsertGuild; use super::{get_songbird, create_response, edit_response}; diff --git a/service/src/bot/api/mod.rs b/service/src/bot/guilds/mod.rs similarity index 100% rename from service/src/bot/api/mod.rs rename to service/src/bot/guilds/mod.rs diff --git a/service/src/storage/guilds/model.rs b/service/src/bot/guilds/model.rs similarity index 100% rename from service/src/storage/guilds/model.rs rename to service/src/bot/guilds/model.rs diff --git a/service/src/bot/api/routes.rs b/service/src/bot/guilds/routes.rs similarity index 87% rename from service/src/bot/api/routes.rs rename to service/src/bot/guilds/routes.rs index a75ff26..eaf8f10 100644 --- a/service/src/bot/api/routes.rs +++ b/service/src/bot/guilds/routes.rs @@ -1,18 +1,16 @@ use std::{sync::Arc, pin::Pin}; use actix_web::{get, post, web, HttpResponse, ResponseError}; -use log::warn; use serde::{Serialize, Deserialize}; use serenity::model::prelude::{GuildChannel, ChannelType}; use siren::{ServiceError, Response}; -use crate::{AppState, bot::commands::audio::{play::play_track, join}, storage::guilds::QueryGuild, auth::{JwtAuth, verify_role}}; +use crate::{AppState, bot::commands::audio::{play::play_track, join}, bot::guilds::QueryGuild, auth::{JwtAuth, verify_role}}; #[get("/guilds")] async fn get_guilds(data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_results = &data.http.get_guilds(None, None).await; let guilds = match guild_results { @@ -30,9 +28,8 @@ async fn get_guilds(data: web::Data>, auth: JwtAuth) -> HttpRespon #[get("/{id}/text")] async fn get_text_channels(id: web::Path, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let channel_results = &data.http.get_channels(id.parse::().unwrap()).await; let channels = match channel_results { @@ -50,9 +47,8 @@ async fn get_text_channels(id: web::Path, data: web::Data> #[get("/{id}/voice")] async fn get_voice_channels(id: web::Path, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let channel_results = &data.http.get_channels(id.parse::().unwrap()).await; let channels = match channel_results { @@ -75,9 +71,8 @@ struct ChannelMessage { #[post("/{guild_id}/text/{channel_id}/message")] async fn send_message(path: web::Path<(String, String)>, text: web::Json, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let (guild_id, channel_id) = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -136,9 +131,8 @@ struct PlayRequest { #[post("/{guild_id}/voice/{channel_id}/play")] async fn play(path: web::Path<(String, String)>, play_request: web::Json, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let (guild_id, channel_id) = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -186,9 +180,8 @@ async fn play(path: web::Path<(String, String)>, play_request: web::Json, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -211,9 +204,8 @@ async fn stop(path: web::Path, data: web::Data>, auth: Jwt #[post("/{guild_id}/voice/resume")] async fn resume(path: web::Path, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -241,9 +233,8 @@ async fn resume(path: web::Path, data: web::Data>, auth: J #[post("/{guild_id}/voice/pause")] async fn pause(path: web::Path, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -276,9 +267,8 @@ struct SetVolume { #[get("/{guild_id}/voice/volume")] async fn get_volume(path: web::Path, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -306,9 +296,8 @@ async fn get_volume(path: web::Path, auth: JwtAuth) -> HttpResponse { #[post("/{guild_id}/voice/volume")] async fn set_volume(path: web::Path, volume: web::Json::, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { @@ -337,9 +326,8 @@ async fn set_volume(path: web::Path, volume: web::Json::, dat #[post("/{guild_id}/voice/skip")] async fn skip(path: web::Path, data: web::Data>, auth: JwtAuth) -> HttpResponse { - let _ = match verify_role(&auth, "admin") { - Ok(_) => {}, - Err(err) => return ResponseError::error_response(&err) + if let Err(err) = verify_role(&auth, "admin") { + return ResponseError::error_response(&err) }; let guild_id = path.into_inner(); let guild_id = match guild_id.parse::() { diff --git a/service/src/bot/handler.rs b/service/src/bot/handler.rs index b7c3db5..c4458f8 100644 --- a/service/src/bot/handler.rs +++ b/service/src/bot/handler.rs @@ -5,7 +5,7 @@ use serenity::model::gateway::Ready; use serenity::model::channel::Message; use serenity::prelude::*; -use crate::storage::guilds::InsertGuild; +use crate::bot::guilds::InsertGuild; use super::commands; use super::commands::audio::create_response; diff --git a/service/src/storage/messages/mod.rs b/service/src/bot/messages/mod.rs similarity index 100% rename from service/src/storage/messages/mod.rs rename to service/src/bot/messages/mod.rs diff --git a/service/src/storage/messages/model.rs b/service/src/bot/messages/model.rs similarity index 100% rename from service/src/storage/messages/model.rs rename to service/src/bot/messages/model.rs diff --git a/service/src/storage/messages/routes.rs b/service/src/bot/messages/routes.rs similarity index 96% rename from service/src/storage/messages/routes.rs rename to service/src/bot/messages/routes.rs index da2f560..11ce3fa 100644 --- a/service/src/storage/messages/routes.rs +++ b/service/src/bot/messages/routes.rs @@ -3,7 +3,7 @@ use log::error; use serde::{Serialize, Deserialize}; use siren::{Response, Metadata, ServiceError}; -use crate::{storage::messages::{QueryMessage, QueryFilters, InsertMessage}, auth::{JwtAuth, verify_role}}; +use crate::{bot::messages::{QueryMessage, QueryFilters, InsertMessage}, auth::{JwtAuth, verify_role}}; #[derive(Serialize, Deserialize)] struct GetAllParams { diff --git a/service/src/bot/mod.rs b/service/src/bot/mod.rs index 5e4fa6a..7f94ede 100644 --- a/service/src/bot/mod.rs +++ b/service/src/bot/mod.rs @@ -1,3 +1,4 @@ -pub mod api; pub mod commands; +pub mod guilds; pub mod handler; +pub mod messages; diff --git a/service/src/main.rs b/service/src/main.rs index 9799f30..080fa07 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -122,11 +122,11 @@ async fn main() -> std::io::Result<()> { App::new() .wrap(cors) .app_data(web::Data::new(Arc::clone(&app_data))) - .configure(crate::storage::messages::init_routes) .configure(crate::auth::init_routes) .configure(crate::users::init_routes) .configure(crate::dnd::spells::init_routes) - .configure(crate::bot::api::init_routes) + .configure(crate::bot::guilds::init_routes) + .configure(crate::bot::messages::init_routes) }) .bind(format!("{}:{}", host, port)) { Ok(b) => { diff --git a/service/src/storage/guilds/mod.rs b/service/src/storage/guilds/mod.rs deleted file mode 100644 index 24e3024..0000000 --- a/service/src/storage/guilds/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod model; - -pub use model::*; \ No newline at end of file diff --git a/service/src/storage/mod.rs b/service/src/storage/mod.rs index 21e5b5d..404625e 100644 --- a/service/src/storage/mod.rs +++ b/service/src/storage/mod.rs @@ -8,8 +8,6 @@ use log::{error, info}; use r2d2; use std::env; -pub mod guilds; -pub mod messages; pub mod schema; type DbPool = r2d2::Pool>; diff --git a/ui/src/api/auth.ts b/ui/src/api/auth.ts index 3978e7a..7831fad 100644 --- a/ui/src/api/auth.ts +++ b/ui/src/api/auth.ts @@ -1,9 +1,9 @@ import Cookies from 'js-cookie'; -import { get, post } from '.'; +import { getRequest, postRequest } from '.'; import { RegisterUser, ResponseAuth } from './auth.types'; export async function login(email: string, password: string): Promise { - const response = await post('auth/login', { email, password }); + const response = await postRequest('auth/login', { email, password }); if (response?.status === 200) { return response.json(); } else { @@ -12,7 +12,7 @@ export async function login(email: string, password: string): Promise { - const response = await post('auth/register', user); + const response = await postRequest('auth/register', user); if (response?.status === 201) { return true; } else { @@ -21,11 +21,11 @@ export async function register(user: RegisterUser): Promise { } export async function logout() { - return await post('auth/logout', {}); + return await postRequest('auth/logout', {}); } export async function refresh(refresh_token_rotation?: boolean): Promise { - const response = await get('auth/refresh', { refresh_token_rotation }); + const response = await getRequest('auth/refresh', { refresh_token_rotation }); if (response?.status === 200) { return response.json(); } else { @@ -34,7 +34,7 @@ export async function refresh(refresh_token_rotation?: boolean): Promise { - const response = await get('auth/me'); + const response = await getRequest('auth/me'); if (response?.status === 200) { return response.json(); } else { diff --git a/ui/src/api/guilds.ts b/ui/src/api/guilds.ts index 900a247..c8984f1 100644 --- a/ui/src/api/guilds.ts +++ b/ui/src/api/guilds.ts @@ -1,54 +1,54 @@ -import { APIResponse, get, post } from '.'; +import { APIResponse, getRequest, postRequest } from '.'; import { GuildChannel, GuildInfo } from './guilds.types'; export async function getGuilds(): Promise { - const response = await get('guilds'); + const response = await getRequest('guilds'); const guilds: APIResponse = await response?.json(); - return guilds.data || []; + return guilds?.data || []; } export async function getTextChannels(guildId: number): Promise { - const response = await get(`guilds/${guildId}/text`); + const response = await getRequest(`guilds/${guildId}/text`); const channels: APIResponse = await response?.json(); return channels.data || []; } export async function sendMessage(guildId: number, channelId: number, message: string): Promise { - await post(`guilds/${guildId}/text/${channelId}/message`, { message }); + await postRequest(`guilds/${guildId}/text/${channelId}/message`, { message }); } export async function getVoiceChannels(guildId: number): Promise { - const response = await get(`guilds/${guildId}/voice`); + const response = await getRequest(`guilds/${guildId}/voice`); const channels: APIResponse = await response?.json(); return channels.data || []; } export async function playTrack(guildId: number, channelId: number, track: string): Promise { - await post(`guilds/${guildId}/voice/${channelId}/play`, { track_url: track }); + await postRequest(`guilds/${guildId}/voice/${channelId}/play`, { track_url: track }); } export async function stopTrack(guildId: number): Promise { - await post(`guilds/${guildId}/voice/stop`, {}); + await postRequest(`guilds/${guildId}/voice/stop`, {}); } export async function pauseTrack(guildId: number): Promise { - await post(`guilds/${guildId}/voice/pause`, {}); + await postRequest(`guilds/${guildId}/voice/pause`, {}); } export async function resumeTrack(guildId: number): Promise { - await post(`guilds/${guildId}/voice/resume`, {}); + await postRequest(`guilds/${guildId}/voice/resume`, {}); } export async function setVolume(guildId: number, volume: number): Promise { - await post(`guilds/${guildId}/voice/volume`, { volume: `${volume}` }); + await postRequest(`guilds/${guildId}/voice/volume`, { volume: `${volume}` }); } export async function skipTrack(guildId: number): Promise { - await post(`guilds/${guildId}/voice/skip`, {}); + await postRequest(`guilds/${guildId}/voice/skip`, {}); } export async function getVolume(guildId: number): Promise { - const response = await get(`guilds/${guildId}/voice/volume`); + const response = await getRequest(`guilds/${guildId}/voice/volume`); const volume: number = await response?.json(); return volume || 0; } diff --git a/ui/src/api/index.ts b/ui/src/api/index.ts index 572ad22..076de6b 100644 --- a/ui/src/api/index.ts +++ b/ui/src/api/index.ts @@ -2,7 +2,7 @@ const serviceHost = process.env.SERVICE_HOST || 'http://localhost'; const servicePort = process.env.SERVICE_PORT || 5000; const baseURL = `${serviceHost}:${servicePort}`; -export async function get(endpoint: string, params: Record = {}): Promise { +export async function getRequest(endpoint: string, params: Record = {}): Promise { // Remove undefined params Object.keys(params).forEach((key) => params[key] === undefined && delete params[key]); const urlParams = new URLSearchParams(params); @@ -19,10 +19,10 @@ interface PostOptions { type?: 'json' | 'form'; } -export async function post(endpoint: string, body: any, options?: PostOptions): Promise { +export async function postRequest(endpoint: string, body?: any, options?: PostOptions): Promise { const url = `${baseURL}/${endpoint}`; let response; - if (!options?.type || options.type === 'json') { + if (body && (!options?.type || options.type === 'json')) { response = await fetch(url, { method: 'POST', headers: { diff --git a/ui/src/api/spells.ts b/ui/src/api/spells.ts index db838f4..e3fc0d1 100644 --- a/ui/src/api/spells.ts +++ b/ui/src/api/spells.ts @@ -1,4 +1,4 @@ -import { get } from '.'; +import { getRequest } from '.'; import { GetSpellsResponse } from './spells.types'; interface GetSpellsParams { @@ -19,7 +19,7 @@ interface GetSpellsParams { } export async function getSpells(params?: GetSpellsParams): Promise { - const response = await get('dnd/spells', { + const response = await getRequest('dnd/spells', { name: params?.name, like_name: params?.like_name, schools: params?.schools?.join(','), diff --git a/ui/src/api/users.ts b/ui/src/api/users.ts index c6ece1f..e14ea66 100644 --- a/ui/src/api/users.ts +++ b/ui/src/api/users.ts @@ -1,7 +1,7 @@ -import { get, post } from '.'; +import { getRequest, postRequest } from '.'; export async function getPicture(): Promise { - const response = await get('users/picture'); + const response = await getRequest('users/picture'); if (response?.status === 200) { return response.blob(); } else { @@ -13,7 +13,7 @@ export async function setPicture(payload: File): Promise { const data = new FormData(); data.append('data', payload); // TODO: Figure out why the form data object is empty - const response = await post('users/picture', data, { + const response = await postRequest('users/picture', data, { type: 'form' }); if (response?.status === 200) { diff --git a/ui/src/app/admin/page.tsx b/ui/src/app/admin/page.tsx index ea66e85..a08f5e3 100644 --- a/ui/src/app/admin/page.tsx +++ b/ui/src/app/admin/page.tsx @@ -14,31 +14,33 @@ import { stopTrack } from '@/api/guilds'; import { GuildChannel, GuildInfo } from '@/api/guilds.types'; +import { userState } from '@/state/auth'; import { Button, Card, Grid, Select, Slider, Tabs, TextInput, Textarea } from '@mantine/core'; import { useForm } from '@mantine/form'; +import { useRouter } from 'next/navigation'; import React, { useEffect, useState } from 'react'; +import { useRecoilValue } from 'recoil'; export default function Page() { + const user = useRecoilValue(userState); const [guilds, setGuilds] = useState([]); const [activeGuild, setActiveGuild] = useState(null); - const [voiceChannels, setVoiceChannels] = useState([]); - const [guildVolume, setGuildVolume] = useState(50.0); + const router = useRouter(); useEffect(() => { - getGuilds().then((g) => { - setGuilds(g); - if (g.length > 0) { - setActiveGuild(g[0]); - } - }); - }, []); - - useEffect(() => { - if (activeGuild) { - getVoiceChannels(activeGuild.id).then((c) => setVoiceChannels(c)); - getVolume(activeGuild.id).then((v) => setGuildVolume(v)); + // Check if the user is logged in and an admin, otherwise redirect to the home page + // if (!user || !user.roles.includes('admin')) { + if (!user || user.role !== 'admin') { + router.push('/'); + } else { + getGuilds().then((g) => { + setGuilds(g); + if (g.length > 0) { + setActiveGuild(g[0]); + } + }); } - }, [activeGuild]); + }, []); return ( @@ -171,11 +173,9 @@ function VoiceChannelsCard({ guild }: { guild: GuildInfo | null }) {
{ - e.preventDefault(); - }} - > + style={{ margin: '1em' }} + onSubmit={form.onSubmit((values) => playTrack(guild!.id, activeChannel.id, values.trackUrl))} + >