소스 검색

Add fables

Kylie Jo Swistak 5 년 전
부모
커밋
f8c9ff2246
12개의 변경된 파일293개의 추가작업 그리고 2개의 파일을 삭제
  1. 64 0
      app/app_forms/fable_app.rb
  2. 49 0
      app/carousels/fable.rb
  3. 54 0
      app/commands/fable.rb
  4. 13 0
      app/controllers/fable_controller.rb
  5. 21 0
      app/embeds/fable.rb
  6. 12 0
      app/embeds/reject.rb
  7. 2 0
      app/models/bot_response.rb
  8. 5 2
      app/models/carousels.rb
  9. 42 0
      app/models/fables.rb
  10. 3 0
      lib/emoji.rb
  11. 25 0
      lib/fable_app.rb
  12. 3 0
      lib/url.rb

+ 64 - 0
app/app_forms/fable_app.rb

@@ -0,0 +1,64 @@
+require './app/app_forms/app_form.rb'
+
+class FableApplication < ApplicationForm
+  def self.process
+    @process||= Application.new('Fable Application') do |event|
+      # Calculate majority
+      maj = majority(event)
+
+      # Check votes
+      reactions = event.message.reactions
+      if reactions[Emoji::Y]&.count.to_i > maj && star(event)
+        approve(event)
+      elsif reactions[Emoji::N]&.count.to_i > maj
+        deny(event)
+      elsif reactions[Emoji::CRAYON]&.count.to_i > 1
+        edit(event)
+      elsif reactions[Emoji::CROSS]&.count.to_i > 1
+        remove(event)
+      end
+    end
+  end
+
+  def self.approve(event)
+    # Save the application
+    app = event.message.embeds.first
+
+    # Save fable
+    fable = FableController.edit_fable(app)
+    reply = BotResponse.new(
+      destination: ENV['FABLE_CH'],
+      text: "Good News, <@#{fable.user_id}>! Your fable was published!",
+      embed: fable_embed(fable: fable, event: event)
+    )
+
+    event.message.delete
+    reply
+  end
+
+  def self.deny(event)
+    reply = BotResponse.new(
+      embed: reject_app(event.message.embeds.first, :fable),
+      reactions: FableApp::REJECT_MESSAGES.map{ |k,v| k }.push(Emoji::CHECK)
+    )
+
+    # Delete message and reply
+    event.message.delete
+    reply
+  end
+
+  def self.edit(event)
+    # Save the application
+    app = event.message.embeds.first
+
+    reply = BotResponse.new(
+      destination: event.channel.id,
+      embed: self_edit_embed(app.footer.text, Url::FABLE),
+      timer: 35
+    )
+
+    # Delete app and reply
+    event.message.delete
+    reply
+  end
+end

+ 49 - 0
app/carousels/fable.rb

@@ -0,0 +1,49 @@
+class FableCarousel < Carousel
+  def self.sections
+    {
+      Emoji::FIRST => 'first',
+      Emoji::LEFT => 'left',
+      Emoji::RIGHT => 'right',
+      Emoji::LAST => 'last'
+    }
+  end
+
+  def self.update_embed(event, carousel)
+    # Save reactions and determine section
+    reactions = event.message.reactions
+    section = sections.filter{ |k,v| reactions[k]&.count.to_i > 1 }.values.first
+
+    # Close the embed if that is chosen
+    return carousel.close(event) if reactions[Emoji::CROSS]&.count.to_i > 1
+
+    # Fetch the corresponding emoji, and remove non-bot reactions
+    emoji = sections.key(section)
+    event.message.reacted_with(emoji).each do |r|
+      event.message.delete_reaction(r.id, emoji) unless r.current_bot?
+    end
+
+    # Find next fable
+    fable = next_fable(section, carousel)
+
+    # Update to new fable
+    BotResponse.new(
+      carousel: carousel,
+      embed: fable_embed(fable, event)
+    )
+  end
+
+  def self.next_fable(section, carousel)
+    case section
+    when 'first'
+      Fable.order('id DESC').first
+    when 'left'
+      Fable.where('id < ?', carousel.fable_id).order('id DESC').first ||
+        Fable.order('id DESC').first
+    when 'right'
+      Fable.where('id > ?', carousel.fable_id).order('id ASC').first ||
+        Fable.order('id ASC').first
+    when 'last'
+      Fable.order('id ASC').first
+    end
+  end
+end

+ 54 - 0
app/commands/fable.rb

@@ -0,0 +1,54 @@
+require './app/commands/base_command.rb'
+
+class FableCommand < BaseCommand
+  def self.opts
+    {
+      usage: {
+        title: "Searches for the fable by title or keyword. If none is given, " +
+        "R0ry will start with the first story"
+      }
+    }
+  end
+
+  def self.cmd
+    desc = 'The book of Zaplanic Myths, Fables, and Legends'
+
+    @cmd ||= Command.new(:fable, desc, opts) do |event, title|
+      case title
+      when /all/i
+      when String
+        # Search for Fable
+        fable =
+          Fable.find_by('title ilike ?', title) ||
+          Fable.where('? ilike any(keywords)', title) if title
+
+        raise 'Fable not found' if fable.empty?
+
+        # Display
+        #embed = fable.lenth > 1 ? fable_list(fable) : fable_embed(fable, event)
+        BotResponse.new(
+          embed: fable_embed(fable.first, event),
+          carousel: fable.first,
+          reactions: FableCarousel.sections.map{ |k,v| k }.push(Emoji::CROSS)
+        )
+      when nil
+        # Display first Fable
+        fable = Fable.first
+        BotResponse.new(
+          embed: fable_embed(fable, event),
+          carousel: fable,
+          reactions: FableCarousel.sections.map{ |k,v| k }.push(Emoji::CROSS)
+        )
+
+      end
+
+    rescue ActiveRecord::RecordNotFound => e
+      error_embed("Record Not Found!", e.message)
+    rescue StandardError => e
+      error_embed(e.message)
+    end
+  end
+
+  def self.example_command
+  end
+end

+ 13 - 0
app/controllers/fable_controller.rb

@@ -0,0 +1,13 @@
+class FableController
+  def self.edit_fable(params)
+    f_hash = Fable.from_form(params)
+
+    fable = Fable.find_by(edit_url: f_hash["edit_url"])
+    if fable
+      fable.update(f_hash)
+      fable.reload
+    else
+      Fable.create(f_hash)
+    end
+  end
+end

+ 21 - 0
app/embeds/fable.rb

@@ -0,0 +1,21 @@
+def fable_embed(fable, event)
+  # Find the author, if they're a member
+  author = event.server.member(fable.user_id)
+
+  embed = Embed.new(
+    title: fable.title,
+    description: fable.story,
+  )
+
+  embed.image = { url: fable.url } if fable.url
+  author_footer(embed, author, [fable.id])
+
+  embed
+end
+
+def fable_list(fables)
+  Embed.new(
+    title: 'Related Fables',
+    description: fables.map(&:title).join("\n")
+  )
+end

+ 12 - 0
app/embeds/reject.rb

@@ -21,6 +21,8 @@ def reject_app(app, opts)
              reject_fields(ImgApp::REJECT_MESSAGES)
            when :landmark
              reject_fields(LmApp::REJECT_MESSAGES)
+           when :fable
+             reject_fields(FableApp::REJECT_MESSAGES)
            when :reactivation
              # Find Character
              character = Character.find(app.footer.text.match(/\|\s(\d+)$/)[1])
@@ -78,6 +80,16 @@ def rejected_app(event, opts)
         value: "[Edit Your Application](#{Url::LANDMARK}" +
         "#{app.footer.text})"
       }]
+    when :fable
+      [{
+        name: "Messages from the admin:",
+        value: selected_messages(reactions, FableApp::REJECT_MESSAGES).
+        join("\n") || 'No messages given'
+      },{
+        name: MSG,
+        value: "[Edit Your Application](#{Url::FABLE}" +
+        "#{app.footer.text})"
+      }]
     end
 
   # Populate embed and return

+ 2 - 0
app/models/bot_response.rb

@@ -41,6 +41,8 @@ class BotResponse
       Carousel.create(message_id: message.id, char_id: @carousel.id)
     when Landmark
       Carousel.create(message_id: message.id, landmark_id: @carousel.id)
+    when Fable
+      Carousel.create(message_id: message.id, fable_id: @carousel.id)
     when CharImage
       Carousel.create(
         message_id: message.id,

+ 5 - 2
app/models/carousels.rb

@@ -15,12 +15,15 @@ class Carousel < ActiveRecord::Base
     elsif landmark_id
       # Landmark
       LandmarkCarousel.update_embed(event, self)
+    elsif fable_id
+      # Fable
+      FableCarousel.update_embed(event, self)
     else
       # Member List
       GuildCarousel.update_embed(event, self)
     end
-  rescue StandardError => e
-    error_embed(e.message)
+  #rescue StandardError => e
+    #error_embed(e.message)
   end
 
   def close(event)

+ 42 - 0
app/models/fables.rb

@@ -0,0 +1,42 @@
+class Fable < ActiveRecord::Base
+  validates :title, presence: true
+  validates :story, presence: true
+
+  def self.from_form(app)
+    key_mapping = {
+      "Author" => "user_id",
+      "Keywords" => "keywords"
+    }
+
+    hash = {
+      "title" => nil,
+      "story" => nil,
+      "url" => nil,
+      "keywords" => nil,
+      "user_id" => nil,
+      "edit_url" => nil
+    }
+
+    hash["title"] = app.title
+    hash["story"] = app.description
+    hash["edit_url"] = app.footer.text
+    hash["url"] = app.image&.url
+
+    app.fields.each do |field|
+      next if field.nil?
+
+      db_column = key_mapping[field.name]
+      if db_column == "user_id"
+        hash[db_column] = UID.match(field.value)[1]
+      elsif db_column == "keywords"
+        hash[db_column] = field.value.split(/\s?(,|\|)\s?/)
+      else
+        hash[db_column] = field.value
+      end
+    end
+
+
+    hash = hash.reject { |k,v| k == nil }
+    hash
+  end
+end

+ 3 - 0
lib/emoji.rb

@@ -28,6 +28,7 @@ module Emoji
   Y = "🇾"
   Z = "🇿"
 
+  ZERO = "0️⃣"
   ONE = "1⃣"
   TWO = "2⃣"
   THREE = "3⃣"
@@ -40,8 +41,10 @@ module Emoji
   TEN = "🔟"
   NUMS = "🔢"
 
+  FIRST = "⏪"
   LEFT = "◀"
   RIGHT = "▶"
+  LAST = "⏩"
   UNDO = "⏫"
 
   CHECK = "✅"

+ 25 - 0
lib/fable_app.rb

@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+require_relative 'emoji.rb'
+
+module FableApp
+  GRAMMAR = "Please check your grammar and capitalization"
+  IMAGE = "The given image doesn't seem relevant, or is inappropriate"
+  LORE = "This fable conflicts with server lore"
+  ELABORATE = "This fable is too short or does not provide useful lore"
+  NONSENSE = "The keywords are confusing or unrelated"
+  DUPLICATE = "This fable is either very similar to another, or does not add any new lore"
+  UNDERLEVELED = "You are not high enough level to make this fable"
+  DISCUSSED = "You have already discussed issues with an admin"
+  INLINE_SPACE = "------------------------------"
+
+  REJECT_MESSAGES = {
+    Emoji::SPEECH_BUBBLE => GRAMMAR,
+    Emoji::PICTURE => IMAGE,
+    Emoji::BOOKS => LORE,
+    Emoji::NOTE => ELABORATE,
+    Emoji::QUESTION => NONSENSE,
+    Emoji::PEOPLE => DUPLICATE,
+    Emoji::WIZARD => UNDERLEVELED,
+    Emoji::TALK => DISCUSSED
+  }
+end

+ 3 - 0
lib/url.rb

@@ -8,4 +8,7 @@ module Url
   LM = "https://forms.gle/sU7vgaSpHiWa9e368"
 
   ITEM = "https://docs.google.com/forms/d/e/1FAIpQLSf1wJsagsgGCxO_gj4Ea3pHU7eusSsezmI0CYZexBPEK7dsOw/viewform"
+
+  FABLE = "https://docs.google.com/forms/d/e/1FAIpQLSeHwlrl_uw6ZVvS8taRAyqc30sFLujLj9UfF4Nh60QOMTcTWA/viewform"
+  FBL = "https://forms.gle/fvZsU3hp1uAPPXUy5"
 end