Browse Source

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
pull/4/head
Eugen Rochko 7 years ago
committed by GitHub
parent
commit
e95bdec7c5
15 changed files with 101 additions and 55 deletions
  1. +4
    -4
      app/controllers/api/oembed_controller.rb
  2. +5
    -0
      app/controllers/statuses_controller.rb
  3. +1
    -4
      app/controllers/stream_entries_controller.rb
  4. +1
    -1
      app/helpers/stream_entries_helper.rb
  5. +7
    -0
      app/javascript/packs/public.js
  6. +30
    -0
      app/javascript/styles/stream_entries.scss
  7. +4
    -4
      app/lib/status_finder.rb
  8. +2
    -2
      app/serializers/oembed_serializer.rb
  9. +5
    -0
      app/views/stream_entries/_detailed_status.html.haml
  10. +3
    -2
      app/views/stream_entries/embed.html.haml
  11. +25
    -25
      config/brakeman.ignore
  12. +3
    -2
      config/environments/development.rb
  13. +2
    -0
      config/routes.rb
  14. +2
    -4
      spec/controllers/stream_entries_controller_spec.rb
  15. +7
    -7
      spec/lib/status_finder_spec.rb

+ 4
- 4
app/controllers/api/oembed_controller.rb View File

@ -4,14 +4,14 @@ class Api::OEmbedController < Api::BaseController
respond_to :json
def show
@stream_entry = find_stream_entry.stream_entry
render json: @stream_entry, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default
@status = status_finder.status
render json: @status, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default
end
private
def find_stream_entry
StreamEntryFinder.new(params[:url])
def status_finder
StatusFinder.new(params[:url])
end
def maxwidth_or_default

+ 5
- 0
app/controllers/statuses_controller.rb View File

@ -30,6 +30,11 @@ class StatusesController < ApplicationController
render json: @status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
end
def embed
response.headers['X-Frame-Options'] = 'ALLOWALL'
render 'stream_entries/embed', layout: 'embedded'
end
private
def set_account

+ 1
- 4
app/controllers/stream_entries_controller.rb View File

@ -25,10 +25,7 @@ class StreamEntriesController < ApplicationController
end
def embed
response.headers['X-Frame-Options'] = 'ALLOWALL'
return gone if @stream_entry.activity.nil?
render layout: 'embedded'
redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301
end
private

+ 1
- 1
app/helpers/stream_entries_helper.rb View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module StreamEntriesHelper
EMBEDDED_CONTROLLER = 'stream_entries'
EMBEDDED_CONTROLLER = 'statuses'
EMBEDDED_ACTION = 'embed'
def display_name(account)

+ 7
- 0
app/javascript/packs/public.js View File

@ -38,6 +38,13 @@ function main() {
content.title = dateTimeFormat.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 }) => {

+ 30
- 0
app/javascript/styles/stream_entries.scss View File

@ -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%);
}
}
}

app/lib/stream_entry_finder.rb → app/lib/status_finder.rb View File

@ -1,20 +1,20 @@
# frozen_string_literal: true
class StreamEntryFinder
class StatusFinder
attr_reader :url
def initialize(url)
@url = url
end
def stream_entry
def status
verify_action!
case recognized_params[:controller]
when 'stream_entries'
StreamEntry.find(recognized_params[:id])
StreamEntry.find(recognized_params[:id]).status
when 'statuses'
Status.find(recognized_params[:id]).stream_entry
Status.find(recognized_params[:id])
else
raise ActiveRecord::RecordNotFound
end

+ 2
- 2
app/serializers/oembed_serializer.rb View File

@ -21,7 +21,7 @@ class OEmbedSerializer < ActiveModel::Serializer
end
def author_url
account_url(object.account)
short_account_url(object.account)
end
def provider_name
@ -38,7 +38,7 @@ class OEmbedSerializer < ActiveModel::Serializer
def html
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',
frameborder: '0',
scrolling: 'no',

+ 5
- 0
app/views/stream_entries/_detailed_status.html.haml View File

@ -1,4 +1,9 @@
.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
%div
.avatar

+ 3
- 2
app/views/stream_entries/embed.html.haml View File

@ -1,2 +1,3 @@
.activity-stream.activity-stream-headless
= render @type, @type.to_sym => @stream_entry.activity, centered: true
- cache @stream_entry.activity do
.activity-stream.activity-stream-headless
= render "stream_entries/#{@type}", @type.to_sym => @stream_entry.activity, centered: true

+ 25
- 25
config/brakeman.ignore View File

@ -1,5 +1,24 @@
{
"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_code": 15,
@ -7,10 +26,10 @@
"check_name": "Render",
"message": "Render path contains parameter value",
"file": "app/views/admin/accounts/index.html.haml",
"line": 32,
"line": 63,
"link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
"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": {
"type": "template",
"template": "admin/accounts/index"
@ -39,25 +58,6 @@
"confidence": "High",
"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_code": 15,
@ -84,10 +84,10 @@
"check_name": "Render",
"message": "Render path contains parameter value",
"file": "app/views/stream_entries/show.html.haml",
"line": 19,
"line": 23,
"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 }) })",
"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": {
"type": "template",
"template": "stream_entries/show"
@ -97,6 +97,6 @@
"note": ""
}
],
"updated": "2017-05-07 08:26:06 +0900",
"brakeman_version": "3.6.1"
"updated": "2017-08-30 05:14:04 +0200",
"brakeman_version": "3.7.2"
}

+ 3
- 2
config/environments/development.rb View File

@ -16,9 +16,10 @@ Rails.application.configure do
if Rails.root.join('tmp/caching-dev.txt').exist?
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 = {
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}",
}
else
config.action_controller.perform_caching = false

+ 2
- 0
config/routes.rb View File

@ -44,6 +44,7 @@ Rails.application.routes.draw do
resources :statuses, only: [:show] do
member do
get :activity
get :embed
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/media', to: 'accounts#show', as: :short_account_media
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
resource :profile, only: [:show, :update]

+ 2
- 4
spec/controllers/stream_entries_controller_spec.rb View File

@ -88,14 +88,12 @@ RSpec.describe StreamEntriesController, type: :controller do
describe 'GET #embed' do
include_examples 'before_action', :embed
it 'returns embedded view of status' do
it 'redirects to new embed page' do
status = Fabricate(:status)
get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
expect(response).to have_http_status(:success)
expect(response.headers['X-Frame-Options']).to eq 'ALLOWALL'
expect(response).to render_template(layout: 'embedded')
expect(response).to redirect_to(embed_short_account_status_url(status.account, status))
end
end
end

spec/lib/stream_entry_finder_spec.rb → spec/lib/status_finder_spec.rb View File

@ -2,17 +2,17 @@
require 'rails_helper'
describe StreamEntryFinder do
describe StatusFinder do
include RoutingHelper
describe '#stream_entry' do
describe '#status' do
context 'with a status url' do
let(:status) { Fabricate(:status) }
let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) }
subject { described_class.new(url) }
it 'finds the stream entry' do
expect(subject.stream_entry).to eq(status.stream_entry)
expect(subject.status).to eq(status)
end
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(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
@ -30,7 +30,7 @@ describe StreamEntryFinder do
subject { described_class.new(url) }
it 'finds the stream entry' do
expect(subject.stream_entry).to eq(stream_entry)
expect(subject.status).to eq(stream_entry.status)
end
end
@ -39,7 +39,7 @@ describe StreamEntryFinder do
subject { described_class.new(url) }
it 'raises an error' do
expect { subject.stream_entry }.to raise_error(ActiveRecord::RecordNotFound)
expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound)
end
end
@ -48,7 +48,7 @@ describe StreamEntryFinder do
subject { described_class.new(url) }
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

Loading…
Cancel
Save