API for apps to register for push notifications
This commit is contained in:
		
							
								
								
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Gemfile
									
									
									
									
									
								
							@@ -50,6 +50,7 @@ gem 'pg_search'
 | 
				
			|||||||
gem 'simple-navigation'
 | 
					gem 'simple-navigation'
 | 
				
			||||||
gem 'statsd-instrument'
 | 
					gem 'statsd-instrument'
 | 
				
			||||||
gem 'ruby-oembed', require: 'oembed'
 | 
					gem 'ruby-oembed', require: 'oembed'
 | 
				
			||||||
 | 
					gem 'fcm'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gem 'react-rails'
 | 
					gem 'react-rails'
 | 
				
			||||||
gem 'browserify-rails'
 | 
					gem 'browserify-rails'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -127,6 +127,9 @@ GEM
 | 
				
			|||||||
    execjs (2.7.0)
 | 
					    execjs (2.7.0)
 | 
				
			||||||
    fabrication (2.15.2)
 | 
					    fabrication (2.15.2)
 | 
				
			||||||
    fast_blank (1.0.0)
 | 
					    fast_blank (1.0.0)
 | 
				
			||||||
 | 
					    fcm (0.0.2)
 | 
				
			||||||
 | 
					      httparty
 | 
				
			||||||
 | 
					      json
 | 
				
			||||||
    font-awesome-rails (4.6.3.1)
 | 
					    font-awesome-rails (4.6.3.1)
 | 
				
			||||||
      railties (>= 3.2, < 5.1)
 | 
					      railties (>= 3.2, < 5.1)
 | 
				
			||||||
    fuubar (2.1.1)
 | 
					    fuubar (2.1.1)
 | 
				
			||||||
@@ -160,6 +163,8 @@ GEM
 | 
				
			|||||||
      domain_name (~> 0.5)
 | 
					      domain_name (~> 0.5)
 | 
				
			||||||
    http-form_data (1.0.1)
 | 
					    http-form_data (1.0.1)
 | 
				
			||||||
    http_parser.rb (0.6.0)
 | 
					    http_parser.rb (0.6.0)
 | 
				
			||||||
 | 
					    httparty (0.14.0)
 | 
				
			||||||
 | 
					      multi_xml (>= 0.5.2)
 | 
				
			||||||
    httplog (0.3.2)
 | 
					    httplog (0.3.2)
 | 
				
			||||||
      colorize
 | 
					      colorize
 | 
				
			||||||
    i18n (0.7.0)
 | 
					    i18n (0.7.0)
 | 
				
			||||||
@@ -207,6 +212,7 @@ GEM
 | 
				
			|||||||
    mini_portile2 (2.1.0)
 | 
					    mini_portile2 (2.1.0)
 | 
				
			||||||
    minitest (5.10.1)
 | 
					    minitest (5.10.1)
 | 
				
			||||||
    multi_json (1.12.1)
 | 
					    multi_json (1.12.1)
 | 
				
			||||||
 | 
					    multi_xml (0.6.0)
 | 
				
			||||||
    nio4r (1.2.1)
 | 
					    nio4r (1.2.1)
 | 
				
			||||||
    nokogiri (1.7.0.1)
 | 
					    nokogiri (1.7.0.1)
 | 
				
			||||||
      mini_portile2 (~> 2.1.0)
 | 
					      mini_portile2 (~> 2.1.0)
 | 
				
			||||||
@@ -434,6 +440,7 @@ DEPENDENCIES
 | 
				
			|||||||
  dotenv-rails
 | 
					  dotenv-rails
 | 
				
			||||||
  fabrication
 | 
					  fabrication
 | 
				
			||||||
  fast_blank
 | 
					  fast_blank
 | 
				
			||||||
 | 
					  fcm
 | 
				
			||||||
  font-awesome-rails
 | 
					  font-awesome-rails
 | 
				
			||||||
  fuubar
 | 
					  fuubar
 | 
				
			||||||
  goldfinger
 | 
					  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
 | 
					    create_notification
 | 
				
			||||||
    send_email if email_enabled?
 | 
					    send_email if email_enabled?
 | 
				
			||||||
 | 
					    send_push_notification
 | 
				
			||||||
  rescue ActiveRecord::RecordInvalid
 | 
					  rescue ActiveRecord::RecordInvalid
 | 
				
			||||||
    return
 | 
					    return
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -57,6 +58,10 @@ class NotifyService < BaseService
 | 
				
			|||||||
    NotificationMailer.send(@notification.type, @recipient, @notification).deliver_later
 | 
					    NotificationMailer.send(@notification.type, @recipient, @notification).deliver_later
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def send_push_notification
 | 
				
			||||||
 | 
					    PushNotificationWorker.perform_async(@notification.id)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def email_enabled?
 | 
					  def email_enabled?
 | 
				
			||||||
    @recipient.user.settings.notification_emails[@notification.type]
 | 
					    @recipient.user.settings.notification_emails[@notification.type]
 | 
				
			||||||
  end
 | 
					  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 :blocks,     only: [:index]
 | 
				
			||||||
      resources :favourites, 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
 | 
					      resources :follow_requests, only: [:index] do
 | 
				
			||||||
        member do
 | 
					        member do
 | 
				
			||||||
          post :authorize
 | 
					          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.
 | 
					# 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
 | 
					  # These are extensions that must be enabled in order to support this database
 | 
				
			||||||
  enable_extension "plpgsql"
 | 
					  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
 | 
					    t.index ["account_id", "target_account_id"], name: "index_blocks_on_account_id_and_target_account_id", unique: true, using: :btree
 | 
				
			||||||
  end
 | 
					  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|
 | 
					  create_table "domain_blocks", force: :cascade do |t|
 | 
				
			||||||
    t.string   "domain",       default: "", null: false
 | 
					    t.string   "domain",       default: "", null: false
 | 
				
			||||||
    t.datetime "created_at",                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
 | 
					Fabricator(:domain_block) do
 | 
				
			||||||
  domain "MyString"
 | 
					  domain "example.com"
 | 
				
			||||||
end
 | 
					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
 | 
				
			||||||
		Reference in New Issue
	
	Block a user