webhooks.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. from flask import Flask, request, json, Blueprint, current_app, render_template, jsonify, request, g
  2. from ownchatbot.db import get_db, clear_fulfilled_rewards
  3. from ownchatbot.owncast_com import send_chat, send_private_chat
  4. from ownchatbot.user_handlers import add_user_to_points, change_name, get_users_points, remove_duplicates, get_email_code, set_email_code, award_chat_points, user_in_points, get_all_users_with_user_id
  5. from ownchatbot.bot_messages import do_reward, help_message
  6. from ownchatbot.reward_handlers import all_active_goals, all_active_votes, all_active_rewards, save_alerts
  7. from ownchatbot.kofi_handlers import accept_donation, accept_sub
  8. import json
  9. import random
  10. ocb = Blueprint('webhooks', __name__)
  11. def format(rawjson): # Make data legible
  12. formatted_data = json.dumps(rawjson, indent=4)
  13. return formatted_data
  14. @ocb.route('/ocbHook', methods=['POST'])
  15. def chat_hook():
  16. prefix = current_app.config['PREFIX']
  17. data = request.json
  18. db = get_db()
  19. if data['type'] in ['CHAT', 'NAME_CHANGED', 'USER_JOINED']: # Check if the viewer is in the chatbot database
  20. user_id = data['eventData']['user']['id']
  21. authed = data['eventData']['user']['authenticated']
  22. display_name = data['eventData']['user']['displayName']
  23. if add_user_to_points(db, user_id, display_name, authed):
  24. current_app.logger.debug(f'Added/updated {user_id} database.')
  25. current_app.logger.debug(f'{display_name}/{user_id}: {data["eventData"]}') # Log all chat messages
  26. if data['type'] == 'STREAM_STARTED':
  27. if clear_fulfilled_rewards():
  28. current_app.logger.info('Cleared fulfilled rewards, since we\'re starting a new stream.')
  29. if data['type'] == 'USER_JOINED': # Do username house cleaning when a viewer joins
  30. if data['eventData']['user']['authenticated']:
  31. remove_duplicates(db, user_id, display_name)
  32. elif data['type'] == 'FEDIVERSE_ENGAGEMENT_FOLLOW':
  33. alerts_dict = current_app.config['ALERTS']
  34. data = request.json
  35. current_app.logger.debug(f'\n\n_______________\n/followHook triggered!\n_______________')
  36. alerts_dict['follower'] = data['eventData']['name']
  37. save_alerts(alerts_dict)
  38. return jsonify({'status': 'success'}), 200
  39. elif data['type'] == 'NAME_CHANGE':
  40. user_id = data['eventData']['user']['id']
  41. new_name = data['eventData']['newName']
  42. change_name(db, user_id, new_name)
  43. if data['eventData']['user']['authenticated']:
  44. remove_duplicates(db, user_id, new_name)
  45. elif data['type'] == 'CHAT': # If a chat message, sort out what command it is
  46. user_id = data['eventData']['user']['id']
  47. display_name = data['eventData']['user']['displayName']
  48. current_app.logger.info(f'{display_name}/{user_id}: {data["eventData"]["rawBody"]}') # Log all chat messages
  49. lowercase_msg = data['eventData']['rawBody'].lower() # Convert body to lower case to match reward case
  50. if lowercase_msg.startswith(f'{prefix}help'): # Send the help message
  51. help_message(user_id)
  52. elif lowercase_msg.startswith(f'{prefix}points'): # Get the viewer's current points
  53. points = get_users_points(db, user_id)
  54. if points is None:
  55. send_private_chat(user_id, f'{display_name}, couldn\'t get your points, for some highly technical reason.')
  56. else:
  57. send_private_chat(user_id, f'{display_name}, you have {points} points.')
  58. elif lowercase_msg.startswith(f'{prefix}reg_mail'): # Generate a code to verify users account for email registration
  59. if current_app.config['KOFI_INTEGRATION']:
  60. mail_reg_code = get_email_code(db, user_id)
  61. if mail_reg_code: # If the viewer already has a code waiting
  62. send_private_chat(user_id, f'{display_name}, your code is {mail_reg_code}. Enter it into the form on the Stream Rewards Info page, with your email address, to enable Kofi perks!')
  63. else: # if not
  64. mail_reg_code = random.randint(100000, 999999)
  65. if set_email_code(db, user_id, mail_reg_code):
  66. send_private_chat(user_id, f'{display_name}, your code is {mail_reg_code}. Enter it into the form on the Stream Rewards Info page, with your email address, to enable Kofi perks!')
  67. else:
  68. send_chat(f'{display_name}, Kofi integration is not enabled on this stream.')
  69. elif lowercase_msg.startswith(f'{prefix}rewards'): # Send rewards list
  70. if current_app.config['REWARDS']:
  71. rewards_msg = f'Currently active rewards:'
  72. for reward, details in current_app.config['REWARDS'].items():
  73. if details.get('categories'):
  74. if not (set(details['categories']) & set(current_app.config['ACTIVE_CAT'])): # If there are no common categories, continue
  75. continue
  76. if 'type' in details and details['type'] == 'goal':
  77. rewards_msg = f'{rewards_msg}<br>* {prefix}{reward} goal at {details["target"]} contributed points.'
  78. else:
  79. rewards_msg = f'{rewards_msg}<br>* {prefix}{reward} for {details["price"]} points.'
  80. if 'info' in details:
  81. rewards_msg = f'{rewards_msg}<br>{details["info"]}'
  82. else:
  83. rewards_msg = f'{rewards_msg}'
  84. else:
  85. rewards_msg = 'There are currently no active rewards.'
  86. send_private_chat(user_id, rewards_msg)
  87. elif lowercase_msg.startswith(f'{prefix}'): # Send to handle rewards
  88. do_reward(lowercase_msg, user_id)
  89. return data
  90. @ocb.route('/kofiHook', methods=["POST"])
  91. def kofi_hook():
  92. current_app.logger.info(f'----------------------------------------------------------------------------')
  93. current_app.logger.info(f'Kofi request')
  94. if request.content_type == 'application/x-www-form-urlencoded':
  95. raw_data = request.form.get('data') # Get the kofi data
  96. if raw_data:
  97. raw_data = json.loads(raw_data)
  98. is_authed = raw_data['verification_token']
  99. if is_authed == current_app.config['KOFI_TOKEN']:
  100. type = raw_data['type']
  101. is_public = raw_data['is_public']
  102. new_sub = raw_data['is_first_subscription_payment']
  103. message = raw_data['message']
  104. shop_items = raw_data['shop_items']
  105. from_name = raw_data['from_name']
  106. email = raw_data['email']
  107. amount = raw_data['amount']
  108. sub_payment = raw_data['is_subscription_payment']
  109. first_sub = raw_data['is_first_subscription_payment']
  110. tier_name = raw_data['tier_name']
  111. if type == 'Shop Order':
  112. current_app.logger.info(f'{from_name} purchased {format(shop_items)}\nMessage: {message}\n')
  113. if type == 'Donation':
  114. donation_info = [is_public, from_name, email, amount, message]
  115. donation_points = current_app.config['KOFI_SETTINGS']['donation_points']
  116. accept_donation(donation_info, donation_points)
  117. if is_public:
  118. alert_info = {'name': from_name, 'amount': amount}
  119. else:
  120. alert_info = {'name': 'Anonymous Hero', 'amount': amount}
  121. donations.append(alert_info) # Append info to be displayed in alert
  122. if type == 'Subscription':
  123. if current_app.config['KOFI_SETTINGS']['subs']: # Check that subscriptions are enabled
  124. if first_sub:
  125. if tier_name:
  126. current_app.logger.info(f'{from_name} <{email}> subscribed as a {tier_name} tier member.')
  127. else:
  128. current_app.logger.info(f'{from_name} <{email}> subscribed.')
  129. else:
  130. if tier_name:
  131. current_app.logger.info(f'{from_name} <{email}> renewed their {tier_name} tier membership.')
  132. else:
  133. current_app.logger.info(f'{from_name} <{email}> renewed their membership.')
  134. sub_info = [is_public, from_name, email, amount, message, first_sub, tier_name]
  135. sub_points = current_app.config['KOFI_SETTINGS']['sub_points']
  136. accept_sub(sub_info, sub_points)
  137. if is_public:
  138. alert_info = {'name': from_name, 'tiername': tier_name}
  139. else:
  140. alert_info = {'name': 'Anonymous Hero', 'teirname': tier_name}
  141. subscribers.append(alert_info) # Append info to be displayed in alert
  142. else:
  143. current_app.logger.info(f'Kofi membership received, but subscriptions are not enabled. Doing nothing.')
  144. return jsonify({'status': 'success'}), 200
  145. else:
  146. current_app.logger.info(f'Token invalid. Rejecting.')
  147. return jsonify({'status': 'unauthorized'}), 401
  148. @ocb.route('/checkFollows') # Polled by follower.html template to check for new followers
  149. def check_follows():
  150. alerts_dict = current_app.config['ALERTS']
  151. follower = {'name': alerts_dict['follower'], 'reward': 'New Follow!'}
  152. if follower['name']:
  153. current_app.logger.info(f'New follower: \"{follower["name"]}\"')
  154. alerts_dict['follower'] = ''
  155. save_alerts(alerts_dict)
  156. return jsonify(follower)
  157. else:
  158. current_app.logger.debug(f'No new followers')
  159. return jsonify(None)
  160. @ocb.route('/checkGoals') # Polled by ocbalert.html template to check for new followers
  161. def check_goals():
  162. alerts_dict = current_app.config['ALERTS']
  163. rgoals = {'name': alerts_dict['g_name'], 'reward': 'GOAL!!'}
  164. if rgoals['name']:
  165. current_app.logger.debug(rgoals)
  166. alerts_dict['g_name'] = ''
  167. alerts_dict['g_reward'] = ''
  168. save_alerts(alerts_dict)
  169. return jsonify(rgoals)
  170. else:
  171. current_app.logger.debug(f'No new goals reached')
  172. return jsonify(None)
  173. @ocb.route('/checkMilestones') # Polled by ocbalert.html template to check for new followers
  174. def check_milestones():
  175. alerts_dict = current_app.config['ALERTS']
  176. rmilestones = {'name': alerts_dict['m_name'], 'reward': 'Milestone!'}
  177. if rmilestones['name']:
  178. current_app.logger.info(rmilestones)
  179. alerts_dict['m_name'] = ''
  180. alerts_dict['m_reward'] = ''
  181. save_alerts(alerts_dict)
  182. return jsonify(rmilestones)
  183. else:
  184. current_app.logger.debug(f'No new milestones passed')
  185. return jsonify(None)