Added auth to endpoints
This commit is contained in:
@@ -79,9 +79,30 @@ impl InsertUser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ResponseUser {
|
||||||
|
pub email: String,
|
||||||
|
pub role: String,
|
||||||
|
pub first_name: String,
|
||||||
|
pub last_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<QueryUser> for ResponseUser {
|
||||||
|
fn from(user: QueryUser) -> Self {
|
||||||
|
ResponseUser {
|
||||||
|
email: user.email,
|
||||||
|
role: user.role,
|
||||||
|
first_name: user.first_name,
|
||||||
|
last_name: user.last_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct JwtAuth {
|
pub struct JwtAuth {
|
||||||
pub access_token_uuid: uuid::Uuid
|
pub access_token_uuid: uuid::Uuid,
|
||||||
|
pub email: String,
|
||||||
|
pub role: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRequest for JwtAuth {
|
impl FromRequest for JwtAuth {
|
||||||
@@ -140,8 +161,8 @@ impl FromRequest for JwtAuth {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match QueryUser::get_by_email(&user_email) {
|
match QueryUser::get_by_email(&user_email) {
|
||||||
Ok(_) => {
|
Ok(user) => {
|
||||||
ready(Ok(JwtAuth { access_token_uuid }))
|
ready(Ok(JwtAuth { access_token_uuid, email: user.email, role: user.role }))
|
||||||
}
|
}
|
||||||
Err(err) => return ready(Err(ActixError::from(ServiceError {
|
Err(err) => return ready(Err(ActixError::from(ServiceError {
|
||||||
status: 500,
|
status: 500,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use log::error;
|
|||||||
use redis::AsyncCommands;
|
use redis::AsyncCommands;
|
||||||
use siren::ServiceError;
|
use siren::ServiceError;
|
||||||
|
|
||||||
use crate::{auth::{LoginRequest, RegisterUser, InsertUser, QueryUser, verify_password, generate_token, JwtAuth}, db};
|
use crate::{auth::{LoginRequest, RegisterUser, InsertUser, QueryUser, verify_password, generate_token, JwtAuth, ResponseUser}, db};
|
||||||
|
|
||||||
#[post("/register")]
|
#[post("/register")]
|
||||||
async fn register(user: web::Json<RegisterUser>) -> HttpResponse {
|
async fn register(user: web::Json<RegisterUser>) -> HttpResponse {
|
||||||
@@ -96,17 +96,17 @@ async fn login(request: web::Json<LoginRequest>) -> HttpResponse {
|
|||||||
|
|
||||||
let access_cookie = Cookie::build("access_token", access_token_details.token.clone().unwrap())
|
let access_cookie = Cookie::build("access_token", access_token_details.token.clone().unwrap())
|
||||||
.path("/")
|
.path("/")
|
||||||
.max_age(Duration::new(access_token_max_age, 0))
|
.max_age(Duration::new(access_token_max_age * 60, 0))
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish();
|
.finish();
|
||||||
let refresh_cookie = Cookie::build("refresh_token", refresh_token_details.token.clone().unwrap())
|
let refresh_cookie = Cookie::build("refresh_token", refresh_token_details.token.clone().unwrap())
|
||||||
.path("/")
|
.path("/")
|
||||||
.max_age(Duration::new(refresh_token_max_age, 0))
|
.max_age(Duration::new(refresh_token_max_age * 60, 0))
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish();
|
.finish();
|
||||||
let logged_in_cookie = Cookie::build("logged_in", "true")
|
let logged_in_cookie = Cookie::build("logged_in", "true")
|
||||||
.path("/")
|
.path("/")
|
||||||
.max_age(Duration::new(access_token_max_age, 0))
|
.max_age(Duration::new(access_token_max_age * 60, 0))
|
||||||
.http_only(false)
|
.http_only(false)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
@@ -135,10 +135,24 @@ async fn logout(req: HttpRequest, auth: JwtAuth) -> HttpResponse {
|
|||||||
|
|
||||||
#[get("/me")]
|
#[get("/me")]
|
||||||
async fn me(auth: JwtAuth) -> HttpResponse {
|
async fn me(auth: JwtAuth) -> HttpResponse {
|
||||||
HttpResponse::Ok().json(auth)
|
let query_user = match QueryUser::get_by_email(&auth.email) {
|
||||||
|
Ok(user) => user,
|
||||||
|
Err(err) => return ResponseError::error_response(&err)
|
||||||
|
};
|
||||||
|
let user: ResponseUser = query_user.into();
|
||||||
|
HttpResponse::Ok().json(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||||
|
let r = RegisterUser {
|
||||||
|
email: "admin".to_string(),
|
||||||
|
password: "admin".to_string(),
|
||||||
|
first_name: "Admin".to_string(),
|
||||||
|
last_name: "Admin".to_string(),
|
||||||
|
};
|
||||||
|
let mut u = r.convert_to_insert().unwrap();
|
||||||
|
u.role = "admin".to_string();
|
||||||
|
let _ = InsertUser::insert(u);
|
||||||
config.service(web::scope("auth")
|
config.service(web::scope("auth")
|
||||||
.service(register)
|
.service(register)
|
||||||
.service(login)
|
.service(login)
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ use serde::{Serialize, Deserialize};
|
|||||||
use serenity::model::prelude::{GuildChannel, ChannelType};
|
use serenity::model::prelude::{GuildChannel, ChannelType};
|
||||||
use siren::ServiceError;
|
use siren::ServiceError;
|
||||||
|
|
||||||
use crate::{AppState, bot::commands::audio::{play::play_track, join}, db::guilds::{InsertGuild, QueryGuild}};
|
use crate::{AppState, bot::commands::audio::{play::play_track, join}, db::guilds::{InsertGuild, QueryGuild}, auth::JwtAuth};
|
||||||
|
|
||||||
#[get("/guilds")]
|
#[get("/guilds")]
|
||||||
async fn get_guilds(data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn get_guilds(data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_results = &data.http.get_guilds(None, None).await;
|
let guild_results = &data.http.get_guilds(None, None).await;
|
||||||
let guilds = match guild_results {
|
let guilds = match guild_results {
|
||||||
Ok(guilds) => guilds,
|
Ok(guilds) => guilds,
|
||||||
@@ -22,7 +22,7 @@ async fn get_guilds(data: web::Data<Arc<AppState>>) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{id}/text")]
|
#[get("/{id}/text")]
|
||||||
async fn get_text_channels(id: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn get_text_channels(id: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let channel_results = &data.http.get_channels(id.parse::<u64>().unwrap()).await;
|
let channel_results = &data.http.get_channels(id.parse::<u64>().unwrap()).await;
|
||||||
let channels = match channel_results {
|
let channels = match channel_results {
|
||||||
Ok(channels) => channels.iter().filter(|c| c.kind == ChannelType::Text).collect::<Vec<&GuildChannel>>(),
|
Ok(channels) => channels.iter().filter(|c| c.kind == ChannelType::Text).collect::<Vec<&GuildChannel>>(),
|
||||||
@@ -35,7 +35,7 @@ async fn get_text_channels(id: web::Path<String>, data: web::Data<Arc<AppState>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{id}/voice")]
|
#[get("/{id}/voice")]
|
||||||
async fn get_voice_channels(id: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn get_voice_channels(id: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let channel_results = &data.http.get_channels(id.parse::<u64>().unwrap()).await;
|
let channel_results = &data.http.get_channels(id.parse::<u64>().unwrap()).await;
|
||||||
let channels = match channel_results {
|
let channels = match channel_results {
|
||||||
Ok(channels) => channels.iter().filter(|c| c.kind == ChannelType::Voice).collect::<Vec<&GuildChannel>>(),
|
Ok(channels) => channels.iter().filter(|c| c.kind == ChannelType::Voice).collect::<Vec<&GuildChannel>>(),
|
||||||
@@ -53,7 +53,7 @@ struct ChannelMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/text/{channel_id}/message")]
|
#[post("/{guild_id}/text/{channel_id}/message")]
|
||||||
async fn send_message(path: web::Path<(String, String)>, text: web::Json<ChannelMessage>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn send_message(path: web::Path<(String, String)>, text: web::Json<ChannelMessage>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let (guild_id, channel_id) = path.into_inner();
|
let (guild_id, channel_id) = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -115,7 +115,7 @@ struct PlayRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/{channel_id}/play")]
|
#[post("/{guild_id}/voice/{channel_id}/play")]
|
||||||
async fn play(path: web::Path<(String, String)>, play_request: web::Json<PlayRequest>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn play(path: web::Path<(String, String)>, play_request: web::Json<PlayRequest>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let (guild_id, channel_id) = path.into_inner();
|
let (guild_id, channel_id) = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -167,7 +167,7 @@ async fn play(path: web::Path<(String, String)>, play_request: web::Json<PlayReq
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/stop")]
|
#[post("/{guild_id}/voice/stop")]
|
||||||
async fn stop(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn stop(path: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -189,7 +189,7 @@ async fn stop(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/resume")]
|
#[post("/{guild_id}/voice/resume")]
|
||||||
async fn resume(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn resume(path: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -217,7 +217,7 @@ async fn resume(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> Http
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/pause")]
|
#[post("/{guild_id}/voice/pause")]
|
||||||
async fn pause(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn pause(path: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -250,7 +250,7 @@ struct SetVolume {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{guild_id}/voice/volume")]
|
#[get("/{guild_id}/voice/volume")]
|
||||||
async fn get_volume(path: web::Path<String>) -> HttpResponse {
|
async fn get_volume(path: web::Path<String>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -278,7 +278,7 @@ async fn get_volume(path: web::Path<String>) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/volume")]
|
#[post("/{guild_id}/voice/volume")]
|
||||||
async fn set_volume(path: web::Path<String>, volume: web::Json::<SetVolume>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn set_volume(path: web::Path<String>, volume: web::Json::<SetVolume>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
@@ -307,7 +307,7 @@ async fn set_volume(path: web::Path<String>, volume: web::Json::<SetVolume>, dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/{guild_id}/voice/skip")]
|
#[post("/{guild_id}/voice/skip")]
|
||||||
async fn skip(path: web::Path<String>, data: web::Data<Arc<AppState>>) -> HttpResponse {
|
async fn skip(path: web::Path<String>, data: web::Data<Arc<AppState>>, auth: JwtAuth) -> HttpResponse {
|
||||||
let guild_id = path.into_inner();
|
let guild_id = path.into_inner();
|
||||||
let guild_id = match guild_id.parse::<u64>() {
|
let guild_id = match guild_id.parse::<u64>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use log::error;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use siren::{GetResponse, Metadata, ServiceError};
|
use siren::{GetResponse, Metadata, ServiceError};
|
||||||
|
|
||||||
use crate::db::messages::{QueryMessage, QueryFilters, InsertMessage};
|
use crate::{db::messages::{QueryMessage, QueryFilters, InsertMessage}, auth::JwtAuth};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct GetAllParams {
|
struct GetAllParams {
|
||||||
@@ -21,7 +21,7 @@ struct GetAllParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/messages")]
|
#[get("/messages")]
|
||||||
async fn get_all(req: HttpRequest) -> HttpResponse {
|
async fn get_all(req: HttpRequest, auth: JwtAuth) -> HttpResponse {
|
||||||
let params = match web::Query::<GetAllParams>::from_query(req.query_string()) {
|
let params = match web::Query::<GetAllParams>::from_query(req.query_string()) {
|
||||||
Ok(params) => params,
|
Ok(params) => params,
|
||||||
Err(err) => return ResponseError::error_response(&ServiceError {
|
Err(err) => return ResponseError::error_response(&ServiceError {
|
||||||
@@ -64,7 +64,7 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/messages")]
|
#[post("/messages")]
|
||||||
async fn create(message: web::Json<InsertMessage>) -> HttpResponse {
|
async fn create(message: web::Json<InsertMessage>, auth: JwtAuth) -> HttpResponse {
|
||||||
match InsertMessage::insert(message.into_inner()) {
|
match InsertMessage::insert(message.into_inner()) {
|
||||||
Ok(message) => HttpResponse::Created().json(message),
|
Ok(message) => HttpResponse::Created().json(message),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use log::error;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use siren::{GetResponse, Metadata, ServiceError};
|
use siren::{GetResponse, Metadata, ServiceError};
|
||||||
|
|
||||||
use crate::db::spells::{QuerySpell, QueryFilters};
|
use crate::{db::spells::{QuerySpell, QueryFilters}, auth::JwtAuth};
|
||||||
|
|
||||||
use super::{Spell, InsertSpell};
|
use super::{Spell, InsertSpell};
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ async fn get_by_id(id: web::Path<String>) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/spells")]
|
#[post("/spells")]
|
||||||
async fn create(spell: web::Json<Spell>) -> HttpResponse {
|
async fn create(spell: web::Json<Spell>, auth: JwtAuth) -> HttpResponse {
|
||||||
match InsertSpell::insert(spell.into_inner().into()) {
|
match InsertSpell::insert(spell.into_inner().into()) {
|
||||||
Ok(spell) => HttpResponse::Created().json(Spell::from(spell)),
|
Ok(spell) => HttpResponse::Created().json(Spell::from(spell)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -145,7 +145,7 @@ async fn create(spell: web::Json<Spell>) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[put("/spells/{id}")]
|
#[put("/spells/{id}")]
|
||||||
async fn update(id: web::Path<String>, spell: web::Json<Spell>) -> HttpResponse {
|
async fn update(id: web::Path<String>, spell: web::Json<Spell>, auth: JwtAuth) -> HttpResponse {
|
||||||
let id = match id.parse::<i32>() {
|
let id = match id.parse::<i32>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
Err(err) => return ResponseError::error_response(&ServiceError {
|
Err(err) => return ResponseError::error_response(&ServiceError {
|
||||||
@@ -163,7 +163,7 @@ async fn update(id: web::Path<String>, spell: web::Json<Spell>) -> HttpResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/spells/{id}")]
|
#[delete("/spells/{id}")]
|
||||||
async fn delete(id: web::Path<String>) -> HttpResponse {
|
async fn delete(id: web::Path<String>, auth: JwtAuth) -> HttpResponse {
|
||||||
let id = match id.parse::<i32>() {
|
let id = match id.parse::<i32>() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
Err(err) => return ResponseError::error_response(&ServiceError {
|
Err(err) => return ResponseError::error_response(&ServiceError {
|
||||||
|
|||||||
13
ui/src/api/auth.ts
Normal file
13
ui/src/api/auth.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { getRequest, postRequest } from '.';
|
||||||
|
|
||||||
|
export async function login(email: string, password: string) {
|
||||||
|
return await postRequest('auth/login', { email, password }, { withCredentials: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function logout() {
|
||||||
|
return await postRequest('auth/logout', {}, { withCredentials: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function me() {
|
||||||
|
return await getRequest('auth/me', { withCredentials: true });
|
||||||
|
}
|
||||||
6
ui/src/api/auth.types.ts
Normal file
6
ui/src/api/auth.types.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface User {
|
||||||
|
email: string;
|
||||||
|
role: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@ import { getRequest, postRequest } from '.';
|
|||||||
import { GuildChannel, GuildInfo } from './guilds.types';
|
import { GuildChannel, GuildInfo } from './guilds.types';
|
||||||
|
|
||||||
export async function getGuilds(): Promise<GuildInfo[]> {
|
export async function getGuilds(): Promise<GuildInfo[]> {
|
||||||
const response = await getRequest('guilds', {});
|
const response = await getRequest('guilds');
|
||||||
return response?.data || { data: [] };
|
return response?.data || { data: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTextChannels(guildId: number): Promise<GuildChannel[]> {
|
export async function getTextChannels(guildId: number): Promise<GuildChannel[]> {
|
||||||
const response = await getRequest(`guilds/${guildId}/text`, {});
|
const response = await getRequest(`guilds/${guildId}/text`);
|
||||||
return response?.data || { data: [] };
|
return response?.data || { data: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ export async function sendMessage(guildId: number, channelId: number, message: s
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getVoiceChannels(guildId: number): Promise<GuildChannel[]> {
|
export async function getVoiceChannels(guildId: number): Promise<GuildChannel[]> {
|
||||||
const response = await getRequest(`guilds/${guildId}/voice`, {});
|
const response = await getRequest(`guilds/${guildId}/voice`);
|
||||||
return response?.data || { data: [] };
|
return response?.data || { data: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ export async function skipTrack(guildId: number): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getVolume(guildId: number): Promise<number> {
|
export async function getVolume(guildId: number): Promise<number> {
|
||||||
const response = await getRequest(`guilds/${guildId}/voice/volume`, {});
|
const response = await getRequest(`guilds/${guildId}/voice/volume`);
|
||||||
return response?.data?.volume || 0;
|
return response?.data?.volume || 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ const servicePort = process.env.SERVICE_PORT || 5000;
|
|||||||
|
|
||||||
export async function getRequest(
|
export async function getRequest(
|
||||||
url: string,
|
url: string,
|
||||||
params: AxiosRequestConfig<any>
|
config?: AxiosRequestConfig<any>
|
||||||
): Promise<AxiosResponse<any, any> | undefined> {
|
): Promise<AxiosResponse<any, any> | undefined> {
|
||||||
const response = await axios
|
const response = await axios
|
||||||
.get(`${serviceHost}:${servicePort}/${url}`, { params })
|
.get(`${serviceHost}:${servicePort}/${url}`, config)
|
||||||
.catch((error) => console.error(error));
|
.catch((error) => console.error(error));
|
||||||
return response || undefined;
|
return response || undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface GetSpellsParams {
|
|||||||
|
|
||||||
export async function getSpells(params?: GetSpellsParams): Promise<GetSpellsResponse> {
|
export async function getSpells(params?: GetSpellsParams): Promise<GetSpellsResponse> {
|
||||||
const response = await getRequest('dnd/spells', {
|
const response = await getRequest('dnd/spells', {
|
||||||
|
params: {
|
||||||
name: params?.name,
|
name: params?.name,
|
||||||
like_name: params?.like_name,
|
like_name: params?.like_name,
|
||||||
schools: params?.schools?.join(','),
|
schools: params?.schools?.join(','),
|
||||||
@@ -34,6 +35,7 @@ export async function getSpells(params?: GetSpellsParams): Promise<GetSpellsResp
|
|||||||
attack_type: params?.attack_type?.join(','),
|
attack_type: params?.attack_type?.join(','),
|
||||||
limit: params?.limit,
|
limit: params?.limit,
|
||||||
page: params?.page
|
page: params?.page
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return response?.data || { data: [] };
|
return response?.data || { data: [] };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { getRequest, postRequest } from '.';
|
|
||||||
|
|
||||||
export async function login(email: string, password: string) {
|
|
||||||
return await postRequest('users/login', { email, password }, { withCredentials: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function logout() {
|
|
||||||
return await postRequest('users/logout', {}, { withCredentials: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function ping() {
|
|
||||||
return await getRequest('users/ping', { withCredentials: true });
|
|
||||||
}
|
|
||||||
@@ -21,9 +21,16 @@ import {
|
|||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { login, logout, ping } from '@/api/users';
|
import { login, logout, me } from '@/api/auth';
|
||||||
|
import { User } from '@/api/auth.types';
|
||||||
|
|
||||||
const headerItems = [
|
interface HeaderItem {
|
||||||
|
name: string;
|
||||||
|
link: string;
|
||||||
|
role?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerItems: HeaderItem[] = [
|
||||||
{
|
{
|
||||||
name: 'Races',
|
name: 'Races',
|
||||||
link: '/races'
|
link: '/races'
|
||||||
@@ -54,24 +61,38 @@ const headerItems = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Management',
|
name: 'Management',
|
||||||
link: '/management'
|
link: '/management',
|
||||||
|
role: 'admin'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Topbar() {
|
export default function Topbar() {
|
||||||
const pathName = usePathname();
|
const pathName = usePathname();
|
||||||
const [showLogin, setShowLogin] = useState(false);
|
const [showLogin, setShowLogin] = useState(false);
|
||||||
const [authenticated, setAuthenticated] = useState(false);
|
const [headers, setHeaders] = useState<HeaderItem[]>([]);
|
||||||
// Check if the auth cookie is set
|
const [user, setUser] = useState<User | undefined>(undefined);
|
||||||
// If it is, show the user avatar
|
|
||||||
// If not, show the login button
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('cookies', Cookies.get());
|
if (Cookies.get('logged_in')) {
|
||||||
if (Cookies.get('auth')) {
|
me().then((response) => {
|
||||||
setAuthenticated(true);
|
if (response?.status == 200) {
|
||||||
|
setUser(response.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setUser(undefined);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const h: HeaderItem[] = [];
|
||||||
|
headerItems.forEach((item) => {
|
||||||
|
if (item.role == undefined || user?.role == item.role) {
|
||||||
|
h.push(item);
|
||||||
|
}
|
||||||
|
setHeaders(h);
|
||||||
|
});
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<nav className='navbar'>
|
<nav className='navbar'>
|
||||||
@@ -80,7 +101,7 @@ export default function Topbar() {
|
|||||||
Siren
|
Siren
|
||||||
</Link>
|
</Link>
|
||||||
<div className='header-items'>
|
<div className='header-items'>
|
||||||
{headerItems.map((item) => (
|
{headers.map((item) => (
|
||||||
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link} key={item.name}>
|
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link} key={item.name}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -93,26 +114,25 @@ export default function Topbar() {
|
|||||||
<Avatar style={{ cursor: 'pointer' }} />
|
<Avatar style={{ cursor: 'pointer' }} />
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
{!authenticated && <Menu.Item onClick={() => setShowLogin(true)}>Login</Menu.Item>}
|
{!user && <Menu.Item onClick={() => setShowLogin(true)}>Login</Menu.Item>}
|
||||||
{authenticated && (
|
{user && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const response = await logout();
|
const response = await logout();
|
||||||
if (response?.status == 200) {
|
if (response?.status == 200) {
|
||||||
Cookies.remove('auth');
|
Cookies.remove('logged_in');
|
||||||
setAuthenticated(false);
|
setUser(undefined);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)}
|
)}
|
||||||
<Menu.Item onClick={() => ping()}>Ping</Menu.Item>
|
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<LoginModal showLogin={showLogin} setShowLogin={setShowLogin} setAuthenticated={setAuthenticated} />
|
<LoginModal showLogin={showLogin} setShowLogin={setShowLogin} setUser={setUser} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -120,20 +140,29 @@ export default function Topbar() {
|
|||||||
function LoginModal({
|
function LoginModal({
|
||||||
showLogin,
|
showLogin,
|
||||||
setShowLogin,
|
setShowLogin,
|
||||||
setAuthenticated
|
setUser
|
||||||
}: {
|
}: {
|
||||||
showLogin: boolean;
|
showLogin: boolean;
|
||||||
setShowLogin: (show: boolean) => void;
|
setShowLogin: (show: boolean) => void;
|
||||||
setAuthenticated: (authenticated: boolean) => void;
|
setUser: (user: User) => void;
|
||||||
}) {
|
}) {
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
email: '',
|
email: '',
|
||||||
password: ''
|
password: '',
|
||||||
|
remember: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
setShowLogin(false);
|
||||||
|
if (!form.values.remember) {
|
||||||
|
form.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={showLogin} onClose={() => setShowLogin(false)} withCloseButton={false}>
|
<Modal opened={showLogin} onClose={onClose} withCloseButton={false}>
|
||||||
<Container>
|
<Container>
|
||||||
<Title ta='center'>Welcome back!</Title>
|
<Title ta='center'>Welcome back!</Title>
|
||||||
<Text c='dimmed' size='sm' ta='center' mt={5}>
|
<Text c='dimmed' size='sm' ta='center' mt={5}>
|
||||||
@@ -148,8 +177,12 @@ function LoginModal({
|
|||||||
onSubmit={form.onSubmit(async (values) => {
|
onSubmit={form.onSubmit(async (values) => {
|
||||||
const response = await login(values.email, values.password);
|
const response = await login(values.email, values.password);
|
||||||
if (response?.status == 200) {
|
if (response?.status == 200) {
|
||||||
setShowLogin(false);
|
me().then((response) => {
|
||||||
setAuthenticated(true);
|
if (response?.status == 200) {
|
||||||
|
setUser(response.data);
|
||||||
|
}
|
||||||
|
onClose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -162,7 +195,7 @@ function LoginModal({
|
|||||||
{...form.getInputProps('password')}
|
{...form.getInputProps('password')}
|
||||||
/>
|
/>
|
||||||
<Group justify='space-between' mt='lg'>
|
<Group justify='space-between' mt='lg'>
|
||||||
<Checkbox label='Remember me' />
|
<Checkbox label='Remember me' {...form.getInputProps('remember')} />
|
||||||
<Anchor component='button' size='sm'>
|
<Anchor component='button' size='sm'>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
|||||||
Reference in New Issue
Block a user