Require private asciicasts to be requested via secret token
This commit is contained in:
parent
6aeb8810ad
commit
2c7d549778
@ -19,7 +19,7 @@ module Api
|
||||
end
|
||||
|
||||
def show
|
||||
@asciicast = Asciicast.find(params[:id])
|
||||
@asciicast = Asciicast.find_by_id_or_secret_token!(params[:id])
|
||||
|
||||
respond_with(asciicast) do |format|
|
||||
format.html do
|
||||
|
@ -15,6 +15,7 @@ class AsciicastsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
# TODO: filter out private or not (????)
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
view_counter.increment(asciicast, cookies)
|
||||
@ -69,7 +70,7 @@ class AsciicastsController < ApplicationController
|
||||
private
|
||||
|
||||
def load_resource
|
||||
@asciicast = Asciicast.find(params[:id])
|
||||
@asciicast = Asciicast.find_by_id_or_secret_token!(params[:id])
|
||||
end
|
||||
|
||||
def view_counter
|
||||
|
@ -30,6 +30,14 @@ class Asciicast < ActiveRecord::Base
|
||||
|
||||
before_create :generate_secret_token
|
||||
|
||||
def self.find_by_id_or_secret_token!(thing)
|
||||
if thing.size == 25
|
||||
find_by_secret_token!(thing)
|
||||
else
|
||||
non_private.find(thing)
|
||||
end
|
||||
end
|
||||
|
||||
def self.cache_key
|
||||
timestamps = scoped.select(:updated_at).map { |o| o.updated_at.to_i }
|
||||
Digest::MD5.hexdigest timestamps.join('/')
|
||||
@ -67,6 +75,14 @@ class Asciicast < ActiveRecord::Base
|
||||
SecureRandom.hex.to_i(16).to_s(36).rjust(25, '0')
|
||||
end
|
||||
|
||||
def to_param
|
||||
if private?
|
||||
secret_token
|
||||
else
|
||||
id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def stdout
|
||||
return @stdout if @stdout
|
||||
@stdout = Stdout::Buffered.new(get_stdout)
|
||||
|
@ -103,16 +103,20 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def public_asciicast_count
|
||||
asciicasts.non_private.count
|
||||
end
|
||||
|
||||
def asciicast_count
|
||||
asciicasts.count
|
||||
end
|
||||
|
||||
def asciicasts_excluding(asciicast, limit)
|
||||
asciicasts.where('id <> ?', asciicast.id).order('RANDOM()').limit(limit)
|
||||
def other_asciicasts(asciicast, limit)
|
||||
asciicasts.non_private.where('id <> ?', asciicast.id).order('RANDOM()').limit(limit)
|
||||
end
|
||||
|
||||
def paged_asciicasts(page, per_page)
|
||||
asciicasts.
|
||||
def paged_asciicasts(page, per_page, include_private)
|
||||
asciicasts_scope(include_private).
|
||||
includes(:user).
|
||||
order("created_at DESC").
|
||||
paginate(page, per_page)
|
||||
@ -134,4 +138,12 @@ class User < ActiveRecord::Base
|
||||
end while self.class.exists?(auth_token: self[:auth_token])
|
||||
end
|
||||
|
||||
def asciicasts_scope(include_private)
|
||||
if include_private
|
||||
asciicasts
|
||||
else
|
||||
asciicasts.non_private
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -118,12 +118,8 @@ class AsciicastPagePresenter
|
||||
end
|
||||
end
|
||||
|
||||
def show_other_asciicasts_by_author?
|
||||
author.asciicast_count > 1
|
||||
end
|
||||
|
||||
def other_asciicasts_by_author
|
||||
author.asciicasts_excluding(asciicast, 3).decorate
|
||||
@other_asciicasts_by_author ||= author.other_asciicasts(asciicast, 3).decorate
|
||||
end
|
||||
|
||||
def asciicast_oembed_url(format)
|
||||
|
@ -39,15 +39,17 @@ class UserPagePresenter
|
||||
|
||||
def asciicast_count_text(h)
|
||||
if current_users_profile?
|
||||
if user.asciicast_count > 0
|
||||
count = h.pluralize(user.asciicast_count, 'asciicast')
|
||||
count = user.asciicast_count
|
||||
if count > 0
|
||||
count = h.pluralize(count, 'asciicast')
|
||||
"You have recorded #{count}"
|
||||
else
|
||||
"Record your first asciicast"
|
||||
end
|
||||
else
|
||||
if user.asciicast_count > 0
|
||||
count = h.pluralize(user.asciicast_count, 'asciicast')
|
||||
count = user.public_asciicast_count
|
||||
if count > 0
|
||||
count = h.pluralize(count, 'asciicast')
|
||||
"#{count} by #{user.display_name}"
|
||||
else
|
||||
"#{user.display_name} hasn't recorded anything yet"
|
||||
@ -70,7 +72,8 @@ class UserPagePresenter
|
||||
private
|
||||
|
||||
def get_asciicasts
|
||||
PaginatingDecorator.new(user.paged_asciicasts(page, per_page))
|
||||
asciicasts = user.paged_asciicasts(page, per_page, current_users_profile?)
|
||||
PaginatingDecorator.new(asciicasts)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -82,7 +82,7 @@
|
||||
.container
|
||||
.content = page.description
|
||||
|
||||
- if page.show_other_asciicasts_by_author?
|
||||
- unless page.other_asciicasts_by_author.empty?
|
||||
section.even
|
||||
.container
|
||||
.other-asciicasts
|
||||
|
@ -1,5 +1,24 @@
|
||||
require 'rails_helper'
|
||||
|
||||
shared_examples_for "asciicast iframe response" do
|
||||
it "responds with status 200" do
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
|
||||
it "responds with html content type" do
|
||||
expect(response.headers['Content-Type']).to match('text/html')
|
||||
end
|
||||
|
||||
it "responds without X-Frame-Options header" do
|
||||
pending "the header is added back by Rails only in tests O_o"
|
||||
expect(response.headers).to_not have_key('Content-Type')
|
||||
end
|
||||
|
||||
it "responds with player page using iframe layout" do
|
||||
expect(response.body).to have_selector('body.iframe div.player')
|
||||
end
|
||||
end
|
||||
|
||||
describe "Asciicast retrieval" do
|
||||
|
||||
let(:asciicast) { create(:asciicast) }
|
||||
@ -18,24 +37,15 @@ describe "Asciicast retrieval" do
|
||||
include Capybara::RSpecMatchers
|
||||
|
||||
before do
|
||||
get "/api/asciicasts/#{asciicast.id}", format: 'html'
|
||||
get "/api/asciicasts/#{asciicast.to_param}", format: 'html'
|
||||
end
|
||||
|
||||
it "responds with status 200" do
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
it_behaves_like "asciicast iframe response"
|
||||
|
||||
it "responds with html content type" do
|
||||
expect(response.headers['Content-Type']).to match('text/html')
|
||||
end
|
||||
context "for private asciicast" do
|
||||
let(:asciicast) { create(:asciicast, private: true) }
|
||||
|
||||
it "responds without X-Frame-Options header" do
|
||||
pending "the header is added back by Rails only in tests O_o"
|
||||
expect(response.headers).to_not have_key('Content-Type')
|
||||
end
|
||||
|
||||
it "responds with player page using iframe layout" do
|
||||
expect(response.body).to have_selector('body.iframe div.player')
|
||||
it_behaves_like "asciicast iframe response"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -41,7 +41,7 @@ describe AsciicastsController do
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:view_counter) { view_counter }
|
||||
expect(Asciicast).to receive(:find).and_return(asciicast)
|
||||
expect(Asciicast).to receive(:find_by_id_or_secret_token!).and_return(asciicast)
|
||||
end
|
||||
|
||||
let(:asciicast_presenter) { double('asciicast_presenter') }
|
||||
@ -74,7 +74,7 @@ describe AsciicastsController do
|
||||
let(:make_request) { get :edit, :id => asciicast.id }
|
||||
|
||||
before do
|
||||
expect(Asciicast).to receive(:find).and_return(asciicast)
|
||||
expect(Asciicast).to receive(:find_by_id_or_secret_token!).and_return(asciicast)
|
||||
asciicast.user = user
|
||||
end
|
||||
|
||||
@ -114,7 +114,7 @@ describe AsciicastsController do
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:asciicast_updater) { asciicast_updater }
|
||||
expect(Asciicast).to receive(:find).and_return(asciicast)
|
||||
expect(Asciicast).to receive(:find_by_id_or_secret_token!).and_return(asciicast)
|
||||
asciicast.user = user
|
||||
end
|
||||
|
||||
@ -165,7 +165,7 @@ describe AsciicastsController do
|
||||
let(:make_request) { delete :destroy, :id => asciicast.id }
|
||||
|
||||
before do
|
||||
expect(Asciicast).to receive(:find).and_return(asciicast)
|
||||
expect(Asciicast).to receive(:find_by_id_or_secret_token!).and_return(asciicast)
|
||||
asciicast.user = user
|
||||
end
|
||||
|
||||
|
@ -3,6 +3,44 @@ require 'tempfile'
|
||||
|
||||
describe Asciicast do
|
||||
|
||||
describe '.find_by_id_or_secret_token!' do
|
||||
subject { Asciicast.find_by_id_or_secret_token!(thing) }
|
||||
|
||||
context 'for public asciicast' do
|
||||
let(:asciicast) { create(:asciicast, private: false) }
|
||||
|
||||
context 'when looked up by id' do
|
||||
let(:thing) { asciicast.id }
|
||||
|
||||
it { should eq(asciicast) }
|
||||
end
|
||||
|
||||
context 'when looked up by secret token' do
|
||||
let(:thing) { asciicast.secret_token }
|
||||
|
||||
it { should eq(asciicast) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'for private asciicast' do
|
||||
let(:asciicast) { create(:asciicast, private: true) }
|
||||
|
||||
context 'when looked up by id' do
|
||||
let(:thing) { asciicast.id }
|
||||
|
||||
it 'raises RecordNotFound' do
|
||||
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when looked up by secret token' do
|
||||
let(:thing) { asciicast.secret_token }
|
||||
|
||||
it { should eq(asciicast) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.for_category_ordered' do
|
||||
subject { described_class.for_category_ordered(category, order) }
|
||||
|
||||
@ -52,7 +90,27 @@ describe Asciicast do
|
||||
end
|
||||
end
|
||||
|
||||
let(:asciicast) { described_class.new }
|
||||
describe '#to_param' do
|
||||
subject { asciicast.to_param }
|
||||
|
||||
let(:asciicast) { Asciicast.new(id: 123, secret_token: 'sekrit') }
|
||||
|
||||
context 'for public asciicast' do
|
||||
before do
|
||||
asciicast.private = false
|
||||
end
|
||||
|
||||
it { should eq('123') }
|
||||
end
|
||||
|
||||
context 'for private asciicast' do
|
||||
before do
|
||||
asciicast.private = true
|
||||
end
|
||||
|
||||
it { should eq('sekrit') }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#stdout' do
|
||||
context 'for single-file, JSON asciicast' do
|
||||
|
@ -148,8 +148,8 @@ describe User do
|
||||
it { should eq(2) }
|
||||
end
|
||||
|
||||
describe '#asciicasts_excluding' do
|
||||
subject { user.asciicasts_excluding(asciicast, 1) }
|
||||
describe '#other_asciicasts' do
|
||||
subject { user.other_asciicasts(asciicast, 1) }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:asciicast) { create(:asciicast, user: user) }
|
||||
|
@ -155,26 +155,6 @@ describe AsciicastPagePresenter do
|
||||
it { should eq('i am description') }
|
||||
end
|
||||
|
||||
describe '#show_other_asciicasts_by_author?' do
|
||||
subject { presenter.show_other_asciicasts_by_author? }
|
||||
|
||||
before do
|
||||
allow(author).to receive(:asciicast_count) { count }
|
||||
end
|
||||
|
||||
context "when user has more than 1 asciicast" do
|
||||
let(:count) { 2 }
|
||||
|
||||
it { should be(true) }
|
||||
end
|
||||
|
||||
context "when user doesn't have more than 1 asciicasts" do
|
||||
let(:count) { 1 }
|
||||
|
||||
it { should be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#other_asciicasts_by_author' do
|
||||
subject { presenter.other_asciicasts_by_author }
|
||||
|
||||
@ -182,7 +162,7 @@ describe AsciicastPagePresenter do
|
||||
let(:decorated_others) { double('decorated_others') }
|
||||
|
||||
before do
|
||||
allow(author).to receive(:asciicasts_excluding).
|
||||
allow(author).to receive(:other_asciicasts).
|
||||
with(asciicast, 3) { others }
|
||||
end
|
||||
|
||||
|
@ -117,11 +117,23 @@ describe UserPagePresenter do
|
||||
describe '#asciicast_count_text' do
|
||||
subject { presenter.asciicast_count_text(view_context) }
|
||||
|
||||
context 'for non author' do
|
||||
before do
|
||||
allow(user).to receive(:public_asciicast_count) { 2 }
|
||||
end
|
||||
|
||||
it { should match(/2.+cartman/) }
|
||||
end
|
||||
|
||||
context 'for author' do
|
||||
let(:current_user) { user }
|
||||
|
||||
before do
|
||||
allow(user).to receive(:asciicast_count) { 3 }
|
||||
end
|
||||
|
||||
it { should eq('3 asciicasts by cartman') }
|
||||
it { should match(/you.+3/i) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#user_username' do
|
||||
@ -143,7 +155,7 @@ describe UserPagePresenter do
|
||||
it "gets user's asciicasts paged" do
|
||||
subject
|
||||
|
||||
expect(user).to have_received(:paged_asciicasts).with(2, 5)
|
||||
expect(user).to have_received(:paged_asciicasts).with(2, 5, false)
|
||||
end
|
||||
|
||||
it "wraps the asciicasts with paginating decorator" do
|
||||
|
Loading…
Reference in New Issue
Block a user