* Improve OpenGraph tags for about pages * Add thumbnail admin setting * Fix error * Fix upmaster
@@ -14,6 +14,7 @@ module Admin | |||||
open_deletion | open_deletion | ||||
timeline_preview | timeline_preview | ||||
bootstrap_timeline_accounts | bootstrap_timeline_accounts | ||||
thumbnail | |||||
).freeze | ).freeze | ||||
BOOLEAN_SETTINGS = %w( | BOOLEAN_SETTINGS = %w( | ||||
@@ -22,14 +23,23 @@ module Admin | |||||
timeline_preview | timeline_preview | ||||
).freeze | ).freeze | ||||
UPLOAD_SETTINGS = %w( | |||||
thumbnail | |||||
).freeze | |||||
def edit | def edit | ||||
@admin_settings = Form::AdminSettings.new | @admin_settings = Form::AdminSettings.new | ||||
end | end | ||||
def update | def update | ||||
settings_params.each do |key, value| | 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 | end | ||||
flash[:notice] = I18n.t('generic.changes_saved_msg') | flash[:notice] = I18n.t('generic.changes_saved_msg') | ||||
@@ -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 |
@@ -35,4 +35,8 @@ class InstancePresenter | |||||
def source_url | def source_url | ||||
Mastodon::Version.source_url | Mastodon::Version.source_url | ||||
end | end | ||||
def thumbnail | |||||
@thumbnail ||= Rails.cache.fetch('site_uploads/thumbnail') { SiteUpload.find_by(var: 'thumbnail') } | |||||
end | |||||
end | end |
@@ -1,8 +1,10 @@ | |||||
# frozen_string_literal: true | # frozen_string_literal: true | ||||
class REST::InstanceSerializer < ActiveModel::Serializer | class REST::InstanceSerializer < ActiveModel::Serializer | ||||
include RoutingHelper | |||||
attributes :uri, :title, :description, :email, | attributes :uri, :title, :description, :email, | ||||
:version, :urls, :stats | |||||
:version, :urls, :stats, :thumbnail | |||||
def uri | def uri | ||||
Rails.configuration.x.local_domain | Rails.configuration.x.local_domain | ||||
@@ -24,6 +26,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer | |||||
Mastodon::Version.to_s | Mastodon::Version.to_s | ||||
end | end | ||||
def thumbnail | |||||
full_asset_url(instance_presenter.thumbnail.file.url) if instance_presenter.thumbnail | |||||
end | |||||
def stats | def stats | ||||
{ | { | ||||
user_count: instance_presenter.user_count, | user_count: instance_presenter.user_count, | ||||
@@ -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' |
@@ -3,16 +3,7 @@ | |||||
- content_for :header_tags do | - content_for :header_tags do | ||||
= javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' | = 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 | .landing-page | ||||
.header-wrapper.compact | .header-wrapper.compact | ||||
@@ -4,16 +4,7 @@ | |||||
- content_for :header_tags do | - content_for :header_tags do | ||||
%script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json) | %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json) | ||||
= javascript_pack_tag 'about', integrity: true, crossorigin: 'anonymous' | = 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 | .landing-page | ||||
.header-wrapper | .header-wrapper | ||||
@@ -11,6 +11,11 @@ | |||||
%hr/ | %hr/ | ||||
.fields-group | .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') | = 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 | .fields-group | ||||
@@ -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 | 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 | title: Custom terms of service | ||||
site_title: Instance name | site_title: Instance name | ||||
thumbnail: | |||||
desc_html: Used for previews via OpenGraph and API. 1200x630px recommended | |||||
title: Instance thumbnail | |||||
timeline_preview: | timeline_preview: | ||||
desc_html: Display public timeline on landing page | desc_html: Display public timeline on landing page | ||||
title: Timeline preview | title: Timeline preview | ||||
@@ -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 |
@@ -10,7 +10,7 @@ | |||||
# | # | ||||
# It's strongly recommended that you check this file into your version control system. | # 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 | # These are extensions that must be enabled in order to support this database | ||||
enable_extension "plpgsql" | 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 | t.index ["thing_type", "thing_id", "var"], name: "index_settings_on_thing_type_and_thing_id_and_var", unique: true | ||||
end | 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| | create_table "status_pins", force: :cascade do |t| | ||||
t.bigint "account_id", null: false | t.bigint "account_id", null: false | ||||
t.bigint "status_id", null: false | t.bigint "status_id", null: false | ||||
@@ -0,0 +1,3 @@ | |||||
Fabricator(:site_upload) do | |||||
end |
@@ -0,0 +1,5 @@ | |||||
require 'rails_helper' | |||||
RSpec.describe SiteUpload, type: :model do | |||||
end |
@@ -15,15 +15,16 @@ describe 'about/show.html.haml', without_verify_partial_doubles: true do | |||||
version_number: '1.0', | version_number: '1.0', | ||||
source_url: 'https://github.com/tootsuite/mastodon', | source_url: 'https://github.com/tootsuite/mastodon', | ||||
open_registrations: false, | open_registrations: false, | ||||
thumbnail: nil, | |||||
closed_registrations_message: 'yes') | closed_registrations_message: 'yes') | ||||
assign(:instance_presenter, instance_presenter) | assign(:instance_presenter, instance_presenter) | ||||
render | render | ||||
header_tags = view.content_for(:header_tags) | 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 | ||||
end | end |