Compare commits
	
		
			17 Commits
		
	
	
		
			afd0a0d0a3
			...
			56cb94e1a0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 56cb94e1a0 | |||
| 4e363876e7 | |||
| 20e3d6d4b2 | |||
| b3cbe42450 | |||
| 68c585405d | |||
| e8d8c265a7 | |||
| a274ddb89f | |||
| 22fcea8a96 | |||
| 0d5d82a23b | |||
| 50403381e0 | |||
| 6758829634 | |||
| 9f89a2a892 | |||
| c8d2865383 | |||
| 09de99234c | |||
| fe75fb7acc | |||
| 477151f423 | |||
| c22af69b2a | 
@ -6,7 +6,7 @@ from tlapbot.db import get_db
 | 
				
			|||||||
from tlapbot.owncast_requests import is_stream_live, give_points_to_chat
 | 
					from tlapbot.owncast_requests import is_stream_live, give_points_to_chat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_app(test_config=None):
 | 
					def create_app(test_config: None = None) -> Flask:
 | 
				
			||||||
    app = Flask(__name__, instance_relative_config=True)
 | 
					    app = Flask(__name__, instance_relative_config=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ensure the instance folder exists
 | 
					    # ensure the instance folder exists
 | 
				
			||||||
@ -59,7 +59,7 @@ def create_app(test_config=None):
 | 
				
			|||||||
    app.cli.add_command(db.hard_reset_milestone_command)
 | 
					    app.cli.add_command(db.hard_reset_milestone_command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # scheduler job for giving points to users
 | 
					    # scheduler job for giving points to users
 | 
				
			||||||
    def proxy_job():
 | 
					    def proxy_job() -> None:
 | 
				
			||||||
        with app.app_context():
 | 
					        with app.app_context():
 | 
				
			||||||
            if is_stream_live():
 | 
					            if is_stream_live():
 | 
				
			||||||
                app.logger.info("Stream is LIVE. Giving points to chat.")
 | 
					                app.logger.info("Stream is LIVE. Giving points to chat.")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
import sqlite3
 | 
					import sqlite3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import click
 | 
					import click
 | 
				
			||||||
from flask import current_app, g
 | 
					from flask import current_app, g, Flask
 | 
				
			||||||
from flask.cli import with_appcontext
 | 
					from flask.cli import with_appcontext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tlapbot.redeems import milestone_complete
 | 
					from tlapbot.redeems import milestone_complete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_db():
 | 
					def get_db() -> sqlite3.Connection:
 | 
				
			||||||
    if 'db' not in g:
 | 
					    if 'db' not in g:
 | 
				
			||||||
        g.db = sqlite3.connect(
 | 
					        g.db = sqlite3.connect(
 | 
				
			||||||
            current_app.config['DATABASE'],
 | 
					            current_app.config['DATABASE'],
 | 
				
			||||||
@ -18,14 +18,14 @@ def get_db():
 | 
				
			|||||||
    return g.db
 | 
					    return g.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def close_db(e=None):
 | 
					def close_db() -> None:
 | 
				
			||||||
    db = g.pop('db', None)
 | 
					    db: sqlite3.Connection = g.pop('db', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if db is not None:
 | 
					    if db is not None:
 | 
				
			||||||
        db.close()
 | 
					        db.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def insert_counters(db):
 | 
					def insert_counters(db: sqlite3.Connection) -> bool:
 | 
				
			||||||
    for redeem, redeem_info in current_app.config['REDEEMS'].items():
 | 
					    for redeem, redeem_info in current_app.config['REDEEMS'].items():
 | 
				
			||||||
        if redeem_info["type"] == "counter":
 | 
					        if redeem_info["type"] == "counter":
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
@ -40,17 +40,16 @@ def insert_counters(db):
 | 
				
			|||||||
    return True
 | 
					    return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def init_db():
 | 
					def init_db() -> bool:
 | 
				
			||||||
    db = get_db()
 | 
					    db = get_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with current_app.open_resource('schema.sql') as f:
 | 
					    with current_app.open_resource('schema.sql') as f:
 | 
				
			||||||
        db.executescript(f.read().decode('utf8'))
 | 
					        db.executescript(f.read().decode('utf8'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if insert_counters(db):
 | 
					    return insert_counters(db)
 | 
				
			||||||
        return True
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def clear_redeem_queue():
 | 
					def clear_redeem_queue() -> bool:
 | 
				
			||||||
    db = get_db()
 | 
					    db = get_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@ -62,25 +61,24 @@ def clear_redeem_queue():
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except sqlite3.Error as e:
 | 
					    except sqlite3.Error as e:
 | 
				
			||||||
        print("Error occured deleting redeem queue:", e.args[0])
 | 
					        print("Error occurred deleting redeem queue:", e.args[0])
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
    return True
 | 
					    return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def refresh_counters():
 | 
					def refresh_counters() -> bool:
 | 
				
			||||||
    db = get_db()
 | 
					    db = get_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute("DELETE FROM counters")
 | 
					        db.execute("DELETE FROM counters")
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except sqlite3.Error as e:
 | 
					    except sqlite3.Error as e:
 | 
				
			||||||
        print("Error occured deleting old counters:", e.args[0])
 | 
					        print("Error occurred deleting old counters:", e.args[0])
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
    if insert_counters(db):
 | 
					    return insert_counters(db)
 | 
				
			||||||
        return True
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def refresh_milestones():
 | 
					def refresh_milestones() -> bool:
 | 
				
			||||||
    db = get_db()
 | 
					    db = get_db()
 | 
				
			||||||
    # delete old milestones
 | 
					    # delete old milestones
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@ -111,7 +109,7 @@ def refresh_milestones():
 | 
				
			|||||||
                result = cursor.fetchone()
 | 
					                result = cursor.fetchone()
 | 
				
			||||||
                if result is None:
 | 
					                if result is None:
 | 
				
			||||||
                    cursor.execute(
 | 
					                    cursor.execute(
 | 
				
			||||||
                        "INSERT INTO milestones(name, progress, goal, complete) VALUES(?, 0, ?, FALSE)",
 | 
					                        "INSERT INTO milestones(name, progress, goal) VALUES(?, 0, ?)",
 | 
				
			||||||
                        (redeem, redeem_info['goal'])
 | 
					                        (redeem, redeem_info['goal'])
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                # update existing milestone to new goal
 | 
					                # update existing milestone to new goal
 | 
				
			||||||
@ -127,7 +125,7 @@ def refresh_milestones():
 | 
				
			|||||||
    return True
 | 
					    return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reset_milestone(milestone):
 | 
					def reset_milestone(milestone: str) -> bool:
 | 
				
			||||||
    if milestone not in current_app.config['REDEEMS']:
 | 
					    if milestone not in current_app.config['REDEEMS']:
 | 
				
			||||||
        print(f"Failed resetting milestone, {milestone} not in redeems file.")
 | 
					        print(f"Failed resetting milestone, {milestone} not in redeems file.")
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
@ -138,19 +136,19 @@ def reset_milestone(milestone):
 | 
				
			|||||||
            (milestone,)
 | 
					            (milestone,)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            "INSERT INTO milestones(name, progress, goal, complete) VALUES(?, ?, ?, FALSE)",
 | 
					            "INSERT INTO milestones(name, progress, goal) VALUES(?, ?, ?)",
 | 
				
			||||||
            (milestone, 0, current_app.config['REDEEMS'][milestone]['goal'])
 | 
					            (milestone, 0, current_app.config['REDEEMS'][milestone]['goal'])
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except sqlite3.Error as e:
 | 
					    except sqlite3.Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured adding a milestone: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred adding a milestone: {e.args[0]}")
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@click.command('init-db')
 | 
					@click.command('init-db')
 | 
				
			||||||
@with_appcontext
 | 
					@with_appcontext
 | 
				
			||||||
def init_db_command():
 | 
					def init_db_command() -> None:
 | 
				
			||||||
    """Clear the existing data and create new tables."""
 | 
					    """Clear the existing data and create new tables."""
 | 
				
			||||||
    if init_db():
 | 
					    if init_db():
 | 
				
			||||||
        click.echo('Initialized the database.')
 | 
					        click.echo('Initialized the database.')
 | 
				
			||||||
@ -158,7 +156,7 @@ def init_db_command():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('clear-queue')
 | 
					@click.command('clear-queue')
 | 
				
			||||||
@with_appcontext
 | 
					@with_appcontext
 | 
				
			||||||
def clear_queue_command():
 | 
					def clear_queue_command() -> None:
 | 
				
			||||||
    """Remove all redeems from the redeem queue."""
 | 
					    """Remove all redeems from the redeem queue."""
 | 
				
			||||||
    if clear_redeem_queue():
 | 
					    if clear_redeem_queue():
 | 
				
			||||||
        click.echo('Cleared redeem queue.')
 | 
					        click.echo('Cleared redeem queue.')
 | 
				
			||||||
@ -166,7 +164,7 @@ def clear_queue_command():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('refresh-counters')
 | 
					@click.command('refresh-counters')
 | 
				
			||||||
@with_appcontext
 | 
					@with_appcontext
 | 
				
			||||||
def refresh_counters_command():
 | 
					def refresh_counters_command() -> None:
 | 
				
			||||||
    """Refresh counters from current config file.
 | 
					    """Refresh counters from current config file.
 | 
				
			||||||
    (Remove old ones, add new ones.)"""
 | 
					    (Remove old ones, add new ones.)"""
 | 
				
			||||||
    if refresh_counters():
 | 
					    if refresh_counters():
 | 
				
			||||||
@ -175,7 +173,7 @@ def refresh_counters_command():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('clear-refresh')
 | 
					@click.command('clear-refresh')
 | 
				
			||||||
@with_appcontext
 | 
					@with_appcontext
 | 
				
			||||||
def refresh_and_clear_command():
 | 
					def refresh_and_clear_command() -> None:
 | 
				
			||||||
    """Refresh counters and clear queue."""
 | 
					    """Refresh counters and clear queue."""
 | 
				
			||||||
    if refresh_counters() and clear_redeem_queue():
 | 
					    if refresh_counters() and clear_redeem_queue():
 | 
				
			||||||
        click.echo('Counters refreshed and queue cleared.')
 | 
					        click.echo('Counters refreshed and queue cleared.')
 | 
				
			||||||
@ -183,7 +181,7 @@ def refresh_and_clear_command():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('refresh-milestones')
 | 
					@click.command('refresh-milestones')
 | 
				
			||||||
@with_appcontext
 | 
					@with_appcontext
 | 
				
			||||||
def refresh_milestones_command():
 | 
					def refresh_milestones_command() -> None:
 | 
				
			||||||
    """Initialize all milestones from the redeems file,
 | 
					    """Initialize all milestones from the redeems file,
 | 
				
			||||||
    delete milestones not in redeem file."""
 | 
					    delete milestones not in redeem file."""
 | 
				
			||||||
    if refresh_milestones():
 | 
					    if refresh_milestones():
 | 
				
			||||||
@ -192,7 +190,7 @@ def refresh_milestones_command():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('reset-milestone')
 | 
					@click.command('reset-milestone')
 | 
				
			||||||
@click.argument('milestone')
 | 
					@click.argument('milestone')
 | 
				
			||||||
def reset_milestone_command(milestone):
 | 
					def reset_milestone_command(milestone: str) -> None:
 | 
				
			||||||
    """Resets a completed milestone back to zero."""
 | 
					    """Resets a completed milestone back to zero."""
 | 
				
			||||||
    if milestone_complete(get_db(), milestone):
 | 
					    if milestone_complete(get_db(), milestone):
 | 
				
			||||||
        if reset_milestone(milestone):
 | 
					        if reset_milestone(milestone):
 | 
				
			||||||
@ -204,12 +202,12 @@ def reset_milestone_command(milestone):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@click.command('hard-reset-milestone')
 | 
					@click.command('hard-reset-milestone')
 | 
				
			||||||
@click.argument('milestone')
 | 
					@click.argument('milestone')
 | 
				
			||||||
def hard_reset_milestone_command(milestone):
 | 
					def hard_reset_milestone_command(milestone: str) -> None:
 | 
				
			||||||
    """Resets any milestone back to zero."""
 | 
					    """Resets any milestone back to zero."""
 | 
				
			||||||
    if reset_milestone(milestone):
 | 
					    if reset_milestone(milestone):
 | 
				
			||||||
        click.echo(f"Hard reset milestone {milestone}.")
 | 
					        click.echo(f"Hard reset milestone {milestone}.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def init_app(app):
 | 
					def init_app(app: Flask) -> None:
 | 
				
			||||||
    app.teardown_appcontext(close_db)
 | 
					    app.teardown_appcontext(close_db)
 | 
				
			||||||
    app.cli.add_command(init_db_command)
 | 
					    app.cli.add_command(init_db_command)
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ from flask import current_app
 | 
				
			|||||||
from tlapbot.owncast_requests import send_chat
 | 
					from tlapbot.owncast_requests import send_chat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_help():
 | 
					def send_help() -> None:
 | 
				
			||||||
    message = []
 | 
					    message = []
 | 
				
			||||||
    message.append("Tlapbot gives you points for being in chat, and then allows you to spend those points. <br>")
 | 
					    message.append("Tlapbot gives you points for being in chat, and then allows you to spend those points. <br>")
 | 
				
			||||||
    message.append(f"People connected to chat receive {current_app.config['POINTS_AMOUNT_GIVEN']} points every {current_app.config['POINTS_CYCLE_TIME']} seconds. <br>")
 | 
					    message.append(f"People connected to chat receive {current_app.config['POINTS_AMOUNT_GIVEN']} points every {current_app.config['POINTS_CYCLE_TIME']} seconds. <br>")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
from flask import current_app
 | 
					from flask import current_app
 | 
				
			||||||
from sqlite3 import Error
 | 
					from sqlite3 import Error, Connection
 | 
				
			||||||
from re import sub
 | 
					from re import sub
 | 
				
			||||||
 | 
					from typing import Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# # # db stuff # # #
 | 
					# # # db stuff # # #
 | 
				
			||||||
def read_users_points(db, user_id):
 | 
					def read_users_points(db: Connection, user_id: str) -> int | None:
 | 
				
			||||||
    """Errors out if user doesn't exist."""
 | 
					    """Returns None and logs error in case of error, or if user doesn't exist."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT points FROM points WHERE id = ?",
 | 
					            "SELECT points FROM points WHERE id = ?",
 | 
				
			||||||
@ -13,11 +14,12 @@ def read_users_points(db, user_id):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        return cursor.fetchone()[0]
 | 
					        return cursor.fetchone()[0]
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured reading points: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred reading points: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user: {user_id}")
 | 
					        current_app.logger.error(f"Of user: {user_id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def read_all_users_with_username(db, username):
 | 
					def read_all_users_with_username(db: Connection, username: str) -> list[Tuple[str, int]] | None:
 | 
				
			||||||
 | 
					    """Returns None only if Error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT name, points FROM points WHERE name = ?",
 | 
					            "SELECT name, points FROM points WHERE name = ?",
 | 
				
			||||||
@ -26,11 +28,11 @@ def read_all_users_with_username(db, username):
 | 
				
			|||||||
        users = cursor.fetchall()
 | 
					        users = cursor.fetchall()
 | 
				
			||||||
        return users
 | 
					        return users
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured reading points by username: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred reading points by username: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To everyone with username: {username}")
 | 
					        current_app.logger.error(f"Of everyone with username: {username}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def give_points_to_user(db, user_id, points):
 | 
					def give_points_to_user(db: Connection, user_id: str, points: int) -> None:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            "UPDATE points SET points = points + ? WHERE id = ?",
 | 
					            "UPDATE points SET points = points + ? WHERE id = ?",
 | 
				
			||||||
@ -38,11 +40,11 @@ def give_points_to_user(db, user_id, points):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured giving points: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred giving points: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user: {user_id} amount of points: {points}")
 | 
					        current_app.logger.error(f"To user: {user_id} amount of points: {points}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def use_points(db, user_id, points):
 | 
					def use_points(db: Connection, user_id: str, points: int) -> bool:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            "UPDATE points SET points = points - ? WHERE id = ?",
 | 
					            "UPDATE points SET points = points - ? WHERE id = ?",
 | 
				
			||||||
@ -51,12 +53,13 @@ def use_points(db, user_id, points):
 | 
				
			|||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured using points: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred using points: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"From user: {user_id} amount of points: {points}")
 | 
					        current_app.logger.error(f"From user: {user_id} amount of points: {points}")
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def user_exists(db, user_id):
 | 
					def user_exists(db: Connection, user_id: str) -> bool | None:
 | 
				
			||||||
 | 
					    """Returns None only if an error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT points FROM points WHERE id = ?",
 | 
					            "SELECT points FROM points WHERE id = ?",
 | 
				
			||||||
@ -66,11 +69,11 @@ def user_exists(db, user_id):
 | 
				
			|||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured checking if user exists: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred checking if user exists: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user: {user_id}")
 | 
					        current_app.logger.error(f"To user: {user_id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_user_to_database(db, user_id, display_name):
 | 
					def add_user_to_database(db: Connection, user_id: str, display_name: str) -> None:
 | 
				
			||||||
    """ Adds a new user to the database. Does nothing if user is already in."""
 | 
					    """ Adds a new user to the database. Does nothing if user is already in."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
@ -92,11 +95,11 @@ def add_user_to_database(db, user_id, display_name):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured adding user to db: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred adding user to db: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user id: {user_id}, with display name: {display_name}")
 | 
					        current_app.logger.error(f"To user id: {user_id}, with display name: {display_name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def change_display_name(db, user_id, new_name):
 | 
					def change_display_name(db: Connection, user_id: str, new_name: str) -> None:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            "UPDATE points SET name = ? WHERE id = ?",
 | 
					            "UPDATE points SET name = ? WHERE id = ?",
 | 
				
			||||||
@ -104,11 +107,11 @@ def change_display_name(db, user_id, new_name):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured changing display name: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred changing display name: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user id: {user_id}, with display name: {new_name}")
 | 
					        current_app.logger.error(f"To user id: {user_id}, with display name: {new_name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def remove_duplicate_usernames(db, user_id, username):
 | 
					def remove_duplicate_usernames(db: Connection, user_id: str, username: str) -> None:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            """UPDATE points
 | 
					            """UPDATE points
 | 
				
			||||||
@ -118,12 +121,12 @@ def remove_duplicate_usernames(db, user_id, username):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured removing duplicate usernames: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred removing duplicate usernames: {e.args[0]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# # # misc. stuff # # #
 | 
					# # # misc. stuff # # #
 | 
				
			||||||
# This is now unused since rawBody attribute of the webhook now returns cleaned-up emotes.
 | 
					# This is now unused since rawBody attribute of the webhook now returns cleaned-up emotes.
 | 
				
			||||||
def remove_emoji(message):
 | 
					def remove_emoji(message: str) -> str:
 | 
				
			||||||
    return sub(
 | 
					    return sub(
 | 
				
			||||||
        r'<img class="emoji" alt="(:.*?:)" title=":.*?:" src="/img/emoji/.*?">',
 | 
					        r'<img class="emoji" alt="(:.*?:)" title=":.*?:" src="/img/emoji/.*?">',
 | 
				
			||||||
        r'\1',
 | 
					        r'\1',
 | 
				
			||||||
 | 
				
			|||||||
@ -1,28 +1,30 @@
 | 
				
			|||||||
import requests
 | 
					import requests
 | 
				
			||||||
from flask import current_app
 | 
					from flask import current_app
 | 
				
			||||||
from tlapbot.owncast_helpers import give_points_to_user
 | 
					from tlapbot.owncast_helpers import give_points_to_user
 | 
				
			||||||
 | 
					from sqlite3 import Connection
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def is_stream_live():
 | 
					def is_stream_live() -> bool:
 | 
				
			||||||
    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/status'
 | 
					    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/status'
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        r = requests.get(url)
 | 
					        r = requests.get(url)
 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured checking if stream is live: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred checking if stream is live: {e.args[0]}")
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
    return r.json()["online"]
 | 
					    return r.json()["online"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def give_points_to_chat(db):
 | 
					def give_points_to_chat(db: Connection) -> None:
 | 
				
			||||||
    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/integrations/clients'
 | 
					    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/integrations/clients'
 | 
				
			||||||
    headers = {"Authorization": "Bearer " + current_app.config['OWNCAST_ACCESS_TOKEN']}
 | 
					    headers = {"Authorization": "Bearer " + current_app.config['OWNCAST_ACCESS_TOKEN']}
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        r = requests.get(url, headers=headers)
 | 
					        r = requests.get(url, headers=headers)
 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured getting users to give points to: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred getting users to give points to: {e.args[0]}")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    if r.status_code != 200:
 | 
					    if r.status_code != 200:
 | 
				
			||||||
        current_app.logger.error(f"Error occured when giving points: Response code not 200.")
 | 
					        current_app.logger.error(f"Error occurred when giving points: Response code not 200.")
 | 
				
			||||||
        current_app.logger.error(f"Response code received: {r.status_code}.")
 | 
					        current_app.logger.error(f"Response code received: {r.status_code}.")
 | 
				
			||||||
        current_app.logger.error(f"Check owncast instance url and access key.")
 | 
					        current_app.logger.error(f"Check owncast instance url and access key.")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
@ -31,16 +33,16 @@ def give_points_to_chat(db):
 | 
				
			|||||||
        give_points_to_user(db, user_id, current_app.config['POINTS_AMOUNT_GIVEN'])
 | 
					        give_points_to_user(db, user_id, current_app.config['POINTS_AMOUNT_GIVEN'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_chat(message):
 | 
					def send_chat(message: str) -> Any:
 | 
				
			||||||
    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/integrations/chat/send'
 | 
					    url = current_app.config['OWNCAST_INSTANCE_URL'] + '/api/integrations/chat/send'
 | 
				
			||||||
    headers = {"Authorization": "Bearer " + current_app.config['OWNCAST_ACCESS_TOKEN']}
 | 
					    headers = {"Authorization": "Bearer " + current_app.config['OWNCAST_ACCESS_TOKEN']}
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        r = requests.post(url, headers=headers, json={"body": message})
 | 
					        r = requests.post(url, headers=headers, json={"body": message})
 | 
				
			||||||
    except requests.exceptions.RequestException as e:
 | 
					    except requests.exceptions.RequestException as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured sending chat message: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred sending chat message: {e.args[0]}")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    if r.status_code != 200:
 | 
					    if r.status_code != 200:
 | 
				
			||||||
        current_app.logger.error(f"Error occured when sending chat: Response code not 200.")
 | 
					        current_app.logger.error(f"Error occurred when sending chat: Response code not 200.")
 | 
				
			||||||
        current_app.logger.error(f"Response code received: {r.status_code}.")
 | 
					        current_app.logger.error(f"Response code received: {r.status_code}.")
 | 
				
			||||||
        current_app.logger.error(f"Check owncast instance url and access key.")
 | 
					        current_app.logger.error(f"Check owncast instance url and access key.")
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
from flask import Flask, request, json, Blueprint, current_app
 | 
					from flask import Flask, request, json, Blueprint, current_app
 | 
				
			||||||
 | 
					from sqlite3 import Connection
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
from tlapbot.db import get_db
 | 
					from tlapbot.db import get_db
 | 
				
			||||||
from tlapbot.owncast_requests import send_chat
 | 
					from tlapbot.owncast_requests import send_chat
 | 
				
			||||||
from tlapbot.owncast_helpers import (add_user_to_database, change_display_name,
 | 
					from tlapbot.owncast_helpers import (add_user_to_database, change_display_name,
 | 
				
			||||||
@ -11,9 +13,12 @@ bp = Blueprint('owncast_webhooks', __name__)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/owncastWebhook', methods=['POST'])
 | 
					@bp.route('/owncastWebhook', methods=['POST'])
 | 
				
			||||||
def owncast_webhook():
 | 
					def owncast_webhook() -> Any | None:
 | 
				
			||||||
    data = request.json
 | 
					    """Reads webhook json -- adds new users, removes duplicate usernames,
 | 
				
			||||||
    db = get_db()
 | 
					    handles name changes and chat messages with commands.
 | 
				
			||||||
 | 
					    Returns the 'data' json from the request."""
 | 
				
			||||||
 | 
					    data: Any | None = request.json
 | 
				
			||||||
 | 
					    db: Connection = get_db()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Make sure user is in db before doing anything else.
 | 
					    # Make sure user is in db before doing anything else.
 | 
				
			||||||
    if data["type"] in ["CHAT", "NAME_CHANGED", "USER_JOINED"]:
 | 
					    if data["type"] in ["CHAT", "NAME_CHANGED", "USER_JOINED"]:
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,11 @@
 | 
				
			|||||||
from flask import current_app
 | 
					from flask import current_app
 | 
				
			||||||
from sqlite3 import Error
 | 
					from sqlite3 import Error, Connection
 | 
				
			||||||
 | 
					from typing import Tuple, Any
 | 
				
			||||||
from tlapbot.owncast_helpers import use_points
 | 
					from tlapbot.owncast_helpers import use_points
 | 
				
			||||||
 | 
					from tlapbot.tlapbot_types import Redeems
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def counter_exists(db, counter_name):
 | 
					def counter_exists(db: Connection, counter_name: str) -> bool | None:
 | 
				
			||||||
 | 
					    """Returns None only if error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT count FROM counters WHERE name = ?",
 | 
					            "SELECT count FROM counters WHERE name = ?",
 | 
				
			||||||
@ -16,11 +19,11 @@ def counter_exists(db, counter_name):
 | 
				
			|||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured checking if counter exists: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred checking if counter exists: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"For counter: {counter_name}")
 | 
					        current_app.logger.error(f"For counter: {counter_name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_to_counter(db, counter_name):
 | 
					def add_to_counter(db: Connection, counter_name: str) -> bool:
 | 
				
			||||||
    if counter_exists(db, counter_name):
 | 
					    if counter_exists(db, counter_name):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            db.execute(
 | 
					            db.execute(
 | 
				
			||||||
@ -30,12 +33,12 @@ def add_to_counter(db, counter_name):
 | 
				
			|||||||
            db.commit()
 | 
					            db.commit()
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
        except Error as e:
 | 
					        except Error as e:
 | 
				
			||||||
            current_app.logger.error(f"Error occured adding to counter: {e.args[0]}")
 | 
					            current_app.logger.error(f"Error occurred adding to counter: {e.args[0]}")
 | 
				
			||||||
            current_app.logger.error(f"To counter: {counter_name}")
 | 
					            current_app.logger.error(f"To counter: {counter_name}")
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO: test if the new default works
 | 
				
			||||||
def add_to_redeem_queue(db, user_id, redeem_name, note=None):
 | 
					def add_to_redeem_queue(db: Connection, user_id: str, redeem_name: str, note: str="") -> bool:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        db.execute(
 | 
					        db.execute(
 | 
				
			||||||
            "INSERT INTO redeem_queue(redeem, redeemer_id, note) VALUES(?, ?, ?)",
 | 
					            "INSERT INTO redeem_queue(redeem, redeemer_id, note) VALUES(?, ?, ?)",
 | 
				
			||||||
@ -44,12 +47,12 @@ def add_to_redeem_queue(db, user_id, redeem_name, note=None):
 | 
				
			|||||||
        db.commit()
 | 
					        db.commit()
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured adding to redeem queue: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred adding to redeem queue: {e.args[0]}")
 | 
				
			||||||
        current_app.logger.error(f"To user: {user_id} with redeem: {redeem_name} with note: {note}")
 | 
					        current_app.logger.error(f"To user: {user_id} with redeem: {redeem_name} with note: {note}")
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def add_to_milestone(db, user_id, redeem_name, points_donated):
 | 
					def add_to_milestone(db: Connection, user_id: str, redeem_name: str, points_donated: int) -> bool:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT progress, goal FROM milestones WHERE name = ?",
 | 
					            "SELECT progress, goal FROM milestones WHERE name = ?",
 | 
				
			||||||
@ -74,28 +77,11 @@ def add_to_milestone(db, user_id, redeem_name, points_donated):
 | 
				
			|||||||
            db.commit()
 | 
					            db.commit()
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured updating milestone: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred updating milestone: {e.args[0]}")
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def milestone_complete(db: Connection, redeem_name: str) -> bool | None:
 | 
				
			||||||
def milestone_complete(db, redeem_name):
 | 
					    """Returns None only if error was logged."""
 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        cursor = db.execute(
 | 
					 | 
				
			||||||
            "SELECT complete FROM milestones WHERE name = ?",
 | 
					 | 
				
			||||||
            (redeem_name,)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        row = cursor.fetchone()
 | 
					 | 
				
			||||||
        if row is None:
 | 
					 | 
				
			||||||
            current_app.logger.warning("Milestone not found in database.")
 | 
					 | 
				
			||||||
            current_app.logger.warning("Maybe you forgot to run the refresh-milestones CLI command "
 | 
					 | 
				
			||||||
                                       "after you added a new milestone to the config?")
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return row[0]
 | 
					 | 
				
			||||||
    except Error as e:
 | 
					 | 
				
			||||||
        current_app.logger.error(f"Error occured checking if milestone is complete: {e.args[0]}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def check_apply_milestone_completion(db, redeem_name):
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT progress, goal FROM milestones WHERE name = ?",
 | 
					            "SELECT progress, goal FROM milestones WHERE name = ?",
 | 
				
			||||||
@ -109,57 +95,63 @@ def check_apply_milestone_completion(db, redeem_name):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            progress, goal = row
 | 
					            progress, goal = row
 | 
				
			||||||
            if progress == goal:
 | 
					            if progress == goal:
 | 
				
			||||||
                cursor = db.execute(
 | 
					 | 
				
			||||||
                    "UPDATE milestones SET complete = TRUE WHERE name = ?",
 | 
					 | 
				
			||||||
                    (redeem_name,)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                db.commit()
 | 
					 | 
				
			||||||
                return True
 | 
					                return True
 | 
				
			||||||
        return False
 | 
					            return False
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured applying milestone completion: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred checking if milestone is complete: {e.args[0]}")
 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def all_milestones(db):
 | 
					
 | 
				
			||||||
 | 
					def all_milestones(db: Connection) -> list[Tuple[str, int, int]] | None:
 | 
				
			||||||
 | 
					    """Returns list of all (even inactive) milestones, their progress and their goal.
 | 
				
			||||||
 | 
					    Returns None only if error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            """SELECT name, progress, goal FROM milestones"""
 | 
					            """SELECT name, progress, goal FROM milestones"""
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return cursor.fetchall()
 | 
					        return cursor.fetchall()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured selecting all milestones: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred selecting all milestones: {e.args[0]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def all_counters(db):
 | 
					def all_active_milestones(db: Connection) -> list[Tuple[str, int, int]] | None:
 | 
				
			||||||
 | 
					    """Returns list of all active milestones, their progress and their goal.
 | 
				
			||||||
 | 
					    Returns None only if error was logged."""
 | 
				
			||||||
 | 
					    milestones = all_milestones(db)
 | 
				
			||||||
 | 
					    if milestones is not None:
 | 
				
			||||||
 | 
					        all_active_milestones = []
 | 
				
			||||||
 | 
					        for name, progress, goal in milestones:
 | 
				
			||||||
 | 
					            if is_redeem_active(name):
 | 
				
			||||||
 | 
					                all_active_milestones.append((name, progress, goal))
 | 
				
			||||||
 | 
					        return all_active_milestones
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def all_counters(db: Connection) -> list[Tuple[str, int]] | None:
 | 
				
			||||||
 | 
					    """Returns list of all (even inactive) counters and their current value.
 | 
				
			||||||
 | 
					    Returns None only if error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            """SELECT counters.name, counters.count FROM counters"""
 | 
					            """SELECT name, count FROM counters"""
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return cursor.fetchall()
 | 
					        return cursor.fetchall()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured selecting all counters: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred selecting all counters: {e.args[0]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def all_active_counters(db):
 | 
					def all_active_counters(db: Connection) -> list[Tuple[str, int]] | None:
 | 
				
			||||||
 | 
					    """Returns list of all active counters, and their current value.
 | 
				
			||||||
 | 
					    Returns None if error was logged."""
 | 
				
			||||||
    counters = all_counters(db)
 | 
					    counters = all_counters(db)
 | 
				
			||||||
    all_active_counters = []
 | 
					    if counters is not None:
 | 
				
			||||||
    for name, count in counters:
 | 
					        all_active_counters = []
 | 
				
			||||||
        if is_redeem_active(name):
 | 
					        for name, count in counters:
 | 
				
			||||||
            all_active_counters.append((name, count))
 | 
					            if is_redeem_active(name):
 | 
				
			||||||
    return all_active_counters
 | 
					                all_active_counters.append((name, count))
 | 
				
			||||||
 | 
					        return all_active_counters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def all_active_milestones(db):
 | 
					def all_active_redeems() -> Redeems:
 | 
				
			||||||
    milestones = all_milestones(db)
 | 
					    """Returns list of all active redeems."""
 | 
				
			||||||
    all_active_milestones = []
 | 
					 | 
				
			||||||
    for name, progress, goal in milestones:
 | 
					 | 
				
			||||||
        if is_redeem_active(name):
 | 
					 | 
				
			||||||
            all_active_milestones.append((name, progress, goal))
 | 
					 | 
				
			||||||
    return all_active_milestones
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def all_active_redeems():
 | 
					 | 
				
			||||||
    redeems = current_app.config['REDEEMS']
 | 
					    redeems = current_app.config['REDEEMS']
 | 
				
			||||||
    all_active_redeems = {}
 | 
					    all_active_redeems = {}
 | 
				
			||||||
    for redeem_name, redeem_dict in redeems.items():
 | 
					    for redeem_name, redeem_dict in redeems.items():
 | 
				
			||||||
@ -173,7 +165,9 @@ def all_active_redeems():
 | 
				
			|||||||
    return all_active_redeems
 | 
					    return all_active_redeems
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pretty_redeem_queue(db):
 | 
					def pretty_redeem_queue(db: Connection) -> list[Tuple[str, str, str, str]] | None:
 | 
				
			||||||
 | 
					    """Returns a 'pretty' redeem queue, with name of the redeemer joined instead of ID.
 | 
				
			||||||
 | 
					    Returns None only if error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            """SELECT redeem_queue.created, redeem_queue.redeem, redeem_queue.note, points.name
 | 
					            """SELECT redeem_queue.created, redeem_queue.redeem, redeem_queue.note, points.name
 | 
				
			||||||
@ -183,45 +177,31 @@ def pretty_redeem_queue(db):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        return cursor.fetchall()
 | 
					        return cursor.fetchall()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured selecting pretty redeem queue: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred selecting pretty redeem queue: {e.args[0]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def whole_redeem_queue(db):
 | 
					def whole_redeem_queue(db: Connection) -> list[Any] | None:
 | 
				
			||||||
 | 
					    """Returns None if error was logged."""
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        cursor = db.execute(
 | 
					        cursor = db.execute(
 | 
				
			||||||
            "SELECT * from redeem_queue"
 | 
					            "SELECT * from redeem_queue" #TODO: specify columns to fetch
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return cursor.fetchall()
 | 
					        return cursor.fetchall()
 | 
				
			||||||
    except Error as e:
 | 
					    except Error as e:
 | 
				
			||||||
        current_app.logger.error(f"Error occured selecting redeem queue: {e.args[0]}")
 | 
					        current_app.logger.error(f"Error occurred selecting redeem queue: {e.args[0]}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def is_redeem_active(redeem_name):
 | 
					def is_redeem_active(redeem_name: str) -> bool | None:
 | 
				
			||||||
    """Checks if redeem is active. Pulls the redeem by name from config."""
 | 
					    """Checks if redeem is active. Pulls the redeem by name from config.
 | 
				
			||||||
 | 
					    Returns None if the redeem doesn't exist."""
 | 
				
			||||||
    active_categories = current_app.config['ACTIVE_CATEGORIES']
 | 
					    active_categories = current_app.config['ACTIVE_CATEGORIES']
 | 
				
			||||||
    redeem_dict = current_app.config['REDEEMS'].get(redeem_name, None)
 | 
					    redeem_dict = current_app.config['REDEEMS'].get(redeem_name, None)
 | 
				
			||||||
    if redeem_dict:
 | 
					    if redeem_dict:
 | 
				
			||||||
        if "category" in redeem_dict:
 | 
					        if redeem_dict.get('category', None):
 | 
				
			||||||
            for category in redeem_dict["category"]:
 | 
					            for category in redeem_dict["category"]:
 | 
				
			||||||
                if category in active_categories:
 | 
					                if category in active_categories:
 | 
				
			||||||
                    return True
 | 
					                    return True
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
    return None # redeem does not exist, unknown active state
 | 
					    return None # redeem does not exist, unknown active state
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def is_redeem_from_config_active(redeem, active_categories):
 | 
					 | 
				
			||||||
    """Checks if redeem is active. `redeem` is a whole key:value pair from redeems config."""
 | 
					 | 
				
			||||||
    if "category" in redeem[1] and redeem[1]["category"]:
 | 
					 | 
				
			||||||
        for category in redeem[1]["category"]:
 | 
					 | 
				
			||||||
            if category in active_categories:
 | 
					 | 
				
			||||||
                return True
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
    return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def remove_inactive_redeems(redeems, active_categories):
 | 
					 | 
				
			||||||
    return dict(filter(lambda redeem: is_redeem_from_config_active(redeem, active_categories),
 | 
					 | 
				
			||||||
                       redeems.items()))
 | 
					 | 
				
			||||||
@ -2,11 +2,11 @@ from flask import current_app
 | 
				
			|||||||
from tlapbot.db import get_db
 | 
					from tlapbot.db import get_db
 | 
				
			||||||
from tlapbot.owncast_requests import send_chat
 | 
					from tlapbot.owncast_requests import send_chat
 | 
				
			||||||
from tlapbot.redeems import (add_to_redeem_queue, add_to_counter, add_to_milestone,
 | 
					from tlapbot.redeems import (add_to_redeem_queue, add_to_counter, add_to_milestone,
 | 
				
			||||||
        check_apply_milestone_completion, milestone_complete, is_redeem_active)
 | 
					        milestone_complete, is_redeem_active)
 | 
				
			||||||
from tlapbot.owncast_helpers import use_points, read_users_points
 | 
					from tlapbot.owncast_helpers import use_points, read_users_points
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def handle_redeem(message, user_id):
 | 
					def handle_redeem(message: str, user_id: str) -> None:
 | 
				
			||||||
    split_message = message[1:].split(maxsplit=1)
 | 
					    split_message = message[1:].split(maxsplit=1)
 | 
				
			||||||
    redeem = split_message[0]
 | 
					    redeem = split_message[0]
 | 
				
			||||||
    if len(split_message) == 1:
 | 
					    if len(split_message) == 1:
 | 
				
			||||||
@ -25,6 +25,11 @@ def handle_redeem(message, user_id):
 | 
				
			|||||||
    redeem_type = current_app.config['REDEEMS'][redeem]["type"]
 | 
					    redeem_type = current_app.config['REDEEMS'][redeem]["type"]
 | 
				
			||||||
    points = read_users_points(db, user_id)
 | 
					    points = read_users_points(db, user_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if points is None:
 | 
				
			||||||
 | 
					        send_chat(f"Can't redeem {redeem}, failed to read users' points.")
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # handle milestone first because it doesn't have a price
 | 
					    # handle milestone first because it doesn't have a price
 | 
				
			||||||
    if redeem_type == "milestone":
 | 
					    if redeem_type == "milestone":
 | 
				
			||||||
        if milestone_complete(db, redeem):
 | 
					        if milestone_complete(db, redeem):
 | 
				
			||||||
@ -39,7 +44,7 @@ def handle_redeem(message, user_id):
 | 
				
			|||||||
            send_chat(f"Can't donate zero points.")
 | 
					            send_chat(f"Can't donate zero points.")
 | 
				
			||||||
        elif add_to_milestone(db, user_id, redeem, int(note)):
 | 
					        elif add_to_milestone(db, user_id, redeem, int(note)):
 | 
				
			||||||
            send_chat(f"Succesfully donated to {redeem} milestone!")
 | 
					            send_chat(f"Succesfully donated to {redeem} milestone!")
 | 
				
			||||||
            if check_apply_milestone_completion(db, redeem):
 | 
					            if milestone_complete(db, redeem):
 | 
				
			||||||
                send_chat(f"Milestone goal {redeem} complete!")
 | 
					                send_chat(f"Milestone goal {redeem} complete!")
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            send_chat(f"Redeeming milestone {redeem} failed.")
 | 
					            send_chat(f"Redeeming milestone {redeem} failed.")
 | 
				
			||||||
 | 
				
			|||||||
@ -12,8 +12,7 @@ CREATE TABLE milestones (
 | 
				
			|||||||
  id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
					  id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
				
			||||||
  name TEXT NOT NULL,
 | 
					  name TEXT NOT NULL,
 | 
				
			||||||
  progress INTEGER NOT NULL,
 | 
					  progress INTEGER NOT NULL,
 | 
				
			||||||
  goal INTEGER NOT NULL,
 | 
					  goal INTEGER NOT NULL
 | 
				
			||||||
  complete BOOLEAN NOT NULL
 | 
					 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TABLE counters (
 | 
					CREATE TABLE counters (
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ bp = Blueprint('redeem_dashboard', __name__)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bp.route('/dashboard', methods=['GET'])
 | 
					@bp.route('/dashboard', methods=['GET'])
 | 
				
			||||||
def dashboard():
 | 
					def dashboard() -> str:
 | 
				
			||||||
    db = get_db()
 | 
					    db = get_db()
 | 
				
			||||||
    username = request.args.get("username")
 | 
					    username = request.args.get("username")
 | 
				
			||||||
    if username is not None:
 | 
					    if username is not None:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								tlapbot/tlapbot_types.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tlapbot/tlapbot_types.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					from typing import Any, TypeAlias
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redeems: TypeAlias = dict[str, dict[str, Any]]
 | 
				
			||||||
 | 
					# at the moment the Any could be specialized to str | int | list[str]
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user