mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-11 04:16:55 +00:00
endpoint for indicating why a user is unsubscribing
This commit is contained in:
1 parent
362f41cbf3
commit
fb8142fb49
9 files changed
+220
-3
No files matched your search
@@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
drop table unsubscribe_reason;
|
||||
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE unsubscribe_reason (
|
||||
-- Generic primary key
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- User unsubscribing
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- User's feedback/reason for unsubscribing
|
||||
feedback_reason MEDIUMTEXT,
|
||||
|
||||
-- tracking
|
||||
ip_address VARCHAR(40) NOT NULL,
|
||||
|
||||
-- Timestamp the feedback was submitted at
|
||||
unsubscribed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (id)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
use anyhow::anyhow;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use sqlx::MySql;
|
||||
use sqlx::pool::PoolConnection;
|
||||
|
||||
pub struct UnsubscribeReasonInsertBuilder<'a> {
|
||||
unsubscribe_reason: &'a str,
|
||||
user_token: &'a str,
|
||||
ip_address: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> UnsubscribeReasonInsertBuilder<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
unsubscribe_reason: "",
|
||||
user_token: "",
|
||||
ip_address: "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_unsubscribe_reason(mut self, value: &'a str) -> Self {
|
||||
self.unsubscribe_reason = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_user_token(mut self, value: &'a str) -> Self {
|
||||
self.user_token = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_ip_address(mut self, value: &'a str) -> Self {
|
||||
self.ip_address = value;
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn insert(&mut self, mysql_connection: &mut PoolConnection<MySql>) -> AnyhowResult<()> {
|
||||
let query = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO unsubscribe_reason
|
||||
SET
|
||||
user_token = ?,
|
||||
feedback_reason = ?,
|
||||
ip_address = ?
|
||||
"#,
|
||||
self.user_token,
|
||||
self.unsubscribe_reason,
|
||||
self.ip_address,
|
||||
);
|
||||
|
||||
let query_result = query.execute(mysql_connection)
|
||||
.await;
|
||||
|
||||
let _record_id = match query_result {
|
||||
Ok(res) => {
|
||||
res.last_insert_id()
|
||||
},
|
||||
Err(err) => {
|
||||
return Err(anyhow!("Unsubscribe reason insert DB error: {:?}", err));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod get_user_subscription_by_stripe_subscription_id;
|
||||
pub mod list_active_user_subscriptions;
|
||||
pub mod upsert_user_subscription_by_stripe_id;
|
||||
pub mod insert_unsubscribe_reason;
|
||||
@@ -17,4 +17,5 @@ pub mod user_ratings;
|
||||
pub mod vocoders;
|
||||
pub mod voice_clone_requests;
|
||||
pub mod voice_conversion;
|
||||
pub mod w2l;
|
||||
pub mod w2l;
|
||||
pub mod subscriptions;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod unsubscribe_reason;
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{HttpRequest, HttpResponse, ResponseError, web};
|
||||
use http_server_common::request::get_request_ip::get_request_ip;
|
||||
use crate::server_state::ServerState;
|
||||
use database_queries::queries::users::user_subscriptions::insert_unsubscribe_reason::UnsubscribeReasonInsertBuilder;
|
||||
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
|
||||
use log::{error, info};
|
||||
use std::sync::Arc;
|
||||
|
||||
// =============== Request ===============
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetUnsubscribeReasonRequest {
|
||||
/// The type of the entity being rated.
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
// =============== Success Response ===============
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SetUnsubscribeReasonResponse {
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
// =============== Error Response ===============
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum SetUnsubscribeReasonError {
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for SetUnsubscribeReasonError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
SetUnsubscribeReasonError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
SetUnsubscribeReasonError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
serialize_as_json_error(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SetUnsubscribeReasonError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// =============== Handler ===============
|
||||
|
||||
pub async fn set_unsubscribe_reason_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<SetUnsubscribeReasonRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetUnsubscribeReasonError>
|
||||
{
|
||||
let mut mysql_connection = server_state.mysql_pool.acquire()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Could not acquire DB pool: {:?}", e);
|
||||
SetUnsubscribeReasonError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_user_session = server_state
|
||||
.session_checker
|
||||
.maybe_get_user_session_from_connection(&http_request, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("Session checker error: {:?}", e);
|
||||
SetUnsubscribeReasonError::ServerError
|
||||
})?;
|
||||
|
||||
let user_session = match maybe_user_session {
|
||||
Some(session) => session,
|
||||
None => {
|
||||
info!("not logged in");
|
||||
return Err(SetUnsubscribeReasonError::NotAuthorized);
|
||||
}
|
||||
};
|
||||
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
UnsubscribeReasonInsertBuilder::new()
|
||||
.set_user_token(&user_session.user_token)
|
||||
.set_ip_address(&ip_address)
|
||||
.set_unsubscribe_reason(&request.reason)
|
||||
.insert(&mut mysql_connection)
|
||||
.await
|
||||
.map_err(|_e| SetUnsubscribeReasonError::ServerError)?;
|
||||
|
||||
|
||||
let response = SetUnsubscribeReasonResponse {
|
||||
success: true,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| SetUnsubscribeReasonError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
@@ -102,6 +102,7 @@ use crate::http_server::endpoints::w2l::list_user_w2l_inference_results::list_us
|
||||
use crate::http_server::endpoints::w2l::list_user_w2l_templates::list_user_w2l_templates_handler;
|
||||
use crate::http_server::endpoints::w2l::list_w2l_templates::list_w2l_templates_handler;
|
||||
use crate::http_server::endpoints::w2l::set_w2l_template_mod_approval::set_w2l_template_mod_approval_handler;
|
||||
use crate::http_server::endpoints::subscriptions::unsubscribe_reason::set_unsubscribe_reason_handler;
|
||||
use users_component::default_routes::add_suggested_api_v1_account_creation_and_session_routes;
|
||||
use users_component::endpoints::edit_profile_handler::edit_profile_handler;
|
||||
use users_component::endpoints::get_profile_handler::get_profile_handler;
|
||||
@@ -134,6 +135,7 @@ pub fn add_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
app = add_media_upload_routes(app); /* /v1/media_upload/... */
|
||||
app = add_trending_routes(app); /* /v1/trending/... */
|
||||
app = add_user_rating_routes(app); /* /v1/user_rating/... */
|
||||
app = add_subscription_routes(app); /* /v1/subscriptions/... */
|
||||
|
||||
// From components
|
||||
app = add_suggested_api_v1_account_creation_and_session_routes(app); // /create_account, /session, /login, /logout
|
||||
@@ -936,7 +938,6 @@ fn add_trending_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ==================== USER RATING ROUTES ====================
|
||||
|
||||
fn add_user_rating_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
@@ -1026,3 +1027,23 @@ fn add_twitch_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ============= SUBSCRIPTION ROUTES ===================
|
||||
fn add_subscription_routes<T, B> (app: App<T, B>) -> App<T, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
>,
|
||||
{
|
||||
app.service(web::scope("/v1/subscriptions")
|
||||
.service(web::resource("/unsubscribe_reason")
|
||||
.route(web::post().to(set_unsubscribe_reason_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
}
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set +e +o pipefail
|
||||
diesel migration run --database-url="${MYSQL_URL}"
|
||||
set -e -o pipefail
|
||||
./target/x86_64-unknown-linux-musl/release/storyteller-web
|
||||
|
||||
Reference in new issue
Block a user