diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index b520cad55..2eeac08a8 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -22,6 +22,6 @@ def update private def user_params - params.require(:user).permit(:username, :password_challenge) + params.require(:user).permit(:username, :password_challenge, :stories_order) end end diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index a304dd614..d5b03747b 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -2,7 +2,8 @@ class StoriesController < ApplicationController def index - @unread_stories = authorization.scope(StoryRepository.unread) + order = current_user.stories_order + @unread_stories = authorization.scope(StoryRepository.unread(order:)) end def update diff --git a/app/models/user.rb b/app/models/user.rb index 4424bf12d..587a6cc93 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -13,6 +13,8 @@ class User < ApplicationRecord before_save :update_api_key + enum :stories_order, { desc: "desc", asc: "asc" }, prefix: true + attr_accessor :password_challenge # `password_challenge` logic should be able to be removed in Rails 7.1 diff --git a/app/repositories/story_repository.rb b/app/repositories/story_repository.rb index d50ac3d75..6ed97afb7 100644 --- a/app/repositories/story_repository.rb +++ b/app/repositories/story_repository.rb @@ -47,8 +47,8 @@ def self.exists?(id, feed_id) Story.exists?(entry_id: id, feed_id:) end - def self.unread - Story.where(is_read: false).order("published desc").includes(:feed) + def self.unread(order: "desc") + Story.where(is_read: false).order("published #{order}").includes(:feed) end def self.unread_since_id(since_id) diff --git a/app/views/profiles/edit.html.erb b/app/views/profiles/edit.html.erb index bd6db8db1..d8bc7c499 100644 --- a/app/views/profiles/edit.html.erb +++ b/app/views/profiles/edit.html.erb @@ -1,12 +1,20 @@

<%= t('.title') %>

-
-

<%= t('.warning_html') %>

-
+<%= form_with(model: user, url: profile_path) do |form| %> +
+ <%= t(".stories_feed_settings") %> + <%= form.label :stories_order %> + <%= form.select :stories_order, User.stories_orders.transform_keys {|k| User.human_attribute_name("stories_order.#{k}") } %> +
+ <%= form.submit("Update") %> +<% end %> <%= form_with(model: user, url: profile_path) do |form| %>
<%= t('.change_username') %> +
+

<%= t('.warning_html') %>

+
<%= form.label :username %> <%= form.text_field :username, required: true %> <%= form.label :password_challenge, "Existing password" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index a6e658125..0ad95644c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -187,3 +187,10 @@ en: title: 'Stringer is ' your_feeds: your feeds your_stories: your stories + activerecord: + attributes: + user: + stories_order: "Stories feed order" + user/stories_order: + asc: "Oldest first" + desc: "Newest first" \ No newline at end of file diff --git a/db/migrate/20240316211109_add_stories_order_to_users.rb b/db/migrate/20240316211109_add_stories_order_to_users.rb new file mode 100644 index 000000000..8aec04941 --- /dev/null +++ b/db/migrate/20240316211109_add_stories_order_to_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddStoriesOrderToUsers < ActiveRecord::Migration[7.1] + def change + add_column :users, :stories_order, :string, default: "desc" + end +end diff --git a/db/schema.rb b/db/schema.rb index cbf392d68..4e0d15317 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_03_14_031223) do +ActiveRecord::Schema[7.1].define(version: 2024_03_16_211109) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -161,6 +161,7 @@ t.string "api_key", limit: 255, null: false t.string "username", null: false t.boolean "admin", null: false + t.string "stories_order", default: "desc" t.index ["api_key"], name: "index_users_on_api_key", unique: true t.index ["username"], name: "index_users_on_username", unique: true end diff --git a/spec/repositories/story_repository_spec.rb b/spec/repositories/story_repository_spec.rb index 718959045..d79b1e1cb 100644 --- a/spec/repositories/story_repository_spec.rb +++ b/spec/repositories/story_repository_spec.rb @@ -251,6 +251,13 @@ def create_feed(url: "http://blog.golang.org/feed.atom") expect(described_class.unread).to be_empty end + + it "allows to override the order" do + story1 = create(:story, :unread, published: 5.minutes.ago) + story2 = create(:story, :unread, published: 4.minutes.ago) + + expect(described_class.unread(order: :asc)).to eq([story1, story2]) + end end describe ".unread_since_id" do diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index b6473990b..07e74c1ca 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true RSpec.describe "profile page" do - it "allows the user to edit their username" do + before do login_as(default_user) visit(edit_profile_path) + end + it "allows the user to edit their username" do fill_in_username_fields(default_user.password) click_on("Update username") @@ -19,9 +21,6 @@ def fill_in_username_fields(existing_password) end it "allows the user to edit their password" do - login_as(default_user) - visit(edit_profile_path) - fill_in_password_fields(default_user.password, "new_password") click_on("Update password") @@ -35,4 +34,11 @@ def fill_in_password_fields(existing_password, new_password) fill_in("Password confirmation", with: new_password) end end + + it "allows the user to edit their feed order" do + select("Oldest first", from: "Stories feed order") + click_on("Update") + + expect(default_user.reload).to be_stories_order_asc + end end