bot.rb 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. require 'bundler'
  2. require 'erb'
  3. require 'yaml'
  4. require 'json'
  5. require 'terminal-table'
  6. require 'rmagick'
  7. require 'down'
  8. BOT_ENV = ENV.fetch('BOT_ENV') { 'development' }
  9. Bundler.require(:default, BOT_ENV)
  10. require 'active_record'
  11. # Constants: such as roles and colors and regexes
  12. DISCORD = "#36393f"
  13. ERROR = "#a41e1f"
  14. UID = /<@\!?([0-9]+)>/
  15. URL = /https?:\/\/[\S]+/
  16. # ---
  17. Dotenv.load if BOT_ENV != 'production'
  18. db_yml = File.open('config/database.yml') do |erb|
  19. ERB.new(erb.read).result
  20. end
  21. db_config = YAML.safe_load(db_yml)[BOT_ENV]
  22. ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
  23. ActiveRecord::Base.establish_connection(
  24. adapter: 'postgresql',
  25. host: db_config.fetch('host') { 'localhost' },
  26. database: db_config['database'],
  27. user: db_config['user'],
  28. password: db_config['password']
  29. )
  30. Dir['app/**/*.rb'].each { |f| require File.join(File.expand_path(__dir__), f) }
  31. Dir['./lib/*.rb'].each { |f| require f }
  32. token = ENV['DISCORD_BOT_TOKEN']
  33. bot = Discordrb::Bot.new(token: token)
  34. #--
  35. # This will trigger on every message sent in discord
  36. bot.message do |event|
  37. # Break if not in a server.. for some reason pms trigger here
  38. break if event.server.nil?
  39. # Save the message contents, and author
  40. content = event.message.content
  41. author = event.author
  42. # Attempt to match a command
  43. cmd = /^pkmn-(\w+)/.match(content)
  44. # Check for a standard command
  45. if cmd
  46. # Search for the corresponding command
  47. commands = BaseCommand.descendants.filter{ |bc| bc.restricted_to == nil }
  48. command = commands.detect{ |c| c.name == cmd[1].downcase.to_sym }
  49. # Call the command, and reply with its results
  50. reply = command&.call(content, event)
  51. BotController.reply(bot, event, reply)
  52. # Check for a form that needs to be reacted to
  53. elsif author.id == ENV['WEBHOOK'].to_i
  54. # Save the app, and check app if character
  55. app = event.message.embeds.first
  56. er = CharacterController.check_user(event) if app.author.name == 'Character Application'
  57. case er
  58. when true, nil
  59. BotController.application_react(event)
  60. when false
  61. BotController.unauthorized_char_app(bot, event, member)
  62. end
  63. # Check for a clear command
  64. elsif ENV['CLEAR_CH'].include?(event.channel.id.to_s) && content.match(/^clear\schat$/i)
  65. msgs = event.channel.history(50).reject{ |m| m.author.webhook? }
  66. event.channel.delete_messages(msgs)
  67. # Check for no exp channels
  68. elsif ENV['NO_EXP_CH'].include?(event.channel.id.to_s)
  69. # Do nothing
  70. # Apply experience to non-bot users
  71. elsif !author.bot_account? && !author.webhook?
  72. # Replace any urls with 150 'x' chars
  73. message = URL.match(content) ? content.gsub(URL, "x" * 150) : content
  74. # Add 40 to the message length if there's a file
  75. msg_length = event.message.attachments.map(&:filename).count > 0 ?
  76. 40 + message.length : message.length
  77. if msg_length >= 40
  78. # Wait until now to find user, so DB isn't touched for every message
  79. user = User.find(author.id)
  80. # Update User and reply with image, if there is one
  81. reply = user.update_xp(msg_length, author)
  82. bot.send_file(event.channel.id, File.open(reply, 'r')) if reply
  83. end
  84. end
  85. end
  86. # This will trigger when a dm is sent to the bot from a user
  87. bot.pm do |event|
  88. # Save the message contents
  89. content = event.message.content
  90. # Attempt to match a command
  91. cmd = /^pkmn-(\w+)/.match(content)
  92. # Check for a standard command
  93. if cmd
  94. # Search for the corresponding command
  95. commands = BaseCommand.descendants.filter{ |bc| bc.restricted_to == :pm }
  96. command = commands.detect{ |c| c.name == cmd[1].downcase.to_sym }
  97. # Call the command, and reply with its results
  98. reply = command&.call(content, event)
  99. BotController.reply(bot, event, reply)
  100. end
  101. end
  102. # This will trigger when any reaction is added in discord
  103. bot.reaction_add do |event|
  104. app_form = event.message.embeds.first
  105. if Team.find_by(channel: event.channel.id)
  106. reactions = event.message.reactions
  107. event.message.pin if reactions[Emoji::PIN]&.count.to_i > 0
  108. end
  109. # Only do logic if this is an embed
  110. break unless app_form
  111. # Find the appropriate app type, and process
  112. app = ApplicationForm.descendants.detect{ |af| af.name == app_form.author&.name }
  113. carousel = Carousel.find_by(message_id: event.message.id)
  114. reply = if app then app&.call(event)
  115. elsif carousel then carousel.navigate(event)
  116. end
  117. if reply
  118. BotController.reply(bot, event, reply)
  119. #elsif event.message&.reactions[Emoji::CROSS]&.count
  120. #crosses = event.message.reacted_with(Emoji::CROSS)
  121. #crosses.each do |cross|
  122. #member = event.server.member(cross.id)
  123. #event.message.delete unless member.current_bot?
  124. #end
  125. end
  126. end
  127. # This will trigger when any reaction is removed in discord
  128. bot.reaction_remove do |event|
  129. end
  130. # This will trigger when a member is updated
  131. bot.member_update do |event|
  132. end
  133. # This will trigger when anyone joins the server
  134. bot.member_join do |event|
  135. unless User.find_by(id: event.user.id)
  136. usr = User.create(id: event.user.id)
  137. usr.make_stats
  138. end
  139. end
  140. # This will trigger when anyone leaves the server
  141. bot.member_leave do |event|
  142. updated = []
  143. fields = []
  144. chars = Character.where(user_id: event.user.id)
  145. roles = event.roles
  146. roles = roles.map{ |r| "<@#{r}>" } if roles
  147. chars.each do |char|
  148. unless char.active == 'NPC'
  149. char.update(active: 'Deleted')
  150. char.reload
  151. end
  152. ct = CharTeam.find_by(char_id: char.id)
  153. ct.update(active: false) if ct
  154. t = Team.find(ct.team_id) if ct
  155. bot.send_message(t.channel, "#{char.name} has left the server", false, nil) if t
  156. updated.push("#{char.name}, #{t.name} -- #{char.active}") if t
  157. updated.push("#{char.name}, no team data -- #{char.active}") if t.nil?
  158. end
  159. fields.push({
  160. name: "```Flagging Guild Members......```",
  161. value: updated.join("\n")
  162. }) unless updated.empty?
  163. fields.push({
  164. name: "User's Roles",
  165. value: roles.join(", ")
  166. }) unless roles.empty?
  167. embed = Embed.new(
  168. title: "I've lost track of a user!",
  169. description: "It seems #{event.member.mention}, (#{event.user.username}) has left the server!",
  170. fields: fields
  171. )
  172. # production channel
  173. bot.send_message(588464466048581632, "", false, embed)
  174. # development channel
  175. #bot.send_message(594244240020865035, "", false, embed)
  176. end
  177. # This will trigger when anyone is banned from the server
  178. bot.user_ban do |event|
  179. updated = []
  180. fields = []
  181. chars = Character.where(user_id: event.user.id)
  182. roles = event.roles
  183. roles = roles.map{ |r| "<@#{r}>" } if roles
  184. chars.each do |char|
  185. unless char.active == 'NPC'
  186. char.update(active: 'Deleted')
  187. char.reload
  188. end
  189. ct = CharTeam.find_by(char_id: char.id)
  190. ct.update(active: false) if ct
  191. t = Team.find(ct.team_id) if ct
  192. updated.push("#{char.name}, #{t.name} -- #{char.active}") if t
  193. updated.push("#{char.name}, no team data -- #{char.active}") if t.nil?
  194. end
  195. fields.push({
  196. name: "```Flagging Guild Members......```",
  197. value: updated.join("\n")
  198. }) unless updated.empty?
  199. fields.push({
  200. name: "User's Roles",
  201. value: roles.join(", ")
  202. }) unless roles.empty?
  203. embed = Embed.new(
  204. title: "A User was forced to leave!",
  205. description: "It seems #{event.member.mention}, (#{event.user.username}) has been banned from the server!",
  206. fields: fields
  207. )
  208. # production channel
  209. bot.send_message(588464466048581632, "", false, embed)
  210. end
  211. # This will trigger when anyone is un-banned from the server
  212. bot.user_unban do |event|
  213. end
  214. bot.run