enviar notificaciones!
This commit is contained in:
parent
532054de11
commit
b1de74aafe
14 changed files with 149 additions and 144 deletions
18
.rubocop.yml
18
.rubocop.yml
|
@ -1,22 +1,6 @@
|
||||||
inherit_from: .rubocop_todo.yml
|
#inherit_from: .rubocop_todo.yml
|
||||||
|
|
||||||
# No siempre queremos metadatear los modelos
|
|
||||||
Rails/CreateTableWithTimestamps:
|
|
||||||
Enabled: false
|
|
||||||
# Queremos poder hacer comentarios en castellano, esto quiere que
|
# Queremos poder hacer comentarios en castellano, esto quiere que
|
||||||
# saquemos las tildes
|
# saquemos las tildes
|
||||||
Style/AsciiComments:
|
Style/AsciiComments:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
# El estilo de módulo y clases anidados agrega mucha indentación para
|
|
||||||
# nuestros gusto
|
|
||||||
Style/ClassAndModuleChildren:
|
|
||||||
Enabled: false
|
|
||||||
Metrics/LineLength:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
Metrics/BlockLength:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
- 'config/routes.rb'
|
|
||||||
- 'db/seeds.rb'
|
|
||||||
- 'config/environments/production.rb'
|
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
# This configuration was generated by
|
|
||||||
# `rubocop --auto-gen-config`
|
|
||||||
# on 2019-04-05 17:51:53 -0300 using RuboCop version 0.66.0.
|
|
||||||
# The point is for the user to remove these configuration records
|
|
||||||
# one by one as the offenses are removed from the code base.
|
|
||||||
# Note that changes in the inspected code, or installation of new
|
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: EnforcedStyle.
|
|
||||||
# SupportedStyles: empty_lines, no_empty_lines
|
|
||||||
Layout/EmptyLinesAroundBlockBody:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
Metrics/AbcSize:
|
|
||||||
Max: 18
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
Metrics/CyclomaticComplexity:
|
|
||||||
Max: 9
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
# Configuration parameters: CountComments, ExcludedMethods.
|
|
||||||
Metrics/MethodLength:
|
|
||||||
Max: 13
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
Metrics/PerceivedComplexity:
|
|
||||||
Max: 9
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
Style/Documentation:
|
|
||||||
Exclude:
|
|
||||||
- 'spec/**/*'
|
|
||||||
- 'test/**/*'
|
|
||||||
- 'config/application.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: EnforcedStyle.
|
|
||||||
# SupportedStyles: when_needed, always, never
|
|
||||||
Style/FrozenStringLiteralComment:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Style/IfUnlessModifier:
|
|
||||||
Exclude:
|
|
||||||
- 'bin/bundle'
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
Style/MixinUsage:
|
|
||||||
Exclude:
|
|
||||||
- 'bin/setup'
|
|
||||||
- 'bin/update'
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: MinDigits, Strict.
|
|
||||||
Style/NumericLiterals:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
|
|
||||||
# Offense count: 4
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
|
|
||||||
# SupportedStyles: single_quotes, double_quotes
|
|
||||||
Style/StringLiterals:
|
|
||||||
Exclude:
|
|
||||||
- 'db/schema.rb'
|
|
||||||
|
|
||||||
# Offense count: 12
|
|
||||||
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
|
||||||
# URISchemes: http, https
|
|
||||||
Metrics/LineLength:
|
|
||||||
Max: 190
|
|
2
Gemfile
2
Gemfile
|
@ -40,7 +40,7 @@ group :development do
|
||||||
gem 'listen', '>= 3.0.5', '< 3.2'
|
gem 'listen', '>= 3.0.5', '< 3.2'
|
||||||
# Spring speeds up development by keeping your application running in
|
# Spring speeds up development by keeping your application running in
|
||||||
# the background. Read more: https://github.com/rails/spring
|
# the background. Read more: https://github.com/rails/spring
|
||||||
gem 'rubocop'
|
gem 'rubocop-rails'
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||||
gem 'yard'
|
gem 'yard'
|
||||||
|
|
23
Gemfile.lock
23
Gemfile.lock
|
@ -64,7 +64,7 @@ GEM
|
||||||
hkdf (0.3.0)
|
hkdf (0.3.0)
|
||||||
i18n (1.6.0)
|
i18n (1.6.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
jaro_winkler (1.5.2)
|
jaro_winkler (1.5.3)
|
||||||
jbuilder (2.8.0)
|
jbuilder (2.8.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
multi_json (>= 1.2)
|
multi_json (>= 1.2)
|
||||||
|
@ -90,13 +90,12 @@ GEM
|
||||||
nio4r (2.3.1)
|
nio4r (2.3.1)
|
||||||
nokogiri (1.10.3)
|
nokogiri (1.10.3)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
parallel (1.16.2)
|
parallel (1.17.0)
|
||||||
parser (2.6.2.0)
|
parser (2.6.3.0)
|
||||||
ast (~> 2.4.0)
|
ast (~> 2.4.0)
|
||||||
pry (0.12.2)
|
pry (0.12.2)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.9.0)
|
method_source (~> 0.9.0)
|
||||||
psych (3.1.0)
|
|
||||||
public_suffix (4.0.0)
|
public_suffix (4.0.0)
|
||||||
puma (3.12.1)
|
puma (3.12.1)
|
||||||
rack (2.0.7)
|
rack (2.0.7)
|
||||||
|
@ -132,15 +131,17 @@ GEM
|
||||||
rb-fsevent (0.10.3)
|
rb-fsevent (0.10.3)
|
||||||
rb-inotify (0.10.0)
|
rb-inotify (0.10.0)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
rubocop (0.66.0)
|
rubocop (0.72.0)
|
||||||
jaro_winkler (~> 1.5.1)
|
jaro_winkler (~> 1.5.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 2.5, != 2.5.1.1)
|
parser (>= 2.6)
|
||||||
psych (>= 3.1.0)
|
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 1.6)
|
unicode-display_width (>= 1.4.0, < 1.7)
|
||||||
ruby-progressbar (1.10.0)
|
rubocop-rails (2.2.0)
|
||||||
|
rack (>= 1.1)
|
||||||
|
rubocop (>= 0.72.0)
|
||||||
|
ruby-progressbar (1.10.1)
|
||||||
ruby_dep (1.5.0)
|
ruby_dep (1.5.0)
|
||||||
spring (2.0.2)
|
spring (2.0.2)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
|
@ -159,7 +160,7 @@ GEM
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tzinfo (1.2.5)
|
tzinfo (1.2.5)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
unicode-display_width (1.5.0)
|
unicode-display_width (1.6.0)
|
||||||
validate_url (1.0.8)
|
validate_url (1.0.8)
|
||||||
activemodel (>= 3.0.0)
|
activemodel (>= 3.0.0)
|
||||||
public_suffix
|
public_suffix
|
||||||
|
@ -185,7 +186,7 @@ DEPENDENCIES
|
||||||
puma (~> 3.11)
|
puma (~> 3.11)
|
||||||
rack-cors
|
rack-cors
|
||||||
rails (~> 5.2.3)
|
rails (~> 5.2.3)
|
||||||
rubocop
|
rubocop-rails
|
||||||
spring
|
spring
|
||||||
spring-watcher-listen (~> 2.0.0)
|
spring-watcher-listen (~> 2.0.0)
|
||||||
sqlite3
|
sqlite3
|
||||||
|
|
|
@ -47,6 +47,9 @@ class BarcasController < ApplicationController
|
||||||
@barca.piratas << current_pirata
|
@barca.piratas << current_pirata
|
||||||
|
|
||||||
if @barca.save
|
if @barca.save
|
||||||
|
piratas = Pirata.todas_menos(current_pirata).pluck(:id)
|
||||||
|
notify(subject: 'barcas.create.subject', piratas: piratas)
|
||||||
|
|
||||||
render status: :created
|
render status: :created
|
||||||
else
|
else
|
||||||
render json: { errors: @barca.errors.messages },
|
render json: { errors: @barca.errors.messages },
|
||||||
|
@ -129,4 +132,17 @@ class BarcasController < ApplicationController
|
||||||
def find_barca
|
def find_barca
|
||||||
@barca = Barca.find(params[:barca_id])
|
@barca = Barca.find(params[:barca_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notify(piratas:, subject:)
|
||||||
|
# Notificar a todas las piratas que hay una nueva barca para que
|
||||||
|
# se puedan sumar
|
||||||
|
payload = WebpushPayload.new(subject: I18n.t(subject,
|
||||||
|
barca: @barca.nombre),
|
||||||
|
message: @barca.descripcion,
|
||||||
|
endpoint: barca_path(@barca))
|
||||||
|
|
||||||
|
WebpushJob.perform_later(piratas: piratas,
|
||||||
|
ttl: 7.days.to_i,
|
||||||
|
payload: payload.to_json)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,8 +66,7 @@ class ConsensosController < ApplicationController
|
||||||
begin
|
begin
|
||||||
@consenso = @barca.consensos.find(params[:id])
|
@consenso = @barca.consensos.find(params[:id])
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render json: {}, status: :not_found
|
render(json: {}, status: :not_found) && return
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if @consenso.posiciones.empty? && @consenso.destroy
|
if @consenso.posiciones.empty? && @consenso.destroy
|
||||||
|
|
|
@ -15,7 +15,8 @@ class PosicionesController < ApplicationController
|
||||||
# Crea una posición dentro de un consenso
|
# Crea una posición dentro de un consenso
|
||||||
#
|
#
|
||||||
# @param :consenso_id [Integer] El ID del consenso
|
# @param :consenso_id [Integer] El ID del consenso
|
||||||
# @param :posicion [Hash] { posicion: { estado: @string, comentario: @string } }
|
# @param :posicion [Hash] { posicion: { estado: @string,
|
||||||
|
# comentario: @string } }
|
||||||
# @return [Hash] { id: @int, estado: @string, comentario: @string,
|
# @return [Hash] { id: @int, estado: @string, comentario: @string,
|
||||||
# pirata: @pirata }
|
# pirata: @pirata }
|
||||||
def create
|
def create
|
||||||
|
|
37
app/jobs/webpush_job.rb
Normal file
37
app/jobs/webpush_job.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Envía las notificaciones
|
||||||
|
class WebpushJob < ApplicationJob
|
||||||
|
queue_as :default
|
||||||
|
|
||||||
|
# @param :piratas [String,Array] 'all' para traer todas, array de IDs
|
||||||
|
# para filtrar
|
||||||
|
# @param :payload [WebpushPayload] La notificación a enviar
|
||||||
|
# @param :urgency [Symbol] La urgencia
|
||||||
|
# @param :ttl [Any] Duración convertible a segundos
|
||||||
|
def perform(piratas:, payload:, urgency: :normal, ttl: 1.day.to_i)
|
||||||
|
# Encontrar todas las piratas
|
||||||
|
piratas = find_piratas(piratas)
|
||||||
|
payload = WebpushPayload.from_json payload
|
||||||
|
|
||||||
|
# No cargar todas las piratas en memoria!
|
||||||
|
piratas.find_each do |pirata|
|
||||||
|
# Enviarles a todas sus suscripciones
|
||||||
|
pirata.webpush_subscriptions.find_each do |subscription|
|
||||||
|
subscription.payload_send(payload: payload,
|
||||||
|
urgency: urgency,
|
||||||
|
ttl: ttl)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_piratas(ids)
|
||||||
|
if ids == 'all'
|
||||||
|
Pirata.all
|
||||||
|
else
|
||||||
|
Pirata.where(id: ids)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -18,4 +18,6 @@ class Pirata < ApplicationRecord
|
||||||
# Una por correo
|
# Una por correo
|
||||||
validates :email, presence: true, uniqueness: true
|
validates :email, presence: true, uniqueness: true
|
||||||
validates :nick, presence: true, uniqueness: true
|
validates :nick, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
scope :todas_menos, ->(pirata) { where.not(id: pirata) }
|
||||||
end
|
end
|
||||||
|
|
20
app/models/webpush_payload.rb
Normal file
20
app/models/webpush_payload.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# El payload que se envía en la notificación
|
||||||
|
#
|
||||||
|
# @param :subject [String] El título de la notificación
|
||||||
|
# @param :message [String] El cuerpo de la notificación
|
||||||
|
# @param :endpoint [String] La URL a visitar al abrir la notificación
|
||||||
|
WebpushPayload = Struct.new(:subject, :message, :endpoint,
|
||||||
|
keyword_init: true) do
|
||||||
|
# Convertir el payload a JSON para poder enviarlo
|
||||||
|
#
|
||||||
|
# @return String
|
||||||
|
def to_json(opts = nil)
|
||||||
|
to_h.to_json(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_json(string)
|
||||||
|
new(JSON.parse(string))
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,4 +6,30 @@ class WebpushSubscription < ApplicationRecord
|
||||||
validates :endpoint, url: true
|
validates :endpoint, url: true
|
||||||
validates_uniqueness_of :auth, scope: %i[p256dh endpoint],
|
validates_uniqueness_of :auth, scope: %i[p256dh endpoint],
|
||||||
case_sensitive: false
|
case_sensitive: false
|
||||||
|
|
||||||
|
URGENCY = %w[very-low low normal high].freeze
|
||||||
|
|
||||||
|
# Envía la notificación
|
||||||
|
def payload_send(payload:, urgency: :normal, ttl: 1.day)
|
||||||
|
Webpush.payload_send(
|
||||||
|
vapid: {
|
||||||
|
subject: 'mailto:lumi@partidopirata.com.ar',
|
||||||
|
public_key: Rails.application.credentials.vapid.public_key,
|
||||||
|
private_key: Rails.application.credentials.vapid.private_key
|
||||||
|
},
|
||||||
|
endpoint: endpoint, auth: auth, p256dh: p256dh,
|
||||||
|
ttl: ttl.to_i, urgency: normalize_urgency(urgency),
|
||||||
|
message: payload.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def normalize_urgency(urgency)
|
||||||
|
if URGENCY.includes? urgency.to_s
|
||||||
|
urgency.to_s
|
||||||
|
else
|
||||||
|
'normal'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,33 +1,4 @@
|
||||||
# Files in the config/locales directory are used for internationalization
|
|
||||||
# and are automatically loaded by Rails. If you want to use locales other
|
|
||||||
# than English, add the necessary files in this directory.
|
|
||||||
#
|
|
||||||
# To use the locales, use `I18n.t`:
|
|
||||||
#
|
|
||||||
# I18n.t 'hello'
|
|
||||||
#
|
|
||||||
# In views, this is aliased to just `t`:
|
|
||||||
#
|
|
||||||
# <%= t('hello') %>
|
|
||||||
#
|
|
||||||
# To use a different locale, set it with `I18n.locale`:
|
|
||||||
#
|
|
||||||
# I18n.locale = :es
|
|
||||||
#
|
|
||||||
# This would use the information in config/locales/es.yml.
|
|
||||||
#
|
|
||||||
# The following keys must be escaped otherwise they will not be retrieved by
|
|
||||||
# the default I18n backend:
|
|
||||||
#
|
|
||||||
# true, false, on, off, yes, no
|
|
||||||
#
|
|
||||||
# Instead, surround them with single quotes.
|
|
||||||
#
|
|
||||||
# en:
|
|
||||||
# 'true': 'foo'
|
|
||||||
#
|
|
||||||
# To learn more, please read the Rails Internationalization guide
|
|
||||||
# available at http://guides.rubyonrails.org/i18n.html.
|
|
||||||
|
|
||||||
en:
|
en:
|
||||||
hello: "Hello world"
|
barcas:
|
||||||
|
create:
|
||||||
|
subject: '%{barca} has been created!'
|
||||||
|
|
4
config/locales/es.yml
Normal file
4
config/locales/es.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
es:
|
||||||
|
barcas:
|
||||||
|
create:
|
||||||
|
subject: '%{barca} creada, ¡al abordaje!'
|
24
test/jobs/webpush_job_test.rb
Normal file
24
test/jobs/webpush_job_test.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class WebpushJobTest < ActiveJob::TestCase
|
||||||
|
test 'se pueden enviar a todas las piratas' do
|
||||||
|
payload = WebpushPayload.new(subject: 'test', message: 'test', endpoint: 'https://partidopirata.com.ar')
|
||||||
|
|
||||||
|
assert_nothing_raised do
|
||||||
|
WebpushJob.perform_now(piratas: 'all', payload: payload.to_json,
|
||||||
|
urgency: :low, ttl: 1.day.to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se pueden enviar a algunas piratas' do
|
||||||
|
pirata = create :pirata
|
||||||
|
payload = WebpushPayload.new(subject: 'test', message: 'test', endpoint: 'https://partidopirata.com.ar')
|
||||||
|
|
||||||
|
assert_nothing_raised do
|
||||||
|
WebpushJob.perform_now(piratas: [pirata.id], payload: payload.to_json,
|
||||||
|
urgency: :low, ttl: 1.day.to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue