all the good changes (#1065)
This commit is contained in:
parent
3706cd83e7
commit
dde097ea75
35 changed files with 222 additions and 119 deletions
|
@ -20,9 +20,7 @@ class AccessController < ApplicationController
|
||||||
|
|
||||||
# POST maps/:id/access_request
|
# POST maps/:id/access_request
|
||||||
def access_request
|
def access_request
|
||||||
request = AccessRequest.create(user: current_user, map: @map)
|
AccessRequest.create(user: current_user, map: @map)
|
||||||
NotificationService.access_request(request)
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json { head :ok }
|
format.json { head :ok }
|
||||||
end
|
end
|
||||||
|
@ -32,12 +30,7 @@ class AccessController < ApplicationController
|
||||||
def access
|
def access
|
||||||
user_ids = params[:access].to_a.map(&:to_i) || []
|
user_ids = params[:access].to_a.map(&:to_i) || []
|
||||||
|
|
||||||
@map.add_new_collaborators(user_ids).each do |user_id|
|
@map.add_new_collaborators(user_ids)
|
||||||
# add_new_collaborators returns array of added users,
|
|
||||||
# who we then send a notification to
|
|
||||||
user = User.find(user_id)
|
|
||||||
NotificationService.invite_to_edit(@map, current_user, user)
|
|
||||||
end
|
|
||||||
@map.remove_old_collaborators(user_ids)
|
@map.remove_old_collaborators(user_ids)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
|
@ -1,31 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class MappingsController < RestfulController
|
class MappingsController < WithUpdatesController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
|
||||||
instantiate_resource
|
|
||||||
resource.user = current_user if current_user.present?
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
authorize resource
|
|
||||||
create_action
|
|
||||||
respond_with_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
update_action
|
|
||||||
respond_with_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
destroy_action
|
|
||||||
head :no_content
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class MapsController < RestfulController
|
class MapsController < WithUpdatesController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
[:name, :desc]
|
[:name, :desc]
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class SynapsesController < RestfulController
|
class SynapsesController < WithUpdatesController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
[:desc]
|
[:desc]
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class TopicsController < RestfulController
|
class TopicsController < WithUpdatesController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
[:name, :desc, :link]
|
[:name, :desc, :link]
|
||||||
end
|
end
|
||||||
|
|
27
app/controllers/api/v2/with_updates_controller.rb
Normal file
27
app/controllers/api/v2/with_updates_controller.rb
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V2
|
||||||
|
class WithUpdatesController < RestfulController
|
||||||
|
def create
|
||||||
|
instantiate_resource
|
||||||
|
resource.user = current_user if current_user.present?
|
||||||
|
resource.updated_by = current_user if current_user.present?
|
||||||
|
authorize resource
|
||||||
|
create_action
|
||||||
|
respond_with_resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
resource.updated_by = current_user if current_user.present?
|
||||||
|
update_action
|
||||||
|
respond_with_resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
resource.updated_by = current_user if current_user.present?
|
||||||
|
destroy_action
|
||||||
|
head :no_content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -33,6 +33,7 @@ class MappingsController < ApplicationController
|
||||||
@mapping = Mapping.find(params[:id])
|
@mapping = Mapping.find(params[:id])
|
||||||
authorize @mapping
|
authorize @mapping
|
||||||
@mapping.updated_by = current_user
|
@mapping.updated_by = current_user
|
||||||
|
@mapping.map.updated_by = current_user
|
||||||
@mapping.assign_attributes(mapping_params)
|
@mapping.assign_attributes(mapping_params)
|
||||||
|
|
||||||
if @mapping.save
|
if @mapping.save
|
||||||
|
@ -47,6 +48,7 @@ class MappingsController < ApplicationController
|
||||||
@mapping = Mapping.find(params[:id])
|
@mapping = Mapping.find(params[:id])
|
||||||
authorize @mapping
|
authorize @mapping
|
||||||
@mapping.updated_by = current_user
|
@mapping.updated_by = current_user
|
||||||
|
@mapping.map.updated_by = current_user
|
||||||
@mapping.destroy
|
@mapping.destroy
|
||||||
|
|
||||||
head :no_content
|
head :no_content
|
||||||
|
|
|
@ -59,6 +59,7 @@ class MapsController < ApplicationController
|
||||||
def create
|
def create
|
||||||
@map = Map.new(create_map_params)
|
@map = Map.new(create_map_params)
|
||||||
@map.user = current_user
|
@map.user = current_user
|
||||||
|
@map.updated_by = current_user
|
||||||
@map.arranged = false
|
@map.arranged = false
|
||||||
authorize @map
|
authorize @map
|
||||||
|
|
||||||
|
@ -79,8 +80,11 @@ class MapsController < ApplicationController
|
||||||
|
|
||||||
# PUT maps/:id
|
# PUT maps/:id
|
||||||
def update
|
def update
|
||||||
|
@map.updated_by = current_user
|
||||||
|
@map.assign_attributes(update_map_params)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @map.update_attributes(update_map_params)
|
if @map.save
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.json { render json: @map.errors, status: :unprocessable_entity }
|
format.json { render json: @map.errors, status: :unprocessable_entity }
|
||||||
|
@ -90,7 +94,8 @@ class MapsController < ApplicationController
|
||||||
|
|
||||||
# DELETE maps/:id
|
# DELETE maps/:id
|
||||||
def destroy
|
def destroy
|
||||||
@map.delete
|
@map.updated_by = current_user
|
||||||
|
@map.destroy
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
|
|
|
@ -22,6 +22,8 @@ class SynapsesController < ApplicationController
|
||||||
@synapse = Synapse.new(synapse_params)
|
@synapse = Synapse.new(synapse_params)
|
||||||
@synapse.desc = '' if @synapse.desc.nil?
|
@synapse.desc = '' if @synapse.desc.nil?
|
||||||
@synapse.desc.strip! # no trailing/leading whitespace
|
@synapse.desc.strip! # no trailing/leading whitespace
|
||||||
|
@synapse.user = current_user
|
||||||
|
@synapse.updated_by = current_user
|
||||||
|
|
||||||
# we want invalid params to return :unprocessable_entity
|
# we want invalid params to return :unprocessable_entity
|
||||||
# so we have to authorize AFTER saving. But if authorize
|
# so we have to authorize AFTER saving. But if authorize
|
||||||
|
@ -47,9 +49,11 @@ class SynapsesController < ApplicationController
|
||||||
@synapse = Synapse.find(params[:id])
|
@synapse = Synapse.find(params[:id])
|
||||||
@synapse.desc = '' if @synapse.desc.nil?
|
@synapse.desc = '' if @synapse.desc.nil?
|
||||||
authorize @synapse
|
authorize @synapse
|
||||||
|
@synapse.updated_by = current_user
|
||||||
|
@synapse.assign_attributes(synapse_params)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @synapse.update_attributes(synapse_params)
|
if @synapse.save
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
||||||
|
@ -61,6 +65,7 @@ class SynapsesController < ApplicationController
|
||||||
def destroy
|
def destroy
|
||||||
@synapse = Synapse.find(params[:id])
|
@synapse = Synapse.find(params[:id])
|
||||||
authorize @synapse
|
authorize @synapse
|
||||||
|
@synapse.updated_by = current_user
|
||||||
@synapse.destroy
|
@synapse.destroy
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
@ -72,7 +77,7 @@ class SynapsesController < ApplicationController
|
||||||
|
|
||||||
def synapse_params
|
def synapse_params
|
||||||
params.require(:synapse).permit(
|
params.require(:synapse).permit(
|
||||||
:id, :desc, :category, :weight, :permission, :topic1_id, :topic2_id, :user_id
|
:id, :desc, :category, :weight, :permission, :topic1_id, :topic2_id
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -134,6 +134,8 @@ class TopicsController < ApplicationController
|
||||||
def create
|
def create
|
||||||
@topic = Topic.new(topic_params)
|
@topic = Topic.new(topic_params)
|
||||||
authorize @topic
|
authorize @topic
|
||||||
|
@topic.user = current_user
|
||||||
|
@topic.updated_by = current_user
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @topic.save
|
if @topic.save
|
||||||
|
@ -149,9 +151,11 @@ class TopicsController < ApplicationController
|
||||||
def update
|
def update
|
||||||
@topic = Topic.find(params[:id])
|
@topic = Topic.find(params[:id])
|
||||||
authorize @topic
|
authorize @topic
|
||||||
|
@topic.updated_by = current_user
|
||||||
|
@topic.assign_attributes(topic_params)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @topic.update_attributes(topic_params)
|
if @topic.save
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||||
|
@ -163,7 +167,7 @@ class TopicsController < ApplicationController
|
||||||
def destroy
|
def destroy
|
||||||
@topic = Topic.find(params[:id])
|
@topic = Topic.find(params[:id])
|
||||||
authorize @topic
|
authorize @topic
|
||||||
|
@topic.updated_by = current_user
|
||||||
@topic.destroy
|
@topic.destroy
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
|
@ -173,6 +177,6 @@ class TopicsController < ApplicationController
|
||||||
private
|
private
|
||||||
|
|
||||||
def topic_params
|
def topic_params
|
||||||
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :user_id, :metacode_id, :defer_to_map_id)
|
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :metacode_id, :defer_to_map_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,15 +9,16 @@ class ApplicationMailer < ActionMailer::Base
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def mail_for_notification(notification)
|
def mail_for_notification(notification)
|
||||||
if notification.notification_code == MAILBOXER_CODE_ACCESS_REQUEST
|
case notification.notification_code
|
||||||
request = notification.notified_object
|
when MAILBOXER_CODE_ACCESS_REQUEST
|
||||||
MapMailer.access_request_email(request)
|
request = notification.notified_object
|
||||||
elsif notification.notification_code == MAILBOXER_CODE_ACCESS_APPROVED
|
MapMailer.access_request(request)
|
||||||
request = notification.notified_object
|
when MAILBOXER_CODE_ACCESS_APPROVED
|
||||||
MapMailer.access_approved_email(request)
|
request = notification.notified_object
|
||||||
elsif notification.notification_code == MAILBOXER_CODE_INVITE_TO_EDIT
|
MapMailer.access_approved(request)
|
||||||
user_map = notification.notified_object
|
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||||
MapMailer.invite_to_edit_email(user_map.map, user_map.map.user, user_map.user)
|
user_map = notification.notified_object
|
||||||
|
MapMailer.invite_to_edit(user_map)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,21 +2,21 @@
|
||||||
class MapMailer < ApplicationMailer
|
class MapMailer < ApplicationMailer
|
||||||
default from: 'team@metamaps.cc'
|
default from: 'team@metamaps.cc'
|
||||||
|
|
||||||
def access_request_email(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: request.requested_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_approved_email(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: request.approved_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_to_edit_email(map, inviter, invitee)
|
def invite_to_edit(user_map)
|
||||||
@inviter = inviter
|
@inviter = user_map.map.user
|
||||||
@map = map
|
@map = user_map.map
|
||||||
mail(to: invitee.email, subject: map.invited_text)
|
mail(to: user_map.user.email, subject: map.invited_text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
class AccessRequest < ApplicationRecord
|
class AccessRequest < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :map
|
belongs_to :map
|
||||||
|
has_one :user_map
|
||||||
|
|
||||||
|
after_create :after_created_async
|
||||||
|
|
||||||
def approve
|
def approve
|
||||||
self.approved = true
|
self.approved = true
|
||||||
|
@ -12,8 +15,7 @@ class AccessRequest < ApplicationRecord
|
||||||
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
UserMap.create(user: user, map: map)
|
UserMap.create(user: user, map: map, access_request: self)
|
||||||
NotificationService.access_approved(self)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def deny
|
def deny
|
||||||
|
@ -33,4 +35,11 @@ class AccessRequest < ApplicationRecord
|
||||||
def approved_text
|
def approved_text
|
||||||
map.name + ' - access approved'
|
map.name + ' - access approved'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def after_created_async
|
||||||
|
NotificationService.access_request(self)
|
||||||
|
end
|
||||||
|
handle_asynchronously :after_created_async
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class Map < ApplicationRecord
|
class Map < ApplicationRecord
|
||||||
|
ATTRS_TO_WATCH = %w(name desc permission).freeze
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :source, class_name: :Map
|
belongs_to :source, class_name: :Map
|
||||||
|
belongs_to :updated_by, class_name: 'User'
|
||||||
|
|
||||||
has_many :topicmappings, -> { Mapping.topicmapping },
|
has_many :topicmappings, -> { Mapping.topicmapping },
|
||||||
class_name: :Mapping, dependent: :destroy
|
class_name: :Mapping, dependent: :destroy
|
||||||
|
@ -10,7 +13,7 @@ class Map < ApplicationRecord
|
||||||
has_many :topics, through: :topicmappings, source: :mappable, source_type: 'Topic'
|
has_many :topics, through: :topicmappings, source: :mappable, source_type: 'Topic'
|
||||||
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
|
has_many :stars, dependent: :destroy
|
||||||
|
|
||||||
has_many :access_requests, dependent: :destroy
|
has_many :access_requests, dependent: :destroy
|
||||||
has_many :user_maps, dependent: :destroy
|
has_many :user_maps, dependent: :destroy
|
||||||
|
@ -126,13 +129,7 @@ class Map < ApplicationRecord
|
||||||
end
|
end
|
||||||
removed.compact
|
removed.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_updated
|
|
||||||
attrs = %w(name desc permission)
|
|
||||||
return unless attrs.any? { |k| changed_attributes.key?(k) }
|
|
||||||
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_deferring_topics_and_synapses
|
def update_deferring_topics_and_synapses
|
||||||
Topic.where(defer_to_map_id: id).update(permission: permission)
|
Topic.where(defer_to_map_id: id).update(permission: permission)
|
||||||
Synapse.where(defer_to_map_id: id).update(permission: permission)
|
Synapse.where(defer_to_map_id: id).update(permission: permission)
|
||||||
|
@ -141,4 +138,12 @@ class Map < ApplicationRecord
|
||||||
def invited_text
|
def invited_text
|
||||||
name + ' - invited to edit'
|
name + ' - invited to edit'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def after_updated
|
||||||
|
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
|
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class Synapse < ApplicationRecord
|
class Synapse < ApplicationRecord
|
||||||
|
ATTRS_TO_WATCH = %w(desc category permission defer_to_map_id).freeze
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
|
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
|
||||||
|
belongs_to :updated_by, class_name: 'User'
|
||||||
|
|
||||||
belongs_to :topic1, class_name: 'Topic', foreign_key: 'topic1_id'
|
belongs_to :topic1, class_name: 'Topic', foreign_key: 'topic1_id'
|
||||||
belongs_to :topic2, class_name: 'Topic', foreign_key: 'topic2_id'
|
belongs_to :topic2, class_name: 'Topic', foreign_key: 'topic2_id'
|
||||||
|
@ -71,13 +74,12 @@ class Synapse < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_updated
|
def after_updated
|
||||||
attrs = %w(desc category permission defer_to_map_id)
|
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
if attrs.any? { |k| changed_attributes.key?(k) }
|
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
new = attributes.select { |k| attrs.include?(k) }
|
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
old = changed_attributes.select { |k| attrs.include?(k) }
|
|
||||||
meta = new.merge(old) # we are prioritizing the old values, keeping them
|
meta = new.merge(old) # we are prioritizing the old values, keeping them
|
||||||
meta['changed'] = changed_attributes.keys.select { |k| attrs.include?(k) }
|
meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
Events::SynapseUpdated.publish!(self, user, meta)
|
Events::SynapseUpdated.publish!(self, updated_by, meta)
|
||||||
maps.each do |map|
|
maps.each do |map|
|
||||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseUpdated', id: id
|
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseUpdated', id: id
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class Topic < ApplicationRecord
|
class Topic < ApplicationRecord
|
||||||
|
ATTRS_TO_WATCH = %w(name desc link metacode_id permission defer_to_map_id).freeze
|
||||||
include TopicsHelper
|
include TopicsHelper
|
||||||
include Attachable
|
include Attachable
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
|
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
|
||||||
|
belongs_to :updated_by, class_name: 'User'
|
||||||
|
|
||||||
has_many :synapses1, class_name: 'Synapse', foreign_key: 'topic1_id', dependent: :destroy
|
has_many :synapses1, class_name: 'Synapse', foreign_key: 'topic1_id', dependent: :destroy
|
||||||
has_many :synapses2, class_name: 'Synapse', foreign_key: 'topic2_id', dependent: :destroy
|
has_many :synapses2, class_name: 'Synapse', foreign_key: 'topic2_id', dependent: :destroy
|
||||||
|
@ -149,13 +151,12 @@ class Topic < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_updated
|
def after_updated
|
||||||
attrs = %w(name desc link metacode_id permission defer_to_map_id)
|
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
|
||||||
if attrs.any? { |k| changed_attributes.key?(k) }
|
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
new = attributes.select { |k| attrs.include?(k) }
|
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
old = changed_attributes.select { |k| attrs.include?(k) }
|
|
||||||
meta = new.merge(old) # we are prioritizing the old values, keeping them
|
meta = new.merge(old) # we are prioritizing the old values, keeping them
|
||||||
meta['changed'] = changed_attributes.keys.select { |k| attrs.include?(k) }
|
meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) }
|
||||||
Events::TopicUpdated.publish!(self, user, meta)
|
Events::TopicUpdated.publish!(self, updated_by, meta)
|
||||||
maps.each do |map|
|
maps.each do |map|
|
||||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicUpdated', id: id
|
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicUpdated', id: id
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,10 +2,24 @@
|
||||||
class UserMap < ApplicationRecord
|
class UserMap < ApplicationRecord
|
||||||
belongs_to :map
|
belongs_to :map
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
belongs_to :access_request
|
||||||
|
|
||||||
|
after_create :after_created_async
|
||||||
|
|
||||||
def mark_invite_notifications_as_read
|
def mark_invite_notifications_as_read
|
||||||
Mailboxer::Notification.where(notified_object: self).find_each do |notification|
|
Mailboxer::Notification.where(notified_object: self).find_each do |notification|
|
||||||
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def after_created_async
|
||||||
|
if access_request
|
||||||
|
NotificationService.access_approved(self.access_request)
|
||||||
|
else
|
||||||
|
NotificationService.invite_to_edit(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
handle_asynchronously :after_created_async
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,23 +10,46 @@ class NotificationService
|
||||||
)
|
)
|
||||||
end
|
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)
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.access_request(request)
|
def self.access_request(request)
|
||||||
body = renderer.render(template: 'map_mailer/access_request_email', locals: { map: request.map, request: request }, layout: false)
|
event_type = 'access_request'
|
||||||
request.map.user.notify(request.requested_text, body, request, false, MAILBOXER_CODE_ACCESS_REQUEST, true, request.user)
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.access_approved(request)
|
def self.access_approved(request)
|
||||||
body = renderer.render(template: 'map_mailer/access_approved_email', locals: { map: request.map }, layout: false)
|
event_type = 'access_approved'
|
||||||
request.user.notify(request.approved_text, body, request, false, MAILBOXER_CODE_ACCESS_APPROVED, true, request.map.user)
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.invite_to_edit(map, inviter, invited)
|
def self.invite_to_edit(user_map)
|
||||||
user_map = UserMap.find_by(user: invited, map: map)
|
event_type = 'invite_to_edit'
|
||||||
body = renderer.render(template: 'map_mailer/invite_to_edit_email', locals: { map: map, inviter: inviter }, layout: false)
|
template = get_template_for_event_type(event_type)
|
||||||
invited.notify(map.invited_text, body, user_map, false, MAILBOXER_CODE_INVITE_TO_EDIT, true, inviter)
|
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(map.invited_text, body, user_map, false, mailboxer_code, true, user_map.map.user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# note: this is a global function, probaobly 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
|
||||||
def self.message_from_devs(subject, body, opts = {})
|
def self.message_from_devs(subject, body, opts = {})
|
||||||
users = opts[:users] || User.all
|
users = opts[:users] || User.all
|
||||||
obj = opts[:obj] || nil
|
obj = opts[:obj] || nil
|
||||||
|
@ -38,17 +61,18 @@ class NotificationService
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.text_for_notification(notification)
|
def self.text_for_notification(notification)
|
||||||
if notification.notification_code == MAILBOXER_CODE_ACCESS_REQUEST
|
case notification.notification_code
|
||||||
map = notification.notified_object.map
|
when MAILBOXER_CODE_ACCESS_APPROVED
|
||||||
'wants permission to map with you on <span class="in-bold">' + map.name + '</span> <div class="action">Offer a response</div>'
|
map = notification.notified_object.map
|
||||||
elsif notification.notification_code == MAILBOXER_CODE_ACCESS_APPROVED
|
'granted your request to edit map <span class="in-bold">' + map.name + '</span>'
|
||||||
map = notification.notified_object.map
|
when MAILBOXER_CODE_ACCESS_REQUEST
|
||||||
'granted your request to edit map <span class="in-bold">' + map.name + '</span>'
|
map = notification.notified_object.map
|
||||||
elsif notification.notification_code == MAILBOXER_CODE_INVITE_TO_EDIT
|
'wants permission to map with you on <span class="in-bold">' + map.name + '</span> <div class="action">Offer a response</div>'
|
||||||
map = notification.notified_object.map
|
when MAILBOXER_CODE_INVITE_TO_EDIT
|
||||||
'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
map = notification.notified_object.map
|
||||||
elsif notification.notification_code == MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
'gave you edit access to map <span class="in-bold">' + map.name + '</span>'
|
||||||
notification.subject
|
when MAILBOXER_CODE_MESSAGE_FROM_DEVS
|
||||||
|
notification.subject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddAccessRequestToUserMap < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_reference :user_maps, :access_request
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,7 @@
|
||||||
|
class AddUpdatedByToTopicsSynapsesAndMaps < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_reference :topics, :updated_by, foreign_key: {to_table: :users}
|
||||||
|
add_reference :synapses, :updated_by, foreign_key: {to_table: :users}
|
||||||
|
add_reference :maps, :updated_by, foreign_key: {to_table: :users}
|
||||||
|
end
|
||||||
|
end
|
17
db/schema.rb
17
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: 20170122201451) do
|
ActiveRecord::Schema.define(version: 20170208161305) 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"
|
||||||
|
@ -164,7 +164,9 @@ ActiveRecord::Schema.define(version: 20170122201451) do
|
||||||
t.integer "screenshot_file_size"
|
t.integer "screenshot_file_size"
|
||||||
t.datetime "screenshot_updated_at"
|
t.datetime "screenshot_updated_at"
|
||||||
t.integer "source_id"
|
t.integer "source_id"
|
||||||
|
t.integer "updated_by_id"
|
||||||
t.index ["source_id"], name: "index_maps_on_source_id", using: :btree
|
t.index ["source_id"], name: "index_maps_on_source_id", using: :btree
|
||||||
|
t.index ["updated_by_id"], name: "index_maps_on_updated_by_id", using: :btree
|
||||||
t.index ["user_id"], name: "index_maps_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_maps_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -259,10 +261,12 @@ ActiveRecord::Schema.define(version: 20170122201451) do
|
||||||
t.text "permission"
|
t.text "permission"
|
||||||
t.text "weight"
|
t.text "weight"
|
||||||
t.integer "defer_to_map_id"
|
t.integer "defer_to_map_id"
|
||||||
t.index ["topic1_id", "topic1_id"], name: "index_synapses_on_node1_id_and_node1_id", using: :btree
|
t.integer "updated_by_id"
|
||||||
|
t.index ["topic1_id"], name: "index_synapses_on_node1_id_and_node1_id", using: :btree
|
||||||
t.index ["topic1_id"], name: "index_synapses_on_topic1_id", using: :btree
|
t.index ["topic1_id"], name: "index_synapses_on_topic1_id", using: :btree
|
||||||
t.index ["topic2_id", "topic2_id"], name: "index_synapses_on_node2_id_and_node2_id", using: :btree
|
t.index ["topic2_id"], name: "index_synapses_on_node2_id_and_node2_id", using: :btree
|
||||||
t.index ["topic2_id"], name: "index_synapses_on_topic2_id", using: :btree
|
t.index ["topic2_id"], name: "index_synapses_on_topic2_id", using: :btree
|
||||||
|
t.index ["updated_by_id"], name: "index_synapses_on_updated_by_id", using: :btree
|
||||||
t.index ["user_id"], name: "index_synapses_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_synapses_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -285,7 +289,9 @@ ActiveRecord::Schema.define(version: 20170122201451) do
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.text "permission"
|
t.text "permission"
|
||||||
t.integer "defer_to_map_id"
|
t.integer "defer_to_map_id"
|
||||||
|
t.integer "updated_by_id"
|
||||||
t.index ["metacode_id"], name: "index_topics_on_metacode_id", using: :btree
|
t.index ["metacode_id"], name: "index_topics_on_metacode_id", using: :btree
|
||||||
|
t.index ["updated_by_id"], name: "index_topics_on_updated_by_id", using: :btree
|
||||||
t.index ["user_id"], name: "index_topics_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_topics_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -294,6 +300,8 @@ ActiveRecord::Schema.define(version: 20170122201451) do
|
||||||
t.integer "map_id"
|
t.integer "map_id"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
|
t.integer "access_request_id"
|
||||||
|
t.index ["access_request_id"], name: "index_user_maps_on_access_request_id", using: :btree
|
||||||
t.index ["map_id"], name: "index_user_maps_on_map_id", using: :btree
|
t.index ["map_id"], name: "index_user_maps_on_map_id", using: :btree
|
||||||
t.index ["user_id"], name: "index_user_maps_on_user_id", using: :btree
|
t.index ["user_id"], name: "index_user_maps_on_user_id", using: :btree
|
||||||
end
|
end
|
||||||
|
@ -347,5 +355,8 @@ ActiveRecord::Schema.define(version: 20170122201451) do
|
||||||
add_foreign_key "mailboxer_receipts", "mailboxer_notifications", column: "notification_id", name: "receipts_on_notification_id"
|
add_foreign_key "mailboxer_receipts", "mailboxer_notifications", column: "notification_id", name: "receipts_on_notification_id"
|
||||||
add_foreign_key "mappings", "users", column: "updated_by_id"
|
add_foreign_key "mappings", "users", column: "updated_by_id"
|
||||||
add_foreign_key "maps", "maps", column: "source_id"
|
add_foreign_key "maps", "maps", column: "source_id"
|
||||||
|
add_foreign_key "maps", "users", column: "updated_by_id"
|
||||||
|
add_foreign_key "synapses", "users", column: "updated_by_id"
|
||||||
add_foreign_key "tokens", "users"
|
add_foreign_key "tokens", "users"
|
||||||
|
add_foreign_key "topics", "users", column: "updated_by_id"
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe TopicsController, type: :controller do
|
RSpec.describe TopicsController, type: :controller do
|
||||||
let(:topic) { create(:topic) }
|
let(:user) { create(:user) }
|
||||||
|
let(:topic) { create(:topic, user: user) }
|
||||||
let(:valid_attributes) { topic.attributes.except('id') }
|
let(:valid_attributes) { topic.attributes.except('id') }
|
||||||
let(:invalid_attributes) { { permission: :invalid_lol } }
|
let(:invalid_attributes) { { permission: :invalid_lol } }
|
||||||
before :each do
|
before :each do
|
||||||
sign_in create(:user)
|
sign_in :user
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'POST #create' do
|
describe 'POST #create' do
|
||||||
|
|
|
@ -7,5 +7,6 @@ FactoryGirl.define do
|
||||||
source_id nil
|
source_id nil
|
||||||
desc ''
|
desc ''
|
||||||
user
|
user
|
||||||
|
association :updated_by, factory: :user
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ FactoryGirl.define do
|
||||||
association :topic1, factory: :topic
|
association :topic1, factory: :topic
|
||||||
association :topic2, factory: :topic
|
association :topic2, factory: :topic
|
||||||
user
|
user
|
||||||
|
association :updated_by, factory: :user
|
||||||
weight 1 # TODO: drop this column
|
weight 1 # TODO: drop this column
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :topic do
|
factory :topic do
|
||||||
user
|
user
|
||||||
|
association :updated_by, factory: :user
|
||||||
metacode
|
metacode
|
||||||
permission :commons
|
permission :commons
|
||||||
sequence(:name) { |n| "Cool Topic ##{n}" }
|
sequence(:name) { |n| "Cool Topic ##{n}" }
|
||||||
|
|
7
spec/factories/user_maps.rb
Normal file
7
spec/factories/user_maps.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
FactoryGirl.define do
|
||||||
|
factory :user_map do
|
||||||
|
map
|
||||||
|
user
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,10 +2,10 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe MapMailer, type: :mailer do
|
RSpec.describe MapMailer, type: :mailer do
|
||||||
describe 'access_request_email' do
|
describe 'access_request' do
|
||||||
let(:map) { create(:map) }
|
let(:map) { create(:map) }
|
||||||
let(:request) { create(:access_request, map: map) }
|
let(:request) { create(:access_request, map: map) }
|
||||||
let(:mail) { described_class.access_request_email(request) }
|
let(:mail) { described_class.access_request(request) }
|
||||||
|
|
||||||
it { expect(mail.from).to eq ['team@metamaps.cc'] }
|
it { expect(mail.from).to eq ['team@metamaps.cc'] }
|
||||||
it { expect(mail.to).to eq [map.user.email] }
|
it { expect(mail.to).to eq [map.user.email] }
|
||||||
|
@ -16,17 +16,17 @@ RSpec.describe MapMailer, type: :mailer do
|
||||||
it { expect(mail.body.encoded).to match 'Decline' }
|
it { expect(mail.body.encoded).to match 'Decline' }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'invite_to_edit_email' do
|
describe 'invite_to_edit' do
|
||||||
let(:map) { create(:map) }
|
|
||||||
let(:inviter) { create(:user) }
|
let(:inviter) { create(:user) }
|
||||||
let(:invitee) { create(:user) }
|
let(:map) { create(:map, user: inviter) }
|
||||||
let(:mail) { described_class.invite_to_edit_email(map, inviter, invitee) }
|
let(:invited) { create(:user) }
|
||||||
|
let(:user_map) { create(:user_map, map: map, user: invited) }
|
||||||
|
let(:mail) { described_class.invite_to_edit(user_map) }
|
||||||
|
|
||||||
it { expect(mail.from).to eq ['team@metamaps.cc'] }
|
it { expect(mail.from).to eq ['team@metamaps.cc'] }
|
||||||
it { expect(mail.to).to eq [invitee.email] }
|
it { expect(mail.to).to eq [invited.email] }
|
||||||
it { expect(mail.subject).to match map.name }
|
it { expect(mail.subject).to match map.name }
|
||||||
it { expect(mail.body.encoded).to match inviter.name }
|
it { expect(mail.body.encoded).to match inviter.name }
|
||||||
it { expect(mail.body.encoded).to match map.name }
|
it { expect(mail.body.encoded).to match map.name }
|
||||||
it { expect(mail.body.encoded).to match map_url(map) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
# Preview all emails at http://localhost:3000/rails/mailers/map_mailer
|
# Preview all emails at http://localhost:3000/rails/mailers/map_mailer
|
||||||
class MapMailerPreview < ActionMailer::Preview
|
class MapMailerPreview < ActionMailer::Preview
|
||||||
def invite_to_edit_email
|
def invite_to_edit
|
||||||
MapMailer.invite_to_edit_email(Map.first, User.first, User.second)
|
user_map = UserMap.first
|
||||||
|
MapMailer.invite_to_edit(user_map)
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_request_email
|
def access_request_email
|
||||||
request = AccessRequest.first
|
request = AccessRequest.first
|
||||||
MapMailer.access_request_email(request)
|
MapMailer.access_request(request)
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_approved_email
|
def access_approved_email
|
||||||
request = AccessRequest.first
|
request = AccessRequest.first
|
||||||
MapMailer.access_approved_email(request)
|
MapMailer.access_approved(request)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,8 +11,6 @@ RSpec.describe AccessRequest, type: :model do
|
||||||
|
|
||||||
it { expect(access_request.approved).to be true }
|
it { expect(access_request.approved).to be true }
|
||||||
it { expect(access_request.answered).to be true }
|
it { expect(access_request.answered).to be true }
|
||||||
it { expect(UserMap.count).to eq 1 }
|
|
||||||
it { expect(Mailboxer::Notification.count).to eq 1 }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'deny' do
|
describe 'deny' do
|
||||||
|
@ -22,7 +20,5 @@ RSpec.describe AccessRequest, type: :model do
|
||||||
|
|
||||||
it { expect(access_request.approved).to be false }
|
it { expect(access_request.approved).to be false }
|
||||||
it { expect(access_request.answered).to be true }
|
it { expect(access_request.answered).to be true }
|
||||||
it { expect(UserMap.count).to eq 0 }
|
|
||||||
it { expect(Mailboxer::Notification.count).to eq 0 }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue