Apply patreon sharing across web/bot
This commit is contained in:
		@@ -43,8 +43,9 @@ impl Recordable for Options {
 | 
				
			|||||||
        // Insert or update the patreon_link entry
 | 
					        // Insert or update the patreon_link entry
 | 
				
			||||||
        sqlx::query!(
 | 
					        sqlx::query!(
 | 
				
			||||||
            "INSERT INTO patreon_link (user_id, guild_id, linked_at) VALUES (?, ?, NOW())
 | 
					            "INSERT INTO patreon_link (user_id, guild_id, linked_at) VALUES (?, ?, NOW())
 | 
				
			||||||
             ON DUPLICATE KEY UPDATE user_id = user_id",
 | 
					             ON DUPLICATE KEY UPDATE guild_id = ?",
 | 
				
			||||||
            user_id.get(),
 | 
					            user_id.get(),
 | 
				
			||||||
 | 
					            guild_id.get(),
 | 
				
			||||||
            guild_id.get()
 | 
					            guild_id.get()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .execute(&ctx.data().database)
 | 
					        .execute(&ctx.data().database)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -532,7 +532,9 @@ pub async fn create_reminder(
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let (processed_interval, processed_expires) = if let Some(repeat) = &interval {
 | 
					            let (processed_interval, processed_expires) = if let Some(repeat) = &interval {
 | 
				
			||||||
                if check_subscription(&ctx, ctx.author().id, ctx.guild_id()).await {
 | 
					                if check_subscription(&ctx, &ctx.data().database, ctx.author().id, ctx.guild_id())
 | 
				
			||||||
 | 
					                    .await
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    (
 | 
					                    (
 | 
				
			||||||
                        parse_duration(repeat)
 | 
					                        parse_duration(repeat)
 | 
				
			||||||
                            .or_else(|_| parse_duration(&format!("1 {}", repeat)))
 | 
					                            .or_else(|_| parse_duration(&format!("1 {}", repeat)))
 | 
				
			||||||
@@ -547,7 +549,7 @@ pub async fn create_reminder(
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    ctx.send(CreateReply::default().content(
 | 
					                    ctx.send(CreateReply::default().content(
 | 
				
			||||||
                        "`repeat` is only available to Patreon subscribers or self-hosted users",
 | 
					                        "`interval` is only available to Patreon subscribers or self-hosted users",
 | 
				
			||||||
                    ))
 | 
					                    ))
 | 
				
			||||||
                    .await?;
 | 
					                    .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@ use std::{
 | 
				
			|||||||
use chrono::{DateTime, Datelike, Timelike, Utc};
 | 
					use chrono::{DateTime, Datelike, Timelike, Utc};
 | 
				
			||||||
use chrono_tz::Tz;
 | 
					use chrono_tz::Tz;
 | 
				
			||||||
use cron_parser::parse;
 | 
					use cron_parser::parse;
 | 
				
			||||||
use std::str::FromStr;
 | 
					 | 
				
			||||||
use tokio::process::Command;
 | 
					use tokio::process::Command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::consts::{LOCAL_TIMEZONE, PYTHON_LOCATION};
 | 
					use crate::consts::{LOCAL_TIMEZONE, PYTHON_LOCATION};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/utils.rs
									
									
									
									
									
								
							@@ -9,24 +9,25 @@ use poise::{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    consts::{CNC_GUILD, SUBSCRIPTION_ROLES},
 | 
					    consts::{CNC_GUILD, SUBSCRIPTION_ROLES},
 | 
				
			||||||
    ApplicationContext, Context, Error,
 | 
					    ApplicationContext, Context, Database, Error,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Check if this user/guild combination should be considered subscribed.
 | 
					/// Check if this user/guild combination should be considered subscribed.
 | 
				
			||||||
/// If the guild has a patreon linked, check the user involved in the link.
 | 
					/// If the guild has a patreon linked, check the user involved in the link.
 | 
				
			||||||
/// Otherwise, check the user and the guild's owner
 | 
					/// Otherwise, check the user and the guild's owner
 | 
				
			||||||
pub async fn check_subscription(
 | 
					pub async fn check_subscription(
 | 
				
			||||||
    ctx: &Context<'_>,
 | 
					    ctx: impl CacheHttp,
 | 
				
			||||||
 | 
					    database: impl Executor<'_, Database = Database>,
 | 
				
			||||||
    user_id: UserId,
 | 
					    user_id: UserId,
 | 
				
			||||||
    guild_id: Option<GuildId>,
 | 
					    guild_id: Option<GuildId>,
 | 
				
			||||||
) -> bool {
 | 
					) -> bool {
 | 
				
			||||||
    if let Some(subscription_guild) = *CNC_GUILD {
 | 
					    if let Some(subscription_guild) = *CNC_GUILD {
 | 
				
			||||||
        let user_subscribed = check_user_subscription(ctx, user_id).await;
 | 
					        let user_subscribed = check_user_subscription(&ctx, user_id).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let owner_subscribed = match guild_id {
 | 
					        let owner_subscribed = match guild_id {
 | 
				
			||||||
            Some(guild_id) => {
 | 
					            Some(guild_id) => {
 | 
				
			||||||
                if let Some(owner) = ctx.cache().unwrap().guild(guild_id).map(|g| g.owner_id) {
 | 
					                if let Some(owner) = ctx.cache().unwrap().guild(guild_id).map(|g| g.owner_id) {
 | 
				
			||||||
                    check_user_subscription(ctx, owner).await
 | 
					                    check_user_subscription(&ctx, owner).await
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    false
 | 
					                    false
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -38,13 +39,13 @@ pub async fn check_subscription(
 | 
				
			|||||||
        let link_subscribed = match guild_id {
 | 
					        let link_subscribed = match guild_id {
 | 
				
			||||||
            Some(guild_id) => {
 | 
					            Some(guild_id) => {
 | 
				
			||||||
                if let Ok(row) = sqlx::query!(
 | 
					                if let Ok(row) = sqlx::query!(
 | 
				
			||||||
                    "SELECT user_id FROM patreon_link WHERE user_id = ?",
 | 
					                    "SELECT user_id FROM patreon_link WHERE guild_id = ?",
 | 
				
			||||||
                    guild_id.get()
 | 
					                    guild_id.get()
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                .fetch_one(&ctx.data().database)
 | 
					                .fetch_one(database)
 | 
				
			||||||
                .await
 | 
					                .await
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    check_user_subscription(ctx, row.user_id).await
 | 
					                    check_user_subscription(&ctx, row.user_id).await
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    false
 | 
					                    false
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -116,6 +117,7 @@ pub trait Extract {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use extract_derive::Extract;
 | 
					pub use extract_derive::Extract;
 | 
				
			||||||
 | 
					use sqlx::Executor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! extract_arg {
 | 
					macro_rules! extract_arg {
 | 
				
			||||||
    ($ctx:ident, $name:ident, String) => {
 | 
					    ($ctx:ident, $name:ident, String) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -233,39 +233,6 @@ pub async fn initialize(
 | 
				
			|||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<UserId>) -> bool {
 | 
					 | 
				
			||||||
    offline!(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if let Some(subscription_guild) = *CNC_GUILD {
 | 
					 | 
				
			||||||
        let guild_member = GuildId::new(subscription_guild).member(cache_http, user_id).await;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Ok(member) = guild_member {
 | 
					 | 
				
			||||||
            for role in member.roles {
 | 
					 | 
				
			||||||
                if SUBSCRIPTION_ROLES.contains(&role.get()) {
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        false
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn check_guild_subscription(
 | 
					 | 
				
			||||||
    cache_http: impl CacheHttp,
 | 
					 | 
				
			||||||
    guild_id: impl Into<GuildId>,
 | 
					 | 
				
			||||||
) -> bool {
 | 
					 | 
				
			||||||
    offline!(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if let Some(owner) = cache_http.cache().unwrap().guild(guild_id).map(|guild| guild.owner_id) {
 | 
					 | 
				
			||||||
        check_subscription(&cache_http, owner).await
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub async fn check_authorization(
 | 
					pub async fn check_authorization(
 | 
				
			||||||
    cookies: &CookieJar<'_>,
 | 
					    cookies: &CookieJar<'_>,
 | 
				
			||||||
    ctx: &Context,
 | 
					    ctx: &Context,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,9 @@ use serenity::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use sqlx::{MySql, Pool};
 | 
					use sqlx::{MySql, Pool};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::utils::check_subscription;
 | 
				
			||||||
use crate::web::{
 | 
					use crate::web::{
 | 
				
			||||||
    check_authorization, check_guild_subscription, check_subscription,
 | 
					    check_authorization,
 | 
				
			||||||
    consts::MIN_INTERVAL,
 | 
					    consts::MIN_INTERVAL,
 | 
				
			||||||
    guards::transaction::Transaction,
 | 
					    guards::transaction::Transaction,
 | 
				
			||||||
    routes::{
 | 
					    routes::{
 | 
				
			||||||
@@ -186,8 +187,13 @@ pub async fn edit_reminder(
 | 
				
			|||||||
        || reminder.interval_months.flatten().is_some()
 | 
					        || reminder.interval_months.flatten().is_some()
 | 
				
			||||||
        || reminder.interval_seconds.flatten().is_some()
 | 
					        || reminder.interval_seconds.flatten().is_some()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if check_guild_subscription(&ctx.inner(), id).await
 | 
					        if check_subscription(
 | 
				
			||||||
            || check_subscription(&ctx.inner(), user_id).await
 | 
					            ctx.inner(),
 | 
				
			||||||
 | 
					            transaction.executor(),
 | 
				
			||||||
 | 
					            UserId::from(user_id),
 | 
				
			||||||
 | 
					            Some(GuildId::from(id)),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let new_interval_length = match reminder.interval_days {
 | 
					            let new_interval_length = match reminder.interval_days {
 | 
				
			||||||
                Some(interval) => interval.unwrap_or(0),
 | 
					                Some(interval) => interval.unwrap_or(0),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
 | 
				
			|||||||
use serenity::{client::Context, model::id::UserId};
 | 
					use serenity::{client::Context, model::id::UserId};
 | 
				
			||||||
use sqlx::types::Json;
 | 
					use sqlx::types::Json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::utils::check_subscription;
 | 
				
			||||||
use crate::web::{
 | 
					use crate::web::{
 | 
				
			||||||
    check_subscription,
 | 
					 | 
				
			||||||
    consts::{
 | 
					    consts::{
 | 
				
			||||||
        DAY, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
 | 
					        DAY, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
 | 
				
			||||||
        MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH,
 | 
					        MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH,
 | 
				
			||||||
@@ -131,7 +131,7 @@ pub async fn create_reminder(
 | 
				
			|||||||
        || reminder.interval_days.is_some()
 | 
					        || reminder.interval_days.is_some()
 | 
				
			||||||
        || reminder.interval_months.is_some()
 | 
					        || reminder.interval_months.is_some()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if !check_subscription(&ctx, user_id).await {
 | 
					        if !check_subscription(&ctx, transaction.executor(), user_id, None).await {
 | 
				
			||||||
            return Err(json!({"error": "Patreon is required to set intervals"}));
 | 
					            return Err(json!({"error": "Patreon is required to set intervals"}));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,8 @@ use rocket::{
 | 
				
			|||||||
use serenity::{client::Context, model::id::UserId};
 | 
					use serenity::{client::Context, model::id::UserId};
 | 
				
			||||||
use sqlx::{MySql, Pool};
 | 
					use sqlx::{MySql, Pool};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::utils::check_subscription;
 | 
				
			||||||
use crate::web::{
 | 
					use crate::web::{
 | 
				
			||||||
    check_subscription,
 | 
					 | 
				
			||||||
    guards::transaction::Transaction,
 | 
					    guards::transaction::Transaction,
 | 
				
			||||||
    routes::{
 | 
					    routes::{
 | 
				
			||||||
        dashboard::{
 | 
					        dashboard::{
 | 
				
			||||||
@@ -162,7 +162,9 @@ pub async fn edit_reminder(
 | 
				
			|||||||
        || reminder.interval_months.flatten().is_some()
 | 
					        || reminder.interval_months.flatten().is_some()
 | 
				
			||||||
        || reminder.interval_seconds.flatten().is_some()
 | 
					        || reminder.interval_seconds.flatten().is_some()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if check_subscription(&ctx.inner(), user_id).await {
 | 
					        if check_subscription(&ctx.inner(), transaction.executor(), UserId::from(user_id), None)
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            let new_interval_length = match reminder.interval_days {
 | 
					            let new_interval_length = match reminder.interval_days {
 | 
				
			||||||
                Some(interval) => interval.unwrap_or(0),
 | 
					                Some(interval) => interval.unwrap_or(0),
 | 
				
			||||||
                None => sqlx::query!(
 | 
					                None => sqlx::query!(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,9 +20,9 @@ use serenity::{
 | 
				
			|||||||
use sqlx::types::Json;
 | 
					use sqlx::types::Json;
 | 
				
			||||||
use sqlx::FromRow;
 | 
					use sqlx::FromRow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::utils::check_subscription;
 | 
				
			||||||
use crate::web::{
 | 
					use crate::web::{
 | 
				
			||||||
    catchers::internal_server_error,
 | 
					    catchers::internal_server_error,
 | 
				
			||||||
    check_guild_subscription, check_subscription,
 | 
					 | 
				
			||||||
    consts::{
 | 
					    consts::{
 | 
				
			||||||
        CHARACTERS, DAY, DEFAULT_AVATAR, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH,
 | 
					        CHARACTERS, DAY, DEFAULT_AVATAR, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH,
 | 
				
			||||||
        MAX_EMBED_DESCRIPTION_LENGTH, MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH,
 | 
					        MAX_EMBED_DESCRIPTION_LENGTH, MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH,
 | 
				
			||||||
@@ -477,9 +477,7 @@ pub(crate) async fn create_reminder(
 | 
				
			|||||||
        || reminder.interval_days.is_some()
 | 
					        || reminder.interval_days.is_some()
 | 
				
			||||||
        || reminder.interval_months.is_some()
 | 
					        || reminder.interval_months.is_some()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if !check_guild_subscription(&ctx, guild_id).await
 | 
					        if !check_subscription(&ctx, transaction.executor(), user_id, Some(guild_id)).await {
 | 
				
			||||||
            && !check_subscription(&ctx, user_id).await
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return Err(json!({"error": "Patreon is required to set intervals"}));
 | 
					            return Err(json!({"error": "Patreon is required to set intervals"}));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user