forked from cybrespace/mastodon
		
	API for apps to register for push notifications
This commit is contained in:
		
							parent
							
								
									1992575d57
								
							
						
					
					
						commit
						3f075c7794
					
				
					 13 changed files with 112 additions and 2 deletions
				
			
		
							
								
								
									
										1
									
								
								Gemfile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Gemfile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -50,6 +50,7 @@ gem 'pg_search'
 | 
			
		|||
gem 'simple-navigation'
 | 
			
		||||
gem 'statsd-instrument'
 | 
			
		||||
gem 'ruby-oembed', require: 'oembed'
 | 
			
		||||
gem 'fcm'
 | 
			
		||||
 | 
			
		||||
gem 'react-rails'
 | 
			
		||||
gem 'browserify-rails'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,6 +127,9 @@ GEM
 | 
			
		|||
    execjs (2.7.0)
 | 
			
		||||
    fabrication (2.15.2)
 | 
			
		||||
    fast_blank (1.0.0)
 | 
			
		||||
    fcm (0.0.2)
 | 
			
		||||
      httparty
 | 
			
		||||
      json
 | 
			
		||||
    font-awesome-rails (4.6.3.1)
 | 
			
		||||
      railties (>= 3.2, < 5.1)
 | 
			
		||||
    fuubar (2.1.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +163,8 @@ GEM
 | 
			
		|||
      domain_name (~> 0.5)
 | 
			
		||||
    http-form_data (1.0.1)
 | 
			
		||||
    http_parser.rb (0.6.0)
 | 
			
		||||
    httparty (0.14.0)
 | 
			
		||||
      multi_xml (>= 0.5.2)
 | 
			
		||||
    httplog (0.3.2)
 | 
			
		||||
      colorize
 | 
			
		||||
    i18n (0.7.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +212,7 @@ GEM
 | 
			
		|||
    mini_portile2 (2.1.0)
 | 
			
		||||
    minitest (5.10.1)
 | 
			
		||||
    multi_json (1.12.1)
 | 
			
		||||
    multi_xml (0.6.0)
 | 
			
		||||
    nio4r (1.2.1)
 | 
			
		||||
    nokogiri (1.7.0.1)
 | 
			
		||||
      mini_portile2 (~> 2.1.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -434,6 +440,7 @@ DEPENDENCIES
 | 
			
		|||
  dotenv-rails
 | 
			
		||||
  fabrication
 | 
			
		||||
  fast_blank
 | 
			
		||||
  fcm
 | 
			
		||||
  font-awesome-rails
 | 
			
		||||
  fuubar
 | 
			
		||||
  goldfinger
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								app/controllers/api/v1/devices_controller.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/controllers/api/v1/devices_controller.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::DevicesController < ApiController
 | 
			
		||||
  before_action -> { doorkeeper_authorize! :read }
 | 
			
		||||
  before_action :require_user!
 | 
			
		||||
 | 
			
		||||
  respond_to :json
 | 
			
		||||
 | 
			
		||||
  def register
 | 
			
		||||
    Device.where(account: current_account, registration_id: params[:registration_id]).first_or_create!(account: current_account, registration_id: params[:registration_id])
 | 
			
		||||
    render_empty
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unregister
 | 
			
		||||
    Device.where(account: current_account, registration_id: params[:registration_id]).delete_all
 | 
			
		||||
    render_empty
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										7
									
								
								app/models/device.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/models/device.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Device < ApplicationRecord
 | 
			
		||||
  belongs_to :account
 | 
			
		||||
 | 
			
		||||
  validates :account, :registration_id, presence: true
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ class NotifyService < BaseService
 | 
			
		|||
 | 
			
		||||
    create_notification
 | 
			
		||||
    send_email if email_enabled?
 | 
			
		||||
    send_push_notification
 | 
			
		||||
  rescue ActiveRecord::RecordInvalid
 | 
			
		||||
    return
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,10 @@ class NotifyService < BaseService
 | 
			
		|||
    NotificationMailer.send(@notification.type, @recipient, @notification).deliver_later
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def send_push_notification
 | 
			
		||||
    PushNotificationWorker.perform_async(@notification.id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def email_enabled?
 | 
			
		||||
    @recipient.user.settings.notification_emails[@notification.type]
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								app/services/send_push_notification_service.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/services/send_push_notification_service.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class SendPushNotificationService < BaseService
 | 
			
		||||
  def call(notification)
 | 
			
		||||
  	return if ENV['FCM_API_KEY'].blank?
 | 
			
		||||
 | 
			
		||||
  	devices = Device.where(account: notification.account).pluck(:registration_id)
 | 
			
		||||
  	fcm     = FCM.new(ENV['FCM_API_KEY'])
 | 
			
		||||
 | 
			
		||||
  	response = fcm.send(devices, data: { notification_id: notification.id }, collapse_key: :notifications, priority: :high)
 | 
			
		||||
  	handle_response(response)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def handle_response(response)
 | 
			
		||||
    update_canonical_ids(response[:canonical_ids]) if response[:canonical_ids]
 | 
			
		||||
    remove_bad_ids(response[:not_registered_ids])  if response[:not_registered_ids]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update_canonical_ids(ids)
 | 
			
		||||
  	ids.each { |pair| Device.find_by(registration_id: pair[:old]).update(registration_id: pair[:new]) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_bad_ids(bad_ids)
 | 
			
		||||
  	Device.where(registration_id: bad_ids).delete_all
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								app/workers/push_notification_worker.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/workers/push_notification_worker.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class PushNotificationWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
 | 
			
		||||
  def perform(notification_id)
 | 
			
		||||
    SendPushNotificationService.new.call(Notification.find(notification_id))
 | 
			
		||||
  rescue ActiveRecord::RecordNotFound
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +118,9 @@ Rails.application.routes.draw do
 | 
			
		|||
      resources :blocks,     only: [:index]
 | 
			
		||||
      resources :favourites, only: [:index]
 | 
			
		||||
 | 
			
		||||
      post '/devices/register',   to: 'devices#register', as: :register_device
 | 
			
		||||
      post '/devices/unregister', to: 'devices#unregister', as: :unregister_device
 | 
			
		||||
 | 
			
		||||
      resources :follow_requests, only: [:index] do
 | 
			
		||||
        member do
 | 
			
		||||
          post :authorize
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								db/migrate/20170129000348_create_devices.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								db/migrate/20170129000348_create_devices.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
class CreateDevices < ActiveRecord::Migration[5.0]
 | 
			
		||||
  def change
 | 
			
		||||
    create_table :devices do |t|
 | 
			
		||||
      t.integer :account_id, null: false
 | 
			
		||||
      t.string :registration_id, null: false, default: ''
 | 
			
		||||
 | 
			
		||||
      t.timestamps
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    add_index :devices, :registration_id
 | 
			
		||||
    add_index :devices, :account_id
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								db/schema.rb
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								db/schema.rb
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170127165745) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170129000348) do
 | 
			
		||||
 | 
			
		||||
  # These are extensions that must be enabled in order to support this database
 | 
			
		||||
  enable_extension "plpgsql"
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +54,15 @@ ActiveRecord::Schema.define(version: 20170127165745) do
 | 
			
		|||
    t.index ["account_id", "target_account_id"], name: "index_blocks_on_account_id_and_target_account_id", unique: true, using: :btree
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "devices", force: :cascade do |t|
 | 
			
		||||
    t.integer  "account_id",                   null: false
 | 
			
		||||
    t.string   "registration_id", default: "", null: false
 | 
			
		||||
    t.datetime "created_at",                   null: false
 | 
			
		||||
    t.datetime "updated_at",                   null: false
 | 
			
		||||
    t.index ["account_id"], name: "index_devices_on_account_id", using: :btree
 | 
			
		||||
    t.index ["registration_id"], name: "index_devices_on_registration_id", using: :btree
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "domain_blocks", force: :cascade do |t|
 | 
			
		||||
    t.string   "domain",       default: "", null: false
 | 
			
		||||
    t.datetime "created_at",                null: false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								spec/fabricators/device_fabricator.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								spec/fabricators/device_fabricator.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
Fabricator(:device) do
 | 
			
		||||
  registration_id "12345678"
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
Fabricator(:domain_block) do
 | 
			
		||||
  domain "MyString"
 | 
			
		||||
  domain "example.com"
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								spec/models/device_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/models/device_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Device, type: :model do
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue