Compare commits

..

1 commit

Author SHA1 Message Date
Devin Howard
9f1a2fa2b2 automatic rubocop fixes 2017-11-25 11:18:32 -08:00
83 changed files with 290 additions and 723 deletions

View file

@ -12,7 +12,7 @@ Rails:
Enabled: true Enabled: true
Metrics/LineLength: Metrics/LineLength:
Max: 120 Max: 100
Metrics/AbcSize: Metrics/AbcSize:
Max: 16 Max: 16
@ -22,8 +22,3 @@ Style/Documentation:
Style/EmptyMethod: Style/EmptyMethod:
EnforcedStyle: expanded 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 group :test do
gem 'brakeman', require: false gem 'brakeman', require: false
gem 'factory_bot_rails' gem 'factory_girl_rails'
gem 'json-schema' gem 'json-schema'
gem 'rspec-rails' gem 'rspec-rails'
gem 'shoulda-matchers' gem 'shoulda-matchers'
@ -51,7 +51,7 @@ group :development, :test do
gem 'faker' gem 'faker'
gem 'pry-byebug' gem 'pry-byebug'
gem 'pry-rails' gem 'pry-rails'
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758 gem 'rubocop', '~> 0.46.0' # match code climate https://github.com/tootsuite/mastodon/issues/1758
gem 'timecop' gem 'timecop'
gem 'tunemygc' gem 'tunemygc'
end end

View file

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

0
Rakefile Executable file → Normal file
View file

View file

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

View file

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

View file

@ -8,7 +8,7 @@ module Api
snorlax_used_rest! 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 after_action :verify_authorized
def index def index

View file

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

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class ExploreController < ApplicationController 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 before_action :authorize_explore
after_action :verify_authorized after_action :verify_authorized
after_action :verify_policy_scoped after_action :verify_policy_scoped

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class MappingsController < ApplicationController 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_authorized, except: :index
after_action :verify_policy_scoped, only: :index after_action :verify_policy_scoped, only: :index

View file

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

View file

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

View file

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

View file

@ -8,7 +8,7 @@ class SearchController < ApplicationController
before_action :authorize_search before_action :authorize_search
after_action :verify_authorized 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 # get /search/topics?term=SOMETERM
def topics def topics

View file

@ -3,7 +3,7 @@
class SynapsesController < ApplicationController class SynapsesController < ApplicationController
include TopicsHelper 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_authorized, except: :index
after_action :verify_policy_scoped, only: :index after_action :verify_policy_scoped, only: :index

View file

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

View file

@ -30,7 +30,7 @@ module Users
end end
def configure_sign_up_params 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 end
def configure_account_update_params def configure_account_update_params

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class UsersController < ApplicationController 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 respond_to :html, :json
@ -42,7 +42,7 @@ class UsersController < ApplicationController
correct_pass = @user.valid_password?(params[:current_password]) correct_pass = @user.valid_password?(params[:current_password])
if correct_pass && @user.update_attributes(user_params) if correct_pass && @user.update_attributes(user_params)
update_follow_settings(@user, params[:settings]) update_follow_settings(@user, params[:settings]) if is_tester(@user)
@user.image = nil if params[:remove_image] == '1' @user.image = nil if params[:remove_image] == '1'
@user.save @user.save
sign_in(@user, bypass: true) sign_in(@user, bypass: true)

View file

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

View file

@ -1,17 +1,17 @@
# frozen_string_literal: true # frozen_string_literal: true
class Event < ApplicationRecord 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 conversation_started_on_map
topic_added_to_map topic_moved_on_map topic_removed_from_map topic_added_to_map topic_moved_on_map topic_removed_from_map
synapse_added_to_map synapse_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 :eventable, polymorphic: true
belongs_to :map belongs_to :map
belongs_to :user belongs_to :user
scope :chronologically, (-> { order('created_at asc') }) scope :chronologically, -> { order('created_at asc') }
after_create :notify_webhooks!, if: :map after_create :notify_webhooks!, if: :map

View file

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

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class FollowReason < ApplicationRecord 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 belongs_to :follow

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Map < ApplicationRecord class Map < ApplicationRecord
ATTRS_TO_WATCH = %w[name desc permission].freeze 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
@ -90,10 +90,10 @@ class Map < ApplicationRecord
def as_json(_options = {}) def as_json(_options = {})
json = super( json = super(
methods: %i[user_name user_image star_count topic_count synapse_count methods: %i(user_name user_image star_count topic_count synapse_count
contributor_count collaborator_ids screenshot_url], contributor_count collaborator_ids screenshot_url),
except: %i[screenshot_content_type screenshot_file_size screenshot_file_name except: %i(screenshot_content_type screenshot_file_size screenshot_file_name
screenshot_updated_at] screenshot_updated_at)
) )
json[:created_at_clean] = created_at_str json[:created_at_clean] = created_at_str
json[:updated_at_clean] = updated_at_str json[:updated_at_clean] = updated_at_str
@ -153,11 +153,12 @@ class Map < ApplicationRecord
end end
def after_updated_async def after_updated_async
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
FollowService.follow(self, updated_by, 'contributed') FollowService.follow(self, updated_by, 'contributed')
# NotificationService.notify_followers(self, 'map_updated', changed_attributes) # NotificationService.notify_followers(self, 'map_updated', changed_attributes)
# or better yet publish an event # or better yet publish an event
end end
end
handle_asynchronously :after_updated_async handle_asynchronously :after_updated_async
def before_destroyed def before_destroyed

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
# 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 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'
@ -22,9 +22,9 @@ class Synapse < ApplicationRecord
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true } validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true }
scope :for_topic, (lambda do |topic_id = nil| scope :for_topic, ->(topic_id = nil) {
where(topic1_id: topic_id).or(where(topic2_id: topic_id)) where(topic1_id: topic_id).or(where(topic2_id: topic_id))
end) }
before_create :set_perm_by_defer before_create :set_perm_by_defer
after_create :after_created_async after_create :after_created_async
@ -55,7 +55,7 @@ class Synapse < ApplicationRecord
end end
def as_json(_options = {}) def as_json(_options = {})
super(methods: %i[user_name user_image collaborator_ids]) super(methods: %i(user_name user_image collaborator_ids))
end end
def as_rdf def as_rdf
@ -73,7 +73,7 @@ class Synapse < ApplicationRecord
protected protected
def set_perm_by_defer def set_perm_by_defer
defer_to_map&.permission permission = defer_to_map.permission if defer_to_map
end end
def after_created_async def after_created_async
@ -83,8 +83,7 @@ class Synapse < ApplicationRecord
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def after_updated def after_updated
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) } new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_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 meta = new.merge(old) # we are prioritizing the old values, keeping them
@ -94,6 +93,7 @@ class Synapse < ApplicationRecord
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
end end
end
def before_destroyed def before_destroyed
# hard to know how to do this yet, because the synapse actually gets 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 # 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 ATTRS_TO_WATCH = %w(name desc link metacode_id permission defer_to_map_id).freeze
include TopicsHelper include TopicsHelper
include Attachable include Attachable
@ -39,13 +39,13 @@ class Topic < ApplicationRecord
topics1.or(topics2) topics1.or(topics2)
end end
scope :relatives, (lambda do |topic_id = nil, user = nil| scope :relatives, ->(topic_id = nil, user = nil) {
# should only see topics through *visible* synapses # should only see topics through *visible* synapses
# e.g. Topic A (commons) -> synapse (private) -> Topic B (commons) must be filtered out # 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(topic1_id: topic_id)).pluck(:topic2_id)
topic_ids += Pundit.policy_scope(user, Synapse.where(topic2_id: topic_id)).pluck(:topic1_id) topic_ids += Pundit.policy_scope(user, Synapse.where(topic2_id: topic_id)).pluck(:topic1_id)
where(id: topic_ids.uniq) where(id: topic_ids.uniq)
end) }
delegate :name, to: :user, prefix: true delegate :name, to: :user, prefix: true
@ -65,13 +65,13 @@ class Topic < ApplicationRecord
Pundit.policy_scope(user, maps).map(&:name) Pundit.policy_scope(user, maps).map(&:name)
end end
def inmaps_links(user) def inmapsLinks(user)
Pundit.policy_scope(user, maps).map(&:id) Pundit.policy_scope(user, maps).map(&:id)
end end
def as_json(options = {}) def as_json(options = {})
super(methods: %i[user_name user_image collaborator_ids]) super(methods: %i(user_name user_image collaborator_ids))
.merge(inmaps: inmaps(options[:user]), inmapsLinks: inmaps_links(options[:user]), .merge(inmaps: inmaps(options[:user]), inmapsLinks: inmapsLinks(options[:user]),
map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user])) map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user]))
end end
@ -127,10 +127,15 @@ class Topic < ApplicationRecord
end end
end end
end end
return output if output_format == 'array' if output_format == 'array'
return output.join('; ') if output_format == 'text' return output
elsif output_format == 'text'
return output.join('; ')
else
raise 'invalid argument to synapses_csv' raise 'invalid argument to synapses_csv'
end end
output
end
def topic_autocomplete_method def topic_autocomplete_method
"Get: #{name}" "Get: #{name}"
@ -139,7 +144,7 @@ class Topic < ApplicationRecord
protected protected
def set_perm_by_defer def set_perm_by_defer
self.permission = defer_to_map.permission if defer_to_map permission = defer_to_map.permission if defer_to_map
end end
def create_metamap? def create_metamap?
@ -158,8 +163,7 @@ class Topic < ApplicationRecord
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def after_updated def after_updated
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) } new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_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 meta = new.merge(old) # we are prioritizing the old values, keeping them
@ -169,12 +173,13 @@ class Topic < ApplicationRecord
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
end end
end
def after_updated_async def after_updated_async
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
FollowService.follow(self, updated_by, 'contributed') FollowService.follow(self, updated_by, 'contributed')
end end
end
handle_asynchronously :after_updated_async handle_asynchronously :after_updated_async
def before_destroyed def before_destroyed

View file

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

View file

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

View file

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

View file

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

View file

@ -3,11 +3,7 @@
class Webhooks::Slack::SynapseRemovedFromMap < Webhooks::Slack::Base class Webhooks::Slack::SynapseRemovedFromMap < Webhooks::Slack::Base
def text def text
connector = eventable.desc.empty? ? '->' : eventable.desc connector = eventable.desc.empty? ? '->' : eventable.desc
# TODO: express correct directionality of arrows when desc is empty # 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
end end

View file

@ -3,7 +3,7 @@
class MapPolicy < ApplicationPolicy class MapPolicy < ApplicationPolicy
class Scope < Scope class Scope < Scope
def resolve def resolve
visible = %w[public commons] visible = %w(public commons)
return scope.where(permission: visible) unless user return scope.where(permission: visible) unless user
scope.where(permission: visible) scope.where(permission: visible)
@ -17,13 +17,13 @@ class MapPolicy < ApplicationPolicy
end end
def show? def show?
record.permission.in?(%w[commons public]) || record.permission.in?(%w(commons public)) ||
record.collaborators.include?(user) || record.collaborators.include?(user) ||
record.user == user record.user == user
end end
def conversation? def conversation?
show? && is_tester(user) show? && %w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email)
end end
def create? 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 # 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 # 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 # a private topic, since you can't see the private topic anyways
visible = %w[public commons] visible = %w(public commons)
permission = 'maps.permission IN (?)' permission = 'maps.permission IN (?)'
return scope.joins(:map).where(permission, visible) unless user return scope.joins(:map).where(permission, visible) unless user

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,5 +10,5 @@ Rails.application.configure do
# Precompile additional assets. # Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # 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 end

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
METAMAPS_VERSION = '3..6.1' METAMAPS_VERSION = '3.5'
METAMAPS_BUILD = `git log -1 --pretty=%H`.chomp[0..11].freeze 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 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 end
get :explore, to: redirect('/') get :explore, to: redirect('/')
resources :maps, except: %i[index edit] do resources :maps, except: %i(index edit) do
member do member do
get :conversation get :conversation
get :export get :export
@ -55,10 +55,10 @@ Metamaps::Application.routes.draw do
end end
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 :messages, only: %i(show create update destroy)
resources :notifications, only: %i[index show] do resources :notifications, only: %i(index show) do
collection do collection do
get :unsubscribe get :unsubscribe
end end
@ -80,9 +80,9 @@ Metamaps::Application.routes.draw do
get :synapses get :synapses
end 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 member do
get :network get :network
get :relative_numbers get :relative_numbers
@ -111,7 +111,7 @@ Metamaps::Application.routes.draw do
get 'join' => 'users/registrations#new', :as => :sign_up get 'join' => 'users/registrations#new', :as => :sign_up
end end
resources :users, except: %i[index destroy] do resources :users, except: %i(index destroy) do
member do member do
get :details get :details
end end
@ -121,16 +121,16 @@ Metamaps::Application.routes.draw do
namespace :api, path: '/api', default: { format: :json } do namespace :api, path: '/api', default: { format: :json } do
namespace :v2, path: '/v2' do namespace :v2, path: '/v2' do
resources :metacodes, only: %i[index show] resources :metacodes, only: %i(index show)
resources :mappings, only: %i[index create show update destroy] resources :mappings, only: %i(index create show update destroy)
resources :maps, only: %i[index create show update destroy] do resources :maps, only: %i(index create show update destroy) do
post :stars, to: 'stars#create', on: :member post :stars, to: 'stars#create', on: :member
delete :stars, to: 'stars#destroy', on: :member delete :stars, to: 'stars#destroy', on: :member
end end
resources :synapses, only: %i[index create show update destroy] resources :synapses, only: %i(index create show update destroy)
resources :tokens, only: %i[index create destroy] resources :tokens, only: %i(index create destroy)
resources :topics, only: %i[index create show update destroy] resources :topics, only: %i(index create show update destroy)
resources :users, only: %i[index show] do resources :users, only: %i(index show) do
get :current, on: :collection get :current, on: :collection
end end
match '*path', to: 'restful#catch_404', via: :all match '*path', to: 'restful#catch_404', via: :all

View file

@ -1,9 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
%w[ %w(
.ruby-version .ruby-version
.ruby-gemset .ruby-gemset
.rbenv-vars .rbenv-vars
tmp/restart.txt tmp/restart.txt
tmp/caching-dev.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 `support`, is for helper functions. `rails_helper.rb` and `spec_helper.rb` are
also for helper functions. also for helper functions.
`factories` is for a gem called [factory-bot][factory_bot]. This gem lets you `factories` is for a gem called [factory-girl][factory-girl]. This gem lets you
use the `create` and `build` functions to quickly create the simplest possible use the `create` and `build` functions to quickly create the simplest possible
valid version of a given model. For instance: valid version of a given model. For instance:
let(:map1) { create :map } let(:map1) { create :map }
let(:alex) { create :user, name: "Alex" } let(:ronald) { create :user, name: "Ronald" }
let(:map2) { create :map, user: alex } let(:map2) { create :map, user: ronald }
As you can see, you can also customize the factories. You can read the full 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. 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! Happy testing!
[factory-bot]: https://github.com/thoughtbot/factory_bot [factory-girl]: https://github.com/thoughtbot/factory_girl
[rspec-docs]: http://rspec.info [rspec-docs]: http://rspec.info

View file

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

View file

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

View file

@ -1,99 +0,0 @@
/* 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

@ -1,95 +0,0 @@
/* 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

@ -1,68 +0,0 @@
/* 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

@ -1,108 +0,0 @@
/* 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 [] expect(JSON.parse(response.body)).to eq []
end end
it 'with 1 record' do it 'with 1 record' do
create(:map) map = create(:map)
get :active, format: :json get :active, format: :json
expect(JSON.parse(response.body).class).to be Array expect(JSON.parse(response.body).class).to be Array
end end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,13 +11,13 @@ if Rails.env.production?
end end
# require all support files # 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! ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config| RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = ::Rails.root.join('spec', 'fixtures') config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true config.use_transactional_fixtures = true

View file

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

View file

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

View file

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