bot.rb 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. require 'bundler'
  2. require 'erb'
  3. require 'yaml'
  4. require 'json'
  5. require 'terminal-table'
  6. BOT_ENV = ENV.fetch('BOT_ENV') { 'development' }
  7. Bundler.require(:default, BOT_ENV)
  8. require 'active_record'
  9. # Constants: such as roles and channel ids
  10. # Users
  11. APP_BOT = 627702340018896896
  12. # Roles
  13. ADMINS = 308250685554556930
  14. # Channels
  15. CHAR_CHANNEL = 594244240020865035
  16. # Images
  17. HAP_ROTOM = "https://static.pokemonpets.com/images/monsters-images-800-800/479-Rotom.png"
  18. # URLs
  19. APP_FORM = "https://docs.google.com/forms/d/e/1FAIpQLSfryXixX3aKBNQxZT8xOfWzuF02emkJbqJ1mbMGxZkwCvsjyA/viewform"
  20. # ---
  21. Dotenv.load if BOT_ENV != 'production'
  22. db_yml = File.open('config/database.yml') do |erb|
  23. ERB.new(erb.read).result
  24. end
  25. db_config = YAML.safe_load(db_yml)[BOT_ENV]
  26. ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
  27. ActiveRecord::Base.establish_connection(
  28. adapter: 'postgresql',
  29. host: db_config.fetch('host') { 'localhost' },
  30. database: db_config['database'],
  31. user: db_config['user'],
  32. password: db_config['password']
  33. )
  34. Dir['app/**/*.rb'].each { |f| require File.join(File.expand_path(__dir__), f) }
  35. Dir["/lib/*.rb"].each {|file| require file }
  36. token = ENV['DISCORD_BOT_TOKEN']
  37. bot = Discordrb::Bot.new(token: token)
  38. # Methods: define basic methods here
  39. def check_user(event)
  40. content = event.message.content
  41. edit_url = /Edit\sKey\s\(ignore\):\s([\s\S]*)/.match(content)
  42. if user_id = (/<@([0-9]+)>/.match(content))
  43. user = User.find_by(id: user_id[1])
  44. allowed_characters = (user.level / 10 + 1)
  45. characters = Character.where(user_id: user_id[1]).count
  46. if characters < allowed_characters && characters < 6
  47. event.message.react(Emoji::Y)
  48. event.message.react(Emoji::N)
  49. else
  50. event.server.member(user_id[1]).dm("You have too many characters!\nPlease deactivate and try again #{edit_url[1]}")
  51. event.message.delete
  52. end
  53. else
  54. event.message.edit("#{content}\n\nI don't know this user!")
  55. end
  56. end
  57. def edit_character(message, member)
  58. params = message.split("\n")
  59. char_hash = Character.from_form(params)
  60. image_url = /\*\*URL to the Character\'s Appearance\*\*\:\s(.*)/.match(message)
  61. if char = Character.find_by(edit_url: char_hash["edit_url"])
  62. char.update!(char_hash)
  63. character = Character.find_by(edit_url: char_hash["edit_url"])
  64. else
  65. character = Character.create(char_hash)
  66. end
  67. edit_images(image_url[1], character.id, 'sfw', 'primary') if image_url[1]
  68. character_embed(character, image_url[1], member)
  69. end
  70. def edit_images(image_url, character_id, category, keyword)
  71. unless CharImages.where(char_id: character_id).find_by(url: image_url)
  72. CharImages.create(char_id: character_id, url: image_url, category: category, keyword: keyword)
  73. end
  74. end
  75. # ---
  76. # Commands: structure basic bot commands here
  77. hello = Command.new(:hello) do |event|
  78. user = event.author.nickname || event.author.name
  79. greetings = [
  80. "Hi there, #{user}",
  81. "Greetings #{user}, you lovable bum",
  82. "Alola, #{user}",
  83. "Hello, #{user}! The Guildmasters have been waiting",
  84. "#{user} would like to battle!"
  85. ]
  86. Embed.new(
  87. description: greetings.sample,
  88. color: event.author.color.combined,
  89. thumbnail: {
  90. url: HAP_ROTOM
  91. }
  92. )
  93. end
  94. matchup = Command.new(:matchup) do |event, type|
  95. channel = event.channel.id
  96. file = "images/Type #{type.capitalize}.png"
  97. if File.exists?(file)
  98. bot.send_file(channel, File.open(file, 'r'))
  99. else
  100. bot.respond("I do not know this pokemon type! Please try again!")
  101. end
  102. end
  103. app = Command.new(:app) do |event, name|
  104. user = event.author
  105. if name
  106. if character = Character.where(user_id: user.id).find_by(name: name)
  107. edit_url = APP_FORM + character.edit_url
  108. event.respond("OK, #{user.name}! I'll send you what you need to edit #{name}")
  109. user.dm("You may edit #{name} here:\n#{edit_url}")
  110. else
  111. event.respond("I didn't find your character, #{name}\nIf you want to start a new app, please use `pkmn-app`")
  112. end
  113. else
  114. event.respond("You want to start a new character application?\nGreat! I'll dm you instructions")
  115. user.dm("Hi, #{user.name}\nYou can start your application here:\n#{APP_FORM}\n\nYour key is: #{user.id}\nOnce complete, your application will submitted to the admins for approval!")
  116. end
  117. end
  118. # ---
  119. commands = [
  120. hello,
  121. matchup,
  122. app
  123. ]
  124. # This will trigger on every message sent in discord
  125. bot.message do |event|
  126. content = event.message.content
  127. if (match = /^pkmn-(\w+)/.match(content))
  128. command = match[1]
  129. if cmd = commands.detect { |c| c.name == command.to_sym }
  130. reply = cmd.call(content, event)
  131. if reply.is_a? Embed
  132. event.send_embed("", reply)
  133. elsif reply
  134. event.respond(reply)
  135. else
  136. event.respond("Something went wrong!")
  137. end
  138. end
  139. end
  140. if event.author.id == APP_BOT
  141. check_user(event)
  142. end
  143. end
  144. # This will trigger on every reaction is added in discord
  145. bot.reaction_add do |event|
  146. content = event.message.content
  147. if event.message.author.id == APP_BOT
  148. maj = event.server.roles.find{ |r| r.id == ADMINS }.members.count / 2
  149. maj = 1
  150. if event.message.reacted_with(Emoji::Y).count > maj
  151. uid = /<@([0-9]+)>/.match(content)
  152. member = event.server.member(uid[1])
  153. embed = edit_character(content, member)
  154. if embed
  155. event.message.delete
  156. bot.send_message(
  157. CHAR_CHANNEL,
  158. "Character Approved!",
  159. false,
  160. embed
  161. )
  162. else
  163. event.respond("Something went wrong")
  164. end
  165. elsif event.message.reacted_with(Emoji::N).count > maj
  166. message = event.message.content
  167. split_message = message.split("\n")
  168. i = 0
  169. split_message.each do |row|
  170. if row.match(/\*\*/)
  171. if row.match(/>>>/)
  172. row.insert 5, "#{Emoji::ALL[i]} "
  173. i += 1
  174. else
  175. row.insert 0, "#{Emoji::ALL[i]} "
  176. i += 1
  177. end
  178. end
  179. end
  180. edited_message = split_message.join("\n")
  181. new_message = "**_APPLICATION REJECTED!!_**\n--------------\n\n#{edited_message}\n\n\nPlease indicate what needs to be updated with the corresponding reactions!\nWhen you're done hit #{Emoji::CHECK}, or to dismiss hit #{Emoji::CROSS}"
  182. event.message.delete
  183. rejected = event.respond(new_message)
  184. j = 0
  185. i.times do
  186. rejected.react(Emoji::ALL[j])
  187. j += 1
  188. end
  189. rejected.react(Emoji::CHECK)
  190. rejected.react(Emoji::CROSS)
  191. end
  192. end
  193. if event.message.from_bot? && content.match(/\*\*\_APPLICATION\sREJECTED\!\!\_\*\*/)
  194. if event.message.reacted_with(Emoji::CHECK).count > 1
  195. reactions = event.message.reactions
  196. edit_url = /Edit\sKey\s\(ignore\):\s([\s\S]*)/.match(content)
  197. user_id = /<@([0-9]+)>/.match(content)
  198. member = event.server.member(user_id[1])
  199. message = "Your application has been rejected!\nPlease fix the following lines, and resubmit here:\n#{APP_FORM}#{edit_url[1]}"
  200. rows = reactions.count - 2
  201. i = 0
  202. rows.times do
  203. if reactions[Emoji::ALL[i]].count > 1
  204. row = /#{Emoji::ALL[i]}\s(.*)/.match(content)
  205. message += "\n> #{row[1]}"
  206. end
  207. i += 1
  208. end
  209. temp_message = "Your application has been rejected!\nPlease fix the following lines, and resubmit here:\n[users url goes here]"
  210. message = "Your application has been rejected!\nPlease fix the following lines, and resubmit here:\n#{APP_FORM}#{edit_url[1]}"
  211. event.message.delete
  212. event.send_temporary_message(temp_message, 15)
  213. member.dm(message)
  214. elsif event.message.reacted_with(Emoji::CROSS).count > 1
  215. event.message.delete
  216. end
  217. end
  218. end
  219. # This will trigger on every reaction is removed in discord
  220. bot.reaction_remove do |event|
  221. end
  222. # This will trigger when a member is updated
  223. bot.member_update do |event|
  224. end
  225. # This will trigger when anyone joins the server
  226. bot.member_join do |event|
  227. end
  228. # This will trigger when anyone leaves the server
  229. bot.member_leave do |event|
  230. end
  231. # This will trigger when anyone is banned from the server
  232. bot.user_ban do |event|
  233. end
  234. # This will trigger when anyone is un-banned from the server
  235. bot.user_unban do |event|
  236. end
  237. bot.run