From 4712ff0a308e86b96b2c94470d8756c09ba1770e Mon Sep 17 00:00:00 2001 From: Jesse Karmani Date: Thu, 6 Feb 2025 18:55:38 -0800 Subject: [PATCH 1/3] Allow for timeline markers for account timelines --- app/controllers/api/v1/markers_controller.rb | 10 +++++++++- app/models/marker.rb | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/markers_controller.rb b/app/controllers/api/v1/markers_controller.rb index 8eaf7767df87e0..3037742a99ba06 100644 --- a/app/controllers/api/v1/markers_controller.rb +++ b/app/controllers/api/v1/markers_controller.rb @@ -42,6 +42,14 @@ def serialize_map(map) end def resource_params - params.slice(*Marker::TIMELINES).permit(*Marker::TIMELINES.map { |timeline| { timeline.to_sym => [:last_read_id] } }) + # Get both static and account-based timeline parameters + timeline_params = params.slice(*Marker::TIMELINES) + account_params = params.select { |key, _| key.start_with?('account:') && key.split(':', 2)[1].match?(/\A\d+\z/) } + + # Merge and permit them + timeline_params.merge(account_params).permit( + *Marker::TIMELINES.map { |timeline| { timeline.to_sym => [:last_read_id] } }, + /\Aaccount:\d+\z/ => [:last_read_id] + ) end end diff --git a/app/models/marker.rb b/app/models/marker.rb index a5bd2176a84e25..0d4fc1552b7a63 100644 --- a/app/models/marker.rb +++ b/app/models/marker.rb @@ -19,5 +19,18 @@ class Marker < ApplicationRecord belongs_to :user validates :timeline, :last_read_id, presence: true - validates :timeline, inclusion: { in: TIMELINES } + validate :timeline_format_valid + + def self.for_account(account_id) + "account:#{account_id}" + end + + private + + def timeline_format_valid + return if TIMELINES.include?(timeline) + return if timeline.start_with?('account:') && timeline.split(':', 2)[1].match?(/\A\d+\z/) + + errors.add(:timeline, 'must be a valid timeline type') + end end From 4ce8a8cab0f311f843828f3d1dc1422a5b47344d Mon Sep 17 00:00:00 2001 From: Jesse Karmani Date: Wed, 19 Feb 2025 15:47:29 -0800 Subject: [PATCH 2/3] Fix markers params to allow account timeline keys --- app/controllers/api/v1/markers_controller.rb | 13 +++++----- .../api/v1/markers_controller_spec.rb | 24 +++++++++++++++++++ spec/rails_helper.rb | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 spec/controllers/api/v1/markers_controller_spec.rb diff --git a/app/controllers/api/v1/markers_controller.rb b/app/controllers/api/v1/markers_controller.rb index 3037742a99ba06..22caec2da37d7e 100644 --- a/app/controllers/api/v1/markers_controller.rb +++ b/app/controllers/api/v1/markers_controller.rb @@ -42,14 +42,15 @@ def serialize_map(map) end def resource_params - # Get both static and account-based timeline parameters - timeline_params = params.slice(*Marker::TIMELINES) - account_params = params.select { |key, _| key.start_with?('account:') && key.split(':', 2)[1].match?(/\A\d+\z/) } + timeline_params = params.slice(*Marker::TIMELINES).permit!.to_h + account_params = params.select { |key, _| key.start_with?('account:') && key.split(':', 2)[1].match?(/\A\d+\z/) }.permit!.to_h - # Merge and permit them - timeline_params.merge(account_params).permit( + merged_params = timeline_params.merge(account_params) + params = ActionController::Parameters.new(merged_params) + + params.permit( *Marker::TIMELINES.map { |timeline| { timeline.to_sym => [:last_read_id] } }, - /\Aaccount:\d+\z/ => [:last_read_id] + *account_params.keys.map { |key| { key.to_sym => [:last_read_id] } } ) end end diff --git a/spec/controllers/api/v1/markers_controller_spec.rb b/spec/controllers/api/v1/markers_controller_spec.rb new file mode 100644 index 00000000000000..e5b67d2107b654 --- /dev/null +++ b/spec/controllers/api/v1/markers_controller_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Api::V1::MarkersController do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses') } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'POST #create' do + it 'creates markers for account-based timelines' do + post :create, params: { + 'account:123': { last_read_id: '456' }, + } + + expect(response).to have_http_status(200) + json = JSON.parse(response.body) + expect(json['account:123']).to include('last_read_id' => '456') + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d2ad40be7310fb..adb7784ca5c30f 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -42,6 +42,7 @@ require 'paperclip/matchers' require 'capybara/rspec' require 'chewy/rspec' +require 'email_spec' require 'email_spec/rspec' require 'pundit/rspec' require 'test_prof/recipes/rspec/before_all' From eaa554d0e6812016180b3d00f850f3977a3c6d26 Mon Sep 17 00:00:00 2001 From: Jesse Karmani Date: Tue, 25 Feb 2025 11:11:36 -0800 Subject: [PATCH 3/3] Update README.md to mention account timeline markers --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0cf97f952c5222..eb81e8012d90c8 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ An opinionated fork of mastodon with the following modifications: * default "inner circle" for all accounts to get them started - [jesseplusplus/decodon#14](https://github.com/jesseplusplus/decodon/pull/14) +* timeline markers for accounts' feed of updates - [jesseplusplus/decodon#189](https://github.com/jesseplusplus/decodon/pull/189) + * more control over logo and branding in email templates [jesseplusplus/decodon#10](https://github.com/jesseplusplus/decodon/pull/10) * updated heroku deployment configs