about summary refs log tree commit diff
path: root/app/lib
diff options
context:
space:
mode:
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/command_tag/command/status_tools.rb22
-rw-r--r--app/lib/formatter.rb20
-rw-r--r--app/lib/sanitize_config.rb19
3 files changed, 55 insertions, 6 deletions
diff --git a/app/lib/command_tag/command/status_tools.rb b/app/lib/command_tag/command/status_tools.rb
index 1727a956e..1cdb90e4a 100644
--- a/app/lib/command_tag/command/status_tools.rb
+++ b/app/lib/command_tag/command/status_tools.rb
@@ -1,11 +1,29 @@
 # frozen_string_literal: true
 module CommandTag::Command::StatusTools
+  def handle_article_before_save(args)
+    return unless author_of_status? && args.present?
+
+    case args.shift.downcase
+    when 'title', 'name', 't'
+      status.title = args.join(' ')
+    when 'summary', 'abstract', 'cw', 'cn', 's', 'a'
+      @status.title = @status.spoiler_text if @status.title.blank?
+      @status.spoiler_text = args.join(' ')
+    end
+  end
+
   def handle_title_before_save(args)
-    return unless author_of_status?
+    args.unshift('title')
+    handle_article_before_save(args)
+  end
 
-    @status.title = args[0]
+  def handle_summary_before_save(args)
+    args.unshift('summary')
+    handle_article_before_save(args)
   end
 
+  alias handle_abstract_before_save handle_summary_before_save
+
   def handle_visibility_before_save(args)
     return unless author_of_status? && args[0].present?
 
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index d85bbf0e0..bf99701b7 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -39,8 +39,14 @@ class Formatter
       prepend_reblog = false
     end
 
+    summary = nil
     raw_content = status.text
 
+    if status.title.present?
+      summary = status.spoiler_text.presence || status.text
+      raw_content = options[:article_content] ? status.text : summary
+    end
+
     if options[:inline_poll_options] && status.preloadable_poll
       raw_content = raw_content + "\n\n" + status.preloadable_poll.options.map { |title| "[ ] #{title}" }.join("\n")
     end
@@ -50,6 +56,7 @@ class Formatter
     unless status.local?
       html = reformat(raw_content)
       html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]
+      html = format_article_content(summary, html) if options[:article_content] && summary.present?
       return html.html_safe # rubocop:disable Rails/OutputSafety
     end
 
@@ -68,6 +75,7 @@ class Formatter
       html = html.delete("\n")
     end
 
+    html = format_article_content(summary, html) if options[:article_content] && summary.present?
     html.html_safe # rubocop:disable Rails/OutputSafety
   end
 
@@ -77,10 +85,14 @@ class Formatter
   end
 
   def format_article(text)
-    text = text.gsub(/>[\r\n]+</, "><")
+    text = text.gsub(/>[\r\n]+</, '><')
     text.html_safe # rubocop:disable Rails/OutputSafety
   end
 
+  def format_article_content(summary, html)
+    "<blockquote data-name=\"summary\">#{format_summary(summary, html)}</blockquote>#{html}"
+  end
+
   def reformat(html, outgoing = false)
     sanitize(html, Sanitize::Config::MASTODON_STRICT.merge(outgoing: outgoing))
   rescue ArgumentError
@@ -108,8 +120,12 @@ class Formatter
     Sanitize.fragment(html, config)
   end
 
+  def format_summary(summary, fallback)
+    summary&.strip.presence || fallback[/(?:<p>.*?<\/p>)/im].presence || '🗎❓'
+  end
+
   def format_spoiler(status, **options)
-    html = encode(status.spoiler_text)
+    html = encode(status.title.presence || status.spoiler_text)
     html = encode_custom_emojis(html, status.emojis, options[:autoplay])
     html.html_safe # rubocop:disable Rails/OutputSafety
   end
diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb
index 74a1d93fb..102dce2d2 100644
--- a/app/lib/sanitize_config.rb
+++ b/app/lib/sanitize_config.rb
@@ -30,12 +30,25 @@ class Sanitize
         next true if e =~ /^(h|p|u|dt|e)-/ # microformats classes
         next true if e =~ /^(mention|hashtag)$/ # semantic classes
         next true if e =~ /^(ellipsis|invisible)$/ # link formatting classes
-        next true if %w(center centered).include?(e)
+        next true if %w(center centered abstract).include?(e)
       end
 
       node['class'] = class_list.join(' ')
     end
 
+    DATA_NAME_ALLOWLIST_TRANSFORMER = lambda do |env|
+      node = env[:node]
+      name_list = node['data-name']&.split(/[\t\n\f\r ]/)
+
+      return unless name_list
+
+      name_list.keep_if do |name|
+        next true if %w(summary abstract).include?(name)
+      end
+
+      node['data-name'] = name_list.join(' ')
+    end
+
     LINK_REL_TRANSFORMER = lambda do |env|
       return unless env[:node_name] == 'a' and env[:node]['href']
 
@@ -71,10 +84,11 @@ class Sanitize
         'a'          => %w(href rel class title),
         'span'       => %w(class),
         'abbr'       => %w(title),
-        'blockquote' => %w(cite),
+        'blockquote' => %w(cite data-name),
         'ol'         => %w(start reversed),
         'li'         => %w(value),
         'img'        => %w(src alt title),
+        'p'          => %w(data-name),
       },
 
       add_attributes: {
@@ -90,6 +104,7 @@ class Sanitize
 
       transformers: [
         CLASS_WHITELIST_TRANSFORMER,
+        DATA_NAME_ALLOWLIST_TRANSFORMER,
         UNSUPPORTED_HREF_TRANSFORMER,
         LINK_REL_TRANSFORMER,
       ]