872 lines
25 KiB
Rust
872 lines
25 KiB
Rust
use crate::{
|
|
error::{Error, OptionExt, ResultExt, StateError},
|
|
State,
|
|
};
|
|
use actix_session::Session;
|
|
use actix_web::{dev::Payload, web, HttpRequest, HttpResponse, Scope};
|
|
use hyaenidae_accounts::Authenticated;
|
|
use uuid::Uuid;
|
|
|
|
mod middleware;
|
|
|
|
pub(crate) use middleware::CurrentProfile;
|
|
|
|
pub(super) fn scope() -> Scope {
|
|
web::scope("/profiles")
|
|
.service(web::resource("").route(web::get().to(profiles)))
|
|
.service(web::resource("/current").route(web::get().to(current_profile)))
|
|
.service(
|
|
web::scope("/update")
|
|
.service(
|
|
web::resource("/bio")
|
|
.route(web::post().to(update_bio))
|
|
.route(web::get().to(to_current_profile)),
|
|
)
|
|
.service(
|
|
web::resource("/icon")
|
|
.route(web::post().to(update_icon))
|
|
.route(web::get().to(to_current_profile)),
|
|
)
|
|
.service(
|
|
web::resource("/banner")
|
|
.route(web::post().to(update_banner))
|
|
.route(web::get().to(to_current_profile)),
|
|
)
|
|
.service(
|
|
web::resource("/require-login")
|
|
.route(web::post().to(update_require_login))
|
|
.route(web::get().to(to_current_profile)),
|
|
),
|
|
)
|
|
.service(
|
|
web::resource("/change")
|
|
.route(web::get().to(change_profile_page))
|
|
.route(web::post().to(change_profile)),
|
|
)
|
|
.service(
|
|
web::scope("/create")
|
|
.service(web::resource("").route(web::get().to(to_create)))
|
|
.service(
|
|
web::resource("/handle")
|
|
.route(web::get().to(new_handle))
|
|
.route(web::post().to(create_handle)),
|
|
)
|
|
.service(
|
|
web::resource("/bio")
|
|
.route(web::get().to(new_bio))
|
|
.route(web::post().to(create_bio)),
|
|
)
|
|
.service(
|
|
web::resource("/icon")
|
|
.route(web::get().to(new_icon))
|
|
.route(web::post().to(create_icon)),
|
|
)
|
|
.service(
|
|
web::resource("/banner")
|
|
.route(web::get().to(new_banner))
|
|
.route(web::post().to(create_banner)),
|
|
)
|
|
.service(
|
|
web::resource("/require-login")
|
|
.route(web::get().to(new_require_login))
|
|
.route(web::post().to(create_require_login)),
|
|
)
|
|
.service(web::resource("/done").route(web::get().to(done))),
|
|
)
|
|
}
|
|
|
|
fn to_create() -> HttpResponse {
|
|
redirect("/profiles/create/handle")
|
|
}
|
|
|
|
fn to_bio() -> HttpResponse {
|
|
redirect("/profiles/create/bio")
|
|
}
|
|
|
|
fn to_icon() -> HttpResponse {
|
|
redirect("/profiles/create/icon")
|
|
}
|
|
|
|
fn to_banner() -> HttpResponse {
|
|
redirect("/profiles/create/banner")
|
|
}
|
|
|
|
fn to_require_login() -> HttpResponse {
|
|
redirect("/profiles/create/require-login")
|
|
}
|
|
|
|
fn to_done() -> HttpResponse {
|
|
redirect("/profiles/create/done")
|
|
}
|
|
|
|
fn to_current_profile() -> HttpResponse {
|
|
redirect("/profiles/current")
|
|
}
|
|
|
|
fn to_change_profile_page() -> HttpResponse {
|
|
redirect("/profiles/change")
|
|
}
|
|
|
|
fn redirect(path: &str) -> HttpResponse {
|
|
HttpResponse::SeeOther().header("Location", path).finish()
|
|
}
|
|
|
|
const ACCEPT_TYPES: &str = "image/png,image/webp,image/jpeg,image/gif,.png,.webp,.jpg,.jpeg,.gif";
|
|
|
|
pub use state::ProfileState;
|
|
mod state {
|
|
use super::Profile;
|
|
use super::ACCEPT_TYPES;
|
|
use hyaenidae_toolkit::{FileInput, TextInput};
|
|
|
|
pub struct ProfileState {
|
|
pub(crate) profile: Profile,
|
|
pub(crate) display_name: TextInput,
|
|
pub(crate) description: TextInput,
|
|
pub(crate) icon: FileInput,
|
|
pub(crate) icon_error: Option<String>,
|
|
pub(crate) banner: FileInput,
|
|
pub(crate) banner_error: Option<String>,
|
|
pub(crate) login_required_error: Option<String>,
|
|
}
|
|
|
|
impl ProfileState {
|
|
pub(super) fn new(profile: Profile) -> Self {
|
|
let mut display_name = TextInput::new("display_name");
|
|
display_name
|
|
.title("Display Name")
|
|
.placeholder("Display Name");
|
|
if let Some(text) = profile.display_name() {
|
|
display_name.value(text);
|
|
}
|
|
|
|
let mut description = TextInput::new("description");
|
|
description
|
|
.title("Description")
|
|
.placeholder("Description")
|
|
.textarea();
|
|
if let Some(text) = profile.description() {
|
|
description.value(text);
|
|
}
|
|
let mut icon = FileInput::secondary("images[]", "Select Icon", "icon-input");
|
|
icon.accept(ACCEPT_TYPES).no_group();
|
|
let mut banner = FileInput::secondary("images[]", "Select Banner", "banner-input");
|
|
banner.accept(ACCEPT_TYPES).no_group();
|
|
|
|
ProfileState {
|
|
profile,
|
|
display_name,
|
|
description,
|
|
icon,
|
|
icon_error: None,
|
|
banner,
|
|
banner_error: None,
|
|
login_required_error: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn display_name_error(&mut self, err: &str) -> &mut Self {
|
|
self.display_name.error_opt(Some(err.to_owned()));
|
|
self
|
|
}
|
|
|
|
pub(super) fn description_error(&mut self, err: &str) -> &mut Self {
|
|
self.description.error_opt(Some(err.to_owned()));
|
|
self
|
|
}
|
|
|
|
pub(super) fn icon_error(&mut self, err: &str) -> &mut Self {
|
|
self.icon_error = Some(err.to_owned());
|
|
self
|
|
}
|
|
|
|
pub(super) fn banner_error(&mut self, err: &str) -> &mut Self {
|
|
self.banner_error = Some(err.to_owned());
|
|
self
|
|
}
|
|
|
|
pub(super) fn login_required_error(&mut self, err: &str) -> &mut Self {
|
|
self.login_required_error = Some(err.to_owned());
|
|
self
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Profile {
|
|
inner: hyaenidae_profiles::store::Profile,
|
|
banner: Option<String>,
|
|
icon: Option<String>,
|
|
}
|
|
|
|
impl Profile {
|
|
fn from_id(profile_id: Uuid, state: &State) -> Result<Self, Error> {
|
|
let inner = state.profiles.store.profiles.by_id(profile_id)?.req()?;
|
|
let banner = match inner.banner() {
|
|
Some(banner_id) => {
|
|
let file = state.profiles.store.files.by_id(banner_id)?.req()?;
|
|
let hyaenidae_profiles::store::FileSource::PictRs(file) = file.source();
|
|
Some(file.key().to_owned())
|
|
}
|
|
None => None,
|
|
};
|
|
let icon = match inner.icon() {
|
|
Some(icon_id) => {
|
|
let file = state.profiles.store.files.by_id(icon_id)?.req()?;
|
|
let hyaenidae_profiles::store::FileSource::PictRs(file) = file.source();
|
|
Some(file.key().to_owned())
|
|
}
|
|
None => None,
|
|
};
|
|
|
|
Ok(Profile {
|
|
inner,
|
|
banner,
|
|
icon,
|
|
})
|
|
}
|
|
|
|
fn refresh(self, state: &State) -> Result<Self, Error> {
|
|
Self::from_id(self.inner.id(), state)
|
|
}
|
|
|
|
pub(crate) fn id(&self) -> Uuid {
|
|
self.inner.id()
|
|
}
|
|
|
|
pub(crate) fn login_required(&self) -> bool {
|
|
self.inner.login_required()
|
|
}
|
|
|
|
pub(crate) fn full_handle(&self) -> String {
|
|
format!("{}@{}", self.inner.handle(), self.inner.domain())
|
|
}
|
|
|
|
pub(crate) fn display_name(&self) -> Option<&str> {
|
|
self.inner.display_name()
|
|
}
|
|
|
|
pub(crate) fn description(&self) -> Option<&str> {
|
|
self.inner.description()
|
|
}
|
|
|
|
pub(crate) fn name(&self) -> &str {
|
|
self.inner.display_name().unwrap_or(self.inner.handle())
|
|
}
|
|
|
|
pub(crate) fn icon_key(&self) -> Option<&str> {
|
|
self.icon.as_deref()
|
|
}
|
|
|
|
pub(crate) fn banner_key(&self) -> Option<&str> {
|
|
self.banner.as_deref()
|
|
}
|
|
}
|
|
|
|
async fn profiles() -> HttpResponse {
|
|
to_current_profile()
|
|
}
|
|
|
|
async fn current_profile(
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_profile(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_profile(profile: Profile) -> Result<HttpResponse, Error> {
|
|
let profile_state = ProfileState::new(profile);
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::current(cursor, &profile_state)
|
|
})
|
|
}
|
|
|
|
async fn update_bio(
|
|
form: web::Form<BioForm>,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_update_bio(form.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_update_bio(
|
|
form: BioForm,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let display_name = form.display_name.clone();
|
|
let description = form.description.clone();
|
|
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_text(
|
|
profile.id(),
|
|
display_name,
|
|
description,
|
|
))
|
|
.await;
|
|
|
|
let mut state = ProfileState::new(profile.refresh(state)?);
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_current_profile()),
|
|
Err(e) => {
|
|
state.display_name_error(&e.to_string());
|
|
}
|
|
};
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::current(cursor, &state)
|
|
})
|
|
}
|
|
|
|
async fn update_icon(
|
|
request: HttpRequest,
|
|
payload: web::Payload,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_update_icon(request, payload.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_update_icon(
|
|
request: HttpRequest,
|
|
payload: Payload,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let res = state.profiles.upload_image(request, payload).await;
|
|
|
|
let error = match res {
|
|
Ok(file_ids) if file_ids.len() == 1 => {
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_icon(profile.id(), file_ids[0]))
|
|
.await;
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_current_profile()),
|
|
Err(e) => e.to_string(),
|
|
}
|
|
}
|
|
Ok(_) => "Incorrect number of files".to_owned(),
|
|
Err(e) => e.to_string(),
|
|
};
|
|
|
|
let mut state = ProfileState::new(profile.refresh(state)?);
|
|
state.icon_error(&error);
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::current(cursor, &state)
|
|
})
|
|
}
|
|
|
|
async fn update_banner(
|
|
request: HttpRequest,
|
|
payload: web::Payload,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_update_banner(request, payload.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_update_banner(
|
|
request: HttpRequest,
|
|
payload: Payload,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let res = state.profiles.upload_image(request, payload).await;
|
|
|
|
let error = match res {
|
|
Ok(file_ids) if file_ids.len() == 1 => {
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_banner(profile.id(), file_ids[0]))
|
|
.await;
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_current_profile()),
|
|
Err(e) => e.to_string(),
|
|
}
|
|
}
|
|
Ok(_) => "Incorrect number of files".to_owned(),
|
|
Err(e) => e.to_string(),
|
|
};
|
|
|
|
let mut state = ProfileState::new(profile.refresh(state)?);
|
|
state.banner_error(&error);
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::current(cursor, &state)
|
|
})
|
|
}
|
|
|
|
async fn update_require_login(
|
|
form: web::Form<RequireLoginForm>,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_update_require_login(form.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_update_require_login(
|
|
form: RequireLoginForm,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let login_required = form.require_login.is_some();
|
|
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_login_required(
|
|
profile.id(),
|
|
login_required,
|
|
))
|
|
.await;
|
|
|
|
let mut state = ProfileState::new(profile.refresh(state)?);
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_current_profile()),
|
|
Err(e) => {
|
|
state.login_required_error(&e.to_string());
|
|
}
|
|
};
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::current(cursor, &state)
|
|
})
|
|
}
|
|
|
|
#[derive(Clone, Debug, serde::Deserialize)]
|
|
struct ChangeProfileForm {
|
|
profile_id: Uuid,
|
|
}
|
|
|
|
async fn change_profile_page(
|
|
auth: Authenticated,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
let user_id = auth.user().id();
|
|
|
|
do_change_profile_page(user_id, &state).await.state(&state)
|
|
}
|
|
|
|
async fn do_change_profile_page(user_id: Uuid, state: &State) -> Result<HttpResponse, Error> {
|
|
let profiles = state
|
|
.profiles
|
|
.store
|
|
.profiles
|
|
.for_local(user_id)
|
|
.filter_map(|profile_id| Profile::from_id(profile_id, state).ok())
|
|
.collect::<Vec<_>>();
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::list(cursor, &profiles)
|
|
})
|
|
}
|
|
|
|
async fn change_profile(
|
|
auth: Authenticated,
|
|
session: Session,
|
|
form: web::Form<ChangeProfileForm>,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
let user_id = auth.user().id();
|
|
do_change_profile(user_id, session, form.into_inner(), &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_change_profile(
|
|
user_id: Uuid,
|
|
session: Session,
|
|
form: ChangeProfileForm,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let profile = Profile::from_id(form.profile_id, state)?;
|
|
if profile.inner.local_owner() != Some(user_id) {
|
|
return Ok(to_change_profile_page());
|
|
}
|
|
|
|
middleware::ProfileData::set_data(form.profile_id, &session)
|
|
.ok()
|
|
.req()?;
|
|
|
|
Ok(to_current_profile())
|
|
}
|
|
|
|
#[derive(Clone, Debug, serde::Deserialize)]
|
|
pub struct HandleForm {
|
|
pub(crate) handle: String,
|
|
}
|
|
|
|
async fn new_handle(_: Authenticated, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
|
let mut handle_input = hyaenidae_toolkit::TextInput::new("handle");
|
|
handle_input.placeholder("Handle").title("Handle");
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::handle(cursor, &handle_input)
|
|
})
|
|
.state(&state)
|
|
}
|
|
|
|
async fn create_handle(
|
|
auth: Authenticated,
|
|
form: web::Form<HandleForm>,
|
|
session: Session,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_create_handle(auth, form.into_inner(), session, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_create_handle(
|
|
auth: Authenticated,
|
|
form: HandleForm,
|
|
session: Session,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let user_id = auth.user().id();
|
|
let domain = state.domain.clone();
|
|
let handle = form.handle.clone();
|
|
|
|
let exists = state
|
|
.profiles
|
|
.store
|
|
.profiles
|
|
.by_handle(&handle, &domain)?
|
|
.is_some();
|
|
|
|
let error = if !exists {
|
|
use hyaenidae_profiles::apub::actions::CreateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&CreateProfile::from_local(user_id, handle, domain))
|
|
.await;
|
|
|
|
match res {
|
|
Ok(Some(id)) => {
|
|
middleware::ProfileData::set_data(id, &session).ok().req()?;
|
|
return Ok(to_bio());
|
|
}
|
|
Ok(None) => None,
|
|
Err(e) => Some(e.to_string()),
|
|
}
|
|
} else {
|
|
Some("Handle already in use".to_owned())
|
|
};
|
|
|
|
let mut handle_input = hyaenidae_toolkit::TextInput::new("handle");
|
|
handle_input
|
|
.placeholder("Handle")
|
|
.title("Handle")
|
|
.value(&form.handle)
|
|
.error_opt(error);
|
|
|
|
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
|
crate::templates::profiles::create::handle(cursor, &handle_input)
|
|
})
|
|
}
|
|
|
|
#[derive(Clone, Debug, serde::Deserialize)]
|
|
pub struct BioForm {
|
|
pub(crate) display_name: String,
|
|
pub(crate) description: String,
|
|
}
|
|
|
|
async fn new_bio(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
|
do_new_bio(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_new_bio(profile: Profile) -> Result<HttpResponse, Error> {
|
|
let mut display_name = hyaenidae_toolkit::TextInput::new("display_name");
|
|
display_name
|
|
.title("Display Name")
|
|
.placeholder("Display Name");
|
|
if let Some(text) = profile.display_name() {
|
|
display_name.value(text);
|
|
}
|
|
|
|
let mut description = hyaenidae_toolkit::TextInput::new("description");
|
|
description
|
|
.title("Description")
|
|
.placeholder("Description")
|
|
.textarea();
|
|
if let Some(text) = profile.description() {
|
|
description.value(text);
|
|
}
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::bio(cursor, &display_name, &description, &profile)
|
|
})
|
|
}
|
|
|
|
async fn create_bio(
|
|
form: web::Form<BioForm>,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_create_bio(form.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_create_bio(
|
|
form: BioForm,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let display_name = form.display_name.clone();
|
|
let description = form.description.clone();
|
|
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_text(
|
|
profile.id(),
|
|
display_name,
|
|
description,
|
|
))
|
|
.await;
|
|
|
|
let error = match res {
|
|
Ok(_) => return Ok(to_icon()),
|
|
Err(e) => Some(e.to_string()),
|
|
};
|
|
|
|
let mut display_name = hyaenidae_toolkit::TextInput::new("display_name");
|
|
display_name
|
|
.title("Display Name")
|
|
.placeholder("Display Name")
|
|
.value(&form.display_name)
|
|
.error_opt(error);
|
|
|
|
let mut description = hyaenidae_toolkit::TextInput::new("description");
|
|
description
|
|
.title("Description")
|
|
.placeholder("Description")
|
|
.value(&form.description);
|
|
|
|
let profile = profile.refresh(state)?;
|
|
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
|
crate::templates::profiles::create::bio(cursor, &display_name, &description, &profile)
|
|
})
|
|
}
|
|
|
|
async fn new_icon(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
|
do_new_icon(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_new_icon(profile: Profile) -> Result<HttpResponse, Error> {
|
|
let mut icon_input =
|
|
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Icon", "icon-input");
|
|
icon_input.accept(ACCEPT_TYPES);
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::icon(cursor, &icon_input, None, &profile)
|
|
})
|
|
}
|
|
|
|
async fn create_icon(
|
|
request: HttpRequest,
|
|
payload: web::Payload,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_create_icon(request, payload.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_create_icon(
|
|
request: HttpRequest,
|
|
payload: Payload,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let res = state.profiles.upload_image(request, payload).await;
|
|
|
|
let error = match res {
|
|
Ok(file_ids) if file_ids.len() == 1 => {
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_icon(profile.id(), file_ids[0]))
|
|
.await;
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_banner()),
|
|
Err(e) => Some(e.to_string()),
|
|
}
|
|
}
|
|
Ok(_) => Some("Incorrect number of files".to_owned()),
|
|
Err(e) => Some(e.to_string()),
|
|
};
|
|
|
|
let mut icon_input =
|
|
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Icon", "icon-input");
|
|
icon_input.accept(ACCEPT_TYPES);
|
|
|
|
let profile = profile.refresh(state)?;
|
|
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
|
crate::templates::profiles::create::icon(cursor, &icon_input, error, &profile)
|
|
})
|
|
}
|
|
|
|
async fn new_banner(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
|
do_new_banner(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_new_banner(profile: Profile) -> Result<HttpResponse, Error> {
|
|
let mut banner_input =
|
|
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Banner", "banner-input");
|
|
banner_input.accept(ACCEPT_TYPES);
|
|
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::banner(cursor, &banner_input, None, &profile)
|
|
})
|
|
}
|
|
|
|
async fn create_banner(
|
|
request: HttpRequest,
|
|
payload: web::Payload,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_create_banner(request, payload.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_create_banner(
|
|
request: HttpRequest,
|
|
payload: Payload,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
let res = state.profiles.upload_image(request, payload).await;
|
|
|
|
let error = match res {
|
|
Ok(file_ids) if file_ids.len() == 1 => {
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_banner(profile.id(), file_ids[0]))
|
|
.await;
|
|
|
|
match res {
|
|
Ok(_) => return Ok(to_require_login()),
|
|
Err(e) => Some(e.to_string()),
|
|
}
|
|
}
|
|
Ok(_) => Some("Incorrect number of files".to_owned()),
|
|
Err(e) => Some(e.to_string()),
|
|
};
|
|
|
|
let mut banner_input =
|
|
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Banner", "banner-input");
|
|
banner_input.accept(ACCEPT_TYPES);
|
|
|
|
let profile = profile.refresh(state)?;
|
|
crate::rendered(HttpResponse::BadRequest(), |cursor| {
|
|
crate::templates::profiles::create::banner(cursor, &banner_input, error, &profile)
|
|
})
|
|
}
|
|
|
|
#[derive(Clone, Debug, serde::Deserialize)]
|
|
struct RequireLoginForm {
|
|
require_login: Option<String>,
|
|
}
|
|
|
|
async fn new_require_login(
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_new_require_login(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_new_require_login(profile: Profile) -> Result<HttpResponse, Error> {
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::require_login(
|
|
cursor,
|
|
profile.inner.login_required(),
|
|
None,
|
|
&profile,
|
|
)
|
|
})
|
|
}
|
|
|
|
async fn create_require_login(
|
|
form: web::Form<RequireLoginForm>,
|
|
profile: Profile,
|
|
state: web::Data<State>,
|
|
) -> Result<HttpResponse, StateError> {
|
|
do_create_require_login(form.into_inner(), profile, &state)
|
|
.await
|
|
.state(&state)
|
|
}
|
|
|
|
async fn do_create_require_login(
|
|
form: RequireLoginForm,
|
|
profile: Profile,
|
|
state: &State,
|
|
) -> Result<HttpResponse, Error> {
|
|
use hyaenidae_profiles::apub::actions::UpdateProfile;
|
|
|
|
let res = state
|
|
.profiles
|
|
.run(&UpdateProfile::from_login_required(
|
|
profile.id(),
|
|
form.require_login.is_some(),
|
|
))
|
|
.await;
|
|
|
|
let error = match res {
|
|
Ok(_) => return Ok(to_done()),
|
|
Err(e) => Some(e.to_string()),
|
|
};
|
|
|
|
let profile = profile.refresh(state)?;
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::require_login(
|
|
cursor,
|
|
form.require_login.is_some(),
|
|
error,
|
|
&profile,
|
|
)
|
|
})
|
|
}
|
|
|
|
async fn done(profile: Profile, state: web::Data<State>) -> Result<HttpResponse, StateError> {
|
|
do_done(profile).await.state(&state)
|
|
}
|
|
|
|
async fn do_done(profile: Profile) -> Result<HttpResponse, Error> {
|
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
|
crate::templates::profiles::create::done(cursor, &profile)
|
|
})
|
|
}
|