diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 1503e62..f94967c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -19,4 +19,8 @@ $(function() { $('input[data-behavior=focus]:first').focus().select(); $('[data-toggle="popover"]').popover({ html: true }); + + if ($('meta[name=referrer][content=none]').length > 0) { + $('a[href*=http]').attr('rel', 'noreferrer'); + } }); diff --git a/app/controllers/api/asciicasts_controller.rb b/app/controllers/api/asciicasts_controller.rb index 285b5dc..a5afab9 100644 --- a/app/controllers/api/asciicasts_controller.rb +++ b/app/controllers/api/asciicasts_controller.rb @@ -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 diff --git a/app/controllers/asciicasts_controller.rb b/app/controllers/asciicasts_controller.rb index f0eeea7..3808706 100644 --- a/app/controllers/asciicasts_controller.rb +++ b/app/controllers/asciicasts_controller.rb @@ -69,7 +69,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 diff --git a/app/decorators/asciicast_decorator.rb b/app/decorators/asciicast_decorator.rb index dc5988c..1d8ea05 100644 --- a/app/decorators/asciicast_decorator.rb +++ b/app/decorators/asciicast_decorator.rb @@ -26,7 +26,7 @@ class AsciicastDecorator < ApplicationDecorator end def title - model.title.presence || command || "asciicast:#{id}" + model.title.presence || command || "asciicast:#{to_param}" end def command diff --git a/app/models/asciicast.rb b/app/models/asciicast.rb index 8164f0a..be772ea 100644 --- a/app/models/asciicast.rb +++ b/app/models/asciicast.rb @@ -24,10 +24,19 @@ class Asciicast < ActiveRecord::Base scope :featured, -> { where(featured: true) } scope :by_recency, -> { order("created_at DESC") } scope :by_random, -> { order("RANDOM()") } - scope :latest_limited, -> (n) { by_recency.limit(n).includes(:user) } - scope :random_featured_limited, -> (n) { - featured.by_random.limit(n).includes(:user) - } + scope :non_private, -> { where(private: false) } + scope :homepage_latest, -> { non_private.by_recency.limit(6).includes(:user) } + scope :homepage_featured, -> { non_private.featured.by_random.limit(6).includes(:user) } + + 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 } @@ -39,7 +48,7 @@ class Asciicast < ActiveRecord::Base end def self.for_category_ordered(category, order, page = nil, per_page = nil) - collection = all + collection = non_private if category == :featured collection = collection.featured @@ -62,6 +71,18 @@ class Asciicast < ActiveRecord::Base value ? super(value.strip[0...255]) : super end + def self.generate_secret_token + 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) @@ -86,6 +107,10 @@ class Asciicast < ActiveRecord::Base !image.file || (image.file.filename != image_filename) end + def owner?(user) + user && self.user == user + end + private def get_stdout @@ -103,4 +128,10 @@ class Asciicast < ActiveRecord::Base Digest::SHA1.hexdigest(input) end + def generate_secret_token + begin + self.secret_token = self.class.generate_secret_token + end while self.class.exists?(secret_token: secret_token) + end + end diff --git a/app/models/user.rb b/app/models/user.rb index 2534092..457e8f7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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) @@ -131,7 +135,15 @@ class User < ActiveRecord::Base def generate_auth_token begin self[:auth_token] = self.class.generate_auth_token - end while User.exists?(auth_token: self[:auth_token]) + 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 diff --git a/app/policies/asciicast_policy.rb b/app/policies/asciicast_policy.rb index 707c257..7b6bf87 100644 --- a/app/policies/asciicast_policy.rb +++ b/app/policies/asciicast_policy.rb @@ -7,9 +7,10 @@ class AsciicastPolicy < ApplicationPolicy end def permitted_attributes - if user.admin? || record.user == user + if user.admin? || record.owner?(user) attrs = [:title, :description, :theme_name, :snapshot_at] - attrs << :featured if user.admin? + attrs << :featured if change_featured? + attrs << :private if change_visibility? attrs else @@ -20,22 +21,22 @@ class AsciicastPolicy < ApplicationPolicy def update? return false unless user - user.admin? || record.user == user + user.admin? || record.owner?(user) end def destroy? return false unless user - user.admin? || record.user == user + user.admin? || record.owner?(user) end - def feature? + def change_featured? return false unless user user.admin? end - def unfeature? + def change_visibility? return false unless user user.admin? diff --git a/app/presenters/asciicast_page_presenter.rb b/app/presenters/asciicast_page_presenter.rb index fa70729..d105967 100644 --- a/app/presenters/asciicast_page_presenter.rb +++ b/app/presenters/asciicast_page_presenter.rb @@ -87,11 +87,19 @@ class AsciicastPagePresenter end def show_set_featured_link? - !asciicast.featured? && policy.feature? + !asciicast.featured? && policy.change_featured? end def show_unset_featured_link? - asciicast.featured? && policy.unfeature? + asciicast.featured? && policy.change_featured? + end + + def show_make_private_link? + !asciicast.private? && policy.change_visibility? + end + + def show_make_public_link? + asciicast.private? && policy.change_visibility? end def show_description? @@ -110,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) diff --git a/app/presenters/bare_asciicast_page_presenter.rb b/app/presenters/bare_asciicast_page_presenter.rb index 35daf51..0cc313a 100644 --- a/app/presenters/bare_asciicast_page_presenter.rb +++ b/app/presenters/bare_asciicast_page_presenter.rb @@ -18,7 +18,7 @@ class BareAsciicastPagePresenter end def asciicast_id - asciicast.id + asciicast.to_param end end diff --git a/app/presenters/home_page_presenter.rb b/app/presenters/home_page_presenter.rb index d37e69d..1e7ac91 100644 --- a/app/presenters/home_page_presenter.rb +++ b/app/presenters/home_page_presenter.rb @@ -11,11 +11,11 @@ class HomePagePresenter end def latest_asciicasts - Asciicast.latest_limited(6).decorate + Asciicast.homepage_latest.decorate end def featured_asciicasts - Asciicast.random_featured_limited(6).decorate + Asciicast.homepage_featured.decorate end def install_script_url diff --git a/app/presenters/user_page_presenter.rb b/app/presenters/user_page_presenter.rb index adebd16..820f1e5 100644 --- a/app/presenters/user_page_presenter.rb +++ b/app/presenters/user_page_presenter.rb @@ -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 diff --git a/app/serializers/asciicast_serializer.rb b/app/serializers/asciicast_serializer.rb index add532f..e52b926 100644 --- a/app/serializers/asciicast_serializer.rb +++ b/app/serializers/asciicast_serializer.rb @@ -4,4 +4,9 @@ class AsciicastSerializer < ActiveModel::Serializer attributes :id, :duration, :stdout_frames_url, :snapshot attribute :terminal_columns, key: :width attribute :terminal_lines, key: :height + + def private? + object.private? + end + end diff --git a/app/views/api/asciicasts/show.html.slim b/app/views/api/asciicasts/show.html.slim index 0479350..1cff2e9 100644 --- a/app/views/api/asciicasts/show.html.slim +++ b/app/views/api/asciicasts/show.html.slim @@ -9,7 +9,7 @@ javascript: if (typeof target != "undefined" && window !== window.parent) { var w = $('.asciinema-player').width(); var h = $(document).height(); - target.postMessage(['asciicast:size', { id: #{page.asciicast_id}, width: w, height: h }], '*'); + target.postMessage(['asciicast:size', { id: '#{page.asciicast_id}', width: w, height: h }], '*'); } function onMessage(e) { diff --git a/app/views/asciicasts/_player.html.erb b/app/views/asciicasts/_player.html.erb index 4d82cbb..2e25b70 100644 --- a/app/views/asciicasts/_player.html.erb +++ b/app/views/asciicasts/_player.html.erb @@ -1,3 +1,10 @@ +<% if asciicast.private? %> + <% content_for(:head) do %> + + + <% end %> +<% end %> +