# frozen_string_literal: true class E621Webhook < ApplicationRecord validate :validate_max_per_channel, on: :create validate :validate_max_per_guild, on: :create after_create do send_creation_message send_update(E621Status.current) end after_destroy do webhook&.delete unless skip_delete_webhook send_deletion_message end attr_reader :skip_delete_webhook MAX_PER_CHANNEL = 1 MAX_PER_GUILD = 5 SUCCESS_COLOR = 0x008000 WARNING_COLOR = 0xFFA500 ERROR_COLOR = 0xFF0000 E621_COLOR = 0x012E57 def self.from_struct(data, creator_id = nil) hook = create( webhook_id: data.id, webhook_token: data.token, channel_id: data.channel_id, creator_id: creator_id, guild_id: data.guild_id, ) if hook.errors[:channel_id].include?("has too many webhooks") hook.send_too_many_channel_message hook.destroy return :too_many_channel end if hook.errors[:guild_id].include?("has too many webhooks") hook.send_too_many_guild_message hook.destroy return :too_many_guild end hook end def validate_max_per_channel return if channel_id.blank? return if E621Webhook.for_channel(channel_id).count < MAX_PER_CHANNEL errors.add(:channel_id, "has too many webhooks") end def validate_max_per_guild return if guild_id.blank? return if E621Webhook.for_guild(guild_id).count < MAX_PER_GUILD errors.add(:guild_id, "has too many webhooks") end module WebhookMethods def webhook return nil unless webhook_id && webhook_token Requests::DiscordWebhook.new(id: webhook_id, token: webhook_token) end def add_defaults(embed) embed.thumbnail = Discordrb::Webhooks::EmbedThumbnail.new(url: "https://status.e621.ws/icon.png") embed.url = "https://status.e621.ws" embed.timestamp = Time.now embed.color = E621_COLOR end def notification_webhook Websites.config.e621_status_check_logs_webhook end def send_creation_message execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "E621 Status Check" embed.description = "This webhook has been setup to receive status updates for e621's api#{creator_id.present? ? " by <@#{creator_id}>" : ''}." end end notification_webhook.execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "Status Check Webhook Added" embed.description = "A status check has been added in the channel **#{channel_id}** of the guild **#{guild_id}**#{creator_id.present? ? " by <@#{creator_id}>" : ''}." embed.color = SUCCESS_COLOR end end end def send_deletion_message notification_webhook.execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "Status Check Webhook Removed" embed.description = "A status check has been removed in the channel **#{channel_id}** of the guild **#{guild_id}**#{creator_id.present? ? " by <@#{creator_id}>" : ''}." embed.color = ERROR_COLOR end end end def send_too_many_guild_message execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "E621 Status Check" embed.description = "You've already enabled #{MAX_PER_GUILD} status checks in this server. Please delete the other webhooks before adding a new check. This webhook will be automatically deleted." embed.color = ERROR_COLOR end end end def send_too_many_channel_message execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "E621 Status Check" embed.description = "You've already enabled #{MAX_PER_CHANNEL} status checks in this channel. Please delete the other webhooks before adding a new check. This webhook will be automatically deleted." embed.color = ERROR_COLOR end end end def send_update(status) status_text = E621Status::STATUS_MESSAGES[status.status] execute do |builder| builder.add_embed do |embed| add_defaults(embed) embed.title = "E621 Status Update" embed.description = "E621's api is **#{status.available ? 'available' : 'unavailable'}**." embed.color = status.available ? SUCCESS_COLOR : status.status == 403 ? WARNING_COLOR : ERROR_COLOR embed.timestamp = status.created_at embed.footer = Discordrb::Webhooks::EmbedFooter.new(text: "Since") embed.add_field(name: "Status", value: "#{status.status} #{status_text.present? ? "(#{status_text})" : ''}", inline: true) embed.add_field(name: "State", value: E621Status::STATES[status.state] || (status.available ? "up" : "down"), inline: true) embed.add_field(name: "Note", value: status.note, inline: false) if status.note.present? end end end def execute(...) if webhook.nil? @skip_delete_webhook = true destroy return nil end begin webhook.execute(...) rescue RestClient::NotFound @skip_delete_webhook = true destroy nil end end end module SearchMethods def for_guild(id) where(guild_id: id) end def for_channel(id) where(channel_id: id) end end include WebhookMethods extend SearchMethods end