Skip to content

Commit 8ae3a3b

Browse files
authored
Merge pull request #329 from coopdevs/feature/device-tokens
Added the device_tokens endpoint
2 parents 7c347e9 + 5f22849 commit 8ae3a3b

File tree

12 files changed

+149
-1
lines changed

12 files changed

+149
-1
lines changed

app/assets/javascripts/application.js.coffee

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#= require datepicker
33
#= require give_time
44
#= require tags
5+
#= require mobile_app_libs
56

67
$(document).on 'click', 'a[data-popup]', (event) ->
78
window.open($(this).attr('href'), 'popup', 'width=600,height=600')
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Used by the mobile app to register the device token
2+
// https://github.com/coopdevs/timeoverflow-mobile-app
3+
window.TimeOverflowRegisterExpoDeviceToken = function (token) {
4+
$.post('/device_tokens', { token: token });
5+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class DeviceTokensController < ApplicationController
2+
before_filter :authenticate_user!
3+
4+
def create
5+
@device_token = DeviceToken.new device_token_params.merge! user_id: current_user.id
6+
7+
if @device_token.save
8+
render nothing: true, status: :created
9+
else
10+
render nothing: true, status: :unprocessable_entity
11+
end
12+
end
13+
14+
private
15+
16+
def device_token_params
17+
params.permit(:token)
18+
end
19+
end

app/models/device_token.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class DeviceToken < ActiveRecord::Base
2+
belongs_to :user
3+
4+
validates :user_id, presence: true
5+
validates :token, presence: true
6+
validates :token, uniqueness: { scope: :user_id }
7+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module PushNotifications
2+
class PostNotification
3+
def title
4+
"Notification title"
5+
end
6+
7+
def body
8+
"Notification body"
9+
end
10+
end
11+
end

app/models/user.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class User < ActiveRecord::Base
2222
has_many :posts
2323
has_many :offers
2424
has_many :inquiries
25+
has_many :device_tokens
2526

2627
accepts_nested_attributes_for :members
2728

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require 'net/http'
2+
3+
module PushNotifications
4+
class ExpoAdaptorService
5+
def initialize(notification, user)
6+
@notification = notification
7+
@user = user
8+
end
9+
10+
def run
11+
user.device_tokens.each do |device_token|
12+
# https://docs.expo.io/versions/latest/guides/push-notifications.html
13+
uri = URI('https://exp.host/--/api/v2/push/send')
14+
Net::HTTP.post_form(uri, post_data(device_token.token))
15+
end
16+
end
17+
18+
private
19+
20+
attr_reader :notification, :user
21+
22+
def post_data(token)
23+
{
24+
"to" => token,
25+
"title" => notification.title,
26+
"body" => notification.body
27+
}
28+
end
29+
end
30+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module PushNotifications
2+
class UsersBroadcasterService
3+
def initialize(users)
4+
@users = users
5+
end
6+
7+
def broadcast
8+
notification = PostNotification.new
9+
10+
users.each do |user|
11+
ExpoSenderService.new(notification, user).run
12+
end
13+
end
14+
15+
private
16+
17+
attr_reader :users
18+
end
19+
end

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
end
2121

2222
resources :inquiries
23+
resources :device_tokens, only: :create
2324

2425
concern :accountable do
2526
get :give_time, on: :member
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class CreateDeviceTokens < ActiveRecord::Migration
2+
def change
3+
create_table :device_tokens do |t|
4+
t.integer :user_id, :null => false
5+
t.string :token, :null => false
6+
7+
t.timestamps
8+
end
9+
add_index :device_tokens, [:user_id, :token], unique: true
10+
end
11+
end

db/schema.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#
1212
# It's strongly recommended that you check this file into your version control system.
1313

14-
ActiveRecord::Schema.define(version: 20150422162806) do
14+
ActiveRecord::Schema.define(version: 20180221161343) do
1515

1616
# These are extensions that must be enabled in order to support this database
1717
enable_extension "plpgsql"
@@ -54,6 +54,15 @@
5454
t.hstore "name_translations"
5555
end
5656

57+
create_table "device_tokens", force: :cascade do |t|
58+
t.integer "user_id", null: false
59+
t.string "token", null: false
60+
t.datetime "created_at"
61+
t.datetime "updated_at"
62+
end
63+
64+
add_index "device_tokens", ["user_id", "token"], name: "index_device_tokens_on_user_id_and_token", unique: true, using: :btree
65+
5766
create_table "documents", force: :cascade do |t|
5867
t.integer "documentable_id"
5968
t.string "documentable_type"
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require 'spec_helper'
2+
3+
describe DeviceTokensController do
4+
let (:organization) { Fabricate(:organization) }
5+
let (:member) { Fabricate(:member, organization: organization) }
6+
7+
describe 'POST #create' do
8+
context 'without login' do
9+
it 'responds with error' do
10+
expect do
11+
post :create
12+
end.to change(DeviceToken, :count).by(0)
13+
end
14+
end
15+
16+
context 'with valid params' do
17+
it 'creates a new device_token' do
18+
login(member.user)
19+
20+
expect do
21+
post :create, token: 'xxx'
22+
end.to change(DeviceToken, :count).by(1)
23+
end
24+
end
25+
26+
context 'with invalid params' do
27+
it 'responds with error' do
28+
login(member.user)
29+
post :create
30+
expect(response.status).to eq(422)
31+
end
32+
end
33+
end
34+
end

0 commit comments

Comments
 (0)