Compare commits

..

15 commits

Author SHA1 Message Date
Devin Howard
98081097b4 Revert "update rails dependencies"
Original commit broke the build, since some dependencies have breaking
changes.

This reverts commit f753392d49.
2018-11-09 07:42:26 -08:00
Devin Howard
f753392d49 update rails dependencies 2018-10-17 19:51:51 -07:00
Connor Turland
38a209a970 small bug fix (#1174)
if someone besides one of "us" tried to change their password, and their settings, it wouldn't work

in the typical case it would work fine
2018-03-11 21:57:23 -07:00
Devin Howard
bd7bf20810
factory_girl => factory_bot (#1172) 2018-03-10 08:10:09 -08:00
Devin Howard
955ebdd747
Change log level of Metamaps.Debug (#1170)
debug log level is invisible in Chrome by default, which is confusing
2018-02-05 21:35:53 -08:00
Devin Howard
fdcd8a93f1 tag 3.6.1 2018-01-24 20:02:28 -08:00
Devin Howard
b5c52adf5e update to paperclip 5.2.0 2018-01-24 19:52:33 -08:00
Devin Howard
b7761a3627
manual rubocop fixes (#1163) 2018-01-21 14:21:00 -08:00
Devin Howard
e0d72fce14
update nokogiri (#1169) 2018-01-21 14:20:21 -08:00
Devin Howard
139fdf8e2b
update rubocop to 0.48.1. We still want to match Code Climate though (#1168) 2018-01-20 14:10:26 -08:00
Devin Howard
4313f6eff8
TopicCard/Desc.spec.js (#1167)
TopicCard/Desc.spec.js
2018-01-20 13:31:36 -08:00
Devin Howard
91c004ebfd
TopicCard/Permission.spec.js (#1166) 2017-12-04 21:06:09 -08:00
Devin Howard
96056f43ef
TopicCard/Title.spec.js (#1165) 2017-12-02 12:45:05 -08:00
Devin Howard
32e58fa8af
tests for TopicCard/index.js (#1164) 2017-11-26 16:13:17 -08:00
Devin Howard
5ebbd87afc
automatic rubocop fixes (#1162) 2017-11-25 11:23:47 -08:00
83 changed files with 723 additions and 290 deletions

View file

@ -12,7 +12,7 @@ Rails:
Enabled: true
Metrics/LineLength:
Max: 100
Max: 120
Metrics/AbcSize:
Max: 16
@ -22,3 +22,8 @@ Style/Documentation:
Style/EmptyMethod:
EnforcedStyle: expanded
# I like this cop, but occasionally code is more readable without a guard clause,
# and I don't want to write rubocop:disable comments every time that happens
Style/GuardClause:
Enabled: false

View file

@ -38,7 +38,7 @@ gem 'uglifier'
group :test do
gem 'brakeman', require: false
gem 'factory_girl_rails'
gem 'factory_bot_rails'
gem 'json-schema'
gem 'rspec-rails'
gem 'shoulda-matchers'
@ -51,7 +51,7 @@ group :development, :test do
gem 'faker'
gem 'pry-byebug'
gem 'pry-rails'
gem 'rubocop', '~> 0.46.0' # match code climate https://github.com/tootsuite/mastodon/issues/1758
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758
gem 'timecop'
gem 'tunemygc'
end

View file

@ -105,10 +105,10 @@ GEM
actionmailer (>= 4.0, < 6)
activesupport (>= 4.0, < 6)
execjs (2.7.0)
factory_girl (4.8.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
factory_girl_rails (4.8.0)
factory_girl (~> 4.8.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
faker (1.8.4)
i18n (~> 0.5)
@ -117,7 +117,8 @@ GEM
activesupport (>= 4.2.0)
httparty (0.15.6)
multi_xml (>= 0.5.2)
i18n (0.8.6)
i18n (0.9.3)
concurrent-ruby (~> 1.0)
jmespath (1.3.1)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
@ -153,21 +154,21 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_portile2 (2.2.0)
minitest (5.10.3)
mini_portile2 (2.3.0)
minitest (5.11.1)
multi_xml (0.6.0)
nio4r (2.1.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
orm_adapter (0.5.0)
paperclip (5.1.0)
paperclip (5.2.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
cocaine (~> 0.5.5)
mime-types
mimemagic (~> 0.3.0)
parser (2.4.0.0)
ast (~> 2.2)
parser (2.4.0.2)
ast (~> 2.3)
pg (0.21.0)
powerpack (0.1.1)
pry (0.10.4)
@ -215,7 +216,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
rake (12.0.0)
rake (12.3.0)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
@ -240,8 +241,8 @@ GEM
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-support (3.6.0)
rubocop (0.46.0)
parser (>= 2.3.1.1, < 3.0)
rubocop (0.48.1)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
@ -283,7 +284,7 @@ GEM
tilt (2.0.8)
timecop (0.9.1)
tunemygc (1.0.69)
tzinfo (1.2.3)
tzinfo (1.2.4)
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
@ -310,7 +311,7 @@ DEPENDENCIES
doorkeeper
dotenv-rails
exception_notification
factory_girl_rails
factory_bot_rails
faker
httparty
jquery-rails
@ -331,7 +332,7 @@ DEPENDENCIES
rails (~> 5.0.0)
redis (~> 3.3.3)
rspec-rails
rubocop (~> 0.46.0)
rubocop (~> 0.48.1)
sass-rails
shoulda-matchers
simplecov
@ -346,4 +347,4 @@ RUBY VERSION
ruby 2.3.0p0
BUNDLED WITH
1.15.4
1.16.1

0
Rakefile Normal file → Executable file
View file

View file

@ -1,12 +1,12 @@
# frozen_string_literal: true
class AccessController < ApplicationController
before_action :require_user, only: %i(access access_request
before_action :require_user, only: %i[access access_request
approve_access approve_access_post
deny_access deny_access_post request_access)
before_action :set_map, only: %i(access access_request
deny_access deny_access_post request_access]
before_action :set_map, only: %i[access access_request
approve_access approve_access_post
deny_access deny_access_post request_access)
deny_access deny_access_post request_access]
after_action :verify_authorized
# GET maps/:id/request_access

View file

@ -4,7 +4,7 @@ module Api
module V2
class MapsController < WithUpdatesController
def searchable_columns
%i(name desc)
%i[name desc]
end
def apply_filters(collection)

View file

@ -8,7 +8,7 @@ module Api
snorlax_used_rest!
before_action :load_resource, only: %i(show update destroy)
before_action :load_resource, only: %i[show update destroy]
after_action :verify_authorized
def index

View file

@ -4,7 +4,7 @@ module Api
module V2
class TopicsController < WithUpdatesController
def searchable_columns
%i(name desc link)
%i[name desc link]
end
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class ExploreController < ApplicationController
before_action :require_authentication, only: %i(mine shared starred)
before_action :require_authentication, only: %i[mine shared starred]
before_action :authorize_explore
after_action :verify_authorized
after_action :verify_policy_scoped

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class MappingsController < ApplicationController
before_action :require_user, only: %i(create update destroy)
before_action :require_user, only: %i[create update destroy]
after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index

View file

@ -1,8 +1,10 @@
# frozen_string_literal: true
class MapsController < ApplicationController
before_action :require_user, only: %i(create update destroy events follow unfollow)
before_action :set_map, only: %i(show conversation update destroy contains events export follow unfollow unfollow_from_email)
before_action :require_user, only: %i[create update destroy events follow unfollow]
before_action :set_map, only: %i[show conversation update destroy
contains events export
follow unfollow unfollow_from_email]
after_action :verify_authorized
# GET maps/:id

View file

@ -1,8 +1,8 @@
# frozen_string_literal: true
class MetacodesController < ApplicationController
before_action :require_admin, except: %i(index show)
before_action :set_metacode, only: %i(edit update)
before_action :require_admin, except: %i[index show]
before_action :set_metacode, only: %i[edit update]
# GET /metacodes
# GET /metacodes.json

View file

@ -1,9 +1,9 @@
# frozen_string_literal: true
class NotificationsController < ApplicationController
before_action :set_receipts, only: %i(index show mark_read mark_unread)
before_action :set_notification, only: %i(show mark_read mark_unread)
before_action :set_receipt, only: %i(show mark_read mark_unread)
before_action :set_receipts, only: %i[index show mark_read mark_unread]
before_action :set_notification, only: %i[show mark_read mark_unread]
before_action :set_receipt, only: %i[show mark_read mark_unread]
def index
@notifications = current_user.mailbox.notifications.page(params[:page]).per(25)

View file

@ -8,7 +8,7 @@ class SearchController < ApplicationController
before_action :authorize_search
after_action :verify_authorized
after_action :verify_policy_scoped, only: %i(maps mappers synapses topics)
after_action :verify_policy_scoped, only: %i[maps mappers synapses topics]
# get /search/topics?term=SOMETERM
def topics

View file

@ -3,7 +3,7 @@
class SynapsesController < ApplicationController
include TopicsHelper
before_action :require_user, only: %i(create update destroy)
before_action :require_user, only: %i[create update destroy]
after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index

View file

@ -3,10 +3,10 @@
class TopicsController < ApplicationController
include TopicsHelper
before_action :require_user, only: %i(create update destroy follow unfollow)
before_action :set_topic, only: %i(show update relative_numbers
before_action :require_user, only: %i[create update destroy follow unfollow]
before_action :set_topic, only: %i[show update relative_numbers
relatives network destroy
follow unfollow unfollow_from_email)
follow unfollow unfollow_from_email]
after_action :verify_authorized, except: :autocomplete_topic
respond_to :html, :js, :json

View file

@ -30,7 +30,7 @@ module Users
end
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: %i(name joinedwithcode))
devise_parameter_sanitizer.permit(:sign_up, keys: %i[name joinedwithcode])
end
def configure_account_update_params

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :require_user, only: %i(edit update updatemetacodes update_metacode_focus)
before_action :require_user, only: %i[edit update updatemetacodes update_metacode_focus]
respond_to :html, :json
@ -42,7 +42,7 @@ class UsersController < ApplicationController
correct_pass = @user.valid_password?(params[:current_password])
if correct_pass && @user.update_attributes(user_params)
update_follow_settings(@user, params[:settings]) if is_tester(@user)
update_follow_settings(@user, params[:settings])
@user.image = nil if params[:remove_image] == '1'
@user.save
sign_in(@user, bypass: true)

View file

@ -17,7 +17,7 @@ module TopicsHelper
rtype: is_map ? 'map' : 'topic',
inmaps: is_map ? [] : t.inmaps(current_user),
inmapsLinks: is_map ? [] : t.inmapsLinks(current_user),
inmapsLinks: is_map ? [] : t.inmaps_links(current_user),
type: is_map ? metamap_metacode.name : t.metacode.name,
typeImageURL: is_map ? metamap_metacode.icon : t.metacode.icon,
mapCount: is_map ? 0 : t.maps.count,

View file

@ -1,17 +1,17 @@
# frozen_string_literal: true
class Event < ApplicationRecord
KINDS = %w(user_present_on_map user_not_present_on_map
KINDS = %w[user_present_on_map user_not_present_on_map
conversation_started_on_map
topic_added_to_map topic_moved_on_map topic_removed_from_map
synapse_added_to_map synapse_removed_from_map
topic_updated synapse_updated).freeze
topic_updated synapse_updated].freeze
belongs_to :eventable, polymorphic: true
belongs_to :map
belongs_to :user
scope :chronologically, -> { order('created_at asc') }
scope :chronologically, (-> { order('created_at asc') })
after_create :notify_webhooks!, if: :map

View file

@ -11,13 +11,11 @@ class Follow < ApplicationRecord
after_create :add_subsetting
scope :active, -> {
where(muted: false)
}
scope :active, (-> { where(muted: false) })
private
def add_subsetting
follow_reason = FollowReason.create!(follow: self)
FollowReason.create!(follow: self)
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class FollowReason < ApplicationRecord
REASONS = %w(created commented contributed followed shared_on starred).freeze
REASONS = %w[created commented contributed followed shared_on starred].freeze
belongs_to :follow

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class Map < ApplicationRecord
ATTRS_TO_WATCH = %w(name desc permission).freeze
ATTRS_TO_WATCH = %w[name desc permission].freeze
belongs_to :user
belongs_to :source, class_name: :Map
@ -90,10 +90,10 @@ class Map < ApplicationRecord
def as_json(_options = {})
json = super(
methods: %i(user_name user_image star_count topic_count synapse_count
contributor_count collaborator_ids screenshot_url),
except: %i(screenshot_content_type screenshot_file_size screenshot_file_name
screenshot_updated_at)
methods: %i[user_name user_image star_count topic_count synapse_count
contributor_count collaborator_ids screenshot_url],
except: %i[screenshot_content_type screenshot_file_size screenshot_file_name
screenshot_updated_at]
)
json[:created_at_clean] = created_at_str
json[:updated_at_clean] = updated_at_str
@ -153,12 +153,11 @@ class Map < ApplicationRecord
end
def after_updated_async
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
return unless 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
def before_destroyed

View file

@ -1,8 +1,8 @@
# frozen_string_literal: true
class Mapping < ApplicationRecord
scope :topicmapping, -> { where(mappable_type: :Topic) }
scope :synapsemapping, -> { where(mappable_type: :Synapse) }
scope :topicmapping, (-> { where(mappable_type: :Topic) })
scope :synapsemapping, (-> { where(mappable_type: :Synapse) })
belongs_to :mappable, polymorphic: true
belongs_to :map, class_name: 'Map', foreign_key: 'map_id', touch: true
@ -25,7 +25,7 @@ class Mapping < ApplicationRecord
end
def as_json(_options = {})
super(methods: %i(user_name user_image))
super(methods: %i[user_name user_image])
end
def after_created
@ -53,18 +53,18 @@ class Mapping < ApplicationRecord
handle_asynchronously :after_created_async
def after_updated
if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
return unless (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
meta = { 'x': xloc, 'y': yloc, 'mapping_id': id }
Events::TopicMovedOnMap.publish!(mappable, map, updated_by, meta)
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicMoved', id: mappable.id, mapping_id: id, x: xloc, y: yloc
end
ActionCable.server.broadcast('map_' + map.id.to_s, type: 'topicMoved',
id: mappable.id, mapping_id: id,
x: xloc, y: yloc)
end
def after_updated_async
if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
return unless (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
FollowService.follow(map, updated_by, 'contributed')
end
end
handle_asynchronously :after_updated_async
def before_destroyed

View file

@ -14,7 +14,7 @@ class Message < ApplicationRecord
end
def as_json(_options = {})
json = super(methods: %i(user_name user_image))
json = super(methods: %i[user_name user_image])
json
end

View file

@ -6,13 +6,11 @@ class Metacode < ApplicationRecord
has_many :topics
# This method associates the attribute ":aws_icon" with a file attachment
has_attached_file :aws_icon, styles: {
ninetysix: ['96x96#', :png]
},
has_attached_file :aws_icon, styles: { ninetysix: ['96x96#', :png] },
default_url: 'https://s3.amazonaws.com/metamaps-assets/metacodes/generics/96px/gen_wildcard.png'
# Validate the attached icon is image/jpg, image/png, etc
validates_attachment_content_type :aws_icon, content_type: /\Aimage\/.*\Z/
validates_attachment_content_type :aws_icon, content_type: %r{\Aimage/.*\Z}
validate :aws_xor_manual_icon
validate :manual_icon_https
@ -31,15 +29,13 @@ class Metacode < ApplicationRecord
def as_json(options = {})
default = super(options)
default[:icon] = icon
default.except('aws_icon_file_name', 'aws_icon_content_type', 'aws_icon_file_size', 'aws_icon_updated_at', 'manual_icon')
default.except(
'aws_icon_file_name', 'aws_icon_content_type', 'aws_icon_file_size', 'aws_icon_updated_at',
'manual_icon'
)
end
def hasSelected(user)
return true if user.settings.metacodes.include? id.to_s
false
end
def inMetacodeSet(metacode_set)
def in_metacode_set(metacode_set)
return true if metacode_sets.include? metacode_set
false
end
@ -56,10 +52,9 @@ class Metacode < ApplicationRecord
end
def manual_icon_https
if manual_icon.present?
return if manual_icon.blank?
unless manual_icon.starts_with? 'https'
errors.add(:base, 'Manual icon must begin with https')
end
end
end
end

View file

@ -1,14 +1,18 @@
# frozen_string_literal: true
class PermittedParams < Struct.new(:params)
%w(map synapse topic mapping token).each do |kind|
class PermittedParams
%w[map synapse topic mapping token].each do |kind|
define_method(kind) do
permitted_attributes = send("#{kind}_attributes")
params.require(kind).permit(*permitted_attributes)
@params.require(kind).permit(*permitted_attributes)
end
alias_method :"api_#{kind}", kind.to_sym
end
def initialize(params)
@params = params
end
alias read_attribute_for_serialization send
def token_attributes
@ -16,18 +20,18 @@ class PermittedParams < Struct.new(:params)
end
def map_attributes
%i(name desc permission arranged)
%i[name desc permission arranged]
end
def synapse_attributes
%i(desc category weight permission topic1_id topic2_id)
%i[desc category weight permission topic1_id topic2_id]
end
def topic_attributes
%i(name desc link permission metacode_id)
%i[name desc link permission metacode_id]
end
def mapping_attributes
%i(xloc yloc map_id mappable_type mappable_id)
%i[xloc yloc map_id mappable_type mappable_id]
end
end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class Synapse < ApplicationRecord
ATTRS_TO_WATCH = %w(desc category permission defer_to_map_id).freeze
ATTRS_TO_WATCH = %w[desc category permission defer_to_map_id].freeze
belongs_to :user
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
@ -22,9 +22,9 @@ class Synapse < ApplicationRecord
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true }
scope :for_topic, ->(topic_id = nil) {
scope :for_topic, (lambda do |topic_id = nil|
where(topic1_id: topic_id).or(where(topic2_id: topic_id))
}
end)
before_create :set_perm_by_defer
after_create :after_created_async
@ -55,7 +55,7 @@ class Synapse < ApplicationRecord
end
def as_json(_options = {})
super(methods: %i(user_name user_image collaborator_ids))
super(methods: %i[user_name user_image collaborator_ids])
end
def as_rdf
@ -73,7 +73,7 @@ class Synapse < ApplicationRecord
protected
def set_perm_by_defer
permission = defer_to_map.permission if defer_to_map
defer_to_map&.permission
end
def after_created_async
@ -83,7 +83,8 @@ class Synapse < ApplicationRecord
handle_asynchronously :after_created_async
def after_updated
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
meta = new.merge(old) # we are prioritizing the old values, keeping them
@ -93,7 +94,6 @@ class Synapse < ApplicationRecord
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseUpdated', id: id
end
end
end
def before_destroyed
# hard to know how to do this yet, because the synapse actually gets destroyed

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true
class Topic < ApplicationRecord
ATTRS_TO_WATCH = %w(name desc link metacode_id permission defer_to_map_id).freeze
ATTRS_TO_WATCH = %w[name desc link metacode_id permission defer_to_map_id].freeze
include TopicsHelper
include Attachable
@ -39,13 +39,13 @@ class Topic < ApplicationRecord
topics1.or(topics2)
end
scope :relatives, ->(topic_id = nil, user = nil) {
scope :relatives, (lambda do |topic_id = nil, user = nil|
# should only see topics through *visible* synapses
# e.g. Topic A (commons) -> synapse (private) -> Topic B (commons) must be filtered out
topic_ids = Pundit.policy_scope(user, Synapse.where(topic1_id: topic_id)).pluck(:topic2_id)
topic_ids += Pundit.policy_scope(user, Synapse.where(topic2_id: topic_id)).pluck(:topic1_id)
where(id: topic_ids.uniq)
}
end)
delegate :name, to: :user, prefix: true
@ -65,13 +65,13 @@ class Topic < ApplicationRecord
Pundit.policy_scope(user, maps).map(&:name)
end
def inmapsLinks(user)
def inmaps_links(user)
Pundit.policy_scope(user, maps).map(&:id)
end
def as_json(options = {})
super(methods: %i(user_name user_image collaborator_ids))
.merge(inmaps: inmaps(options[:user]), inmapsLinks: inmapsLinks(options[:user]),
super(methods: %i[user_name user_image collaborator_ids])
.merge(inmaps: inmaps(options[:user]), inmapsLinks: inmaps_links(options[:user]),
map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user]))
end
@ -127,15 +127,10 @@ class Topic < ApplicationRecord
end
end
end
if output_format == 'array'
return output
elsif output_format == 'text'
return output.join('; ')
else
return output if output_format == 'array'
return output.join('; ') if output_format == 'text'
raise 'invalid argument to synapses_csv'
end
output
end
def topic_autocomplete_method
"Get: #{name}"
@ -144,7 +139,7 @@ class Topic < ApplicationRecord
protected
def set_perm_by_defer
permission = defer_to_map.permission if defer_to_map
self.permission = defer_to_map.permission if defer_to_map
end
def create_metamap?
@ -163,7 +158,8 @@ class Topic < ApplicationRecord
handle_asynchronously :after_created_async
def after_updated
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
meta = new.merge(old) # we are prioritizing the old values, keeping them
@ -173,13 +169,12 @@ class Topic < ApplicationRecord
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicUpdated', id: id
end
end
end
def after_updated_async
if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
return unless 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

View file

@ -52,24 +52,24 @@ class User < ApplicationRecord
validates_attachment_content_type :image, content_type: %r{\Aimage/.*\Z}
# override default as_json
def as_json(_options = {})
def as_json(options = {})
json = { id: id,
name: name,
image: image.url(:sixtyfour),
admin: admin }
if _options[:follows]
if options[:follows]
json['follows'] = {
topics: following.active.where(followed_type: 'Topic').to_a.map(&:followed_id),
maps: following.active.where(followed_type: 'Map').to_a.map(&:followed_id)
}
end
if _options[:follow_settings]
if options[:follow_settings]
json['follow_topic_on_created'] = settings.follow_topic_on_created == '1'
json['follow_topic_on_contributed'] = settings.follow_topic_on_contributed == '1'
json['follow_map_on_created'] = settings.follow_map_on_created == '1'
json['follow_map_on_contributed'] = settings.follow_map_on_contributed == '1'
end
json['email'] = email if _options[:email]
json['email'] = email if options[:email]
json
end
@ -106,10 +106,14 @@ class User < ApplicationRecord
end
def most_used_metacodes
topics.to_a.each_with_object(Hash.new(0)) do |topic, memo|
memo[topic.metacode_id] += 1
memo
end.to_a.sort { |a, b| b[1] <=> a[1] }.map { |i| i[0] }.slice(0, 5)
metacode_counts = topics.to_a.each_with_object(Hash.new(0)) do |topic, list_so_far|
list_so_far[topic.metacode_id] += 1
list_so_far
end
id_count_pairs = metacode_counts.to_a
id_count_pairs.sort! { |a, b| b[1] <=> a[1] }
metacode_ids = id_count_pairs.map { |i| i[0] }
metacode_ids.slice(0, 5)
end
# generate a random 8 letter/digit code that they can use to invite people
@ -132,11 +136,11 @@ class User < ApplicationRecord
end
def has_map_open(map)
latestEvent = Event.where(map: map, user: self)
.where(kind: %w(user_present_on_map user_not_present_on_map))
latest_event = Event.where(map: map, user: self)
.where(kind: %w[user_present_on_map user_not_present_on_map])
.order(:created_at)
.last
latestEvent && latestEvent.kind == 'user_present_on_map'
latest_event && latest_event.kind == 'user_present_on_map'
end
def has_map_with_synapse_open(synapse)

View file

@ -5,20 +5,24 @@ class UserPreference
:follow_map_on_created, :follow_map_on_contributed
def initialize
array = []
%w(Action Aim Idea Question Note Wildcard Subject).each do |m|
@metacodes = init_metacodes.compact
@metacode_focus = @metacodes[0]
initialize_follow_settings
end
private
def init_metacodes
%w[Action Aim Idea Question Note Wildcard Subject].map do |m|
begin
metacode = Metacode.find_by(name: m)
array.push(metacode.id.to_s) if metacode
metacode.id.to_s if metacode
rescue ActiveRecord::StatementInvalid
if m == 'Action'
Rails.logger.warn('TODO: remove this travis workaround in user_preference.rb')
end
end
end
@metacodes = array
@metacode_focus = array[0]
initialize_follow_settings
end.compact
end
def initialize_follow_settings

View file

@ -5,7 +5,7 @@ class Webhook < ApplicationRecord
validates :uri, presence: true
validates :hookable, presence: true
validates :kind, inclusion: { in: %w(slack) }
validates :kind, inclusion: { in: %w[slack] }
validates :event_types, length: { minimum: 1 }
def headers

View file

@ -3,6 +3,8 @@
class Webhooks::Slack::SynapseAddedToMap < Webhooks::Slack::Base
def text
connector = eventable.desc.empty? ? '->' : eventable.desc
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\" was added as a connection by *#{event.user.name}* to the map *#{view_map_on_metamaps}*"
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\"" \
" was added as a connection by *#{event.user.name}*" \
" to the map *#{view_map_on_metamaps}*"
end
end

View file

@ -3,7 +3,11 @@
class Webhooks::Slack::SynapseRemovedFromMap < Webhooks::Slack::Base
def text
connector = eventable.desc.empty? ? '->' : eventable.desc
# TODO: express correct directionality of arrows when desc is empty
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\" was removed by *#{event.user.name}* as a connection from the map *#{view_map_on_metamaps}*"
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\"" \
" was removed by *#{event.user.name}* as a connection" \
" from the map *#{view_map_on_metamaps}*"
end
end

View file

@ -3,7 +3,7 @@
class MapPolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = %w(public commons)
visible = %w[public commons]
return scope.where(permission: visible) unless user
scope.where(permission: visible)
@ -17,13 +17,13 @@ class MapPolicy < ApplicationPolicy
end
def show?
record.permission.in?(%w(commons public)) ||
record.permission.in?(%w[commons public]) ||
record.collaborators.include?(user) ||
record.user == user
end
def conversation?
show? && %w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email)
show? && is_tester(user)
end
def create?

View file

@ -7,7 +7,7 @@ class MappingPolicy < ApplicationPolicy
# it would be nice if we could also base this on the mappable, but that
# gets really complicated. Devin thinks it's OK to SHOW a mapping for
# a private topic, since you can't see the private topic anyways
visible = %w(public commons)
visible = %w[public commons]
permission = 'maps.permission IN (?)'
return scope.joins(:map).where(permission, visible) unless user

View file

@ -3,7 +3,7 @@
class MessagePolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = %w(public commons)
visible = %w[public commons]
permission = 'maps.permission IN (?)'
return scope.joins(:map).where(permission, visible) unless user

View file

@ -3,12 +3,21 @@
class SynapsePolicy < ApplicationPolicy
class Scope < Scope
def resolve
return scope.where(permission: %w(public commons)) unless user
return authenticated_scope if user
unauthenticated_scope
end
scope.where(permission: %w(public commons))
private
def authenticated_scope
scope.where(permission: %w[public commons])
.or(scope.where(defer_to_map_id: user.all_accessible_maps.map(&:id)))
.or(scope.where(user_id: user.id))
end
def unauthenticated_scope
scope.where(permission: %w[public commons])
end
end
def index?

View file

@ -3,12 +3,21 @@
class TopicPolicy < ApplicationPolicy
class Scope < Scope
def resolve
return scope.where(permission: %w(public commons)) unless user
return authenticated_scope if user
unauthenticated_scope
end
scope.where(permission: %w(public commons))
private
def authenticated_scope
scope.where(permission: %w[public commons])
.or(scope.where(defer_to_map_id: user.all_accessible_maps.map(&:id)))
.or(scope.where(user_id: user.id))
end
def unauthenticated_scope
scope.where(permission: %w[public commons])
end
end
def index?
@ -23,7 +32,7 @@ class TopicPolicy < ApplicationPolicy
if record.defer_to_map.present?
map_policy.show?
else
record.permission.in?(%w(commons public)) || record.user == user
record.permission.in?(%w[commons public]) || record.user == user
end
end

View file

@ -17,7 +17,6 @@ module Api
object.image.url(:sixtyfour)
end
# rubocop:disable Style/PredicateName
def is_admin
object.admin
end

View file

@ -18,21 +18,21 @@ class FollowService
def unfollow(entity, user)
follow = Follow.where(followed: entity, user: user).first
if follow
return unless follow
unless follow.update(muted: true)
raise follow.errors.full_messages.join("\n")
end
end
end
def remove_reason(entity, user, reason)
return unless FollowReason::REASONS.include?(reason)
follow = Follow.where(followed: entity, user: user).first
if follow
return unless follow
follow.follow_reason.update_attribute(reason, false)
follow.destroy unless follow.follow_reason.has_reason
end
end
protected
@ -40,17 +40,11 @@ class FollowService
follow = Follow.where(followed: entity, user: user).first
return false if follow && follow.muted
if entity.class == Topic
if reason == 'created'
return user.settings.follow_topic_on_created == '1'
elsif reason == 'contributed'
return user.settings.follow_topic_on_contributed == '1'
end
return user.settings.follow_topic_on_created == '1' if reason == 'created'
return user.settings.follow_topic_on_contributed == '1' if reason == 'contributed'
elsif entity.class == Map
if reason == 'created'
return user.settings.follow_map_on_created == '1'
elsif reason == 'contributed'
return user.settings.follow_map_on_contributed == '1'
end
return user.settings.follow_map_on_created == '1' if reason == 'created'
return user.settings.follow_map_on_contributed == '1' if reason == 'contributed'
end
end
end

View file

@ -5,7 +5,7 @@ class MapActivityService
'Activity on map ' + map.name
end
def self.summarize_data(map, user, until_moment = DateTime.now)
def self.summarize_data(map, user, until_moment = DateTime.current)
results = {
stats: {}
}
@ -18,7 +18,7 @@ class MapActivityService
message_count = Message.where(resource: map)
.where('created_at > ? AND created_at < ?', since, until_moment)
.where.not(user: user).count
results[:stats][:messages_sent] = message_count if message_count > 0
results[:stats][:messages_sent] = message_count if message_count.positive?
moved_count = Event.where(kind: 'topic_moved_on_map', map: map)
.where('created_at > ? AND created_at < ?', since, until_moment)
@ -42,7 +42,9 @@ class MapActivityService
topics_added_events.each do |ta|
num_adds = topics_added_events.where(eventable_id: ta.eventable_id).count
num_removes = topics_removed_events.where(eventable_id: ta.eventable_id).count
topics_added_to_include[ta.eventable_id] = ta if num_adds > num_removes && scoped_topic_ids.include?(ta.eventable.id)
if num_adds > num_removes && scoped_topic_ids.include?(ta.eventable.id)
topics_added_to_include[ta.eventable_id] = ta
end
end
unless topics_added_to_include.keys.empty?
results[:stats][:topics_added] = topics_added_to_include.keys.length
@ -53,7 +55,9 @@ class MapActivityService
topics_removed_events.each do |ta|
num_adds = topics_added_events.where(eventable_id: ta.eventable_id).count
num_removes = topics_removed_events.where(eventable_id: ta.eventable_id).count
topics_removed_to_include[ta.eventable_id] = ta if num_removes > num_adds && TopicPolicy.new(user, ta.eventable).show?
if num_removes > num_adds && TopicPolicy.new(user, ta.eventable).show?
topics_removed_to_include[ta.eventable_id] = ta
end
end
unless topics_removed_to_include.keys.empty?
results[:stats][:topics_removed] = topics_removed_to_include.keys.length
@ -74,7 +78,9 @@ class MapActivityService
synapses_added_events.each do |ta|
num_adds = synapses_added_events.where(eventable_id: ta.eventable_id).count
num_removes = synapses_removed_events.where(eventable_id: ta.eventable_id).count
synapses_added_to_include[ta.eventable_id] = ta if num_adds > num_removes && scoped_synapse_ids.include?(ta.eventable.id)
if num_adds > num_removes && scoped_synapse_ids.include?(ta.eventable.id)
synapses_added_to_include[ta.eventable_id] = ta
end
end
unless synapses_added_to_include.keys.empty?
results[:stats][:synapses_added] = synapses_added_to_include.keys.length
@ -85,7 +91,9 @@ class MapActivityService
synapses_removed_events.each do |ta|
num_adds = synapses_added_events.where(eventable_id: ta.eventable_id).count
num_removes = synapses_removed_events.where(eventable_id: ta.eventable_id).count
synapses_removed_to_include[ta.eventable_id] = ta if num_removes > num_adds && SynapsePolicy.new(user, ta.eventable).show?
if num_removes > num_adds && SynapsePolicy.new(user, ta.eventable).show?
synapses_removed_to_include[ta.eventable_id] = ta
end
end
unless synapses_removed_to_include.keys.empty?
results[:stats][:synapses_removed] = synapses_removed_to_include.keys.length

View file

@ -47,16 +47,16 @@ class MapExportService
private
def topic_headings
%i(id name metacode x y description link user permission)
%i[id name metacode x y description link user permission]
end
def synapse_headings
%i(topic1 topic2 category description user permission)
%i[topic1 topic2 category description user permission]
end
def exportable_topics
visible_topics ||= Pundit.policy_scope!(user, map.topics)
topic_mappings = Mapping.includes(mappable: %i(metacode user))
topic_mappings = Mapping.includes(mappable: %i[metacode user])
.where(mappable: visible_topics, map: map)
topic_mappings.map do |mapping|
topic = mapping.mappable

View file

@ -7,7 +7,7 @@ class NotificationService
include ActionView::Helpers::SanitizeHelper
def self.renderer
renderer ||= ApplicationController.renderer.new(
@renderer ||= ApplicationController.renderer.new(
http_host: ENV['MAILER_DEFAULT_URL'],
https: Rails.env.production? ? true : false
)
@ -70,19 +70,25 @@ class NotificationService
def self.access_request(request)
subject = access_request_subject(request.map)
body = renderer.render(template: 'map_mailer/access_request', locals: { map: request.map, request: request }, layout: false)
body = renderer.render(template: 'map_mailer/access_request',
locals: { map: request.map, request: request },
layout: false)
request.map.user.notify(subject, body, request, false, MAP_ACCESS_REQUEST, true, request.user)
end
def self.access_approved(request)
subject = access_approved_subject(request.map)
body = renderer.render(template: 'map_mailer/access_approved', locals: { map: request.map }, layout: false)
body = renderer.render(template: 'map_mailer/access_approved',
locals: { map: request.map },
layout: false)
request.user.notify(subject, body, request, false, MAP_ACCESS_APPROVED, true, request.map.user)
end
def self.invite_to_edit(user_map)
subject = invite_to_edit_subject(user_map.map)
body = renderer.render(template: 'map_mailer/invite_to_edit', locals: { map: user_map.map, inviter: user_map.map.user }, layout: false)
body = renderer.render(template: 'map_mailer/invite_to_edit',
locals: { map: user_map.map, inviter: user_map.map.user },
layout: false)
user_map.user.notify(subject, body, user_map, false, MAP_INVITE_TO_EDIT, true, user_map.map.user)
end

View file

@ -2,7 +2,7 @@
class Perm
# e.g. Perm::ISSIONS
ISSIONS = %i(commons public private).freeze
ISSIONS = %i[commons public private].freeze
class << self
def short(permission)

View file

@ -35,7 +35,7 @@
<% $i = 0 %>
<% @m = Metacode.order("name").all %>
<% while $i < (Metacode.all.length / 4) do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].inMetacodeSet(@metacode_set) %>class="toggledOff"<% end %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].in_metacode_set(@metacode_set) %>class="toggledOff"<% end %>
onclick="Metamaps.Admin.liClickHandler.call(this);">
<img src="<%= asset_path @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
@ -46,7 +46,7 @@
</ul>
<ul id="filters-two">
<% while $i < (Metacode.all.length / 4 * 2) do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].inMetacodeSet(@metacode_set) %>class="toggledOff"<% end %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].in_metacode_set(@metacode_set) %>class="toggledOff"<% end %>
onclick="Metamaps.Admin.liClickHandler.call(this);">
<img src="<%= asset_path @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
@ -57,7 +57,7 @@
</ul>
<ul id="filters-three">
<% while $i < (Metacode.all.length / 4 * 3) do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].inMetacodeSet(@metacode_set) %>class="toggledOff"<% end %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].in_metacode_set(@metacode_set) %>class="toggledOff"<% end %>
onclick="Metamaps.Admin.liClickHandler.call(this);">
<img src="<%= asset_path @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>
@ -68,7 +68,7 @@
</ul>
<ul id="filters-four">
<% while $i < Metacode.all.length do %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].inMetacodeSet(@metacode_set) %>class="toggledOff"<% end %>
<li id="<%= @m[$i].id %>" <% if not @m[$i].in_metacode_set(@metacode_set) %>class="toggledOff"<% end %>
onclick="Metamaps.Admin.liClickHandler.call(this);">
<img src="<%= asset_path @m[$i].icon %>" alt="<%= @m[$i].name %>" />
<p><%= @m[$i].name.downcase %></p>

View file

@ -6,7 +6,7 @@
<script>
<% Metacode.all.each do |m| %>
<% if m.inMetacodeSet(@metacode_set) %>
<% if m.in_metacode_set(@metacode_set) %>
Metamaps.Admin.selectMetacodes.push("<%= m.id %>");
<% end %>
Metamaps.Admin.allMetacodes.push("<%= m.id %>");

View file

@ -6,7 +6,7 @@
<script>
<% Metacode.all.each do |m| %>
<% if m.inMetacodeSet(@metacode_set) %>
<% if m.in_metacode_set(@metacode_set) %>
Metamaps.Admin.selectMetacodes.push("<%= m.id %>");
<% end %>
Metamaps.Admin.allMetacodes.push("<%= m.id %>");

View file

@ -25,7 +25,7 @@ Rails.application.configure do
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
config.action_mailer.preview_path = "#{Rails.root}/spec/mailers/previews"
config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews')
# Expands the lines which load the assets
config.assets.debug = false

View file

@ -4,7 +4,9 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb
config.action_cable.allowed_request_origins = ['https://metamaps.herokuapp.com', 'http://metamaps.herokuapp.com', 'https://metamaps.cc']
config.action_cable.allowed_request_origins = [
'https://metamaps.herokuapp.com', 'http://metamaps.herokuapp.com', 'https://metamaps.cc'
]
# log to stdout
logger = Logger.new(STDOUT)

View file

@ -10,5 +10,5 @@ Rails.application.configure do
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
config.assets.precompile += %w(application-secret.css application-secret.js webpacked/metamaps.bundle.js)
config.assets.precompile += %w[application-secret.css application-secret.js webpacked/metamaps.bundle.js]
end

View file

@ -5,6 +5,6 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do
origins '*'
resource '/api/*',
headers: :any,
methods: %i(get post put delete options head)
methods: %i[get post put delete options head]
end
end

View file

@ -11,4 +11,4 @@ Delayed::Worker.class_eval do
prepend ExceptionNotifierInDelayedJob
end
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log'))

View file

@ -51,11 +51,11 @@ ExceptionNotification.configure do |config|
# Ignore additional exception types.
# ActiveRecord::RecordNotFound, AbstractController::ActionNotFound and
# ActionController::RoutingError are already added.
config.ignored_exceptions += %w(
config.ignored_exceptions += %w[
ActionView::TemplateError CustomError UnauthorizedException
InvalidArgumentException InvalidEntityException InvalidRequestException
NotFoundException ValidationException
)
]
# Adds a condition to decide when an exception must be ignored or not.
# The ignore_if method can be invoked multiple times to add extra conditions.

View file

@ -1,5 +1,8 @@
# frozen_string_literal: true
def is_tester(user)
user && %w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email)
user && %w[
connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com
ishanshapiro@gmail.com
].include?(user.email)
end

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true
METAMAPS_VERSION = '3.5'
METAMAPS_VERSION = '3..6.1'
METAMAPS_BUILD = `git log -1 --pretty=%H`.chomp[0..11].freeze
METAMAPS_LAST_UPDATED = `git log -1 --pretty='%ad'`.split(' ').values_at(1, 2, 4).join(' ').freeze

View file

@ -17,7 +17,7 @@ Metamaps::Application.routes.draw do
end
get :explore, to: redirect('/')
resources :maps, except: %i(index edit) do
resources :maps, except: %i[index edit] do
member do
get :conversation
get :export
@ -55,10 +55,10 @@ Metamaps::Application.routes.draw do
end
end
resources :mappings, except: %i(index new edit)
resources :mappings, except: %i[index new edit]
resources :messages, only: %i(show create update destroy)
resources :notifications, only: %i(index show) do
resources :messages, only: %i[show create update destroy]
resources :notifications, only: %i[index show] do
collection do
get :unsubscribe
end
@ -80,9 +80,9 @@ Metamaps::Application.routes.draw do
get :synapses
end
resources :synapses, except: %i(index new edit)
resources :synapses, except: %i[index new edit]
resources :topics, except: %i(index new edit) do
resources :topics, except: %i[index new edit] do
member do
get :network
get :relative_numbers
@ -111,7 +111,7 @@ Metamaps::Application.routes.draw do
get 'join' => 'users/registrations#new', :as => :sign_up
end
resources :users, except: %i(index destroy) do
resources :users, except: %i[index destroy] do
member do
get :details
end
@ -121,16 +121,16 @@ Metamaps::Application.routes.draw do
namespace :api, path: '/api', default: { format: :json } do
namespace :v2, path: '/v2' do
resources :metacodes, only: %i(index show)
resources :mappings, only: %i(index create show update destroy)
resources :maps, only: %i(index create show update destroy) do
resources :metacodes, only: %i[index show]
resources :mappings, only: %i[index create show update destroy]
resources :maps, only: %i[index create show update destroy] do
post :stars, to: 'stars#create', on: :member
delete :stars, to: 'stars#destroy', on: :member
end
resources :synapses, only: %i(index create show update destroy)
resources :tokens, only: %i(index create destroy)
resources :topics, only: %i(index create show update destroy)
resources :users, only: %i(index show) do
resources :synapses, only: %i[index create show update destroy]
resources :tokens, only: %i[index create destroy]
resources :topics, only: %i[index create show update destroy]
resources :users, only: %i[index show] do
get :current, on: :collection
end
match '*path', to: 'restful#catch_404', via: :all

View file

@ -1,9 +1,9 @@
# frozen_string_literal: true
%w(
%w[
.ruby-version
.ruby-gemset
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
).each { |path| Spring.watch(path) }
].each { |path| Spring.watch(path) }

View file

@ -26,13 +26,13 @@ At the time of writing, there are four directories in the spec folder. One,
`support`, is for helper functions. `rails_helper.rb` and `spec_helper.rb` are
also for helper functions.
`factories` is for a gem called [factory-girl][factory-girl]. This gem lets you
`factories` is for a gem called [factory-bot][factory_bot]. This gem lets you
use the `create` and `build` functions to quickly create the simplest possible
valid version of a given model. For instance:
let(:map1) { create :map }
let(:ronald) { create :user, name: "Ronald" }
let(:map2) { create :map, user: ronald }
let(:alex) { create :user, name: "Alex" }
let(:map2) { create :map, user: alex }
As you can see, you can also customize the factories. You can read the full
documentation at the link above or check the existing specs to see how it works.
@ -53,5 +53,5 @@ the added code works. This will help in a few ways:
Happy testing!
[factory-girl]: https://github.com/thoughtbot/factory_girl
[factory-bot]: https://github.com/thoughtbot/factory_bot
[rspec-docs]: http://rspec.info

View file

@ -1,9 +1,9 @@
const Debug = function(arg = window.Metamaps) {
if (arg === undefined && typeof window !== 'undefined') arg = window.Metamaps
console.debug(arg)
console.debug(`Metamaps Version: ${arg.ServerData.VERSION}`)
console.debug(`Build: ${arg.ServerData.BUILD}`)
console.debug(`Last Updated: ${arg.ServerData.LAST_UPDATED}`)
console.log(arg)
console.log(`Metamaps Version: ${arg.ServerData.VERSION}`)
console.log(`Build: ${arg.ServerData.BUILD}`)
console.log(`Last Updated: ${arg.ServerData.LAST_UPDATED}`)
}
export default Debug

View file

@ -15,10 +15,6 @@ class Permission extends Component {
this.setState({selectingPermission: !this.state.selectingPermission})
}
openPermissionSelect = () => {
this.setState({selectingPermission: true})
}
closePermissionSelect = () => {
this.setState({selectingPermission: false})
}
@ -67,4 +63,5 @@ Permission.propTypes = {
updateTopic: PropTypes.func
}
export { Permission } // for testing
export default onClickOutsideAddon(Permission)

View file

@ -0,0 +1,99 @@
/* global describe, it */
import React from 'react'
import { expect } from 'chai'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import Desc from '../../../src/components/TopicCard/Desc.js'
function render(props) {
return shallow(<Desc {...props} />)
}
function sharedAssertions(wrapper, desc, { descProp }) {
it('renders the correct wrapping html', function() {
expect(wrapper.find('.scroll').length).to.equal(1)
expect(wrapper.find('.scroll').find('.desc').length).to.equal(1)
})
it('renders the description', function() {
expect(wrapper
.find('.scroll')
.find('.desc')
.find('.riek_desc')
.prop(descProp)).to.equal(desc)
})
}
describe('TopicCard/Desc', function() {
const desc = 'sample description'
describe('not authorized to edit', function() {
const wrapper = render({ authorizedToEdit: false, desc })
sharedAssertions(wrapper, desc, { descProp: 'children' })
})
describe('authorized to edit', function() {
const onChange = sinon.spy()
const wrapper = render({ authorizedToEdit: true, desc, onChange })
sharedAssertions(wrapper, desc, { descProp: 'value' })
it('renders mdSupport', function() {
const mdSupport = wrapper.find('.desc').childAt(1)
expect(mdSupport.prop('className')).to.equal('mdSupport')
expect(mdSupport.prop('href')).to.include('commonmark.org/help')
expect(mdSupport.prop('target')).to.equal('_blank')
})
it('renders clearfloat', function() {
const clearfloat = wrapper.find('.desc').childAt(2)
expect(clearfloat.prop('className')).to.equal('clearfloat')
})
const textArea = wrapper.find('.riek_desc')
it('has the correct classEditing', function() {
expect(textArea.prop('classEditing')).to.equal('riek-editing')
})
it('has 6 rows', function() {
expect(textArea.prop('rows')).to.equal('6')
})
describe('defaultProps', function() {
describe('desc is present', function() {
const textArea = render({
authorizedToEdit: true, desc: '**sample description 2**'
}).find('.riek_desc')
// TODO I'd prefer to be mocking Util.mdToHTML
it('converts markdown to html', function() {
expect(textArea.prop('defaultProps').dangerouslySetInnerHTML.__html)
.to.equal('<p><strong>sample description 2</strong></p>\n')
})
})
describe('desc is not present', function() {
const textArea = render({ authorizedToEdit: true, desc: null })
.find('.riek_desc')
it('renders placeholder message', function() {
expect(textArea.prop('defaultProps').dangerouslySetInnerHTML.__html)
.to.equal('<p class="emptyDesc">Edit the description... (supports markdown)</p>')
})
})
})
describe('editProps', function() {
const ENTER = 13
const target = { value: 'new value' }
it('does not call onChange on Shift+Enter', function() {
textArea.prop('editProps').onKeyPress({
shiftKey: true, which: ENTER
})
expect(onChange.notCalled).to.equal(true)
})
it('calls onChange on ENTER', function() {
textArea.prop('editProps').onKeyPress({
which: ENTER, preventDefault: () => {}, target
})
expect(onChange.calledWith({ desc: 'new value' })).to.equal(true)
})
})
})
})

View file

@ -0,0 +1,95 @@
/* global describe, it */
import React from 'react'
import { expect } from 'chai'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import PermissionWrapper, { Permission } from '../../../src/components/TopicCard/Permission.js'
function render(props) {
return shallow(<Permission {...props} />)
}
function sharedAssertions(permission) {
describe(permission, function() {
const shortname = permission === 'commons' ? 'co'
: permission === 'public' ? 'pu'
: permission === 'private' ? 'pr'
: new Error('invalid permission')
const wrapper = render({ permission })
it('has the correct css classes', function() {
expect(wrapper.find(`.${shortname}`).props().className).to.include('linkItem')
expect(wrapper.find(`.${shortname}`).props().className).to.include('mapPerm')
})
it('sets the title', function() {
expect(wrapper.find(`.${shortname}`).props().title).to.include(permission)
})
it('has correct permission select options', function() {
expect(wrapper.find('.permissionSelect').find('.commons').length)
.to.equal(permission === 'commons' ? 0 : 1)
expect(wrapper.find('.permissionSelect').find('.public').length)
.to.equal(permission === 'public' ? 0 : 1)
expect(wrapper.find('.permissionSelect').find('.private').length)
.to.equal(permission === 'private' ? 0 : 1)
})
})
}
describe('TopicCard/Permission', function() {
sharedAssertions('commons')
sharedAssertions('public')
sharedAssertions('private')
describe('not authorizedToEdit', function() {
const togglePermissionSelect = sinon.spy()
const wrapper = render({
permission: 'commons', authorizedToEdit: false, togglePermissionSelect
})
it('hides the permissionSelect div', function() {
expect(wrapper.find('.permissionSelect').props().style.display)
.to.equal('none')
})
it("doesn't open the permissionSelect div", function() {
wrapper.find('.linkItem').simulate('click')
expect(togglePermissionSelect.notCalled).to.equal(true)
expect(wrapper.state().selectingPermission).to.equal(false)
})
})
describe('authorizedToEdit', function() {
const updateTopic = sinon.spy()
const wrapper = render({
permission: 'commons', authorizedToEdit: true, updateTopic
})
it('opens the permissionSelect div', function() {
wrapper.setState({ selectingPermission: false })
wrapper.find('.linkItem').simulate('click')
expect(wrapper.state().selectingPermission).to.equal(true)
})
it('updates the topic permissions', function() {
wrapper.setState({ selectingPermission: true })
wrapper.find('.permissionSelect').find('.public').simulate('click', {
preventDefault: () => {}
})
expect(wrapper.state().selectingPermission).to.equal(false)
expect(updateTopic.calledWith({
permission: 'public', defer_to_map_id: null
})).to.equal(true)
})
})
})
describe('PermissionWrapper', function() {
const wrapper = shallow(<PermissionWrapper />)
it('wraps Permission component in onclickoutside', function() {
expect(wrapper.type()).to.equal(Permission)
})
})

View file

@ -0,0 +1,68 @@
/* global describe, it */
import React from 'react'
import { expect } from 'chai'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import { RIETextArea } from 'riek'
import Title from '../../../src/components/TopicCard/Title.js'
function render(props) {
return shallow(<Title {...props} />)
}
const name = 'name 1'
function assertParentTitleSpan(wrapper) {
it('wraps everything in span.title', function() {
expect(wrapper.props().className).to.equal('title')
expect(wrapper.type()).to.equal('span')
})
}
describe('TopicCard/Title', function() {
describe('not authorized to edit', function() {
const wrapper = render({ authorizedToEdit: false, name })
assertParentTitleSpan(wrapper)
it('renders the name in span.titleWrapper', function() {
expect(wrapper.find('.titleWrapper').text()).to.have.string(name)
expect(wrapper.find('.titleWrapper').type()).to.equal('span')
})
})
describe('authorized to edit', function() {
const onChange = sinon.spy()
const wrapper = render({ authorizedToEdit: true, onChange, name })
const textArea = wrapper.find('.titleWrapper')
assertParentTitleSpan(wrapper)
it('renders RIETextArea with correct value', function() {
expect(textArea.type()).to.equal(RIETextArea)
expect(textArea.props().value).to.equal(name)
})
it('RIETextArea props are correct', function() {
expect(textArea.props().id).to.equal('titleActivator')
expect(textArea.props().classEditing).to.equal('riek-editing')
})
it('calls onChange on Enter', function() {
// simulate pressing Enter
textArea.props().editProps.onKeyPress({
which: 13, preventDefault: () => {}, target: { value: 'new name' }
})
expect(onChange.calledOnce).to.equal(true)
expect(onChange.calledWithExactly({ name: 'new name' }))
})
it('renders a namecounter', function() {
expect(wrapper.find('.nameCounter').props().className).to.equal('nameCounter')
expect(wrapper.find('.nameCounter').text()).to.have.string(`${name.length}/140`)
})
})
})

View file

@ -0,0 +1,108 @@
/* global describe, it */
import React from 'react'
import { expect } from 'chai'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import ReactTopicCard from '../../../src/components/TopicCard/index.js'
import Links from '../../../src/components/TopicCard/Links.js'
import Title from '../../../src/components/TopicCard/Title.js'
import Desc from '../../../src/components/TopicCard/Desc.js'
import Attachments from '../../../src/components/TopicCard/Attachments.js'
import Info from '../../../src/components/TopicCard/Info.js'
const currentUser = { current: 'user' }
function render(props) {
return shallow(<ReactTopicCard {...props} currentUser={currentUser} />)
}
function mockTopic({ hasAttachment, canEdit, isOwner }) {
const get = sinon.stub()
if (hasAttachment) {
get.withArgs('link').returns('https://www.google.ca')
} else {
get.withArgs('link').returns('')
}
const authorizeToEdit = sinon.stub()
authorizeToEdit.withArgs(currentUser).returns(canEdit)
const authorizePermissionChange = sinon.stub()
authorizePermissionChange.withArgs(currentUser).returns(isOwner)
return {
get,
authorizeToEdit,
authorizePermissionChange
}
}
function assertCssClassPresent({ mockTopicParam, mockTopicValue, cssClass }) {
const topic = mockTopic({ [mockTopicParam]: mockTopicValue })
const wrapper = render({ openTopic: topic })
it(`correctly shows ${cssClass} css class`, function() {
expect(wrapper.find(`.${cssClass}`).length).to.equal(1)
})
}
describe('TopicCard', function() {
describe('topic is null', function() {
const wrapper = render({ openTopic: null })
it('returns null', function() {
expect(wrapper.type()).to.be.null
})
})
describe('has attachment', function() {
assertCssClassPresent({ mockTopicParam: 'hasAttachment', mockTopicValue: true, cssClass: 'hasAttachment' })
})
describe('authorized to edit', function() {
assertCssClassPresent({ mockTopicParam: 'canEdit', mockTopicValue: true, cssClass: 'canEdit' })
})
describe('not authorized to edit', function() {
assertCssClassPresent({ mockTopicParam: 'canEdit', mockTopicValue: false, cssClass: 'cannotEdit' })
})
describe('topic is owned by current user', function() {
assertCssClassPresent({ mockTopicParam: 'isOwner', mockTopicValue: true, cssClass: 'yourTopic' })
})
describe('Draggable wrapper', function() {
const wrapper = render({ openTopic: mockTopic({}) })
it('handle is metacodeImage', function() {
expect(wrapper.props().handle).to.equal('.metacodeImage')
})
it('default position is 100, 100', function() {
expect(wrapper.props().defaultPosition.x).to.equal(100)
expect(wrapper.props().defaultPosition.y).to.equal(100)
})
})
describe('content', function() {
const wrapper = render({ openTopic: mockTopic({}) })
const innerDiv = wrapper.find('.CardOnGraph')
it('renders a Links component', function() {
expect(innerDiv.childAt(0).type()).to.equal(Links)
})
it('renders a Title component', function() {
expect(innerDiv.childAt(1).type()).to.equal(Title)
})
it('renders a Desc component', function() {
expect(innerDiv.childAt(2).type()).to.equal(Desc)
})
it('renders a Attachments component', function() {
expect(innerDiv.childAt(3).type()).to.equal(Attachments)
})
it('renders a Info component', function() {
expect(innerDiv.childAt(4).type()).to.equal(Info)
})
it('renders a clearfloat div at the end', function() {
const div = innerDiv.childAt(5)
expect(div.type()).to.equal('div')
expect(div.props().className).to.have.string('clearfloat')
})
})
})

View file

@ -15,7 +15,7 @@ RSpec.describe ExploreController, type: :controller do
expect(JSON.parse(response.body)).to eq []
end
it 'with 1 record' do
map = create(:map)
create(:map)
get :active, format: :json
expect(JSON.parse(response.body).class).to be Array
end

View file

@ -40,7 +40,10 @@ RSpec.describe SynapsesController, type: :controller do
context 'with private topics' do
it 'redirects to /' do
post :create, format: :json, params: {
synapse: valid_attributes.merge(topic1_id: create(:topic, permission: 'private'), topic2_id: create(:topic, permission: 'private'))
synapse: valid_attributes.merge(
topic1_id: create(:topic, permission: 'private'),
topic2_id: create(:topic, permission: 'private')
)
}
expect(response.status).to eq 302
expect(response).to redirect_to('/')

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :access_request do
map
user

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :mapping do
xloc 0
yloc 0

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :map do
sequence(:name) { |n| "Cool Map ##{n}" }
permission :commons

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :message do
association :resource, factory: :map
user

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :metacode do
sequence(:name) { |n| "Cool Metacode ##{n}" }
manual_icon 'https://images.com/image.png'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :star do
end
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :synapse do
sequence(:desc) { |n| "Cool synapse ##{n}" }
category :'from-to'

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :token do
user
description ''

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :topic do
user
association :updated_by, factory: :user

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
FactoryGirl.define do
FactoryBot.define do
factory :user_map do
map
user

View file

@ -10,7 +10,7 @@
# have actual codes, you'll need to specify one simple_user and then you
# can specify other :code_user users based on the pre-existing user's code.
FactoryGirl.define do
FactoryBot.define do
factory :code_user, class: User do
sequence(:name) { |n| "Cool User ##{n}" }
sequence(:email) { |n| "cooluser#{n}@cooldomain.com" }

View file

@ -69,17 +69,20 @@ class MapActivityMailerPreview < ActionMailer::Preview
end
def generate_user
User.create(name: Faker::Name.name, email: Faker::Internet.email, password: 'password', password_confirmation: 'password', joinedwithcode: 'qwertyui')
User.create(name: Faker::Name.name, email: Faker::Internet.email,
password: 'password', password_confirmation: 'password',
joinedwithcode: 'qwertyui')
end
def generate_map
Map.create(name: Faker::HarryPotter.book, permission: 'commons', arranged: false, user: generate_user)
Map.create(name: Faker::HarryPotter.book, permission: 'commons',
arranged: false, user: generate_user)
end
def topic_added_to_map(map)
user = generate_user
topic = Topic.create(name: Faker::Friends.quote, permission: 'commons', user: user)
mapping = Mapping.create(map: map, mappable: topic, user: user)
Mapping.create(map: map, mappable: topic, user: user)
end
def topic_moved_on_map(mapping)
@ -95,8 +98,9 @@ class MapActivityMailerPreview < ActionMailer::Preview
def synapse_added_to_map(map, topic1, topic2)
user = generate_user
topic = Synapse.create(desc: 'describes', permission: 'commons', user: user, topic1: topic1, topic2: topic2)
mapping = Mapping.create(map: map, mappable: topic, user: user)
topic = Synapse.create(desc: 'describes', permission: 'commons',
user: user, topic1: topic1, topic2: topic2)
Mapping.create(map: map, mappable: topic, user: user)
end
def synapse_removed_from_map(mapping)

View file

@ -11,13 +11,13 @@ if Rails.env.production?
end
# require all support files
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.fixture_path = ::Rails.root.join('spec', 'fixtures')
config.use_transactional_fixtures = true

View file

@ -16,7 +16,8 @@ RSpec.describe MapActivityService do
describe 'topics added to map' do
it 'includes a topic added within the last 24 hours' do
topic = create(:topic)
mapping = create(:mapping, user: other_user, map: map, mappable: topic, created_at: 6.hours.ago)
create(:mapping, user: other_user, map: map, mappable: topic, created_at: 6.hours.ago)
event = Event.find_by(kind: 'topic_added_to_map', eventable_id: topic.id)
event.update_columns(created_at: 6.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
@ -47,26 +48,33 @@ RSpec.describe MapActivityService do
mapping.destroy
Event.find_by(kind: 'topic_removed_from_map', eventable_id: topic.id).update_columns(created_at: 6.hours.ago)
mapping2 = create(:mapping, user: other_user, map: map, mappable: topic, created_at: 5.hours.ago)
Event.where(kind: 'topic_added_to_map').where("meta->>'mapping_id' = ?", mapping2.id.to_s).first.update_columns(created_at: 5.hours.ago)
Event.where(kind: 'topic_added_to_map').where("meta->>'mapping_id' = ?", mapping2.id.to_s)
.first
.update_columns(created_at: 5.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response).to eq empty_response
end
it 'excludes a topic added outside the last 24 hours' do
topic = create(:topic)
mapping = create(:mapping, user: other_user, map: map, mappable: topic, created_at: 25.hours.ago)
create(:mapping, user: other_user, map: map, mappable: topic, created_at: 25.hours.ago)
Event.find_by(kind: 'topic_added_to_map', eventable_id: topic.id).update_columns(created_at: 25.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response).to eq empty_response
end
it 'excludes topics added by the user who will receive the data' do
topic = create(:topic)
topic2 = create(:topic)
mapping = create(:mapping, user: other_user, map: map, mappable: topic, created_at: 5.hours.ago)
create(:mapping, user: other_user, map: map, mappable: topic, created_at: 5.hours.ago)
event = Event.find_by(kind: 'topic_added_to_map', eventable_id: topic.id)
event.update_columns(created_at: 5.hours.ago)
mapping2 = create(:mapping, user: email_user, map: map, mappable: topic2, created_at: 5.hours.ago)
topic2 = create(:topic)
create(:mapping, user: email_user, map: map, mappable: topic2, created_at: 5.hours.ago)
Event.find_by(kind: 'topic_added_to_map', eventable_id: topic2.id).update_columns(created_at: 5.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response[:stats][:topics_added]).to eq(1)
@ -166,7 +174,7 @@ RSpec.describe MapActivityService do
describe 'synapses added to map' do
it 'includes a synapse added within the last 24 hours' do
synapse = create(:synapse)
mapping = create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 6.hours.ago)
create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 6.hours.ago)
event = Event.find_by(kind: 'synapse_added_to_map', eventable_id: synapse.id)
event.update_columns(created_at: 6.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
@ -197,14 +205,16 @@ RSpec.describe MapActivityService do
mapping.destroy
Event.find_by(kind: 'synapse_removed_from_map', eventable_id: synapse.id).update_columns(created_at: 6.hours.ago)
mapping2 = create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 5.hours.ago)
Event.where(kind: 'synapse_added_to_map').where("meta->>'mapping_id' = ?", mapping2.id.to_s).first.update_columns(created_at: 5.hours.ago)
Event.where(kind: 'synapse_added_to_map').where("meta->>'mapping_id' = ?", mapping2.id.to_s)
.first
.update_columns(created_at: 5.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response).to eq empty_response
end
it 'excludes a synapse added outside the last 24 hours' do
synapse = create(:synapse)
mapping = create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 25.hours.ago)
create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 25.hours.ago)
Event.find_by(kind: 'synapse_added_to_map', eventable_id: synapse.id).update_columns(created_at: 25.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response).to eq empty_response
@ -212,11 +222,14 @@ RSpec.describe MapActivityService do
it 'excludes synapses added by the user who will receive the data' do
synapse = create(:synapse)
synapse2 = create(:synapse)
mapping = create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 5.hours.ago)
create(:mapping, user: other_user, map: map, mappable: synapse, created_at: 5.hours.ago)
event = Event.find_by(kind: 'synapse_added_to_map', eventable_id: synapse.id)
event.update_columns(created_at: 5.hours.ago)
mapping2 = create(:mapping, user: email_user, map: map, mappable: synapse2, created_at: 5.hours.ago)
synapse2 = create(:synapse)
create(:mapping, user: email_user, map: map, mappable: synapse2, created_at: 5.hours.ago)
Event.find_by(kind: 'synapse_added_to_map', eventable_id: synapse2.id).update_columns(created_at: 5.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response[:stats][:synapses_added]).to eq(1)
@ -262,7 +275,9 @@ RSpec.describe MapActivityService do
mapping2.destroy
event = Event.find_by(kind: 'synapse_removed_from_map', eventable_id: synapse.id)
event.update_columns(created_at: 5.hours.ago)
Event.find_by(kind: 'synapse_removed_from_map', eventable_id: synapse2.id).update_columns(created_at: 5.hours.ago)
Event
.find_by(kind: 'synapse_removed_from_map', eventable_id: synapse2.id)
.update_columns(created_at: 5.hours.ago)
response = MapActivityService.summarize_data(map, email_user)
expect(response[:stats][:synapses_removed]).to eq(1)
expect(response[:synapses_removed]).to eq([event])
@ -297,7 +312,8 @@ RSpec.describe MapActivityService do
old_topic = create(:topic, permission: 'commons', user: other_user)
old_topic_mapping = create(:mapping, map: map, mappable: old_topic, user: other_user)
old_private_topic = create(:topic, permission: 'private', user: other_user)
old_private_topic_mapping = create(:mapping, map: map, mappable: old_private_topic, user: other_user)
old_private_topic_mapping = create(:mapping, map: map, mappable: old_private_topic,
user: other_user)
end
Timecop.return
@ -347,7 +363,8 @@ RSpec.describe MapActivityService do
old_synapse = create(:synapse, permission: 'commons', user: other_user)
old_synapse_mapping = create(:mapping, map: map, mappable: old_synapse, user: other_user)
old_private_synapse = create(:synapse, permission: 'private', user: other_user)
old_private_synapse_mapping = create(:mapping, map: map, mappable: old_private_synapse, user: other_user)
old_private_synapse_mapping = create(:mapping, map: map, mappable: old_private_synapse,
user: other_user)
end
Timecop.return

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
# lets you type create(:user) instead of FactoryGirl.create(:user)
# lets you type create(:user) instead of FactoryBot.create(:user)
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include FactoryBot::Syntax::Methods
end

View file

@ -2,11 +2,10 @@
RSpec::Matchers.define :match_json_schema do |schema_name|
match do |response|
schema_directory = Rails.root.join('doc', 'api', 'schemas').to_s
schema = "#{schema_directory}/#{schema_name}.json"
schema_path = Rails.root.join('doc', 'api', 'schemas', "#{schema_name}.json").to_s
# schema customizations
schema = JSON.parse(File.read(schema))
schema = JSON.parse(File.read(schema_path))
schema = update_file_refs(schema)
data = JSON.parse(response.body)
@ -15,7 +14,7 @@ RSpec::Matchers.define :match_json_schema do |schema_name|
end
def get_json_example(resource)
filepath = "#{Rails.root}/doc/api/examples/#{resource}.json"
filepath = Rails.root.join('doc', 'api', 'examples', "#{resource}.json")
OpenStruct.new(body: File.read(filepath))
end
@ -25,7 +24,7 @@ def update_file_refs(schema)
schema[key] = if value.is_a? Hash
update_file_refs(value)
elsif key == '$ref'
"#{Rails.root}/doc/api/schemas/#{value}"
Rails.root.join('doc', 'api', 'schemas', value).to_s
else
value
end