Add push subscription block feature
This commit is contained in:
parent
7b4508d6c2
commit
5817230fcd
19 changed files with 281 additions and 1 deletions
72
app/controllers/admin/push_subscription_blocks_controller.rb
Normal file
72
app/controllers/admin/push_subscription_blocks_controller.rb
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class PushSubscriptionBlocksController < BaseController
|
||||||
|
before_action :set_push_subscription_block, except: [:index, :new, :create]
|
||||||
|
|
||||||
|
def index
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
@push_subscription_blocks = PushSubscriptionBlock.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
@push_subscription_block = PushSubscriptionBlock.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
|
||||||
|
@push_subscription_block = PushSubscriptionBlock.new(resource_params)
|
||||||
|
|
||||||
|
if @push_subscription_block.save
|
||||||
|
@push_subscription_block.enable!
|
||||||
|
redirect_to admin_push_subscription_blocks_path
|
||||||
|
else
|
||||||
|
render action: :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
|
||||||
|
if @push_subscription_block.update(resource_params)
|
||||||
|
redirect_to admin_push_subscription_blocks_path
|
||||||
|
else
|
||||||
|
render action: :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
@push_subscription_block.destroy
|
||||||
|
redirect_to admin_push_subscription_blocks_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
@push_subscription_block.enable!
|
||||||
|
redirect_to admin_push_subscription_blocks_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
authorize :push_subscription_block, :update?
|
||||||
|
@push_subscription_block.disable!
|
||||||
|
redirect_to admin_push_subscription_blocks_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_push_subscription_block
|
||||||
|
@push_subscription_block = PushSubscriptionBlock.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_params
|
||||||
|
params.require(:push_subscription_block).permit(:name, :endpoint)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -54,6 +54,11 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
th.wrap,
|
||||||
|
td.wrap {
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
th.symbol,
|
th.symbol,
|
||||||
td.symbol {
|
td.symbol {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
44
app/models/push_subscription_block.rb
Normal file
44
app/models/push_subscription_block.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: push_subscription_blocks
|
||||||
|
#
|
||||||
|
# id :bigint(8) not null, primary key
|
||||||
|
# name :string default(""), not null
|
||||||
|
# endpoint :string not null
|
||||||
|
# enable :boolean default(TRUE), not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
class PushSubscriptionBlock < ApplicationRecord
|
||||||
|
CACHE_KEY = 'push_subscription_blocks'
|
||||||
|
|
||||||
|
validates :endpoint, presence: true, uniqueness: true, url: true, if: :will_save_change_to_endpoint?
|
||||||
|
|
||||||
|
after_commit :reset_cache
|
||||||
|
|
||||||
|
def enable!
|
||||||
|
update!(enable: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def disable!
|
||||||
|
update!(enable: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def allow?(url)
|
||||||
|
!deny?(url)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deny?(url)
|
||||||
|
blocks = Rails.cache.fetch(CACHE_KEY) { Regexp.union(PushSubscriptionBlock.where(enable: true).pluck(:endpoint).map { |pattern| Regexp.new("^#{Regexp.escape(pattern)}", Regexp::IGNORECASE) }) }
|
||||||
|
blocks.match?(url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reset_cache
|
||||||
|
Rails.cache.delete(CACHE_KEY)
|
||||||
|
end
|
||||||
|
end
|
|
@ -47,7 +47,7 @@ class Web::PushSubscription < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def pushable?(notification)
|
def pushable?(notification)
|
||||||
policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification)
|
policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification) && PushSubscriptionBlock.allow?(endpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
def associated_user
|
def associated_user
|
||||||
|
|
7
app/policies/push_subscription_block_policy.rb
Normal file
7
app/policies/push_subscription_block_policy.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class PushSubscriptionBlockPolicy < ApplicationPolicy
|
||||||
|
def update?
|
||||||
|
admin?
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
%tr
|
||||||
|
%td.nowrap
|
||||||
|
%samp= push_subscription_block.name
|
||||||
|
%td.wrap
|
||||||
|
%samp= push_subscription_block.endpoint
|
||||||
|
%td.nowrap
|
||||||
|
- if push_subscription_block.enable?
|
||||||
|
%span.positive-hint
|
||||||
|
= fa_icon('check')
|
||||||
|
= ' '
|
||||||
|
= t 'admin.push_subscription_blocks.enabled'
|
||||||
|
- else
|
||||||
|
%span.negative-hint
|
||||||
|
= fa_icon('times')
|
||||||
|
= ' '
|
||||||
|
= t 'admin.push_subscription_blocks.disabled'
|
||||||
|
%td.nowrap
|
||||||
|
- if push_subscription_block.enable?
|
||||||
|
= table_link_to 'power-off', t('admin.push_subscription_blocks.disable'), disable_admin_push_subscription_block_path(push_subscription_block), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
|
- else
|
||||||
|
= table_link_to 'power-off', t('admin.push_subscription_blocks.enable'), enable_admin_push_subscription_block_path(push_subscription_block), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
|
|
||||||
|
= table_link_to 'pencil', t('admin.push_subscription_blocks.edit.title'), edit_admin_push_subscription_block_path(push_subscription_block)
|
||||||
|
= table_link_to 'times', t('admin.push_subscription_blocks.delete'), admin_push_subscription_block_path(push_subscription_block), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
16
app/views/admin/push_subscription_blocks/edit.html.haml
Normal file
16
app/views/admin/push_subscription_blocks/edit.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.push_subscription_blocks.edit.title')
|
||||||
|
|
||||||
|
= simple_form_for @push_subscription_block, url: admin_push_subscription_block_path(@push_subscription_block), method: :put do |f|
|
||||||
|
= render 'shared/error_messages', object: @push_subscription_block
|
||||||
|
|
||||||
|
%p.hint= t('admin.push_subscription_blocks.enable_hint')
|
||||||
|
|
||||||
|
.field-group
|
||||||
|
= f.input :name, as: :string, wrapper: :with_block_label
|
||||||
|
|
||||||
|
.field-group
|
||||||
|
= f.input :endpoint, as: :string, wrapper: :with_block_label
|
||||||
|
|
||||||
|
.actions
|
||||||
|
= f.button :button, t('admin.push_subscription_blocks.save'), type: :submit
|
21
app/views/admin/push_subscription_blocks/index.html.haml
Normal file
21
app/views/admin/push_subscription_blocks/index.html.haml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.push_subscription_blocks.title')
|
||||||
|
|
||||||
|
.simple_form
|
||||||
|
%p.hint= t('admin.push_subscription_blocks.description_html')
|
||||||
|
= link_to @push_subscription_blocks.empty? ? t('admin.push_subscription_blocks.setup') : t('admin.push_subscription_blocks.add_new'), new_admin_push_subscription_block_path, class: 'block-button'
|
||||||
|
|
||||||
|
- unless @push_subscription_blocks.empty?
|
||||||
|
%hr.spacer
|
||||||
|
|
||||||
|
.table-wrapper
|
||||||
|
%table.table
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th= t('admin.push_subscription_blocks.name')
|
||||||
|
%th= t('admin.push_subscription_blocks.endpoint')
|
||||||
|
%th= t('admin.push_subscription_blocks.enable')
|
||||||
|
%th
|
||||||
|
%tbody
|
||||||
|
= render @push_subscription_blocks
|
||||||
|
|
16
app/views/admin/push_subscription_blocks/new.html.haml
Normal file
16
app/views/admin/push_subscription_blocks/new.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('admin.push_subscription_blocks.add_new')
|
||||||
|
|
||||||
|
= simple_form_for @push_subscription_block, url: admin_push_subscription_blocks_path do |f|
|
||||||
|
= render 'shared/error_messages', object: @push_subscription_block
|
||||||
|
|
||||||
|
%p.hint= t('admin.push_subscription_blocks.enable_hint')
|
||||||
|
|
||||||
|
.field-group
|
||||||
|
= f.input :name, as: :string, wrapper: :with_block_label
|
||||||
|
|
||||||
|
.field-group
|
||||||
|
= f.input :endpoint, as: :string, wrapper: :with_block_label
|
||||||
|
|
||||||
|
.actions
|
||||||
|
= f.button :button, t('admin.push_subscription_blocks.save'), type: :submit
|
|
@ -540,6 +540,22 @@ en:
|
||||||
title: IP rules
|
title: IP rules
|
||||||
pending_accounts:
|
pending_accounts:
|
||||||
title: Pending accounts (%{count})
|
title: Pending accounts (%{count})
|
||||||
|
push_subscription_blocks:
|
||||||
|
add_new: Add new block
|
||||||
|
delete: Delete
|
||||||
|
disable: Disable
|
||||||
|
disabled: Disabled
|
||||||
|
description_html: Block dead/delayed push notification servers.
|
||||||
|
edit:
|
||||||
|
title: Edit
|
||||||
|
enable: Enable
|
||||||
|
enabled: Enabled
|
||||||
|
enable_hint: Refer to Sidekiq's dead job and specify the non-functioning endpoint. Since it matches with a prefix match, specify it without user-specific parts such as ID. A meaningful name is recommended, but not required.
|
||||||
|
endpoint: End point
|
||||||
|
name: Name
|
||||||
|
save: Save
|
||||||
|
setup: Setup a push subscription block
|
||||||
|
title: Push subscription block
|
||||||
relationships:
|
relationships:
|
||||||
title: "%{acct}'s relationships"
|
title: "%{acct}'s relationships"
|
||||||
relays:
|
relays:
|
||||||
|
|
|
@ -522,6 +522,22 @@ ja:
|
||||||
title: IPルール
|
title: IPルール
|
||||||
pending_accounts:
|
pending_accounts:
|
||||||
title: 承認待ちアカウント (%{count})
|
title: 承認待ちアカウント (%{count})
|
||||||
|
push_subscription_blocks:
|
||||||
|
add_new: プッシュ通知ブロックを追加
|
||||||
|
delete: 削除
|
||||||
|
disable: 無効化
|
||||||
|
disabled: 無効
|
||||||
|
description_html: 停止・遅延しているプッシュ通知サーバーの利用をブロックします。
|
||||||
|
edit:
|
||||||
|
title: 編集
|
||||||
|
enable: 有効化
|
||||||
|
enabled: 有効
|
||||||
|
enable_hint: Sidekiqのデッドジョブを参考に、機能していないエンドポイントを指定します。前方一致でマッチするので、IDなどのユーザー固有部分を除いて指定してください。わかりやすい名前をつけておくことをおすすめしますが、必須ではありません。
|
||||||
|
endpoint: エンドポイント
|
||||||
|
name: 名前
|
||||||
|
save: 保存
|
||||||
|
setup: プッシュ通知ブロックを設定する
|
||||||
|
title: プッシュ通知ブロック
|
||||||
relationships:
|
relationships:
|
||||||
title: "%{acct} さんのフォロー・フォロワー"
|
title: "%{acct} さんのフォロー・フォロワー"
|
||||||
relays:
|
relays:
|
||||||
|
|
|
@ -390,6 +390,9 @@ en:
|
||||||
report: New report is submitted
|
report: New report is submitted
|
||||||
status_reference: Someone referenced your post
|
status_reference: Someone referenced your post
|
||||||
trending_tag: An unreviewed hashtag is trending
|
trending_tag: An unreviewed hashtag is trending
|
||||||
|
push_subscription_blocks:
|
||||||
|
endpoint: End point
|
||||||
|
name: Name
|
||||||
rule:
|
rule:
|
||||||
text: Rule
|
text: Rule
|
||||||
tag:
|
tag:
|
||||||
|
|
|
@ -390,6 +390,9 @@ ja:
|
||||||
report: 通報を受けた時
|
report: 通報を受けた時
|
||||||
status_reference: 投稿が参照された時
|
status_reference: 投稿が参照された時
|
||||||
trending_tag: 未審査のハッシュタグが人気の時
|
trending_tag: 未審査のハッシュタグが人気の時
|
||||||
|
push_subscription_block:
|
||||||
|
endpoint: エンドポイント
|
||||||
|
name: 名前
|
||||||
rule:
|
rule:
|
||||||
text: ルール
|
text: ルール
|
||||||
tag:
|
tag:
|
||||||
|
|
|
@ -63,6 +63,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
||||||
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}
|
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}
|
||||||
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
|
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
|
||||||
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/relays}
|
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/relays}
|
||||||
|
s.item :push_subscription_blocks, safe_join([fa_icon('ban fw'), t('admin.push_subscription_blocks.title')]), admin_push_subscription_blocks_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/push_subscription_blocks}
|
||||||
s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
|
s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
|
||||||
s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
|
s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
|
||||||
end
|
end
|
||||||
|
|
|
@ -322,6 +322,13 @@ Rails.application.routes.draw do
|
||||||
post :batch
|
post :batch
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :push_subscription_blocks, except: [:show] do
|
||||||
|
member do
|
||||||
|
post :enable
|
||||||
|
post :disable
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/admin', to: redirect('/admin/dashboard', status: 302)
|
get '/admin', to: redirect('/admin/dashboard', status: 302)
|
||||||
|
|
11
db/migrate/20221215211405_create_push_subscription_blocks.rb
Normal file
11
db/migrate/20221215211405_create_push_subscription_blocks.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class CreatePushSubscriptionBlocks < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
create_table :push_subscription_blocks do |t|
|
||||||
|
t.string :name, null: false, default: ''
|
||||||
|
t.string :endpoint, null: false
|
||||||
|
t.boolean :enable, null: false, default: true
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -838,6 +838,14 @@ ActiveRecord::Schema.define(version: 2023_01_29_193248) do
|
||||||
t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id"
|
t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "push_subscription_blocks", force: :cascade do |t|
|
||||||
|
t.string "name", default: "", null: false
|
||||||
|
t.string "endpoint", null: false
|
||||||
|
t.boolean "enable", default: true, null: false
|
||||||
|
t.datetime "created_at", precision: 6, null: false
|
||||||
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
|
end
|
||||||
|
|
||||||
create_table "relays", force: :cascade do |t|
|
create_table "relays", force: :cascade do |t|
|
||||||
t.string "inbox_url", default: "", null: false
|
t.string "inbox_url", default: "", null: false
|
||||||
t.string "follow_activity_id"
|
t.string "follow_activity_id"
|
||||||
|
|
5
spec/fabricators/push_subscription_block_fabricator.rb
Normal file
5
spec/fabricators/push_subscription_block_fabricator.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Fabricator(:push_subscription_block) do
|
||||||
|
name 'tootle'
|
||||||
|
endpoint 'https://tootleformastodon.appspot.com/api/v1/notifications/callback/'
|
||||||
|
enable true
|
||||||
|
end
|
5
spec/models/push_subscription_block_spec.rb
Normal file
5
spec/models/push_subscription_block_spec.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe PushSubscriptionBlock, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
Loading…
Reference in a new issue