Commit cd280ca5 authored by Alex Gleason's avatar Alex Gleason

Add notification forwarding #207

parent db1d8004
# frozen_string_literal: true
module Admin
class EditNotificationForwardingsController < BaseController
before_action :set_account
before_action :require_local_account!
def show
authorize @account, :edit_notification_forwarding?
end
def update
authorize @account, :edit_notification_forwarding?
@account.update! notification_forwarding: resource_params.fetch(:notification_forwarding)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.edit_notification_forwarding.changed_msg')
end
private
def set_account
@account = Account.find(params[:account_id])
@user = @account.user
end
def require_local_account!
redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present?
end
def resource_params
params.require(:account).permit(
:notification_forwarding
)
end
end
end
......@@ -51,6 +51,7 @@
# is_donor :boolean default(FALSE), not null
# is_investor :boolean default(FALSE), not null
# stripe_cus_id :string
# notification_forwarding :string
#
class Account < ApplicationRecord
......@@ -83,6 +84,7 @@ class Account < ApplicationRecord
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
validates :notification_forwarding, existing_username: { multiple: true }, if: -> { local? && will_save_change_to_notification_forwarding? }
scope :remote, -> { where.not(domain: nil) }
scope :local, -> { where(domain: nil) }
......@@ -390,6 +392,12 @@ class Account < ApplicationRecord
shared_inbox_url.presence || inbox_url
end
def notification_forwarding_accounts
value = self[:notification_forwarding] || ''
usernames = value.split(',').map { |value| value.strip.gsub(/\[email protected]/, '') }
usernames.map { |username| Account.find_local(username) }.compact.uniq
end
class Field < ActiveModelSerializers::Model
attributes :name, :value, :verified_at, :account, :errors
......
......@@ -78,4 +78,8 @@ class AccountPolicy < ApplicationPolicy
def update_badges?
admin?
end
def edit_notification_forwarding?
admin?
end
end
......@@ -16,6 +16,7 @@ class ProcessMentionsService < BaseService
status.text = status.text.gsub(Account::MENTION_RE) do |match|
username, domain = Regexp.last_match(1).split('@')
mentioned_account = Account.find_remote(username, domain)
forwarding_accounts = mentioned_account.notification_forwarding_accounts
if mention_undeliverable?(mentioned_account)
begin
......@@ -29,12 +30,23 @@ class ProcessMentionsService < BaseService
mentions << mentioned_account.mentions.where(status: status).first_or_create(status: status)
# Forward mentions when configured on a particular user
# eg @moderators could be configured to forward mentions to @alex and @mk
forwarding_accounts.each do |forwarding_account|
# Skip it if the post author and forwarding account match
return if status.account_id == forwarding_account.id
# Skip it if forwarding is configured on oneself
return if mentioned_account.id == forwarding_account.id
mentions << forwarding_account.mentions.where(status: status).first_or_create(status: status)
end
"@#{mentioned_account.acct}"
end
status.save!
mentions.each { |mention| create_notification(mention) }
mentions.uniq.each { |mention| create_notification(mention) }
end
private
......
......@@ -177,6 +177,13 @@
- else
= table_link_to '', t('admin.accounts.add_investor_badge'), add_investor_badge_admin_account_path(@account.id), class: 'button', method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:update_badges, @account)
%tr
%th= t('admin.accounts.notification_forwarding')
%td
= @account.notification_forwarding
%td
= table_link_to '', t('admin.accounts.edit_notification_forwarding.label'), admin_account_edit_notification_forwarding_path(@account.id), class: 'button' if can?(:edit_notification_forwarding, @account)
- else
%tr
%th= t('admin.accounts.inbox_url')
......
- content_for :page_title do
= t('admin.accounts.edit_notification_forwarding.title', username: @account.acct)
= simple_form_for @account, url: admin_account_edit_notification_forwarding_path(@account.id) do |f|
.fields-group
= f.input :notification_forwarding, wrapper: :with_label, label: t('admin.accounts.edit_notification_forwarding.input_label')
.actions
= f.button :submit, class: "button", value: t('admin.accounts.edit_notification_forwarding.submit')
......@@ -78,6 +78,12 @@ en:
display_name: Display name
domain: Domain
edit: Edit
edit_notification_forwarding:
changed_msg: Notification forwarding successfully updated.
input_label: Comma separated list of accounts to forward notifications to. Only local accounts are permitted.
label: Edit notification forwarding
submit: Submit
title: Edit notification forwarding for %{username}
email: Email
email_status: Email status
enable: Enable
......
......@@ -221,6 +221,7 @@ Rails.application.routes.draw do
end
resource :change_email, only: [:show, :update]
resource :edit_notification_forwarding, only: [:show, :update]
resource :reset, only: [:create]
resource :action, only: [:new, :create], controller: 'account_actions'
resources :statuses, only: [:index, :show, :create, :update, :destroy]
......
class AddNotificationForwardingToAccounts < ActiveRecord::Migration[5.2]
def change
add_column :accounts, :notification_forwarding, :string
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_12_02_004114) do
ActiveRecord::Schema.define(version: 2020_01_15_213843) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -165,6 +165,7 @@ ActiveRecord::Schema.define(version: 2019_12_02_004114) do
t.boolean "is_donor", default: false, null: false
t.boolean "is_investor", default: false, null: false
t.string "stripe_cus_id"
t.string "notification_forwarding"
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
......
require 'rails_helper'
RSpec.describe Admin::EditNotificationForwardingsController, type: :controller do
render_views
let(:admin) { Fabricate(:user, admin: true) }
let(:user1) { Fabricate(:account) }
let(:user2) { Fabricate(:account) }
before do
sign_in admin
end
describe "GET #show" do
it "returns http success" do
account = Fabricate(:account)
get :show, params: { account_id: account.id }
expect(response).to have_http_status(200)
end
end
describe "GET #update" do
it "returns http success" do
account = Fabricate(:account)
post :update, params: { account_id: account.id, notification_forwarding: 'user1, user2' }
expect(response).to redirect_to(admin_account_path(account.id))
end
end
end
......@@ -83,4 +83,22 @@ RSpec.describe ProcessMentionsService, type: :service do
expect(a_request(:post, remote_user.inbox_url)).to have_been_made.once
end
end
context 'Forwarded mention' do
let(:mod1) { Fabricate(:account, username: 'mod1') }
let(:mod2) { Fabricate(:account, username: 'mod2') }
let(:mods) { Fabricate(:account, username: 'mods', notification_forwarding: "#{mod1.acct}, #{mod2.acct}") }
let(:status) { Fabricate(:status, account: account, text: "Hello @#{mods.acct}", visibility: visibility) }
subject { ProcessMentionsService.new }
before do
subject.call(status)
end
it 'forwards the mention' do
expect(mod1.mentions.where(status: status).count).to eq 1
expect(mod2.mentions.where(status: status).count).to eq 1
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment