mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
feat-webgarages-121 (#129)
### Description Closes #121 ### Please confirm - [x] I am the legal owner or represent the legal owner of all work submitted (including LLM-generated code, if any) - [x] I consent to my changes being added to this FOSS project - [x] I have confirmed that this does not add new errors or warnings with `utils/clippy.sh` - [ ] This PR used LLMs to generate some or all of the code changes Reviewed-on: https://git.ngram.ca/OpenJam/rc-servers/pulls/129
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use actix_web::{get, web::Data, Responder, HttpRequest};
|
||||
use actix_web::{get, post, web::Data, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
@@ -29,12 +29,12 @@ struct PermissionData {
|
||||
banned: bool,
|
||||
}
|
||||
|
||||
#[get("/dashboard")]
|
||||
pub async fn get(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
pub async fn dashboard_impl(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match super::try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
super::LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
super::LoginReturn::Success(user) => {
|
||||
// TODO
|
||||
log::debug!("Rendering user's dashboard");
|
||||
let creation_time = user.creation();
|
||||
let creation_time_chrono = chrono::DateTime::<chrono::Utc>::from_timestamp_secs(creation_time).unwrap_or_default();
|
||||
Ok(super::render_ok(
|
||||
@@ -63,3 +63,13 @@ pub async fn get(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Bo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/dashboard")]
|
||||
pub async fn get(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
dashboard_impl(handlebars_ref, auth, user_opt, req).await
|
||||
}
|
||||
|
||||
#[post("/dashboard")]
|
||||
pub async fn post(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
dashboard_impl(handlebars_ref, auth, user_opt, req).await
|
||||
}
|
||||
|
||||
52
rc_society/src/web/garage/export.rs
Normal file
52
rc_society/src/web/garage/export.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use actix_web::{HttpRequest, HttpResponse, Responder, get, http::StatusCode, web::{Data, Path, Query}};
|
||||
use actix_identity::Identity;
|
||||
|
||||
use oj_rc_plugins::vehicle_import::VehicleImportData;
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user};
|
||||
use crate::api::garage::plugins::ImportPlugins;
|
||||
|
||||
#[get("/garages/{id}/export")]
|
||||
pub async fn get(id: Path<i32>, query: Query<super::PortQuery>, exporter: Data<ImportPlugins>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
match user.garage_by_id(*id).await {
|
||||
Ok(Some(garage)) => {
|
||||
let data = VehicleImportData {
|
||||
cube_data: garage.robot_data,
|
||||
colour_data: garage.colour_data,
|
||||
vehicle_name: garage.name,
|
||||
vehicle_author: Some(user.display_name().to_owned()),
|
||||
};
|
||||
match exporter.export_by_name(&query.plugin, &data) {
|
||||
Ok(export) => {
|
||||
//export.push(b'\n');
|
||||
use actix_web::http::header::{ContentDisposition, TryIntoHeaderPair};
|
||||
let ext = exporter.file_ext(&query.plugin).unwrap();
|
||||
// TODO sanitise vehicle name and include it in the filename
|
||||
let dispo = ContentDisposition::attachment(format!("export-{}-{}.{}", &query.plugin, *id, ext));
|
||||
let (key, val) = dispo.try_into_pair().unwrap();
|
||||
let mut resp = HttpResponse::with_body(StatusCode::OK, export);
|
||||
resp.headers_mut().append(key, val);
|
||||
Ok(resp.map_into_boxed_body())
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed export of vehicle {} for user {}: {}", id, user.public_id(), e);
|
||||
Err(super::PluginPortError::from(e).into())
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(None) => {
|
||||
Ok(HttpResponse::NotFound()
|
||||
.finish())
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to load garage ID for user {}: {}", user.public_id(), e);
|
||||
Ok(HttpResponse::InternalServerError()
|
||||
.finish())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
221
rc_society/src/web/garage/import.rs
Normal file
221
rc_society/src/web/garage/import.rs
Normal file
@@ -0,0 +1,221 @@
|
||||
use actix_web::{get, post, web::{Data, Path}, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user, render_ok, render_err};
|
||||
use crate::api::garage::plugins::ImportPlugins;
|
||||
|
||||
const FORM_NAME: &str = "garage_import";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RenderData {
|
||||
display_name: String,
|
||||
public_id: String,
|
||||
garage: Option<GarageData>,
|
||||
importers: Vec<String>,
|
||||
selected_importer: Option<String>,
|
||||
success: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct GarageData {
|
||||
garage_id: i32,
|
||||
slot: i32,
|
||||
}
|
||||
|
||||
async fn import_impl(id: Option<i32>, handlebars_ref: Data<handlebars::Handlebars<'_>>, importer: Data<ImportPlugins>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let html = if let Some(id) = id {
|
||||
match user.garage_by_id(id).await {
|
||||
Ok(Some(garage)) => {
|
||||
render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: Some(GarageData {
|
||||
garage_id: id,
|
||||
slot: garage.slot,
|
||||
}),
|
||||
importers: importer.plugin_names()
|
||||
.map(|x| x.to_owned())
|
||||
.collect(),
|
||||
selected_importer: None,
|
||||
success: None,
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
},
|
||||
Ok(None) => {
|
||||
log::error!("Failed to find vehicle {} for user {}", id, user.public_id());
|
||||
render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: Some(GarageData {
|
||||
garage_id: -1,
|
||||
slot: -1,
|
||||
}),
|
||||
importers: Vec::new(),
|
||||
selected_importer: None,
|
||||
success: None,
|
||||
},
|
||||
"Vehicle not found".to_owned(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to retrieve vehicle {} for user {}: {}", id, user.public_id(), e);
|
||||
render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: Some(GarageData {
|
||||
garage_id: -1,
|
||||
slot: -1,
|
||||
}),
|
||||
importers: Vec::new(),
|
||||
selected_importer: None,
|
||||
success: None,
|
||||
},
|
||||
e.to_string(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: None,
|
||||
importers: importer.plugin_names()
|
||||
.map(|x| x.to_owned())
|
||||
.collect(),
|
||||
selected_importer: None,
|
||||
success: None,
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
};
|
||||
Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/garages/{id}/import")]
|
||||
pub async fn get_existing(id: Path<i32>, handlebars_ref: Data<handlebars::Handlebars<'_>>, importer: Data<ImportPlugins>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
import_impl(Some(*id), handlebars_ref, importer, auth, user_opt, req).await
|
||||
}
|
||||
|
||||
#[get("/garages/import")]
|
||||
pub async fn get_new(handlebars_ref: Data<handlebars::Handlebars<'_>>, importer: Data<ImportPlugins>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
import_impl(None, handlebars_ref, importer, auth, user_opt, req).await
|
||||
}
|
||||
|
||||
#[derive(Debug, actix_multipart::form::MultipartForm)]
|
||||
struct ImportForm {
|
||||
//#[multipart]
|
||||
files: Vec<actix_multipart::form::bytes::Bytes>,
|
||||
garage_id: actix_multipart::form::text::Text<i32>,
|
||||
plugin: actix_multipart::form::text::Text<String>,
|
||||
|
||||
}
|
||||
|
||||
#[post("/garages/import")]
|
||||
pub async fn post(form: actix_multipart::form::MultipartForm<ImportForm>, handlebars_ref: Data<handlebars::Handlebars<'_>>, importer: Data<ImportPlugins>, parsers: Data<oj_rc_core::cubes::CubeParsers>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let total_size: usize = form.files.iter().map(|f| f.data.len()).sum();
|
||||
if form.files.is_empty() {
|
||||
return Err(super::PluginPortError {
|
||||
code: oj_rc_plugins::vehicle_import::VehicleImportErrorCode::Invalid,
|
||||
}.into());
|
||||
}
|
||||
if *form.garage_id != -1 && form.files.len() != 1 {
|
||||
return Err(super::PluginPortError {
|
||||
code: oj_rc_plugins::vehicle_import::VehicleImportErrorCode::Invalid,
|
||||
}.into());
|
||||
}
|
||||
for (i, file) in form.files.iter().enumerate() {
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("import {} file {} data: {:?}", &*form.plugin, i, &file.data[..]);
|
||||
let import_data = match importer.import_by_name(&form.plugin, &file.data)
|
||||
.map_err(|e| super::PluginPortError { code: e }) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
let html = render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: None,
|
||||
importers: importer.plugin_names()
|
||||
.map(|x| x.to_owned())
|
||||
.collect(),
|
||||
selected_importer: Some(form.plugin.0.clone()),
|
||||
success: None,
|
||||
},
|
||||
format!("Failed to import file {}: {}", i, e),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
);
|
||||
return Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
);
|
||||
},
|
||||
};
|
||||
let vehicle_data = oj_rc_core::persist::user::VehicleData {
|
||||
name: import_data.vehicle_name,
|
||||
slot: -1, // will be overriden in oj_rc_core
|
||||
robot_data: import_data.cube_data,
|
||||
colour_data: import_data.colour_data,
|
||||
weapon_order: Vec::default(), // will be overriden in oj_rc_core
|
||||
crf_id: None, // irrelevant
|
||||
was_rated: None, // irrelevant
|
||||
};
|
||||
user.save_garage(
|
||||
vehicle_data,
|
||||
if *form.garage_id < 0 { None } else { Some(*form.garage_id) }, // multipart crate silliness
|
||||
parsers.cpu_counter().as_ref(),
|
||||
parsers.weapon_order().as_ref(),
|
||||
).await?;
|
||||
}
|
||||
let html = render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: None,
|
||||
importers: importer.plugin_names()
|
||||
.map(|x| x.to_owned())
|
||||
.collect(),
|
||||
selected_importer: Some(form.plugin.0.clone()),
|
||||
success: Some(format!(
|
||||
"Imported {} vehicle{} ({:.2}KiB)",
|
||||
form.files.len(),
|
||||
if form.files.len() > 1 { "s" } else { "" },
|
||||
total_size as f64 / 1024.0,
|
||||
)),
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
);
|
||||
Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
93
rc_society/src/web/garage/info.rs
Normal file
93
rc_society/src/web/garage/info.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use actix_web::{get, web::{Data, Path}, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user, render_ok, render_err};
|
||||
use crate::api::garage::plugins::ImportPlugins;
|
||||
|
||||
const FORM_NAME: &str = "garage_info";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RenderData {
|
||||
display_name: String,
|
||||
public_id: String,
|
||||
garage: GarageData,
|
||||
exporters: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct GarageData {
|
||||
garage_id: i32,
|
||||
slot: i32,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[get("/garages/{id}/info")]
|
||||
pub async fn get(id: Path<i32>, handlebars_ref: Data<handlebars::Handlebars<'_>>, exporter: Data<ImportPlugins>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let html = match user.garage_by_id(*id).await {
|
||||
Ok(Some(garage)) => {
|
||||
render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: GarageData {
|
||||
garage_id: *id,
|
||||
slot: garage.slot,
|
||||
name: garage.name.unwrap_or_default(),
|
||||
},
|
||||
exporters: exporter.plugin_names()
|
||||
.map(|x| x.to_owned())
|
||||
.collect(),
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
},
|
||||
Ok(None) => {
|
||||
log::error!("Failed to find vehicle {} for user {}", id, user.public_id());
|
||||
render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: GarageData {
|
||||
garage_id: -1,
|
||||
slot: -1,
|
||||
name: String::default(),
|
||||
},
|
||||
exporters: Vec::new(),
|
||||
},
|
||||
"Vehicle not found".to_owned(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to retrieve vehicle {} for user {}: {}", id, user.public_id(), e);
|
||||
render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garage: GarageData {
|
||||
garage_id: -1,
|
||||
slot: -1,
|
||||
name: String::default(),
|
||||
},
|
||||
exporters: Vec::new(),
|
||||
},
|
||||
e.to_string(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
76
rc_society/src/web/garage/list.rs
Normal file
76
rc_society/src/web/garage/list.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use actix_web::{get, web::Data, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user, render_ok, render_err};
|
||||
|
||||
const FORM_NAME: &str = "garage_list";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RenderData {
|
||||
display_name: String,
|
||||
public_id: String,
|
||||
garages: Vec<GarageData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct GarageData {
|
||||
garage_id: i32,
|
||||
slot: i32,
|
||||
name: String,
|
||||
cpu: i32,
|
||||
max_cpu: i32,
|
||||
creation_time_unix: i64,
|
||||
creation_time_iso: String,
|
||||
}
|
||||
|
||||
#[get("/garages/list")]
|
||||
pub async fn get(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let html = match user.garages().await {
|
||||
Ok(mut garage_infos) => {
|
||||
garage_infos.sort_by_key(|g| g.slot);
|
||||
render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garages: garage_infos.into_iter()
|
||||
.map(|g| GarageData {
|
||||
garage_id: g.id,
|
||||
slot: g.slot,
|
||||
name: g.name,
|
||||
cpu: g.total_robot_cpu,
|
||||
max_cpu: g.bay_cpu,
|
||||
creation_time_unix: g.creation_time,
|
||||
creation_time_iso: chrono::DateTime::<chrono::Utc>::from_timestamp_secs(g.creation_time).unwrap_or_default().to_rfc3339(),
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to retrieve garages for user {}: {}", user.public_id(), e);
|
||||
render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
garages: Vec::new(),
|
||||
},
|
||||
e.to_string(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
37
rc_society/src/web/garage/mod.rs
Normal file
37
rc_society/src/web/garage/mod.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
pub mod list;
|
||||
pub mod export;
|
||||
pub mod import;
|
||||
pub mod info;
|
||||
pub mod selected;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct PortQuery {
|
||||
pub plugin: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PluginPortError {
|
||||
code: oj_rc_plugins::vehicle_import::VehicleImportErrorCode,
|
||||
}
|
||||
|
||||
impl std::convert::From<oj_rc_plugins::vehicle_import::VehicleImportErrorCode> for PluginPortError {
|
||||
fn from(value: oj_rc_plugins::vehicle_import::VehicleImportErrorCode) -> Self {
|
||||
Self {
|
||||
code: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for PluginPortError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.code)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for PluginPortError {}
|
||||
|
||||
impl actix_web::error::ResponseError for PluginPortError {
|
||||
fn status_code(&self) -> actix_web::http::StatusCode {
|
||||
actix_web::http::StatusCode::UNPROCESSABLE_ENTITY
|
||||
}
|
||||
}
|
||||
29
rc_society/src/web/garage/selected.rs
Normal file
29
rc_society/src/web/garage/selected.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use actix_web::{get, web::{Data, Redirect}, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user};
|
||||
|
||||
#[get("/garages/selected")]
|
||||
pub async fn get(auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let resp = if let Some(selected_garage) = user.garage_id_selected().await? {
|
||||
Redirect::to(format!("/garages/{}/info", selected_garage))
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
|
||||
} else {
|
||||
log::error!("User {} has no garage selected (bad database state?)", user.display_name());
|
||||
Redirect::to("/garages/list".to_owned())
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
};
|
||||
Ok(
|
||||
resp
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pub mod dashboard;
|
||||
pub mod login;
|
||||
pub mod favicon;
|
||||
pub mod index;
|
||||
pub mod garage;
|
||||
|
||||
use serde::Serialize;
|
||||
use actix_web::{web::{Html, Redirect}, Responder};
|
||||
@@ -51,19 +52,25 @@ async fn try_auth_user(user_opt: Option<actix_identity::Identity>, auth: &oj_rc_
|
||||
if let Some(user) = user_opt {
|
||||
let user_id = user.id()?;
|
||||
match <oj_rc_core::UserImpl as oj_rc_core::UserProvider<()>>::web_authenticate(auth, user_id.clone()).await {
|
||||
Ok(user) => Ok(LoginReturn::Success(user)),
|
||||
Ok(user) => {
|
||||
//log::debug!("Web auth success");
|
||||
Ok(LoginReturn::Success(user))
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("Failed to login with token {}: {} ({:?})", user_id, e.message, e.code);
|
||||
Ok(LoginReturn::AuthFail(
|
||||
Redirect::to("/login")
|
||||
.temporary()
|
||||
.respond_to(req)
|
||||
.map_into_boxed_body()
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::debug!("No user identity, redirecting to login page");
|
||||
Ok(LoginReturn::AuthFail(
|
||||
Redirect::to("/login")
|
||||
.temporary()
|
||||
.respond_to(req)
|
||||
.map_into_boxed_body()
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user