diff --git a/app/assets/stylesheets/article-show.scss b/app/assets/stylesheets/article-show.scss index fb154ea6e..6e033bf3f 100644 --- a/app/assets/stylesheets/article-show.scss +++ b/app/assets/stylesheets/article-show.scss @@ -319,10 +319,6 @@ article { color: var(--body-color-inverted); } - &.coming-soon { - pointer-events: none; - color: lighten($black, 78%); - } &.collection-link-hidden { display: none; } diff --git a/app/assets/stylesheets/views/article.scss b/app/assets/stylesheets/views/article.scss index b3e7f72e8..a4c15c9f5 100644 --- a/app/assets/stylesheets/views/article.scss +++ b/app/assets/stylesheets/views/article.scss @@ -568,10 +568,6 @@ color: var(--body-color-inverted); } - &.coming-soon { - pointer-events: none; - color: var(--base-80); - } &.collection-link-hidden { display: none; } diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb index a7aa26848..ba20052af 100644 --- a/app/controllers/articles_controller.rb +++ b/app/controllers/articles_controller.rb @@ -112,7 +112,8 @@ class ArticlesController < ApplicationController def create authorize Article - article = Articles::Creator.call(current_user, article_params_json) + @user = current_user + article = Articles::Creator.call(@user, article_params_json) render json: if article.persisted? { id: article.id, current_state_path: article.decorate.current_state_path }.to_json diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb new file mode 100644 index 000000000..e44c48618 --- /dev/null +++ b/app/controllers/collections_controller.rb @@ -0,0 +1,12 @@ +class CollectionsController < ApplicationController + def index + @user = User.find_by!(username: params[:username]) + @collections = @user.collections.order(created_at: :desc) + end + + def show + @collection = Collection.find(params[:id]) + @user = @collection.user + @articles = @collection.articles.published.order(Arel.sql("COALESCE(crossposted_at, published_at) ASC")) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a2fea830e..5f5e4af7e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -193,6 +193,13 @@ module ApplicationHelper "#{start_year} - #{current_year}" end + def collection_link(collection, **kwargs) + size_string = "#{collection.articles.published.size} Part Series" + body = collection.slug.present? ? "#{collection.slug} (#{size_string})" : size_string + + link_to body, collection.path, **kwargs + end + def email_link(type = :default, text: nil, additional_info: nil) # The allowed types for type is :default, :business, :privacy, and members. # These options can be found in field :email_addresses of models/site_config.rb diff --git a/app/helpers/articles_helper.rb b/app/helpers/articles_helper.rb index 3cddec25a..95ea06888 100644 --- a/app/helpers/articles_helper.rb +++ b/app/helpers/articles_helper.rb @@ -17,14 +17,6 @@ module ArticlesHelper article.comments_blob.include?("youtube") end - def collection_link_class(current_article, linked_article) - if current_article.id == linked_article.id - "current-article" - elsif !linked_article.published - "coming-soon" - end - end - def image_tag_or_inline_svg_tag(service_name, width: nil, height: nil) name = "#{service_name}-logo.svg" diff --git a/app/models/collection.rb b/app/models/collection.rb index f2e0e4c76..fd6f52431 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -12,6 +12,10 @@ class Collection < ApplicationRecord Collection.find_or_create_by(slug: slug, user: user) end + def path + "/#{user.username}/series/#{id}" + end + private def touch_articles diff --git a/app/views/articles/_collection.html.erb b/app/views/articles/_collection.html.erb index 0c7d79d01..2fd9d54a4 100644 --- a/app/views/articles/_collection.html.erb +++ b/app/views/articles/_collection.html.erb @@ -3,11 +3,8 @@ <% if collection && collection_size > 1 %>
- <% if collection.slug.present? %> -

<%= collection.slug %> (<%= collection_size %> Part Series)

- <% else %> -

<%= collection_size %> Part Series

- <% end %> +

<%= collection_link(collection) %>

+
<% articles.each_with_index do |article, i| %> <% if collection_size > 5 && i == 2 %> @@ -24,7 +21,7 @@ 5 && (i > 1 && i < collection_size - 2) %>" + class="<%= "current-article" if rendered_article.id == article.id %> <%= "collection-link-hidden" if collection_size > 5 && (i > 1 && i < collection_size - 2) %>" data-preload-image="<%= cloud_cover_url(article.main_image) %>" title="Published <%= article.readable_publish_date %>"> <%= i + 1 %>) <%= article.title %> diff --git a/app/views/collections/_meta.html.erb b/app/views/collections/_meta.html.erb new file mode 100644 index 000000000..9f2499087 --- /dev/null +++ b/app/views/collections/_meta.html.erb @@ -0,0 +1,17 @@ +<% title title_string %> +" /> + + + + +" /> + + + + + + +"> + + + diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb new file mode 100644 index 000000000..6bfc9c2d5 --- /dev/null +++ b/app/views/collections/index.html.erb @@ -0,0 +1,25 @@ +<% title_string = "#{@user.name}'s Series" %> + +<%= content_for :page_meta do %> + <%= render "collections/meta", title_string: title_string %> +<% end %> + +
+
+

<%= title_string %>

+
+ +
+ <% if @collections.present? %> + <% @collections.each do |collection| %> +
+

+ <%= collection_link(collection, class: "crayons-link") %> +

+
+ <% end %> + <% else %> +

This user doesn't have any series

+ <% end %> +
+
diff --git a/app/views/collections/show.html.erb b/app/views/collections/show.html.erb new file mode 100644 index 000000000..f0962b578 --- /dev/null +++ b/app/views/collections/show.html.erb @@ -0,0 +1,24 @@ +<% title_string = "#{@collection.slug} Series' Articles" %> + +<%= content_for :page_meta do %> + <%= render "collections/meta", title_string: title_string %> +<% end %> + +
+
+

<%= title_string %>

+ <%= link_to "Back to #{@user.name}'s Series", user_series_path(@user.username) %> +
+ +
+
+ <% if @articles.present? %> + <% @articles.each do |article| %> + <%= render "articles/single_story", story: article.decorate, featured: article.main_image.present? %> + <% end %> + <% else %> +

This series doesn't have any articles

+ <% end %> +
+
+
diff --git a/config/routes.rb b/config/routes.rb index 5c972f4cc..ee0e7f734 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -457,6 +457,9 @@ Rails.application.routes.draw do get "/:timeframe" => "stories#index", :constraints => { timeframe: /latest/ } + get "/:username/series" => "collections#index", :as => "user_series" + get "/:username/series/:id" => "collections#show" + # Legacy comment format (might still be floating around app, and external links) get "/:username/:slug/comments" => "comments#index" get "/:username/:slug/comments/:id_code" => "comments#index" diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index e9786c1cc..88d5c0273 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -108,6 +108,22 @@ RSpec.describe ApplicationHelper, type: :helper do end end + describe "#collection_link" do + let(:collection) { create(:collection, :with_articles) } + + it "returns an 'a' tag" do + expect(helper.collection_link(collection)).to have_selector("a") + end + + it "sets the correct href" do + expect(helper.collection_link(collection)).to have_link(href: collection.path) + end + + it "has the correct text in the a tag" do + expect(helper.collection_link(collection)).to have_text("#{collection.slug} (#{collection.articles.published.size} Part Series)") + end + end + describe "#email_link" do before do allow(SiteConfig).to receive(:email_addresses).and_return( diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb index f39e9bd5d..e673b731c 100644 --- a/spec/models/collection_spec.rb +++ b/spec/models/collection_spec.rb @@ -34,6 +34,12 @@ RSpec.describe Collection, type: :model do end end + describe "path" do + it "returns the correct path" do + expect(collection.path).to eq("/#{collection.user.username}/series/#{collection.id}") + end + end + context "when callbacks are triggered after touch" do it "touches all articles in the collection" do before_times = collection.articles.order(updated_at: :desc).pluck(:updated_at).map(&:to_i) diff --git a/spec/requests/collections_spec.rb b/spec/requests/collections_spec.rb new file mode 100644 index 000000000..8c74b2371 --- /dev/null +++ b/spec/requests/collections_spec.rb @@ -0,0 +1,20 @@ +require "rails_helper" + +RSpec.describe "Collections", type: :request do + let(:user) { create(:user) } + let(:collection) { create(:collection, :with_articles, user: user) } + + describe "GET user collections index" do + it "returns 200" do + get "/#{user.username}/series" + expect(response).to have_http_status(:ok) + end + end + + describe "GET user collection show" do + it "returns 200" do + get collection.path + expect(response).to have_http_status(:ok) + end + end +end diff --git a/spec/system/collections/user_views_collection_articles_spec.rb b/spec/system/collections/user_views_collection_articles_spec.rb new file mode 100644 index 000000000..cecd966ad --- /dev/null +++ b/spec/system/collections/user_views_collection_articles_spec.rb @@ -0,0 +1,17 @@ +require "rails_helper" + +RSpec.describe "Viewing a collection", type: :system do + let(:user) { create(:user) } + let(:collection) { create(:collection, :with_articles, user: user) } + + before do + sign_in user + visit collection.path + end + + it "shows all published articles" do + collection.articles.published.each do |article| + expect(page.body).to have_link(article.title) + end + end +end diff --git a/spec/system/collections/user_views_collections_spec.rb b/spec/system/collections/user_views_collections_spec.rb new file mode 100644 index 000000000..e078e5409 --- /dev/null +++ b/spec/system/collections/user_views_collections_spec.rb @@ -0,0 +1,18 @@ +require "rails_helper" + +RSpec.describe "Visiting collections", type: :system do + let(:user) { create(:user) } + let!(:collection1) { create(:collection, :with_articles, user: user) } + let!(:collection2) { create(:collection, user: user) } + + before do + sign_in user + visit user_series_path(user.username) + end + + it "shows all collections", :aggregate_failures do + [collection1, collection2].each do |collection| + expect(page.body).to have_link("#{collection.slug} (#{collection.articles.published.size} Part Series)") + end + end +end