Follows and some new notifications (#1063)
* all the good changes * follows * dont send duplicates * remove follow_type for now * dont add all the extra stuff we're not implementing yet * refactor * lots of fixes * Delete activity.html.erb * Delete activity.text.erb * Update 20170209215819_create_follows.rb * Update schema.rb * Update mapping.rb * Update mailboxer.rb
This commit is contained in:
parent
a647d80efa
commit
b0deafc53e
29 changed files with 445 additions and 77 deletions
13
app/helpers/map_mailer_helper.rb
Normal file
13
app/helpers/map_mailer_helper.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
module MapMailerHelper
|
||||
def access_approved_subject(map)
|
||||
map.name + ' - access approved'
|
||||
end
|
||||
|
||||
def access_request_subject(map)
|
||||
map.name + ' - request to edit'
|
||||
end
|
||||
|
||||
def invite_to_edit_subject(map)
|
||||
map.name + ' - invited to edit'
|
||||
end
|
||||
end
|
10
app/helpers/topic_mailer_helper.rb
Normal file
10
app/helpers/topic_mailer_helper.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
module TopicMailerHelper
|
||||
def added_to_map_subject(topic, map)
|
||||
topic.name + ' was added to map ' + map.name
|
||||
end
|
||||
|
||||
def connected_subject(topic)
|
||||
'new synapse to topic ' + topic.name
|
||||
end
|
||||
end
|
|
@ -10,15 +10,24 @@ class ApplicationMailer < ActionMailer::Base
|
|||
class << self
|
||||
def mail_for_notification(notification)
|
||||
case notification.notification_code
|
||||
when MAILBOXER_CODE_ACCESS_REQUEST
|
||||
when MAP_ACCESS_REQUEST
|
||||
request = notification.notified_object
|
||||
MapMailer.access_request(request)
|
||||
when MAILBOXER_CODE_ACCESS_APPROVED
|
||||
when MAP_ACCESS_APPROVED
|
||||
request = notification.notified_object
|
||||
MapMailer.access_approved(request)
|
||||
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||
when MAP_INVITE_TO_EDIT
|
||||
user_map = notification.notified_object
|
||||
MapMailer.invite_to_edit(user_map)
|
||||
when TOPIC_ADDED_TO_MAP
|
||||
event = notification.notified_object
|
||||
TopicMailer.added_to_map(event, notification.recipients[0])
|
||||
when TOPIC_CONNECTED_1
|
||||
synapse = notification.notified_object
|
||||
TopicMailer.connected(synapse, synapse.topic1, notification.recipients[0])
|
||||
when TOPIC_CONNECTED_2
|
||||
synapse = notification.notified_object
|
||||
TopicMailer.connected(synapse, synapse.topic2, notification.recipients[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
class MapMailer < ApplicationMailer
|
||||
include MapMailerHelper
|
||||
default from: 'team@metamaps.cc'
|
||||
|
||||
def access_request(request)
|
||||
@request = request
|
||||
@map = request.map
|
||||
mail(to: @map.user.email, subject: request.requested_text)
|
||||
end
|
||||
|
||||
def access_approved(request)
|
||||
@request = request
|
||||
@map = request.map
|
||||
mail(to: request.user, subject: request.approved_text)
|
||||
mail(to: request.user.email, subject: access_approved_subject(@map))
|
||||
end
|
||||
|
||||
def access_request(request)
|
||||
@request = request
|
||||
@map = request.map
|
||||
mail(to: @map.user.email, subject: access_request_subject(@map))
|
||||
end
|
||||
|
||||
def invite_to_edit(user_map)
|
||||
@inviter = user_map.map.user
|
||||
@map = user_map.map
|
||||
mail(to: user_map.user.email, subject: @map.invited_text)
|
||||
mail(to: user_map.user.email, subject: invite_to_edit_subject(@map))
|
||||
end
|
||||
end
|
||||
|
|
17
app/mailers/topic_mailer.rb
Normal file
17
app/mailers/topic_mailer.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
class TopicMailer < ApplicationMailer
|
||||
include TopicMailerHelper
|
||||
default from: 'team@metamaps.cc'
|
||||
|
||||
def added_to_map(event, user)
|
||||
@entity = event.eventable
|
||||
@event = event
|
||||
mail(to: user.email, subject: added_to_map_subject(@entity, event.map))
|
||||
end
|
||||
|
||||
def connected(synapse, topic, user)
|
||||
@entity = topic
|
||||
@event = synapse
|
||||
mail(to: user.email, subject: connected_subject(topic))
|
||||
end
|
||||
end
|
|
@ -27,14 +27,6 @@ class AccessRequest < ApplicationRecord
|
|||
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
||||
end
|
||||
end
|
||||
|
||||
def requested_text
|
||||
map.name + ' - request to edit'
|
||||
end
|
||||
|
||||
def approved_text
|
||||
map.name + ' - access approved'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
module Events
|
||||
class TopicAddedToMap < Event
|
||||
# after_create :notify_users!
|
||||
after_create :notify_users!
|
||||
|
||||
def self.publish!(topic, map, user, meta)
|
||||
create!(kind: 'topic_added_to_map',
|
||||
|
@ -10,5 +10,12 @@ module Events
|
|||
user: user,
|
||||
meta: meta)
|
||||
end
|
||||
|
||||
def notify_users!
|
||||
# in the future, notify followers of both the topic, and the map
|
||||
NotificationService.notify_followers(eventable, TOPIC_ADDED_TO_MAP, self)
|
||||
# NotificationService.notify_followers(map, MAP_RECEIVED_TOPIC, self)
|
||||
end
|
||||
handle_asynchronously :notify_users!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
module Events
|
||||
class TopicUpdated < Event
|
||||
# after_create :notify_users!
|
||||
#after_create :notify_users!
|
||||
|
||||
def self.publish!(topic, user, meta)
|
||||
create!(kind: 'topic_updated',
|
||||
|
@ -9,5 +9,9 @@ module Events
|
|||
user: user,
|
||||
meta: meta)
|
||||
end
|
||||
|
||||
def notify_users!
|
||||
NotificationService.notify_followers(eventable, 'topic_updated', self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
19
app/models/follow.rb
Normal file
19
app/models/follow.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
class Follow < ApplicationRecord
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :followed, polymorphic: true
|
||||
has_one :follow_reason, dependent: :destroy
|
||||
|
||||
validates :user, presence: true
|
||||
validates :followed, presence: true
|
||||
validates :user, uniqueness: { scope: :followed, message: 'This entity is already followed by this user' }
|
||||
|
||||
after_create :add_subsetting
|
||||
|
||||
private
|
||||
|
||||
def add_subsetting
|
||||
follow_reason = FollowReason.create!(follow: self)
|
||||
end
|
||||
end
|
12
app/models/follow_reason.rb
Normal file
12
app/models/follow_reason.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
class FollowReason < ApplicationRecord
|
||||
REASONS = %w(created commented contributed followed shared_on starred).freeze
|
||||
|
||||
belongs_to :follow
|
||||
|
||||
validates :follow, presence: true
|
||||
|
||||
def has_reason
|
||||
created || commented || contributed || followed || shared_on || starred
|
||||
end
|
||||
end
|
|
@ -14,6 +14,8 @@ class Map < ApplicationRecord
|
|||
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: 'Synapse'
|
||||
has_many :messages, as: :resource, dependent: :destroy
|
||||
has_many :stars, dependent: :destroy
|
||||
has_many :follows, as: :followed, dependent: :destroy
|
||||
has_many :followers, :through => :follows, source: :user
|
||||
|
||||
has_many :access_requests, dependent: :destroy
|
||||
has_many :user_maps, dependent: :destroy
|
||||
|
@ -37,6 +39,7 @@ class Map < ApplicationRecord
|
|||
# Validate the attached image is image/jpg, image/png, etc
|
||||
validates_attachment_content_type :screenshot, content_type: %r{\Aimage/.*\Z}
|
||||
|
||||
after_create :after_created_async
|
||||
after_update :after_updated
|
||||
after_save :update_deferring_topics_and_synapses, if: :permission_changed?
|
||||
|
||||
|
@ -135,15 +138,25 @@ class Map < ApplicationRecord
|
|||
Synapse.where(defer_to_map_id: id).update(permission: permission)
|
||||
end
|
||||
|
||||
def invited_text
|
||||
name + ' - invited to edit'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(self, self.user, 'created')
|
||||
# notify users following the map creator
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def after_updated
|
||||
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
|
||||
end
|
||||
|
||||
def after_updated_async
|
||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||
FollowService.follow(self, updated_by, 'contributed')
|
||||
# NotificationService.notify_followers(self, 'map_updated', changed_attributes)
|
||||
# or better yet publish an event
|
||||
end
|
||||
end
|
||||
handle_asynchronously :after_updated_async
|
||||
end
|
||||
|
|
|
@ -14,7 +14,9 @@ class Mapping < ApplicationRecord
|
|||
delegate :name, to: :user, prefix: true
|
||||
|
||||
after_create :after_created
|
||||
after_create :after_created_async
|
||||
after_update :after_updated
|
||||
after_update :after_updated_async
|
||||
before_destroy :before_destroyed
|
||||
|
||||
def user_image
|
||||
|
@ -27,11 +29,10 @@ class Mapping < ApplicationRecord
|
|||
|
||||
def after_created
|
||||
if mappable_type == 'Topic'
|
||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicAdded', topic: mappable.filtered, mapping_id: id
|
||||
meta = { 'x': xloc, 'y': yloc, 'mapping_id': id }
|
||||
Events::TopicAddedToMap.publish!(mappable, map, user, meta)
|
||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicAdded', topic: mappable.filtered, mapping_id: id
|
||||
elsif mappable_type == 'Synapse'
|
||||
Events::SynapseAddedToMap.publish!(mappable, map, user, meta)
|
||||
ActionCable.server.broadcast(
|
||||
'map_' + map.id.to_s,
|
||||
type: 'synapseAdded',
|
||||
|
@ -40,8 +41,14 @@ class Mapping < ApplicationRecord
|
|||
topic2: mappable.topic2.filtered,
|
||||
mapping_id: id
|
||||
)
|
||||
Events::SynapseAddedToMap.publish!(mappable, map, user, nil)
|
||||
end
|
||||
end
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(map, user, 'contributed')
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def after_updated
|
||||
if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
|
||||
|
@ -50,6 +57,13 @@ class Mapping < ApplicationRecord
|
|||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicMoved', id: mappable.id, mapping_id: id, x: xloc, y: yloc
|
||||
end
|
||||
end
|
||||
|
||||
def after_updated_async
|
||||
if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
|
||||
FollowService.follow(map, updated_by, 'contributed')
|
||||
end
|
||||
end
|
||||
handle_asynchronously :after_updated_async
|
||||
|
||||
def before_destroyed
|
||||
if mappable.defer_to_map
|
||||
|
@ -66,5 +80,6 @@ class Mapping < ApplicationRecord
|
|||
Events::SynapseRemovedFromMap.publish!(mappable, map, updated_by, meta)
|
||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseRemoved', id: mappable.id, mapping_id: id
|
||||
end
|
||||
FollowService.follow(map, updated_by, 'contributed')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,8 @@ class Message < ApplicationRecord
|
|||
delegate :name, to: :user, prefix: true
|
||||
|
||||
after_create :after_created
|
||||
#after_create :after_created_async
|
||||
|
||||
|
||||
def user_image
|
||||
user.image.url
|
||||
|
@ -19,4 +21,10 @@ class Message < ApplicationRecord
|
|||
def after_created
|
||||
ActionCable.server.broadcast 'map_' + resource.id.to_s, type: 'messageCreated', message: as_json
|
||||
end
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(resource, user, 'commented')
|
||||
NotificationService.notify_followers(resource, 'map_message', self)
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
end
|
||||
|
|
|
@ -3,4 +3,19 @@ class Star < ActiveRecord::Base
|
|||
belongs_to :user
|
||||
belongs_to :map
|
||||
validates :map, uniqueness: { scope: :user, message: 'You have already starred this map' }
|
||||
|
||||
#after_create :after_created_async
|
||||
#before_destroy :before_destroyed
|
||||
|
||||
protected
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(map, user, 'starred')
|
||||
NotificationService.notify_followers(map, 'map_starred', self, 'created')
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def before_destroyed
|
||||
FollowService.remove_reason(map, user, 'starred')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,7 +26,9 @@ class Synapse < ApplicationRecord
|
|||
}
|
||||
|
||||
before_create :set_perm_by_defer
|
||||
after_create :after_created_async
|
||||
after_update :after_updated
|
||||
before_destroy :before_destroyed
|
||||
|
||||
delegate :name, to: :user, prefix: true
|
||||
|
||||
|
@ -72,6 +74,12 @@ class Synapse < ApplicationRecord
|
|||
def set_perm_by_defer
|
||||
permission = defer_to_map.permission if defer_to_map
|
||||
end
|
||||
|
||||
def after_created_async
|
||||
follow_ids = NotificationService.notify_followers(topic1, TOPIC_CONNECTED_1, self)
|
||||
NotificationService.notify_followers(topic2, TOPIC_CONNECTED_2, self, nil, follow_ids)
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def after_updated
|
||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||
|
@ -85,4 +93,10 @@ class Synapse < ApplicationRecord
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def before_destroyed
|
||||
# hard to know how to do this yet, because the synapse actually gets destroyed
|
||||
#NotificationService.notify_followers(topic1, 'topic_disconnected', self)
|
||||
#NotificationService.notify_followers(topic2, 'topic_disconnected', self)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,12 +15,17 @@ class Topic < ApplicationRecord
|
|||
|
||||
has_many :mappings, as: :mappable, dependent: :destroy
|
||||
has_many :maps, through: :mappings
|
||||
has_many :follows, as: :followed, dependent: :destroy
|
||||
has_many :followers, :through => :follows, source: :user
|
||||
|
||||
belongs_to :metacode
|
||||
|
||||
before_create :set_perm_by_defer
|
||||
before_create :create_metamap?
|
||||
after_create :after_created_async
|
||||
after_update :after_updated
|
||||
after_update :after_updated_async
|
||||
#before_destroy :before_destroyed
|
||||
|
||||
validates :permission, presence: true
|
||||
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
|
||||
|
@ -149,6 +154,12 @@ class Topic < ApplicationRecord
|
|||
self.link = Rails.application.routes.url_helpers
|
||||
.map_url(host: ENV['MAILER_DEFAULT_URL'], id: @map.id)
|
||||
end
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(self, self.user, 'created')
|
||||
# notify users following the topic creator
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def after_updated
|
||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||
|
@ -162,4 +173,16 @@ class Topic < ApplicationRecord
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def after_updated_async
|
||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||
FollowService.follow(self, updated_by, 'contributed')
|
||||
end
|
||||
end
|
||||
handle_asynchronously :after_updated_async
|
||||
|
||||
def before_destroyed
|
||||
# hard to know how to do this yet, because the topic actually gets destroyed
|
||||
#NotificationService.notify_followers(self, 'topic_deleted', ?)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,10 @@ class User < ApplicationRecord
|
|||
has_many :stars
|
||||
has_many :user_maps, dependent: :destroy
|
||||
has_many :shared_maps, through: :user_maps, source: :map
|
||||
has_many :follows, as: :followed
|
||||
has_many :followers, through: :follows, source: :user
|
||||
|
||||
has_many :following, class_name: 'Follow'
|
||||
|
||||
after_create :generate_code
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ class UserMap < ApplicationRecord
|
|||
belongs_to :access_request
|
||||
|
||||
after_create :after_created_async
|
||||
before_destroy :before_destroyed
|
||||
|
||||
def mark_invite_notifications_as_read
|
||||
Mailboxer::Notification.where(notified_object: self).find_each do |notification|
|
||||
|
@ -15,11 +16,17 @@ class UserMap < ApplicationRecord
|
|||
protected
|
||||
|
||||
def after_created_async
|
||||
FollowService.follow(map, user, 'shared_on')
|
||||
if access_request
|
||||
NotificationService.access_approved(self.access_request)
|
||||
else
|
||||
NotificationService.invite_to_edit(self)
|
||||
end
|
||||
# NotificationService.notify_followers(map, 'map_collaborator_added', self, 'shared_on')
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
|
||||
def before_destroyed
|
||||
FollowService.remove_reason(map, user, 'shared_on')
|
||||
end
|
||||
end
|
||||
|
|
35
app/services/follow_service.rb
Normal file
35
app/services/follow_service.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
class FollowService
|
||||
|
||||
|
||||
def self.follow(entity, user, reason)
|
||||
|
||||
#return unless is_tester(user)
|
||||
|
||||
follow = Follow.where(followed: entity, user: user).first_or_create
|
||||
if FollowReason::REASONS.include?(reason) && !follow.follow_reason.read_attribute(reason)
|
||||
follow.follow_reason.update_attribute(reason, true)
|
||||
end
|
||||
end
|
||||
|
||||
def self.unfollow(entity, user)
|
||||
Follow.where(followed: entity, user: user).destroy_all
|
||||
end
|
||||
|
||||
def self.remove_reason(entity, user, reason)
|
||||
return unless FollowReason::REASONS.include?(reason)
|
||||
follow = Follow.where(followed: entity, user: user).first
|
||||
if follow
|
||||
follow.follow_reason.update_attribute(reason, false)
|
||||
if !follow.follow_reason.has_reason
|
||||
follow.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def is_tester(user)
|
||||
%w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email)
|
||||
end
|
||||
end
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
class NotificationService
|
||||
extend TopicMailerHelper
|
||||
extend MapMailerHelper
|
||||
# for strip_tags
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
|
@ -10,43 +12,68 @@ class NotificationService
|
|||
)
|
||||
end
|
||||
|
||||
def self.get_template_for_event_type(event_type)
|
||||
'map_mailer/' + event_type
|
||||
end
|
||||
|
||||
def self.get_mailboxer_code_for_event_type(event_type)
|
||||
def self.get_settings_for_event(entity, event_type, event)
|
||||
case event_type
|
||||
when 'access_approved'
|
||||
MAILBOXER_CODE_ACCESS_APPROVED
|
||||
when 'access_request'
|
||||
MAILBOXER_CODE_ACCESS_REQUEST
|
||||
when 'invite_to_edit'
|
||||
MAILBOXER_CODE_INVITE_TO_EDIT
|
||||
when TOPIC_ADDED_TO_MAP
|
||||
subject = added_to_map_subject(entity, event.map)
|
||||
template = 'topic_mailer/added_to_map'
|
||||
when TOPIC_CONNECTED_1
|
||||
subject = connected_subject(event.topic1)
|
||||
template = 'topic_mailer/connected'
|
||||
when TOPIC_CONNECTED_2
|
||||
subject = connected_subject(event.topic2)
|
||||
template = 'topic_mailer/connected'
|
||||
end
|
||||
|
||||
{template: template, subject: subject}
|
||||
end
|
||||
|
||||
def self.send_for_follows(follows, entity, event_type, event)
|
||||
return if follows.length == 0
|
||||
settings = get_settings_for_event(entity, event_type, event)
|
||||
# we'll prbly want to put the body into the actual loop so we can pass the current user in as a local
|
||||
body = renderer.render(template: settings[:template], locals: { entity: entity, event: event }, layout: false)
|
||||
follows.each{|follow|
|
||||
# this handles email and in-app notifications, in the future, include push
|
||||
follow.user.notify(settings[:subject], body, event, false, event_type, (follow.user.emails_allowed && follow.email), event.user)
|
||||
# push could be handled with Actioncable to send transient notifications to the UI
|
||||
# the receipt from the notify call could be used to link to the full notification
|
||||
}
|
||||
end
|
||||
|
||||
def self.notify_followers(entity, event_type, event, reason_filter = nil, exclude_follows = nil)
|
||||
follows = entity.follows.where.not(user_id: event.user.id)
|
||||
|
||||
if !exclude_follows.nil?
|
||||
follows = follows.where.not(id: exclude_follows)
|
||||
end
|
||||
|
||||
if reason_filter.class == String && FollowReason::REASONS.include?(reason_filter)
|
||||
follows = follows.joins(:follow_reason).where('follow_reasons.' + reason_filter => true)
|
||||
elsif reason_filter.class == Array
|
||||
# TODO: throw an error here if all the reasons aren't valid
|
||||
follows = follows.joins(:follow_reason).where(reason_filter.map{|r| "follow_reasons.#{r} = 't'"}.join(' OR '))
|
||||
end
|
||||
send_for_follows(follows, entity, event_type, event)
|
||||
return follows.map(&:id)
|
||||
end
|
||||
|
||||
def self.access_request(request)
|
||||
event_type = 'access_request'
|
||||
template = get_template_for_event_type(event_type)
|
||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||
body = renderer.render(template: template, locals: { map: request.map, request: request }, layout: false)
|
||||
request.map.user.notify(request.requested_text, body, request, false, mailboxer_code, true, request.user)
|
||||
subject = access_request_subject(request.map)
|
||||
body = renderer.render(template: 'map_mailer/access_request', locals: { map: request.map, request: request }, layout: false)
|
||||
request.map.user.notify(subject, body, request, false, MAP_ACCESS_REQUEST, true, request.user)
|
||||
end
|
||||
|
||||
def self.access_approved(request)
|
||||
event_type = 'access_approved'
|
||||
template = get_template_for_event_type(event_type)
|
||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||
body = renderer.render(template: template, locals: { map: request.map }, layout: false)
|
||||
request.user.notify(request.approved_text, body, request, false, mailboxer_code, true, request.map.user)
|
||||
subject = access_approved_subject(request.map)
|
||||
body = renderer.render(template: 'map_mailer/access_approved', locals: { map: request.map }, layout: false)
|
||||
request.user.notify(subject, body, request, false, MAP_ACCESS_APPROVED, true, request.map.user)
|
||||
end
|
||||
|
||||
def self.invite_to_edit(user_map)
|
||||
event_type = 'invite_to_edit'
|
||||
template = get_template_for_event_type(event_type)
|
||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||
body = renderer.render(template: template, locals: { map: user_map.map, inviter: user_map.map.user }, layout: false)
|
||||
user_map.user.notify(user_map.map.invited_text, body, user_map, false, mailboxer_code, true, user_map.map.user)
|
||||
subject = invite_to_edit_subject(user_map.map)
|
||||
body = renderer.render(template: 'map_mailer/invite_to_edit', locals: { map: user_map.map, inviter: user_map.map.user }, layout: false)
|
||||
user_map.user.notify(subject, body, user_map, false, MAP_INVITE_TO_EDIT, true, user_map.map.user)
|
||||
end
|
||||
|
||||
# note: this is a global function, probably called from the rails console with some html body
|
||||
|
@ -54,25 +81,9 @@ class NotificationService
|
|||
users = opts[:users] || User.all
|
||||
obj = opts[:obj] || nil
|
||||
sanitize_text = opts[:sanitize_text] || false
|
||||
notification_code = opts[:notification_code] || MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
||||
notification_code = opts[:notification_code] || MESSAGE_FROM_DEVS
|
||||
send_mail = opts[:send_mail] || true
|
||||
sender = opts[:sender] || User.find_by(email: 'ishanshapiro@gmail.com')
|
||||
Mailboxer::Notification.notify_all(users, subject, body, obj, sanitize_text, notification_code, send_mail, sender)
|
||||
end
|
||||
|
||||
def self.text_for_notification(notification)
|
||||
case notification.notification_code
|
||||
when MAILBOXER_CODE_ACCESS_APPROVED
|
||||
map = notification.notified_object.map
|
||||
'granted your request to edit map <span class="in-bold">' + map.name + '</span>'
|
||||
when MAILBOXER_CODE_ACCESS_REQUEST
|
||||
map = notification.notified_object.map
|
||||
'wants permission to map with you on <span class="in-bold">' + map.name + '</span> <div class="action">Offer a response</div>'
|
||||
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||
map = notification.notified_object.map
|
||||
'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
||||
when MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
||||
notification.subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<h2 class="title">Notifications</h4>
|
||||
</header>
|
||||
<ul class="notifications">
|
||||
<% blacklist = [MAILBOXER_CODE_ACCESS_REQUEST, MAILBOXER_CODE_ACCESS_APPROVED, MAILBOXER_CODE_INVITE_TO_EDIT] %>
|
||||
<% blacklist = [MAP_ACCESS_REQUEST, MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT] %>
|
||||
<% notifications = @notifications.to_a.delete_if{|n| blacklist.include?(n.notification_code) && (n.notified_object.nil? || n.notified_object.map.nil?) }%>
|
||||
<% notifications.each do |notification| %>
|
||||
<% receipt = @receipts.find_by(notification_id: notification.id) %>
|
||||
|
@ -18,7 +18,34 @@
|
|||
</div>
|
||||
<div class="notification-body">
|
||||
<div class="in-bold"><%= notification.sender.name %></div>
|
||||
<%= raw NotificationService.text_for_notification(notification) %>
|
||||
<%=
|
||||
case notification.notification_code
|
||||
when MAP_ACCESS_APPROVED
|
||||
map = notification.notified_object.map
|
||||
output = 'granted your request to edit map <span class="in-bold">' + map.name + '</span>'
|
||||
when MAP_ACCESS_REQUEST
|
||||
map = notification.notified_object.map
|
||||
output = 'wants permission to map with you on <span class="in-bold">' + map.name + '</span> <div class="action">Offer a response</div>'
|
||||
when MAP_INVITE_TO_EDIT
|
||||
map = notification.notified_object.map
|
||||
output = 'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
||||
when TOPIC_ADDED_TO_MAP
|
||||
topic = notification.notified_object.eventable
|
||||
map = notification.notified_object.map
|
||||
output = 'added topic <span class="in-bold">' + topic.name + '</span> to map <span class="in-bold">' + map.name + '</span>'
|
||||
when TOPIC_CONNECTED_1
|
||||
topic1 = notification.notified_object.topic1
|
||||
topic2 = notification.notified_object.topic2
|
||||
output = 'connected <span class="in-bold">' + topic1.name + '</span> to <span class="in-bold">' + topic2.name + '</span>'
|
||||
when TOPIC_CONNECTED_2
|
||||
topic1 = notification.notified_object.topic1
|
||||
topic2 = notification.notified_object.topic2
|
||||
output = 'connected <span class="in-bold">' + topic2.name + '</span> to <span class="in-bold">' + topic1.name + '</span>'
|
||||
when MESSAGE_FROM_DEVS
|
||||
output = notification.subject
|
||||
end
|
||||
raw output
|
||||
%>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="notification-read-unread">
|
||||
|
|
11
app/views/topic_mailer/added_to_map.html.erb
Normal file
11
app/views/topic_mailer/added_to_map.html.erb
Normal file
|
@ -0,0 +1,11 @@
|
|||
<% topic = @entity || entity %>
|
||||
<% event = @event || event %>
|
||||
<% button_style = "background-color:#4fc059;border-radius:2px;color:white;display:inline-block;font-family:Roboto,Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;min-height:29px;line-height:29px;min-width:54px;outline:0px;padding:0 8px;text-align:center;text-decoration:none" %>
|
||||
<p>
|
||||
<span style="font-weight: bold;"><%= event.user.name %></span>
|
||||
added topic <span style="font-weight: bold"><%= topic.name %></span>
|
||||
to map <span style="font-weight: bold"><%= event.map.name %></span>
|
||||
</p>
|
||||
|
||||
<%= link_to 'Go to Topic', topic_url(topic), style: button_style %>
|
||||
<%= link_to 'Go to Map', map_url(event.map), style: button_style %>
|
6
app/views/topic_mailer/added_to_map.text.erb
Normal file
6
app/views/topic_mailer/added_to_map.text.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
<% topic = @entity || entity %>
|
||||
<% event = @event || event %>
|
||||
<%= event.user.name %> added topic <%= topic.name %> to map <%= event.map.name %>
|
||||
|
||||
topic_url(topic)
|
||||
map_url(event.map)
|
15
app/views/topic_mailer/connected.html.erb
Normal file
15
app/views/topic_mailer/connected.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% topic1 = @entity || entity
|
||||
synapse = @event || event
|
||||
button_style = "background-color:#4fc059;border-radius:2px;color:white;display:inline-block;font-family:Roboto,Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;min-height:29px;line-height:29px;min-width:54px;outline:0px;padding:0 8px;text-align:center;text-decoration:none"
|
||||
topic2 = (topic1.id == synapse.topic1_id ? synapse.topic2 : synapse.topic1) %>
|
||||
|
||||
<p>
|
||||
<span style="font-weight: bold;"><%= synapse.user.name %></span>
|
||||
connected topic <span style="font-weight: bold"><%= topic1.name %></span>
|
||||
to topic <span style="font-weight: bold"><%= topic2.name %></span>
|
||||
<% if synapse.desc.length > 0 %>
|
||||
with the description "<%= synapse.desc %>".
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
<%= link_to 'View the connection', topic_url(topic1), style: button_style %>
|
8
app/views/topic_mailer/connected.text.erb
Normal file
8
app/views/topic_mailer/connected.text.erb
Normal file
|
@ -0,0 +1,8 @@
|
|||
<% topic1 = @entity || entity
|
||||
synapse = @event || event
|
||||
topic2 = (topic1.id == synapse.topic1_id ? synapse.topic2 : synapse.topic1) %>
|
||||
|
||||
<%= synapse.user.name %> connected topic <%= topic1.name %> to topic <%= topic2.name %>
|
||||
<%= synapse.desc.length > 0 ? ' with the description' + event.desc : '' %>
|
||||
|
||||
<%= topic_url(topic1) %>
|
|
@ -7,10 +7,36 @@
|
|||
# notification_code: MAILBOXER_CODE_ACCESS_REQUEST
|
||||
# },
|
||||
# which would imply that this is an access request to Map.find(1)
|
||||
MAILBOXER_CODE_ACCESS_REQUEST = 'ACCESS_REQUEST'
|
||||
MAILBOXER_CODE_ACCESS_APPROVED = 'ACCESS_APPROVED'
|
||||
MAILBOXER_CODE_INVITE_TO_EDIT = 'INVITE_TO_EDIT'
|
||||
MAILBOXER_CODE_MESSAGE_FROM_DEVS = 'MESSAGE_FROM_DEVS'
|
||||
MESSAGE_FROM_DEVS = 'MESSAGE_FROM_DEVS'
|
||||
|
||||
# these ones are old and can't change without a migration
|
||||
MAP_ACCESS_APPROVED = 'ACCESS_APPROVED'
|
||||
MAP_ACCESS_REQUEST = 'ACCESS_REQUEST'
|
||||
MAP_INVITE_TO_EDIT = 'INVITE_TO_EDIT'
|
||||
|
||||
# these ones are new
|
||||
# this one's a catch all for occurences on the map
|
||||
# MAP_ACTIVITY = 'MAP_ACTIVITY'
|
||||
# MAP_RECEIVED_TOPIC
|
||||
# MAP_LOST_TOPIC
|
||||
# MAP_TOPIC_MOVED
|
||||
# MAP_RECEIVED_SYNAPSE
|
||||
# MAP_LOST_SYNAPSE
|
||||
# MAP_COLLABORATOR_ADDED
|
||||
# MAP_UPDATED
|
||||
# ADD_MAP_FORKED
|
||||
# MAP_ADDED_TO_MAP
|
||||
# MAP_MESSAGE
|
||||
# MAP_STARRED
|
||||
# MAP_COLLABORATOR_REMOVED
|
||||
|
||||
TOPIC_ADDED_TO_MAP = 'TOPIC_ADDED_TO_MAP'
|
||||
TOPIC_CONNECTED_1 = 'TOPIC_CONNECTED_1'
|
||||
TOPIC_CONNECTED_2 = 'TOPIC_CONNECTED_2'
|
||||
# TOPIC_DELETED
|
||||
# TOPIC_DISCONNECTED
|
||||
# TOPIC_UPDATED
|
||||
# TOPIC_REMOVED_FROM_MAP
|
||||
|
||||
Mailboxer.setup do |config|
|
||||
# Configures if your application uses or not email sending for Notifications and Messages
|
||||
|
|
9
db/migrate/20170209215819_create_follows.rb
Normal file
9
db/migrate/20170209215819_create_follows.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class CreateFollows < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
create_table :follows do |t|
|
||||
t.references :user, index: true
|
||||
t.references :followed, polymorphic: true, index: true
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
14
db/migrate/20170209215911_create_follow_reasons.rb
Normal file
14
db/migrate/20170209215911_create_follow_reasons.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
class CreateFollowReasons < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
create_table :follow_reasons do |t|
|
||||
t.references :follow, index: true
|
||||
t.boolean :created
|
||||
t.boolean :contributed
|
||||
t.boolean :commented
|
||||
t.boolean :followed
|
||||
t.boolean :shared_on
|
||||
t.boolean :starred
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
25
db/schema.rb
25
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: 20170208161305) do
|
||||
ActiveRecord::Schema.define(version: 20170209215911) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -67,6 +67,29 @@ ActiveRecord::Schema.define(version: 20170208161305) do
|
|||
t.index ["user_id"], name: "index_events_on_user_id", using: :btree
|
||||
end
|
||||
|
||||
create_table "follow_reasons", force: :cascade do |t|
|
||||
t.integer "follow_id"
|
||||
t.boolean "created"
|
||||
t.boolean "contributed"
|
||||
t.boolean "commented"
|
||||
t.boolean "followed"
|
||||
t.boolean "shared_on"
|
||||
t.boolean "starred"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["follow_id"], name: "index_follow_reasons_on_follow_id", using: :btree
|
||||
end
|
||||
|
||||
create_table "follows", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "followed_type"
|
||||
t.integer "followed_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["followed_type", "followed_id"], name: "index_follows_on_followed_type_and_followed_id", using: :btree
|
||||
t.index ["user_id"], name: "index_follows_on_user_id", using: :btree
|
||||
end
|
||||
|
||||
create_table "in_metacode_sets", force: :cascade do |t|
|
||||
t.integer "metacode_id"
|
||||
t.integer "metacode_set_id"
|
||||
|
|
Loading…
Reference in a new issue