mirror of
https://github.com/n08i40k/schedule-parser-rusted.git
synced 2025-12-06 17:57:47 +03:00
0.7.0
Добавлена OpenAPI документация эндпоинтов и структур с интерфейсом RapiDoc. Добавлены derive макросы для преобразования структуры в HttpResponse с помощью ResponderJson и IResponse<T> с помощью IntoIResponse. Ревью кода эндпоинтов связанных с авторизацией. Эндпоинт users/me теперь объект пользователя в требуемом виде.
This commit is contained in:
@@ -3,6 +3,8 @@ use crate::AppState;
|
||||
use crate::database::driver;
|
||||
use crate::database::models::UserRole;
|
||||
use crate::routes::auth::shared::{Error, parse_vk_id};
|
||||
use crate::routes::schema::ResponseError;
|
||||
use crate::routes::schema::user::UserResponse;
|
||||
use actix_web::{post, web};
|
||||
use rand::{Rng, rng};
|
||||
use web::Json;
|
||||
@@ -10,7 +12,7 @@ use web::Json;
|
||||
async fn sign_up(data: SignUpData, app_state: &web::Data<AppState>) -> Response {
|
||||
// If user selected forbidden role.
|
||||
if data.role == UserRole::Admin {
|
||||
return Response::err(ErrorCode::DisallowedRole);
|
||||
return ErrorCode::DisallowedRole.into();
|
||||
}
|
||||
|
||||
// If specified group doesn't exist in schedule.
|
||||
@@ -18,28 +20,32 @@ async fn sign_up(data: SignUpData, app_state: &web::Data<AppState>) -> Response
|
||||
|
||||
if let Some(schedule) = &*schedule_opt {
|
||||
if !schedule.data.groups.contains_key(&data.group) {
|
||||
return Response::err(ErrorCode::InvalidGroupName);
|
||||
return ErrorCode::InvalidGroupName.into();
|
||||
}
|
||||
}
|
||||
|
||||
// If user with specified username already exists.
|
||||
if driver::users::contains_by_username(&app_state.database, &data.username) {
|
||||
return Response::err(ErrorCode::UsernameAlreadyExists);
|
||||
return ErrorCode::UsernameAlreadyExists.into();
|
||||
}
|
||||
|
||||
// If user with specified VKID already exists.
|
||||
if let Some(id) = data.vk_id {
|
||||
if driver::users::contains_by_vk_id(&app_state.database, id) {
|
||||
return Response::err(ErrorCode::VkAlreadyExists);
|
||||
return ErrorCode::VkAlreadyExists.into();
|
||||
}
|
||||
}
|
||||
|
||||
let user = data.to_user();
|
||||
let user = data.into();
|
||||
driver::users::insert(&app_state.database, &user).unwrap();
|
||||
|
||||
Response::ok(&user)
|
||||
UserResponse::from(&user).into()
|
||||
}
|
||||
|
||||
#[utoipa::path(responses(
|
||||
(status = OK, body = UserResponse),
|
||||
(status = NOT_ACCEPTABLE, body = ResponseError<ErrorCode>)
|
||||
))]
|
||||
#[post("/sign-up")]
|
||||
pub async fn sign_up_default(data_json: Json<Request>, app_state: web::Data<AppState>) -> Response {
|
||||
let data = data_json.into_inner();
|
||||
@@ -58,8 +64,15 @@ pub async fn sign_up_default(data_json: Json<Request>, app_state: web::Data<AppS
|
||||
.await
|
||||
}
|
||||
|
||||
#[utoipa::path(responses(
|
||||
(status = OK, body = UserResponse),
|
||||
(status = NOT_ACCEPTABLE, body = ResponseError<ErrorCode>)
|
||||
))]
|
||||
#[post("/sign-up-vk")]
|
||||
pub async fn sign_up_vk(data_json: Json<vk::Request>, app_state: web::Data<AppState>) -> Response {
|
||||
pub async fn sign_up_vk(
|
||||
data_json: Json<vk::Request>,
|
||||
app_state: web::Data<AppState>,
|
||||
) -> Response {
|
||||
let data = data_json.into_inner();
|
||||
|
||||
match parse_vk_id(&data.access_token) {
|
||||
@@ -87,14 +100,15 @@ pub async fn sign_up_vk(data_json: Json<vk::Request>, app_state: web::Data<AppSt
|
||||
eprintln!("{:?}", err);
|
||||
}
|
||||
|
||||
Response::err(ErrorCode::InvalidVkAccessToken)
|
||||
ErrorCode::InvalidVkAccessToken.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod schema {
|
||||
use crate::database::models::{User, UserRole};
|
||||
use crate::routes::schema::{ErrorToHttpCode, IResponse, user};
|
||||
use crate::routes::schema::user::UserResponse;
|
||||
use crate::routes::schema::{HttpStatusCode, IResponse};
|
||||
use crate::utility;
|
||||
use actix_web::http::StatusCode;
|
||||
use objectid::ObjectId;
|
||||
@@ -102,12 +116,20 @@ mod schema {
|
||||
|
||||
/// WEB
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[schema(as = SignUp::Request)]
|
||||
pub struct Request {
|
||||
#[schema(examples("n08i40k"))]
|
||||
pub username: String,
|
||||
|
||||
pub password: String,
|
||||
|
||||
#[schema(examples("ИС-214/23"))]
|
||||
pub group: String,
|
||||
|
||||
pub role: UserRole,
|
||||
|
||||
#[schema(examples("3.0.0"))]
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
@@ -115,34 +137,30 @@ mod schema {
|
||||
use crate::database::models::UserRole;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[schema(as = SignUpVk::Request)]
|
||||
pub struct Request {
|
||||
pub access_token: String,
|
||||
|
||||
#[schema(examples("n08i40k"))]
|
||||
pub username: String,
|
||||
|
||||
#[schema(examples("ИС-214/23"))]
|
||||
pub group: String,
|
||||
|
||||
pub role: UserRole,
|
||||
|
||||
#[schema(examples("3.0.0"))]
|
||||
pub version: String,
|
||||
}
|
||||
}
|
||||
|
||||
pub type Response = IResponse<user::ResponseOk, ResponseErr>;
|
||||
pub type Response = IResponse<UserResponse, ErrorCode>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ResponseOk {
|
||||
id: String,
|
||||
access_token: String,
|
||||
group: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseErr {
|
||||
code: ErrorCode,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Clone, Serialize, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
#[schema(as = SignUp::ErrorCode)]
|
||||
pub enum ErrorCode {
|
||||
DisallowedRole,
|
||||
InvalidGroupName,
|
||||
@@ -151,23 +169,8 @@ mod schema {
|
||||
VkAlreadyExists,
|
||||
}
|
||||
|
||||
pub trait ResponseExt {
|
||||
fn ok(user: &User) -> Self;
|
||||
fn err(code: ErrorCode) -> Self;
|
||||
}
|
||||
|
||||
impl ResponseExt for Response {
|
||||
fn ok(user: &User) -> Self {
|
||||
IResponse(Ok(user::ResponseOk::from_user(&user)))
|
||||
}
|
||||
|
||||
fn err(code: ErrorCode) -> Response {
|
||||
Self(Err(ResponseErr { code }))
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorToHttpCode for ResponseErr {
|
||||
fn to_http_status_code(&self) -> StatusCode {
|
||||
impl HttpStatusCode for ErrorCode {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::NOT_ACCEPTABLE
|
||||
}
|
||||
}
|
||||
@@ -183,8 +186,8 @@ mod schema {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl SignUpData {
|
||||
pub fn to_user(self) -> User {
|
||||
impl Into<User> for SignUpData {
|
||||
fn into(self) -> User {
|
||||
let id = ObjectId::new().unwrap().to_string();
|
||||
let access_token = utility::jwt::encode(&id);
|
||||
|
||||
@@ -209,11 +212,11 @@ mod tests {
|
||||
use crate::routes::auth::sign_up::schema::Request;
|
||||
use crate::routes::auth::sign_up::sign_up_default;
|
||||
use crate::test_env::tests::{static_app_state, test_app_state, test_env};
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_test::test_app;
|
||||
use actix_web::dev::ServiceResponse;
|
||||
use actix_web::http::Method;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::test;
|
||||
use actix_test::test_app;
|
||||
|
||||
struct SignUpPartial {
|
||||
username: String,
|
||||
|
||||
Reference in New Issue
Block a user