123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- import os
- from flask import current_app
- from sqlite3 import Error
- from ownchatbot.user_handlers import spend_points
- import subprocess
- import json
- def check_vote(db, vote_name, user_id): # Check if user has already voted on this vote
- try:
- cursor = db.execute(
- "SELECT voters FROM votes WHERE name = ?",
- (vote_name,)
- )
- row = cursor.fetchone()
- if row is None:
- current_app.logger.warning(f'\"{vote_name}\" not found in vote table.')
- return False
- if row[0] == user_id:
- return True
- except Error as cverror:
- current_app.logger.error(f'Couldn\'t check if {user_id} already voted on \"{vote_name}\": {cverror.args[0]}')
- return False
- def add_to_vote(db, vote_name, user_id): # Add a count to a vote
- try: # Check if vote exists in the database
- cursor = db.execute(
- "SELECT count FROM votes WHERE name = ?",
- (vote_name,)
- )
- vote = cursor.fetchone()
- if vote is None:
- current_app.logger.warning(f'{vote_name} not found in vote table.')
- return False
- else: # If vote exists, add a count
- db.execute(
- "UPDATE votes SET count = count + 1, voters = ? WHERE name = ?",
- (user_id, vote_name,)
- )
- db.commit()
- return True
- except Error as terror:
- current_app.logger.error(f'Couldn\'t add to \"{vote_name}\" vote: {terror.args[0]}')
- return False
- def add_to_queue(db, user_id, reward_name): # Add a reward to the queue
- try:
- db.execute(
- "INSERT INTO reward_queue(reward, user_id, fulfilled, refunded) VALUES(?, ?, ?, ?)",
- (reward_name, user_id, 0, 0)
- )
- db.commit()
- return True
- except Error as qerror:
- current_app.logger.error(f'Couldn\'t add to reward \"{reward_name}\" for {user_id} queue: {qerror.args[0]}')
- return False
- def run_script(reward_name, script_cmd): # Run a script form a special reward
- try:
- subprocess.check_call(script_cmd, shell=True)
- except Exception as scerror:
- current_app.logger.error(f'Couldn\'t run script \"{reward_name}\": {scerror.args[0]}')
- return False
- return True
- def add_to_goal(db, user_id, reward_name, points_contributed): # Add a contribution to a goal
- try:
- cursor = db.execute(
- "SELECT progress, target FROM goals WHERE name = ?",
- (reward_name,)
- )
- row = cursor.fetchone()
- if row is None:
- current_app.logger.warning(f'\"{reward_name}\" not found in goal table.')
- return False
- progress, target = row
- if progress + points_contributed > target:
- points_contributed = target - progress
- if points_contributed < 0:
- points_contributed = 0
- if spend_points(db, user_id, points_contributed):
- cursor = db.execute(
- "UPDATE goals SET progress = ? WHERE name = ?",
- (progress + points_contributed, reward_name)
- )
- db.commit()
- return True
- except Error as gerror:
- current_app.logger.error(f'Couldn\'t update goal: {gerror.args[0]}')
- return False
- def goal_left(db, reward_name):
- try:
- cursor = db.execute(
- "SELECT progress, target FROM goals WHERE name = ?",
- (reward_name,)
- )
- row = cursor.fetchone()
- if row is None:
- current_app.logger.warning(f'{reward_name} not found in Goal table.')
- else:
- progress, target = row
- left = target - progress
- return left
- except Error as glerror:
- current_app.logger.error(f'Couldn\'t check progress for \"{reward_name}\" goal: {glerror.args[0]}')
- def goal_reached(db, reward_name): # Set a goal as completed
- try:
- cursor = db.execute(
- "SELECT complete FROM goals WHERE name = ?",
- (reward_name,)
- )
- row = cursor.fetchone()
- if row is None:
- current_app.logger.warning(f'{reward_name} not found in goal table.')
- else:
- return row[0]
- except Error as grerror:
- current_app.logger.error(f'Couldn\'t check if goal was met: {grerror.args[0]}')
- def was_goal_reached(db, reward_name): # Check if a goal was reached
- try:
- cursor = db.execute(
- "SELECT progress, target FROM goals WHERE name = ?",
- (reward_name,)
- )
- row = cursor.fetchone()
- if row is None:
- current_app.logger.warning(f'{reward_name} not found in Goal table.')
- else:
- progress, target = row
- if progress == target:
- cursor = db.execute(
- "UPDATE goals SET complete = TRUE WHERE name = ?",
- (reward_name,)
- )
- db.commit()
- return True
- return False
- except Error as wgrerror:
- current_app.logger.error(f'Couldn\'t mark goal met: {wgrerror.args[0]}')
- return False
- def all_votes(db): # Get all the votes
- try:
- cursor = db.execute(
- "SELECT votes.name, votes.count, votes.info FROM votes"
- )
- return cursor.fetchall()
- except Error as aterror:
- current_app.logger.error(f'Couldn\'t select all votes: {aterror.args[0]}')
- def refund_reward(db, reward_id): # Refund a user for a particular reward
- reward_id = reward_id
- try:
- cursor = db.execute(
- "UPDATE reward_queue SET refunded = 1 WHERE id = ?",
- (reward_id,)
- )
- db.commit()
- except Error as rferror:
- current_app.logger.error(f'Couldn\'t refund reward id {reward_id}: {rferror.args[0]}')
- return False
- def fulfill_reward(db, reward_id): # Mark a reward as fulfilled in the database
- reward_id = reward_id
- try:
- cursor = db.execute(
- "UPDATE reward_queue SET fulfilled = 1 WHERE id = ?",
- (reward_id,)
- )
- db.commit()
- except Error as frerror:
- current_app.logger.error(f'Couldn\'t fulfill reward id {reward_id}: {frerror.args[0]}')
- return False
- def all_active_votes(db): # Get only active votes
- votes = all_votes(db)
- all_active_votes = []
- for name, count, info in votes:
- if is_reward_active(name):
- all_active_votes.append((name, count, info))
- return all_active_votes
- def all_goals(db): # Get all the goals
- try:
- cursor = db.execute(
- """SELECT name, progress, target, info FROM goals"""
- )
- return cursor.fetchall()
- except Error as agerror:
- current_app.logger.error(f'Couldn\'t select all goals: {agerror.args[0]}')
- def all_active_goals(db): # Get only active goals
- goals = all_goals(db)
- all_active_goals = []
- for name, progress, target, info in goals:
- if is_reward_active(name):
- all_active_goals.append((name, progress, target, info))
- return all_active_goals
- def all_active_rewards(): # Get only active rewards
- rewards = current_app.config['REWARDS']
- all_active_rewards = {}
- for reward_name, reward_dict in rewards.items():
- if reward_dict.get('categories'): # If reward has empty categories list
- for category in reward_dict['categories']: # Compare each category to ACTIVE_CAT list
- if category in current_app.config['ACTIVE_CAT']:
- all_active_rewards[reward_name] = reward_dict
- break
- return all_active_rewards
- def save_rewards(reward_info): # Write rewards to rewards.py
- new_rewards = json.dumps(reward_info, indent=4)
- rewards_file = os.path.join(current_app.instance_path, 'rewards.py')
- try:
- with open(rewards_file, 'w') as f:
- f.write(f'REWARDS = {new_rewards}')
- f.close
- except Exception as srerror:
- current_app.logger.error(f'Couldn\'t save rewards.py: {serror.args[0]}')
- return False
- return True
- def save_config(config_dict): # Write settings to config.py
- settings_file = os.path.join(current_app.instance_path, 'config.py')
- secret_key = current_app.config['SECRET_KEY']
- new_settings = f"# Owncast stuff. Needed to interact with your Owncast instance\n\
- ACCESS_TOKEN = '{config_dict['ACCESS_TOKEN']}'\n\
- OWNCAST_URL = '{config_dict['OWNCAST_URL']}'\n\
- \n\
- # OwnchatBot Configuration \n\
- SECRET_KEY = '{secret_key}' # Needed for internal Flask stuff. DO NOT DELETE.\n\
- POINTS_INTERVAL = {config_dict['POINTS_INTERVAL']} # How long, in seconds, between points awards\n\
- POINTS_AWARD = {config_dict['POINTS_AWARD']} # How many points awarded each interval?\n\
- GUNICORN = {config_dict['GUNICORN']} # Integrate OwnchatBot logging into Gunicorn\n\
- PREFIX = '{config_dict['PREFIX']}' # Preceeds commands, so OwnchatBot knows what is a command\n\
- MGMT_AUTH = '{config_dict['MGMT_AUTH']}' # Needed to access the OwnchatBot management panel. See README.md for more details.\n"
-
- with open(settings_file, 'w') as f:
- f.write(new_settings)
- f.close
- current_app.config.from_pyfile('config.py', silent=True) # Reread config.py into the app
- def reread_categories(): # Read _CAT varaibles and write to categories.py
- categories_file = os.path.join(current_app.instance_path, 'categories.py')
- active_categories = current_app.config['ACTIVE_CAT']
- inactive_categories = current_app.config['INACTIVE_CAT']
- try:
- with open(categories_file, 'r', encoding='utf-8') as f: # Read categories.py, and set up lines to change
- category_data = f.readlines()
- category_data[0] = f'ACTIVE_CAT = {active_categories}\n'
- category_data[1] = f'INACTIVE_CAT = {inactive_categories}\n'
- f.close
- with open(categories_file, 'w', encoding='utf-8') as f: # Write changes to categories.py
- f.writelines(category_data)
- f.close
- current_app.config.from_pyfile('categories.py', silent=True) # Reread categories into the app
- except Error as rcerror:
- current_app.logger.error(f'Couldn\'t reread categories: {rcerror.args[0]}')
- def activate_category(category): # Move an item from the ACTIVE_CAT list to the INACTIVE_CAT list
- try:
- categories_file = os.path.join(current_app.instance_path, 'categories.py')
- active_categories = current_app.config['ACTIVE_CAT']
- inactive_categories = current_app.config['INACTIVE_CAT']
- active_categories.append(category) # Add to ACTIVE_CAT
- inactive_categories.remove(category) # Remove from INACTIVE_CAT
- reread_categories()
- except Error as acerror:
- current_app.logger.error(f'Couldn\'t activate {category}: {acerror.args[0]}')
- def deactivate_category(category): # Move an item from the INACTIVE_CAT list to the ACTIVE_CAT list
- try:
- categories_file = os.path.join(current_app.instance_path, 'categories.py')
- active_categories = current_app.config['ACTIVE_CAT']
- inactive_categories = current_app.config['INACTIVE_CAT']
- active_categories.remove(category) # Remove from ACTIVE_CAT
- inactive_categories.append(category) # Add to INACTIVE_CAT
- reread_categories()
- except Error as dcerror:
- current_app.logger.error(f'Couldn\'t deactivate {category}: {dcerror.args[0]}')
- def get_queue(db): # Get the reward queue and the username
- try:
- cursor = db.execute(
- """SELECT reward_queue.id, reward_queue.created, reward_queue.reward, reward_queue.user_id, reward_queue.fulfilled, reward_queue.refunded, points.name
- FROM reward_queue
- INNER JOIN points
- on reward_queue.user_id = points.id"""
- )
- return cursor.fetchall()
- except Error as gqerror:
- current_app.logger.error(f'Couldn\'t get queue: {gqerror.args[0]}')
- def is_reward_active(reward_name): # Check if reward is active
- active_categories = current_app.config['ACTIVE_CAT']
- reward_dict = current_app.config['REWARDS'].get(reward_name, None)
- try:
- if reward_dict:
- if 'categories' in reward_dict: # Is there a categories key at all?
- for category in reward_dict['categories']: # Cycle through categories and compare to active_categories
- if category in active_categories:
- return True
- return False
- elif reward_dict['categories'] == []: # If categories key is there but empty, return False
- return False
- else:
- return True
- return None
- except Error as iraerror:
- current_app.logger.error(f'Couldn\'t check if {reward_name} is active: {iraerror.args[0]}')
|