parent
56f6b8edb4
commit
5446fcb128
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
source: web/src/endpoints/user/put_receive_notifications.rs
|
||||||
|
expression: subscribe_body
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
<input
|
||||||
|
hx-put="/users/1/unsubscribeNotifications"
|
||||||
|
type="checkbox" hx-swap="outerHTML" checked>
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
source: web/src/endpoints/user/put_receive_notifications.rs
|
||||||
|
expression: unsubscribe_body
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
<input
|
||||||
|
hx-put="/users/1/subscribeNotifications"
|
||||||
|
type="checkbox" hx-swap="outerHTML" >
|
@ -49,6 +49,8 @@ pub fn init(cfg: &mut ServiceConfig) {
|
|||||||
cfg.service(user::get_register::get);
|
cfg.service(user::get_register::get);
|
||||||
cfg.service(user::post_register::post);
|
cfg.service(user::post_register::post);
|
||||||
cfg.service(user::post_resend_registration::post);
|
cfg.service(user::post_resend_registration::post);
|
||||||
|
cfg.service(user::put_receive_notifications::put_subscribe);
|
||||||
|
cfg.service(user::put_receive_notifications::put_unsubscribe);
|
||||||
|
|
||||||
cfg.service(availability::delete::delete);
|
cfg.service(availability::delete::delete);
|
||||||
cfg.service(availability::get_new::get);
|
cfg.service(availability::get_new::get);
|
||||||
|
@ -69,17 +69,6 @@ pub async fn post(
|
|||||||
id = user.id));
|
id = user.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"receiveNotifications" => {
|
|
||||||
User::update_receive_notifications(
|
|
||||||
pool.get_ref(),
|
|
||||||
user.id,
|
|
||||||
!user.receive_notifications,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
_ => return HttpResponse::BadRequest().body("Other PATCH paths are not supported!"),
|
_ => return HttpResponse::BadRequest().body("Other PATCH paths are not supported!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpResponse::Ok().finish()
|
|
||||||
}
|
}
|
||||||
|
115
web/src/endpoints/user/put_receive_notifications.rs
Normal file
115
web/src/endpoints/user/put_receive_notifications.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
|
use askama::Template;
|
||||||
|
use serde_json::json;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
endpoints::IdPath,
|
||||||
|
filters,
|
||||||
|
models::User,
|
||||||
|
utils::{ApplicationError, TemplateResponse},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "user/profile.html", block = "notificationinput")]
|
||||||
|
struct ProfilePartialNotificationInputTemplate {
|
||||||
|
user: User,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::put("/users/{id}/unsubscribeNotifications")]
|
||||||
|
pub async fn put_unsubscribe(
|
||||||
|
user: web::ReqData<User>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
path: web::Path<IdPath>,
|
||||||
|
) -> Result<impl Responder, ApplicationError> {
|
||||||
|
handle_subscription_to_notifications(user, pool, path, false).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::put("/users/{id}/subscribeNotifications")]
|
||||||
|
pub async fn put_subscribe(
|
||||||
|
user: web::ReqData<User>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
path: web::Path<IdPath>,
|
||||||
|
) -> Result<impl Responder, ApplicationError> {
|
||||||
|
handle_subscription_to_notifications(user, pool, path, true).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_subscription_to_notifications(
|
||||||
|
user: web::ReqData<User>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
path: web::Path<IdPath>,
|
||||||
|
subscription_state: bool,
|
||||||
|
) -> Result<impl Responder, ApplicationError> {
|
||||||
|
if user.id != path.id {
|
||||||
|
return Err(ApplicationError::Unauthorized);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(user_in_db) = User::read_by_id(pool.get_ref(), path.id).await? else {
|
||||||
|
error!(user = user.id, "Logged in user does not exist in database!");
|
||||||
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut user = user.into_inner();
|
||||||
|
if user_in_db.receive_notifications != subscription_state {
|
||||||
|
User::update_receive_notifications(pool.get_ref(), user_in_db.id, subscription_state)
|
||||||
|
.await?;
|
||||||
|
user.receive_notifications = subscription_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
let trigger = json!({
|
||||||
|
"showToast": {
|
||||||
|
"type": "success",
|
||||||
|
"message": "Benachrichtigungseinstellung gespeichert!"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let template = ProfilePartialNotificationInputTemplate { user };
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok()
|
||||||
|
.insert_header(("HX-TRIGGER", trigger))
|
||||||
|
.body(template.to_response()?.into_body()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::utils::test_helper::{
|
||||||
|
assert_snapshot, read_body, test_put, DbTestContext, RequestConfig, StatusCode,
|
||||||
|
};
|
||||||
|
use brass_macros::db_test;
|
||||||
|
|
||||||
|
#[db_test]
|
||||||
|
async fn user_can_toggle_subscription_for_himself(context: &DbTestContext) {
|
||||||
|
let app = context.app().await;
|
||||||
|
|
||||||
|
let unsubscribe_config = RequestConfig::new("/users/1/unsubscribeNotifications");
|
||||||
|
let unsubscribe_response =
|
||||||
|
test_put::<_, _, String>(&context.db_pool, &app, &unsubscribe_config, None).await;
|
||||||
|
|
||||||
|
assert_eq!(StatusCode::OK, unsubscribe_response.status());
|
||||||
|
|
||||||
|
let unsubscribe_body = read_body(unsubscribe_response).await;
|
||||||
|
assert_snapshot!(unsubscribe_body);
|
||||||
|
|
||||||
|
let subscribe_config = RequestConfig::new("/users/1/subscribeNotifications");
|
||||||
|
let subscribe_response =
|
||||||
|
test_put::<_, _, String>(&context.db_pool, &app, &subscribe_config, None).await;
|
||||||
|
|
||||||
|
assert_eq!(StatusCode::OK, subscribe_response.status());
|
||||||
|
|
||||||
|
let subscribe_body = read_body(subscribe_response).await;
|
||||||
|
assert_snapshot!(subscribe_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[db_test]
|
||||||
|
async fn user_cant_toggle_subscription_for_someone_else(context: &DbTestContext) {
|
||||||
|
let app = context.app().await;
|
||||||
|
|
||||||
|
let unsubscribe_config = RequestConfig::new("/users/3/unsubscribeNotifications");
|
||||||
|
let unsubscribe_response =
|
||||||
|
test_put::<_, _, String>(&context.db_pool, &app, &unsubscribe_config, None).await;
|
||||||
|
|
||||||
|
assert_eq!(StatusCode::UNAUTHORIZED, unsubscribe_response.status());
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ mod test_context;
|
|||||||
mod test_requests;
|
mod test_requests;
|
||||||
pub use test_context::{setup, teardown, DbTestContext};
|
pub use test_context::{setup, teardown, DbTestContext};
|
||||||
pub use test_requests::RequestConfig;
|
pub use test_requests::RequestConfig;
|
||||||
pub use test_requests::{read_body, test_delete, test_get, test_post};
|
pub use test_requests::{read_body, test_delete, test_get, test_post, test_put};
|
||||||
|
|
||||||
pub use actix_http::StatusCode;
|
pub use actix_http::StatusCode;
|
||||||
|
|
||||||
@ -25,5 +25,5 @@ macro_rules! assert_mail_snapshot {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use assert_snapshot;
|
|
||||||
pub(crate) use assert_mail_snapshot;
|
pub(crate) use assert_mail_snapshot;
|
||||||
|
pub(crate) use assert_snapshot;
|
||||||
|
@ -59,7 +59,7 @@ where
|
|||||||
let login_form = LoginForm {
|
let login_form = LoginForm {
|
||||||
email: "abc".to_string(),
|
email: "abc".to_string(),
|
||||||
password: "abc".to_string(),
|
password: "abc".to_string(),
|
||||||
next: None
|
next: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let login_req = test::TestRequest::post()
|
let login_req = test::TestRequest::post()
|
||||||
@ -119,6 +119,28 @@ where
|
|||||||
test::call_service(&app, post_request).await
|
test::call_service(&app, post_request).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn test_put<T, R, F>(
|
||||||
|
pool: &Pool<Postgres>,
|
||||||
|
app: &T,
|
||||||
|
config: &RequestConfig,
|
||||||
|
form: Option<F>,
|
||||||
|
) -> ServiceResponse<R>
|
||||||
|
where
|
||||||
|
T: Service<Request, Response = ServiceResponse<R>, Error = Error>,
|
||||||
|
R: MessageBody,
|
||||||
|
F: Serialize,
|
||||||
|
{
|
||||||
|
let cookie = create_user_and_get_login_cookie(pool, app, config).await;
|
||||||
|
|
||||||
|
let put_request = test::TestRequest::put()
|
||||||
|
.uri(&config.uri)
|
||||||
|
.cookie(cookie)
|
||||||
|
.set_form(form)
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
test::call_service(app, put_request).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test_delete<T, R>(
|
pub async fn test_delete<T, R>(
|
||||||
pool: &Pool<Postgres>,
|
pool: &Pool<Postgres>,
|
||||||
app: T,
|
app: T,
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
{{ user.function|show_tree|safe }}
|
{{ user.function|show_tree|safe }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -88,19 +88,12 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input hx-post="/users/{{ user.id }}/toggle?field=receiveNotifications" type="checkbox"
|
{% block notificationinput %}
|
||||||
hx-on::before-request="document.getElementById('success').classList.remove('fadeout')"
|
<input
|
||||||
hx-on::after-request="document.getElementById('success').classList.add('fadeout')"
|
hx-put="/users/{{ user.id }}/{%- if user.receive_notifications -%}un{%- endif -%}subscribeNotifications"
|
||||||
checked="{{ user.receive_notifications }}">
|
type="checkbox" hx-swap="outerHTML" {{ user.receive_notifications|cond_show("checked") }}>
|
||||||
|
{% endblock %}
|
||||||
Ich möchte E-Mail Benachrichtigungen zu neuen Brasiwa-Einteilungen erhalten.
|
Ich möchte E-Mail Benachrichtigungen zu neuen Brasiwa-Einteilungen erhalten.
|
||||||
<span id="success" class="result">
|
|
||||||
<svg class="icon mr-2">
|
|
||||||
<use href="/static/feather-sprite.svg#check" />
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
gespeichert
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user