mirror of https://github.com/LemmyNet/lemmy.git
Adding views and functionality to registration application. #209
parent
9889d158f1
commit
e28977c987
|
@ -97,6 +97,9 @@
|
||||||
open_registration: true
|
open_registration: true
|
||||||
enable_nsfw: true
|
enable_nsfw: true
|
||||||
community_creation_admin_only: true
|
community_creation_admin_only: true
|
||||||
|
require_email_verification: true
|
||||||
|
require_application: true
|
||||||
|
application_question: "string"
|
||||||
}
|
}
|
||||||
# the domain name of your instance (mandatory)
|
# the domain name of your instance (mandatory)
|
||||||
hostname: "unset"
|
hostname: "unset"
|
||||||
|
|
|
@ -38,6 +38,15 @@ pub async fn match_websocket_operation(
|
||||||
UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
|
UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
|
||||||
UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
|
UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
|
||||||
UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
|
UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
|
||||||
|
UserOperation::GetUnreadRegistrationApplicationCount => {
|
||||||
|
do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ListRegistrationApplications => {
|
||||||
|
do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ApproveRegistrationApplication => {
|
||||||
|
do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
|
||||||
|
}
|
||||||
UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
|
UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
|
||||||
UserOperation::BlockPerson => {
|
UserOperation::BlockPerson => {
|
||||||
do_websocket_operation::<BlockPerson>(context, id, op, data).await
|
do_websocket_operation::<BlockPerson>(context, id, op, data).await
|
||||||
|
|
|
@ -261,6 +261,7 @@ impl Perform for SaveUserSettings {
|
||||||
show_new_post_notifs: data.show_new_post_notifs,
|
show_new_post_notifs: data.show_new_post_notifs,
|
||||||
send_notifications_to_email: data.send_notifications_to_email,
|
send_notifications_to_email: data.send_notifications_to_email,
|
||||||
email_verified: None,
|
email_verified: None,
|
||||||
|
accepted_application: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let local_user_res = blocking(context.pool(), move |conn| {
|
let local_user_res = blocking(context.pool(), move |conn| {
|
||||||
|
|
|
@ -19,9 +19,15 @@ use lemmy_apub::{
|
||||||
EndpointType,
|
EndpointType,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
diesel_option_overwrite,
|
||||||
from_opt_str_to_opt_enum,
|
from_opt_str_to_opt_enum,
|
||||||
newtypes::PersonId,
|
newtypes::PersonId,
|
||||||
source::{moderator::*, site::Site},
|
source::{
|
||||||
|
local_user::{LocalUser, LocalUserForm},
|
||||||
|
moderator::*,
|
||||||
|
registration_application::{RegistrationApplication, RegistrationApplicationForm},
|
||||||
|
site::Site,
|
||||||
|
},
|
||||||
traits::{Crud, DeleteableOrRemoveable},
|
traits::{Crud, DeleteableOrRemoveable},
|
||||||
DbPool,
|
DbPool,
|
||||||
ListingType,
|
ListingType,
|
||||||
|
@ -31,6 +37,10 @@ use lemmy_db_schema::{
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
comment_view::{CommentQueryBuilder, CommentView},
|
comment_view::{CommentQueryBuilder, CommentView},
|
||||||
post_view::{PostQueryBuilder, PostView},
|
post_view::{PostQueryBuilder, PostView},
|
||||||
|
registration_application_view::{
|
||||||
|
RegistrationApplicationQueryBuilder,
|
||||||
|
RegistrationApplicationView,
|
||||||
|
},
|
||||||
site_view::SiteView,
|
site_view::SiteView,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::{
|
use lemmy_db_views_actor::{
|
||||||
|
@ -550,3 +560,131 @@ impl Perform for SaveSiteConfig {
|
||||||
Ok(GetSiteConfigResponse { config_hjson })
|
Ok(GetSiteConfigResponse { config_hjson })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists registration applications, filterable by undenied only.
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ListRegistrationApplications {
|
||||||
|
type Response = ListRegistrationApplicationsResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<Self::Response, LemmyError> {
|
||||||
|
let data = self;
|
||||||
|
let local_user_view =
|
||||||
|
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
|
||||||
|
|
||||||
|
// Make sure user is an admin
|
||||||
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
let unread_only = data.unread_only;
|
||||||
|
let verified_email_only = blocking(context.pool(), Site::read_simple)
|
||||||
|
.await??
|
||||||
|
.require_email_verification;
|
||||||
|
|
||||||
|
let page = data.page;
|
||||||
|
let limit = data.limit;
|
||||||
|
let registration_applications = blocking(context.pool(), move |conn| {
|
||||||
|
RegistrationApplicationQueryBuilder::create(conn)
|
||||||
|
.unread_only(unread_only)
|
||||||
|
.verified_email_only(verified_email_only)
|
||||||
|
.page(page)
|
||||||
|
.limit(limit)
|
||||||
|
.list()
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
let res = Self::Response {
|
||||||
|
registration_applications,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ApproveRegistrationApplication {
|
||||||
|
type Response = RegistrationApplicationResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<Self::Response, LemmyError> {
|
||||||
|
let data = self;
|
||||||
|
let local_user_view =
|
||||||
|
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
|
||||||
|
|
||||||
|
let app_id = data.id;
|
||||||
|
|
||||||
|
// Only let admins do this
|
||||||
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
// Update the registration with reason, admin_id
|
||||||
|
let deny_reason = diesel_option_overwrite(&data.deny_reason);
|
||||||
|
let app_form = RegistrationApplicationForm {
|
||||||
|
admin_id: Some(local_user_view.person.id),
|
||||||
|
deny_reason,
|
||||||
|
..RegistrationApplicationForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let registration_application = blocking(context.pool(), move |conn| {
|
||||||
|
RegistrationApplication::update(conn, app_id, &app_form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
// Update the local_user row
|
||||||
|
let local_user_form = LocalUserForm {
|
||||||
|
accepted_application: Some(data.approve),
|
||||||
|
..LocalUserForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let approved_user_id = registration_application.local_user_id;
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
LocalUser::update(conn, approved_user_id, &local_user_form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
// Read the view
|
||||||
|
let registration_application = blocking(context.pool(), move |conn| {
|
||||||
|
RegistrationApplicationView::read(conn, app_id)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
Ok(Self::Response {
|
||||||
|
registration_application,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for GetUnreadRegistrationApplicationCount {
|
||||||
|
type Response = GetUnreadRegistrationApplicationCountResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<Self::Response, LemmyError> {
|
||||||
|
let data = self;
|
||||||
|
let local_user_view =
|
||||||
|
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
|
||||||
|
|
||||||
|
// Only let admins do this
|
||||||
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
let verified_email_only = blocking(context.pool(), Site::read_simple)
|
||||||
|
.await??
|
||||||
|
.require_email_verification;
|
||||||
|
|
||||||
|
let registration_applications = blocking(context.pool(), move |conn| {
|
||||||
|
RegistrationApplicationView::get_unread_count(conn, verified_email_only)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
Ok(Self::Response {
|
||||||
|
registration_applications,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ pub struct Register {
|
||||||
pub captcha_uuid: Option<String>,
|
pub captcha_uuid: Option<String>,
|
||||||
pub captcha_answer: Option<String>,
|
pub captcha_answer: Option<String>,
|
||||||
pub honeypot: Option<String>,
|
pub honeypot: Option<String>,
|
||||||
|
/// An answer is mandatory if require application is enabled on the server
|
||||||
|
pub answer: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use lemmy_db_views::{
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
local_user_view::LocalUserSettingsView,
|
local_user_view::LocalUserSettingsView,
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
|
registration_application_view::RegistrationApplicationView,
|
||||||
site_view::SiteView,
|
site_view::SiteView,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::{
|
use lemmy_db_views_actor::{
|
||||||
|
@ -97,6 +98,9 @@ pub struct CreateSite {
|
||||||
pub open_registration: Option<bool>,
|
pub open_registration: Option<bool>,
|
||||||
pub enable_nsfw: Option<bool>,
|
pub enable_nsfw: Option<bool>,
|
||||||
pub community_creation_admin_only: Option<bool>,
|
pub community_creation_admin_only: Option<bool>,
|
||||||
|
pub require_email_verification: Option<bool>,
|
||||||
|
pub require_application: Option<bool>,
|
||||||
|
pub application_question: Option<String>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +116,8 @@ pub struct EditSite {
|
||||||
pub enable_nsfw: Option<bool>,
|
pub enable_nsfw: Option<bool>,
|
||||||
pub community_creation_admin_only: Option<bool>,
|
pub community_creation_admin_only: Option<bool>,
|
||||||
pub require_email_verification: Option<bool>,
|
pub require_email_verification: Option<bool>,
|
||||||
|
pub require_application: Option<bool>,
|
||||||
|
pub application_question: Option<String>,
|
||||||
pub auth: String,
|
pub auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,3 +179,40 @@ pub struct FederatedInstances {
|
||||||
pub allowed: Option<Vec<String>>,
|
pub allowed: Option<Vec<String>>,
|
||||||
pub blocked: Option<Vec<String>>,
|
pub blocked: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ListRegistrationApplications {
|
||||||
|
/// Only shows the unread applications (IE those without an admin actor)
|
||||||
|
pub unread_only: Option<bool>,
|
||||||
|
pub page: Option<i64>,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ListRegistrationApplicationsResponse {
|
||||||
|
pub registration_applications: Vec<RegistrationApplicationView>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ApproveRegistrationApplication {
|
||||||
|
pub id: i32,
|
||||||
|
pub approve: bool,
|
||||||
|
pub deny_reason: Option<String>,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct RegistrationApplicationResponse {
|
||||||
|
pub registration_application: RegistrationApplicationView,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct GetUnreadRegistrationApplicationCount {
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct GetUnreadRegistrationApplicationCountResponse {
|
||||||
|
pub registration_applications: i64,
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ impl PerformCrud for GetSite {
|
||||||
captcha_uuid: None,
|
captcha_uuid: None,
|
||||||
captcha_answer: None,
|
captcha_answer: None,
|
||||||
honeypot: None,
|
honeypot: None,
|
||||||
|
answer: None,
|
||||||
};
|
};
|
||||||
let admin_jwt = register
|
let admin_jwt = register
|
||||||
.perform(context, websocket_id)
|
.perform(context, websocket_id)
|
||||||
|
@ -62,6 +63,9 @@ impl PerformCrud for GetSite {
|
||||||
open_registration: setup.open_registration,
|
open_registration: setup.open_registration,
|
||||||
enable_nsfw: setup.enable_nsfw,
|
enable_nsfw: setup.enable_nsfw,
|
||||||
community_creation_admin_only: setup.community_creation_admin_only,
|
community_creation_admin_only: setup.community_creation_admin_only,
|
||||||
|
require_email_verification: setup.require_email_verification,
|
||||||
|
require_application: setup.require_application,
|
||||||
|
application_question: setup.application_question.to_owned(),
|
||||||
auth: admin_jwt,
|
auth: admin_jwt,
|
||||||
};
|
};
|
||||||
create_site.perform(context, websocket_id).await?;
|
create_site.perform(context, websocket_id).await?;
|
||||||
|
|
|
@ -40,6 +40,7 @@ impl PerformCrud for EditSite {
|
||||||
|
|
||||||
let sidebar = diesel_option_overwrite(&data.sidebar);
|
let sidebar = diesel_option_overwrite(&data.sidebar);
|
||||||
let description = diesel_option_overwrite(&data.description);
|
let description = diesel_option_overwrite(&data.description);
|
||||||
|
let application_question = diesel_option_overwrite(&data.application_question);
|
||||||
let icon = diesel_option_overwrite_to_url(&data.icon)?;
|
let icon = diesel_option_overwrite_to_url(&data.icon)?;
|
||||||
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
let banner = diesel_option_overwrite_to_url(&data.banner)?;
|
||||||
|
|
||||||
|
@ -60,6 +61,8 @@ impl PerformCrud for EditSite {
|
||||||
enable_nsfw: data.enable_nsfw,
|
enable_nsfw: data.enable_nsfw,
|
||||||
community_creation_admin_only: data.community_creation_admin_only,
|
community_creation_admin_only: data.community_creation_admin_only,
|
||||||
require_email_verification: data.require_email_verification,
|
require_email_verification: data.require_email_verification,
|
||||||
|
require_application: data.require_application,
|
||||||
|
application_question,
|
||||||
};
|
};
|
||||||
|
|
||||||
let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
|
let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
|
||||||
|
|
|
@ -21,6 +21,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
local_user::{LocalUser, LocalUserForm},
|
local_user::{LocalUser, LocalUserForm},
|
||||||
person::{Person, PersonForm},
|
person::{Person, PersonForm},
|
||||||
|
registration_application::{RegistrationApplication, RegistrationApplicationForm},
|
||||||
site::Site,
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::{Crud, Followable, Joinable},
|
traits::{Crud, Followable, Joinable},
|
||||||
|
@ -47,8 +48,8 @@ impl PerformCrud for Register {
|
||||||
) -> Result<LoginResponse, LemmyError> {
|
) -> Result<LoginResponse, LemmyError> {
|
||||||
let data: &Register = self;
|
let data: &Register = self;
|
||||||
|
|
||||||
// no email verification if the site is not setup yet
|
// no email verification, or applications if the site is not setup yet
|
||||||
let mut email_verification = false;
|
let (mut email_verification, mut require_application) = (false, false);
|
||||||
|
|
||||||
// Make sure site has open registration
|
// Make sure site has open registration
|
||||||
if let Ok(site) = blocking(context.pool(), Site::read_simple).await? {
|
if let Ok(site) = blocking(context.pool(), Site::read_simple).await? {
|
||||||
|
@ -56,6 +57,7 @@ impl PerformCrud for Register {
|
||||||
return Err(ApiError::err_plain("registration_closed").into());
|
return Err(ApiError::err_plain("registration_closed").into());
|
||||||
}
|
}
|
||||||
email_verification = site.require_email_verification;
|
email_verification = site.require_email_verification;
|
||||||
|
require_application = site.require_application;
|
||||||
}
|
}
|
||||||
|
|
||||||
password_length_check(&data.password)?;
|
password_length_check(&data.password)?;
|
||||||
|
@ -65,6 +67,10 @@ impl PerformCrud for Register {
|
||||||
return Err(ApiError::err_plain("email_required").into());
|
return Err(ApiError::err_plain("email_required").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if require_application && data.answer.is_none() {
|
||||||
|
return Err(ApiError::err_plain("registration_application_answer_required").into());
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure passwords match
|
// Make sure passwords match
|
||||||
if data.password != data.password_verify {
|
if data.password != data.password_verify {
|
||||||
return Err(ApiError::err_plain("passwords_dont_match").into());
|
return Err(ApiError::err_plain("passwords_dont_match").into());
|
||||||
|
@ -164,6 +170,21 @@ impl PerformCrud for Register {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if require_application {
|
||||||
|
// Create the registration application
|
||||||
|
let form = RegistrationApplicationForm {
|
||||||
|
local_user_id: Some(inserted_local_user.id),
|
||||||
|
// We already made sure answer was not null above
|
||||||
|
answer: data.answer.to_owned(),
|
||||||
|
..RegistrationApplicationForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
blocking(context.pool(), move |conn| {
|
||||||
|
RegistrationApplication::create(conn, &form)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
}
|
||||||
|
|
||||||
let main_community_keypair = generate_actor_keypair()?;
|
let main_community_keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
// Create the main community if it doesn't exist
|
// Create the main community if it doesn't exist
|
||||||
|
@ -243,6 +264,7 @@ impl PerformCrud for Register {
|
||||||
&context.settings().hostname,
|
&context.settings().hostname,
|
||||||
)?)
|
)?)
|
||||||
};
|
};
|
||||||
|
// TODO this needs a "registration created" type response
|
||||||
Ok(LoginResponse { jwt })
|
Ok(LoginResponse { jwt })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
community_creation_admin_only: Some(false),
|
community_creation_admin_only: Some(false),
|
||||||
require_email_verification: None,
|
require_email_verification: None,
|
||||||
|
require_application: None,
|
||||||
|
application_question: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Site::create(&conn, &site_form).unwrap();
|
Site::create(&conn, &site_form).unwrap();
|
||||||
|
|
|
@ -13,5 +13,6 @@ pub mod person_mention;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod post_report;
|
pub mod post_report;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
|
pub mod registration_application;
|
||||||
pub mod secret;
|
pub mod secret;
|
||||||
pub mod site;
|
pub mod site;
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::{source::registration_application::*, traits::Crud};
|
||||||
|
use diesel::{insert_into, result::Error, PgConnection, QueryDsl, RunQueryDsl};
|
||||||
|
|
||||||
|
impl Crud for RegistrationApplication {
|
||||||
|
type Form = RegistrationApplicationForm;
|
||||||
|
type IdType = i32;
|
||||||
|
fn create(conn: &PgConnection, form: &Self::Form) -> Result<Self, Error> {
|
||||||
|
use crate::schema::registration_application::dsl::*;
|
||||||
|
insert_into(registration_application)
|
||||||
|
.values(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(conn: &PgConnection, id_: Self::IdType) -> Result<Self, Error> {
|
||||||
|
use crate::schema::registration_application::dsl::*;
|
||||||
|
registration_application.find(id_).first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(conn: &PgConnection, id_: Self::IdType, form: &Self::Form) -> Result<Self, Error> {
|
||||||
|
use crate::schema::registration_application::dsl::*;
|
||||||
|
diesel::update(registration_application.find(id_))
|
||||||
|
.set(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete(conn: &PgConnection, id_: Self::IdType) -> Result<usize, Error> {
|
||||||
|
use crate::schema::registration_application::dsl::*;
|
||||||
|
diesel::delete(registration_application.find(id_)).execute(conn)
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,6 +158,7 @@ table! {
|
||||||
show_read_posts -> Bool,
|
show_read_posts -> Bool,
|
||||||
show_new_post_notifs -> Bool,
|
show_new_post_notifs -> Bool,
|
||||||
email_verified -> Bool,
|
email_verified -> Bool,
|
||||||
|
accepted_application -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,6 +450,8 @@ table! {
|
||||||
description -> Nullable<Text>,
|
description -> Nullable<Text>,
|
||||||
community_creation_admin_only -> Bool,
|
community_creation_admin_only -> Bool,
|
||||||
require_email_verification -> Bool,
|
require_email_verification -> Bool,
|
||||||
|
require_application -> Bool,
|
||||||
|
application_question -> Nullable<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,6 +572,17 @@ table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
registration_application (id) {
|
||||||
|
id -> Int4,
|
||||||
|
local_user_id -> Int4,
|
||||||
|
answer -> Text,
|
||||||
|
admin_id -> Nullable<Int4>,
|
||||||
|
deny_reason -> Nullable<Text>,
|
||||||
|
published -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
joinable!(comment_alias_1 -> person_alias_1 (creator_id));
|
joinable!(comment_alias_1 -> person_alias_1 (creator_id));
|
||||||
joinable!(comment -> comment_alias_1 (parent_id));
|
joinable!(comment -> comment_alias_1 (parent_id));
|
||||||
joinable!(person_mention -> person_alias_1 (recipient_id));
|
joinable!(person_mention -> person_alias_1 (recipient_id));
|
||||||
|
@ -631,6 +645,8 @@ joinable!(post_saved -> post (post_id));
|
||||||
joinable!(site -> person (creator_id));
|
joinable!(site -> person (creator_id));
|
||||||
joinable!(site_aggregates -> site (site_id));
|
joinable!(site_aggregates -> site (site_id));
|
||||||
joinable!(email_verification -> local_user (local_user_id));
|
joinable!(email_verification -> local_user (local_user_id));
|
||||||
|
joinable!(registration_application -> local_user (local_user_id));
|
||||||
|
joinable!(registration_application -> person (admin_id));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(
|
||||||
activity,
|
activity,
|
||||||
|
@ -674,5 +690,6 @@ allow_tables_to_appear_in_same_query!(
|
||||||
comment_alias_1,
|
comment_alias_1,
|
||||||
person_alias_1,
|
person_alias_1,
|
||||||
person_alias_2,
|
person_alias_2,
|
||||||
email_verification
|
email_verification,
|
||||||
|
registration_application
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub struct LocalUser {
|
||||||
pub show_read_posts: bool,
|
pub show_read_posts: bool,
|
||||||
pub show_new_post_notifs: bool,
|
pub show_new_post_notifs: bool,
|
||||||
pub email_verified: bool,
|
pub email_verified: bool,
|
||||||
|
pub accepted_application: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO redo these, check table defaults
|
// TODO redo these, check table defaults
|
||||||
|
@ -45,6 +46,7 @@ pub struct LocalUserForm {
|
||||||
pub show_read_posts: Option<bool>,
|
pub show_read_posts: Option<bool>,
|
||||||
pub show_new_post_notifs: Option<bool>,
|
pub show_new_post_notifs: Option<bool>,
|
||||||
pub email_verified: Option<bool>,
|
pub email_verified: Option<bool>,
|
||||||
|
pub accepted_application: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A local user view that removes password encrypted
|
/// A local user view that removes password encrypted
|
||||||
|
|
|
@ -13,5 +13,6 @@ pub mod person_mention;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod post_report;
|
pub mod post_report;
|
||||||
pub mod private_message;
|
pub mod private_message;
|
||||||
|
pub mod registration_application;
|
||||||
pub mod secret;
|
pub mod secret;
|
||||||
pub mod site;
|
pub mod site;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
use crate::{
|
||||||
|
newtypes::{LocalUserId, PersonId},
|
||||||
|
schema::registration_application,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
#[table_name = "registration_application"]
|
||||||
|
pub struct RegistrationApplication {
|
||||||
|
pub id: i32,
|
||||||
|
pub local_user_id: LocalUserId,
|
||||||
|
pub answer: String,
|
||||||
|
pub admin_id: Option<PersonId>,
|
||||||
|
pub deny_reason: Option<String>,
|
||||||
|
pub published: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable, AsChangeset, Default)]
|
||||||
|
#[table_name = "registration_application"]
|
||||||
|
pub struct RegistrationApplicationForm {
|
||||||
|
pub local_user_id: Option<LocalUserId>,
|
||||||
|
pub answer: Option<String>,
|
||||||
|
pub admin_id: Option<PersonId>,
|
||||||
|
pub deny_reason: Option<Option<String>>,
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ pub struct Site {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub community_creation_admin_only: bool,
|
pub community_creation_admin_only: bool,
|
||||||
pub require_email_verification: bool,
|
pub require_email_verification: bool,
|
||||||
|
pub require_application: bool,
|
||||||
|
pub application_question: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset, Default)]
|
#[derive(Insertable, AsChangeset, Default)]
|
||||||
|
@ -39,4 +41,6 @@ pub struct SiteForm {
|
||||||
pub description: Option<Option<String>>,
|
pub description: Option<Option<String>>,
|
||||||
pub community_creation_admin_only: Option<bool>,
|
pub community_creation_admin_only: Option<bool>,
|
||||||
pub require_email_verification: Option<bool>,
|
pub require_email_verification: Option<bool>,
|
||||||
|
pub require_application: Option<bool>,
|
||||||
|
pub application_question: Option<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,5 @@ pub mod local_user_view;
|
||||||
pub mod post_report_view;
|
pub mod post_report_view;
|
||||||
pub mod post_view;
|
pub mod post_view;
|
||||||
pub mod private_message_view;
|
pub mod private_message_view;
|
||||||
|
pub mod registration_application_view;
|
||||||
pub mod site_view;
|
pub mod site_view;
|
||||||
|
|
|
@ -0,0 +1,378 @@
|
||||||
|
use diesel::{dsl::count, result::Error, *};
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
limit_and_offset,
|
||||||
|
schema::{local_user, person, person_alias_1, registration_application},
|
||||||
|
source::{
|
||||||
|
local_user::LocalUser,
|
||||||
|
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
|
||||||
|
registration_application::RegistrationApplication,
|
||||||
|
},
|
||||||
|
traits::{MaybeOptional, ToSafe, ViewToVec},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct RegistrationApplicationView {
|
||||||
|
pub registration_application: RegistrationApplication,
|
||||||
|
pub creator_local_user: LocalUser,
|
||||||
|
pub creator: PersonSafe,
|
||||||
|
pub admin: Option<PersonSafeAlias1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegistrationApplicationViewTuple = (
|
||||||
|
RegistrationApplication,
|
||||||
|
LocalUser,
|
||||||
|
PersonSafe,
|
||||||
|
Option<PersonSafeAlias1>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl RegistrationApplicationView {
|
||||||
|
pub fn read(conn: &PgConnection, registration_application_id: i32) -> Result<Self, Error> {
|
||||||
|
let (registration_application, creator_local_user, creator, admin) =
|
||||||
|
registration_application::table
|
||||||
|
.find(registration_application_id)
|
||||||
|
.inner_join(
|
||||||
|
local_user::table.on(registration_application::local_user_id.eq(local_user::id)),
|
||||||
|
)
|
||||||
|
.inner_join(person::table.on(local_user::person_id.eq(person::id)))
|
||||||
|
.left_join(
|
||||||
|
person_alias_1::table
|
||||||
|
.on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
|
||||||
|
)
|
||||||
|
.order_by(registration_application::published.desc())
|
||||||
|
.select((
|
||||||
|
registration_application::all_columns,
|
||||||
|
local_user::all_columns,
|
||||||
|
Person::safe_columns_tuple(),
|
||||||
|
PersonAlias1::safe_columns_tuple().nullable(),
|
||||||
|
))
|
||||||
|
.first::<RegistrationApplicationViewTuple>(conn)?;
|
||||||
|
|
||||||
|
Ok(RegistrationApplicationView {
|
||||||
|
registration_application,
|
||||||
|
creator_local_user,
|
||||||
|
creator,
|
||||||
|
admin,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current unread registration_application count
|
||||||
|
pub fn get_unread_count(conn: &PgConnection, verified_email_only: bool) -> Result<i64, Error> {
|
||||||
|
let mut query = registration_application::table
|
||||||
|
.inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
|
||||||
|
.inner_join(person::table.on(local_user::person_id.eq(person::id)))
|
||||||
|
.left_join(
|
||||||
|
person_alias_1::table
|
||||||
|
.on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
|
||||||
|
)
|
||||||
|
.filter(registration_application::admin_id.is_null())
|
||||||
|
.into_boxed();
|
||||||
|
|
||||||
|
if verified_email_only {
|
||||||
|
query = query.filter(local_user::email_verified.eq(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
query
|
||||||
|
.select(count(registration_application::id))
|
||||||
|
.first::<i64>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RegistrationApplicationQueryBuilder<'a> {
|
||||||
|
conn: &'a PgConnection,
|
||||||
|
unread_only: Option<bool>,
|
||||||
|
verified_email_only: Option<bool>,
|
||||||
|
page: Option<i64>,
|
||||||
|
limit: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RegistrationApplicationQueryBuilder<'a> {
|
||||||
|
pub fn create(conn: &'a PgConnection) -> Self {
|
||||||
|
RegistrationApplicationQueryBuilder {
|
||||||
|
conn,
|
||||||
|
unread_only: None,
|
||||||
|
verified_email_only: None,
|
||||||
|
page: None,
|
||||||
|
limit: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
|
||||||
|
self.unread_only = unread_only.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verified_email_only<T: MaybeOptional<bool>>(mut self, verified_email_only: T) -> Self {
|
||||||
|
self.verified_email_only = verified_email_only.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
|
||||||
|
self.page = page.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
|
||||||
|
self.limit = limit.get_optional();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list(self) -> Result<Vec<RegistrationApplicationView>, Error> {
|
||||||
|
let mut query = registration_application::table
|
||||||
|
.inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
|
||||||
|
.inner_join(person::table.on(local_user::person_id.eq(person::id)))
|
||||||
|
.left_join(
|
||||||
|
person_alias_1::table
|
||||||
|
.on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
|
||||||
|
)
|
||||||
|
.order_by(registration_application::published.desc())
|
||||||
|
.select((
|
||||||
|
registration_application::all_columns,
|
||||||
|
local_user::all_columns,
|
||||||
|
Person::safe_columns_tuple(),
|
||||||
|
PersonAlias1::safe_columns_tuple().nullable(),
|
||||||
|
))
|
||||||
|
.into_boxed();
|
||||||
|
|
||||||
|
if self.unread_only.unwrap_or(false) {
|
||||||
|
query = query.filter(registration_application::admin_id.is_null())
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.verified_email_only.unwrap_or(false) {
|
||||||
|
query = query.filter(local_user::email_verified.eq(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
let (limit, offset) = limit_and_offset(self.page, self.limit);
|
||||||
|
|
||||||
|
query = query
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset)
|
||||||
|
.order_by(registration_application::published.desc());
|
||||||
|
|
||||||
|
let res = query.load::<RegistrationApplicationViewTuple>(self.conn)?;
|
||||||
|
|
||||||
|
Ok(RegistrationApplicationView::from_tuple_to_vec(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewToVec for RegistrationApplicationView {
|
||||||
|
type DbTuple = RegistrationApplicationViewTuple;
|
||||||
|
fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
|
||||||
|
items
|
||||||
|
.iter()
|
||||||
|
.map(|a| Self {
|
||||||
|
registration_application: a.0.to_owned(),
|
||||||
|
creator_local_user: a.1.to_owned(),
|
||||||
|
creator: a.2.to_owned(),
|
||||||
|
admin: a.3.to_owned(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<Self>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::registration_application_view::{
|
||||||
|
RegistrationApplicationQueryBuilder,
|
||||||
|
RegistrationApplicationView,
|
||||||
|
};
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
establish_unpooled_connection,
|
||||||
|
source::{
|
||||||
|
local_user::{LocalUser, LocalUserForm},
|
||||||
|
person::*,
|
||||||
|
registration_application::{RegistrationApplication, RegistrationApplicationForm},
|
||||||
|
},
|
||||||
|
traits::Crud,
|
||||||
|
};
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_crud() {
|
||||||
|
let conn = establish_unpooled_connection();
|
||||||
|
|
||||||
|
let timmy_person_form = PersonForm {
|
||||||
|
name: "timmy_rav".into(),
|
||||||
|
admin: Some(true),
|
||||||
|
..PersonForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_timmy_person = Person::create(&conn, &timmy_person_form).unwrap();
|
||||||
|
|
||||||
|
let timmy_local_user_form = LocalUserForm {
|
||||||
|
person_id: Some(inserted_timmy_person.id),
|
||||||
|
password_encrypted: Some("nada".to_string()),
|
||||||
|
..LocalUserForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let _inserted_timmy_local_user = LocalUser::create(&conn, &timmy_local_user_form).unwrap();
|
||||||
|
|
||||||
|
let sara_person_form = PersonForm {
|
||||||
|
name: "sara_rav".into(),
|
||||||
|
..PersonForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_sara_person = Person::create(&conn, &sara_person_form).unwrap();
|
||||||
|
|
||||||
|
let sara_local_user_form = LocalUserForm {
|
||||||
|
person_id: Some(inserted_sara_person.id),
|
||||||
|
password_encrypted: Some("nada".to_string()),
|
||||||
|
..LocalUserForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_sara_local_user = LocalUser::create(&conn, &sara_local_user_form).unwrap();
|
||||||
|
|
||||||
|
// Sara creates an application
|
||||||
|
let sara_app_form = RegistrationApplicationForm {
|
||||||
|
local_user_id: Some(inserted_sara_local_user.id),
|
||||||
|
answer: Some("LET ME IIIIINN".to_string()),
|
||||||
|
..RegistrationApplicationForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let sara_app = RegistrationApplication::create(&conn, &sara_app_form).unwrap();
|
||||||
|
|
||||||
|
let read_sara_app_view = RegistrationApplicationView::read(&conn, sara_app.id).unwrap();
|
||||||
|
|
||||||
|
let jess_person_form = PersonForm {
|
||||||
|
name: "jess_rav".into(),
|
||||||
|
..PersonForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_jess_person = Person::create(&conn, &jess_person_form).unwrap();
|
||||||
|
|
||||||
|
let jess_local_user_form = LocalUserForm {
|
||||||
|
person_id: Some(inserted_jess_person.id),
|
||||||
|
password_encrypted: Some("nada".to_string()),
|
||||||
|
..LocalUserForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_jess_local_user = LocalUser::create(&conn, &jess_local_user_form).unwrap();
|
||||||
|
|
||||||
|
// Sara creates an application
|
||||||
|
let jess_app_form = RegistrationApplicationForm {
|
||||||
|
local_user_id: Some(inserted_jess_local_user.id),
|
||||||
|
answer: Some("LET ME IIIIINN".to_string()),
|
||||||
|
..RegistrationApplicationForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let jess_app = RegistrationApplication::create(&conn, &jess_app_form).unwrap();
|
||||||
|
|
||||||
|
let read_jess_app_view = RegistrationApplicationView::read(&conn, jess_app.id).unwrap();
|
||||||
|
|
||||||
|
let mut expected_sara_app_view = RegistrationApplicationView {
|
||||||
|
registration_application: sara_app.to_owned(),
|
||||||
|
creator_local_user: inserted_sara_local_user.to_owned(),
|
||||||
|
creator: PersonSafe {
|
||||||
|
id: inserted_sara_person.id,
|
||||||
|
name: inserted_sara_person.name.to_owned(),
|
||||||
|
display_name: None,
|
||||||
|
published: inserted_sara_person.published,
|
||||||
|
avatar: None,
|
||||||
|
actor_id: inserted_sara_person.actor_id.to_owned(),
|
||||||
|
local: true,
|
||||||
|
banned: false,
|
||||||
|
deleted: false,
|
||||||
|
admin: false,
|
||||||
|
bot_account: false,
|
||||||
|
bio: None,
|
||||||
|
banner: None,
|
||||||
|
updated: None,
|
||||||
|
inbox_url: inserted_sara_person.inbox_url.to_owned(),
|
||||||
|
shared_inbox_url: None,
|
||||||
|
matrix_user_id: None,
|
||||||
|
},
|
||||||
|
admin: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(read_sara_app_view, expected_sara_app_view);
|
||||||
|
|
||||||
|
// Do a batch read of the applications
|
||||||
|
let apps = RegistrationApplicationQueryBuilder::create(&conn)
|
||||||
|
.unread_only(true)
|
||||||
|
.list()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
apps,
|
||||||
|
[
|
||||||
|
read_jess_app_view.to_owned(),
|
||||||
|
expected_sara_app_view.to_owned()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Make sure the counts are correct
|
||||||
|
let unread_count = RegistrationApplicationView::get_unread_count(&conn, false).unwrap();
|
||||||
|
assert_eq!(unread_count, 2);
|
||||||
|
|
||||||
|
// Approve the application
|
||||||
|
let approve_form = RegistrationApplicationForm {
|
||||||
|
admin_id: Some(inserted_timmy_person.id),
|
||||||
|
deny_reason: None,
|
||||||
|
..RegistrationApplicationForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
RegistrationApplication::update(&conn, sara_app.id, &approve_form).unwrap();
|
||||||
|
|
||||||
|
// Update the local_user row
|
||||||
|
let approve_local_user_form = LocalUserForm {
|
||||||
|
accepted_application: Some(true),
|
||||||
|
..LocalUserForm::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalUser::update(&conn, inserted_sara_local_user.id, &approve_local_user_form).unwrap();
|
||||||
|
|
||||||
|
let read_sara_app_view_after_approve =
|
||||||
|
RegistrationApplicationView::read(&conn, sara_app.id).unwrap();
|
||||||
|
|
||||||
|
// Make sure the columns changed
|
||||||
|
expected_sara_app_view
|
||||||
|
.creator_local_user
|
||||||
|
.accepted_application = true;
|
||||||
|
expected_sara_app_view.registration_application.admin_id = Some(inserted_timmy_person.id);
|
||||||
|
|
||||||
|
expected_sara_app_view.admin = Some(PersonSafeAlias1 {
|
||||||
|
id: inserted_timmy_person.id,
|
||||||
|
name: inserted_timmy_person.name.to_owned(),
|
||||||
|
display_name: None,
|
||||||
|
published: inserted_timmy_person.published,
|
||||||
|
avatar: None,
|
||||||
|
actor_id: inserted_timmy_person.actor_id.to_owned(),
|
||||||
|
local: true,
|
||||||
|
banned: false,
|
||||||
|
deleted: false,
|
||||||
|
admin: true,
|
||||||
|
bot_account: false,
|
||||||
|
bio: None,
|
||||||
|
banner: None,
|
||||||
|
updated: None,
|
||||||
|
inbox_url: inserted_timmy_person.inbox_url.to_owned(),
|
||||||
|
shared_inbox_url: None,
|
||||||
|
matrix_user_id: None,
|
||||||
|
});
|
||||||
|
assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
|
||||||
|
|
||||||
|
// Do a batch read of apps again
|
||||||
|
// It should show only jessicas which is unresolved
|
||||||
|
let apps_after_resolve = RegistrationApplicationQueryBuilder::create(&conn)
|
||||||
|
.unread_only(true)
|
||||||
|
.list()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
|
||||||
|
|
||||||
|
// Make sure the counts are correct
|
||||||
|
let unread_count_after_approve =
|
||||||
|
RegistrationApplicationView::get_unread_count(&conn, false).unwrap();
|
||||||
|
assert_eq!(unread_count_after_approve, 1);
|
||||||
|
|
||||||
|
// Make sure the not undenied_only has all the apps
|
||||||
|
let all_apps = RegistrationApplicationQueryBuilder::create(&conn)
|
||||||
|
.list()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(all_apps.len(), 2);
|
||||||
|
|
||||||
|
Person::delete(&conn, inserted_timmy_person.id).unwrap();
|
||||||
|
Person::delete(&conn, inserted_sara_person.id).unwrap();
|
||||||
|
Person::delete(&conn, inserted_jess_person.id).unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -187,4 +187,10 @@ pub struct SetupConfig {
|
||||||
pub enable_nsfw: Option<bool>,
|
pub enable_nsfw: Option<bool>,
|
||||||
#[default(None)]
|
#[default(None)]
|
||||||
pub community_creation_admin_only: Option<bool>,
|
pub community_creation_admin_only: Option<bool>,
|
||||||
|
#[default(None)]
|
||||||
|
pub require_email_verification: Option<bool>,
|
||||||
|
#[default(None)]
|
||||||
|
pub require_application: Option<bool>,
|
||||||
|
#[default(None)]
|
||||||
|
pub application_question: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,9 @@ pub enum UserOperation {
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
AddModToCommunity,
|
AddModToCommunity,
|
||||||
AddAdmin,
|
AddAdmin,
|
||||||
|
GetUnreadRegistrationApplicationCount,
|
||||||
|
ListRegistrationApplications,
|
||||||
|
ApproveRegistrationApplication,
|
||||||
BanPerson,
|
BanPerson,
|
||||||
Search,
|
Search,
|
||||||
ResolveObject,
|
ResolveObject,
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
-- This file should undo anything in `up.sql`
|
|
||||||
-- Add columns to site table
|
-- Add columns to site table
|
||||||
alter table site drop column require_application;
|
alter table site drop column require_application;
|
||||||
alter table site drop column require_email;
|
|
||||||
alter table site drop column application_question;
|
alter table site drop column application_question;
|
||||||
|
|
||||||
-- Add pending to local_user
|
-- Add pending to local_user
|
||||||
alter table local_user drop column accepted_application;
|
alter table local_user drop column accepted_application;
|
||||||
alter table local_user drop column verified_email;
|
|
||||||
|
|
||||||
drop table registration_application;
|
drop table registration_application;
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
-- Add columns to site table
|
-- Add columns to site table
|
||||||
alter table site add column require_application boolean not null default false;
|
alter table site add column require_application boolean not null default false;
|
||||||
alter table site add column require_email boolean not null default false;
|
|
||||||
alter table site add column application_question text;
|
alter table site add column application_question text;
|
||||||
|
|
||||||
-- Add pending to local_user
|
-- Add pending to local_user
|
||||||
alter table local_user add column accepted_application boolean not null default false;
|
alter table local_user add column accepted_application boolean not null default false;
|
||||||
alter table local_user add column verified_email boolean not null default false;
|
|
||||||
|
|
||||||
create table registration_application (
|
create table registration_application (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
local_user_id int references local_user on update cascade on delete cascade not null,
|
local_user_id int references local_user on update cascade on delete cascade not null,
|
||||||
answer text not null,
|
answer text not null,
|
||||||
acceptor_id int references person on update cascade on delete cascade,
|
admin_id int references person on update cascade on delete cascade,
|
||||||
accepted boolean not null default false,
|
|
||||||
deny_reason text,
|
deny_reason text,
|
||||||
published timestamp not null default now(),
|
published timestamp not null default now(),
|
||||||
unique(local_user_id)
|
unique(local_user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
create index idx_registration_application_published on registration_application (published desc);
|
||||||
|
|
|
@ -211,9 +211,21 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
)
|
)
|
||||||
// Admin Actions
|
// Admin Actions
|
||||||
.service(
|
.service(
|
||||||
web::resource("/admin/add")
|
web::scope("/admin")
|
||||||
.wrap(rate_limit.message())
|
.wrap(rate_limit.message())
|
||||||
.route(web::post().to(route_post::<AddAdmin>)),
|
.route("/add", web::post().to(route_post::<AddAdmin>))
|
||||||
|
.route(
|
||||||
|
"/registration_application/count",
|
||||||
|
web::get().to(route_get::<GetUnreadRegistrationApplicationCount>),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/registration_application/list",
|
||||||
|
web::get().to(route_get::<ListRegistrationApplications>),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/registration_application/approve",
|
||||||
|
web::put().to(route_post::<ApproveRegistrationApplication>),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue