web_panels.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. from flask import flash, render_template, Blueprint, current_app, redirect, request, url_for, session, g
  2. from datetime import timezone
  3. from ownchatbot.db import get_db, reread_goals, reread_votes, rem_vote, reset_vote, reset_goal, clear_fulfilled_rewards, clear_reward_queue, rem_cool, rem_from_queue
  4. from ownchatbot.reward_handlers import all_active_votes, all_active_goals, all_active_rewards, get_queue, fulfill_reward, save_rewards, activate_category, deactivate_category, refund_reward, reread_categories, save_config
  5. from ownchatbot.user_handlers import get_all_users, get_all_users_by_name, refund_points, adjust_points, change_email, get_email_code, del_email_code
  6. from ownchatbot.bot_messages import save_announce
  7. from ownchatbot.owncast_com import send_private_chat
  8. import json
  9. import emoji
  10. from ownchatbot.kofi_handlers import save_kofi_settings, kofi_pngs
  11. import random
  12. ocb = Blueprint('web_panels', __name__)
  13. @ocb.route('/mgmt', methods=['GET']) # The streamer's management panel
  14. def mgmt():
  15. auth_code = request.args.get('auth')
  16. if auth_code == current_app.config['MGMT_AUTH']:
  17. session['auth_code'] = auth_code # Store auth code in session
  18. else:
  19. return "Not authorized", 403
  20. db = get_db()
  21. users = get_all_users(db)
  22. utc_timezone = timezone.utc
  23. rewards = current_app.config['REWARDS']
  24. active_rewards = []
  25. for each_reward in all_active_rewards(): # Get the name of all active rewards
  26. active_rewards.append(each_reward)
  27. active_categories = current_app.config['ACTIVE_CAT']
  28. inactive_categories = current_app.config['INACTIVE_CAT']
  29. all_cats = current_app.config['ALL_CAT']
  30. mgmt_auth = current_app.config['MGMT_AUTH']
  31. points_interval = current_app.config['POINTS_INTERVAL']
  32. points_award = current_app.config['POINTS_AWARD']
  33. gunicorn_logging = current_app.config['GUNICORN']
  34. prefix = current_app.config['PREFIX']
  35. access_token = current_app.config['ACCESS_TOKEN']
  36. owncast_url = current_app.config['OWNCAST_URL']
  37. kofi_token = current_app.config['KOFI_TOKEN']
  38. kofi_integration = current_app.config['KOFI_INTEGRATION']
  39. kofi_logos = kofi_pngs()
  40. announce_enable = current_app.config['ANNOUNCE_ENABLE']
  41. announce_interval = current_app.config['ANNOUNCE_INTERVAL']
  42. announcements = current_app.config['ANNOUNCEMENTS']
  43. settings_info = [
  44. mgmt_auth,
  45. points_interval,
  46. points_award,
  47. gunicorn_logging,
  48. prefix,
  49. access_token,
  50. owncast_url,
  51. kofi_token,
  52. kofi_integration,
  53. announce_enable,
  54. announce_interval
  55. ]
  56. return render_template('mgmt.html',
  57. queue=get_queue(db),
  58. votes=all_active_votes(db),
  59. goals=all_active_goals(db),
  60. rewards=rewards,
  61. active_rewards=active_rewards,
  62. prefix=current_app.config['PREFIX'],
  63. kofi_settings=current_app.config['KOFI_SETTINGS'],
  64. kofi_integration=kofi_integration,
  65. kofi_logos=kofi_logos,
  66. announcements=announcements,
  67. users=users,
  68. utc_timezone=utc_timezone,
  69. active_categories=active_categories,
  70. inactive_categories=inactive_categories,
  71. settings_info=settings_info)
  72. @ocb.route('/userpanel', methods=['GET']) # The viewers panel
  73. def user_panel():
  74. db = get_db()
  75. instance = request.args.get('instance')
  76. all_rewards = rewards = current_app.config['REWARDS']
  77. username = request.args.get('username')
  78. points_interval = current_app.config['POINTS_INTERVAL']
  79. points_award = current_app.config['POINTS_AWARD']
  80. if username is not None:
  81. users = get_all_users_by_name(db, username)
  82. else:
  83. users = []
  84. utc_timezone = timezone.utc
  85. return render_template('userpanel.html',
  86. queue=get_queue(db),
  87. votes=all_active_votes(db),
  88. goals=all_active_goals(db),
  89. rewards=all_active_rewards(),
  90. all_rewards=all_rewards,
  91. prefix=current_app.config['PREFIX'],
  92. kofi_settings=current_app.config['KOFI_SETTINGS'],
  93. kofi_integration=current_app.config['KOFI_INTEGRATION'],
  94. points_interval=points_interval,
  95. points_award=points_award,
  96. username=username,
  97. users=users,
  98. instance=instance,
  99. utc_timezone=utc_timezone)
  100. @ocb.route('/mgmt/fulfill', methods=['GET'])
  101. def fulfilled():
  102. db = get_db()
  103. reward_id = request.args.get('reward_id')
  104. username = request.args.get('username')
  105. fulfill_reward(db, reward_id)
  106. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  107. @ocb.route('/mgmt/refund', methods=['GET'])
  108. def refund():
  109. db = get_db()
  110. reward_id = request.args.get('reward_id')
  111. reward = request.args.get('reward')
  112. rewards = current_app.config['REWARDS']
  113. points = rewards[reward]['price']
  114. username = request.args.get('username')
  115. user_id = request.args.get('rewarder_id')
  116. refund_points(db, user_id, points) # resets points
  117. refund_reward(db, reward_id) # marks the reward as refunded
  118. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  119. @ocb.route('/mgmt/edit_account/<user_id>', methods=['GET', 'POST']) # Streamer manually edit user's account
  120. def edit_account(user_id):
  121. if 'auth_code' not in session:
  122. return "Not authorized", 403
  123. db = get_db()
  124. name = request.args.get('name')
  125. points = request.args.get('points')
  126. email = request.args.get('email')
  127. if request.method == 'POST':
  128. user_id = request.form['user_id']
  129. name = request.form['name']
  130. newpoints = request.form['newpoints']
  131. adjust_points(db, user_id, newpoints)
  132. newemail = request.form['newemail']
  133. if newemail == 'None':
  134. current_app.logger.info(f'No email change requested')
  135. else:
  136. if change_email(db, user_id, newemail):
  137. if newemail == '':
  138. current_app.logger.info(f'Removed {name}\'s email')
  139. else:
  140. current_app.logger.info(f'Changed {name}\'s email to {newemail}')
  141. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  142. return render_template('edit_account.html',
  143. name=name,
  144. user_id=user_id,
  145. points=points,
  146. email=email)
  147. @ocb.route('/mgmt/delete/<reward_name>', methods=['GET', 'POST'])
  148. def delete(reward_name):
  149. del_reward = current_app.config['REWARDS']
  150. del_reward.pop(reward_name)
  151. if save_rewards(del_reward):
  152. if rem_cool(reward_name):
  153. rem_from_queue(reward_name)
  154. if reread_votes():
  155. if reread_goals():
  156. pass
  157. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  158. @ocb.route('/mgmt/edit/<reward_name>', methods=['GET', 'POST'])
  159. def edit(reward_name):
  160. if 'auth_code' not in session:
  161. return "Not authorized", 403
  162. active_categories = current_app.config['ACTIVE_CAT']
  163. all_the_rewards = current_app.config['REWARDS']
  164. reward_data = all_the_rewards[reward_name]
  165. all_cats = current_app.config['ALL_CAT']
  166. if request.method == 'POST':
  167. reward_data['cooldown'] = int(request.form['cooldown'])
  168. reward_data['type'] = request.form['type']
  169. if reward_data['type'] == 'goal':
  170. reward_data['target'] = int(request.form['target'])
  171. if "milestones" not in reward_data: # If using old rewards.py, and no milestones key exists, create one
  172. reward_data["milestones"] = {"milestone1": [], "milestone2": [], "milestone3": []}
  173. if request.form['milestone1_points'] == '':
  174. reward_data['milestones']['milestone1'] = []
  175. else:
  176. milestone1_points = int(request.form['milestone1_points'])
  177. reward_data['milestones']['milestone1'] = [request.form['milestone1_desc'], milestone1_points]
  178. if request.form['milestone2_points'] == '':
  179. reward_data['milestones']['milestone2'] = []
  180. else:
  181. milestone2_points = int(request.form['milestone2_points'])
  182. reward_data['milestones']['milestone2'] = [request.form['milestone2_desc'], milestone2_points]
  183. if request.form['milestone3_points'] == '':
  184. reward_data['milestones']['milestone3'] = []
  185. else:
  186. milestone3_points = int(request.form['milestone3_points'])
  187. reward_data['milestones']['milestone3'] = [request.form['milestone3_desc'], milestone3_points]
  188. else:
  189. reward_data['price'] = int(request.form['price'])
  190. reward_data['info'] = emoji.demojize(request.form['info'])
  191. if reward_data['type'] == 'special':
  192. reward_data['cmd'] = request.form['cmd']
  193. reward_data['categories'] = request.form.getlist('category')
  194. reward_data['cooldown'] = int(request.form['cooldown'])
  195. all_the_rewards[reward_name] = reward_data
  196. save_rewards(all_the_rewards)
  197. if reward_data['type'] == 'goal': # Sync goals and votes in the db with rewards.py
  198. reread_goals()
  199. if reward_data['type'] == 'vote':
  200. reread_votes()
  201. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  202. return render_template('edit.html',
  203. all_cats=all_cats,
  204. reward_name=reward_name,
  205. active_categories=active_categories,
  206. reward_data=reward_data)
  207. @ocb.route('/mgmt/settings', methods=['GET', 'POST']) # OwnchatBot settings panel
  208. def settings():
  209. points_interval = int(request.form['points_interval'])
  210. points_award = int(request.form['points_award'])
  211. gunicorn_logging = 'gunicorn_logging' in request.form
  212. prefix = request.form['prefix']
  213. access_token = request.form['access_token']
  214. owncast_url = request.form['owncast_url']
  215. mgmt_auth = request.form['mgmt_auth']
  216. kofi_integration = 'kofi_integration' in request.form
  217. kofi_token = request.form['kofi_token']
  218. config_dict = {
  219. 'MGMT_AUTH': mgmt_auth,
  220. 'POINTS_INTERVAL': points_interval,
  221. 'POINTS_AWARD': points_award,
  222. 'GUNICORN': gunicorn_logging,
  223. 'PREFIX': prefix,
  224. 'ACCESS_TOKEN': access_token,
  225. 'OWNCAST_URL': owncast_url,
  226. 'KOFI_TOKEN': kofi_token,
  227. 'KOFI_INTEGRATION': kofi_integration
  228. }
  229. if save_config(config_dict): # Save new config.py
  230. current_app.logger.info('Saved new config.')
  231. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  232. @ocb.route('/mgmt/announcements', methods=['GET', 'POST']) # OwnchatBot settings panel
  233. def announcements():
  234. announce_enable = 'announce_enable' in request.form
  235. announce_interval = int(request.form['announce_interval'])
  236. new_announcements = []
  237. new_announcements = request.form['announcements'].strip().split('\n')
  238. announce_dict = {
  239. 'ANNOUNCEMENTS': new_announcements,
  240. 'ANNOUNCE_ENABLE': announce_enable,
  241. 'ANNOUNCE_INTERVAL': announce_interval
  242. }
  243. if save_announce(announce_dict): # Save new announce.py
  244. current_app.logger.info('Saved new announcements.')
  245. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  246. @ocb.route('/mgmt/ksettings', methods=['GET', 'POST']) # OwnchatBot settings panel
  247. def ksettings():
  248. kofi_settings_dict = current_app.config['KOFI_SETTINGS']
  249. if request.method == 'POST':
  250. enable_tips = 'enable_tips' in request.form
  251. set_tip_points = request.form['set_tip_points']
  252. kofi_url = request.form['kofi_url']
  253. kofi_logo = request.form.get('kofi_logo')
  254. kofi_settings_dict['tips'] = enable_tips
  255. kofi_settings_dict['tip_points'] = int(set_tip_points)
  256. kofi_settings_dict['kofi_url'] = kofi_url
  257. kofi_settings_dict['kofi_logo'] = kofi_logo
  258. if save_kofi_settings(kofi_settings_dict):
  259. current_app.logger.info(f'Saved Kofi settings')
  260. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  261. @ocb.route('/mgmt/add/<reward_type>', methods=['GET', 'POST'])
  262. def add(reward_type):
  263. if 'auth_code' not in session:
  264. return "Not authorized", 403
  265. all_cats = current_app.config['ALL_CAT']
  266. active_categories = current_app.config['ACTIVE_CAT']
  267. all_the_rewards = current_app.config['REWARDS']
  268. if request.method == 'POST':
  269. name = request.form['name']
  270. name = name.lower() # Force the name to all lower case
  271. name = emoji.demojize(name) # Remove any emojis
  272. name = name.replace(" ", "") # Remove any spaces from the name
  273. type = request.form['type']
  274. if name in all_the_rewards: # Check for duplicate reward names
  275. flash("A reward with this name already exists.", "error") # Flash an error message
  276. return redirect(url_for('web_panels.add', reward_type=reward_type)) # Redirect back to the add page
  277. if type != 'category': # If we're only adding a category, skip all of this
  278. cooldown = int(request.form['cooldown'])
  279. if type == 'redeem' or type == 'special' or type == 'vote':
  280. price = int(request.form['price'])
  281. if type == 'goal':
  282. target = int(request.form['target'])
  283. milestone1_desc = request.form['milestone1_desc']
  284. if request.form['milestone1_points'] == '':
  285. milestone1_points = ''
  286. else:
  287. milestone1_points = int(request.form['milestone1_points'])
  288. milestone2_desc = request.form['milestone2_desc']
  289. if request.form['milestone2_points'] == '':
  290. milestone2_points = ''
  291. else:
  292. milestone2_points = int(request.form['milestone2_points'])
  293. milestone3_desc = request.form['milestone3_desc']
  294. if request.form['milestone3_points'] == '':
  295. milestone3_points = ''
  296. else:
  297. milestone3_points = int(request.form['milestone3_points'])
  298. info = request.form['info']
  299. info = emoji.demojize(info) # Remove any emojis
  300. if type == 'special':
  301. cmd = request.form['cmd']
  302. categories = request.form.getlist('category')
  303. if type == 'redeem':
  304. if categories == ['']:
  305. all_the_rewards[name] = {'price': price, 'type': type, 'info': info, 'cooldown': cooldown}
  306. else:
  307. all_the_rewards[name] = {'price': price, 'type': type, 'info': info, 'categories': categories, 'cooldown': cooldown}
  308. if type == 'goal':
  309. if categories == ['']:
  310. all_the_rewards[name] = {'target': target, 'type': type, 'info': info, 'cooldown': cooldown}
  311. else:
  312. all_the_rewards[name] = {'target': target, 'type': type, 'info': info, 'categories': categories, 'cooldown': cooldown}
  313. all_the_rewards[name]["milestones"] = {"milestone1": [], "milestone2": [], "milestone3": []} # Create empty milestones key
  314. if milestone1_points:
  315. all_the_rewards[name]["milestones"]["milestone1"] = [milestone1_desc, milestone1_points]
  316. if milestone2_points:
  317. all_the_rewards[name]["milestones"]["milestone2"] = [milestone2_desc, milestone2_points]
  318. if milestone3_points:
  319. all_the_rewards[name]["milestones"]["milestone3"] = [milestone3_desc, milestone3_points]
  320. if type == 'vote':
  321. if categories == ['']:
  322. all_the_rewards[name] = {'price': price, 'type': type, 'info': info}
  323. else:
  324. all_the_rewards[name] = {'price': price, 'type': type, 'info': info, 'categories': categories, 'cooldown': cooldown}
  325. if type == 'special':
  326. if categories == ['']:
  327. all_the_rewards[name] = {'price': price, 'type': type, 'info': info, 'cmd': cmd, 'cooldown': cooldown}
  328. else:
  329. all_the_rewards[name] = {'price': price, 'type': type, 'info': info, 'cmd': cmd, 'categories': categories, 'cooldown': cooldown}
  330. save_rewards(all_the_rewards)
  331. if type == 'goal': # Remove old goals and votes from the database
  332. reread_goals()
  333. if type == 'vote':
  334. reread_votes()
  335. else: # If we're only adding a category
  336. inactive_categories = current_app.config['INACTIVE_CAT']
  337. inactive_categories.append(name) # Add it to the INACTIVE_CAT variable
  338. reread_categories() # Write it to categories.py
  339. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  340. return render_template('add.html',
  341. all_cats=all_cats,
  342. reward_type=reward_type,
  343. active_categories=active_categories)
  344. @ocb.route('/set_viewer_email', methods=['GET', 'POST'])
  345. def set_viewer_email():
  346. db = get_db()
  347. mail_reg_code = int(request.form['code'])
  348. user_id = request.form['user_id']
  349. db_mail_reg_code = get_email_code(db, user_id)
  350. new_email = request.form['new_email']
  351. instance = request.form['instance']
  352. user_name = request.form['user_name']
  353. if mail_reg_code == db_mail_reg_code:
  354. if change_email(db, user_id, new_email):
  355. del_email_code(db, user_id)
  356. flash(f"Email Address \"{new_email}\" successfully registered.", "success")
  357. send_private_chat(user_id, f'{user_name}, thanks for registering for Kofi perks! I appreciate your support!')
  358. current_app.logger.info(f'Changed {user_id}\'s email to {new_email}')
  359. else:
  360. flash(f"Incorrect code. Email Address \"{new_email}\" was not registered.", "failure")
  361. current_app.logger.info(f'The code entered, \"{mail_reg_code}\", does not match \"{db_mail_reg_code}\" found in database.')
  362. return redirect(url_for('web_panels.user_panel', instance=instance, username=user_name))
  363. @ocb.route('/mgmt/activate/<category>', methods=['GET', 'POST'])
  364. def activate(category):
  365. activate_category(category)
  366. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  367. @ocb.route('/mgmt/deactivate/<category>', methods=['GET', 'POST'])
  368. def deactivate(category):
  369. deactivate_category(category)
  370. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  371. @ocb.route('/mgmt/delcat/<cat_name>/<cat_act>', methods=['GET', 'POST'])
  372. def delcat(cat_name, cat_act):
  373. active_categories = current_app.config['ACTIVE_CAT']
  374. inactive_categories = current_app.config['INACTIVE_CAT']
  375. if cat_act == 'inactive':
  376. inactive_categories.remove(cat_name)
  377. else:
  378. active_categories.remove(cat_name)
  379. reread_categories()
  380. current_rewards = current_app.config['REWARDS']
  381. for reward, details in current_rewards.items(): # Remove from rewards.py as well
  382. if cat_name in details['categories']:
  383. details['categories'].remove(cat_name)
  384. save_rewards(current_rewards)
  385. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  386. @ocb.route('/mgmt/reset/<reward_name>/<reward_type>', methods=['GET', 'POST']) # Reset votes and goals to zero
  387. def reset(reward_name, reward_type):
  388. if reward_type == "goal":
  389. reset_goal(reward_name)
  390. if reward_type == "vote":
  391. reset_vote(reward_name)
  392. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  393. @ocb.route('/mgmt/rereadvotes', methods=['GET', 'POST'])
  394. def rereadv():
  395. reread_votes()
  396. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  397. @ocb.route('/mgmt/clearfulfilled', methods=['GET', 'POST'])
  398. def clearfulfilled():
  399. clear_fulfilled_rewards()
  400. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))
  401. @ocb.route('/mgmt/clearqueue', methods=['GET', 'POST'])
  402. def clear_queue():
  403. clear_reward_queue()
  404. return redirect(url_for('web_panels.mgmt', auth=session['auth_code']))