about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/settings_controller.rb14
-rw-r--r--app/javascript/images/mastodon_small.jpgbin25199 -> 0 bytes
-rw-r--r--app/javascript/images/preview.jpgbin0 -> 292252 bytes
-rw-r--r--app/models/site_upload.rb44
-rw-r--r--app/presenters/instance_presenter.rb4
-rw-r--r--app/serializers/rest/instance_serializer.rb8
-rw-r--r--app/views/about/_og.html.haml10
-rw-r--r--app/views/about/more.html.haml11
-rw-r--r--app/views/about/show.html.haml11
-rw-r--r--app/views/admin/settings/edit.html.haml5
-rw-r--r--config/locales/en.yml3
-rw-r--r--db/migrate/20170913000752_create_site_uploads.rb10
-rw-r--r--db/schema.rb14
-rw-r--r--spec/fabricators/site_upload_fabricator.rb3
-rw-r--r--spec/models/site_upload_spec.rb5
-rw-r--r--spec/views/about/show.html.haml_spec.rb9
16 files changed, 123 insertions, 28 deletions
diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb
index c5e6fe4e5..a2f86b8a9 100644
--- a/app/controllers/admin/settings_controller.rb
+++ b/app/controllers/admin/settings_controller.rb
@@ -14,6 +14,7 @@ module Admin
       open_deletion
       timeline_preview
       bootstrap_timeline_accounts
+      thumbnail
     ).freeze
 
     BOOLEAN_SETTINGS = %w(
@@ -22,14 +23,23 @@ module Admin
       timeline_preview
     ).freeze
 
+    UPLOAD_SETTINGS = %w(
+      thumbnail
+    ).freeze
+
     def edit
       @admin_settings = Form::AdminSettings.new
     end
 
     def update
       settings_params.each do |key, value|
-        setting = Setting.where(var: key).first_or_initialize(var: key)
-        setting.update(value: value_for_update(key, value))
+        if UPLOAD_SETTINGS.include?(key)
+          upload = SiteUpload.where(var: key).first_or_initialize(var: key)
+          upload.update(file: value)
+        else
+          setting = Setting.where(var: key).first_or_initialize(var: key)
+          setting.update(value: value_for_update(key, value))
+        end
       end
 
       flash[:notice] = I18n.t('generic.changes_saved_msg')
diff --git a/app/javascript/images/mastodon_small.jpg b/app/javascript/images/mastodon_small.jpg
deleted file mode 100644
index 9c88ce3f7..000000000
--- a/app/javascript/images/mastodon_small.jpg
+++ /dev/null
Binary files differdiff --git a/app/javascript/images/preview.jpg b/app/javascript/images/preview.jpg
new file mode 100644
index 000000000..ec2856748
--- /dev/null
+++ b/app/javascript/images/preview.jpg
Binary files differdiff --git a/app/models/site_upload.rb b/app/models/site_upload.rb
new file mode 100644
index 000000000..8ffdc8313
--- /dev/null
+++ b/app/models/site_upload.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+# == Schema Information
+#
+# Table name: site_uploads
+#
+#  id                :integer          not null, primary key
+#  var               :string           default(""), not null
+#  file_file_name    :string
+#  file_content_type :string
+#  file_file_size    :integer
+#  file_updated_at   :datetime
+#  meta              :json
+#  created_at        :datetime         not null
+#  updated_at        :datetime         not null
+#
+
+class SiteUpload < ApplicationRecord
+  has_attached_file :file
+
+  validates_attachment_content_type :file, content_type: /\Aimage\/.*\z/
+  validates :var, presence: true, uniqueness: true
+
+  before_save :set_meta
+  after_commit :clear_cache
+
+  def cache_key
+    "site_uploads/#{var}"
+  end
+
+  private
+
+  def set_meta
+    tempfile = file.queued_for_write[:original]
+
+    return if tempfile.nil?
+
+    geometry  = Paperclip::Geometry.from_file(tempfile)
+    self.meta = { width: geometry.width.to_i, height: geometry.height.to_i }
+  end
+
+  def clear_cache
+    Rails.cache.delete(cache_key)
+  end
+end
diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb
index 8104b7531..c9e3c31a1 100644
--- a/app/presenters/instance_presenter.rb
+++ b/app/presenters/instance_presenter.rb
@@ -35,4 +35,8 @@ class InstancePresenter
   def source_url
     Mastodon::Version.source_url
   end
+
+  def thumbnail
+    @thumbnail ||= Rails.cache.fetch('site_uploads/thumbnail') { SiteUpload.find_by(var: 'thumbnail') }
+  end
 end
diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb
index a97137909..2898011fd 100644
--- a/app/serializers/rest/instance_serializer.rb
+++ b/app/serializers/rest/instance_serializer.rb
@@ -1,8 +1,10 @@
 # frozen_string_literal: true
 
 class REST::InstanceSerializer < ActiveModel::Serializer
+  include RoutingHelper
+
   attributes :uri, :title, :description, :email,
-             :version, :urls, :stats
+             :version, :urls, :stats, :thumbnail
 
   def uri
     Rails.configuration.x.local_domain
@@ -24,6 +26,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer
     Mastodon::Version.to_s
   end
 
+  def thumbnail
+    full_asset_url(instance_presenter.thumbnail.file.url) if instance_presenter.thumbnail
+  end
+
   def stats
     {
       user_count: instance_presenter.user_count,
diff --git a/app/views/about/_og.html.haml b/app/views/about/_og.html.haml
new file mode 100644
index 000000000..dbd476915
--- /dev/null
+++ b/app/views/about/_og.html.haml
@@ -0,0 +1,10 @@
+- thumbnail = @instance_presenter.thumbnail
+= opengraph 'og:site_name', t('about.hosted_on', domain: site_hostname)
+= opengraph 'og:url', about_url
+= opengraph 'og:type', 'website'
+= opengraph 'og:title', @instance_presenter.site_title
+= opengraph 'og:description', strip_tags(@instance_presenter.site_description.presence || t('about.about_mastodon_html'))
+= opengraph 'og:image', full_asset_url(thumbnail&.file&.url || asset_pack_path('preview.jpg', protocol: :request))
+= opengraph 'og:image:width', thumbnail ? thumbnail.meta['width'] : '1200'
+= opengraph 'og:image:height', thumbnail ? thumbnail.meta['height'] : '630'
+= opengraph 'twitter:card', 'summary_large_image'
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
index 094188472..1a4e74643 100644
--- a/app/views/about/more.html.haml
+++ b/app/views/about/more.html.haml
@@ -3,16 +3,7 @@
 
 - content_for :header_tags do
   = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
-
-  %meta{ property: 'og:site_name', content: site_title }/
-  %meta{ property: 'og:url', content: about_url }/
-  %meta{ property: 'og:type', content: 'website' }/
-  %meta{ property: 'og:title', content: site_hostname }/
-  %meta{ property: 'og:description', content: strip_tags(@instance_presenter.site_description.presence || t('about.about_mastodon_html')) }/
-  %meta{ property: 'og:image', content: asset_pack_path('mastodon_small.jpg', protocol: :request) }/
-  %meta{ property: 'og:image:width', content: '400' }/
-  %meta{ property: 'og:image:height', content: '400' }/
-  %meta{ property: 'twitter:card', content: 'summary' }/
+  = render partial: 'og'
 
 .landing-page
   .header-wrapper.compact
diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml
index 93270fe3d..0d311b895 100644
--- a/app/views/about/show.html.haml
+++ b/app/views/about/show.html.haml
@@ -4,16 +4,7 @@
 - content_for :header_tags do
   %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
   = javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous'
-
-  %meta{ property: 'og:site_name', content: site_title }/
-  %meta{ property: 'og:url', content: about_url }/
-  %meta{ property: 'og:type', content: 'website' }/
-  %meta{ property: 'og:title', content: site_hostname }/
-  %meta{ property: 'og:description', content: strip_tags(@instance_presenter.site_description.presence || t('about.about_mastodon_html')) }/
-  %meta{ property: 'og:image', content: asset_pack_path('mastodon_small.jpg', protocol: :request) }/
-  %meta{ property: 'og:image:width', content: '400' }/
-  %meta{ property: 'og:image:height', content: '400' }/
-  %meta{ property: 'twitter:card', content: 'summary' }/
+  = render partial: 'og'
 
 .landing-page
   .header-wrapper
diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml
index 50d019ec4..468166035 100644
--- a/app/views/admin/settings/edit.html.haml
+++ b/app/views/admin/settings/edit.html.haml
@@ -11,6 +11,11 @@
   %hr/
 
   .fields-group
+    = f.input :thumbnail, as: :file, wrapper: :with_block_label, label: t('admin.settings.thumbnail.title'), hint: t('admin.settings.thumbnail.desc_html')
+
+  %hr/
+
+  .fields-group
     = f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')
 
   .fields-group
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 0cd57a64f..8b5f52b02 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -195,6 +195,9 @@ en:
         desc_html: You can write your own privacy policy, terms of service or other legalese. You can use HTML tags
         title: Custom terms of service
       site_title: Instance name
+      thumbnail:
+        desc_html: Used for previews via OpenGraph and API. 1200x630px recommended
+        title: Instance thumbnail
       timeline_preview:
         desc_html: Display public timeline on landing page
         title: Timeline preview
diff --git a/db/migrate/20170913000752_create_site_uploads.rb b/db/migrate/20170913000752_create_site_uploads.rb
new file mode 100644
index 000000000..2246e48cd
--- /dev/null
+++ b/db/migrate/20170913000752_create_site_uploads.rb
@@ -0,0 +1,10 @@
+class CreateSiteUploads < ActiveRecord::Migration[5.1]
+  def change
+    create_table :site_uploads do |t|
+      t.string :var, default: '', null: false, index: { unique: true }
+      t.attachment :file
+      t.json :meta
+      t.timestamps
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d8af0a1f8..f2ca2af69 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20170905165803) do
+ActiveRecord::Schema.define(version: 20170913000752) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -288,6 +288,18 @@ ActiveRecord::Schema.define(version: 20170905165803) do
     t.index ["thing_type", "thing_id", "var"], name: "index_settings_on_thing_type_and_thing_id_and_var", unique: true
   end
 
+  create_table "site_uploads", force: :cascade do |t|
+    t.string "var", default: "", null: false
+    t.string "file_file_name"
+    t.string "file_content_type"
+    t.integer "file_file_size"
+    t.datetime "file_updated_at"
+    t.json "meta"
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.index ["var"], name: "index_site_uploads_on_var", unique: true
+  end
+
   create_table "status_pins", force: :cascade do |t|
     t.bigint "account_id", null: false
     t.bigint "status_id", null: false
diff --git a/spec/fabricators/site_upload_fabricator.rb b/spec/fabricators/site_upload_fabricator.rb
new file mode 100644
index 000000000..8f4e43ac9
--- /dev/null
+++ b/spec/fabricators/site_upload_fabricator.rb
@@ -0,0 +1,3 @@
+Fabricator(:site_upload) do
+
+end
diff --git a/spec/models/site_upload_spec.rb b/spec/models/site_upload_spec.rb
new file mode 100644
index 000000000..8745d54b8
--- /dev/null
+++ b/spec/models/site_upload_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe SiteUpload, type: :model do
+
+end
diff --git a/spec/views/about/show.html.haml_spec.rb b/spec/views/about/show.html.haml_spec.rb
index aa151dd27..724643cbc 100644
--- a/spec/views/about/show.html.haml_spec.rb
+++ b/spec/views/about/show.html.haml_spec.rb
@@ -15,15 +15,16 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do
                                 version_number: '1.0',
                                 source_url: 'https://github.com/tootsuite/mastodon',
                                 open_registrations: false,
+                                thumbnail: nil,
                                 closed_registrations_message: 'yes')
     assign(:instance_presenter, instance_presenter)
     render
 
     header_tags = view.content_for(:header_tags)
 
-    expect(header_tags).to match(%r{<meta content='.+' property='og:title'>})
-    expect(header_tags).to match(%r{<meta content='website' property='og:type'>})
-    expect(header_tags).to match(%r{<meta content='.+' property='og:image'>})
-    expect(header_tags).to match(%r{<meta content='http://.+' property='og:url'>})
+    expect(header_tags).to match(%r{<meta content=".+" property="og:title" />})
+    expect(header_tags).to match(%r{<meta content="website" property="og:type" />})
+    expect(header_tags).to match(%r{<meta content=".+" property="og:image" />})
+    expect(header_tags).to match(%r{<meta content="http://.+" property="og:url" />})
   end
 end