twitch event rule endpoints

This commit is contained in:
Brandon Thomas committed 2022-02-19 05:19:56 -05:00
1 parent 867e1c0ed5
commit 8e0a21421b
13 files changed
+562 -10

No files matched your search

@@ -5,8 +5,8 @@ use crate::column_types::twitch_event_category::TwitchEventCategory;
use crate::helpers::boolean_converters::i8_to_bool;
use sqlx::MySqlPool;
/// table: api_tokens
#[derive(Debug)]
// TODO: This is exposed to the frontend. Write a different struct.
#[derive(Debug, Serialize)]
pub struct TwitchEventRule {
pub token: String,
pub event_category: TwitchEventCategory,
+1 -1
View File
@@ -68,7 +68,7 @@ impl Tokens {
}
pub fn new_api_token_internal_token() -> AnyhowResult<String> {
random_prefix_crockford_token("AIT:", 32, false)
random_prefix_crockford_token("INT_API:", 32, false)
}
// ========== [Twitch] Tokens not typically visible to users ==========
@@ -12,6 +12,7 @@ use crate::http_server::web_utils::response_success_helpers::simple_json_success
use crate::server_state::ServerState;
use crate::util::email_to_gravatar::email_to_gravatar;
use crate::util::markdown_to_html::markdown_to_html;
use database_queries::queries::api_tokens::create_api_token::create_api_token_for_user;
use database_queries::tokens::Tokens;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use log::{info, warn, log};
@@ -22,7 +23,6 @@ use sqlx::error::Error::Database;
use sqlx::mysql::MySqlDatabaseError;
use std::fmt;
use std::sync::Arc;
use database_queries::queries::api_tokens::create_api_token::create_api_token_for_user;
// =============== Request ===============
@@ -0,0 +1,135 @@
use actix_http::Error;
use actix_http::http::header;
use actix_web::HttpResponseBuilder;
use actix_web::cookie::Cookie;
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Json};
use actix_web::{Responder, web, HttpResponse, error, HttpRequest};
use crate::http_server::web_utils::ip_address::get_request_ip;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
use crate::server_state::ServerState;
use database_queries::column_types::twitch_event_category::TwitchEventCategory;
use database_queries::queries::twitch::twitch_event_rules::insert_twitch_event_rule_builder::InsertTwitchEventRuleBuilder;
use database_queries::tokens::Tokens;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use log::{info, warn, log};
use sqlx::MySqlPool;
use sqlx::error::DatabaseError;
use sqlx::error::Error::Database;
use sqlx::mysql::MySqlDatabaseError;
use std::fmt;
use std::sync::Arc;
// =============== Request ===============
#[derive(Deserialize)]
pub struct CreateTwitchEventRuleRequest {
pub idempotency_token: String,
pub event_category: TwitchEventCategory,
pub event_match_predicate: String,
pub event_response: String,
pub user_specified_rule_order: u32,
pub rule_is_disabled: bool,
}
// =============== Success Response ===============
#[derive(Serialize)]
pub struct CreateTwitchEventRuleResponse {
pub success: bool,
pub twitch_event_rule_token: String,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
pub enum CreateTwitchEventRuleError {
BadInput(String),
NotAuthorized,
ServerError,
}
impl ResponseError for CreateTwitchEventRuleError {
fn status_code(&self) -> StatusCode {
match *self {
CreateTwitchEventRuleError::BadInput(_) => StatusCode::BAD_REQUEST,
CreateTwitchEventRuleError::NotAuthorized => StatusCode::UNAUTHORIZED,
CreateTwitchEventRuleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
serialize_as_json_error(self)
}
}
// NB: Not using DeriveMore since Clion doesn't understand it.
impl fmt::Display for CreateTwitchEventRuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// =============== Handler ===============
pub async fn create_twitch_event_rule_handler(
http_request: HttpRequest,
request: web::Json<CreateTwitchEventRuleRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, CreateTwitchEventRuleError>
{
let maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
CreateTwitchEventRuleError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(CreateTwitchEventRuleError::NotAuthorized);
}
};
if user_session.is_banned {
warn!("banned users cannot use");
return Err(CreateTwitchEventRuleError::NotAuthorized);
}
let creator_ip_address = get_request_ip(&http_request);
let insert_builder = InsertTwitchEventRuleBuilder {
uuid_idempotency_token: request.idempotency_token.clone(),
user_token: user_session.user_token,
event_category: request.event_category,
event_match_predicate: request.event_match_predicate.clone(),
event_response: request.event_response.clone(),
user_specified_rule_order: request.user_specified_rule_order,
rule_is_disabled: request.rule_is_disabled,
ip_address_creation: creator_ip_address,
};
let twitch_event_rule_token = insert_builder.insert(&server_state.mysql_pool)
.await
.map_err(|e| {
warn!("creation error: {:?}", e);
CreateTwitchEventRuleError::ServerError
})?;
let response = CreateTwitchEventRuleResponse {
success: true,
twitch_event_rule_token
};
let body = serde_json::to_string(&response)
.map_err(|e| CreateTwitchEventRuleError::ServerError)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
@@ -0,0 +1,134 @@
use actix_http::Error;
use actix_http::http::header;
use actix_web::HttpResponseBuilder;
use actix_web::cookie::Cookie;
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Json};
use actix_web::{Responder, web, HttpResponse, error, HttpRequest};
use crate::http_server::web_utils::ip_address::get_request_ip;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
use crate::server_state::ServerState;
use database_queries::queries::twitch::twitch_event_rules::delete_twitch_event_rule::delete_twitch_event_rule;
use database_queries::queries::twitch::twitch_event_rules::get_twitch_event_rule_for_user::get_twitch_event_rules_for_user;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use log::{info, warn, log, error};
use sqlx::MySqlPool;
use sqlx::error::DatabaseError;
use sqlx::error::Error::Database;
use sqlx::mysql::MySqlDatabaseError;
use std::fmt;
use std::sync::Arc;
// =============== Request ===============
#[derive(Deserialize)]
pub struct DeleteTwitchEventRulePathInfo {
token: String,
}
// =============== Success Response ===============
#[derive(Serialize)]
pub struct DeleteTwitchEventRuleResponse {
pub success: bool,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
pub enum DeleteTwitchEventRuleError {
BadInput(String),
NotFound,
NotAuthorized,
ServerError,
}
impl ResponseError for DeleteTwitchEventRuleError {
fn status_code(&self) -> StatusCode {
match *self {
DeleteTwitchEventRuleError::BadInput(_) => StatusCode::BAD_REQUEST,
DeleteTwitchEventRuleError::NotFound => StatusCode::NOT_FOUND,
DeleteTwitchEventRuleError::NotAuthorized => StatusCode::UNAUTHORIZED,
DeleteTwitchEventRuleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
serialize_as_json_error(self)
}
}
// NB: Not using derive_more::Display since Clion doesn't understand it.
impl fmt::Display for DeleteTwitchEventRuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// =============== Handler ===============
pub async fn delete_twitch_event_rule_handler(
http_request: HttpRequest,
path: Path<DeleteTwitchEventRulePathInfo>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, DeleteTwitchEventRuleError>
{
let maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
DeleteTwitchEventRuleError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(DeleteTwitchEventRuleError::NotAuthorized);
}
};
if user_session.is_banned {
warn!("banned users cannot delete");
return Err(DeleteTwitchEventRuleError::NotAuthorized);
}
let twitch_event_rule = get_twitch_event_rules_for_user(
&path.token, &user_session.user_token, &server_state.mysql_pool)
.await
.map_err(|e| {
error!("Error with query: {:?}", e);
return DeleteTwitchEventRuleError::ServerError;
})?;
if twitch_event_rule.is_none() {
info!("event rule not found");
return Err(DeleteTwitchEventRuleError::NotFound);
}
let creator_ip_address = get_request_ip(&http_request);
let _r = delete_twitch_event_rule(
&path.token,
&creator_ip_address,
&server_state.mysql_pool)
.await
.map_err(|e| {
error!("Error with query: {:?}", e);
return DeleteTwitchEventRuleError::ServerError;
});
let response = DeleteTwitchEventRuleResponse {
success: true,
};
let body = serde_json::to_string(&response)
.map_err(|e| DeleteTwitchEventRuleError::ServerError)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
@@ -0,0 +1,150 @@
use actix_http::Error;
use actix_http::http::header;
use actix_web::HttpResponseBuilder;
use actix_web::cookie::Cookie;
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Json};
use actix_web::{Responder, web, HttpResponse, error, HttpRequest};
use crate::http_server::web_utils::ip_address::get_request_ip;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
use crate::server_state::ServerState;
use database_queries::queries::twitch::twitch_event_rules::get_twitch_event_rule_for_user::get_twitch_event_rules_for_user;
use database_queries::queries::twitch::twitch_event_rules::update_twitch_event_rule_builder::UpdateTwitchEventRuleBuilder;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use log::{info, warn, log, error};
use sqlx::MySqlPool;
use sqlx::error::DatabaseError;
use sqlx::error::Error::Database;
use sqlx::mysql::MySqlDatabaseError;
use std::fmt;
use std::sync::Arc;
// =============== Request ===============
#[derive(Deserialize)]
pub struct EditTwitchEventRulePathInfo {
token: String,
}
// These are not sparse updates!
#[derive(Deserialize)]
pub struct EditTwitchEventRuleRequest {
pub event_match_predicate: String,
pub event_response: String,
pub user_specified_rule_order: u32,
pub rule_is_disabled: bool,
}
// =============== Success Response ===============
#[derive(Serialize)]
pub struct EditTwitchEventRuleResponse {
pub success: bool,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
pub enum EditTwitchEventRuleError {
BadInput(String),
NotFound,
NotAuthorized,
ServerError,
}
impl ResponseError for EditTwitchEventRuleError {
fn status_code(&self) -> StatusCode {
match *self {
EditTwitchEventRuleError::BadInput(_) => StatusCode::BAD_REQUEST,
EditTwitchEventRuleError::NotFound => StatusCode::NOT_FOUND,
EditTwitchEventRuleError::NotAuthorized => StatusCode::UNAUTHORIZED,
EditTwitchEventRuleError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
serialize_as_json_error(self)
}
}
// NB: Not using derive_more::Display since Clion doesn't understand it.
impl fmt::Display for EditTwitchEventRuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// =============== Handler ===============
pub async fn edit_twitch_event_rule_handler(
http_request: HttpRequest,
path: Path<EditTwitchEventRulePathInfo>,
request: web::Json<EditTwitchEventRuleRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EditTwitchEventRuleError>
{
let maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
EditTwitchEventRuleError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(EditTwitchEventRuleError::NotAuthorized);
}
};
if user_session.is_banned {
warn!("banned users cannot edit");
return Err(EditTwitchEventRuleError::NotAuthorized);
}
let twitch_event_rule = get_twitch_event_rules_for_user(
&path.token, &user_session.user_token, &server_state.mysql_pool)
.await
.map_err(|e| {
error!("Error with query: {:?}", e);
return EditTwitchEventRuleError::ServerError;
})?;
if twitch_event_rule.is_none() {
info!("event rule not found");
return Err(EditTwitchEventRuleError::NotFound);
}
let creator_ip_address = get_request_ip(&http_request);
let update_builder = UpdateTwitchEventRuleBuilder {
token: path.token.clone(),
event_match_predicate: request.event_match_predicate.clone(),
event_response: request.event_response.clone(),
user_specified_rule_order: request.user_specified_rule_order,
rule_is_disabled: request.rule_is_disabled,
ip_address_update: creator_ip_address,
};
let _r = update_builder.update(&server_state.mysql_pool)
.await
.map_err(|e| {
error!("Error with query: {:?}", e);
return EditTwitchEventRuleError::ServerError;
});
let response = EditTwitchEventRuleResponse {
success: true,
};
let body = serde_json::to_string(&response)
.map_err(|e| EditTwitchEventRuleError::ServerError)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
@@ -0,0 +1,109 @@
use actix_http::Error;
use actix_http::http::header;
use actix_web::HttpResponseBuilder;
use actix_web::cookie::Cookie;
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::{Path, Json};
use actix_web::{Responder, web, HttpResponse, error, HttpRequest};
use chrono::{DateTime, Utc};
use crate::http_server::web_utils::ip_address::get_request_ip;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
use crate::server_state::ServerState;
use database_queries::queries::twitch::twitch_event_rules::list_twitch_event_rules_for_user::{TwitchEventRule, list_twitch_event_rules_for_user};
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use lexical_sort::natural_lexical_cmp;
use log::{info, warn, log};
use sqlx::MySqlPool;
use sqlx::error::DatabaseError;
use sqlx::error::Error::Database;
use sqlx::mysql::MySqlDatabaseError;
use std::fmt;
use std::sync::Arc;
// =============== Success Response ===============
#[derive(Serialize)]
pub struct ListTwitchEventRulesResponse {
pub success: bool,
pub twitch_event_rules: Vec<TwitchEventRule>,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
pub enum ListTwitchEventRulesError {
NotAuthorized,
ServerError,
}
impl ResponseError for ListTwitchEventRulesError {
fn status_code(&self) -> StatusCode {
match *self {
ListTwitchEventRulesError::NotAuthorized => StatusCode::UNAUTHORIZED,
ListTwitchEventRulesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
serialize_as_json_error(self)
}
}
// NB: Not using derive_more::Display since Clion doesn't understand it.
impl fmt::Display for ListTwitchEventRulesError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
// =============== Handler ===============
pub async fn list_twitch_event_rules_for_user_handler(
http_request: HttpRequest,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, ListTwitchEventRulesError>
{
let maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
ListTwitchEventRulesError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(ListTwitchEventRulesError::NotAuthorized);
}
};
if user_session.is_banned {
warn!("banned users cannot use");
return Err(ListTwitchEventRulesError::NotAuthorized);
}
let twitch_event_rules = list_twitch_event_rules_for_user(
&user_session.user_token, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("query error: {:?}", e);
ListTwitchEventRulesError::ServerError
})?;
let response = ListTwitchEventRulesResponse {
success: true,
twitch_event_rules,
};
let body = serde_json::to_string(&response)
.map_err(|e| ListTwitchEventRulesError::ServerError)?;
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
@@ -1,4 +1,2 @@
pub mod event_rules;
pub mod oauth_begin_json;
pub mod oauth_begin_redirect;
pub mod oauth_end;
pub mod oauth;
@@ -0,0 +1,3 @@
pub mod oauth_begin_json;
pub mod oauth_begin_redirect;
pub mod oauth_end;
+26 -3
View File
@@ -48,9 +48,9 @@ use crate::http_server::endpoints::tts::get_tts_model_use_count::get_tts_model_u
use crate::http_server::endpoints::tts::get_tts_result::get_tts_inference_result_handler;
use crate::http_server::endpoints::tts::get_tts_upload_model_job_status::get_tts_upload_model_job_status_handler;
use crate::http_server::endpoints::tts::list_tts_models::list_tts_models_handler;
use crate::http_server::endpoints::twitch::oauth_begin_json::oauth_begin_enroll_json;
use crate::http_server::endpoints::twitch::oauth_begin_redirect::oauth_begin_enroll_redirect;
use crate::http_server::endpoints::twitch::oauth_end::oauth_end_enroll_from_redirect;
use crate::http_server::endpoints::twitch::oauth::oauth_begin_json::oauth_begin_enroll_json;
use crate::http_server::endpoints::twitch::oauth::oauth_begin_redirect::oauth_begin_enroll_redirect;
use crate::http_server::endpoints::twitch::oauth::oauth_end::oauth_end_enroll_from_redirect;
use crate::http_server::endpoints::users::create_account::create_account_handler;
use crate::http_server::endpoints::users::edit_profile::edit_profile_handler;
use crate::http_server::endpoints::users::get_profile::get_profile_handler;
@@ -75,6 +75,10 @@ use crate::http_server::endpoints::w2l::get_w2l_template_use_count::get_w2l_temp
use crate::http_server::endpoints::w2l::get_w2l_upload_template_job_status::get_w2l_upload_template_job_status_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::twitch::event_rules::create_event_rule::create_twitch_event_rule_handler;
use crate::http_server::endpoints::twitch::event_rules::list_event_rules_for_user::list_twitch_event_rules_for_user_handler;
use crate::http_server::endpoints::twitch::event_rules::delete_event_rule::delete_twitch_event_rule_handler;
use crate::http_server::endpoints::twitch::event_rules::edit_event_rule::edit_twitch_event_rule_handler;
pub fn add_routes<T, B> (app: App<T, B>) -> App<T, B>
where
@@ -583,6 +587,7 @@ fn add_twitch_oauth_routes<T, B> (app: App<T, B>) -> App<T, B>
InitError = (),
>,
{
// TODO: Move oauth endpoints under /twitch/oauth (requires updating Twitch configs too.)
app.service(web::scope("/twitch")
.service(web::resource("/oauth_enroll_json")
.route(web::get().to(oauth_begin_enroll_json))
@@ -596,5 +601,23 @@ fn add_twitch_oauth_routes<T, B> (app: App<T, B>) -> App<T, B>
.route(web::get().to(oauth_end_enroll_from_redirect))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::scope("/event_rule")
.service(web::resource("/create")
.route(web::post().to(create_twitch_event_rule_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/list")
.route(web::get().to(list_twitch_event_rules_for_user_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/update/{token}")
.route(web::post().to(edit_twitch_event_rule_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/delete/{token}")
.route(web::delete().to(delete_twitch_event_rule_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
)
)
}