db.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. import sqlite3
  2. from flask import current_app, g
  3. from ownchatbot.reward_handlers import goal_reached, get_queue
  4. from flask.cli import with_appcontext
  5. import click
  6. from time import time
  7. def rem_from_queue(reward_name): # Remove a reward from the queue
  8. db = get_db()
  9. try:
  10. cursor = db.execute(
  11. "DELETE FROM reward_queue WHERE reward = ?", (reward_name,)
  12. )
  13. db.commit()
  14. except sqlite3.Error as rfqerror:
  15. print(f'Couldn\'t remove {reward_name} from reward queue: {rfqerror.args[0]}')
  16. return False
  17. return True
  18. def init_app(app):
  19. app.teardown_appcontext(close_db)
  20. app.cli.add_command(init_db_command)
  21. def get_db():
  22. if 'db' not in g:
  23. g.db = sqlite3.connect(
  24. current_app.config['DATABASE'],
  25. detect_types=sqlite3.PARSE_DECLTYPES
  26. )
  27. g.db.row_factory = sqlite3.Row
  28. return g.db
  29. def close_db(e=None):
  30. db = g.pop('db', None)
  31. if db is not None:
  32. db.close()
  33. def init_db(): # Setup the database. If it already exists, apply new schema
  34. db = get_db()
  35. with current_app.open_resource('schema.sql') as f: # Set up database
  36. db.executescript(f.read().decode('utf8'))
  37. reread_votes()
  38. reread_goals()
  39. if get_queue(db): # Make sure database is initialized
  40. return True
  41. @click.command('init-db')
  42. @with_appcontext
  43. def init_db_command(): # If there is already a database, clear it and do setup
  44. if init_db():
  45. click.echo('Database initialized.')
  46. def clear_reward_queue(): # Completely clear the reward queue
  47. db = get_db()
  48. try:
  49. cursor = db.execute(
  50. "DELETE FROM reward_queue"
  51. )
  52. cursor.execute(
  53. "UPDATE votes SET count = 0"
  54. )
  55. db.commit()
  56. except sqlite3.Error as serror:
  57. print(f'Couldn\'t clear reward queue: {serror.args[0]}')
  58. return False
  59. return True
  60. def clear_fulfilled_rewards(): # Clears only fulfilled rewards from the queue
  61. db = get_db()
  62. try:
  63. cursor = db.execute(
  64. "DELETE FROM reward_queue WHERE fulfilled = 1"
  65. )
  66. db.commit()
  67. except sqlite3.Error as serror:
  68. print(f'Couldn\'t clear fulfilled rewards: {serror.args[0]}')
  69. return False
  70. return True
  71. def rem_all_votes(): # USED TO BE "clear_votes" Clear all votes from the database
  72. db = get_db()
  73. try:
  74. db.execute("DELETE FROM votes")
  75. db.commit()
  76. except sqlite3.Error as cverror:
  77. print(f'Couldn\'t clear all votes: {cverror.args[0]}')
  78. return False
  79. if put_votes(db):
  80. return True
  81. def rem_vote(): # Remove a single vote from the database
  82. db = get_db(vote)
  83. try:
  84. db.execute("DELETE FROM votes WHERE name = ?", ('vote',))
  85. db.commit()
  86. except sqlite3.Error as rverror:
  87. print(f'Couldn\'t remove \"{vote}\" from database: {rverror.args[0]}')
  88. return False
  89. if put_votes(db):
  90. return True
  91. def is_cool(reward_name): # Check if a reward is cooling down.
  92. current_time = time() # In seconds
  93. rewards = current_app.config['REWARDS']
  94. this_cool_down = rewards[reward_name]['cooldown']
  95. if this_cool_down > 0: # If this reward has a cooldown
  96. try: # Get the cooldown time for it
  97. db = get_db()
  98. cursor = db.execute(
  99. "SELECT created FROM cool_downs WHERE reward = ?", (reward_name,)
  100. )
  101. current_cds = cursor.fetchall()
  102. except sqlite3.Error as icerror:
  103. print(f'Couldn\'t get \"{reward_name}\" from database: {icerror.args[0]}')
  104. if current_cds:
  105. last_time = current_cds[0][0]
  106. hot_time = current_time - last_time
  107. if hot_time < this_cool_down * 60: # If it is in the database and still within the cooldown time, return False
  108. hot_time = this_cool_down - (hot_time / 60) # Get remaining minutes in cooldown
  109. return False, hot_time # Return False, and the time left on the cooldown
  110. else: # If it is in the database and the cooldown has expired, update the cooldown time, and return True
  111. try:
  112. db.execute(
  113. "UPDATE cool_downs SET created = ? WHERE reward = ?",
  114. (current_time, reward_name)
  115. )
  116. db.commit()
  117. return True, 0
  118. except sqlite3.Error as scerror:
  119. print(f'Couldn\'t update \"{reward_name}\"\'s cooldown time in the database: {scerror.args[0]}')
  120. else: # If it is not in the database, add it and return True
  121. try:
  122. db.execute(
  123. "INSERT INTO cool_downs(created, reward) VALUES(?, ?)",
  124. (current_time, reward_name)
  125. )
  126. db.commit()
  127. return True, 0
  128. except sqlite3.Error as scerror:
  129. print(f'Couldn\'t add \"{reward_name}\" to database: {scerror.args[0]}')
  130. else: # If the redeem has no cooldown
  131. return True, 0
  132. def rem_cool(reward_name): # Remove a reward from the database
  133. try:
  134. db = get_db()
  135. cursor = db.execute(
  136. "DELETE FROM cool_downs WHERE reward = ?", (reward_name,)
  137. )
  138. current_cds = cursor.fetchall()
  139. except sqlite3.Error as icerror:
  140. print(f'Couldn\'t remove \"{reward_name}\" from database: {icerror.args[0]}')
  141. return False
  142. return True
  143. def put_votes(db): # Reread votes from rewards.py, and sync with database
  144. info = details['info']
  145. for reward, details in current_app.config['REWARDS'].items():
  146. if details['type'] == 'vote':
  147. try:
  148. db.execute(
  149. "INSERT INTO votes(name, count, info) VALUES(?, 0, ?)",
  150. (reward, info)
  151. )
  152. db.commit()
  153. except sqlite3.Error as serror:
  154. print(f'Couldn\'t insert \"{vote}\" into database: {serror.args[0]}')
  155. return False
  156. return True
  157. def reread_votes(): # Reread votes from rewards.py, and sync with database
  158. db = get_db()
  159. try: # Remove votes not in rewards.py
  160. cursor = db.execute("SELECT name FROM votes")
  161. votes = cursor.fetchall()
  162. chopping_block = []
  163. for vote in votes:
  164. vote = vote[0]
  165. if vote not in current_app.config['REWARDS'].keys():
  166. chopping_block.append(vote)
  167. elif current_app.config['REWARDS'][vote]['type'] != 'vote':
  168. chopping_block.append(vote)
  169. for vote in chopping_block:
  170. cursor.execute("DELETE FROM votes WHERE name = ?", (vote,))
  171. db.commit()
  172. except sqlite3.Error as serror:
  173. print(f'Couldn\'t clear deleted votes from database: {serror.args[0]}')
  174. return False
  175. try: # Add new votes found in rewards.py
  176. for reward, details in current_app.config['REWARDS'].items():
  177. if details['type'] == 'vote': # Check if the vote is already in the database
  178. cursor = db.execute(
  179. "SELECT count FROM votes WHERE name = ?",
  180. (reward,)
  181. )
  182. result = cursor.fetchone()
  183. if result is None: # If it isn't, add it
  184. info = details['info']
  185. if details['type'] == 'vote':
  186. db.execute(
  187. "INSERT INTO votes(name, count, info) VALUES(?, 0, ?)",
  188. (reward, details["info"])
  189. )
  190. else: # If it is, update the info
  191. cursor.execute(
  192. "UPDATE votes SET info = ? WHERE name = ?",
  193. (details['info'], reward)
  194. )
  195. db.commit()
  196. except sqlite3.Error as serror:
  197. print(f'Couldn\'t insert \"{vote}\" into database: {serror.args[0]}')
  198. return False
  199. return True
  200. def reread_goals(): # Reread goals from rewards.py, and sync with database
  201. db = get_db()
  202. try: # Remove goals not in rewards.py
  203. cursor = db.execute("SELECT name FROM goals")
  204. goals = cursor.fetchall()
  205. chopping_block = []
  206. for goal in goals:
  207. goal = goal[0]
  208. if goal not in current_app.config['REWARDS'].keys():
  209. chopping_block.append(goal)
  210. elif current_app.config['REWARDS'][goal]['type'] != 'goal':
  211. chopping_block.append(goal)
  212. for goal in chopping_block:
  213. cursor.execute("DELETE FROM goals WHERE name = ?", (goal,))
  214. db.commit()
  215. except sqlite3.Error as serror:
  216. print(f'Couldn\'t clear removed goals from database: {serror.args[0]}')
  217. return False
  218. try: # Add new goals found in rewards.py
  219. for reward, details in current_app.config['REWARDS'].items():
  220. if details['type'] == 'goal': # Check if the goal is already in the database
  221. cursor = db.execute(
  222. "SELECT target FROM goals WHERE name = ?",
  223. (reward,)
  224. )
  225. result = cursor.fetchone()
  226. if result is None: # If it isn't, add it
  227. cursor.execute(
  228. "INSERT INTO goals(name, progress, target, info, complete) VALUES(?, 0, ?, ?, FALSE)",
  229. (reward, details['target'], details['info'])
  230. )
  231. elif result != details['target']: # If it is, update the target
  232. cursor.execute(
  233. "UPDATE goals SET target = ?, info = ? WHERE name = ?",
  234. (details["target"], details["info"], reward)
  235. )
  236. db.commit()
  237. except sqlite3.Error as serror:
  238. print(f'Couldn\'t insert \"{reward}\" into database: {serror.args[0]}')
  239. return False
  240. return True
  241. def reset_goal(goal): # Set goal progress back to zero
  242. if goal not in current_app.config['REWARDS']: # If it doesn't exist in rewards.py
  243. print(f'Couldn\'t reset goal, {goal} not in rewards file.')
  244. return False
  245. try:
  246. db = get_db()
  247. target = current_app.config['REWARDS'][goal]['target']
  248. info = current_app.config['REWARDS'][goal]['info']
  249. cursor = db.cursor()
  250. cursor.execute(
  251. "UPDATE goals SET progress = 0, target = ?, complete = FALSE, info = ? WHERE name = ?",
  252. (target, info, goal)
  253. )
  254. db.commit()
  255. return True
  256. except sqlite3.Error as rgerror:
  257. current_app.logger.error(f'Couldn\'t reset {goal} in the goals table: {rgerror.args[0]}')
  258. return False
  259. def reset_vote(vote):
  260. if vote not in current_app.config['REWARDS']: # Check if it exists in rewards.py
  261. print(f'Couldn\'t reset vote, {vote} not in rewards file.')
  262. return False
  263. else:
  264. try:
  265. db = get_db()
  266. cursor = db.cursor()
  267. cursor.execute(
  268. "UPDATE votes SET count = 0, voters = '' WHERE name = ?",
  269. (vote,)
  270. )
  271. db.commit()
  272. except sqlite3.Error as rverror:
  273. current_app.logger.error(f'Couldn\'t reset {vote} in the votes table: {rverror.args[0]}')
  274. return False
  275. return True