This commit is contained in:
Connor Turland 2017-02-09 22:01:09 +00:00
parent de0100a0b9
commit 713f731aaf
40 changed files with 428 additions and 23 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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

View 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

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
class FollowType < ApplicationRecord
belongs_to :follow
validates :follow, presence: true
end

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View 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 %>

View 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 %>

View 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 %>

View 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 %>

View 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

View 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

View 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

View 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

View file

@ -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"