forked from cybrespace/mastodon
Update status embeds (#4742)
- Use statuses controller for embeds instead of stream entries controller - Prefer /@:username/:id/embed URL for embeds - Use /@:username as author_url in OEmbed - Add follow link to embeds which opens web intent in new window - Use redis cache in development - Cache entire embed
This commit is contained in:
parent
fcca31350d
commit
e95bdec7c5
|
@ -4,14 +4,14 @@ class Api::OEmbedController < Api::BaseController
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@stream_entry = find_stream_entry.stream_entry
|
@status = status_finder.status
|
||||||
render json: @stream_entry, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default
|
render json: @status, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_stream_entry
|
def status_finder
|
||||||
StreamEntryFinder.new(params[:url])
|
StatusFinder.new(params[:url])
|
||||||
end
|
end
|
||||||
|
|
||||||
def maxwidth_or_default
|
def maxwidth_or_default
|
||||||
|
|
|
@ -30,6 +30,11 @@ class StatusesController < ApplicationController
|
||||||
render json: @status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
render json: @status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def embed
|
||||||
|
response.headers['X-Frame-Options'] = 'ALLOWALL'
|
||||||
|
render 'stream_entries/embed', layout: 'embedded'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
|
|
@ -25,10 +25,7 @@ class StreamEntriesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def embed
|
def embed
|
||||||
response.headers['X-Frame-Options'] = 'ALLOWALL'
|
redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301
|
||||||
return gone if @stream_entry.activity.nil?
|
|
||||||
|
|
||||||
render layout: 'embedded'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module StreamEntriesHelper
|
module StreamEntriesHelper
|
||||||
EMBEDDED_CONTROLLER = 'stream_entries'
|
EMBEDDED_CONTROLLER = 'statuses'
|
||||||
EMBEDDED_ACTION = 'embed'
|
EMBEDDED_ACTION = 'embed'
|
||||||
|
|
||||||
def display_name(account)
|
def display_name(account)
|
||||||
|
|
|
@ -38,6 +38,13 @@ function main() {
|
||||||
content.title = dateTimeFormat.format(datetime);
|
content.title = dateTimeFormat.format(datetime);
|
||||||
content.textContent = relativeFormat.format(datetime);
|
content.textContent = relativeFormat.format(datetime);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[].forEach.call(document.querySelectorAll('.logo-button'), (content) => {
|
||||||
|
content.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
window.open(e.target.href, 'mastodon-intent', 'width=400,height=400,resizable=no,menubar=no,status=no,scrollbars=yes');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
delegate(document, '.video-player video', 'click', ({ target }) => {
|
delegate(document, '.video-player video', 'click', ({ target }) => {
|
||||||
|
|
|
@ -421,3 +421,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button.button-secondary.logo-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 14px;
|
||||||
|
top: 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 20px;
|
||||||
|
height: auto;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
path:first-child {
|
||||||
|
fill: $ui-primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
path:last-child {
|
||||||
|
fill: $simple-background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
svg path:first-child {
|
||||||
|
fill: lighten($ui-primary-color, 4%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class StreamEntryFinder
|
class StatusFinder
|
||||||
attr_reader :url
|
attr_reader :url
|
||||||
|
|
||||||
def initialize(url)
|
def initialize(url)
|
||||||
@url = url
|
@url = url
|
||||||
end
|
end
|
||||||
|
|
||||||
def stream_entry
|
def status
|
||||||
verify_action!
|
verify_action!
|
||||||
|
|
||||||
case recognized_params[:controller]
|
case recognized_params[:controller]
|
||||||
when 'stream_entries'
|
when 'stream_entries'
|
||||||
StreamEntry.find(recognized_params[:id])
|
StreamEntry.find(recognized_params[:id]).status
|
||||||
when 'statuses'
|
when 'statuses'
|
||||||
Status.find(recognized_params[:id]).stream_entry
|
Status.find(recognized_params[:id])
|
||||||
else
|
else
|
||||||
raise ActiveRecord::RecordNotFound
|
raise ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
|
@ -21,7 +21,7 @@ class OEmbedSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def author_url
|
def author_url
|
||||||
account_url(object.account)
|
short_account_url(object.account)
|
||||||
end
|
end
|
||||||
|
|
||||||
def provider_name
|
def provider_name
|
||||||
|
@ -38,7 +38,7 @@ class OEmbedSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
def html
|
def html
|
||||||
tag :iframe,
|
tag :iframe,
|
||||||
src: embed_account_stream_entry_url(object.account, object),
|
src: embed_short_account_status_url(object.account, object),
|
||||||
style: 'width: 100%; overflow: hidden',
|
style: 'width: 100%; overflow: hidden',
|
||||||
frameborder: '0',
|
frameborder: '0',
|
||||||
scrolling: 'no',
|
scrolling: 'no',
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
.detailed-status.light
|
.detailed-status.light
|
||||||
|
- if embedded_view?
|
||||||
|
= link_to "web+mastodon://follow?uri=#{status.account.local_username_and_domain}", class: 'button button-secondary logo-button', target: '_new' do
|
||||||
|
= render file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')
|
||||||
|
= t('accounts.follow')
|
||||||
|
|
||||||
= link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do
|
= link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do
|
||||||
%div
|
%div
|
||||||
.avatar
|
.avatar
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
.activity-stream.activity-stream-headless
|
- cache @stream_entry.activity do
|
||||||
= render @type, @type.to_sym => @stream_entry.activity, centered: true
|
.activity-stream.activity-stream-headless
|
||||||
|
= render "stream_entries/#{@type}", @type.to_sym => @stream_entry.activity, centered: true
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
{
|
{
|
||||||
"ignored_warnings": [
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"warning_type": "Dynamic Render Path",
|
||||||
|
"warning_code": 15,
|
||||||
|
"fingerprint": "44d3f14e05d8fbb5b23e13ac02f15aa38b2a2f0f03b9ba76bab7f98e155a4a4e",
|
||||||
|
"check_name": "Render",
|
||||||
|
"message": "Render path contains parameter value",
|
||||||
|
"file": "app/views/stream_entries/embed.html.haml",
|
||||||
|
"line": 3,
|
||||||
|
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
||||||
|
"code": "render(action => \"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\", { Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :centered => true })",
|
||||||
|
"render_path": [{"type":"controller","class":"StatusesController","method":"embed","line":35,"file":"app/controllers/statuses_controller.rb"}],
|
||||||
|
"location": {
|
||||||
|
"type": "template",
|
||||||
|
"template": "stream_entries/embed"
|
||||||
|
},
|
||||||
|
"user_input": "params[:id]",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"warning_type": "Dynamic Render Path",
|
"warning_type": "Dynamic Render Path",
|
||||||
"warning_code": 15,
|
"warning_code": 15,
|
||||||
|
@ -7,10 +26,10 @@
|
||||||
"check_name": "Render",
|
"check_name": "Render",
|
||||||
"message": "Render path contains parameter value",
|
"message": "Render path contains parameter value",
|
||||||
"file": "app/views/admin/accounts/index.html.haml",
|
"file": "app/views/admin/accounts/index.html.haml",
|
||||||
"line": 32,
|
"line": 63,
|
||||||
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
||||||
"code": "render(action => filtered_accounts.page(params[:page]), {})",
|
"code": "render(action => filtered_accounts.page(params[:page]), {})",
|
||||||
"render_path": [{"type":"controller","class":"Admin::AccountsController","method":"index","line":7,"file":"app/controllers/admin/accounts_controller.rb"}],
|
"render_path": [{"type":"controller","class":"Admin::AccountsController","method":"index","line":10,"file":"app/controllers/admin/accounts_controller.rb"}],
|
||||||
"location": {
|
"location": {
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"template": "admin/accounts/index"
|
"template": "admin/accounts/index"
|
||||||
|
@ -39,25 +58,6 @@
|
||||||
"confidence": "High",
|
"confidence": "High",
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"warning_type": "Dynamic Render Path",
|
|
||||||
"warning_code": 15,
|
|
||||||
"fingerprint": "c417f9d44ab05dd9cf3d5ec9df2324a5036774c151181787b32c4c940623191b",
|
|
||||||
"check_name": "Render",
|
|
||||||
"message": "Render path contains parameter value",
|
|
||||||
"file": "app/views/stream_entries/embed.html.haml",
|
|
||||||
"line": 2,
|
|
||||||
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
|
||||||
"code": "render(action => Account.find_local!(params[:account_username]).stream_entries.where(:activity_type => \"Status\").find(params[:id]).activity_type.downcase, { Account.find_local!(params[:account_username]).stream_entries.where(:activity_type => \"Status\").find(params[:id]).activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).stream_entries.where(:activity_type => \"Status\").find(params[:id]).activity, :centered => true })",
|
|
||||||
"render_path": [{"type":"controller","class":"StreamEntriesController","method":"embed","line":32,"file":"app/controllers/stream_entries_controller.rb"}],
|
|
||||||
"location": {
|
|
||||||
"type": "template",
|
|
||||||
"template": "stream_entries/embed"
|
|
||||||
},
|
|
||||||
"user_input": "params[:id]",
|
|
||||||
"confidence": "Weak",
|
|
||||||
"note": ""
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"warning_type": "Dynamic Render Path",
|
"warning_type": "Dynamic Render Path",
|
||||||
"warning_code": 15,
|
"warning_code": 15,
|
||||||
|
@ -84,10 +84,10 @@
|
||||||
"check_name": "Render",
|
"check_name": "Render",
|
||||||
"message": "Render path contains parameter value",
|
"message": "Render path contains parameter value",
|
||||||
"file": "app/views/stream_entries/show.html.haml",
|
"file": "app/views/stream_entries/show.html.haml",
|
||||||
"line": 19,
|
"line": 23,
|
||||||
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
|
||||||
"code": "render(partial => \"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\", { :locals => ({ Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :include_threads => true }) })",
|
"code": "render(partial => \"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\", { :locals => ({ Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :include_threads => true }) })",
|
||||||
"render_path": [{"type":"controller","class":"StatusesController","method":"show","line":15,"file":"app/controllers/statuses_controller.rb"}],
|
"render_path": [{"type":"controller","class":"StatusesController","method":"show","line":20,"file":"app/controllers/statuses_controller.rb"}],
|
||||||
"location": {
|
"location": {
|
||||||
"type": "template",
|
"type": "template",
|
||||||
"template": "stream_entries/show"
|
"template": "stream_entries/show"
|
||||||
|
@ -97,6 +97,6 @@
|
||||||
"note": ""
|
"note": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"updated": "2017-05-07 08:26:06 +0900",
|
"updated": "2017-08-30 05:14:04 +0200",
|
||||||
"brakeman_version": "3.6.1"
|
"brakeman_version": "3.7.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ Rails.application.configure do
|
||||||
if Rails.root.join('tmp/caching-dev.txt').exist?
|
if Rails.root.join('tmp/caching-dev.txt').exist?
|
||||||
config.action_controller.perform_caching = true
|
config.action_controller.perform_caching = true
|
||||||
|
|
||||||
config.cache_store = :memory_store
|
config.cache_store = :redis_store, ENV['REDIS_URL'], REDIS_CACHE_PARAMS
|
||||||
|
|
||||||
config.public_file_server.headers = {
|
config.public_file_server.headers = {
|
||||||
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
|
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}",
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
config.action_controller.perform_caching = false
|
config.action_controller.perform_caching = false
|
||||||
|
|
|
@ -44,6 +44,7 @@ Rails.application.routes.draw do
|
||||||
resources :statuses, only: [:show] do
|
resources :statuses, only: [:show] do
|
||||||
member do
|
member do
|
||||||
get :activity
|
get :activity
|
||||||
|
get :embed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ Rails.application.routes.draw do
|
||||||
get '/@:username/with_replies', to: 'accounts#show', as: :short_account_with_replies
|
get '/@:username/with_replies', to: 'accounts#show', as: :short_account_with_replies
|
||||||
get '/@:username/media', to: 'accounts#show', as: :short_account_media
|
get '/@:username/media', to: 'accounts#show', as: :short_account_media
|
||||||
get '/@:account_username/:id', to: 'statuses#show', as: :short_account_status
|
get '/@:account_username/:id', to: 'statuses#show', as: :short_account_status
|
||||||
|
get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status
|
||||||
|
|
||||||
namespace :settings do
|
namespace :settings do
|
||||||
resource :profile, only: [:show, :update]
|
resource :profile, only: [:show, :update]
|
||||||
|
|
|
@ -88,14 +88,12 @@ RSpec.describe StreamEntriesController, type: :controller do
|
||||||
describe 'GET #embed' do
|
describe 'GET #embed' do
|
||||||
include_examples 'before_action', :embed
|
include_examples 'before_action', :embed
|
||||||
|
|
||||||
it 'returns embedded view of status' do
|
it 'redirects to new embed page' do
|
||||||
status = Fabricate(:status)
|
status = Fabricate(:status)
|
||||||
|
|
||||||
get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
|
get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
expect(response).to redirect_to(embed_short_account_status_url(status.account, status))
|
||||||
expect(response.headers['X-Frame-Options']).to eq 'ALLOWALL'
|
|
||||||
expect(response).to render_template(layout: 'embedded')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe StreamEntryFinder do
|
describe StatusFinder do
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
describe '#stream_entry' do
|
describe '#status' do
|
||||||
context 'with a status url' do
|
context 'with a status url' do
|
||||||
let(:status) { Fabricate(:status) }
|
let(:status) { Fabricate(:status) }
|
||||||
let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) }
|
let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) }
|
||||||
subject { described_class.new(url) }
|
subject { described_class.new(url) }
|
||||||
|
|
||||||
it 'finds the stream entry' do
|
it 'finds the stream entry' do
|
||||||
expect(subject.stream_entry).to eq(status.stream_entry)
|
expect(subject.status).to eq(status)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error if action is not :show' do
|
it 'raises an error if action is not :show' do
|
||||||
|
@ -20,7 +20,7 @@ describe StreamEntryFinder do
|
||||||
expect(recognized).to receive(:[]).with(:action).and_return(:create)
|
expect(recognized).to receive(:[]).with(:action).and_return(:create)
|
||||||
expect(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized)
|
expect(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized)
|
||||||
|
|
||||||
expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ describe StreamEntryFinder do
|
||||||
subject { described_class.new(url) }
|
subject { described_class.new(url) }
|
||||||
|
|
||||||
it 'finds the stream entry' do
|
it 'finds the stream entry' do
|
||||||
expect(subject.stream_entry).to eq(stream_entry)
|
expect(subject.status).to eq(stream_entry.status)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ describe StreamEntryFinder do
|
||||||
subject { described_class.new(url) }
|
subject { described_class.new(url) }
|
||||||
|
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ describe StreamEntryFinder do
|
||||||
subject { described_class.new(url) }
|
subject { described_class.new(url) }
|
||||||
|
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
Reference in New Issue