Skip to content

Commit

Permalink
fix(puzzles): Better handle GenerateSlackThread job errors and incomp…
Browse files Browse the repository at this point in the history
…lete puzzle data (#719)

* feat(errors): create SlackError class

* fix(puzzles): improve GenerateSlackThread

* feat(tasks): create rake task to update puzzle thread

* fix(puzzles): better handle missing puzzle data

* fix(puzzles): wrap rake instruction in code block

* fix: rubocop

* Fix typo

---------

Co-authored-by: Jérémie Bonal <jeremie.bonal@gmail.com>
  • Loading branch information
wJoenn and Aquaj authored Dec 3, 2024
1 parent bfabddd commit b518fd8
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 20 deletions.
2 changes: 2 additions & 0 deletions app/controllers/snippets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ def client

def post_slack_message
puzzle = Puzzle.by_date(Aoc.begin_time.change(day: params[:day]))
return if puzzle.thread_ts.nil?

username = "<#{helpers.profile_url(current_user.uid)}|#{current_user.username}>"
text = "#{username} submitted a new #{solution_markdown} for part #{params[:challenge]} in :#{@snippet.language}-hd:"
client.chat_postMessage(channel: ENV.fetch("SLACK_CHANNEL", "#aoc-dev"), text:, thread_ts: puzzle.thread_ts)
Expand Down
3 changes: 3 additions & 0 deletions app/errors/slack_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

class SlackError < StandardError; end
57 changes: 38 additions & 19 deletions app/jobs/generate_slack_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,69 @@
class GenerateSlackThread < ApplicationJob
queue_as :default

retry_on SlackError do |_, error|
client.chat_postMessage(channel: "#aoc-dev", text: error)
end

def perform(date)
@puzzle = Puzzle.find_or_create_by(date:)
return if @puzzle.slack_url.present?

if @puzzle.title ||= title_scraped
post_message(channel: ENV.fetch("SLACK_CHANNEL", "#aoc-dev"), text: @puzzle.title)
@puzzle.slack_url = save_permalink
@puzzle.thread_ts = @message["message"]["ts"]
@puzzle.save
if @puzzle.persisted?
@puzzle.title = scraped_title || "`SPOILER` <#{@puzzle.url}|Day #{date.day}>"
@puzzle.thread_ts = message["message"]["ts"]
@puzzle.slack_url = permalink
@puzzle.save!
else
post_message(channel: "#aoc-dev", text: "Title not found for day ##{@puzzle.date.day}")
@puzzle.destroy
client.chat_postMessage(channel: "#aoc-dev", text: @puzzle.errors.full_messages.join(", "))
end
end

private

def channel
ENV.fetch("SLACK_CHANNEL", "#aoc-dev")
end

def client
@client ||= Slack::Web::Client.new
end

def post_message(channel:, text:)
# https://api.slack.com/methods/chat.postMessage
@message = client.chat_postMessage(channel:, text:)
def message
@message ||= if @puzzle.thread_ts.present?
{ "message" => { "ts" => @puzzle.thread_ts } }
else
response = client.chat_postMessage(channel:, text: @puzzle.title)
raise SlackError.new, "Failed to post message for day ##{@puzzle.date.day}" unless response["ok"]

response
end
end

def save_permalink
# https://api.slack.com/methods/chat.getPermalink
slack_thread = client.chat_getPermalink(
channel: @message["channel"],
message_ts: @message["message"]["ts"]
)
def permalink
@permalink ||= begin
response = client.chat_getPermalink(channel:, message_ts: message["message"]["ts"])[:permalink]
raise SlackError.new, "Failed to get permalink for day ##{@puzzle.date.day}" unless response["ok"]

slack_thread[:permalink] || Aoc.slack_channel
response
end
end

def title_scraped
@title_scraped ||= begin
def scraped_title
@scraped_title ||= begin
html = URI.parse(@puzzle.url).open
doc = Nokogiri::HTML(html)
titles = doc.css("h2").map(&:text)
raw_title = titles.find { |title| title.match?(/--- Day \d+:/) }

"`SPOILER` <#{@puzzle.url}|#{raw_title.gsub('---', '').strip}>" if raw_title.present?
rescue OpenURI::HTTPError
day = @puzzle.date.day
client.chat_postMessage(
channel: "#aoc-dev",
text: "Title not found for day ##{day}, run `bundle exec rake 'update_puzzle_thread[#{day},#{channel}]'`"
)

nil
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/views/days/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<span>·</span>
<%= link_to "puzzle", Aoc.url(@day), target: :_blank, rel: :noopener, class: "link-explicit link-external" %>

<% if @puzzle.present? %>
<% if @puzzle.slack_url.present? %>
<span>·</span>
<%= link_to "slack thread", @puzzle.slack_url, target: :_blank, rel: :noopener, class: "link-explicit link-slack" %>
<% end %>
Expand Down
23 changes: 23 additions & 0 deletions lib/tasks/update_puzzle_thread.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

desc "update_puzzle_thread"
task :update_puzzle_thread, %i[day channel] => :environment do |_, args|
next p "day param missing" if args[:day].nil?
next p "channel missing or incorrect" unless args[:channel].in? %w[aoc aoc-dev]

puzzle = Puzzle.by_date(Aoc.begin_time.change(day: args[:day]))
next p "Puzzle not found" if puzzle.nil?

html = URI.parse(@puzzle.url).open
doc = Nokogiri::HTML(html)
titles = doc.css("h2").map(&:text)
raw_title = titles.find { |title| title.match?(/--- Day \d+:/) }
next p "Title not found" if raw_title.nil?

client = Slack::Web::Client.new
text = "`SPOILER` <#{@puzzle.url}|#{raw_title.gsub('---', '').strip}>"
response = client.chat_update(channel: args[:channel], ts: puzzle.thread_ts, text:)
next p "Failed to update message" unless response["ok"]

puzzle.update!(title: text)
end

0 comments on commit b518fd8

Please sign in to comment.