hyaenidae/server/src/profiles/mod.rs

933 lines
26 KiB
Rust
Raw Normal View History

2021-01-06 08:21:37 +00:00
use crate::{
error::{Error, OptionExt, ResultExt, StateError},
State,
};
use actix_session::Session;
use actix_web::{dev::Payload, web, HttpRequest, HttpResponse, Scope};
2021-01-08 04:44:43 +00:00
use hyaenidae_accounts::{LogoutState, User};
2021-01-06 08:21:37 +00:00
use uuid::Uuid;
mod middleware;
pub(crate) use middleware::CurrentProfile;
2021-01-06 08:21:37 +00:00
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)))
2021-01-06 08:21:37 +00:00
.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)),
),
2021-01-06 08:21:37 +00:00
)
.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)))
2021-01-06 08:21:37 +00:00
.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))),
)
}
2021-01-08 04:44:43 +00:00
pub(super) fn to_create() -> HttpResponse {
2021-01-06 08:21:37 +00:00
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")
}
2021-01-06 08:21:37 +00:00
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
}
}
2021-01-06 08:21:37 +00:00
}
#[derive(Clone, Debug)]
2021-01-06 08:21:37 +00:00
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()
}
2021-01-06 16:45:43 +00:00
pub(crate) fn full_handle(&self) -> String {
format!("{}@{}", self.inner.handle(), self.inner.domain())
2021-01-06 08:21:37 +00:00
}
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,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_profile(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_profile(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
let profile_state = ProfileState::new(profile);
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::current(cursor, &profile_state, logout)
})
}
async fn update_bio(
form: web::Form<BioForm>,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_update_bio(form.into_inner(), profile, logout, &state)
.await
.state(&state)
}
async fn do_update_bio(
form: BioForm,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
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());
}
2021-01-06 08:21:37 +00:00
};
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::current(cursor, &state, logout)
})
}
async fn update_icon(
request: HttpRequest,
payload: web::Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_update_icon(request, payload.into_inner(), profile, logout, &state)
.await
.state(&state)
}
async fn do_update_icon(
request: HttpRequest,
payload: Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
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(),
2021-01-06 08:21:37 +00:00
};
let mut state = ProfileState::new(profile.refresh(state)?);
state.icon_error(&error);
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::current(cursor, &state, logout)
})
2021-01-06 08:21:37 +00:00
}
async fn update_banner(
request: HttpRequest,
payload: web::Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_update_banner(request, payload.into_inner(), profile, logout, &state)
.await
.state(&state)
2021-01-06 08:21:37 +00:00
}
async fn do_update_banner(
request: HttpRequest,
payload: Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
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| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::current(cursor, &state, logout)
})
}
async fn update_require_login(
form: web::Form<RequireLoginForm>,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_update_require_login(form.into_inner(), profile, logout, &state)
.await
.state(&state)
2021-01-06 08:21:37 +00:00
}
async fn do_update_require_login(
form: RequireLoginForm,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
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| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::current(cursor, &state, logout)
})
}
#[derive(Clone, Debug, serde::Deserialize)]
struct ChangeProfileForm {
profile_id: Uuid,
}
async fn change_profile_page(
2021-01-08 04:44:43 +00:00
user: User,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_change_profile_page(user.id(), logout, &state)
.await
.state(&state)
}
2021-01-08 04:44:43 +00:00
async fn do_change_profile_page(
user_id: Uuid,
logout: LogoutState,
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| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::list(cursor, &profiles, logout)
})
}
async fn change_profile(
2021-01-08 04:44:43 +00:00
user: User,
session: Session,
form: web::Form<ChangeProfileForm>,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
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()?;
2021-01-08 04:44:43 +00:00
Ok(crate::to_home())
2021-01-06 08:21:37 +00:00
}
#[derive(Clone, Debug, serde::Deserialize)]
pub struct HandleForm {
pub(crate) handle: String,
}
2021-01-08 04:44:43 +00:00
async fn new_handle(
_: User,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-06 08:21:37 +00:00
let mut handle_input = hyaenidae_toolkit::TextInput::new("handle");
handle_input.placeholder("Handle").title("Handle");
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::handle(cursor, &handle_input, logout)
2021-01-06 08:21:37 +00:00
})
.state(&state)
}
async fn create_handle(
2021-01-08 04:44:43 +00:00
user: User,
2021-01-06 08:21:37 +00:00
form: web::Form<HandleForm>,
session: Session,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_create_handle(user.id(), form.into_inner(), session, logout, &state)
2021-01-06 08:21:37 +00:00
.await
.state(&state)
}
async fn do_create_handle(
2021-01-08 04:44:43 +00:00
user_id: Uuid,
2021-01-06 08:21:37 +00:00
form: HandleForm,
session: Session,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: &State,
) -> Result<HttpResponse, Error> {
let domain = state.domain.clone();
let handle = form.handle.clone();
let exists = state
.profiles
.store
2021-01-06 08:21:37 +00:00
.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()),
2021-01-06 08:21:37 +00:00
}
} else {
Some("Handle already in use".to_owned())
2021-01-06 08:21:37 +00:00
};
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| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::handle(cursor, &handle_input, logout)
2021-01-06 08:21:37 +00:00
})
}
#[derive(Clone, Debug, serde::Deserialize)]
pub struct BioForm {
pub(crate) display_name: String,
pub(crate) description: String,
}
2021-01-08 04:44:43 +00:00
async fn new_bio(
profile: Profile,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
do_new_bio(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_new_bio(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
2021-01-06 08:21:37 +00:00
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| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::bio(
cursor,
&display_name,
&description,
&profile,
logout,
)
2021-01-06 08:21:37 +00:00
})
}
async fn create_bio(
form: web::Form<BioForm>,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_create_bio(form.into_inner(), profile, logout, &state)
2021-01-06 08:21:37 +00:00
.await
.state(&state)
}
async fn do_create_bio(
form: BioForm,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
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(),
2021-01-06 08:21:37 +00:00
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)?;
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::BadRequest(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::bio(
cursor,
&display_name,
&description,
&profile,
logout,
)
2021-01-06 08:21:37 +00:00
})
}
2021-01-08 04:44:43 +00:00
async fn new_icon(
profile: Profile,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
do_new_icon(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_new_icon(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
2021-01-06 16:45:43 +00:00
let mut icon_input =
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Icon", "icon-input");
icon_input.accept(ACCEPT_TYPES);
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::icon(cursor, &icon_input, None, &profile, logout)
2021-01-06 08:21:37 +00:00
})
}
async fn create_icon(
request: HttpRequest,
payload: web::Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_create_icon(request, payload.into_inner(), profile, logout, &state)
2021-01-06 08:21:37 +00:00
.await
.state(&state)
}
async fn do_create_icon(
request: HttpRequest,
payload: Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
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]))
2021-01-06 08:21:37 +00:00
.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()),
};
2021-01-06 16:45:43 +00:00
let mut icon_input =
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Icon", "icon-input");
icon_input.accept(ACCEPT_TYPES);
2021-01-06 08:21:37 +00:00
let profile = profile.refresh(state)?;
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::BadRequest(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::icon(cursor, &icon_input, error, &profile, logout)
2021-01-06 08:21:37 +00:00
})
}
2021-01-08 04:44:43 +00:00
async fn new_banner(
profile: Profile,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
do_new_banner(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_new_banner(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
2021-01-06 08:21:37 +00:00
let mut banner_input =
2021-01-06 16:45:43 +00:00
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Banner", "banner-input");
banner_input.accept(ACCEPT_TYPES);
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::banner(cursor, &banner_input, None, &profile, logout)
2021-01-06 08:21:37 +00:00
})
}
async fn create_banner(
request: HttpRequest,
payload: web::Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_create_banner(request, payload.into_inner(), profile, logout, &state)
2021-01-06 08:21:37 +00:00
.await
.state(&state)
}
async fn do_create_banner(
request: HttpRequest,
payload: Payload,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
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]))
2021-01-06 08:21:37 +00:00
.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 =
2021-01-06 16:45:43 +00:00
hyaenidae_toolkit::FileInput::secondary("images[]", "Select Banner", "banner-input");
banner_input.accept(ACCEPT_TYPES);
2021-01-06 08:21:37 +00:00
let profile = profile.refresh(state)?;
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::BadRequest(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::banner(cursor, &banner_input, error, &profile, logout)
2021-01-06 08:21:37 +00:00
})
}
#[derive(Clone, Debug, serde::Deserialize)]
struct RequireLoginForm {
require_login: Option<String>,
}
async fn new_require_login(
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_new_require_login(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_new_require_login(
profile: Profile,
logout: LogoutState,
) -> Result<HttpResponse, Error> {
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::Ok(), |cursor| {
crate::templates::profiles::create::require_login(
cursor,
profile.inner.login_required(),
None,
&profile,
2021-01-08 04:44:43 +00:00
logout,
2021-01-06 08:21:37 +00:00
)
})
}
async fn create_require_login(
form: web::Form<RequireLoginForm>,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
2021-01-08 04:44:43 +00:00
do_create_require_login(form.into_inner(), profile, logout, &state)
2021-01-06 08:21:37 +00:00
.await
.state(&state)
}
async fn do_create_require_login(
form: RequireLoginForm,
profile: Profile,
2021-01-08 04:44:43 +00:00
logout: LogoutState,
2021-01-06 08:21:37 +00:00
state: &State,
) -> Result<HttpResponse, Error> {
use hyaenidae_profiles::apub::actions::UpdateProfile;
let res = state
.profiles
.run(&UpdateProfile::from_login_required(
profile.id(),
2021-01-06 08:21:37 +00:00
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)?;
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::Ok(), |cursor| {
crate::templates::profiles::create::require_login(
cursor,
form.require_login.is_some(),
error,
&profile,
2021-01-08 04:44:43 +00:00
logout,
2021-01-06 08:21:37 +00:00
)
})
}
2021-01-08 04:44:43 +00:00
async fn done(
profile: Profile,
logout: LogoutState,
state: web::Data<State>,
) -> Result<HttpResponse, StateError> {
do_done(profile, logout).await.state(&state)
2021-01-06 08:21:37 +00:00
}
2021-01-08 04:44:43 +00:00
async fn do_done(profile: Profile, logout: LogoutState) -> Result<HttpResponse, Error> {
2021-01-06 08:21:37 +00:00
crate::rendered(HttpResponse::Ok(), |cursor| {
2021-01-08 04:44:43 +00:00
crate::templates::profiles::create::done(cursor, &profile, logout)
2021-01-06 08:21:37 +00:00
})
}