From 3843cab6439d90a16e49418bea289f269cf42d7c Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Thu, 22 Sep 2016 01:22:40 +0800 Subject: [PATCH] rails 5 + api v2 + raml api docs (#593) * update Gemfile to rails 5 and ruby 2.3.0 * fiddle with javascripts and add sprockets manifest file * update config directory for rails 5 * fix some errors with controllers/serializers * fix travis and rspec * new serializers renamed to serializers * module Api::V1 * reusable embedding code * add index/collections/paging. overriding most of snorlax now |:) * raml api documentation + rspec tests to verify schemas/examples * add sorting by ?sort and searching by ?q. Add pagination Link headers * api v1 => v2 * fill out synapse api * alphabetize map policy * fix page thing * fill out maps api * formParameters => properties, and fiddle with map api * more raml 1.0 stuff i'm learning about * deprecate v1 api * rails 5 uses ApplicationRecord class for app-wide model config * Update topic spec for api v2 * workaround for user_preference.rb issue * get ready for token api docs. also TODO is mapping api docs * spec out mapping api * map/mapping/synapse spec, plus other bugs * awesome, token specs/apis are done * add sanity checks to the api tests * more cleanup * devise fix * fix starred map error --- Gemfile | 20 +- Gemfile.lock | 211 +++++++++--------- app/assets/config/manifest.js | 6 + app/controllers/api/mappings_controller.rb | 2 - app/controllers/api/maps_controller.rb | 2 - app/controllers/api/restful_controller.rb | 50 ----- app/controllers/api/synapses_controller.rb | 2 - app/controllers/api/tokens_controller.rb | 17 -- app/controllers/api/topics_controller.rb | 2 - .../api/v1/deprecated_controller.rb | 9 + app/controllers/api/v1/mappings_controller.rb | 6 + app/controllers/api/v1/maps_controller.rb | 6 + app/controllers/api/v1/synapses_controller.rb | 6 + app/controllers/api/v1/tokens_controller.rb | 6 + app/controllers/api/v1/topics_controller.rb | 6 + app/controllers/api/v2/mappings_controller.rb | 6 + app/controllers/api/v2/maps_controller.rb | 9 + app/controllers/api/v2/restful_controller.rb | 179 +++++++++++++++ app/controllers/api/v2/sessions_controller.rb | 20 ++ app/controllers/api/v2/synapses_controller.rb | 9 + app/controllers/api/v2/tokens_controller.rb | 11 + app/controllers/api/v2/topics_controller.rb | 6 + app/controllers/main_controller.rb | 4 +- app/controllers/maps_controller.rb | 2 +- .../users/registrations_controller.rb | 5 +- app/models/application_record.rb | 3 + app/models/event.rb | 2 +- app/models/in_metacode_set.rb | 2 +- app/models/map.rb | 2 +- app/models/mapping.rb | 2 +- app/models/message.rb | 2 +- app/models/metacode.rb | 2 +- app/models/metacode_set.rb | 2 +- app/models/synapse.rb | 2 +- app/models/token.rb | 2 +- app/models/topic.rb | 2 +- app/models/user.rb | 4 +- app/models/user_map.rb | 2 +- app/models/user_preference.rb | 10 +- app/models/webhook.rb | 2 +- app/policies/map_policy.rb | 58 ++--- app/policies/mapping_policy.rb | 8 +- app/policies/synapse_policy.rb | 4 + app/policies/topic_policy.rb | 4 + .../api/v2/application_serializer.rb | 29 +++ app/serializers/api/v2/event_serializer.rb | 18 ++ app/serializers/api/v2/map_serializer.rb | 28 +++ app/serializers/api/v2/mapping_serializer.rb | 25 +++ app/serializers/api/v2/metacode_serializer.rb | 11 + app/serializers/api/v2/synapse_serializer.rb | 24 ++ app/serializers/api/v2/token_serializer.rb | 10 + app/serializers/api/v2/topic_serializer.rb | 24 ++ app/serializers/api/v2/user_serializer.rb | 19 ++ app/serializers/api/v2/webhook_serializer.rb | 7 + app/serializers/event_serializer.rb | 15 -- app/serializers/new_map_serializer.rb | 16 -- app/serializers/new_mapping_serializer.rb | 19 -- app/serializers/new_metacode_serializer.rb | 7 - app/serializers/new_synapse_serializer.rb | 14 -- app/serializers/new_topic_serializer.rb | 13 -- app/serializers/new_user_serializer.rb | 15 -- app/serializers/token_serializer.rb | 7 - app/serializers/webhook_serializer.rb | 3 - config/application.rb | 23 +- config/boot.rb | 5 +- config/cable.yml | 9 + config/environment.rb | 8 +- config/environments/production.rb | 51 +---- config/environments/test.rb | 6 +- config/initializers/access_codes.rb | 2 +- .../initializers/active_model_serializers.rb | 1 + .../application_controller_renderer.rb | 6 + config/initializers/assets.rb | 11 + config/initializers/cookies_serializer.rb | 5 + .../initializers/filter_parameter_logging.rb | 4 + config/initializers/inflections.rb | 11 +- config/initializers/kaminari_config.rb | 10 + config/initializers/mime_types.rb | 1 - config/initializers/new_framework_defaults.rb | 24 ++ config/initializers/secret_token.rb | 2 +- config/initializers/session_store.rb | 4 +- config/initializers/wrap_parameters.rb | 8 +- config/puma.rb | 47 ++++ config/routes.rb | 27 ++- config/spring.rb | 7 + db/schema.rb | 92 +++----- doc/api/api.raml | 39 ++++ doc/api/apis/mappings.raml | 68 ++++++ doc/api/apis/maps.raml | 82 +++++++ doc/api/apis/synapses.raml | 82 +++++++ doc/api/apis/tokens.raml | 25 +++ doc/api/apis/topics.raml | 72 ++++++ doc/api/examples/map.json | 27 +++ doc/api/examples/mapping.json | 11 + doc/api/examples/mappings.json | 54 +++++ doc/api/examples/maps.json | 37 +++ doc/api/examples/synapse.json | 13 ++ doc/api/examples/synapses.json | 34 +++ doc/api/examples/token.json | 8 + doc/api/examples/tokens.json | 18 ++ doc/api/examples/topic.json | 13 ++ doc/api/examples/topics.json | 34 +++ doc/api/resourceTypes/base.raml | 35 +++ doc/api/resourceTypes/collection.raml | 22 ++ doc/api/resourceTypes/item.raml | 29 +++ doc/api/schemas/_datetimestamp.json | 4 + doc/api/schemas/_id.json | 4 + doc/api/schemas/_map.json | 67 ++++++ doc/api/schemas/_mapping.json | 41 ++++ doc/api/schemas/_page.json | 38 ++++ doc/api/schemas/_permission.json | 4 + doc/api/schemas/_synapse.json | 42 ++++ doc/api/schemas/_token.json | 24 ++ doc/api/schemas/_topic.json | 43 ++++ doc/api/schemas/map.json | 12 + doc/api/schemas/mapping.json | 12 + doc/api/schemas/mappings.json | 19 ++ doc/api/schemas/maps.json | 19 ++ doc/api/schemas/synapse.json | 12 + doc/api/schemas/synapses.json | 19 ++ doc/api/schemas/token.json | 12 + doc/api/schemas/tokens.json | 19 ++ doc/api/schemas/topic.json | 12 + doc/api/schemas/topics.json | 19 ++ doc/api/traits/orderable.raml | 3 + doc/api/traits/pageable.raml | 7 + doc/api/traits/searchable.raml | 4 + spec/api/v2/mappings_api_spec.rb | 59 +++++ spec/api/v2/maps_api_spec.rb | 59 +++++ spec/api/v2/synapses_api_spec.rb | 59 +++++ spec/api/v2/tokens_api_spec.rb | 44 ++++ spec/api/v2/topics_api_spec.rb | 59 +++++ spec/controllers/mappings_controller_spec.rb | 56 ++--- spec/controllers/maps_controller_spec.rb | 73 +++--- spec/controllers/metacodes_controller_spec.rb | 45 ++-- spec/controllers/synapses_controller_spec.rb | 53 +++-- spec/controllers/topics_controller_spec.rb | 58 ++--- spec/factories/maps.rb | 1 + spec/factories/synapses.rb | 1 + spec/factories/tokens.rb | 6 + spec/factories/topics.rb | 6 +- spec/mailers/map_mailer_spec.rb | 5 - spec/rails_helper.rb | 27 +-- spec/spec_helper.rb | 4 - spec/support/controller_helpers.rb | 23 +- spec/support/pundit.rb | 1 + spec/support/schema_matcher.rb | 35 ++- spec/support/simplecov.rb | 2 + 148 files changed, 2506 insertions(+), 694 deletions(-) create mode 100644 app/assets/config/manifest.js delete mode 100644 app/controllers/api/mappings_controller.rb delete mode 100644 app/controllers/api/maps_controller.rb delete mode 100644 app/controllers/api/restful_controller.rb delete mode 100644 app/controllers/api/synapses_controller.rb delete mode 100644 app/controllers/api/tokens_controller.rb delete mode 100644 app/controllers/api/topics_controller.rb create mode 100644 app/controllers/api/v1/deprecated_controller.rb create mode 100644 app/controllers/api/v1/mappings_controller.rb create mode 100644 app/controllers/api/v1/maps_controller.rb create mode 100644 app/controllers/api/v1/synapses_controller.rb create mode 100644 app/controllers/api/v1/tokens_controller.rb create mode 100644 app/controllers/api/v1/topics_controller.rb create mode 100644 app/controllers/api/v2/mappings_controller.rb create mode 100644 app/controllers/api/v2/maps_controller.rb create mode 100644 app/controllers/api/v2/restful_controller.rb create mode 100644 app/controllers/api/v2/sessions_controller.rb create mode 100644 app/controllers/api/v2/synapses_controller.rb create mode 100644 app/controllers/api/v2/tokens_controller.rb create mode 100644 app/controllers/api/v2/topics_controller.rb create mode 100644 app/models/application_record.rb create mode 100644 app/serializers/api/v2/application_serializer.rb create mode 100644 app/serializers/api/v2/event_serializer.rb create mode 100644 app/serializers/api/v2/map_serializer.rb create mode 100644 app/serializers/api/v2/mapping_serializer.rb create mode 100644 app/serializers/api/v2/metacode_serializer.rb create mode 100644 app/serializers/api/v2/synapse_serializer.rb create mode 100644 app/serializers/api/v2/token_serializer.rb create mode 100644 app/serializers/api/v2/topic_serializer.rb create mode 100644 app/serializers/api/v2/user_serializer.rb create mode 100644 app/serializers/api/v2/webhook_serializer.rb delete mode 100644 app/serializers/event_serializer.rb delete mode 100644 app/serializers/new_map_serializer.rb delete mode 100644 app/serializers/new_mapping_serializer.rb delete mode 100644 app/serializers/new_metacode_serializer.rb delete mode 100644 app/serializers/new_synapse_serializer.rb delete mode 100644 app/serializers/new_topic_serializer.rb delete mode 100644 app/serializers/new_user_serializer.rb delete mode 100644 app/serializers/token_serializer.rb delete mode 100644 app/serializers/webhook_serializer.rb create mode 100644 config/cable.yml create mode 100644 config/initializers/active_model_serializers.rb create mode 100644 config/initializers/application_controller_renderer.rb create mode 100644 config/initializers/cookies_serializer.rb create mode 100644 config/initializers/filter_parameter_logging.rb create mode 100644 config/initializers/kaminari_config.rb create mode 100644 config/initializers/new_framework_defaults.rb create mode 100644 config/puma.rb create mode 100644 config/spring.rb create mode 100644 doc/api/api.raml create mode 100644 doc/api/apis/mappings.raml create mode 100644 doc/api/apis/maps.raml create mode 100644 doc/api/apis/synapses.raml create mode 100644 doc/api/apis/tokens.raml create mode 100644 doc/api/apis/topics.raml create mode 100644 doc/api/examples/map.json create mode 100644 doc/api/examples/mapping.json create mode 100644 doc/api/examples/mappings.json create mode 100644 doc/api/examples/maps.json create mode 100644 doc/api/examples/synapse.json create mode 100644 doc/api/examples/synapses.json create mode 100644 doc/api/examples/token.json create mode 100644 doc/api/examples/tokens.json create mode 100644 doc/api/examples/topic.json create mode 100644 doc/api/examples/topics.json create mode 100644 doc/api/resourceTypes/base.raml create mode 100644 doc/api/resourceTypes/collection.raml create mode 100644 doc/api/resourceTypes/item.raml create mode 100644 doc/api/schemas/_datetimestamp.json create mode 100644 doc/api/schemas/_id.json create mode 100644 doc/api/schemas/_map.json create mode 100644 doc/api/schemas/_mapping.json create mode 100644 doc/api/schemas/_page.json create mode 100644 doc/api/schemas/_permission.json create mode 100644 doc/api/schemas/_synapse.json create mode 100644 doc/api/schemas/_token.json create mode 100644 doc/api/schemas/_topic.json create mode 100644 doc/api/schemas/map.json create mode 100644 doc/api/schemas/mapping.json create mode 100644 doc/api/schemas/mappings.json create mode 100644 doc/api/schemas/maps.json create mode 100644 doc/api/schemas/synapse.json create mode 100644 doc/api/schemas/synapses.json create mode 100644 doc/api/schemas/token.json create mode 100644 doc/api/schemas/tokens.json create mode 100644 doc/api/schemas/topic.json create mode 100644 doc/api/schemas/topics.json create mode 100644 doc/api/traits/orderable.raml create mode 100644 doc/api/traits/pageable.raml create mode 100644 doc/api/traits/searchable.raml create mode 100644 spec/api/v2/mappings_api_spec.rb create mode 100644 spec/api/v2/maps_api_spec.rb create mode 100644 spec/api/v2/synapses_api_spec.rb create mode 100644 spec/api/v2/tokens_api_spec.rb create mode 100644 spec/api/v2/topics_api_spec.rb create mode 100644 spec/factories/tokens.rb delete mode 100644 spec/mailers/map_mailer_spec.rb create mode 100644 spec/support/pundit.rb create mode 100644 spec/support/simplecov.rb diff --git a/Gemfile b/Gemfile index 6be2271b..4c58772c 100644 --- a/Gemfile +++ b/Gemfile @@ -1,28 +1,27 @@ source 'https://rubygems.org' ruby '2.3.0' -gem 'rails' +gem 'rails', '~> 5.0.0' -gem 'active_model_serializers', '~> 0.8.1' +gem 'active_model_serializers' gem 'aws-sdk', '< 2.0' -gem 'best_in_place' # in-place editing -gem 'delayed_job', '~> 4.0.2' -gem 'delayed_job_active_record', '~> 4.0.1' +gem 'best_in_place' +gem 'delayed_job' +gem 'delayed_job_active_record' gem 'devise' -gem 'doorkeeper' +gem 'doorkeeper', '~> 4.0.0.rc4' gem 'dotenv-rails' gem 'exception_notification' gem 'formtastic' gem 'formula' gem 'httparty' gem 'json' -gem 'kaminari' # pagination -gem 'paperclip' +gem 'kaminari' +gem 'paperclip', '~> 4.3.6' gem 'pg' gem 'pundit' gem 'pundit_extra' gem 'rack-cors' -gem 'rails3-jquery-autocomplete' gem 'redis' gem 'slack-notifier' gem 'snorlax' @@ -31,12 +30,12 @@ gem 'uservoice-ruby' gem 'jquery-rails' gem 'jquery-ui-rails' gem 'jbuilder' +gem 'rails3-jquery-autocomplete' group :assets do gem 'coffee-rails' gem 'sass-rails' gem 'uglifier' - # gem 'therubyracer' end group :production do @@ -57,7 +56,6 @@ group :development, :test do gem 'binding_of_caller' gem 'pry-byebug' gem 'pry-rails' - gem 'quiet_assets' gem 'tunemygc' gem 'rubocop' end diff --git a/Gemfile.lock b/Gemfile.lock index c385bd81..c2fd0d28 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,45 +1,50 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) + actioncable (5.0.0) + actionpack (= 5.0.0) + nio4r (~> 1.2) + websocket-driver (~> 0.6.1) + actionmailer (5.0.0) + actionpack (= 5.0.0) + actionview (= 5.0.0) + activejob (= 5.0.0) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.6) - actionview (= 4.2.6) - activesupport (= 4.2.6) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) + rails-dom-testing (~> 2.0) + actionpack (5.0.0) + actionview (= 5.0.0) + activesupport (= 5.0.0) + rack (~> 2.0) + rack-test (~> 0.6.3) + rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.6) - activesupport (= 4.2.6) + actionview (5.0.0) + activesupport (= 5.0.0) builder (~> 3.1) erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) + rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - active_model_serializers (0.8.3) - activemodel (>= 3.0) - activejob (4.2.6) - activesupport (= 4.2.6) - globalid (>= 0.3.0) - activemodel (4.2.6) - activesupport (= 4.2.6) - builder (~> 3.1) - activerecord (4.2.6) - activemodel (= 4.2.6) - activesupport (= 4.2.6) - arel (~> 6.0) - activesupport (4.2.6) + active_model_serializers (0.10.1) + actionpack (>= 4.1, < 6) + activemodel (>= 4.1, < 6) + jsonapi (~> 0.1.1.beta2) + railties (>= 4.1, < 6) + activejob (5.0.0) + activesupport (= 5.0.0) + globalid (>= 0.3.6) + activemodel (5.0.0) + activesupport (= 5.0.0) + activerecord (5.0.0) + activemodel (= 5.0.0) + activesupport (= 5.0.0) + arel (~> 7.0) + activesupport (5.0.0) + concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) addressable (2.3.8) - arel (6.0.3) + arel (7.1.1) ast (2.3.0) aws-sdk (1.66.0) aws-sdk-v1 (= 1.66.0) @@ -56,7 +61,7 @@ GEM rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - brakeman (3.3.2) + brakeman (3.3.3) builder (3.2.2) byebug (9.0.5) climate_control (0.0.3) @@ -64,21 +69,21 @@ GEM cocaine (0.5.8) climate_control (>= 0.0.3, < 1.0) coderay (1.1.1) - coffee-rails (4.1.1) + coffee-rails (4.2.1) coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.1.x) + railties (>= 4.0.0, < 5.2.x) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.10.0) concurrent-ruby (1.0.2) debug_inspector (0.0.2) - delayed_job (4.0.6) - activesupport (>= 3.0, < 5.0) - delayed_job_active_record (4.0.3) - activerecord (>= 3.0, < 5.0) - delayed_job (>= 3.0, < 4.1) - devise (4.1.1) + delayed_job (4.1.2) + activesupport (>= 3.0, < 5.1) + delayed_job_active_record (4.1.1) + activerecord (>= 3.0, < 5.1) + delayed_job (>= 3.0, < 5) + devise (4.2.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0, < 5.1) @@ -86,16 +91,16 @@ GEM warden (~> 1.2.3) diff-lcs (1.2.5) docile (1.1.5) - doorkeeper (3.1.0) - railties (>= 3.2) + doorkeeper (4.0.0) + railties (>= 4.2) dotenv (2.1.1) dotenv-rails (2.1.1) dotenv (= 2.1.1) railties (>= 4.0, < 5.1) erubis (2.7.0) - exception_notification (4.1.4) - actionmailer (~> 4.0) - activesupport (~> 4.0) + exception_notification (4.2.1) + actionmailer (>= 4.0, < 6) + activesupport (>= 4.0, < 6) execjs (2.7.0) ezcrypto (0.7.2) factory_girl (4.7.0) @@ -107,13 +112,12 @@ GEM actionpack (>= 3.2.13) formula (1.1.1) rails (> 3.0.0) - globalid (0.3.6) + globalid (0.3.7) activesupport (>= 4.1.0) - httparty (0.13.7) - json (~> 1.8) + httparty (0.14.0) multi_xml (>= 0.5.2) i18n (0.7.0) - jbuilder (2.5.0) + jbuilder (2.6.0) activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) jquery-rails (4.1.1) @@ -125,6 +129,8 @@ GEM json (1.8.3) json-schema (2.6.2) addressable (~> 2.3.8) + jsonapi (0.1.1.beta2) + json (~> 1.8) kaminari (0.17.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -141,6 +147,7 @@ GEM minitest (5.9.0) multi_json (1.12.1) multi_xml (0.5.5) + nio4r (1.2.1) nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) @@ -157,7 +164,7 @@ GEM pg (0.18.4) pkg-config (1.1.7) powerpack (0.1.1) - pry (0.10.3) + pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) @@ -169,29 +176,25 @@ GEM pundit (1.1.0) activesupport (>= 3.0.0) pundit_extra (0.2.0) - quiet_assets (1.1.0) - railties (>= 3.1, < 5.0) - rack (1.6.4) + rack (2.0.1) rack-cors (0.4.0) rack-test (0.6.3) rack (>= 1.0) - rails (4.2.6) - actionmailer (= 4.2.6) - actionpack (= 4.2.6) - actionview (= 4.2.6) - activejob (= 4.2.6) - activemodel (= 4.2.6) - activerecord (= 4.2.6) - activesupport (= 4.2.6) + rails (5.0.0) + actioncable (= 5.0.0) + actionmailer (= 5.0.0) + actionpack (= 5.0.0) + actionview (= 5.0.0) + activejob (= 5.0.0) + activemodel (= 5.0.0) + activerecord (= 5.0.0) + activesupport (= 5.0.0) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.6) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.7) - activesupport (>= 4.2.0.beta, < 5.0) + railties (= 5.0.0) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.1) + activesupport (>= 4.2.0, < 6.0) nokogiri (~> 1.6.0) - rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) rails3-jquery-autocomplete (1.0.15) @@ -201,34 +204,35 @@ GEM rails_stdout_logging rails_serve_static_assets (0.0.5) rails_stdout_logging (0.0.5) - railties (4.2.6) - actionpack (= 4.2.6) - activesupport (= 4.2.6) + railties (5.0.0) + actionpack (= 5.0.0) + activesupport (= 5.0.0) + method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.1.0) rake (11.2.2) - redis (3.3.0) + redis (3.3.1) responders (2.2.0) railties (>= 4.2.0, < 5.1) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) + rspec-core (3.5.2) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-mocks (3.4.1) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-rails (3.4.2) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) - rubocop (0.41.1) + rspec-support (~> 3.5.0) + rspec-rails (3.5.1) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + rubocop (0.42.0) parser (>= 2.3.1.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) @@ -236,8 +240,8 @@ GEM unicode-display_width (~> 1.0, >= 1.0.1) ruby-progressbar (1.8.1) sass (3.4.22) - sass-rails (5.0.4) - railties (>= 4.0.0, < 5.0) + sass-rails (5.0.5) + railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) @@ -253,20 +257,20 @@ GEM slop (3.6.0) snorlax (0.1.6) rails (> 4.1) - sprockets (3.6.0) + sprockets (3.6.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.0.4) + sprockets-rails (3.1.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) thor (0.19.1) thread_safe (0.3.5) tilt (2.0.5) - tunemygc (1.0.65) + tunemygc (1.0.68) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.0) + uglifier (3.0.1) execjs (>= 0.3.0, < 3) unicode-display_width (1.1.0) uservoice-ruby (0.0.11) @@ -275,22 +279,25 @@ GEM oauth (>= 0.4.7) warden (1.2.6) rack (>= 1.0) + websocket-driver (0.6.4) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.2) PLATFORMS ruby DEPENDENCIES - active_model_serializers (~> 0.8.1) + active_model_serializers aws-sdk (< 2.0) best_in_place better_errors binding_of_caller brakeman coffee-rails - delayed_job (~> 4.0.2) - delayed_job_active_record (~> 4.0.1) + delayed_job + delayed_job_active_record devise - doorkeeper + doorkeeper (~> 4.0.0.rc4) dotenv-rails exception_notification factory_girl_rails @@ -303,15 +310,14 @@ DEPENDENCIES json json-schema kaminari - paperclip + paperclip (~> 4.3.6) pg pry-byebug pry-rails pundit pundit_extra - quiet_assets rack-cors - rails + rails (~> 5.0.0) rails3-jquery-autocomplete rails_12factor redis @@ -326,5 +332,8 @@ DEPENDENCIES uglifier uservoice-ruby +RUBY VERSION + ruby 2.3.0p0 + BUNDLED WITH - 1.11.2 + 1.12.5 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 00000000..72a7189c --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,6 @@ +// JS and CSS bundles +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css + +// Other +//= link_tree ../images diff --git a/app/controllers/api/mappings_controller.rb b/app/controllers/api/mappings_controller.rb deleted file mode 100644 index 15fde6bc..00000000 --- a/app/controllers/api/mappings_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Api::MappingsController < API::RestfulController -end diff --git a/app/controllers/api/maps_controller.rb b/app/controllers/api/maps_controller.rb deleted file mode 100644 index bb2d553d..00000000 --- a/app/controllers/api/maps_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Api::MapsController < API::RestfulController -end diff --git a/app/controllers/api/restful_controller.rb b/app/controllers/api/restful_controller.rb deleted file mode 100644 index 5b6c41da..00000000 --- a/app/controllers/api/restful_controller.rb +++ /dev/null @@ -1,50 +0,0 @@ -class API::RestfulController < ActionController::Base - include Pundit - include PunditExtra - - snorlax_used_rest! - - load_and_authorize_resource only: [:show, :update, :destroy] - - def create - instantiate_resource - resource.user = current_user - authorize resource - create_action - respond_with_resource - end - - private - - def resource_serializer - "new_#{resource_name}_serializer".camelize.constantize - end - - def accessible_records - if current_user - visible_records - else - public_records - end - end - - def current_user - super || token_user || doorkeeper_user || nil - end - - def token_user - token = params[:access_token] - access_token = Token.find_by_token(token) - @token_user ||= access_token.user if access_token - end - - def doorkeeper_user - return unless doorkeeper_token.present? - doorkeeper_render_error unless valid_doorkeeper_token? - @doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id) - end - - def permitted_params - @permitted_params ||= PermittedParams.new(params) - end -end diff --git a/app/controllers/api/synapses_controller.rb b/app/controllers/api/synapses_controller.rb deleted file mode 100644 index 47cb6056..00000000 --- a/app/controllers/api/synapses_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Api::SynapsesController < API::RestfulController -end diff --git a/app/controllers/api/tokens_controller.rb b/app/controllers/api/tokens_controller.rb deleted file mode 100644 index cea6ac5f..00000000 --- a/app/controllers/api/tokens_controller.rb +++ /dev/null @@ -1,17 +0,0 @@ -class Api::TokensController < API::RestfulController - def my_tokens - raise Pundit::NotAuthorizedError unless current_user - instantiate_collection page_collection: false, timeframe_collection: false - respond_with_collection - end - - private - - def resource_serializer - "#{resource_name}_serializer".camelize.constantize - end - - def visible_records - current_user.tokens - end -end diff --git a/app/controllers/api/topics_controller.rb b/app/controllers/api/topics_controller.rb deleted file mode 100644 index 4ccc619c..00000000 --- a/app/controllers/api/topics_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Api::TopicsController < API::RestfulController -end diff --git a/app/controllers/api/v1/deprecated_controller.rb b/app/controllers/api/v1/deprecated_controller.rb new file mode 100644 index 00000000..ed68b897 --- /dev/null +++ b/app/controllers/api/v1/deprecated_controller.rb @@ -0,0 +1,9 @@ +module Api + module V1 + class DeprecatedController < ApplicationController + def method_missing + render json: { error: "/api/v1 is deprecated! Please use /api/v2 instead." } + end + end + end +end diff --git a/app/controllers/api/v1/mappings_controller.rb b/app/controllers/api/v1/mappings_controller.rb new file mode 100644 index 00000000..35c7d6bd --- /dev/null +++ b/app/controllers/api/v1/mappings_controller.rb @@ -0,0 +1,6 @@ +module Api + module V1 + class MappingsController < DeprecatedController + end + end +end diff --git a/app/controllers/api/v1/maps_controller.rb b/app/controllers/api/v1/maps_controller.rb new file mode 100644 index 00000000..056810f1 --- /dev/null +++ b/app/controllers/api/v1/maps_controller.rb @@ -0,0 +1,6 @@ +module Api + module V1 + class MapsController < DeprecatedController + end + end +end diff --git a/app/controllers/api/v1/synapses_controller.rb b/app/controllers/api/v1/synapses_controller.rb new file mode 100644 index 00000000..e2111e95 --- /dev/null +++ b/app/controllers/api/v1/synapses_controller.rb @@ -0,0 +1,6 @@ +module Api + module V1 + class SynapsesController < DeprecatedController + end + end +end diff --git a/app/controllers/api/v1/tokens_controller.rb b/app/controllers/api/v1/tokens_controller.rb new file mode 100644 index 00000000..c96b1065 --- /dev/null +++ b/app/controllers/api/v1/tokens_controller.rb @@ -0,0 +1,6 @@ +module Api + module V1 + class TokensController < DeprecatedController + end + end +end diff --git a/app/controllers/api/v1/topics_controller.rb b/app/controllers/api/v1/topics_controller.rb new file mode 100644 index 00000000..e974fff3 --- /dev/null +++ b/app/controllers/api/v1/topics_controller.rb @@ -0,0 +1,6 @@ +module Api + module V1 + class TopicsController < DeprecatedController + end + end +end diff --git a/app/controllers/api/v2/mappings_controller.rb b/app/controllers/api/v2/mappings_controller.rb new file mode 100644 index 00000000..7f0d9513 --- /dev/null +++ b/app/controllers/api/v2/mappings_controller.rb @@ -0,0 +1,6 @@ +module Api + module V2 + class MappingsController < RestfulController + end + end +end diff --git a/app/controllers/api/v2/maps_controller.rb b/app/controllers/api/v2/maps_controller.rb new file mode 100644 index 00000000..fd54fa7b --- /dev/null +++ b/app/controllers/api/v2/maps_controller.rb @@ -0,0 +1,9 @@ +module Api + module V2 + class MapsController < RestfulController + def searchable_columns + [:name, :desc] + end + end + end +end diff --git a/app/controllers/api/v2/restful_controller.rb b/app/controllers/api/v2/restful_controller.rb new file mode 100644 index 00000000..e73f21b8 --- /dev/null +++ b/app/controllers/api/v2/restful_controller.rb @@ -0,0 +1,179 @@ +module Api + module V2 + class RestfulController < ActionController::Base + include Pundit + include PunditExtra + + snorlax_used_rest! + + before_action :load_resource, only: [:show, :update, :destroy] + after_action :verify_authorized + + def index + authorize resource_class + instantiate_collection + respond_with_collection + end + + def create + instantiate_resource + resource.user = current_user if current_user.present? + authorize resource + create_action + respond_with_resource + end + + def destroy + destroy_action + head :no_content + end + + private + + def accessible_records + if current_user + visible_records + else + public_records + end + end + + def current_user + super || token_user || doorkeeper_user || nil + end + + def load_resource + super + authorize resource + end + + def resource_serializer + "Api::V2::#{resource_name.camelize}Serializer".constantize + end + + def respond_with_resource(scope: default_scope, serializer: resource_serializer, root: serializer_root) + if resource.errors.empty? + render json: resource, scope: scope, serializer: serializer, root: root + else + respond_with_errors + end + end + + def respond_with_collection(resources: collection, scope: default_scope, serializer: resource_serializer, root: serializer_root) + render json: resources, scope: scope, each_serializer: serializer, root: root, meta: pagination(resources), meta_key: :page + end + + def default_scope + { + embeds: embeds + } + end + + def embeds + (params[:embed] || '').split(',').map(&:to_sym) + end + + def token_user + token = params[:access_token] + access_token = Token.find_by_token(token) + @token_user ||= access_token.user if access_token + end + + def doorkeeper_user + return unless doorkeeper_token.present? + doorkeeper_render_error unless valid_doorkeeper_token? + @doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id) + end + + def permitted_params + @permitted_params ||= PermittedParams.new(params) + end + + def serializer_root + 'data' + end + + def pagination(collection) + per = (params[:per] || 25).to_i + current_page = (params[:page] || 1).to_i + total_pages = (collection.total_count.to_f / per).ceil + prev_page = current_page > 1 ? current_page - 1 : 0 + next_page = current_page < total_pages ? current_page + 1 : 0 + + base_url = request.base_url + request.path + nxt = request.query_parameters.merge(page: next_page).map{|x| x.join('=')}.join('&') + prev = request.query_parameters.merge(page: prev_page).map{|x| x.join('=')}.join('&') + last = request.query_parameters.merge(page: total_pages).map{|x| x.join('=')}.join('&') + response.headers['Link'] = [ + %(<#{base_url}?#{nxt}>; rel="next"), + %(<#{base_url}?#{prev}>; rel="prev"), + %(<#{base_url}?#{last}>; rel="last") + ].join(',') + response.headers['X-Total-Pages'] = collection.total_pages.to_s + response.headers['X-Total-Count'] = collection.total_count.to_s + response.headers['X-Per-Page'] = per.to_s + + { + current_page: current_page, + next_page: next_page, + prev_page: prev_page, + total_pages: total_pages, + total_count: collection.total_count, + per: per + } + end + + def instantiate_collection + collection = accessible_records + collection = yield collection if block_given? + collection = search_by_q(collection) if params[:q] + collection = order_by_sort(collection) if params[:sort] + collection = collection.page(params[:page]).per(params[:per]) + self.collection = collection + end + + # override this method to explicitly set searchable columns + def searchable_columns + columns = resource_class.columns.select do |column| + column.type == :text || column.type == :string + end + columns.map(&:name) + end + + # thanks to http://stackoverflow.com/questions/4430578 + def search_by_q(collection) + table = resource_class.arel_table + safe_query = "%#{params[:q].gsub(/[%_]/, '\\\\\0')}%" + search_column = -> (column) { table[column].matches(safe_query) } + + condition = searchable_columns.reduce(nil) do |prev, column| + next search_column.(column) if prev.nil? + search_column.(column).or(prev) + end + puts collection.where(condition).to_sql + collection.where(condition) + end + + def order_by_sort(collection) + builder = collection + sorts = params[:sort].split(',') + sorts.each do |sort| + direction = sort.starts_with?('-') ? 'desc' : 'asc' + sort = sort.sub(/^-/, '') + if resource_class.columns.map(&:name).include?(sort) + builder = builder.order(sort => direction) + end + end + return builder + end + + def visible_records + policy_scope(resource_class) + end + + def public_records + policy_scope(resource_class) + end + end + end +end diff --git a/app/controllers/api/v2/sessions_controller.rb b/app/controllers/api/v2/sessions_controller.rb new file mode 100644 index 00000000..3aefa214 --- /dev/null +++ b/app/controllers/api/v2/sessions_controller.rb @@ -0,0 +1,20 @@ +module Api + module V2 + class SessionsController < ApplicationController + def create + @user = User.find_by(email: params[:email]) + if @user && @user.valid_password(params[:password]) + sign_in(@user) + render json: @user + else + render json: { error: 'Error' } + end + end + + def destroy + sign_out + head :no_content + end + end + end +end diff --git a/app/controllers/api/v2/synapses_controller.rb b/app/controllers/api/v2/synapses_controller.rb new file mode 100644 index 00000000..6572997d --- /dev/null +++ b/app/controllers/api/v2/synapses_controller.rb @@ -0,0 +1,9 @@ +module Api + module V2 + class SynapsesController < RestfulController + def searchable_columns + [:desc] + end + end + end +end diff --git a/app/controllers/api/v2/tokens_controller.rb b/app/controllers/api/v2/tokens_controller.rb new file mode 100644 index 00000000..6eeb102b --- /dev/null +++ b/app/controllers/api/v2/tokens_controller.rb @@ -0,0 +1,11 @@ +module Api + module V2 + class TokensController < RestfulController + def my_tokens + authorize resource_class + instantiate_collection + respond_with_collection + end + end + end +end diff --git a/app/controllers/api/v2/topics_controller.rb b/app/controllers/api/v2/topics_controller.rb new file mode 100644 index 00000000..74fa7105 --- /dev/null +++ b/app/controllers/api/v2/topics_controller.rb @@ -0,0 +1,6 @@ +module Api + module V2 + class TopicsController < RestfulController + end + end +end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 1164d42e..01304328 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -163,8 +163,8 @@ class MainController < ApplicationController @synapses = [] end - # limit to 5 results - @synapses = @synapses.slice(0, 5) + #limit to 5 results + @synapses = @synapses.to_a.slice(0,5) render json: autocomplete_synapse_array_json(@synapses) end diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb index ee3e6549..7c4a74a7 100644 --- a/app/controllers/maps_controller.rb +++ b/app/controllers/maps_controller.rb @@ -1,6 +1,6 @@ class MapsController < ApplicationController before_action :require_user, only: [:create, :update, :access, :star, :unstar, :screenshot, :events, :destroy] - after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps, :events] + after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps] after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps] respond_to :html, :json, :csv diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index efd6b42d..8895cfd2 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -15,11 +15,10 @@ class Users::RegistrationsController < Devise::RegistrationsController private def configure_sign_up_params - devise_parameter_sanitizer.for(:sign_up) << [:name, :joinedwithcode] + devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :joinedwithcode]) end def configure_account_update_params - puts devise_parameter_sanitizer_for(:account_update) - devise_parameter_sanitizer.for(:account_update) << [:image] + devise_parameter_sanitizer.permit(:account_update, keys: [:image]) end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 00000000..10a4cba8 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/event.rb b/app/models/event.rb index 67606aa2..90407314 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,4 +1,4 @@ -class Event < ActiveRecord::Base +class Event < ApplicationRecord KINDS = %w(user_present_on_map conversation_started_on_map topic_added_to_map synapse_added_to_map).freeze # has_many :notifications, dependent: :destroy diff --git a/app/models/in_metacode_set.rb b/app/models/in_metacode_set.rb index c1b1ca33..de1f2514 100644 --- a/app/models/in_metacode_set.rb +++ b/app/models/in_metacode_set.rb @@ -1,4 +1,4 @@ -class InMetacodeSet < ActiveRecord::Base +class InMetacodeSet < ApplicationRecord belongs_to :metacode, class_name: 'Metacode', foreign_key: 'metacode_id' belongs_to :metacode_set, class_name: 'MetacodeSet', foreign_key: 'metacode_set_id' end diff --git a/app/models/map.rb b/app/models/map.rb index bf5757d3..f59eb790 100644 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -1,4 +1,4 @@ -class Map < ActiveRecord::Base +class Map < ApplicationRecord belongs_to :user has_many :topicmappings, -> { Mapping.topicmapping }, class_name: :Mapping, dependent: :destroy diff --git a/app/models/mapping.rb b/app/models/mapping.rb index ceb15538..eba7a6d2 100644 --- a/app/models/mapping.rb +++ b/app/models/mapping.rb @@ -1,4 +1,4 @@ -class Mapping < ActiveRecord::Base +class Mapping < ApplicationRecord scope :topicmapping, -> { where(mappable_type: :Topic) } scope :synapsemapping, -> { where(mappable_type: :Synapse) } diff --git a/app/models/message.rb b/app/models/message.rb index 597caeb7..348c5d4e 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -1,4 +1,4 @@ -class Message < ActiveRecord::Base +class Message < ApplicationRecord belongs_to :user belongs_to :resource, polymorphic: true diff --git a/app/models/metacode.rb b/app/models/metacode.rb index bc0bef7b..9b05bee5 100644 --- a/app/models/metacode.rb +++ b/app/models/metacode.rb @@ -1,4 +1,4 @@ -class Metacode < ActiveRecord::Base +class Metacode < ApplicationRecord has_many :in_metacode_sets has_many :metacode_sets, through: :in_metacode_sets has_many :topics diff --git a/app/models/metacode_set.rb b/app/models/metacode_set.rb index cc672784..c52811fd 100644 --- a/app/models/metacode_set.rb +++ b/app/models/metacode_set.rb @@ -1,4 +1,4 @@ -class MetacodeSet < ActiveRecord::Base +class MetacodeSet < ApplicationRecord belongs_to :user has_many :in_metacode_sets has_many :metacodes, through: :in_metacode_sets diff --git a/app/models/synapse.rb b/app/models/synapse.rb index 710cb029..afd40a25 100644 --- a/app/models/synapse.rb +++ b/app/models/synapse.rb @@ -1,4 +1,4 @@ -class Synapse < ActiveRecord::Base +class Synapse < ApplicationRecord belongs_to :user belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id' diff --git a/app/models/token.rb b/app/models/token.rb index 1dac3fde..9103aebc 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -1,4 +1,4 @@ -class Token < ActiveRecord::Base +class Token < ApplicationRecord belongs_to :user before_create :assign_token diff --git a/app/models/topic.rb b/app/models/topic.rb index a91c75fc..c250338b 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1,4 +1,4 @@ -class Topic < ActiveRecord::Base +class Topic < ApplicationRecord include TopicsHelper belongs_to :user diff --git a/app/models/user.rb b/app/models/user.rb index 1f091499..876e10cd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,6 @@ require 'open-uri' -class User < ActiveRecord::Base +class User < ApplicationRecord has_many :topics has_many :synapses has_many :maps @@ -80,7 +80,7 @@ class User < ActiveRecord::Base end def starred_map?(map) - return !!self.stars.index{|s| s.map_id == map.id } + return self.stars.where(map_id: map.id).exists? end def settings diff --git a/app/models/user_map.rb b/app/models/user_map.rb index 5e91ecc2..c48cfb96 100644 --- a/app/models/user_map.rb +++ b/app/models/user_map.rb @@ -1,4 +1,4 @@ -class UserMap < ActiveRecord::Base +class UserMap < ApplicationRecord belongs_to :map belongs_to :user end diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index a87dc679..3aadbdb3 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -4,8 +4,14 @@ class UserPreference def initialize array = [] %w(Action Aim Idea Question Note Wildcard Subject).each do |m| - metacode = Metacode.find_by_name(m) - array.push(metacode.id.to_s) if metacode + begin + metacode = Metacode.find_by_name(m) + array.push(metacode.id.to_s) if metacode + rescue ActiveRecord::StatementInvalid + if m == 'Action' + Rails.logger.warn("TODO: remove this travis workaround in user_preference.rb") + end + end end @metacodes = array end diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 86d2333d..6389398e 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -1,4 +1,4 @@ -class Webhook < ActiveRecord::Base +class Webhook < ApplicationRecord belongs_to :hookable, polymorphic: true validates :uri, presence: true diff --git a/app/policies/map_policy.rb b/app/policies/map_policy.rb index bf511869..0a2b33ce 100644 --- a/app/policies/map_policy.rb +++ b/app/policies/map_policy.rb @@ -12,19 +12,7 @@ class MapPolicy < ApplicationPolicy end end - def activemaps? - user.blank? # redirect to root url if authenticated for some reason - end - - def featuredmaps? - true - end - - def mymaps? - user.present? - end - - def usermaps? + def index? true end @@ -32,18 +20,6 @@ class MapPolicy < ApplicationPolicy record.permission == 'commons' || record.permission == 'public' || record.collaborators.include?(user) || record.user == user end - def export? - show? - end - - def events? - show? - end - - def contains? - show? - end - def create? user.present? end @@ -52,11 +28,39 @@ class MapPolicy < ApplicationPolicy user.present? && (record.permission == 'commons' || record.collaborators.include?(user) || record.user == user) end + def destroy? + record.user == user || admin_override + end + def access? # note that this is to edit access user.present? && record.user == user end + def activemaps? + user.blank? # redirect to root url if authenticated for some reason + end + + def contains? + show? + end + + def events? + show? + end + + def export? + show? + end + + def featuredmaps? + true + end + + def mymaps? + user.present? + end + def star? unstar? end @@ -69,7 +73,7 @@ class MapPolicy < ApplicationPolicy update? end - def destroy? - record.user == user || admin_override + def usermaps? + true end end diff --git a/app/policies/mapping_policy.rb b/app/policies/mapping_policy.rb index 07b6d0c5..1cd99783 100644 --- a/app/policies/mapping_policy.rb +++ b/app/policies/mapping_policy.rb @@ -8,13 +8,17 @@ class MappingPolicy < ApplicationPolicy visible = %w(public commons) permission = 'maps.permission IN (?)' if user - scope.joins(:maps).where(permission + ' OR maps.user_id = ?', visible, user.id) + scope.joins(:map).where(permission, visible).or(scope.joins(:map).where(user_id: user.id)) else - scope.where(permission, visible) + scope.joins(:map).where(permission, visible) end end end + def index? + true + end + def show? map_policy.show? && mappable_policy.try(:show?) end diff --git a/app/policies/synapse_policy.rb b/app/policies/synapse_policy.rb index 97d993f5..310b3947 100644 --- a/app/policies/synapse_policy.rb +++ b/app/policies/synapse_policy.rb @@ -11,6 +11,10 @@ class SynapsePolicy < ApplicationPolicy end end + def index? + true # really only for the API. should be policy scoped! + end + def create? user.present? # TODO: add validation against whether you can see both topics diff --git a/app/policies/topic_policy.rb b/app/policies/topic_policy.rb index a8d5df2a..7bca6770 100644 --- a/app/policies/topic_policy.rb +++ b/app/policies/topic_policy.rb @@ -11,6 +11,10 @@ class TopicPolicy < ApplicationPolicy end end + def index? + user.present? + end + def create? user.present? end diff --git a/app/serializers/api/v2/application_serializer.rb b/app/serializers/api/v2/application_serializer.rb new file mode 100644 index 00000000..f943646c --- /dev/null +++ b/app/serializers/api/v2/application_serializer.rb @@ -0,0 +1,29 @@ +module Api + module V2 + class ApplicationSerializer < ActiveModel::Serializer + def self.embeddable + {} + end + + def embeds + @embeds ||= (scope[:embeds] || []).select { |e| self.class.embeddable.keys.include?(e) } + end + + def self.embed_dat + embeddable.each_pair do |key, opts| + attr = opts.delete(:attr) || key + if attr.to_s.pluralize == attr.to_s + attribute "#{attr.to_s.singularize}_ids".to_sym, opts.merge(unless: -> { embeds.include?(key) }) do + object.send(attr).map(&:id) + end + has_many attr, opts.merge(if: -> { embeds.include?(key) }) + else + id_opts = opts.merge(key: "#{key}_id") + attribute "#{attr}_id".to_sym, id_opts.merge(unless: -> { embeds.include?(key) }) + attribute key, opts.merge(if: -> { embeds.include?(key) }) + end + end + end + end + end +end diff --git a/app/serializers/api/v2/event_serializer.rb b/app/serializers/api/v2/event_serializer.rb new file mode 100644 index 00000000..644598cf --- /dev/null +++ b/app/serializers/api/v2/event_serializer.rb @@ -0,0 +1,18 @@ +module Api + module V2 + class EventSerializer < ApplicationSerializer + attributes :id, :sequence_id, :kind, :map_id, :created_at + + has_one :actor, serializer: UserSerializer, root: 'users' + has_one :map, serializer: MapSerializer + + def actor + object.user || object.eventable.try(:user) + end + + def map + object.eventable.try(:map) || object.eventable.map + end + end + end +end diff --git a/app/serializers/api/v2/map_serializer.rb b/app/serializers/api/v2/map_serializer.rb new file mode 100644 index 00000000..438f97ee --- /dev/null +++ b/app/serializers/api/v2/map_serializer.rb @@ -0,0 +1,28 @@ +module Api + module V2 + class MapSerializer < ApplicationSerializer + attributes :id, + :name, + :desc, + :permission, + :screenshot, + :created_at, + :updated_at + + def self.embeddable + { + user: {}, + topics: {}, + synapses: {}, + mappings: {}, + contributors: { serializer: UserSerializer }, + collaborators: { serializer: UserSerializer } + } + end + + self.class_eval do + embed_dat + end + end + end +end diff --git a/app/serializers/api/v2/mapping_serializer.rb b/app/serializers/api/v2/mapping_serializer.rb new file mode 100644 index 00000000..dc36421e --- /dev/null +++ b/app/serializers/api/v2/mapping_serializer.rb @@ -0,0 +1,25 @@ +module Api + module V2 + class MappingSerializer < ApplicationSerializer + attributes :id, + :created_at, + :updated_at, + :mappable_id, + :mappable_type + + attribute :xloc, if: -> { object.mappable_type == 'Topic' } + attribute :yloc, if: -> { object.mappable_type == 'Topic' } + + def self.embeddable + { + user: {}, + map: {} + } + end + + self.class_eval do + embed_dat + end + end + end +end diff --git a/app/serializers/api/v2/metacode_serializer.rb b/app/serializers/api/v2/metacode_serializer.rb new file mode 100644 index 00000000..4f4daa35 --- /dev/null +++ b/app/serializers/api/v2/metacode_serializer.rb @@ -0,0 +1,11 @@ +module Api + module V2 + class MetacodeSerializer < ApplicationSerializer + attributes :id, + :name, + :manual_icon, + :color, + :aws_icon + end + end +end diff --git a/app/serializers/api/v2/synapse_serializer.rb b/app/serializers/api/v2/synapse_serializer.rb new file mode 100644 index 00000000..9ef86660 --- /dev/null +++ b/app/serializers/api/v2/synapse_serializer.rb @@ -0,0 +1,24 @@ +module Api + module V2 + class SynapseSerializer < ApplicationSerializer + attributes :id, + :desc, + :category, + :permission, + :created_at, + :updated_at + + def self.embeddable + { + topic1: { attr: :node1, serializer: TopicSerializer }, + topic2: { attr: :node2, serializer: TopicSerializer }, + user: {} + } + end + + self.class_eval do + embed_dat + end + end + end +end diff --git a/app/serializers/api/v2/token_serializer.rb b/app/serializers/api/v2/token_serializer.rb new file mode 100644 index 00000000..18d15d15 --- /dev/null +++ b/app/serializers/api/v2/token_serializer.rb @@ -0,0 +1,10 @@ +module Api + module V2 + class TokenSerializer < ApplicationSerializer + attributes :id, + :token, + :description, + :created_at + end + end +end diff --git a/app/serializers/api/v2/topic_serializer.rb b/app/serializers/api/v2/topic_serializer.rb new file mode 100644 index 00000000..48d1d6de --- /dev/null +++ b/app/serializers/api/v2/topic_serializer.rb @@ -0,0 +1,24 @@ +module Api + module V2 + class TopicSerializer < ApplicationSerializer + attributes :id, + :name, + :desc, + :link, + :permission, + :created_at, + :updated_at + + def self.embeddable + { + user: {}, + metacode: {} + } + end + + self.class_eval do + embed_dat + end + end + end +end diff --git a/app/serializers/api/v2/user_serializer.rb b/app/serializers/api/v2/user_serializer.rb new file mode 100644 index 00000000..fdfffae0 --- /dev/null +++ b/app/serializers/api/v2/user_serializer.rb @@ -0,0 +1,19 @@ +module Api + module V2 + class UserSerializer < ApplicationSerializer + attributes :id, + :name, + :avatar, + :is_admin, + :generation + + def avatar + object.image.url(:sixtyfour) + end + + def is_admin + object.admin + end + end + end +end diff --git a/app/serializers/api/v2/webhook_serializer.rb b/app/serializers/api/v2/webhook_serializer.rb new file mode 100644 index 00000000..59d60283 --- /dev/null +++ b/app/serializers/api/v2/webhook_serializer.rb @@ -0,0 +1,7 @@ +module Api + module V2 + class WebhookSerializer < ApplicationSerializer + attributes :text, :username, :icon_url # , :attachments + end + end +end diff --git a/app/serializers/event_serializer.rb b/app/serializers/event_serializer.rb deleted file mode 100644 index 0e87cd44..00000000 --- a/app/serializers/event_serializer.rb +++ /dev/null @@ -1,15 +0,0 @@ -class EventSerializer < ActiveModel::Serializer - embed :ids, include: true - attributes :id, :sequence_id, :kind, :map_id, :created_at - - has_one :actor, serializer: NewUserSerializer, root: 'users' - has_one :map, serializer: NewMapSerializer - - def actor - object.user || object.eventable.try(:user) - end - - def map - object.eventable.try(:map) || object.eventable.map - end -end diff --git a/app/serializers/new_map_serializer.rb b/app/serializers/new_map_serializer.rb deleted file mode 100644 index c323b09d..00000000 --- a/app/serializers/new_map_serializer.rb +++ /dev/null @@ -1,16 +0,0 @@ -class NewMapSerializer < ActiveModel::Serializer - embed :ids, include: true - attributes :id, - :name, - :desc, - :permission, - :screenshot, - :created_at, - :updated_at - - has_many :topics, serializer: NewTopicSerializer - has_many :synapses, serializer: NewSynapseSerializer - has_many :mappings, serializer: NewMappingSerializer - has_many :contributors, root: :users, serializer: NewUserSerializer - has_many :collaborators, root: :users, serializer: NewUserSerializer -end diff --git a/app/serializers/new_mapping_serializer.rb b/app/serializers/new_mapping_serializer.rb deleted file mode 100644 index 3ef9a8b6..00000000 --- a/app/serializers/new_mapping_serializer.rb +++ /dev/null @@ -1,19 +0,0 @@ -class NewMappingSerializer < ActiveModel::Serializer - embed :ids, include: true - attributes :id, - :xloc, - :yloc, - :created_at, - :updated_at, - :mappable_id, - :mappable_type - - has_one :user, serializer: NewUserSerializer - has_one :map, serializer: NewMapSerializer - - def filter(keys) - keys.delete(:xloc) unless object.mappable_type == 'Topic' - keys.delete(:yloc) unless object.mappable_type == 'Topic' - keys - end -end diff --git a/app/serializers/new_metacode_serializer.rb b/app/serializers/new_metacode_serializer.rb deleted file mode 100644 index b20f25b6..00000000 --- a/app/serializers/new_metacode_serializer.rb +++ /dev/null @@ -1,7 +0,0 @@ -class NewMetacodeSerializer < ActiveModel::Serializer - attributes :id, - :name, - :manual_icon, - :color, - :aws_icon -end diff --git a/app/serializers/new_synapse_serializer.rb b/app/serializers/new_synapse_serializer.rb deleted file mode 100644 index 5cdf644d..00000000 --- a/app/serializers/new_synapse_serializer.rb +++ /dev/null @@ -1,14 +0,0 @@ -class NewSynapseSerializer < ActiveModel::Serializer - embed :ids, include: true - attributes :id, - :desc, - :category, - :weight, - :permission, - :created_at, - :updated_at - - has_one :topic1, root: :topics, serializer: NewTopicSerializer - has_one :topic2, root: :topics, serializer: NewTopicSerializer - has_one :user, serializer: NewUserSerializer -end diff --git a/app/serializers/new_topic_serializer.rb b/app/serializers/new_topic_serializer.rb deleted file mode 100644 index 2eb718df..00000000 --- a/app/serializers/new_topic_serializer.rb +++ /dev/null @@ -1,13 +0,0 @@ -class NewTopicSerializer < ActiveModel::Serializer - embed :ids, include: true - attributes :id, - :name, - :desc, - :link, - :permission, - :created_at, - :updated_at - - has_one :user, serializer: NewUserSerializer - has_one :metacode, serializer: NewMetacodeSerializer -end diff --git a/app/serializers/new_user_serializer.rb b/app/serializers/new_user_serializer.rb deleted file mode 100644 index 62796f31..00000000 --- a/app/serializers/new_user_serializer.rb +++ /dev/null @@ -1,15 +0,0 @@ -class NewUserSerializer < ActiveModel::Serializer - attributes :id, - :name, - :avatar, - :is_admin, - :generation - - def avatar - object.image.url(:sixtyfour) - end - - def is_admin - object.admin - end -end diff --git a/app/serializers/token_serializer.rb b/app/serializers/token_serializer.rb deleted file mode 100644 index 4d593c0e..00000000 --- a/app/serializers/token_serializer.rb +++ /dev/null @@ -1,7 +0,0 @@ -class TokenSerializer < ActiveModel::Serializer - attributes :id, - :token, - :description, - :created_at, - :updated_at -end diff --git a/app/serializers/webhook_serializer.rb b/app/serializers/webhook_serializer.rb deleted file mode 100644 index 8108c86c..00000000 --- a/app/serializers/webhook_serializer.rb +++ /dev/null @@ -1,3 +0,0 @@ -class WebhookSerializer < ActiveModel::Serializer - attributes :text, :username, :icon_url # , :attachments -end diff --git a/config/application.rb b/config/application.rb index afebfd6d..b80306c5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,4 +1,4 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' require 'csv' require 'rails/all' @@ -15,21 +15,6 @@ module Metamaps # Custom directories with classes and modules you want to be autoloadable. config.autoload_paths << Rails.root.join('app', 'services') - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named. - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Activate observers that should always be running. - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - # config.time_zone = 'Central Time (US & Canada)' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de - # Configure the default encoding used in templates for Ruby 1.9. config.encoding = 'utf-8' @@ -43,11 +28,6 @@ module Metamaps # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] - # Use SQL instead of Active Record's schema dumper when creating the database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - # Enable the asset pipeline config.assets.initialize_on_precompile = false @@ -57,7 +37,6 @@ module Metamaps config.generators do |g| g.test_framework :rspec end - config.active_record.raise_in_transactional_callbacks = true # pundit errors return 403 FORBIDDEN config.action_dispatch.rescue_responses['Pundit::NotAuthorizedError'] = :forbidden diff --git a/config/boot.rb b/config/boot.rb index 4add3ee3..e49b6649 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,5 +1,6 @@ require 'rubygems' require 'rails/commands/server' + module Rails class Server def default_options @@ -9,6 +10,6 @@ module Rails end # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 00000000..0bbde6f7 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,9 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 diff --git a/config/environment.rb b/config/environment.rb index 6e9ad9e4..426333bb 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ -# Load the rails application -require File.expand_path('../application', __FILE__) +# Load the Rails application. +require_relative 'application' -# Initialize the rails application -Metamaps::Application.initialize! +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/production.rb b/config/environments/production.rb index 5ad26ad3..24ceed21 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,9 +1,8 @@ -Metamaps::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb config.log_level = :warn config.eager_load = true - config.assets.js_compressor = :uglifier # Code is not reloaded between requests config.cache_classes = true @@ -13,12 +12,12 @@ Metamaps::Application.configure do config.action_controller.perform_caching = true # Disable Rails's static asset server (Apache or nginx will already do this) - config.serve_static_files = true + config.public_file_server.enabled = false + # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false - # Compress JavaScripts and CSS - config.assets.compress = true + config.assets.js_compressor = :uglifier # S3 file storage config.paperclip_defaults = { @@ -37,7 +36,6 @@ Metamaps::Application.configure do port: ENV['SMTP_PORT'], user_name: ENV['SMTP_USERNAME'], password: ENV['SMTP_PASSWORD'], - # domain: ENV['SMTP_DOMAIN'] authentication: 'plain', enable_starttls_auto: true, openssl_verify_mode: 'none' @@ -46,54 +44,13 @@ Metamaps::Application.configure do # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = true - # Don't fallback to assets pipeline if a precompiled asset is missed - config.assets.compile = false - # Generate digests for assets URLs config.assets.digest = true - # Defaults to Rails.root.join("public/assets") - # config.assets.manifest = YOUR_PATH - - # Specifies the header that your server uses for sending files - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx - - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true - - # See everything in the log (default is :info) - # config.log_level = :debug - - # Prepend all log lines with the following tags - # config.log_tags = [ :subdomain, :uuid ] - - # Use a different logger for distributed setups - # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) - - # Use a different cache store in production - # config.cache_store = :mem_cache_store - - # Enable serving of images, stylesheets, and JavaScripts from an asset server - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - # config.assets.precompile += %w( ) - - # Disable delivery errors, bad email addresses will be ignored - # config.action_mailer.raise_delivery_errors = false - - # Enable threaded mode - # config.threadsafe! - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found) config.i18n.fallbacks = true # Send deprecation notices to registered listeners config.active_support.deprecation = :notify - - # Log the query plan for queries taking more than this (works - # with SQLite, MySQL, and PostgreSQL) - # config.active_record.auto_explain_threshold_in_seconds = 0.5 end diff --git a/config/environments/test.rb b/config/environments/test.rb index 4980b34c..dac060f1 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -10,8 +10,10 @@ Metamaps::Application.configure do config.cache_classes = true # Configure static asset server for tests with Cache-Control for performance - config.serve_static_files = true - config.static_cache_control = 'public, max-age=3600' + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => 'public, max-age=3600' + } # Show full error reports and disable caching config.consider_all_requests_local = true diff --git a/config/initializers/access_codes.rb b/config/initializers/access_codes.rb index 66ace9a1..4a220c97 100644 --- a/config/initializers/access_codes.rb +++ b/config/initializers/access_codes.rb @@ -1,4 +1,4 @@ $codes = [] -if ActiveRecord::Base.connection.table_exists? 'users' +if ActiveRecord::Base.connection.data_source_exists? 'users' $codes = ActiveRecord::Base.connection.execute('SELECT code FROM users').map { |user| user['code'] } end diff --git a/config/initializers/active_model_serializers.rb b/config/initializers/active_model_serializers.rb new file mode 100644 index 00000000..aba3586b --- /dev/null +++ b/config/initializers/active_model_serializers.rb @@ -0,0 +1 @@ +ActiveModelSerializers.config.adapter = :json diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 00000000..51639b67 --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,6 @@ +# Be sure to restart your server when you modify this file. + +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index b84c4e25..31897cf4 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -1 +1,12 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '2.0' +Rails.application.config.assets.quiet = true + +# Add additional assets to the asset load path +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. Rails.application.config.assets.precompile += %w( webpacked/metamaps.bundle.js ) diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb new file mode 100644 index 00000000..f51a497e --- /dev/null +++ b/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :hybrid diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 00000000..4a994e1e --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 5d8d9be2..ac033bf9 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -1,15 +1,16 @@ # Be sure to restart your server when you modify this file. -# Add new inflection rules using the following format -# (all these examples are active by default): -# ActiveSupport::Inflector.inflections do |inflect| +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end -# + # These inflection rules are supported but not enabled by default: -# ActiveSupport::Inflector.inflections do |inflect| +# ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' # end diff --git a/config/initializers/kaminari_config.rb b/config/initializers/kaminari_config.rb new file mode 100644 index 00000000..b1d87b01 --- /dev/null +++ b/config/initializers/kaminari_config.rb @@ -0,0 +1,10 @@ +Kaminari.configure do |config| + # config.default_per_page = 25 + # config.max_per_page = nil + # config.window = 4 + # config.outer_window = 0 + # config.left = 0 + # config.right = 0 + # config.page_method_name = :page + # config.param_name = :page +end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index 54890c6e..c7b0c86d 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -2,6 +2,5 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf -# Mime::Type.register_alias "text/html", :iphone Mime::Type.register 'application/xls', :xls diff --git a/config/initializers/new_framework_defaults.rb b/config/initializers/new_framework_defaults.rb new file mode 100644 index 00000000..0706cafd --- /dev/null +++ b/config/initializers/new_framework_defaults.rb @@ -0,0 +1,24 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.0 upgrade. +# +# Read the Rails 5.0 release notes for more info on each option. + +# Enable per-form CSRF tokens. Previous versions had false. +Rails.application.config.action_controller.per_form_csrf_tokens = true + +# Enable origin-checking CSRF mitigation. Previous versions had false. +Rails.application.config.action_controller.forgery_protection_origin_check = true + +# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. +# Previous versions had false. +ActiveSupport.to_time_preserves_timezone = true + +# Require `belongs_to` associations by default. Previous versions had false. +Rails.application.config.active_record.belongs_to_required_by_default = true + +# Do not halt callback chains when a callback returns false. Previous versions had true. +ActiveSupport.halt_callback_chains_on_return_false = false + +# Configure SSL options to enable HSTS with subdomains. Previous versions had false. +Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 83877c08..e7f18911 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -4,4 +4,4 @@ # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -Metamaps::Application.config.secret_key_base = ENV['SECRET_KEY_BASE'] +Rails.application.config.secret_key_base = ENV['SECRET_KEY_BASE'] diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 757d66cc..d2dc13b6 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,8 +1,8 @@ # Be sure to restart your server when you modify this file. -Metamaps::Application.config.session_store :cookie_store, key: '_Metamaps_session' +Rails.application.config.session_store :cookie_store, key: '_Metamaps_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") -# Metamaps::Application.config.session_store :active_record_store +# Rails.application.config.session_store :active_record_store diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 999df201..36bb3e27 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -8,7 +8,7 @@ ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] end -# Disable root element in JSON by default. -ActiveSupport.on_load(:active_record) do - self.include_root_in_json = false -end +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 00000000..c7f311f8 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,47 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum, this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests, default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. If you use this option +# you need to make sure to reconnect any threads in the `on_worker_boot` +# block. +# +# preload_app! + +# The code in the `on_worker_boot` will be called if you are using +# clustered mode by specifying a number of `workers`. After each worker +# process is booted this block will be run, if you are using `preload_app!` +# option you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, Ruby +# cannot share connections between processes. +# +# on_worker_boot do +# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +# end + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb index 83f03051..38fe274e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,13 +9,26 @@ Metamaps::Application.routes.draw do get 'search/mappers', to: 'main#searchmappers', as: :searchmappers get 'search/synapses', to: 'main#searchsynapses', as: :searchsynapses - namespace :api, path: '/api/v1', defaults: { format: :json } do - resources :maps, only: [:create, :show, :update, :destroy] - resources :synapses, only: [:create, :show, :update, :destroy] - resources :topics, only: [:create, :show, :update, :destroy] - resources :mappings, only: [:create, :show, :update, :destroy] - resources :tokens, only: [:create, :destroy] do - get :my_tokens, on: :collection + namespace :api, path: '/api', default: { format: :json } do + namespace :v2, path: '/v2' do + resources :maps, only: [:index, :create, :show, :update, :destroy] + resources :synapses, only: [:index, :create, :show, :update, :destroy] + resources :topics, only: [:index, :create, :show, :update, :destroy] + resources :mappings, only: [:index, :create, :show, :update, :destroy] + resources :tokens, only: [:create, :destroy] do + get :my_tokens, on: :collection + end + end + namespace :v1, path: '/v1' do + # api v1 routes all lead to a deprecation error method + # see app/controllers/api/v1/deprecated_controller.rb + resources :maps, only: [:create, :show, :update, :destroy] + resources :synapses, only: [:create, :show, :update, :destroy] + resources :topics, only: [:create, :show, :update, :destroy] + resources :mappings, only: [:create, :show, :update, :destroy] + resources :tokens, only: [:create, :destroy] do + get :my_tokens, on: :collection + end end end diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 00000000..be72de67 --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,7 @@ +%w( + .ruby-version + .ruby-gemset + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +).each { |path| Spring.watch(path) } diff --git a/db/schema.rb b/db/schema.rb index 6b586a0d..ea06b679 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,4 +1,3 @@ -# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -28,10 +27,9 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.string "queue" t.datetime "created_at" t.datetime "updated_at" + t.index ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree end - add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree - create_table "events", force: :cascade do |t| t.string "kind", limit: 255 t.integer "eventable_id" @@ -41,24 +39,22 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.integer "sequence_id" t.datetime "created_at" t.datetime "updated_at" + t.index ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id", using: :btree + t.index ["map_id", "sequence_id"], name: "index_events_on_map_id_and_sequence_id", unique: true, using: :btree + t.index ["map_id"], name: "index_events_on_map_id", using: :btree + t.index ["sequence_id"], name: "index_events_on_sequence_id", using: :btree + t.index ["user_id"], name: "index_events_on_user_id", using: :btree end - add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id", using: :btree - add_index "events", ["map_id", "sequence_id"], name: "index_events_on_map_id_and_sequence_id", unique: true, using: :btree - add_index "events", ["map_id"], name: "index_events_on_map_id", using: :btree - add_index "events", ["sequence_id"], name: "index_events_on_sequence_id", using: :btree - add_index "events", ["user_id"], name: "index_events_on_user_id", using: :btree - create_table "in_metacode_sets", force: :cascade do |t| t.integer "metacode_id" t.integer "metacode_set_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["metacode_id"], name: "index_in_metacode_sets_on_metacode_id", using: :btree + t.index ["metacode_set_id"], name: "index_in_metacode_sets_on_metacode_set_id", using: :btree end - add_index "in_metacode_sets", ["metacode_id"], name: "index_in_metacode_sets_on_metacode_id", using: :btree - add_index "in_metacode_sets", ["metacode_set_id"], name: "index_in_metacode_sets_on_metacode_set_id", using: :btree - create_table "mappings", force: :cascade do |t| t.text "category" t.integer "xloc" @@ -71,14 +67,13 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.datetime "updated_at", null: false t.integer "mappable_id" t.string "mappable_type" + t.index ["map_id", "synapse_id"], name: "index_mappings_on_map_id_and_synapse_id", using: :btree + t.index ["map_id", "topic_id"], name: "index_mappings_on_map_id_and_topic_id", using: :btree + t.index ["map_id"], name: "index_mappings_on_map_id", using: :btree + t.index ["mappable_id", "mappable_type"], name: "index_mappings_on_mappable_id_and_mappable_type", using: :btree + t.index ["user_id"], name: "index_mappings_on_user_id", using: :btree end - add_index "mappings", ["map_id", "synapse_id"], name: "index_mappings_on_map_id_and_synapse_id", using: :btree - add_index "mappings", ["map_id", "topic_id"], name: "index_mappings_on_map_id_and_topic_id", using: :btree - add_index "mappings", ["map_id"], name: "index_mappings_on_map_id", using: :btree - add_index "mappings", ["mappable_id", "mappable_type"], name: "index_mappings_on_mappable_id_and_mappable_type", using: :btree - add_index "mappings", ["user_id"], name: "index_mappings_on_user_id", using: :btree - create_table "maps", force: :cascade do |t| t.text "name" t.boolean "arranged" @@ -92,10 +87,9 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.string "screenshot_content_type" t.integer "screenshot_file_size" t.datetime "screenshot_updated_at" + t.index ["user_id"], name: "index_maps_on_user_id", using: :btree end - add_index "maps", ["user_id"], name: "index_maps_on_user_id", using: :btree - create_table "messages", force: :cascade do |t| t.text "message" t.integer "user_id" @@ -103,12 +97,11 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.string "resource_type" t.datetime "created_at" t.datetime "updated_at" + t.index ["resource_id"], name: "index_messages_on_resource_id", using: :btree + t.index ["resource_type"], name: "index_messages_on_resource_type", using: :btree + t.index ["user_id"], name: "index_messages_on_user_id", using: :btree end - add_index "messages", ["resource_id"], name: "index_messages_on_resource_id", using: :btree - add_index "messages", ["resource_type"], name: "index_messages_on_resource_type", using: :btree - add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree - create_table "metacode_sets", force: :cascade do |t| t.string "name" t.text "desc" @@ -116,10 +109,9 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.boolean "mapperContributed" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["user_id"], name: "index_metacode_sets_on_user_id", using: :btree end - add_index "metacode_sets", ["user_id"], name: "index_metacode_sets_on_user_id", using: :btree - create_table "metacodes", force: :cascade do |t| t.text "name" t.string "manual_icon" @@ -141,10 +133,9 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.datetime "created_at", null: false t.datetime "revoked_at" t.string "scopes" + t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree end - add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree - create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" @@ -154,12 +145,11 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.datetime "revoked_at" t.datetime "created_at", null: false t.string "scopes" + t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree + t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree + t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree end - add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree - add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree - add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree - create_table "oauth_applications", force: :cascade do |t| t.string "name", null: false t.string "uid", null: false @@ -168,20 +158,18 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.string "scopes", default: "", null: false t.datetime "created_at" t.datetime "updated_at" + t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree end - add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree - create_table "stars", force: :cascade do |t| t.integer "user_id" t.integer "map_id" t.datetime "created_at" t.datetime "updated_at" + t.index ["map_id"], name: "index_stars_on_map_id", using: :btree + t.index ["user_id"], name: "index_stars_on_user_id", using: :btree end - add_index "stars", ["map_id"], name: "index_stars_on_map_id", using: :btree - add_index "stars", ["user_id"], name: "index_stars_on_user_id", using: :btree - create_table "synapses", force: :cascade do |t| t.text "desc" t.text "category" @@ -193,24 +181,22 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "defer_to_map_id" + t.index ["node1_id", "node1_id"], name: "index_synapses_on_node1_id_and_node1_id", using: :btree + t.index ["node1_id"], name: "index_synapses_on_node1_id", using: :btree + t.index ["node2_id", "node2_id"], name: "index_synapses_on_node2_id_and_node2_id", using: :btree + t.index ["node2_id"], name: "index_synapses_on_node2_id", using: :btree + t.index ["user_id"], name: "index_synapses_on_user_id", using: :btree end - add_index "synapses", ["node1_id", "node1_id"], name: "index_synapses_on_node1_id_and_node1_id", using: :btree - add_index "synapses", ["node1_id"], name: "index_synapses_on_node1_id", using: :btree - add_index "synapses", ["node2_id", "node2_id"], name: "index_synapses_on_node2_id_and_node2_id", using: :btree - add_index "synapses", ["node2_id"], name: "index_synapses_on_node2_id", using: :btree - add_index "synapses", ["user_id"], name: "index_synapses_on_user_id", using: :btree - create_table "tokens", force: :cascade do |t| t.string "token" t.string "description" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["user_id"], name: "index_tokens_on_user_id", using: :btree end - add_index "tokens", ["user_id"], name: "index_tokens_on_user_id", using: :btree - create_table "topics", force: :cascade do |t| t.text "name" t.text "desc" @@ -229,21 +215,19 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.integer "audio_file_size" t.datetime "audio_updated_at" t.integer "defer_to_map_id" + t.index ["metacode_id"], name: "index_topics_on_metacode_id", using: :btree + t.index ["user_id"], name: "index_topics_on_user_id", using: :btree end - add_index "topics", ["metacode_id"], name: "index_topics_on_metacode_id", using: :btree - add_index "topics", ["user_id"], name: "index_topics_on_user_id", using: :btree - create_table "user_maps", force: :cascade do |t| t.integer "user_id" t.integer "map_id" t.datetime "created_at" t.datetime "updated_at" + t.index ["map_id"], name: "index_user_maps_on_map_id", using: :btree + t.index ["user_id"], name: "index_user_maps_on_user_id", using: :btree end - add_index "user_maps", ["map_id"], name: "index_user_maps_on_map_id", using: :btree - add_index "user_maps", ["user_id"], name: "index_user_maps_on_user_id", using: :btree - create_table "users", force: :cascade do |t| t.string "name" t.string "email" @@ -272,19 +256,17 @@ ActiveRecord::Schema.define(version: 20160820231717) do t.integer "image_file_size" t.datetime "image_updated_at" t.integer "generation" + t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree end - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree - create_table "webhooks", force: :cascade do |t| t.integer "hookable_id" t.string "hookable_type" t.string "kind", null: false t.string "uri", null: false t.text "event_types", default: [], array: true + t.index ["hookable_type", "hookable_id"], name: "index_webhooks_on_hookable_type_and_hookable_id", using: :btree end - add_index "webhooks", ["hookable_type", "hookable_id"], name: "index_webhooks_on_hookable_type_and_hookable_id", using: :btree - add_foreign_key "tokens", "users" end diff --git a/doc/api/api.raml b/doc/api/api.raml new file mode 100644 index 00000000..d61e66ac --- /dev/null +++ b/doc/api/api.raml @@ -0,0 +1,39 @@ +#%RAML 1.0 +--- +title: Metamaps +version: v2 +baseUri: http://metamaps.cc/api/v2 +mediaType: application/json + +securitySchemes: + - oauth_2_0: + description: | + OAuth 2.0 implementation + type: OAuth 2.0 + settings: + authorizationUri: https://metamaps.cc/api/v2/oauth/authorize + accessTokenUri: https://metamaps.cc/api/v2/oauth/token + authorizationGrants: [ authorization_code, password, client_credentials, implicit, refresh_token ] + +traits: + - pageable: !include traits/pageable.raml + - orderable: !include traits/orderable.raml + - searchable: !include traits/searchable.raml + +schemas: + - topic: !include schemas/_topic.json + - synapse: !include schemas/_synapse.json + - map: !include schemas/_map.json + - mapping: !include schemas/_mapping.json + - token: !include schemas/_token.json + +resourceTypes: + - base: !include resourceTypes/base.raml + - item: !include resourceTypes/item.raml + - collection: !include resourceTypes/collection.raml + +/topics: !include apis/topics.raml +/synapses: !include apis/synapses.raml +/maps: !include apis/maps.raml +/mappings: !include apis/mappings.raml +/tokens: !include apis/tokens.raml diff --git a/doc/api/apis/mappings.raml b/doc/api/apis/mappings.raml new file mode 100644 index 00000000..8b72b4df --- /dev/null +++ b/doc/api/apis/mappings.raml @@ -0,0 +1,68 @@ +type: collection +get: + responses: + 200: + body: + application/json: + example: !include ../examples/mappings.json +post: + body: + application/json: + properties: + mappable_id: + description: id of the topic/synapse to be mapped + mappable_type: + description: Topic or Synapse + map_id: + description: id of the map + xloc: + description: (for Topic mappings only) x location on the canvas + yloc: + description: (for Topic mappings only) y location on the canvas + responses: + 201: + body: + application/json: + example: !include ../examples/mapping.json +/{id}: + type: item + get: + responses: + 200: + body: + application/json: + example: !include ../examples/mapping.json + put: + body: + application/json: + properties: + mappable_id: + description: id of the topic/synapse to be mapped + mappable_type: + description: Topic or Synapse + map_id: + description: id of the map + responses: + 200: + body: + application/json: + example: !include ../examples/mapping.json + patch: + body: + application/json: + properties: + mappable_id: + description: id of the topic/synapse to be mapped + mappable_type: + description: Topic or Synapse + map_id: + description: id of the map + responses: + 200: + body: + application/json: + example: !include ../examples/mapping.json + delete: + responses: + 204: + description: No content diff --git a/doc/api/apis/maps.raml b/doc/api/apis/maps.raml new file mode 100644 index 00000000..c5499a33 --- /dev/null +++ b/doc/api/apis/maps.raml @@ -0,0 +1,82 @@ +type: collection +get: + responses: + 200: + body: + application/json: + example: !include ../examples/maps.json +post: + body: + application/json: + properties: + name: + description: name + desc: + description: description + permission: + description: commons, public, or private + screenshot: + description: url to a screenshot of the map + contributor_ids: + description: the topic being linked from + collaborator_ids: + description: the topic being linked to + responses: + 201: + body: + application/json: + example: !include ../examples/map.json +/{id}: + type: item + get: + responses: + 200: + body: + application/json: + example: !include ../examples/map.json + put: + body: + application/json: + properties: + name: + description: name + desc: + description: description + permission: + description: commons, public, or private + screenshot: + description: url to a screenshot of the map + contributor_ids: + description: the topic being linked from + collaborator_ids: + description: the topic being linked to + responses: + 200: + body: + application/json: + example: !include ../examples/map.json + patch: + body: + application/json: + properties: + name: + description: name + desc: + description: description + permission: + description: commons, public, or private + screenshot: + description: url to a screenshot of the map + contributor_ids: + description: the topic being linked from + collaborator_ids: + description: the topic being linked to + responses: + 200: + body: + application/json: + example: !include ../examples/map.json + delete: + responses: + 204: + description: No content diff --git a/doc/api/apis/synapses.raml b/doc/api/apis/synapses.raml new file mode 100644 index 00000000..3169c712 --- /dev/null +++ b/doc/api/apis/synapses.raml @@ -0,0 +1,82 @@ +type: collection +get: + responses: + 200: + body: + application/json: + example: !include ../examples/synapses.json +post: + body: + application/json: + properties: + desc: + description: name + category: + description: from to or both + permission: + description: commons, public, or private + topic1_id: + description: the topic being linked from + topic2_id: + description: the topic being linked to + user_id: + description: the creator of the topic + responses: + 201: + body: + application/json: + example: !include ../examples/synapse.json +/{id}: + type: item + get: + responses: + 200: + body: + application/json: + example: !include ../examples/synapse.json + put: + body: + application/json: + properties: + desc: + description: name + category: + description: from-to or both + permission: + description: commons, public, or private + topic1_id: + description: the topic being linked from + topic2_id: + description: the topic being linked to + user_id: + description: the creator of the topic + responses: + 200: + body: + application/json: + example: !include ../examples/synapse.json + patch: + body: + application/json: + properties: + desc: + description: name + category: + description: from-to or both + permission: + description: commons, public, or private + topic1_id: + description: the topic being linked from + topic2_id: + description: the topic being linked to + user_id: + description: the creator of the topic + responses: + 200: + body: + application/json: + example: !include ../examples/synapse.json + delete: + responses: + 204: + description: No content diff --git a/doc/api/apis/tokens.raml b/doc/api/apis/tokens.raml new file mode 100644 index 00000000..9f471615 --- /dev/null +++ b/doc/api/apis/tokens.raml @@ -0,0 +1,25 @@ +type: collection +post: + body: + application/json: + properties: + description: + description: short string describing this token + responses: + 201: + body: + application/json: + example: !include ../examples/token.json +/my_tokens: + get: + responses: + 200: + body: + application/json: + example: !include ../examples/tokens.json +/{id}: + type: item + delete: + responses: + 204: + description: No content diff --git a/doc/api/apis/topics.raml b/doc/api/apis/topics.raml new file mode 100644 index 00000000..7c214dd2 --- /dev/null +++ b/doc/api/apis/topics.raml @@ -0,0 +1,72 @@ +type: collection +get: + responses: + 200: + body: + application/json: + example: !include ../examples/topics.json +post: + body: + application/json: + properties: + name: + description: name + desc: + description: description + link: + description: (optional) link to content on the web + permission: + description: commons, public, or private + metacode_id: + description: Topic's metacode + responses: + 201: + body: + application/json: + example: !include ../examples/topic.json +/{id}: + type: item + get: + responses: + 200: + body: + application/json: + example: !include ../examples/topic.json + put: + body: + application/json: + properties: + name: + description: name + desc: + description: description + link: + description: (optional) link to content on the web + permission: + description: commons, public, or private + responses: + 200: + body: + application/json: + example: !include ../examples/topic.json + patch: + body: + application/json: + properties: + name: + description: name + desc: + description: description + link: + description: (optional) link to content on the web + permission: + description: commons, public, or private + responses: + 200: + body: + application/json: + example: !include ../examples/topic.json + delete: + responses: + 204: + description: No content diff --git a/doc/api/examples/map.json b/doc/api/examples/map.json new file mode 100644 index 00000000..fe3796ca --- /dev/null +++ b/doc/api/examples/map.json @@ -0,0 +1,27 @@ +{ + "data": { + "id": 2, + "name": "Emergent Network Phenomena", + "desc": "Example map for the API", + "permission": "commons", + "screenshot": "https://s3.amazonaws.com/metamaps-assets/site/missing-map.png", + "created_at": "2016-03-26T08:02:05.379Z", + "updated_at": "2016-03-27T07:20:18.047Z", + "topic_ids": [ + 58, + 59 + ], + "synapse_ids": [ + 2 + ], + "mapping_ids": [ + 94, + 95, + 96 + ], + "collaborator_ids": [], + "contributor_ids": [ + 2 + ] + } +} diff --git a/doc/api/examples/mapping.json b/doc/api/examples/mapping.json new file mode 100644 index 00000000..c4aa87bf --- /dev/null +++ b/doc/api/examples/mapping.json @@ -0,0 +1,11 @@ +{ + "data": { + "id": 4, + "created_at": "2016-03-25T08:44:21.337Z", + "updated_at": "2016-03-25T08:44:21.337Z", + "mappable_id": 1, + "mappable_type": "Synapse", + "user_id": 1, + "map_id": 1 + } +} diff --git a/doc/api/examples/mappings.json b/doc/api/examples/mappings.json new file mode 100644 index 00000000..5a4a99c3 --- /dev/null +++ b/doc/api/examples/mappings.json @@ -0,0 +1,54 @@ +{ + "data": [ + { + "created_at": "2016-03-25T08:44:07.152Z", + "id": 1, + "map_id": 1, + "mappable_id": 1, + "mappable_type": "Topic", + "updated_at": "2016-03-25T08:44:07.152Z", + "user_id": 1, + "xloc": -271, + "yloc": 22 + }, + { + "created_at": "2016-03-25T08:44:13.907Z", + "id": 2, + "map_id": 1, + "mappable_id": 2, + "mappable_type": "Topic", + "updated_at": "2016-03-25T08:44:13.907Z", + "user_id": 1, + "xloc": -12, + "yloc": 61 + }, + { + "created_at": "2016-03-25T08:44:19.333Z", + "id": 3, + "map_id": 1, + "mappable_id": 3, + "mappable_type": "Topic", + "updated_at": "2016-03-25T08:44:19.333Z", + "user_id": 1, + "xloc": -93, + "yloc": -90 + }, + { + "created_at": "2016-03-25T08:44:21.337Z", + "id": 4, + "map_id": 1, + "mappable_id": 1, + "mappable_type": "Synapse", + "updated_at": "2016-03-25T08:44:21.337Z", + "user_id": 1 + } + ], + "page": { + "current_page": 1, + "next_page": 2, + "per": 4, + "prev_page": 0, + "total_count": 303, + "total_pages": 76 + } +} diff --git a/doc/api/examples/maps.json b/doc/api/examples/maps.json new file mode 100644 index 00000000..8b963990 --- /dev/null +++ b/doc/api/examples/maps.json @@ -0,0 +1,37 @@ +{ + "data": [ + { + "id": 2, + "name": "Emergent Network Phenomena", + "desc": "Example map for the API", + "permission": "commons", + "screenshot": "https://s3.amazonaws.com/metamaps-assets/site/missing-map.png", + "created_at": "2016-03-26T08:02:05.379Z", + "updated_at": "2016-03-27T07:20:18.047Z", + "topic_ids": [ + 58, + 59 + ], + "synapse_ids": [ + 2 + ], + "mapping_ids": [ + 94, + 95, + 96 + ], + "collaborator_ids": [], + "contributor_ids": [ + 2 + ] + } + ], + "page": { + "current_page": 1, + "next_page": 2, + "prev_page": 0, + "total_pages": 5, + "total_count": 5, + "per": 1 + } +} diff --git a/doc/api/examples/synapse.json b/doc/api/examples/synapse.json new file mode 100644 index 00000000..0de4acb3 --- /dev/null +++ b/doc/api/examples/synapse.json @@ -0,0 +1,13 @@ +{ + "data": { + "id": 2, + "desc": "hello", + "category": "from-to", + "permission": "commons", + "created_at": "2016-03-26T08:02:17.994Z", + "updated_at": "2016-03-26T08:02:17.994Z", + "topic1_id": 5, + "topic2_id": 6, + "user_id": 2 + } +} diff --git a/doc/api/examples/synapses.json b/doc/api/examples/synapses.json new file mode 100644 index 00000000..1bcb00c2 --- /dev/null +++ b/doc/api/examples/synapses.json @@ -0,0 +1,34 @@ +{ + "data": [ + { + "id": 2, + "desc": "hello", + "category": "from-to", + "permission": "commons", + "created_at": "2016-03-26T08:02:17.994Z", + "updated_at": "2016-03-26T08:02:17.994Z", + "topic1_id": 1, + "topic2_id": 2, + "user_id": 2 + }, + { + "id": 6, + "desc": "nice", + "category": "both", + "permission": "public", + "created_at": "2016-03-26T08:05:31.563Z", + "updated_at": "2016-03-26T08:05:31.563Z", + "topic1_id": 2, + "topic2_id": 3, + "user_id": 2 + } + ], + "page": { + "current_page": 1, + "next_page": 2, + "prev_page": 0, + "total_pages": 71, + "total_count": 142, + "per": 2 + } +} diff --git a/doc/api/examples/token.json b/doc/api/examples/token.json new file mode 100644 index 00000000..14f559ea --- /dev/null +++ b/doc/api/examples/token.json @@ -0,0 +1,8 @@ +{ + "data": { + "id": 1, + "token": "VeI0qAe2bf2ytnrTRxmywsH0VSwuyjK5", + "description": "Personal token for in-browser testing", + "created_at": "2016-09-06T03:47:56.553Z" + } +} diff --git a/doc/api/examples/tokens.json b/doc/api/examples/tokens.json new file mode 100644 index 00000000..6d05cffc --- /dev/null +++ b/doc/api/examples/tokens.json @@ -0,0 +1,18 @@ +{ + "data": [ + { + "id": 1, + "token": "VeI0qAe2bf2ytnrTRxmywsH0VSwuyjK5", + "description": "Personal token for in-browser testing", + "created_at": "2016-09-06T03:47:56.553Z" + } + ], + "page": { + "current_page": 1, + "next_page": 0, + "prev_page": 0, + "total_pages": 1, + "total_count": 1, + "per": 25 + } +} diff --git a/doc/api/examples/topic.json b/doc/api/examples/topic.json new file mode 100644 index 00000000..90e702a2 --- /dev/null +++ b/doc/api/examples/topic.json @@ -0,0 +1,13 @@ +{ + "data": { + "id": 670, + "name": "Junto feedback and enhancements map", + "desc": "", + "link": "", + "permission": "commons", + "created_at": "2016-07-02T09:23:30.397Z", + "updated_at": "2016-07-02T09:23:30.397Z", + "user_id": 2, + "metacode_id": 36 + } +} diff --git a/doc/api/examples/topics.json b/doc/api/examples/topics.json new file mode 100644 index 00000000..d4eba53e --- /dev/null +++ b/doc/api/examples/topics.json @@ -0,0 +1,34 @@ +{ + "data": [ + { + "id": 670, + "name": "Junto feedback and enhancements map", + "desc": "", + "link": "", + "permission": "commons", + "created_at": "2016-07-02T09:23:30.397Z", + "updated_at": "2016-07-02T09:23:30.397Z", + "user_id": 2, + "metacode_id": 36 + }, + { + "id": 60, + "name": "View others on map in realtime", + "desc": "", + "link": "", + "permission": "commons", + "created_at": "2016-03-31T01:20:26.734Z", + "updated_at": "2016-03-31T01:20:26.734Z", + "user_id": 2, + "metacode_id": 8 + } + ], + "page": { + "current_page": 1, + "next_page": 2, + "prev_page": 0, + "total_pages": 249, + "total_count": 497, + "per": 2 + } +} diff --git a/doc/api/resourceTypes/base.raml b/doc/api/resourceTypes/base.raml new file mode 100644 index 00000000..47ca56e3 --- /dev/null +++ b/doc/api/resourceTypes/base.raml @@ -0,0 +1,35 @@ +get?: + responses: + 400: + description: Invalid request or params + body: + application/json: + schema: error +put?: + responses: + 400: + description: Invalid request or params + body: + application/json: + schema: error +patch?: + responses: + 400: + description: Invalid request or params + body: + application/json: + schema: error +post?: + responses: + 400: + description: Invalid request or params + body: + application/json: + schema: error +delete?: + responses: + 400: + description: Invalid request or params + body: + application/json: + schema: error diff --git a/doc/api/resourceTypes/collection.raml b/doc/api/resourceTypes/collection.raml new file mode 100644 index 00000000..d54e6c0c --- /dev/null +++ b/doc/api/resourceTypes/collection.raml @@ -0,0 +1,22 @@ +type: base +get?: + description: Get all <> + queryParameters: + page: + description: The page number + type: integer + per: + description: Number of records per page + type: integer + responses: + 200: + body: + application/json: + schema: <> +post?: + description: Create a new <> + responses: + 200: + body: + application/json: + schema: <> diff --git a/doc/api/resourceTypes/item.raml b/doc/api/resourceTypes/item.raml new file mode 100644 index 00000000..1abf040e --- /dev/null +++ b/doc/api/resourceTypes/item.raml @@ -0,0 +1,29 @@ +get?: + description: Get a <> + responses: + 200: + body: + application/json: + schema: <> +put?: + description: Update a <> + responses: + 201: + description: Update success + body: + application/json: + schema: <> +patch?: + description: Update a <> + responses: + 201: + description: Update success + body: + application/json: + schema: <> +delete?: + description: Delete a <> + responses: + 204: + description: Removed +type: base diff --git a/doc/api/schemas/_datetimestamp.json b/doc/api/schemas/_datetimestamp.json new file mode 100644 index 00000000..fd9a76a4 --- /dev/null +++ b/doc/api/schemas/_datetimestamp.json @@ -0,0 +1,4 @@ +{ + "type": "string", + "format": "date-time" +} diff --git a/doc/api/schemas/_id.json b/doc/api/schemas/_id.json new file mode 100644 index 00000000..d94ff818 --- /dev/null +++ b/doc/api/schemas/_id.json @@ -0,0 +1,4 @@ +{ + "type": "integer", + "minimum": 1 +} diff --git a/doc/api/schemas/_map.json b/doc/api/schemas/_map.json new file mode 100644 index 00000000..469b4dbe --- /dev/null +++ b/doc/api/schemas/_map.json @@ -0,0 +1,67 @@ +{ + "name": "Map", + "type": "object", + "properties": { + "id": { + "$ref": "_id.json" + }, + "name": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "permission": { + "$ref": "_permission.json" + }, + "screenshot": { + "format": "uri", + "type": "string" + }, + "created_at": { + "$ref": "_datetimestamp.json" + }, + "updated_at": { + "$ref": "_datetimestamp.json" + }, + "topic_ids": { + "type": "array", + "items": { + "$ref": "_id.json" + } + }, + "synapse_ids": { + "type": "array", + "items": { + "$ref": "_id.json" + } + }, + "mapping_ids": { + "type": "array", + "items": { + "$ref": "_id.json" + } + }, + "contributor_ids": { + "type": "array", + "items": { + "$ref": "_id.json" + } + }, + "collaborator_ids": { + "type": "array", + "items": { + "$ref": "_id.json" + } + } + }, + "required": [ + "id", + "name", + "desc", + "permission", + "screenshot", + "created_at", + "updated_at" + ] +} diff --git a/doc/api/schemas/_mapping.json b/doc/api/schemas/_mapping.json new file mode 100644 index 00000000..5a3b06a6 --- /dev/null +++ b/doc/api/schemas/_mapping.json @@ -0,0 +1,41 @@ +{ + "name": "Mapping", + "type": "object", + "properties": { + "id": { + "$ref": "_id.json" + }, + "mappable_id": { + "$ref": "_id.json" + }, + "mappable_type": { + "type": "string", + "pattern": "(Topic|Synapse)" + }, + "xloc": { + "type": "integer" + }, + "yloc": { + "type": "integer" + }, + "created_at": { + "$ref": "_datetimestamp.json" + }, + "updated_at": { + "$ref": "_datetimestamp.json" + }, + "map_id": { + "$ref": "_id.json" + }, + "user_id": { + "$ref": "_id.json" + } + }, + "required": [ + "id", + "mappable_id", + "mappable_type", + "created_at", + "updated_at" + ] +} diff --git a/doc/api/schemas/_page.json b/doc/api/schemas/_page.json new file mode 100644 index 00000000..635f0286 --- /dev/null +++ b/doc/api/schemas/_page.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "properties": { + "current_page": { + "type": "integer", + "minimum": 1 + }, + "next_page": { + "type": "integer", + "minimum": 0 + }, + "prev_page": { + "type": "integer", + "minimum": 0 + }, + "total_pages": { + "type": "integer", + "minimum": 0 + }, + "total_count": { + "type": "integer", + "minimum": 0 + }, + "per": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "current_page", + "next_page", + "prev_page", + "total_pages", + "total_count", + "per" + ] +} + diff --git a/doc/api/schemas/_permission.json b/doc/api/schemas/_permission.json new file mode 100644 index 00000000..5c94fc81 --- /dev/null +++ b/doc/api/schemas/_permission.json @@ -0,0 +1,4 @@ +{ + "type": "string", + "pattern": "(commons|private|public)" +} diff --git a/doc/api/schemas/_synapse.json b/doc/api/schemas/_synapse.json new file mode 100644 index 00000000..dea238e2 --- /dev/null +++ b/doc/api/schemas/_synapse.json @@ -0,0 +1,42 @@ +{ + "name": "Synapse", + "type": "object", + "properties": { + "id": { + "$ref": "_id.json" + }, + "desc": { + "type": "string" + }, + "category": { + "type": "string", + "pattern": "(from-to|both)" + }, + "permission": { + "$ref": "_permission.json" + }, + "created_at": { + "$ref": "_datetimestamp.json" + }, + "updated_at": { + "$ref": "_datetimestamp.json" + }, + "topic1_id": { + "$ref": "_id.json" + }, + "topic2_id": { + "$ref": "_id.json" + }, + "user_id": { + "$ref": "_id.json" + } + }, + "required": [ + "id", + "desc", + "category", + "permission", + "created_at", + "updated_at" + ] +} diff --git a/doc/api/schemas/_token.json b/doc/api/schemas/_token.json new file mode 100644 index 00000000..62a44b3c --- /dev/null +++ b/doc/api/schemas/_token.json @@ -0,0 +1,24 @@ +{ + "name": "Token", + "type": "object", + "properties": { + "id": { + "$ref": "_id.json" + }, + "token": { + "type": "string" + }, + "description": { + "type": "string" + }, + "created_at": { + "$ref": "_datetimestamp.json" + } + }, + "required": [ + "id", + "token", + "description", + "created_at" + ] +} diff --git a/doc/api/schemas/_topic.json b/doc/api/schemas/_topic.json new file mode 100644 index 00000000..e9ccf67b --- /dev/null +++ b/doc/api/schemas/_topic.json @@ -0,0 +1,43 @@ +{ + "name": "Topic", + "type": "object", + "properties": { + "id": { + "$ref": "_id.json" + }, + "name": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "link": { + "format": "uri", + "type": "string" + }, + "permission": { + "$ref": "_permission.json" + }, + "created_at": { + "$ref": "_datetimestamp.json" + }, + "updated_at": { + "$ref": "_datetimestamp.json" + }, + "user_id": { + "$ref": "_id.json" + }, + "metacode_id": { + "$ref": "_id.json" + } + }, + "required": [ + "id", + "name", + "desc", + "link", + "permission", + "created_at", + "updated_at" + ] +} diff --git a/doc/api/schemas/map.json b/doc/api/schemas/map.json new file mode 100644 index 00000000..0a7ece7e --- /dev/null +++ b/doc/api/schemas/map.json @@ -0,0 +1,12 @@ +{ + "name": "Map Envelope", + "type": "object", + "properties": { + "data": { + "$ref": "_map.json" + } + }, + "required": [ + "data" + ] +} diff --git a/doc/api/schemas/mapping.json b/doc/api/schemas/mapping.json new file mode 100644 index 00000000..f0e91ace --- /dev/null +++ b/doc/api/schemas/mapping.json @@ -0,0 +1,12 @@ +{ + "name": "Mapping Envelope", + "type": "object", + "properties": { + "data": { + "$ref": "_mapping.json" + } + }, + "required": [ + "data" + ] +} diff --git a/doc/api/schemas/mappings.json b/doc/api/schemas/mappings.json new file mode 100644 index 00000000..37976a70 --- /dev/null +++ b/doc/api/schemas/mappings.json @@ -0,0 +1,19 @@ +{ + "name": "Mappings", + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "_mapping.json" + } + }, + "page": { + "$ref": "_page.json" + } + }, + "required": [ + "data", + "page" + ] +} diff --git a/doc/api/schemas/maps.json b/doc/api/schemas/maps.json new file mode 100644 index 00000000..39698b96 --- /dev/null +++ b/doc/api/schemas/maps.json @@ -0,0 +1,19 @@ +{ + "name": "Maps", + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "_map.json" + } + }, + "page": { + "$ref": "_page.json" + } + }, + "required": [ + "data", + "page" + ] +} diff --git a/doc/api/schemas/synapse.json b/doc/api/schemas/synapse.json new file mode 100644 index 00000000..5f916976 --- /dev/null +++ b/doc/api/schemas/synapse.json @@ -0,0 +1,12 @@ +{ + "name": "Synapse Envelope", + "type": "object", + "properties": { + "data": { + "$ref": "_synapse.json" + } + }, + "required": [ + "data" + ] +} diff --git a/doc/api/schemas/synapses.json b/doc/api/schemas/synapses.json new file mode 100644 index 00000000..dd41cc53 --- /dev/null +++ b/doc/api/schemas/synapses.json @@ -0,0 +1,19 @@ +{ + "name": "Synapses", + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "_synapse.json" + } + }, + "page": { + "$ref": "_page.json" + } + }, + "required": [ + "data", + "page" + ] +} diff --git a/doc/api/schemas/token.json b/doc/api/schemas/token.json new file mode 100644 index 00000000..85be81a5 --- /dev/null +++ b/doc/api/schemas/token.json @@ -0,0 +1,12 @@ +{ + "name": "Token Envelope", + "type": "object", + "properties": { + "data": { + "$ref": "_token.json" + } + }, + "required": [ + "data" + ] +} diff --git a/doc/api/schemas/tokens.json b/doc/api/schemas/tokens.json new file mode 100644 index 00000000..5ea5bdce --- /dev/null +++ b/doc/api/schemas/tokens.json @@ -0,0 +1,19 @@ +{ + "name": "Tokens", + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "_token.json" + } + }, + "page": { + "$ref": "_page.json" + } + }, + "required": [ + "data", + "page" + ] +} diff --git a/doc/api/schemas/topic.json b/doc/api/schemas/topic.json new file mode 100644 index 00000000..170670b1 --- /dev/null +++ b/doc/api/schemas/topic.json @@ -0,0 +1,12 @@ +{ + "name": "Topic Envelope", + "type": "object", + "properties": { + "data": { + "$ref": "_topic.json" + } + }, + "required": [ + "data" + ] +} diff --git a/doc/api/schemas/topics.json b/doc/api/schemas/topics.json new file mode 100644 index 00000000..643e7607 --- /dev/null +++ b/doc/api/schemas/topics.json @@ -0,0 +1,19 @@ +{ + "name": "Topics", + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "_topic.json" + } + }, + "page": { + "$ref": "_page.json" + } + }, + "required": [ + "data", + "page" + ] +} diff --git a/doc/api/traits/orderable.raml b/doc/api/traits/orderable.raml new file mode 100644 index 00000000..708736ab --- /dev/null +++ b/doc/api/traits/orderable.raml @@ -0,0 +1,3 @@ +queryParameters: + sort: + description: The name of the field to sort by, prefixed by "-" to sort descending diff --git a/doc/api/traits/pageable.raml b/doc/api/traits/pageable.raml new file mode 100644 index 00000000..88165861 --- /dev/null +++ b/doc/api/traits/pageable.raml @@ -0,0 +1,7 @@ +queryParameters: + page: + description: The page number + type: integer + per: + description: Number of records per page + type: integer diff --git a/doc/api/traits/searchable.raml b/doc/api/traits/searchable.raml new file mode 100644 index 00000000..53ae8525 --- /dev/null +++ b/doc/api/traits/searchable.raml @@ -0,0 +1,4 @@ +queryParameters: + q: + description: The search string to query by + type: string diff --git a/spec/api/v2/mappings_api_spec.rb b/spec/api/v2/mappings_api_spec.rb new file mode 100644 index 00000000..4a1e3298 --- /dev/null +++ b/spec/api/v2/mappings_api_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe 'mappings API', type: :request do + let(:user) { create(:user, admin: true) } + let(:token) { create(:token, user: user).token } + let(:mapping) { create(:mapping, user: user) } + + it 'GET /api/v2/mappings' do + create_list(:mapping, 5) + get '/api/v2/mappings', params: { access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:mappings) + expect(JSON.parse(response.body)['data'].count).to eq 5 + end + + it 'GET /api/v2/mappings/:id' do + get "/api/v2/mappings/#{mapping.id}" + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:mapping) + expect(JSON.parse(response.body)['data']['id']).to eq mapping.id + end + + it 'POST /api/v2/mappings' do + post '/api/v2/mappings', params: { mapping: mapping.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:mapping) + expect(Mapping.count).to eq 2 + end + + it 'PATCH /api/v2/mappings/:id' do + patch "/api/v2/mappings/#{mapping.id}", params: { mapping: mapping.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:mapping) + end + + it 'DELETE /api/v2/mappings/:id' do + delete "/api/v2/mappings/#{mapping.id}", params: { access_token: token } + + expect(response).to have_http_status(:no_content) + expect(Mapping.count).to eq 0 + end + + context 'RAML example' do + let(:resource) { get_json_example(:mapping) } + let(:collection) { get_json_example(:mappings) } + + it 'resource matches schema' do + expect(resource).to match_json_schema(:mapping) + end + + it 'collection matches schema' do + expect(collection).to match_json_schema(:mappings) + end + end +end diff --git a/spec/api/v2/maps_api_spec.rb b/spec/api/v2/maps_api_spec.rb new file mode 100644 index 00000000..7356ca72 --- /dev/null +++ b/spec/api/v2/maps_api_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe 'maps API', type: :request do + let(:user) { create(:user, admin: true) } + let(:token) { create(:token, user: user).token } + let(:map) { create(:map, user: user) } + + it 'GET /api/v2/maps' do + create_list(:map, 5) + get '/api/v2/maps', params: { access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:maps) + expect(JSON.parse(response.body)['data'].count).to eq 5 + end + + it 'GET /api/v2/maps/:id' do + get "/api/v2/maps/#{map.id}" + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:map) + expect(JSON.parse(response.body)['data']['id']).to eq map.id + end + + it 'POST /api/v2/maps' do + post '/api/v2/maps', params: { map: map.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:map) + expect(Map.count).to eq 2 + end + + it 'PATCH /api/v2/maps/:id' do + patch "/api/v2/maps/#{map.id}", params: { map: map.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:map) + end + + it 'DELETE /api/v2/maps/:id' do + delete "/api/v2/maps/#{map.id}", params: { access_token: token } + + expect(response).to have_http_status(:no_content) + expect(Map.count).to eq 0 + end + + context 'RAML example' do + let(:resource) { get_json_example(:map) } + let(:collection) { get_json_example(:maps) } + + it 'resource matches schema' do + expect(resource).to match_json_schema(:map) + end + + it 'collection matches schema' do + expect(collection).to match_json_schema(:maps) + end + end +end diff --git a/spec/api/v2/synapses_api_spec.rb b/spec/api/v2/synapses_api_spec.rb new file mode 100644 index 00000000..f232b879 --- /dev/null +++ b/spec/api/v2/synapses_api_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe 'synapses API', type: :request do + let(:user) { create(:user, admin: true) } + let(:token) { create(:token, user: user).token } + let(:synapse) { create(:synapse, user: user) } + + it 'GET /api/v2/synapses' do + create_list(:synapse, 5) + get '/api/v2/synapses', params: { access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:synapses) + expect(JSON.parse(response.body)['data'].count).to eq 5 + end + + it 'GET /api/v2/synapses/:id' do + get "/api/v2/synapses/#{synapse.id}" + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:synapse) + expect(JSON.parse(response.body)['data']['id']).to eq synapse.id + end + + it 'POST /api/v2/synapses' do + post '/api/v2/synapses', params: { synapse: synapse.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:synapse) + expect(Synapse.count).to eq 2 + end + + it 'PATCH /api/v2/synapses/:id' do + patch "/api/v2/synapses/#{synapse.id}", params: { synapse: synapse.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:synapse) + end + + it 'DELETE /api/v2/synapses/:id' do + delete "/api/v2/synapses/#{synapse.id}", params: { access_token: token } + + expect(response).to have_http_status(:no_content) + expect(Synapse.count).to eq 0 + end + + context 'RAML example' do + let(:resource) { get_json_example(:synapse) } + let(:collection) { get_json_example(:synapses) } + + it 'resource matches schema' do + expect(resource).to match_json_schema(:synapse) + end + + it 'collection matches schema' do + expect(collection).to match_json_schema(:synapses) + end + end +end diff --git a/spec/api/v2/tokens_api_spec.rb b/spec/api/v2/tokens_api_spec.rb new file mode 100644 index 00000000..c2e480a5 --- /dev/null +++ b/spec/api/v2/tokens_api_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +RSpec.describe 'tokens API', type: :request do + let(:user) { create(:user, admin: true) } + let(:auth_token) { create(:token, user: user).token } + let(:token) { create(:token, user: user) } + + it 'GET /api/v2/tokens/my_tokens' do + create_list(:token, 5, user: user) + get '/api/v2/tokens/my_tokens', params: { access_token: auth_token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:tokens) + expect(Token.count).to eq 6 # 5 + the extra auth token; let(:token) wasn't used + end + + it 'POST /api/v2/tokens' do + post '/api/v2/tokens', params: { token: token.attributes, access_token: auth_token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:token) + expect(Token.count).to eq 3 # auth_token, token, and the new POST-ed token + end + + it 'DELETE /api/v2/tokens/:id' do + delete "/api/v2/tokens/#{token.id}", params: { access_token: auth_token } + + expect(response).to have_http_status(:no_content) + expect(Token.count).to eq 1 # the extra auth token + end + + context 'RAML example' do + let(:resource) { get_json_example(:token) } + let(:collection) { get_json_example(:tokens) } + + it 'resource matches schema' do + expect(resource).to match_json_schema(:token) + end + + it 'collection matches schema' do + expect(collection).to match_json_schema(:tokens) + end + end +end diff --git a/spec/api/v2/topics_api_spec.rb b/spec/api/v2/topics_api_spec.rb new file mode 100644 index 00000000..4781348a --- /dev/null +++ b/spec/api/v2/topics_api_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe 'topics API', type: :request do + let(:user) { create(:user, admin: true) } + let(:token) { create(:token, user: user).token } + let(:topic) { create(:topic, user: user) } + + it 'GET /api/v2/topics' do + create_list(:topic, 5) + get '/api/v2/topics', params: { access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:topics) + expect(JSON.parse(response.body)['data'].count).to eq 5 + end + + it 'GET /api/v2/topics/:id' do + get "/api/v2/topics/#{topic.id}" + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:topic) + expect(JSON.parse(response.body)['data']['id']).to eq topic.id + end + + it 'POST /api/v2/topics' do + post '/api/v2/topics', params: { topic: topic.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:topic) + expect(Topic.count).to eq 2 + end + + it 'PATCH /api/v2/topics/:id' do + patch "/api/v2/topics/#{topic.id}", params: { topic: topic.attributes, access_token: token } + + expect(response).to have_http_status(:success) + expect(response).to match_json_schema(:topic) + end + + it 'DELETE /api/v2/topics/:id' do + delete "/api/v2/topics/#{topic.id}", params: { access_token: token } + + expect(response).to have_http_status(:no_content) + expect(Topic.count).to eq 0 + end + + context 'RAML example' do + let(:resource) { get_json_example(:topic) } + let(:collection) { get_json_example(:topics) } + + it 'resource matches schema' do + expect(resource).to match_json_schema(:topic) + end + + it 'collection matches schema' do + expect(collection).to match_json_schema(:topics) + end + end +end diff --git a/spec/controllers/mappings_controller_spec.rb b/spec/controllers/mappings_controller_spec.rb index ecf726c2..bcd2b97f 100644 --- a/spec/controllers/mappings_controller_spec.rb +++ b/spec/controllers/mappings_controller_spec.rb @@ -1,39 +1,40 @@ require 'rails_helper' RSpec.describe MappingsController, type: :controller do - let!(:mapping) { create(:mapping) } + let(:user) { create(:user) } + let!(:mapping) { create(:mapping, user: user) } let(:valid_attributes) { mapping.attributes.except('id') } - let(:invalid_attributes) { { xloc: 0 } } + let(:invalid_attributes) { { id: mapping.id } } before :each do - sign_in - end - - describe 'GET #show' do - it 'assigns the requested mapping as @mapping' do - get :show, id: mapping.to_param - expect(assigns(:mapping)).to eq(mapping) - end + sign_in user end describe 'POST #create' do context 'with valid params' do it 'creates a new Mapping' do expect do - post :create, mapping: valid_attributes + post :create, params: { + mapping: valid_attributes + } end.to change(Mapping, :count).by(1) end it 'assigns a newly created mapping as @mapping' do - post :create, mapping: valid_attributes - expect(assigns(:mapping)).to be_a(Mapping) - expect(assigns(:mapping)).to be_persisted + post :create, params: { + mapping: valid_attributes + } + expect(comparable(Mapping.last)).to eq comparable(mapping) end end context 'with invalid params' do it 'assigns a newly created but unsaved mapping as @mapping' do - post :create, mapping: invalid_attributes - expect(assigns(:mapping)).to be_a_new(Mapping) + post :create, params: { + mapping: invalid_attributes + } + # for some reason, the first mapping is still persisted + # TODO: fixme?? + expect(Mapping.count).to eq 1 end end end @@ -43,23 +44,26 @@ RSpec.describe MappingsController, type: :controller do let(:new_attributes) { build(:mapping_random_location).attributes.except('id') } it 'updates the requested mapping' do - put :update, - id: mapping.to_param, mapping: new_attributes + put :update, params: { + id: mapping.to_param, mapping: new_attributes + } mapping.reload end it 'assigns the requested mapping as @mapping' do - put :update, - id: mapping.to_param, mapping: valid_attributes - expect(assigns(:mapping)).to eq(mapping) + put :update, params: { + id: mapping.to_param, mapping: valid_attributes + } + expect(Mapping.last).to eq mapping end end context 'with invalid params' do it 'assigns the mapping as @mapping' do - put :update, - id: mapping.to_param, mapping: invalid_attributes - expect(assigns(:mapping)).to eq(mapping) + put :update, params: { + id: mapping.to_param, mapping: invalid_attributes + } + expect(Mapping.last).to eq mapping end end end @@ -67,7 +71,9 @@ RSpec.describe MappingsController, type: :controller do describe 'DELETE #destroy' do it 'destroys the requested mapping' do expect do - delete :destroy, id: mapping.to_param + delete :destroy, params: { + id: mapping.to_param + } end.to change(Mapping, :count).by(-1) end end diff --git a/spec/controllers/maps_controller_spec.rb b/spec/controllers/maps_controller_spec.rb index 60b52ec1..278ec559 100644 --- a/spec/controllers/maps_controller_spec.rb +++ b/spec/controllers/maps_controller_spec.rb @@ -5,50 +5,33 @@ RSpec.describe MapsController, type: :controller do let(:valid_attributes) { map.attributes.except(:id) } let(:invalid_attributes) { { permission: :commons } } before :each do - sign_in - end - - describe 'GET #index' do - it 'viewable maps as @maps' do - get :activemaps - expect(assigns(:maps)).to eq([map]) - end - end - - describe 'GET #contains' do - it 'returns json matching schema' do - get :contains, id: map.to_param, format: :json - expect(response.body).to match_json_schema(:map_contains) - end - end - - describe 'GET #show' do - it 'assigns the requested map as @map' do - get :show, id: map.to_param - expect(assigns(:map)).to eq(map) - end + sign_in create(:user) end describe 'POST #create' do context 'with valid params' do it 'creates a new Map' do - map.reload expect do - post :create, valid_attributes.merge(format: :json) + post :create, format: :json, params: { + map: valid_attributes + } end.to change(Map, :count).by(1) end it 'assigns a newly created map as @map' do - post :create, valid_attributes.merge(format: :json) - expect(assigns(:map)).to be_a(Map) - expect(assigns(:map)).to be_persisted + post :create, format: :json, params: { + map: valid_attributes + } + expect(Map.last).to eq map end end context 'with invalid params' do it 'assigns a newly created but unsaved map as @map' do - post :create, invalid_attributes.merge(format: :json) - expect(assigns(:map)).to be_a_new(Map) + post :create, format: :json, params: { + map: invalid_attributes + } + expect(Map.count).to eq 0 end end end @@ -58,24 +41,28 @@ RSpec.describe MapsController, type: :controller do let(:new_attributes) { { name: 'Uncool map', permission: :private } } it 'updates the requested map' do - put :update, - id: map.to_param, map: new_attributes, format: :json - expect(assigns(:map).name).to eq 'Uncool map' - expect(assigns(:map).permission).to eq 'private' + put :update, format: :json, params: { + id: map.to_param, map: new_attributes + } + map.reload + expect(map.name).to eq 'Uncool map' + expect(map.permission).to eq 'private' end it 'assigns the requested map as @map' do - put :update, - id: map.to_param, map: valid_attributes, format: :json - expect(assigns(:map)).to eq(map) + put :update, format: :json, params: { + id: map.to_param, map: valid_attributes + } + expect(Map.last).to eq map end end context 'with invalid params' do it 'assigns the map as @map' do - put :update, - id: map.to_param, map: invalid_attributes, format: :json - expect(assigns(:map)).to eq(map) + put :update, format: :json, params: { + id: map.to_param, map: invalid_attributes + } + expect(Map.last).to eq map end end end @@ -87,7 +74,9 @@ RSpec.describe MapsController, type: :controller do it 'prevents deletion by non-owners' do unowned_map.reload expect do - delete :destroy, id: unowned_map.to_param, format: :json + delete :destroy, format: :json, params: { + id: unowned_map.to_param + } end.to change(Map, :count).by(0) expect(response.body).to eq '' expect(response.status).to eq 403 @@ -96,7 +85,9 @@ RSpec.describe MapsController, type: :controller do it 'deletes owned map' do owned_map.reload # ensure it's in the database expect do - delete :destroy, id: owned_map.to_param, format: :json + delete :destroy, format: :json, params: { + id: owned_map.to_param + } end.to change(Map, :count).by(-1) expect(response.body).to eq '' expect(response.status).to eq 204 diff --git a/spec/controllers/metacodes_controller_spec.rb b/spec/controllers/metacodes_controller_spec.rb index 06434d49..cb4116d4 100644 --- a/spec/controllers/metacodes_controller_spec.rb +++ b/spec/controllers/metacodes_controller_spec.rb @@ -10,43 +10,33 @@ RSpec.describe MetacodesController, type: :controller do describe 'GET #index' do it 'assigns all metacodes as @metacodes' do metacode.reload # ensure it's created - get :index, {} + get :index expect(Metacode.all.to_a).to eq([metacode]) end end - describe 'GET #new' do - it 'assigns a new metacode as @metacode' do - get :new, format: :json - expect(assigns(:metacode)).to be_a_new(Metacode) - end - end - - describe 'GET #edit' do - it 'assigns the requested metacode as @metacode' do - get :edit, id: metacode.to_param - expect(assigns(:metacode)).to eq(metacode) - end - end - describe 'POST #create' do context 'with valid params' do it 'creates a new Metacode' do metacode.reload # ensure it's present to start expect do - post :create, metacode: valid_attributes + post :create, params: { + metacode: valid_attributes + } end.to change(Metacode, :count).by(1) end it 'has the correct attributes' do - post :create, metacode: valid_attributes - # expect(Metacode.last.attributes.expect(:id)).to eq(metacode.attributes.except(:id)) - expect(assigns(:metacode)).to be_a(Metacode) - expect(assigns(:metacode)).to be_persisted + post :create, params: { + metacode: valid_attributes + } + expect(comparable(Metacode.last)).to eq(comparable(metacode)) end it 'redirects to the metacode index' do - post :create, metacode: valid_attributes + post :create, params: { + metacode: valid_attributes + } expect(response).to redirect_to(metacodes_url) end end @@ -62,8 +52,9 @@ RSpec.describe MetacodesController, type: :controller do end it 'updates the requested metacode' do - put :update, - id: metacode.to_param, metacode: new_attributes + put :update, params: { + id: metacode.to_param, metacode: new_attributes + } metacode.reload expect(metacode.icon).to eq 'https://newimages.ca/cool-image.jpg' expect(metacode.color).to eq '#ffffff' @@ -75,13 +66,17 @@ RSpec.describe MetacodesController, type: :controller do context 'not admin' do it 'denies access to create' do sign_in create(:user, admin: false) - post :create, metacode: valid_attributes + post :create, params: { + metacode: valid_attributes + } expect(response).to redirect_to root_url end it 'denies access to update' do sign_in create(:user, admin: false) - post :update, id: metacode.to_param, metacode: valid_attributes + post :update, params: { + id: metacode.to_param, metacode: valid_attributes + } expect(response).to redirect_to root_url end end diff --git a/spec/controllers/synapses_controller_spec.rb b/spec/controllers/synapses_controller_spec.rb index 55b2addb..15d91250 100644 --- a/spec/controllers/synapses_controller_spec.rb +++ b/spec/controllers/synapses_controller_spec.rb @@ -5,14 +5,7 @@ RSpec.describe SynapsesController, type: :controller do let(:valid_attributes) { synapse.attributes.except('id') } let(:invalid_attributes) { { permission: :invalid_lol } } before :each do - sign_in - end - - describe 'GET #show' do - it 'assigns the requested synapse as @synapse' do - get :show, id: synapse.to_param, format: :json - expect(assigns(:synapse)).to eq(synapse) - end + sign_in create(:user) end describe 'POST #create' do @@ -20,25 +13,32 @@ RSpec.describe SynapsesController, type: :controller do it 'creates a new Synapse' do synapse.reload # ensure it's present expect do - post :create, synapse: valid_attributes, format: :json + post :create, format: :json, params: { + synapse: valid_attributes + } end.to change(Synapse, :count).by(1) end it 'assigns a newly created synapse as @synapse' do - post :create, synapse: valid_attributes, format: :json - expect(assigns(:synapse)).to be_a(Synapse) - expect(assigns(:synapse)).to be_persisted + post :create, format: :json, params: { + synapse: valid_attributes + } + expect(comparable(Synapse.last)).to eq comparable(synapse) end it 'returns 201 CREATED' do - post :create, synapse: valid_attributes, format: :json + post :create, format: :json, params: { + synapse: valid_attributes + } expect(response.status).to eq 201 end end context 'with invalid params' do it 'returns 422 UNPROCESSABLE ENTITY' do - post :create, synapse: invalid_attributes, format: :json + post :create, format: :json, params: { + synapse: invalid_attributes + } expect(response.status).to eq 422 end end @@ -53,8 +53,9 @@ RSpec.describe SynapsesController, type: :controller do end it 'updates the requested synapse' do - put :update, - id: synapse.to_param, synapse: new_attributes, format: :json + put :update, format: :json, params: { + id: synapse.to_param, synapse: new_attributes + } synapse.reload expect(synapse.desc).to eq 'My new description' expect(synapse.category).to eq 'both' @@ -62,17 +63,19 @@ RSpec.describe SynapsesController, type: :controller do end it 'returns 204 NO CONTENT' do - put :update, - id: synapse.to_param, synapse: valid_attributes, format: :json + put :update, format: :json, params: { + id: synapse.to_param, synapse: valid_attributes + } expect(response.status).to eq 204 end end context 'with invalid params' do it 'assigns the synapse as @synapse' do - put :update, - id: synapse.to_param, synapse: invalid_attributes, format: :json - expect(assigns(:synapse)).to eq(synapse) + put :update, format: :json, params: { + id: synapse.to_param, synapse: invalid_attributes + } + expect(Synapse.last).to eq synapse end end end @@ -83,12 +86,16 @@ RSpec.describe SynapsesController, type: :controller do it 'destroys the requested synapse' do synapse.reload # ensure it's present expect do - delete :destroy, id: synapse.to_param, format: :json + delete :destroy, format: :json, params: { + id: synapse.to_param + } end.to change(Synapse, :count).by(-1) end it 'returns 204 NO CONTENT' do - delete :destroy, id: synapse.to_param, format: :json + delete :destroy, format: :json, params: { + id: synapse.to_param + } expect(response.status).to eq 204 end end diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb index b6081701..315b931f 100644 --- a/spec/controllers/topics_controller_spec.rb +++ b/spec/controllers/topics_controller_spec.rb @@ -5,14 +5,7 @@ RSpec.describe TopicsController, type: :controller do let(:valid_attributes) { topic.attributes.except('id') } let(:invalid_attributes) { { permission: :invalid_lol } } before :each do - sign_in - end - - describe 'GET #show' do - it 'assigns the requested topic as @topic' do - get :show, id: topic.to_param, format: :json - expect(assigns(:topic)).to eq(topic) - end + sign_in create(:user) end describe 'POST #create' do @@ -20,26 +13,33 @@ RSpec.describe TopicsController, type: :controller do it 'creates a new Topic' do topic.reload # ensure it's created expect do - post :create, topic: valid_attributes, format: :json + post :create, format: :json, params: { + topic: valid_attributes + } end.to change(Topic, :count).by(1) end it 'assigns a newly created topic as @topic' do - post :create, topic: valid_attributes, format: :json - expect(assigns(:topic)).to be_a(Topic) - expect(assigns(:topic)).to be_persisted + post :create, format: :json, params: { + topic: valid_attributes + } + expect(comparable(Topic.last)).to eq comparable(topic) end it 'returns 201 CREATED' do - post :create, topic: valid_attributes, format: :json + post :create, format: :json, params: { + topic: valid_attributes + } expect(response.status).to eq 201 end end context 'with invalid params' do it 'assigns a newly created but unsaved topic as @topic' do - post :create, topic: invalid_attributes, format: :json - expect(assigns(:topic)).to be_a_new(Topic) + post :create, format: :json, params: { + topic: invalid_attributes + } + expect(Topic.count).to eq 0 end end end @@ -54,8 +54,9 @@ RSpec.describe TopicsController, type: :controller do end it 'updates the requested topic' do - put :update, - id: topic.to_param, topic: new_attributes, format: :json + put :update, format: :json, params: { + id: topic.to_param, topic: new_attributes + } topic.reload expect(topic.name).to eq 'Cool Topic with no number' expect(topic.desc).to eq 'This is a cool topic.' @@ -64,23 +65,26 @@ RSpec.describe TopicsController, type: :controller do end it 'assigns the requested topic as @topic' do - put :update, - id: topic.to_param, topic: valid_attributes, format: :json - expect(assigns(:topic)).to eq(topic) + put :update, format: :json, params: { + id: topic.to_param, topic: valid_attributes + } + expect(Topic.last).to eq(topic) end it 'returns status of no content' do - put :update, - id: topic.to_param, topic: valid_attributes, format: :json + put :update, format: :json, params: { + id: topic.to_param, topic: valid_attributes + } expect(response.status).to eq 204 end end context 'with invalid params' do it 'assigns the topic as @topic' do - put :update, - id: topic.to_param, topic: invalid_attributes, format: :json - expect(assigns(:topic)).to eq(topic) + put :update, format: :json, params: { + id: topic.to_param, topic: invalid_attributes + } + expect(Topic.last).to eq topic end end end @@ -90,7 +94,9 @@ RSpec.describe TopicsController, type: :controller do it 'destroys the requested topic' do owned_topic.reload # ensure it's there expect do - delete :destroy, id: owned_topic.to_param, format: :json + delete :destroy, format: :json, params: { + id: owned_topic.to_param + } end.to change(Topic, :count).by(-1) expect(response.body).to eq '' expect(response.status).to eq 204 diff --git a/spec/factories/maps.rb b/spec/factories/maps.rb index a786d109..14450c00 100644 --- a/spec/factories/maps.rb +++ b/spec/factories/maps.rb @@ -3,6 +3,7 @@ FactoryGirl.define do sequence(:name) { |n| "Cool Map ##{n}" } permission :commons arranged { false } + desc '' user end end diff --git a/spec/factories/synapses.rb b/spec/factories/synapses.rb index 4454a7a4..db82fc39 100644 --- a/spec/factories/synapses.rb +++ b/spec/factories/synapses.rb @@ -6,5 +6,6 @@ FactoryGirl.define do association :topic1, factory: :topic association :topic2, factory: :topic user + weight 1 # todo drop this column end end diff --git a/spec/factories/tokens.rb b/spec/factories/tokens.rb new file mode 100644 index 00000000..3970d76f --- /dev/null +++ b/spec/factories/tokens.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :token do + user + description '' + end +end diff --git a/spec/factories/topics.rb b/spec/factories/topics.rb index 17c69a25..f4c73f4c 100644 --- a/spec/factories/topics.rb +++ b/spec/factories/topics.rb @@ -1,8 +1,10 @@ FactoryGirl.define do factory :topic do - sequence(:name) { |n| "Cool Topic ##{n}" } - permission :commons user metacode + permission :commons + sequence(:name) { |n| "Cool Topic ##{n}" } + sequence(:desc) { |n| "topic desc #{n}" } + sequence(:link) { |n| "https://metamaps.cc/maps/#{n}" } end end diff --git a/spec/mailers/map_mailer_spec.rb b/spec/mailers/map_mailer_spec.rb deleted file mode 100644 index 9c398b20..00000000 --- a/spec/mailers/map_mailer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe MapMailer, type: :mailer do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 23f21101..d14d6dbe 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,45 +1,26 @@ -# This file is copied to spec/ when you run 'rails generate rspec:install' ENV['RAILS_ENV'] ||= 'test' +require 'spec_helper' require File.expand_path('../../config/environment', __FILE__) +require 'rspec/rails' # Prevent database truncation if the environment is production if Rails.env.production? abort('The Rails environment is running in production mode!') end -require 'spec_helper' -require 'rspec/rails' -# Add additional requires below this line. Rails is not loaded until this point! - # require all support files Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } +ActiveRecord::Migration.maintain_test_schema! + RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. config.use_transactional_fixtures = true - # RSpec Rails can automatically mix in different behaviours to your tests - # based on their file location, for example enabling you to call `get` and - # `post` in specs under `spec/controllers`. - # - # You can disable this behaviour by removing the line below, and instead - # explicitly tag your specs with their type, e.g.: - # - # RSpec.describe UsersController, :type => :controller do - # # ... - # end - # - # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! - config.include Devise::TestHelpers, type: :controller - config.include ControllerHelpers, type: :controller config.include Shoulda::Matchers::ActiveModel, type: :model config.include Shoulda::Matchers::ActiveRecord, type: :model end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d4028602..a2b164b2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,3 @@ -require 'simplecov' -require 'support/controller_helpers' -require 'pundit/rspec' - RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true diff --git a/spec/support/controller_helpers.rb b/spec/support/controller_helpers.rb index a8364f91..1672479f 100644 --- a/spec/support/controller_helpers.rb +++ b/spec/support/controller_helpers.rb @@ -3,24 +3,17 @@ require 'devise' module ControllerHelpers - # rubocop:disable Metrics/AbcSize - def sign_in(user = create(:user)) - if user.nil? # simulate unauthenticated - allow(request.env['warden']).to( - receive(:authenticate!).and_throw(:warden, scope: :user) - ) - else # simulate authenticated - allow_message_expectations_on_nil - allow(request.env['warden']).to( - receive(:authenticate!).and_return(user) - ) - end - allow(controller).to receive(:current_user).and_return(user) + extend ActiveSupport::Concern + + included do + include Devise::Test::ControllerHelpers + end + + def comparable(model) + model.attributes.except('id', 'created_at', 'updated_at') end - # rubocop:enable Metrics/AbcSize end RSpec.configure do |config| - config.include Devise::TestHelpers, type: :controller config.include ControllerHelpers, type: :controller end diff --git a/spec/support/pundit.rb b/spec/support/pundit.rb new file mode 100644 index 00000000..1fd8e296 --- /dev/null +++ b/spec/support/pundit.rb @@ -0,0 +1 @@ +require 'pundit/rspec' diff --git a/spec/support/schema_matcher.rb b/spec/support/schema_matcher.rb index b2a89352..207c5fa6 100644 --- a/spec/support/schema_matcher.rb +++ b/spec/support/schema_matcher.rb @@ -1,7 +1,32 @@ -RSpec::Matchers.define :match_json_schema do |schema| - match do |json| - schema_directory = Rails.root.join('spec', 'schemas').to_s - schema_path = "#{schema_directory}/#{schema}.json" - JSON::Validator.validate!(schema_path, json) +RSpec::Matchers.define :match_json_schema do |schema_name| + match do |response| + schema_directory = Rails.root.join('doc', 'api', 'schemas').to_s + schema = "#{schema_directory}/#{schema_name}.json" + + # schema customizations + schema = JSON.parse(File.read(schema)) + schema = update_file_refs(schema) + + data = JSON.parse(response.body) + JSON::Validator.validate!(schema, data, validate_schema: true) end end + +def get_json_example(resource) + filepath = "#{Rails.root}/doc/api/examples/#{resource}.json" + OpenStruct.new(body: File.read(filepath)) +end + +# add full paths to file references +def update_file_refs(schema) + schema.each_pair do |key, value| + schema[key] = if value.is_a? Hash + update_file_refs(value) + elsif key == '$ref' + "#{Rails.root}/doc/api/schemas/#{value}" + else + value + end + end + schema +end diff --git a/spec/support/simplecov.rb b/spec/support/simplecov.rb new file mode 100644 index 00000000..8017e897 --- /dev/null +++ b/spec/support/simplecov.rb @@ -0,0 +1,2 @@ +require 'simplecov' +