diff --git a/app/models/notice.rb b/app/models/notice.rb index 04bcd269dd..99ab9a4023 100644 --- a/app/models/notice.rb +++ b/app/models/notice.rb @@ -5,7 +5,9 @@ class Notice < ActiveModelSerializers::Model # Notices a user has seen are stored as a bitmap in # `users.seen_notifications`. - NOTICE_BIT_MAP = {}.freeze + NOTICE_BIT_MAP = { + mastodon_privacy_4_2: 1, # rubocop:disable Naming/VariableNumber + }.freeze def dismiss_for_user!(user) user.update!(seen_notices: (user.seen_notices || 0) | NOTICE_BIT_MAP[id]) @@ -29,5 +31,22 @@ class Notice < ActiveModelSerializers::Model send("#{key}_notice") end + + private + + def mastodon_privacy_4_2_notice + new( + id: :mastodon_privacy_4_2, # rubocop:disable Naming/VariableNumber + icon: nil, + title: I18n.t('notices.mastodon_privacy_4_2.title'), + message: I18n.t('notices.mastodon_privacy_4_2.message'), + actions: [ + Action.new( + label: I18n.t('notices.mastodon_privacy_4_2.review'), + url: settings_privacy_url + ), + ] + ) + end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 71b8f27aac..5f759a6ff0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1441,6 +1441,11 @@ en: copy_account_note_text: 'This user moved from %{acct}, here were your previous notes about them:' navigation: toggle_menu: Toggle menu + notices: + mastodon_privacy_4_2: + message: Mastodon's privacy settings have been moved to a new page, and now include a new setting related to search! Give it a look if you want to allow other people to search for your posts, or if you just want to make sure everything is set up like you want! + review: Go to privacy settings + title: Search and privacy settings notification_mailer: admin: report: diff --git a/spec/requests/api/v1/notices_spec.rb b/spec/requests/api/v1/notices_spec.rb new file mode 100644 index 0000000000..c318801158 --- /dev/null +++ b/spec/requests/api/v1/notices_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'notices' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'write:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'DELETE /api/v1/notices/:id' do + subject do + delete '/api/v1/notices/mastodon_privacy_4_2', headers: headers + end + + it_behaves_like 'forbidden for wrong scope', 'read' + + it 'retruns http success' do + subject + + expect(response).to have_http_status(200) + end + + it 'marks the notice as seen' do + expect { subject }.to change { Notice.first_unseen(user.reload)&.id }.from(:mastodon_privacy_4_2) # rubocop:disable Naming/VariableNumber + end + end + + describe 'GET /api/v1/notices' do + subject do + get '/api/v1/notices', headers: headers + end + + context 'when the user has seen all notices' do + before do + Notice.find(:mastodon_privacy_4_2).dismiss_for_user!(user) # rubocop:disable Naming/VariableNumber + end + + it 'returns an empty list', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json).to eq [] + end + end + + context 'when the user has unseen notices' do + it 'returns exactly one notice', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json.size).to eq 1 + end + end + + context 'without the authorization header' do + let(:headers) { {} } + + it 'returns http unprocessable content' do + subject + + expect(response).to have_http_status(422) + end + end + end +end