follows
This commit is contained in:
parent
de0100a0b9
commit
713f731aaf
40 changed files with 428 additions and 23 deletions
|
@ -19,6 +19,10 @@ class ApplicationMailer < ActionMailer::Base
|
||||||
when MAILBOXER_CODE_INVITE_TO_EDIT
|
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||||
user_map = notification.notified_object
|
user_map = notification.notified_object
|
||||||
MapMailer.invite_to_edit(user_map)
|
MapMailer.invite_to_edit(user_map)
|
||||||
|
when MAILBOXER_CODE_MAP_MESSAGE
|
||||||
|
when MAILBOXER_CODE_MAP_STARRED
|
||||||
|
when MAILBOXER_CODE_TOPIC_ADDED_TO_MAP
|
||||||
|
when MAILBOXER_CODE_TOPIC_CONNECTED
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,18 +5,18 @@ class MapMailer < ApplicationMailer
|
||||||
def access_request(request)
|
def access_request(request)
|
||||||
@request = request
|
@request = request
|
||||||
@map = request.map
|
@map = request.map
|
||||||
mail(to: @map.user.email, subject: request.requested_text)
|
mail(to: @map.user.email, subject: NotificationService.get_subject_for_event(@map, 'access_request', request))
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_approved(request)
|
def access_approved(request)
|
||||||
@request = request
|
@request = request
|
||||||
@map = request.map
|
@map = request.map
|
||||||
mail(to: request.user, subject: request.approved_text)
|
mail(to: request.user, subject: NotificationService.get_subject_for_event(@map, 'access_approved', request))
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_to_edit(user_map)
|
def invite_to_edit(user_map)
|
||||||
@inviter = user_map.map.user
|
@inviter = user_map.map.user
|
||||||
@map = user_map.map
|
@map = user_map.map
|
||||||
mail(to: user_map.user.email, subject: @map.invited_text)
|
mail(to: user_map.user.email, subject: NotificationService.get_subject_for_event(@map, 'invite_to_edit', user_map))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,14 +28,6 @@ class AccessRequest < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def requested_text
|
|
||||||
map.name + ' - request to edit'
|
|
||||||
end
|
|
||||||
|
|
||||||
def approved_text
|
|
||||||
map.name + ' - access approved'
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def after_created_async
|
def after_created_async
|
||||||
|
|
|
@ -9,5 +9,9 @@ module Events
|
||||||
user: user,
|
user: user,
|
||||||
meta: meta)
|
meta: meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notify_users!
|
||||||
|
NotificationService.notify_followers(eventable, 'topic_updated', self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
21
app/models/follow.rb
Normal file
21
app/models/follow.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class Follow < ApplicationRecord
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :followed, polymorphic: true
|
||||||
|
has_one :follow_reason, dependent: :destroy
|
||||||
|
has_one :follow_type, 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_subsettings
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def add_subsettings
|
||||||
|
follow_reason = FollowReason.create!(follow: self)
|
||||||
|
follow_type = FollowType.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
|
6
app/models/follow_type.rb
Normal file
6
app/models/follow_type.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class FollowType < ApplicationRecord
|
||||||
|
belongs_to :follow
|
||||||
|
|
||||||
|
validates :follow, presence: true
|
||||||
|
end
|
|
@ -14,6 +14,8 @@ class Map < ApplicationRecord
|
||||||
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: 'Synapse'
|
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: 'Synapse'
|
||||||
has_many :messages, as: :resource, dependent: :destroy
|
has_many :messages, as: :resource, dependent: :destroy
|
||||||
has_many :stars, 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 :access_requests, dependent: :destroy
|
||||||
has_many :user_maps, 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
|
# Validate the attached image is image/jpg, image/png, etc
|
||||||
validates_attachment_content_type :screenshot, content_type: %r{\Aimage/.*\Z}
|
validates_attachment_content_type :screenshot, content_type: %r{\Aimage/.*\Z}
|
||||||
|
|
||||||
|
after_create :after_created_async
|
||||||
after_update :after_updated
|
after_update :after_updated
|
||||||
after_save :update_deferring_topics_and_synapses, if: :permission_changed?
|
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)
|
Synapse.where(defer_to_map_id: id).update(permission: permission)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invited_text
|
|
||||||
name + ' - invited to edit'
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
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
|
def after_updated
|
||||||
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
|
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -6,6 +6,8 @@ class Message < ApplicationRecord
|
||||||
delegate :name, to: :user, prefix: true
|
delegate :name, to: :user, prefix: true
|
||||||
|
|
||||||
after_create :after_created
|
after_create :after_created
|
||||||
|
after_create :after_created_async
|
||||||
|
|
||||||
|
|
||||||
def user_image
|
def user_image
|
||||||
user.image.url
|
user.image.url
|
||||||
|
@ -19,4 +21,10 @@ class Message < ApplicationRecord
|
||||||
def after_created
|
def after_created
|
||||||
ActionCable.server.broadcast 'map_' + resource.id.to_s, type: 'messageCreated', message: as_json
|
ActionCable.server.broadcast 'map_' + resource.id.to_s, type: 'messageCreated', message: as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def after_created_async
|
||||||
|
FollowService.follow(resource, user, 'commented')
|
||||||
|
NotificationService.notify_followers(resource, 'map_message', self)
|
||||||
|
end
|
||||||
|
handle_asynchronously :after_created_async
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,4 +3,19 @@ class Star < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :map
|
belongs_to :map
|
||||||
validates :map, uniqueness: { scope: :user, message: 'You have already starred this 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
|
end
|
||||||
|
|
|
@ -26,7 +26,9 @@ class Synapse < ApplicationRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
before_create :set_perm_by_defer
|
before_create :set_perm_by_defer
|
||||||
|
after_create :after_created_async
|
||||||
after_update :after_updated
|
after_update :after_updated
|
||||||
|
before_destroy :before_destroyed
|
||||||
|
|
||||||
delegate :name, to: :user, prefix: true
|
delegate :name, to: :user, prefix: true
|
||||||
|
|
||||||
|
@ -73,6 +75,12 @@ class Synapse < ApplicationRecord
|
||||||
permission = defer_to_map.permission if defer_to_map
|
permission = defer_to_map.permission if defer_to_map
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def after_created_async
|
||||||
|
NotificationService.notify_followers(topic1, 'topic_connected', self)
|
||||||
|
NotificationService.notify_followers(topic2, 'topic_connected', self)
|
||||||
|
end
|
||||||
|
handle_asynchronously :after_created_async
|
||||||
|
|
||||||
def after_updated
|
def after_updated
|
||||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
|
@ -85,4 +93,10 @@ class Synapse < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -15,12 +15,17 @@ class Topic < ApplicationRecord
|
||||||
|
|
||||||
has_many :mappings, as: :mappable, dependent: :destroy
|
has_many :mappings, as: :mappable, dependent: :destroy
|
||||||
has_many :maps, through: :mappings
|
has_many :maps, through: :mappings
|
||||||
|
has_many :follows, as: :followed, dependent: :destroy
|
||||||
|
has_many :followers, :through => :follows, source: :user
|
||||||
|
|
||||||
belongs_to :metacode
|
belongs_to :metacode
|
||||||
|
|
||||||
before_create :set_perm_by_defer
|
before_create :set_perm_by_defer
|
||||||
before_create :create_metamap?
|
before_create :create_metamap?
|
||||||
|
after_create :after_created_async
|
||||||
after_update :after_updated
|
after_update :after_updated
|
||||||
|
after_update :after_updated_async
|
||||||
|
#before_destroy :before_destroyed
|
||||||
|
|
||||||
validates :permission, presence: true
|
validates :permission, presence: true
|
||||||
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
|
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
|
||||||
|
@ -150,6 +155,12 @@ class Topic < ApplicationRecord
|
||||||
.map_url(host: ENV['MAILER_DEFAULT_URL'], id: @map.id)
|
.map_url(host: ENV['MAILER_DEFAULT_URL'], id: @map.id)
|
||||||
end
|
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
|
def after_updated
|
||||||
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
|
@ -162,4 +173,16 @@ class Topic < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -12,6 +12,10 @@ class User < ApplicationRecord
|
||||||
has_many :stars
|
has_many :stars
|
||||||
has_many :user_maps, dependent: :destroy
|
has_many :user_maps, dependent: :destroy
|
||||||
has_many :shared_maps, through: :user_maps, source: :map
|
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
|
after_create :generate_code
|
||||||
|
|
||||||
|
|
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
|
|
@ -22,31 +22,124 @@ class NotificationService
|
||||||
MAILBOXER_CODE_ACCESS_REQUEST
|
MAILBOXER_CODE_ACCESS_REQUEST
|
||||||
when 'invite_to_edit'
|
when 'invite_to_edit'
|
||||||
MAILBOXER_CODE_INVITE_TO_EDIT
|
MAILBOXER_CODE_INVITE_TO_EDIT
|
||||||
|
|
||||||
|
when 'map_activity'
|
||||||
|
MAILBOXER_CODE_MAP_ACTIVITY
|
||||||
|
when 'map_collaborator_added'
|
||||||
|
MAILBOXER_CODE_MAP_COLLABORATOR_ADDED
|
||||||
|
when 'map_updated'
|
||||||
|
MAILBOXER_CODE_MAP_UPDATED
|
||||||
|
when 'map_message'
|
||||||
|
MAILBOXER_CODE_MAP_MESSAGE
|
||||||
|
when 'map_starred'
|
||||||
|
MAILBOXER_CODE_MAP_STARRED
|
||||||
|
|
||||||
|
when 'topic_added_to_map'
|
||||||
|
MAILBOXER_CODE_TOPIC_ADDED_TO_MAP
|
||||||
|
when 'topic_connected'
|
||||||
|
MAILBOXER_CODE_TOPIC_CONNECTED
|
||||||
|
when 'topic_deleted'
|
||||||
|
MAILBOXER_CODE_TOPIC_DELETED
|
||||||
|
when 'topic_disconnected'
|
||||||
|
MAILBOXER_CODE_TOPIC_DISCONNECTED
|
||||||
|
when 'topic_updated'
|
||||||
|
MAILBOXER_CODE_TOPIC_UPDATED
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_subject_for_event(entity, event_type, event)
|
||||||
|
case event_type
|
||||||
|
when 'access_approved' # event is an AccessRequest
|
||||||
|
entity.name + ' - access approved'
|
||||||
|
when 'access_request' # event is an AccessRequest
|
||||||
|
entity.name + ' - request to edit'
|
||||||
|
when 'invite_to_edit' # event is a UserMap
|
||||||
|
entity.name + ' - invited to edit'
|
||||||
|
|
||||||
|
when 'map_activity' #disabled
|
||||||
|
'placeholder'
|
||||||
|
when 'map_collaborator_added' #disabled
|
||||||
|
'placeholder'
|
||||||
|
when 'map_updated' #disabled
|
||||||
|
'placeholder'
|
||||||
|
when 'map_message' # event is a Message
|
||||||
|
entity.name + ' - received a chat message'
|
||||||
|
when 'map_starred' # event is a Star
|
||||||
|
entity.name + ' was starred by ' + event.user.name
|
||||||
|
|
||||||
|
when 'topic_added_to_map' # event is an Event::TopicAddedToMap
|
||||||
|
entity.name + ' was added to map ' + event.map.name
|
||||||
|
when 'topic_connected' # event is a Synapse
|
||||||
|
'new synapse to topic ' + entity.name
|
||||||
|
when 'topic_deleted' #disabled
|
||||||
|
'placeholder'
|
||||||
|
when 'topic_disconnected' #disabled
|
||||||
|
'placeholder'
|
||||||
|
when 'topic_updated' #disabled
|
||||||
|
'placeholder'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_for_follows(follows, entity, event_type, event)
|
||||||
|
return if follows.length == 0
|
||||||
|
template = get_template_for_event_type(event_type)
|
||||||
|
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||||
|
subject = get_subject_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: template, locals: { entity: entity, event: event }, layout: false)
|
||||||
|
follows.each{|follow|
|
||||||
|
# don't send if they've indicated disinterest in this event_type
|
||||||
|
return unless follow.follow_type.all || follow.follow_type.read_attribute(event_type)
|
||||||
|
# this handles email and in-app notifications, in the future, include push
|
||||||
|
receipt = follow.user.notify(subject, body, event, false, mailboxer_code, (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)
|
||||||
|
follows = entity.follows
|
||||||
|
|
||||||
|
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
|
||||||
|
# filter out the person who took the action
|
||||||
|
follows = follows.to_a.delete_if{|f| f.user.id == event.user.id}
|
||||||
|
send_for_follows(follows, entity, event_type, event)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: refactor this
|
||||||
def self.access_request(request)
|
def self.access_request(request)
|
||||||
event_type = 'access_request'
|
event_type = 'access_request'
|
||||||
template = get_template_for_event_type(event_type)
|
template = get_template_for_event_type(event_type)
|
||||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||||
|
subject = get_subject_for_event(request.map, event_type, request)
|
||||||
body = renderer.render(template: template, locals: { map: request.map, request: request }, layout: false)
|
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)
|
request.map.user.notify(subject, body, request, false, mailboxer_code, true, request.user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: refactor this
|
||||||
def self.access_approved(request)
|
def self.access_approved(request)
|
||||||
event_type = 'access_approved'
|
event_type = 'access_approved'
|
||||||
template = get_template_for_event_type(event_type)
|
template = get_template_for_event_type(event_type)
|
||||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||||
|
subject = get_subject_for_event(request.map, event_type, request)
|
||||||
body = renderer.render(template: template, locals: { map: request.map }, layout: false)
|
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)
|
request.user.notify(subject, body, request, false, mailboxer_code, true, request.map.user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: refactor this
|
||||||
def self.invite_to_edit(user_map)
|
def self.invite_to_edit(user_map)
|
||||||
event_type = 'invite_to_edit'
|
event_type = 'invite_to_edit'
|
||||||
template = get_template_for_event_type(event_type)
|
template = get_template_for_event_type(event_type)
|
||||||
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
mailboxer_code = get_mailboxer_code_for_event_type(event_type)
|
||||||
|
subject = get_subject_for_event(user_map.map, event_type, user_map)
|
||||||
body = renderer.render(template: template, locals: { map: user_map.map, inviter: user_map.map.user }, layout: false)
|
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)
|
user_map.user.notify(subject, body, user_map, false, mailboxer_code, true, user_map.map.user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# note: this is a global function, probably called from the rails console with some html body
|
# note: this is a global function, probably called from the rails console with some html body
|
||||||
|
@ -71,6 +164,20 @@ class NotificationService
|
||||||
when MAILBOXER_CODE_INVITE_TO_EDIT
|
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||||
map = notification.notified_object.map
|
map = notification.notified_object.map
|
||||||
'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
||||||
|
when MAILBOXER_CODE_MAP_MESSAGE
|
||||||
|
map = notification.notified_object.resource
|
||||||
|
'commented on map <span class="in-bold">' + map.name + '</span>'
|
||||||
|
when MAILBOXER_CODE_MAP_STARRED
|
||||||
|
map = notification.notified_object.map
|
||||||
|
'starred map <span class="in-bold">' + map.name + '</span>'
|
||||||
|
when MAILBOXER_CODE_TOPIC_ADDED_TO_MAP
|
||||||
|
topic = notification.notified_object.eventable
|
||||||
|
map = notification.notified_object.map
|
||||||
|
'added topic <span class="in-bold">' + topic.name + '</span> to map <span class="in-bold">' + map.name + '</span>'
|
||||||
|
when MAILBOXER_CODE_TOPIC_CONNECTED
|
||||||
|
topic1 = notification.notified_object.topic1
|
||||||
|
topic2 = notification.notified_object.topic2
|
||||||
|
'connected <span class="in-bold">' + topic1.name + '</span> to <span class="in-bold">' + topic2.name + '</span>'
|
||||||
when MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
when MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
||||||
notification.subject
|
notification.subject
|
||||||
end
|
end
|
||||||
|
|
0
app/views/map_mailer/map_activity.html.erb
Normal file
0
app/views/map_mailer/map_activity.html.erb
Normal file
0
app/views/map_mailer/map_activity.text.erb
Normal file
0
app/views/map_mailer/map_activity.text.erb
Normal file
0
app/views/map_mailer/map_collaborator_added.html.erb
Normal file
0
app/views/map_mailer/map_collaborator_added.html.erb
Normal file
0
app/views/map_mailer/map_collaborator_added.text.erb
Normal file
0
app/views/map_mailer/map_collaborator_added.text.erb
Normal file
5
app/views/map_mailer/map_message.html.erb
Normal file
5
app/views/map_mailer/map_message.html.erb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<% 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 a chat message to map <span style="font-weight: bold"><%= entity.name %></span></p>
|
||||||
|
<p><%= event.message %></p>
|
||||||
|
|
||||||
|
<%= link_to 'Go to Map', map_url(entity), style: button_style %>
|
0
app/views/map_mailer/map_message.text.erb
Normal file
0
app/views/map_mailer/map_message.text.erb
Normal file
3
app/views/map_mailer/map_starred.html.erb
Normal file
3
app/views/map_mailer/map_starred.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<% 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> starred map <span style="font-weight: bold"><%= entity.name %></span></p>
|
||||||
|
<%= link_to 'Go to Map', map_url(entity), style: button_style %>
|
0
app/views/map_mailer/map_starred.text.erb
Normal file
0
app/views/map_mailer/map_starred.text.erb
Normal file
0
app/views/map_mailer/map_updated.html.erb
Normal file
0
app/views/map_mailer/map_updated.html.erb
Normal file
0
app/views/map_mailer/map_updated.text.erb
Normal file
0
app/views/map_mailer/map_updated.text.erb
Normal file
9
app/views/map_mailer/topic_added_to_map.html.erb
Normal file
9
app/views/map_mailer/topic_added_to_map.html.erb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<% 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"><%= entity.name %></span>
|
||||||
|
to map <span style="font-weight: bold"><%= event.map.name %></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= link_to 'Go to Topic', topic_url(entity), style: button_style %>
|
||||||
|
<%= link_to 'Go to Map', map_url(event.map), style: button_style %>
|
0
app/views/map_mailer/topic_added_to_map.text.erb
Normal file
0
app/views/map_mailer/topic_added_to_map.text.erb
Normal file
15
app/views/map_mailer/topic_connected.html.erb
Normal file
15
app/views/map_mailer/topic_connected.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<% 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" %>
|
||||||
|
|
||||||
|
<% topic1 = entity %>
|
||||||
|
<% topic2 = (entity.id == event.topic1_id ? event.topic2 : event.topic1) %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span style="font-weight: bold;"><%= event.user.name %></span>
|
||||||
|
connected topic <span style="font-weight: bold"><%= topic1.name %></span>
|
||||||
|
to topic <span style="font-weight: bold"><%= topic2.name %></span>
|
||||||
|
<% if event.desc %>
|
||||||
|
with the description "<%= event.desc %>".
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= link_to 'View the connection', topic_url(topic1), style: button_style %>
|
0
app/views/map_mailer/topic_connected.text.erb
Normal file
0
app/views/map_mailer/topic_connected.text.erb
Normal file
0
app/views/map_mailer/topic_deleted.html.erb
Normal file
0
app/views/map_mailer/topic_deleted.html.erb
Normal file
0
app/views/map_mailer/topic_deleted.text.erb
Normal file
0
app/views/map_mailer/topic_deleted.text.erb
Normal file
0
app/views/map_mailer/topic_disconnected.html.erb
Normal file
0
app/views/map_mailer/topic_disconnected.html.erb
Normal file
0
app/views/map_mailer/topic_disconnected.text.erb
Normal file
0
app/views/map_mailer/topic_disconnected.text.erb
Normal file
0
app/views/map_mailer/topic_updated.html.erb
Normal file
0
app/views/map_mailer/topic_updated.html.erb
Normal file
0
app/views/map_mailer/topic_updated.text.erb
Normal file
0
app/views/map_mailer/topic_updated.text.erb
Normal file
|
@ -7,11 +7,31 @@
|
||||||
# notification_code: MAILBOXER_CODE_ACCESS_REQUEST
|
# notification_code: MAILBOXER_CODE_ACCESS_REQUEST
|
||||||
# },
|
# },
|
||||||
# which would imply that this is an access request to Map.find(1)
|
# 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'
|
MAILBOXER_CODE_MESSAGE_FROM_DEVS = 'MESSAGE_FROM_DEVS'
|
||||||
|
|
||||||
|
# these ones are old and can't change without a migration
|
||||||
|
MAILBOXER_CODE_ACCESS_APPROVED = 'ACCESS_APPROVED'
|
||||||
|
MAILBOXER_CODE_ACCESS_REQUEST = 'ACCESS_REQUEST'
|
||||||
|
MAILBOXER_CODE_INVITE_TO_EDIT = 'INVITE_TO_EDIT'
|
||||||
|
|
||||||
|
# these ones are new
|
||||||
|
# this one's a catch all for edits ON the map
|
||||||
|
MAILBOXER_CODE_MAP_ACTIVITY = 'MAP_ACTIVITY'
|
||||||
|
# MAILBOXER_CODE_MAP_ADDED_TO_MAP = 'MAP_ADDED_TO_MAP'
|
||||||
|
MAILBOXER_CODE_MAP_COLLABORATOR_ADDED = 'MAP_COLLABORATOR_ADDED'
|
||||||
|
# BOTHER WITH MAP_COLLABORATOR_REMOVED ?
|
||||||
|
MAILBOXER_CODE_MAP_UPDATED = 'MAP_UPDATED' # this refers to the map object itself: name, desc, permission, etc
|
||||||
|
# ADD MAP_FORKED
|
||||||
|
MAILBOXER_CODE_MAP_MESSAGE = 'MAP_MESSAGE'
|
||||||
|
MAILBOXER_CODE_MAP_STARRED = 'MAP_STARRED'
|
||||||
|
|
||||||
|
MAILBOXER_CODE_TOPIC_ADDED_TO_MAP = 'TOPIC_ADDED_TO_MAP'
|
||||||
|
MAILBOXER_CODE_TOPIC_CONNECTED = 'TOPIC_CONNECTED'
|
||||||
|
MAILBOXER_CODE_TOPIC_DELETED = 'TOPIC_DELETED'
|
||||||
|
MAILBOXER_CODE_TOPIC_DISCONNECTED = 'TOPIC_DISCONNECTED'
|
||||||
|
MAILBOXER_CODE_TOPIC_UPDATED = 'TOPIC_UPDATED'
|
||||||
|
# BOTHER WITH TOPIC_REMOVED_FROM_MAP ?
|
||||||
|
|
||||||
Mailboxer.setup do |config|
|
Mailboxer.setup do |config|
|
||||||
# Configures if your application uses or not email sending for Notifications and Messages
|
# Configures if your application uses or not email sending for Notifications and Messages
|
||||||
config.uses_emails = true
|
config.uses_emails = true
|
||||||
|
|
12
db/migrate/20170209215819_create_follows.rb
Normal file
12
db/migrate/20170209215819_create_follows.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class CreateFollows < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :follows do |t|
|
||||||
|
t.references :user, index: true
|
||||||
|
t.boolean :email, default: true
|
||||||
|
t.boolean :app, default: true
|
||||||
|
t.boolean :push, default: 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
|
22
db/migrate/20170209215920_create_follow_types.rb
Normal file
22
db/migrate/20170209215920_create_follow_types.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class CreateFollowTypes < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :follow_types do |t|
|
||||||
|
t.references :follow, index: true
|
||||||
|
t.boolean :all, default: true
|
||||||
|
t.boolean :acccess_approved
|
||||||
|
t.boolean :access_request
|
||||||
|
t.boolean :invite_to_edit
|
||||||
|
t.boolean :map_activity
|
||||||
|
t.boolean :map_collaborator_added
|
||||||
|
t.boolean :map_message
|
||||||
|
t.boolean :map_starred
|
||||||
|
t.boolean :map_updated
|
||||||
|
t.boolean :topic_added_to_map
|
||||||
|
t.boolean :topic_connected
|
||||||
|
t.boolean :topic_deleted
|
||||||
|
t.boolean :topic_disconnected
|
||||||
|
t.boolean :topic_updated
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
49
db/schema.rb
49
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: 20170208161305) do
|
ActiveRecord::Schema.define(version: 20170209215920) 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"
|
||||||
|
@ -67,6 +67,53 @@ ActiveRecord::Schema.define(version: 20170208161305) do
|
||||||
t.index ["user_id"], name: "index_events_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_events_on_user_id", using: :btree
|
||||||
end
|
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 "follow_types", force: :cascade do |t|
|
||||||
|
t.integer "follow_id"
|
||||||
|
t.boolean "all", default: true
|
||||||
|
t.boolean "acccess_approved"
|
||||||
|
t.boolean "access_request"
|
||||||
|
t.boolean "invite_to_edit"
|
||||||
|
t.boolean "map_activity"
|
||||||
|
t.boolean "map_collaborator_added"
|
||||||
|
t.boolean "map_message"
|
||||||
|
t.boolean "map_starred"
|
||||||
|
t.boolean "map_updated"
|
||||||
|
t.boolean "topic_added_to_map"
|
||||||
|
t.boolean "topic_connected"
|
||||||
|
t.boolean "topic_deleted"
|
||||||
|
t.boolean "topic_disconnected"
|
||||||
|
t.boolean "topic_updated"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["follow_id"], name: "index_follow_types_on_follow_id", using: :btree
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "follows", force: :cascade do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.boolean "email", default: true
|
||||||
|
t.boolean "app", default: true
|
||||||
|
t.boolean "push", default: true
|
||||||
|
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|
|
create_table "in_metacode_sets", force: :cascade do |t|
|
||||||
t.integer "metacode_id"
|
t.integer "metacode_id"
|
||||||
t.integer "metacode_set_id"
|
t.integer "metacode_set_id"
|
||||||
|
|
Loading…
Add table
Reference in a new issue