Added Location and location ownership/rights to gamenight.
This commit is contained in:
860
backend-actix/Cargo.lock
generated
860
backend-actix/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,8 @@
|
||||
use std::{fs::{exists, read_dir, remove_dir_all, File}, io::Write, process::Command};
|
||||
|
||||
use std::{
|
||||
fs::{exists, read_dir, remove_dir_all, File},
|
||||
io::Write,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
println!("cargo::rerun-if-changed=gamenight-api.yaml");
|
||||
@@ -7,12 +10,19 @@ fn main() {
|
||||
if exists("src/models").unwrap() {
|
||||
remove_dir_all("src/models").unwrap();
|
||||
}
|
||||
|
||||
let _ =
|
||||
Command::new("openapi-generator")
|
||||
.args(["generate", "-i", "gamenight-api.yaml", "-g", "rust", "--global-property", "models"])
|
||||
.output()
|
||||
.expect("Failed to generate models sources for the gamenight API");
|
||||
|
||||
let _ = Command::new("openapi-generator")
|
||||
.args([
|
||||
"generate",
|
||||
"-i",
|
||||
"gamenight-api.yaml",
|
||||
"-g",
|
||||
"rust",
|
||||
"--global-property",
|
||||
"models",
|
||||
])
|
||||
.output()
|
||||
.expect("Failed to generate models sources for the gamenight API");
|
||||
|
||||
let mut file = File::create("src/models/mod.rs").unwrap();
|
||||
let paths = read_dir("./src/models").unwrap();
|
||||
@@ -21,10 +31,10 @@ fn main() {
|
||||
let path = path.path();
|
||||
let stem = path.file_stem().unwrap();
|
||||
if stem == "mod" {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
let line = format!("pub mod {};\n", stem.to_str().unwrap());
|
||||
let _ = file.write(line.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@ paths:
|
||||
parameters: []
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/users:
|
||||
get:
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/UsersResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/user:
|
||||
post:
|
||||
summary: ''
|
||||
@@ -242,9 +253,72 @@ paths:
|
||||
$ref: '#/components/requestBodies/OwnedGamesRequest'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/location:
|
||||
get:
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/LocationResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'422':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/GetLocationRequest'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
post:
|
||||
responses:
|
||||
'200':
|
||||
description: 'Ok'
|
||||
$ref: '#/components/responses/LocationIdResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'422':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/AddLocationRequest'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/locations:
|
||||
get:
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/LocationsResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'422':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/location_authorize:
|
||||
post:
|
||||
responses:
|
||||
'200':
|
||||
description: 'Ok'
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'422':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/AuthorizeLocationRequest'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
/authorized_location_user_ids:
|
||||
get:
|
||||
responses:
|
||||
'200':
|
||||
$ref: "#/components/responses/UserIdsResponse"
|
||||
'401':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
'422':
|
||||
$ref: '#/components/responses/FailureResponse'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/AuthorizedLocationUserIdsRequest'
|
||||
security:
|
||||
- JWT-Auth: []
|
||||
|
||||
|
||||
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Gamenight:
|
||||
@@ -326,6 +400,14 @@ components:
|
||||
type: string
|
||||
required:
|
||||
- user_id
|
||||
LocationId:
|
||||
title: LocationId
|
||||
type: object
|
||||
properties:
|
||||
location_id:
|
||||
type: string
|
||||
required:
|
||||
- location_id
|
||||
AddGamenightRequestBody:
|
||||
title: AddGamenightRequestBody
|
||||
type: object
|
||||
@@ -401,7 +483,49 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
UserIdsResponse:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/UserId"
|
||||
AddLocationRequestBody:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
note:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
Location:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
note:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
AuthorizeLocationRequestBody:
|
||||
type: object
|
||||
properties:
|
||||
location_id:
|
||||
type: string
|
||||
user_id:
|
||||
type: string
|
||||
op:
|
||||
type: string
|
||||
enum: [grant, revoke]
|
||||
required:
|
||||
- location_id
|
||||
- user_id
|
||||
- op
|
||||
requestBodies:
|
||||
LoginRequest:
|
||||
content:
|
||||
@@ -473,6 +597,27 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserId'
|
||||
GetLocationRequest:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LocationId'
|
||||
AddLocationRequest:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AddLocationRequestBody'
|
||||
AuthorizeLocationRequest:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AuthorizeLocationRequestBody'
|
||||
AuthorizedLocationUserIdsRequest:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LocationId'
|
||||
|
||||
responses:
|
||||
TokenResponse:
|
||||
description: Example response
|
||||
@@ -500,6 +645,14 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Gamenight'
|
||||
UsersResponse:
|
||||
description: List of all Users
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
GamenightResponse:
|
||||
description: A gamenight being hosted
|
||||
content:
|
||||
@@ -532,6 +685,34 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GameIdsResponse'
|
||||
UserIdsResponse:
|
||||
description: A list of user ids.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserIdsResponse'
|
||||
LocationResponse:
|
||||
description: A location
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Location'
|
||||
LocationIdResponse:
|
||||
description: A location Id
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LocationId'
|
||||
|
||||
LocationsResponse:
|
||||
description: A list of all LocationsResponse
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Location'
|
||||
|
||||
securitySchemes:
|
||||
JWT-Auth:
|
||||
type: http
|
||||
|
||||
@@ -3,19 +3,19 @@ pub mod models;
|
||||
pub mod request;
|
||||
|
||||
use actix_cors::Cors;
|
||||
use actix_web::middleware::Logger;
|
||||
use actix_web::HttpServer;
|
||||
use actix_web::App;
|
||||
use actix_web::http;
|
||||
use actix_web::middleware::Logger;
|
||||
use actix_web::web;
|
||||
use request::{*, login, register, gamenights};
|
||||
use tracing_actix_web::TracingLogger;
|
||||
use actix_web::App;
|
||||
use actix_web::HttpServer;
|
||||
use gamenight_database::*;
|
||||
use request::{gamenights, login, register, *};
|
||||
use tracing_actix_web::TracingLogger;
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let url = "postgres://root:root@127.0.0.1/gamenight";
|
||||
|
||||
|
||||
let pool = get_connection_pool(url);
|
||||
|
||||
let mut conn = pool.get_conn();
|
||||
@@ -26,11 +26,11 @@ async fn main() -> std::io::Result<()> {
|
||||
HttpServer::new(move || {
|
||||
let cors = Cors::default()
|
||||
.allowed_origin("0.0.0.0")
|
||||
.allowed_origin_fn(|_origin, _req_head| { true })
|
||||
.allowed_methods(vec!["GET", "POST"])
|
||||
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
|
||||
.allowed_header(http::header::CONTENT_TYPE)
|
||||
.max_age(3600);
|
||||
.allowed_origin_fn(|_origin, _req_head| true)
|
||||
.allowed_methods(vec!["GET", "POST"])
|
||||
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
|
||||
.allowed_header(http::header::CONTENT_TYPE)
|
||||
.max_age(3600);
|
||||
|
||||
App::new()
|
||||
.wrap(cors)
|
||||
@@ -44,6 +44,7 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(gamenight_post)
|
||||
.service(gamenight_get)
|
||||
.service(get_user)
|
||||
.service(get_users)
|
||||
.service(get_user_unauthenticated)
|
||||
.service(post_join_gamenight)
|
||||
.service(post_leave_gamenight)
|
||||
@@ -55,8 +56,12 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(post_own_game)
|
||||
.service(post_disown_game)
|
||||
.service(get_owned_games)
|
||||
.service(get_locations)
|
||||
.service(post_location)
|
||||
.service(post_location_authorize)
|
||||
.service(get_authorized_location_user_ids)
|
||||
})
|
||||
.bind(("::1", 8080))?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
use std::future::{Ready, ready};
|
||||
use std::future::{ready, Ready};
|
||||
|
||||
use actix_web::{FromRequest, http, HttpRequest, dev::Payload, web::Data};
|
||||
use actix_web::{dev::Payload, http, web::Data, FromRequest, HttpRequest};
|
||||
use chrono::Utc;
|
||||
use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use gamenight_database::{user::{get_user, User}, DbPool};
|
||||
use gamenight_database::{
|
||||
user::{get_user, User},
|
||||
DbPool,
|
||||
};
|
||||
|
||||
use super::error::ApiError;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Claims {
|
||||
exp: i64,
|
||||
uid: Uuid
|
||||
uid: Uuid,
|
||||
}
|
||||
|
||||
pub struct AuthUser(pub User);
|
||||
@@ -25,24 +28,31 @@ pub struct AuthUser(pub User);
|
||||
// pub role: Role,
|
||||
// }
|
||||
|
||||
impl From<User> for AuthUser {
|
||||
impl From<User> for AuthUser {
|
||||
fn from(value: User) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_claims(req: &HttpRequest) -> Result<Claims, ApiError> {
|
||||
let token = req.headers()
|
||||
fn get_claims(req: &HttpRequest) -> Result<Claims, ApiError> {
|
||||
let token = req
|
||||
.headers()
|
||||
.get(http::header::AUTHORIZATION)
|
||||
.map(|h| h.to_str().unwrap().split_at(7).1.to_string());
|
||||
|
||||
let token = token.ok_or(ApiError{
|
||||
let token = token.ok_or(ApiError {
|
||||
status: 400,
|
||||
message: "JWT-token was not specified in the Authorization header as Bearer: token".to_string()
|
||||
message: "JWT-token was not specified in the Authorization header as Bearer: token"
|
||||
.to_string(),
|
||||
})?;
|
||||
|
||||
let secret = "secret";
|
||||
Ok(decode::<Claims>(token.as_str(), &DecodingKey::from_secret(secret.as_bytes()), &Validation::default())?.claims)
|
||||
Ok(decode::<Claims>(
|
||||
token.as_str(),
|
||||
&DecodingKey::from_secret(secret.as_bytes()),
|
||||
&Validation::default(),
|
||||
)?
|
||||
.claims)
|
||||
}
|
||||
|
||||
pub fn get_token(user: &User) -> Result<String, ApiError> {
|
||||
@@ -55,7 +65,8 @@ pub fn get_token(user: &User) -> Result<String, ApiError> {
|
||||
Ok(encode(
|
||||
&Header::default(),
|
||||
&claims,
|
||||
&EncodingKey::from_secret(secret.as_bytes()))?)
|
||||
&EncodingKey::from_secret(secret.as_bytes()),
|
||||
)?)
|
||||
}
|
||||
|
||||
impl FromRequest for AuthUser {
|
||||
@@ -63,15 +74,15 @@ impl FromRequest for AuthUser {
|
||||
type Future = Ready<Result<Self, Self::Error>>;
|
||||
|
||||
fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
|
||||
ready(
|
||||
(|| -> Result<AuthUser, ApiError>{
|
||||
let pool = req.app_data::<Data<DbPool>>().expect("No database configured");
|
||||
let mut conn = pool.get().expect("couldn't get db connection from pool");
|
||||
let uid = get_claims(req)?.uid;
|
||||
let user = get_user(&mut conn, uid)?;
|
||||
|
||||
Ok(user.into())
|
||||
})()
|
||||
)
|
||||
ready((|| -> Result<AuthUser, ApiError> {
|
||||
let pool = req
|
||||
.app_data::<Data<DbPool>>()
|
||||
.expect("No database configured");
|
||||
let mut conn = pool.get().expect("couldn't get db connection from pool");
|
||||
let uid = get_claims(req)?.uid;
|
||||
let user = get_user(&mut conn, uid)?;
|
||||
|
||||
Ok(user.into())
|
||||
})())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use actix_web::{
|
||||
error::BlockingError,
|
||||
http::{header::ContentType, StatusCode},
|
||||
HttpResponse, ResponseError,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
use actix_web::{ResponseError, error::BlockingError, HttpResponse, http::{header::ContentType, StatusCode}};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use validator::ValidationErrors;
|
||||
|
||||
use gamenight_database::error::DatabaseError;
|
||||
@@ -9,7 +13,7 @@ use gamenight_database::error::DatabaseError;
|
||||
pub struct ApiError {
|
||||
#[serde(skip_serializing)]
|
||||
pub status: u16,
|
||||
pub message: String
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl Display for ApiError {
|
||||
@@ -21,9 +25,9 @@ impl Display for ApiError {
|
||||
impl ResponseError for ApiError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(StatusCode::from_u16(self.status).unwrap())
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DatabaseError> for ApiError {
|
||||
@@ -31,7 +35,7 @@ impl From<DatabaseError> for ApiError {
|
||||
ApiError {
|
||||
//Todo, split this in unrecoverable and schema error
|
||||
status: 500,
|
||||
message: value.0
|
||||
message: value.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +44,7 @@ impl From<BlockingError> for ApiError {
|
||||
fn from(value: BlockingError) -> Self {
|
||||
ApiError {
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +53,7 @@ impl From<serde_json::Error> for ApiError {
|
||||
fn from(value: serde_json::Error) -> Self {
|
||||
ApiError {
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +62,7 @@ impl From<jsonwebtoken::errors::Error> for ApiError {
|
||||
fn from(value: jsonwebtoken::errors::Error) -> Self {
|
||||
ApiError {
|
||||
status: 500,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +71,7 @@ impl From<ValidationErrors> for ApiError {
|
||||
fn from(value: ValidationErrors) -> Self {
|
||||
ApiError {
|
||||
status: 422,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +80,7 @@ impl From<chrono::ParseError> for ApiError {
|
||||
fn from(value: chrono::ParseError) -> Self {
|
||||
ApiError {
|
||||
status: 422,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +89,7 @@ impl From<uuid::Error> for ApiError {
|
||||
fn from(value: uuid::Error) -> Self {
|
||||
ApiError {
|
||||
status: 422,
|
||||
message: value.to_string()
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,73 @@
|
||||
use actix_web::{get, http::header::ContentType, post, web, HttpResponse, Responder};
|
||||
use gamenight_database::{game::{insert_game, load_game, rename_game}, owned_game::{disown_game, own_game, owned_games, OwnedGame}, DbPool, GetConnection};
|
||||
use gamenight_database::{
|
||||
game::{insert_game, load_game, rename_game},
|
||||
owned_game::{disown_game, own_game, owned_games, OwnedGame},
|
||||
DbPool, GetConnection,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{models::{add_game_request_body::AddGameRequestBody, game::Game, game_id::GameId, rename_game_request_body::RenameGameRequestBody}, request::{authorization::AuthUser, error::ApiError}};
|
||||
use crate::{
|
||||
models::{
|
||||
add_game_request_body::AddGameRequestBody, game::Game, game_id::GameId,
|
||||
rename_game_request_body::RenameGameRequestBody,
|
||||
},
|
||||
request::{authorization::AuthUser, error::ApiError},
|
||||
};
|
||||
|
||||
#[get("/games")]
|
||||
pub async fn get_games(pool: web::Data<DbPool>, _user: AuthUser) -> Result<impl Responder, ApiError> {
|
||||
pub async fn get_games(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let games: Vec<gamenight_database::game::Game> = gamenight_database::games(&mut conn)?;
|
||||
let model: Vec<Game> = games.iter().map(|x| {
|
||||
Game {
|
||||
let model: Vec<Game> = games
|
||||
.iter()
|
||||
.map(|x| Game {
|
||||
id: x.id.to_string(),
|
||||
name: x.name.clone(),
|
||||
}}
|
||||
).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?)
|
||||
)
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
impl From<AddGameRequestBody> for gamenight_database::game::Game {
|
||||
fn from(value: AddGameRequestBody) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
name: value.name
|
||||
name: value.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/game")]
|
||||
pub async fn get_game(pool: web::Data<DbPool>, _user: AuthUser, game_id: web::Json<GameId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn get_game(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
game_id: web::Json<GameId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let db_game = load_game(&mut conn, Uuid::parse_str(&game_id.0.game_id)?)?;
|
||||
|
||||
let model = Game {
|
||||
let model = Game {
|
||||
id: db_game.id.to_string(),
|
||||
name: db_game.name
|
||||
name: db_game.name,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?)
|
||||
)
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
#[post("/game")]
|
||||
pub async fn post_game(pool: web::Data<DbPool>, _user: AuthUser, game_data: web::Json<AddGameRequestBody>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn post_game(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
game_data: web::Json<AddGameRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
insert_game(&mut conn, game_data.0.into())?;
|
||||
|
||||
@@ -55,40 +75,68 @@ pub async fn post_game(pool: web::Data<DbPool>, _user: AuthUser, game_data: web:
|
||||
}
|
||||
|
||||
#[post("/rename_game")]
|
||||
pub async fn post_rename_game(pool: web::Data<DbPool>, _user: AuthUser, game_data: web::Json<RenameGameRequestBody>) -> Result <impl Responder, ApiError> {
|
||||
pub async fn post_rename_game(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
game_data: web::Json<RenameGameRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
rename_game(&mut conn, Uuid::parse_str(&game_data.0.id)?, game_data.0.name)?;
|
||||
rename_game(
|
||||
&mut conn,
|
||||
Uuid::parse_str(&game_data.0.id)?,
|
||||
game_data.0.name,
|
||||
)?;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[post("/own")]
|
||||
pub async fn post_own_game(pool: web::Data<DbPool>, user: AuthUser, game_id: web::Json<GameId>) -> Result <impl Responder, ApiError> {
|
||||
pub async fn post_own_game(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
game_id: web::Json<GameId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
own_game(&mut conn, OwnedGame { user_id: user.0.id, game_id: Uuid::parse_str(&game_id.0.game_id)? })?;
|
||||
own_game(
|
||||
&mut conn,
|
||||
OwnedGame {
|
||||
user_id: user.0.id,
|
||||
game_id: Uuid::parse_str(&game_id.0.game_id)?,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[post("/disown")]
|
||||
pub async fn post_disown_game(pool: web::Data<DbPool>, user: AuthUser, game_id: web::Json<GameId>) -> Result <impl Responder, ApiError> {
|
||||
pub async fn post_disown_game(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
game_id: web::Json<GameId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
disown_game(&mut conn, OwnedGame { user_id: user.0.id, game_id: Uuid::parse_str(&game_id.0.game_id)? })?;
|
||||
disown_game(
|
||||
&mut conn,
|
||||
OwnedGame {
|
||||
user_id: user.0.id,
|
||||
game_id: Uuid::parse_str(&game_id.0.game_id)?,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[get("/owned_games")]
|
||||
pub async fn get_owned_games(pool: web::Data<DbPool>, user: AuthUser) -> Result <impl Responder, ApiError> {
|
||||
pub async fn get_owned_games(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let game_ids = owned_games(&mut conn, user.0.id)?;
|
||||
|
||||
let model : Vec<String> = game_ids.iter().map(|x| {
|
||||
x.to_string()
|
||||
}).collect();
|
||||
let model: Vec<String> = game_ids.iter().map(|x| x.to_string()).collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?)
|
||||
)
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
use actix_web::{get, web, Responder, http::header::ContentType, HttpResponse, post};
|
||||
use actix_web::{get, http::header::ContentType, post, web, HttpResponse, Responder};
|
||||
use chrono::{DateTime, ParseError};
|
||||
use uuid::Uuid;
|
||||
|
||||
use gamenight_database::{gamenight, DbPool, GetConnection};
|
||||
|
||||
use crate::{models::{add_gamenight_request_body::AddGamenightRequestBody, gamenight::Gamenight, get_gamenight_request_body::GetGamenightRequestBody}, request::authorization::AuthUser};
|
||||
use crate::request::error::ApiError;
|
||||
|
||||
use crate::{
|
||||
models::{
|
||||
add_gamenight_request_body::AddGamenightRequestBody, gamenight::Gamenight,
|
||||
get_gamenight_request_body::GetGamenightRequestBody,
|
||||
},
|
||||
request::authorization::AuthUser,
|
||||
};
|
||||
|
||||
impl AddGamenightRequestBody {
|
||||
pub fn into_with_user(&self, user: AuthUser) -> Result<gamenight::Gamenight, ParseError> {
|
||||
@@ -14,7 +19,8 @@ impl AddGamenightRequestBody {
|
||||
datetime: DateTime::parse_from_rfc3339(&self.datetime)?.with_timezone(&chrono::Utc),
|
||||
id: Uuid::new_v4(),
|
||||
name: self.name.clone(),
|
||||
owner_id: user.0.id
|
||||
owner_id: user.0.id,
|
||||
location_id: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -26,38 +32,49 @@ impl From<GetGamenightRequestBody> for Uuid {
|
||||
}
|
||||
|
||||
#[get("/gamenights")]
|
||||
pub async fn gamenights(pool: web::Data<DbPool>, _user: AuthUser) -> Result<impl Responder, ApiError> {
|
||||
pub async fn gamenights(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let gamenights: Vec<gamenight::Gamenight> = gamenight_database::gamenights(&mut conn)?;
|
||||
let model: Vec<Gamenight> = gamenights.iter().map(|x| {
|
||||
Gamenight {
|
||||
let model: Vec<Gamenight> = gamenights
|
||||
.iter()
|
||||
.map(|x| Gamenight {
|
||||
id: x.id.to_string(),
|
||||
name: x.name.clone(),
|
||||
datetime: x.datetime.to_rfc3339(),
|
||||
owner_id: x.owner_id.to_string()
|
||||
}}
|
||||
).collect();
|
||||
owner_id: x.owner_id.to_string(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?)
|
||||
)
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
#[post("/gamenight")]
|
||||
pub async fn gamenight_post(pool: web::Data<DbPool>, user: AuthUser, gamenight_data: web::Json<AddGamenightRequestBody>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn gamenight_post(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
gamenight_data: web::Json<AddGamenightRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
|
||||
|
||||
gamenight::add_gamenight(&mut conn, gamenight_data.into_with_user(user)?)?;
|
||||
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[get("/gamenight")]
|
||||
pub async fn gamenight_get(pool: web::Data<DbPool>, _user: AuthUser, gamenight_data: web::Json<GetGamenightRequestBody>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn gamenight_get(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
gamenight_data: web::Json<GetGamenightRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let gamenight = gamenight::get_gamenight(&mut conn, gamenight_data.into_inner().into())?;
|
||||
let model = Gamenight{
|
||||
let model = Gamenight {
|
||||
id: gamenight.id.to_string(),
|
||||
datetime: gamenight.datetime.to_rfc3339(),
|
||||
name: gamenight.name,
|
||||
@@ -67,4 +84,4 @@ pub async fn gamenight_get(pool: web::Data<DbPool>, _user: AuthUser, gamenight_d
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,55 @@
|
||||
use actix_web::{post, web, HttpResponse, Responder};
|
||||
use gamenight_database::{gamenight_participants::{delete_gamenight_participant, insert_gamenight_participant, GamenightParticipant}, DbPool, GetConnection};
|
||||
use gamenight_database::{
|
||||
gamenight_participants::{
|
||||
delete_gamenight_participant, insert_gamenight_participant, GamenightParticipant,
|
||||
},
|
||||
DbPool, GetConnection,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{models::gamenight_id::GamenightId, request::{authorization::AuthUser, error::ApiError}};
|
||||
use crate::{
|
||||
models::gamenight_id::GamenightId,
|
||||
request::{authorization::AuthUser, error::ApiError},
|
||||
};
|
||||
|
||||
#[post("/join")]
|
||||
pub async fn post_join_gamenight(pool: web::Data<DbPool>, user: AuthUser, gamenight_id: web::Json<GamenightId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn post_join_gamenight(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
gamenight_id: web::Json<GamenightId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
web::block(move || -> Result<usize, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
Ok(insert_gamenight_participant(&mut conn, GamenightParticipant {
|
||||
gamenight_id: Uuid::parse_str(&gamenight_id.gamenight_id)?,
|
||||
user_id: user.0.id
|
||||
})?)
|
||||
}).await??;
|
||||
Ok(insert_gamenight_participant(
|
||||
&mut conn,
|
||||
GamenightParticipant {
|
||||
gamenight_id: Uuid::parse_str(&gamenight_id.gamenight_id)?,
|
||||
user_id: user.0.id,
|
||||
},
|
||||
)?)
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
#[post("/leave")]
|
||||
pub async fn post_leave_gamenight(pool: web::Data<DbPool>, user: AuthUser, gamenight_id: web::Json<GamenightId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn post_leave_gamenight(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
gamenight_id: web::Json<GamenightId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
web::block(move || -> Result<usize, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let participant = GamenightParticipant {
|
||||
gamenight_id: Uuid::parse_str(&gamenight_id.gamenight_id)?,
|
||||
user_id: user.0.id
|
||||
user_id: user.0.id,
|
||||
};
|
||||
let x = delete_gamenight_participant(&mut conn, participant)?;
|
||||
|
||||
Ok(x)
|
||||
}).await??;
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
|
||||
65
backend-actix/src/request/location.rs
Normal file
65
backend-actix/src/request/location.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use actix_web::{get, http::header::ContentType, post, web, HttpResponse, Responder};
|
||||
use gamenight_database::{
|
||||
location::{insert_location, locations},
|
||||
DbPool, GetConnection,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
models::{
|
||||
add_location_request_body::AddLocationRequestBody, location::Location,
|
||||
location_id::LocationId,
|
||||
},
|
||||
request::{authorization::AuthUser, error::ApiError},
|
||||
};
|
||||
|
||||
impl From<AddLocationRequestBody> for gamenight_database::location::Location {
|
||||
fn from(value: AddLocationRequestBody) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
name: value.name,
|
||||
address: value.address,
|
||||
note: value.note,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/locations")]
|
||||
pub async fn get_locations(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let games: Vec<gamenight_database::location::Location> = locations(&mut conn)?;
|
||||
let model: Vec<Location> = games
|
||||
.iter()
|
||||
.map(|x| Location {
|
||||
id: x.id.to_string(),
|
||||
name: x.name.clone(),
|
||||
address: x.address.clone(),
|
||||
note: x.note.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
#[post("/location")]
|
||||
pub async fn post_location(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
game_data: web::Json<AddLocationRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let uuid = insert_location(&mut conn, game_data.0.into())?;
|
||||
|
||||
let model = LocationId {
|
||||
location_id: uuid.to_string(),
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
79
backend-actix/src/request/location_owner.rs
Normal file
79
backend-actix/src/request/location_owner.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use actix_web::{get, http::header::ContentType, post, web, HttpResponse, Responder};
|
||||
use gamenight_database::{
|
||||
location_owner::{grant_permission, location_permissions, revoke_permission, LocationOwner},
|
||||
user::Role,
|
||||
DbPool, GetConnection,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
models::{
|
||||
authorize_location_request_body::{
|
||||
AuthorizeLocationRequestBody,
|
||||
Op::{Grant, Revoke},
|
||||
},
|
||||
location_id::LocationId,
|
||||
user_id::UserId,
|
||||
},
|
||||
request::{authorization::AuthUser, error::ApiError},
|
||||
};
|
||||
|
||||
impl<'a> TryFrom<&'a AuthorizeLocationRequestBody> for LocationOwner {
|
||||
type Error = ApiError;
|
||||
|
||||
fn try_from(value: &'a AuthorizeLocationRequestBody) -> Result<Self, Self::Error> {
|
||||
Ok(LocationOwner {
|
||||
location_id: Uuid::parse_str(&value.location_id)?,
|
||||
user_id: Uuid::parse_str(&value.user_id)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/location_authorize")]
|
||||
pub async fn post_location_authorize(
|
||||
pool: web::Data<DbPool>,
|
||||
user: AuthUser,
|
||||
auth_data: web::Json<AuthorizeLocationRequestBody>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
|
||||
let inner_auth_data = &auth_data.into_inner();
|
||||
let location_owner: LocationOwner = inner_auth_data.try_into()?;
|
||||
let authorized = location_permissions(&mut conn, location_owner.location_id)?;
|
||||
if user.0.role != Role::Admin && !authorized.contains(&user.0.id) {
|
||||
Ok(HttpResponse::Unauthorized())
|
||||
} else {
|
||||
match inner_auth_data.op {
|
||||
Grant => grant_permission(&mut conn, location_owner)?,
|
||||
Revoke => revoke_permission(&mut conn, location_owner)?,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for UserId {
|
||||
fn from(value: Uuid) -> Self {
|
||||
Self {
|
||||
user_id: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/authorized_location_user_ids")]
|
||||
pub async fn get_authorized_location_user_ids(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
location_id: web::Json<LocationId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
|
||||
let permissions =
|
||||
location_permissions(&mut conn, Uuid::parse_str(&location_id.0.location_id)?)?;
|
||||
|
||||
let model: Vec<UserId> = permissions.into_iter().map(Into::into).collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
@@ -1,27 +1,33 @@
|
||||
|
||||
mod user_handlers;
|
||||
mod gamenight_handlers;
|
||||
mod error;
|
||||
mod authorization;
|
||||
mod join_gamenight;
|
||||
mod participant_handlers;
|
||||
mod error;
|
||||
mod game;
|
||||
mod gamenight_handlers;
|
||||
mod join_gamenight;
|
||||
mod location;
|
||||
mod location_owner;
|
||||
mod participant_handlers;
|
||||
mod user_handlers;
|
||||
|
||||
pub use game::get_game;
|
||||
pub use game::get_games;
|
||||
pub use game::get_owned_games;
|
||||
pub use game::post_disown_game;
|
||||
pub use game::post_game;
|
||||
pub use game::post_own_game;
|
||||
pub use game::post_rename_game;
|
||||
pub use gamenight_handlers::gamenight_get;
|
||||
pub use gamenight_handlers::gamenight_post;
|
||||
pub use gamenight_handlers::gamenights;
|
||||
pub use join_gamenight::post_join_gamenight;
|
||||
pub use join_gamenight::post_leave_gamenight;
|
||||
pub use location::get_locations;
|
||||
pub use location::post_location;
|
||||
pub use location_owner::get_authorized_location_user_ids;
|
||||
pub use location_owner::post_location_authorize;
|
||||
pub use participant_handlers::get_get_participants;
|
||||
pub use user_handlers::get_user;
|
||||
pub use user_handlers::get_user_unauthenticated;
|
||||
pub use user_handlers::get_users;
|
||||
pub use user_handlers::login;
|
||||
pub use user_handlers::refresh;
|
||||
pub use user_handlers::register;
|
||||
pub use gamenight_handlers::gamenights;
|
||||
pub use gamenight_handlers::gamenight_post;
|
||||
pub use gamenight_handlers::gamenight_get;
|
||||
pub use user_handlers::get_user;
|
||||
pub use user_handlers::get_user_unauthenticated;
|
||||
pub use join_gamenight::post_join_gamenight;
|
||||
pub use join_gamenight::post_leave_gamenight;
|
||||
pub use participant_handlers::get_get_participants;
|
||||
pub use game::get_games;
|
||||
pub use game::get_game;
|
||||
pub use game::post_game;
|
||||
pub use game::post_rename_game;
|
||||
pub use game::post_own_game;
|
||||
pub use game::post_disown_game;
|
||||
pub use game::get_owned_games;
|
||||
|
||||
@@ -2,16 +2,30 @@ use actix_web::{get, http::header::ContentType, web, HttpResponse, Responder};
|
||||
use gamenight_database::{DbPool, GetConnection};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{models::{gamenight_id::GamenightId, participants::Participants}, request::{authorization::AuthUser, error::ApiError}};
|
||||
use crate::{
|
||||
models::{gamenight_id::GamenightId, participants::Participants},
|
||||
request::{authorization::AuthUser, error::ApiError},
|
||||
};
|
||||
|
||||
#[get("/participants")]
|
||||
pub async fn get_get_participants(pool: web::Data<DbPool>, _user: AuthUser, gamenight_info: web::Json<GamenightId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn get_get_participants(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
gamenight_info: web::Json<GamenightId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
|
||||
let users = gamenight_database::get_participants(&mut conn, &Uuid::parse_str(&gamenight_info.into_inner().gamenight_id)?)?
|
||||
.iter().map(|x| x.to_string()).collect();
|
||||
|
||||
|
||||
let users = gamenight_database::get_participants(
|
||||
&mut conn,
|
||||
&Uuid::parse_str(&gamenight_info.into_inner().gamenight_id)?,
|
||||
)?
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&Participants{participants: users})?))
|
||||
}
|
||||
.body(serde_json::to_string(&Participants {
|
||||
participants: users,
|
||||
})?))
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
|
||||
use actix_web::http::header::ContentType;
|
||||
use actix_web::{get, post, web, HttpResponse, Responder};
|
||||
use crate::models::{
|
||||
login::Login, registration::Registration, token::Token, user::User, user_id::UserId,
|
||||
};
|
||||
use crate::request::{authorization::get_token, error::ApiError};
|
||||
use actix_web::{get, http::header::ContentType, post, web, HttpResponse, Responder};
|
||||
use gamenight_database::user::{count_users_with_email, count_users_with_username};
|
||||
use gamenight_database::{DbPool, GetConnection};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
use uuid::Uuid;
|
||||
use validator::{Validate, ValidateArgs, ValidationError};
|
||||
use crate::models::login::Login;
|
||||
use crate::models::registration::Registration;
|
||||
use crate::models::token::Token;
|
||||
use crate::models::user::User;
|
||||
use crate::models::user_id::UserId;
|
||||
use crate::request::error::ApiError;
|
||||
use crate::request::authorization::get_token;
|
||||
use serde_json;
|
||||
use gamenight_database::{DbPool, GetConnection};
|
||||
|
||||
use super::authorization::AuthUser;
|
||||
|
||||
@@ -21,7 +16,7 @@ impl From<Login> for gamenight_database::user::LoginUser {
|
||||
fn from(val: Login) -> Self {
|
||||
gamenight_database::user::LoginUser {
|
||||
username: val.username,
|
||||
password: val.password
|
||||
password: val.password,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,20 +26,22 @@ impl From<Registration> for gamenight_database::user::Register {
|
||||
gamenight_database::user::Register {
|
||||
email: val.email,
|
||||
username: val.username,
|
||||
password: val.password
|
||||
password: val.password,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RegisterContext<'v_a> {
|
||||
pub pool: &'v_a DbPool
|
||||
pub pool: &'v_a DbPool,
|
||||
}
|
||||
|
||||
pub fn unique_username(username: &String, context: &RegisterContext) -> Result<(), ValidationError> {
|
||||
pub fn unique_username(
|
||||
username: &String,
|
||||
context: &RegisterContext,
|
||||
) -> Result<(), ValidationError> {
|
||||
let mut conn = context.pool.get_conn();
|
||||
|
||||
match count_users_with_username(&mut conn, username)
|
||||
{
|
||||
match count_users_with_username(&mut conn, username) {
|
||||
Ok(0) => Ok(()),
|
||||
Ok(_) => Err(ValidationError::new("User already exists")),
|
||||
Err(_) => Err(ValidationError::new("Database error while validating user")),
|
||||
@@ -54,28 +51,23 @@ pub fn unique_username(username: &String, context: &RegisterContext) -> Result<(
|
||||
pub fn unique_email(email: &String, context: &RegisterContext) -> Result<(), ValidationError> {
|
||||
let mut conn = context.pool.get_conn();
|
||||
|
||||
match count_users_with_email(&mut conn, email)
|
||||
{
|
||||
match count_users_with_email(&mut conn, email) {
|
||||
Ok(0) => Ok(()),
|
||||
Ok(_) => Err(ValidationError::new("email already exists")),
|
||||
Err(_) => Err(ValidationError::new("Database error while validating email"))
|
||||
Err(_) => Err(ValidationError::new(
|
||||
"Database error while validating email",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Validate)]
|
||||
#[validate(context = RegisterContext::<'v_a>)]
|
||||
pub struct ValidatableRegistration {
|
||||
#[validate(
|
||||
length(min = 1),
|
||||
custom(function = "unique_username", use_context)
|
||||
)]
|
||||
#[validate(length(min = 1), custom(function = "unique_username", use_context))]
|
||||
pub username: String,
|
||||
#[validate(
|
||||
email,
|
||||
custom(function = "unique_email", use_context)
|
||||
)]
|
||||
#[validate(email, custom(function = "unique_email", use_context))]
|
||||
pub email: String,
|
||||
#[validate(length(min = 10), must_match(other = "password_repeat", ))]
|
||||
#[validate(length(min = 10), must_match(other = "password_repeat",))]
|
||||
pub password: String,
|
||||
pub password_repeat: String,
|
||||
}
|
||||
@@ -86,13 +78,16 @@ impl From<Registration> for ValidatableRegistration {
|
||||
username: value.username,
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
password_repeat: value.password_repeat
|
||||
password_repeat: value.password_repeat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/token")]
|
||||
pub async fn login(pool: web::Data<DbPool>, login_data: web::Json<Login>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn login(
|
||||
pool: web::Data<DbPool>,
|
||||
login_data: web::Json<Login>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let data = login_data.into_inner();
|
||||
|
||||
if let Ok(Some(user)) = web::block(move || {
|
||||
@@ -102,35 +97,45 @@ pub async fn login(pool: web::Data<DbPool>, login_data: web::Json<Login>) -> Res
|
||||
.await?
|
||||
{
|
||||
let token = get_token(&user)?;
|
||||
let response = Token{ jwt_token: Some(token) };
|
||||
let response = Token {
|
||||
jwt_token: Some(token),
|
||||
};
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&response)?))
|
||||
}
|
||||
else {
|
||||
Err(ApiError{status: 401, message: "User doesn't exist or password doesn't match".to_string()})
|
||||
} else {
|
||||
Err(ApiError {
|
||||
status: 401,
|
||||
message: "User doesn't exist or password doesn't match".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/token")]
|
||||
pub async fn refresh(user: AuthUser) -> Result<impl Responder, ApiError> {
|
||||
let new_token = get_token(&user.0)?;
|
||||
let response = Token{ jwt_token: Some(new_token) };
|
||||
let response = Token {
|
||||
jwt_token: Some(new_token),
|
||||
};
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&response)?))
|
||||
}
|
||||
|
||||
#[post("/user")]
|
||||
pub async fn register(pool: web::Data<DbPool>, register_data: web::Json<Registration>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn register(
|
||||
pool: web::Data<DbPool>,
|
||||
register_data: web::Json<Registration>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
web::block(move || -> Result<(), ApiError> {
|
||||
let validatable_registration: ValidatableRegistration = register_data.clone().into();
|
||||
validatable_registration.validate_with_args(&RegisterContext{pool: &pool})?;
|
||||
validatable_registration.validate_with_args(&RegisterContext { pool: &pool })?;
|
||||
let register_request = register_data.into_inner().into();
|
||||
let mut conn = pool.get_conn();
|
||||
gamenight_database::register(&mut conn, register_request)?;
|
||||
Ok(())
|
||||
}).await??;
|
||||
})
|
||||
.await??;
|
||||
|
||||
Ok(HttpResponse::Ok())
|
||||
}
|
||||
@@ -146,20 +151,42 @@ impl From<gamenight_database::user::User> for User {
|
||||
}
|
||||
|
||||
#[get("/user")]
|
||||
pub async fn get_user(pool: web::Data<DbPool>, _user: AuthUser, user_info: web::Json<UserId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn get_user(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
user_info: web::Json<UserId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
|
||||
let user = gamenight_database::user::get_user(&mut conn, Uuid::parse_str(&user_info.into_inner().user_id)?)?;
|
||||
|
||||
|
||||
let user = gamenight_database::user::get_user(
|
||||
&mut conn,
|
||||
Uuid::parse_str(&user_info.into_inner().user_id)?,
|
||||
)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&user)?))
|
||||
}
|
||||
|
||||
#[get("/user")]
|
||||
pub async fn get_user_unauthenticated(_path: web::Path<UserId>) -> Result<impl Responder, ApiError> {
|
||||
pub async fn get_user_unauthenticated(
|
||||
_path: web::Path<UserId>,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
Ok(HttpResponse::Forbidden())
|
||||
}
|
||||
|
||||
#[get("/users")]
|
||||
|
||||
pub async fn get_users(
|
||||
pool: web::Data<DbPool>,
|
||||
_user: AuthUser,
|
||||
) -> Result<impl Responder, ApiError> {
|
||||
let mut conn = pool.get_conn();
|
||||
let users = gamenight_database::user::get_users(&mut conn)?;
|
||||
|
||||
let model: Vec<User> = users.into_iter().map(Into::into).collect();
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type(ContentType::json())
|
||||
.body(serde_json::to_string(&model)?))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user