From 2e0acfc1709c5b4476c6f3caf1adbc8f35e2293a Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 12:04:31 -0500 Subject: [PATCH 01/58] update docs --- doc/production/first-deploy.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index b6eddd22..f90d1502 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -17,7 +17,7 @@ sudo apt-get install postgresql-9.4 #specify version!! sudo -u postgres psql postgres=# CREATE USER metamaps WITH PASSWORD 'mycoolpassword' CREATEDB; - postgres=# CREATE DATABASE metamap002_production OWNER metamaps; + postgres=# CREATE DATABASE metamaps_production OWNER metamaps; postgres=# \q #### Install system-wide rvm: @@ -68,7 +68,7 @@ Run this in the metamaps directory, still as metamaps: #### Precompile assets -This step depends on running npm install first; assets:precompile calls `npm install` and `bin/build-apidocs.sh`, both of which require node_modules to be installed. We suggest you run the commands separately this time to better catch any errors. +This step depends on running `npm install` (in the previous step) first. Note that `rails assets:precompile` will normally call `npm install` and `bin/build-apidocs.sh` as part of its process. Both of these latter commands require the node_modules to already be installed. We suggest you run the commands separately this time (like below) to better catch any errors. npm run build bin/build-apidocs.sh @@ -93,13 +93,14 @@ server to see what problems show up: #### Realtime server: sudo npm install -g forever - (crontab -u metamaps -l 2>/dev/null; echo "@reboot env NODE_REALTIME_PORT=5000 $(which forever) --append -l /home/metamaps/logs/forever.realtime.log start /home/metamaps/metamaps/realtime/realtime-server.js") | crontab -u metamaps - + (crontab -u metamaps -l 2>/dev/null; echo "@reboot NODE_REALTIME_PORT=5000 /usr/bin/forever --minUptime 1000 --spinSleepTime 1000 --append -l /home/metamaps/logs/forever.realtime.log -c /home/metamaps/metamaps.cc/node_modules/.bin/babel-node --workingDir /home/metamaps/metamaps.cc start /home/metamaps/metamaps.cc/realtime/realtime-server.js") | crontab -u metamaps mkdir -p /home/metamaps/logs - env NODE_REALTIME_PORT=5000 forever --append \ - -c /home/metamaps/metamaps/node_modules/.bin/babel-node \ - -l /home/metamaps/logs/forever.realtime.log \ - start /home/metamaps/metamaps/realtime/realtime-server.js + /usr/bin/forever --minUptime 1000 --spinSleepTime 1000 \ + --append -l /home/metamaps/logs/forever.realtime.log \ + -c /home/metamaps/metamaps.cc/node_modules/.bin/babel-node \ + --workingDir /home/metamaps/metamaps.cc \ + start /home/metamaps/metamaps.cc/realtime/realtime-server.js #### Upstart service for delayed_worker: From 6296df11020fc0b7fc04a2ce50314bade827e0a7 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:09:47 -0500 Subject: [PATCH 02/58] need postgres dev headers --- doc/production/first-deploy.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index f90d1502..19d2e386 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -14,7 +14,9 @@ #### Setup Postgres - sudo apt-get install postgresql-9.4 #specify version!! + sudo apt-get install postgresql-9.4 + # make sure you have development headers for postgres. The package name might be different on your distribution. + sudo apt-get install libpq-dev sudo -u postgres psql postgres=# CREATE USER metamaps WITH PASSWORD 'mycoolpassword' CREATEDB; postgres=# CREATE DATABASE metamaps_production OWNER metamaps; From b4bffbe427a87b909e415fc529e59e55a47dac13 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:10:09 -0500 Subject: [PATCH 03/58] database called metamaps, not metamap002 in example --- .example-env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.example-env b/.example-env index 96b60f55..03f7f615 100644 --- a/.example-env +++ b/.example-env @@ -6,7 +6,7 @@ export DB_USERNAME='postgres' export DB_PASSWORD='3112' export DB_HOST='localhost' export DB_PORT='5432' -export DB_NAME='metamap002' +export DB_NAME='metamaps' export REALTIME_SERVER='http://localhost:5000' export MAILER_DEFAULT_URL='localhost:3000' From 9223295320e67ebd391b032cad5abac910c1f434 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:14:39 -0500 Subject: [PATCH 04/58] add node source --- doc/production/first-deploy.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index 19d2e386..ac1d7111 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -64,6 +64,9 @@ Run this in the metamaps directory, still as metamaps: #### Install node & ES6 modules + # this first line lets us use up-to-date versions of node.js + # instead of the old versions in the Ubuntu repositories + curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - sudo aptitude install nodejs npm sudo ln -s /usr/bin/nodejs /usr/bin/node npm install From c57015cb15d4a88704820ef7b4ac60b47dee25ec Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:16:33 -0500 Subject: [PATCH 05/58] rvm install needs sudo --- doc/production/first-deploy.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index ac1d7111..0d12b216 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -40,8 +40,15 @@ rvm user gemsets git clone https://github.com/metamaps/metamaps \ --branch instance/mycoolinstance - rvm install $(cat metamaps/.ruby-version) #ensure ruby is installed - cd metamaps + cat metamaps/.ruby-version + +The last line tells you what version of ruby you need to install. For example, at the time of writing the version is 2.3.0. As your normal sudo-enabled user, run + + sudo rvm install 2.3.0 + +Now switch back to the metamaps user and continue + + cd /home/metamaps/metamaps gem install bundler RAILS_ENV=production bundle install From cd796f3ade1fcae9d5410776b9abe719ef6aadec Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:25:50 -0500 Subject: [PATCH 06/58] gist for unicode error on db:setup --- doc/production/first-deploy.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index 0d12b216..e8e5a306 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -22,6 +22,8 @@ postgres=# CREATE DATABASE metamaps_production OWNER metamaps; postgres=# \q +On some deploys, we have had problems with unicode encoding when trying to run `db:setup`. Running the commands in this Github gist resolved the issue: https://gist.github.com/amolkhanorkar/8706915. Try this link if you have problems + #### Install system-wide rvm: sudo gpg --keyserver hkp://keys.gnupg.net \ From 38004c1f1fd5d04d9750b170bc27a334ee4c5644 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:34:32 -0500 Subject: [PATCH 07/58] fix npm install isntructions --- doc/production/first-deploy.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index e8e5a306..b63da0af 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -73,17 +73,21 @@ Run this in the metamaps directory, still as metamaps: #### Install node & ES6 modules +Run these commands on your sudo-enabled account + # this first line lets us use up-to-date versions of node.js # instead of the old versions in the Ubuntu repositories curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - - sudo aptitude install nodejs npm + sudo aptitude install nodejs sudo ln -s /usr/bin/nodejs /usr/bin/node - npm install #### Precompile assets -This step depends on running `npm install` (in the previous step) first. Note that `rails assets:precompile` will normally call `npm install` and `bin/build-apidocs.sh` as part of its process. Both of these latter commands require the node_modules to already be installed. We suggest you run the commands separately this time (like below) to better catch any errors. +Run these commands as the metamaps user. +Note that `rails assets:precompile` will normally call `npm install` and `bin/build-apidocs.sh` as part of its process. Both of these latter commands require `npm install` to be run first. We suggest you run all five commands separately this time (like below) to better catch any errors. In the future, you won't need to run the second and third commands separately. + + npm install npm run build bin/build-apidocs.sh bundle exec rails assets:precompile From 991c4cabdbf4b43a3c21bb4976316eec14124f4c Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 13:40:48 -0500 Subject: [PATCH 08/58] move node installation further up --- doc/production/first-deploy.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index b63da0af..2fb6abfb 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -24,6 +24,15 @@ On some deploys, we have had problems with unicode encoding when trying to run `db:setup`. Running the commands in this Github gist resolved the issue: https://gist.github.com/amolkhanorkar/8706915. Try this link if you have problems +#### Install Node for javascript building + + # this first line lets us use up-to-date versions of node.js + # instead of the old versions in the Ubuntu repositories + curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - + sudo aptitude install nodejs + sudo ln -s /usr/bin/nodejs /usr/bin/node + + #### Install system-wide rvm: sudo gpg --keyserver hkp://keys.gnupg.net \ @@ -71,20 +80,8 @@ Run this in the metamaps directory, still as metamaps: # create, load schema, seed bundle exec rails db:setup -#### Install node & ES6 modules - -Run these commands on your sudo-enabled account - - # this first line lets us use up-to-date versions of node.js - # instead of the old versions in the Ubuntu repositories - curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - - sudo aptitude install nodejs - sudo ln -s /usr/bin/nodejs /usr/bin/node - #### Precompile assets -Run these commands as the metamaps user. - Note that `rails assets:precompile` will normally call `npm install` and `bin/build-apidocs.sh` as part of its process. Both of these latter commands require `npm install` to be run first. We suggest you run all five commands separately this time (like below) to better catch any errors. In the future, you won't need to run the second and third commands separately. npm install From 36ed85312e45da81b4a609d1994f7415a28cdf75 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 16:29:52 -0500 Subject: [PATCH 09/58] fix crontab --- doc/production/first-deploy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index 2fb6abfb..8310f521 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -108,14 +108,14 @@ server to see what problems show up: #### Realtime server: sudo npm install -g forever - (crontab -u metamaps -l 2>/dev/null; echo "@reboot NODE_REALTIME_PORT=5000 /usr/bin/forever --minUptime 1000 --spinSleepTime 1000 --append -l /home/metamaps/logs/forever.realtime.log -c /home/metamaps/metamaps.cc/node_modules/.bin/babel-node --workingDir /home/metamaps/metamaps.cc start /home/metamaps/metamaps.cc/realtime/realtime-server.js") | crontab -u metamaps + (sudo crontab -u metamaps -l 2>/dev/null; echo "@reboot NODE_REALTIME_PORT=5000 /usr/bin/forever --minUptime 1000 --spinSleepTime 1000 --append -l /home/metamaps/logs/forever.realtime.log -c /home/metamaps/metamaps/node_modules/.bin/babel-node --workingDir /home/metamaps/metamaps start /home/metamaps/metamaps/realtime/realtime-server.js") | sudo crontab -u metamaps mkdir -p /home/metamaps/logs /usr/bin/forever --minUptime 1000 --spinSleepTime 1000 \ --append -l /home/metamaps/logs/forever.realtime.log \ - -c /home/metamaps/metamaps.cc/node_modules/.bin/babel-node \ - --workingDir /home/metamaps/metamaps.cc \ - start /home/metamaps/metamaps.cc/realtime/realtime-server.js + -c /home/metamaps/metamaps/node_modules/.bin/babel-node \ + --workingDir /home/metamaps/metamaps \ + start /home/metamaps/metamaps/realtime/realtime-server.js #### Upstart service for delayed_worker: From 460de840b63f042e36112bbc04483e14f5238b08 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Wed, 18 Jan 2017 16:38:34 -0500 Subject: [PATCH 10/58] redis server --- doc/production/first-deploy.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/production/first-deploy.md b/doc/production/first-deploy.md index 8310f521..44b6b659 100644 --- a/doc/production/first-deploy.md +++ b/doc/production/first-deploy.md @@ -29,9 +29,12 @@ On some deploys, we have had problems with unicode encoding when trying to run ` # this first line lets us use up-to-date versions of node.js # instead of the old versions in the Ubuntu repositories curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - - sudo aptitude install nodejs + sudo apt-get install nodejs sudo ln -s /usr/bin/nodejs /usr/bin/node +### Install redis server for action cable + + sudo apt-get install redis-server #### Install system-wide rvm: From a9f19815e4688bb05f5013185f5e460648fdf73b Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Thu, 19 Jan 2017 14:49:40 -0500 Subject: [PATCH 11/58] fix api embed to use the correct serializers (fix #998) (#1029) * use correct serializer for singular embeds in api (almost fixes #998) * fix has_many api embeds too! * unused arg --- .../api/v2/application_serializer.rb | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/serializers/api/v2/application_serializer.rb b/app/serializers/api/v2/application_serializer.rb index 4345c941..81772577 100644 --- a/app/serializers/api/v2/application_serializer.rb +++ b/app/serializers/api/v2/application_serializer.rb @@ -35,13 +35,29 @@ module Api Pundit.policy_scope(scope[:current_user], object.send(attr))&.map(&:id) || [] end has_many(attr, opts.merge(if: -> { embeds.include?(key) })) do - Pundit.policy_scope(scope[:current_user], object.send(attr)) || [] + list = Pundit.policy_scope(scope[:current_user], object.send(attr)) || [] + child_serializer = "Api::V2::#{attr.to_s.singularize.camelize}Serializer".constantize + resource = ActiveModelSerializers::SerializableResource.new( + list, + each_serializer: child_serializer, + scope: scope.merge(embeds: []) + ) + resource.as_json end 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) })) + attribute(key, opts.merge(if: -> { embeds.include?(key) })) do |serializer| + object = serializer.object.send(key) + child_serializer = "Api::V2::#{object.class.name}Serializer".constantize + resource = ActiveModelSerializers::SerializableResource.new( + object, + serializer: child_serializer, + scope: scope.merge(embeds: []) + ) + resource.as_json + end end end end From af2c6ebef169dcdcf5b4e3a95db4afa5f259cc09 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Thu, 19 Jan 2017 14:50:08 -0500 Subject: [PATCH 12/58] split screenshot function/button into two parts (#1027) * split screenshot function into 4 separate helpers * screenshot download button in import dialog box * thumbnail button inside map info box * import blue button styling * fight with styling to make the button at least appear * add more text * fix tooltip display * automatically start downloading the screenshot * eslint * revamp GlobalUI.notifyUser * fix object destructuring syntax * fix --- app/assets/stylesheets/application.scss.erb | 38 +++++++++ app/views/layouts/_templates.html.erb | 5 ++ app/views/maps/_mapinfobox.html.erb | 5 ++ .../src/Metamaps/GlobalUI/ImportDialog.js | 10 ++- frontend/src/Metamaps/GlobalUI/index.js | 44 ++++++++--- frontend/src/Metamaps/Map/InfoBox.js | 5 +- frontend/src/Metamaps/Map/index.js | 77 ++++++++++++------- frontend/src/Metamaps/Realtime/receivable.js | 8 +- frontend/src/components/ImportDialogBox.js | 6 +- 9 files changed, 153 insertions(+), 45 deletions(-) diff --git a/app/assets/stylesheets/application.scss.erb b/app/assets/stylesheets/application.scss.erb index 988b8241..35665918 100644 --- a/app/assets/stylesheets/application.scss.erb +++ b/app/assets/stylesheets/application.scss.erb @@ -1558,6 +1558,7 @@ h3.filterBox { box-sizing: border-box; margin: 0.75em; padding: 0.75em; + padding-top: 0.85em; height: 3em; background-color: #AAB0FB; border-radius: 0.3em; @@ -2051,6 +2052,43 @@ and it won't be important on password protected instances */ .yourMap .mapInfoDelete { display: block; } + +.mapInfoButtonsWrapper .mapInfoThumbnail { + display: block; + background-image: url(<%= asset_path('screenshot_sprite.png') %>); + width: 32px; + height: 32px; + + & > span { + bottom: -9px; + right: 3px; + font-size: 10px; + color: #eee; + + &:hover { + color: white; + } + } + + .tooltip { + display: none; + } + + &:hover { + background-position: -32px 0; + + .tooltip { + display: block; + position: absolute; + bottom: 30px; + background: black; + color: white; + border-radius: 2px; + padding: 3px 5px 2px 5px; + } + } +} + .mapInfoButtonsWrapper span { position: absolute; width: 100%; diff --git a/app/views/layouts/_templates.html.erb b/app/views/layouts/_templates.html.erb index efb3ed68..4fbbd12d 100644 --- a/app/views/layouts/_templates.html.erb +++ b/app/views/layouts/_templates.html.erb @@ -34,6 +34,11 @@

Created by: {{user_name}} on {{created_at}}

Last edited: {{updated_at}}

+
+
+
Update Thumbnail
+ Thumb +
Delete diff --git a/app/views/maps/_mapinfobox.html.erb b/app/views/maps/_mapinfobox.html.erb index 650125ee..9ded6a02 100644 --- a/app/views/maps/_mapinfobox.html.erb +++ b/app/views/maps/_mapinfobox.html.erb @@ -77,6 +77,11 @@

Created by: <%= @map.user == user ? "You" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %>

Last edited: <%= @map.updated_at.strftime("%m/%d/%Y") %>

+
+
+
Update Thumbnail
+ Thumb +
Delete diff --git a/frontend/src/Metamaps/GlobalUI/ImportDialog.js b/frontend/src/Metamaps/GlobalUI/ImportDialog.js index dfc319b7..1428ab6d 100644 --- a/frontend/src/Metamaps/GlobalUI/ImportDialog.js +++ b/frontend/src/Metamaps/GlobalUI/ImportDialog.js @@ -7,6 +7,7 @@ import outdent from 'outdent' import ImportDialogBox from '../../components/ImportDialogBox' import PasteInput from '../PasteInput' +import Map from '../Map' const ImportDialog = { openLightbox: null, @@ -24,14 +25,19 @@ const ImportDialog = { `)) ReactDOM.render(React.createElement(ImportDialogBox, { onFileAdded: PasteInput.handleFile, - exampleImageUrl: serverData['import-example.png'] + exampleImageUrl: serverData['import-example.png'], + downloadScreenshot: ImportDialog.downloadScreenshot }), $('.importDialogWrapper').get(0)) }, show: function() { ImportDialog.openLightbox('import-dialog') }, hide: function() { - ImportDialog.closeLightbox('import-dialog') + ImportDialog.closeLightbox() + }, + downloadScreenshot: function() { + ImportDialog.hide() + Map.offerScreenshotDownload() } } diff --git a/frontend/src/Metamaps/GlobalUI/index.js b/frontend/src/Metamaps/GlobalUI/index.js index 932e3319..a1d2bbff 100644 --- a/frontend/src/Metamaps/GlobalUI/index.js +++ b/frontend/src/Metamaps/GlobalUI/index.js @@ -12,9 +12,11 @@ import NotificationIcon from './NotificationIcon' const GlobalUI = { notifyTimeout: null, + notifyQueue: [], + notifying: false, lightbox: null, init: function(serverData) { - var self = GlobalUI + const self = GlobalUI self.Search.init(serverData) self.CreateMap.init(serverData) @@ -45,7 +47,7 @@ const GlobalUI = { }, 200, 'easeInCubic', function() { $(this).hide() }) }, openLightbox: function(which) { - var self = GlobalUI + const self = GlobalUI $('.lightboxContent').hide() $('#' + which).show() @@ -72,7 +74,7 @@ const GlobalUI = { }, closeLightbox: function(event) { - var self = GlobalUI + const self = GlobalUI if (event) event.preventDefault() @@ -96,23 +98,45 @@ const GlobalUI = { } self.lightbox = null }, - notifyUser: function(message, leaveOpen) { - var self = GlobalUI + notifyUser: function(message, opts = {}) { + const self = GlobalUI + + if (self.notifying) { + self.notifyQueue.push({ message, opts }) + return + } else { + self._notifyUser(message, opts) + } + }, + // note: use the wrapper function notifyUser instead of this one + _notifyUser: function(message, opts = {}) { + const self = GlobalUI + + const { leaveOpen = false, timeOut = 8000 } = opts $('#toast').html(message) self.showDiv('#toast') clearTimeout(self.notifyTimeOut) + if (!leaveOpen) { self.notifyTimeOut = setTimeout(function() { - self.hideDiv('#toast') - }, 8000) + GlobalUI.clearNotify() + }, timeOut) } + + self.notifying = true }, clearNotify: function() { - var self = GlobalUI + const self = GlobalUI - clearTimeout(self.notifyTimeOut) - self.hideDiv('#toast') + // if there are messages remaining, display them + if (self.notifyQueue.length > 0) { + const { message, opts } = self.notifyQueue.shift() + self._notifyUser(message, opts) + } else { + self.hideDiv('#toast') + self.notifying = false + } }, shareInvite: function(inviteLink) { clipboard.copy({ diff --git a/frontend/src/Metamaps/Map/InfoBox.js b/frontend/src/Metamaps/Map/InfoBox.js index 21d947ad..1949e96e 100644 --- a/frontend/src/Metamaps/Map/InfoBox.js +++ b/frontend/src/Metamaps/Map/InfoBox.js @@ -35,9 +35,11 @@ const InfoBox = { data-bip-value="{{desc}}" >{{desc}}`, userImageUrl: '', - init: function(serverData) { + init: function(serverData, updateThumbnail) { var self = InfoBox + self.updateThumbnail = updateThumbnail + $('.mapInfoIcon').click(self.toggleBox) $('.mapInfoBox').click(function(event) { event.stopPropagation() @@ -181,6 +183,7 @@ const InfoBox = { $('.mapInfoBox.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect) $('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap) + $('.mapInfoThumbnail').unbind().click(self.updateThumbnail) $('.mapContributors span, #mapContribs').unbind().click(function(event) { $('.mapContributors .tip').toggle() diff --git a/frontend/src/Metamaps/Map/index.js b/frontend/src/Metamaps/Map/index.js index 51038b87..3df5a3e2 100644 --- a/frontend/src/Metamaps/Map/index.js +++ b/frontend/src/Metamaps/Map/index.js @@ -45,7 +45,10 @@ const Map = { GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html() self.updateStar() - InfoBox.init(serverData) + + InfoBox.init(serverData, function updateThumbnail() { + self.uploadMapScreenshot() + }) CheatSheet.init(serverData) $('.viewOnly .requestAccess').click(self.requestAccess) @@ -251,6 +254,48 @@ const Map = { } }, exportImage: function() { + Map.uploadMapScreenshot() + Map.offerScreenshotDownload() + GlobalUI.notifyUser('Note: this button is going away. Check the map card or the import box for setting the map thumbnail or downloading a screenshot.') + }, + offerScreenshotDownload: () => { + const canvas = Map.getMapCanvasForScreenshots() + const filename = Map.getMapScreenshotFilename(Active.Map) + + var downloadMessage = outdent` + Captured map screenshot! + + DOWNLOAD + ` + GlobalUI.notifyUser(downloadMessage) + }, + uploadMapScreenshot: () => { + const canvas = Map.getMapCanvasForScreenshots() + const filename = Map.getMapScreenshotFilename(Active.Map) + + canvas.canvas.toBlob(imageBlob => { + const formData = new window.FormData() + formData.append('map[screenshot]', imageBlob, filename) + $.ajax({ + type: 'PATCH', + dataType: 'json', + url: `/maps/${Active.Map.id}`, + data: formData, + processData: false, + contentType: false, + success: function(data) { + GlobalUI.notifyUser('Successfully updated map screenshot.') + }, + error: function() { + GlobalUI.notifyUser('Failed to update map screenshot.') + } + }) + }) + }, + getMapCanvasForScreenshots: () => { var canvas = {} canvas.canvas = document.createElement('canvas') @@ -336,8 +381,9 @@ const Map = { node.visited = !T }) - var map = Active.Map - + return canvas + }, + getMapScreenshotFilename: map => { var today = new Date() var dd = today.getDate() var mm = today.getMonth() + 1 // January is 0! @@ -352,30 +398,7 @@ const Map = { var mapName = map.get('name').split(' ').join(['-']) const filename = `metamap-${map.id}-${mapName}-${today}.png` - - var downloadMessage = outdent` - Captured map screenshot! - DOWNLOAD` - GlobalUI.notifyUser(downloadMessage) - - canvas.canvas.toBlob(imageBlob => { - const formData = new window.FormData() - formData.append('map[screenshot]', imageBlob, filename) - $.ajax({ - type: 'PATCH', - dataType: 'json', - url: `/maps/${map.id}`, - data: formData, - processData: false, - contentType: false, - success: function(data) { - console.log('successfully uploaded map screenshot') - }, - error: function() { - console.log('failed to save map screenshot') - } - }) - }) + return filename } } diff --git a/frontend/src/Metamaps/Realtime/receivable.js b/frontend/src/Metamaps/Realtime/receivable.js index dd37fd99..f673d2e5 100644 --- a/frontend/src/Metamaps/Realtime/receivable.js +++ b/frontend/src/Metamaps/Realtime/receivable.js @@ -149,7 +149,7 @@ export const invitedToCall = self => inviter => { notifyText += username + ' is inviting you to a conversation. Join live?' notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.acceptCall(inviter)) $('#toast button.no').click(e => self.denyCall(inviter)) } @@ -162,7 +162,7 @@ export const invitedToJoin = self => inviter => { var notifyText = username + ' is inviting you to the conversation. Join?' notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => self.denyInvite(inviter)) } @@ -201,7 +201,7 @@ export const callInProgress = self => () => { var notifyText = "There's a conversation happening, want to join?" notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => GlobalUI.clearNotify()) ChatView.conversationInProgress() @@ -212,7 +212,7 @@ export const callStarted = self => () => { var notifyText = "There's a conversation starting, want to join?" notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => GlobalUI.clearNotify()) ChatView.conversationInProgress() diff --git a/frontend/src/components/ImportDialogBox.js b/frontend/src/components/ImportDialogBox.js index ddf81c38..85b3ee67 100644 --- a/frontend/src/components/ImportDialogBox.js +++ b/frontend/src/components/ImportDialogBox.js @@ -27,6 +27,9 @@ class ImportDialogBox extends Component {
Export as JSON
+
+ Download screenshot +

IMPORT

To upload a file, drop it here:

Date: Sat, 21 Jan 2017 13:04:28 -0500 Subject: [PATCH 13/58] mark v3.2 on develop --- config/initializers/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/version.rb b/config/initializers/version.rb index cccd43bf..a1e20598 100644 --- a/config/initializers/version.rb +++ b/config/initializers/version.rb @@ -1,4 +1,4 @@ # frozen_string_literal: true -METAMAPS_VERSION = '3.0.1' +METAMAPS_VERSION = '3.2' METAMAPS_BUILD = `git log -1 --pretty=%H`.chomp[0..11].freeze METAMAPS_LAST_UPDATED = `git log -1 --pretty='%ad'`.split(' ').values_at(1, 2, 4).join(' ').freeze From ba3d5f07ddf6b357471dc67d5d816ec4bb3e38d1 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 21 Jan 2017 13:09:26 -0500 Subject: [PATCH 14/58] try to fix metamaps.debug --- frontend/src/Metamaps/Debug.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/Metamaps/Debug.js b/frontend/src/Metamaps/Debug.js index 0fe5f769..1d1bfe71 100644 --- a/frontend/src/Metamaps/Debug.js +++ b/frontend/src/Metamaps/Debug.js @@ -1,6 +1,9 @@ -const Debug = (arg = window.Metamaps) => { +const Debug = function(arg = window.Metamaps) => { + if (arg === undefined && typeof window !== 'undefined') arg = window.Metamaps console.debug(arg) - console.debug(`Metamaps Version: ${arg.VERSION}`) + console.debug(`Metamaps Version: ${arg.ServerData.VERSION}`) + console.debug(`Build: ${arg.ServerData.BUILD}`) + console.debug(`Last Updated: ${arg.ServerData.LAST_UPDATED}`) } export default Debug From 1229e92feb98cdd65ccca58580beded0d7f92bca Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 21 Jan 2017 13:34:39 -0500 Subject: [PATCH 15/58] fix bug in Debug.js --- frontend/src/Metamaps/Debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Metamaps/Debug.js b/frontend/src/Metamaps/Debug.js index 1d1bfe71..2871ea4c 100644 --- a/frontend/src/Metamaps/Debug.js +++ b/frontend/src/Metamaps/Debug.js @@ -1,4 +1,4 @@ -const Debug = function(arg = window.Metamaps) => { +const Debug = function(arg = window.Metamaps) { if (arg === undefined && typeof window !== 'undefined') arg = window.Metamaps console.debug(arg) console.debug(`Metamaps Version: ${arg.ServerData.VERSION}`) From bba8231e8c954b8f272786a3b0664260bf343248 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 21 Jan 2017 15:37:14 -0500 Subject: [PATCH 16/58] update npm dependencies (#1038) * only one github dependency left * update npm deps * exact versions of npm deps --- package.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 56fc3545..01bd6f71 100644 --- a/package.json +++ b/package.json @@ -22,27 +22,27 @@ "dependencies": { "attachmediastream": "1.4.2", "autolinker": "1.4.0", - "babel-cli": "6.18.0", - "babel-loader": "6.2.9", - "babel-plugin-lodash": "3.2.10", - "babel-plugin-transform-class-properties": "6.19.0", - "babel-preset-es2015": "6.18.0", - "babel-preset-react": "6.16.0", + "babel-cli": "6.22.2", + "babel-loader": "6.2.10", + "babel-plugin-lodash": "3.2.11", + "babel-plugin-transform-class-properties": "6.22.0", + "babel-preset-es2015": "6.22.0", + "babel-preset-react": "6.22.0", "backbone": "1.0.0", "clipboard-js": "0.3.2", "commonmark": "0.27.0", - "csv-parse": "1.1.7", - "emoji-mart": "^0.3.5", - "getScreenMedia": "git://github.com/devvmh/getScreenMedia#patch-1", - "hark": "git://github.com/devvmh/hark#patch-1", + "csv-parse": "1.1.10", + "emoji-mart": "0.3.5", + "getscreenmedia": "2.0.0", + "hark": "git://github.com/otalk/hark#342ef9b7eff2", "howler": "2.0.2", "json-loader": "0.5.4", - "lodash": "4.17.2", + "lodash": "4.17.4", "node-uuid": "1.4.7", "outdent": "0.3.0", - "react": "15.4.1", - "react-dom": "15.4.1", - "react-dropzone": "3.7.3", + "react": "15.4.2", + "react-dom": "15.4.2", + "react-dropzone": "3.9.1", "redux": "3.6.0", "simplewebrtc": "2.2.1", "socket.io": "1.3.7", @@ -60,6 +60,6 @@ "mocha": "^3.2.0" }, "optionalDependencies": { - "raml2html": "4.0.1" + "raml2html": "4.0.5" } } From 2fd972ddce1ff4fd4a3a2ca2b89bbc0ddb00125c Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 22 Jan 2017 13:50:34 -0500 Subject: [PATCH 17/58] ajax queue (fixes #853) (#1037) * jquery.ajaxq * install jquery.ajaxq from npm * patch ajaxq into Backbone code * use ajaxq library with more github stars * eslint --- app/assets/javascripts/lib/ajaxq.js | 161 ++++++++++++++++++++++++++++ frontend/src/index.js | 7 +- package.json | 1 + 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/lib/ajaxq.js diff --git a/app/assets/javascripts/lib/ajaxq.js b/app/assets/javascripts/lib/ajaxq.js new file mode 100644 index 00000000..7e2c9e61 --- /dev/null +++ b/app/assets/javascripts/lib/ajaxq.js @@ -0,0 +1,161 @@ +// AjaxQ jQuery Plugin +// Copyright (c) 2012 Foliotek Inc. +// MIT License +// https://github.com/Foliotek/ajaxq +// Uses CommonJS, AMD or browser globals to create a jQuery plugin. + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + var queues = {}; + var activeReqs = {}; + + // Register an $.ajaxq function, which follows the $.ajax interface, but allows a queue name which will force only one request per queue to fire. + // opts can be the regular $.ajax settings plainObject, or a callback returning the settings object, to be evaluated just prior to the actual call to $.ajax. + $.ajaxq = function(qname, opts) { + + if (typeof opts === "undefined") { + throw ("AjaxQ: queue name is not provided"); + } + + // Will return a Deferred promise object extended with success/error/callback, so that this function matches the interface of $.ajax + var deferred = $.Deferred(), + promise = deferred.promise(); + + promise.success = promise.done; + promise.error = promise.fail; + promise.complete = promise.always; + + // Check whether options are to be evaluated at call time or not. + var deferredOpts = typeof opts === 'function'; + // Create a deep copy of the arguments, and enqueue this request. + var clonedOptions = !deferredOpts ? $.extend(true, {}, opts) : null; + enqueue(function() { + // Send off the ajax request now that the item has been removed from the queue + var jqXHR = $.ajax.apply(window, [deferredOpts ? opts() : clonedOptions]); + + // Notify the returned deferred object with the correct context when the jqXHR is done or fails + // Note that 'always' will automatically be fired once one of these are called: http://api.jquery.com/category/deferred-object/. + jqXHR.done(function() { + deferred.resolve.apply(this, arguments); + }); + jqXHR.fail(function() { + deferred.reject.apply(this, arguments); + }); + + jqXHR.always(dequeue); // make sure to dequeue the next request AFTER the done and fail callbacks are fired + + return jqXHR; + }); + + return promise; + + + // If there is no queue, create an empty one and instantly process this item. + // Otherwise, just add this item onto it for later processing. + function enqueue(cb) { + if (!queues[qname]) { + queues[qname] = []; + var xhr = cb(); + activeReqs[qname] = xhr; + } + else { + queues[qname].push(cb); + } + } + + // Remove the next callback from the queue and fire it off. + // If the queue was empty (this was the last item), delete it from memory so the next one can be instantly processed. + function dequeue() { + if (!queues[qname]) { + return; + } + var nextCallback = queues[qname].shift(); + if (nextCallback) { + var xhr = nextCallback(); + activeReqs[qname] = xhr; + } + else { + delete queues[qname]; + delete activeReqs[qname]; + } + } + }; + + // Register a $.postq and $.getq method to provide shortcuts for $.get and $.post + // Copied from jQuery source to make sure the functions share the same defaults as $.get and $.post. + $.each( [ "getq", "postq" ], function( i, method ) { + $[ method ] = function( qname, url, data, callback, type ) { + + if ( $.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return $.ajaxq(qname, { + type: method === "postq" ? "post" : "get", + url: url, + data: data, + success: callback, + dataType: type + }); + }; + }); + + var isQueueRunning = function(qname) { + return (queues.hasOwnProperty(qname) && queues[qname].length > 0) || activeReqs.hasOwnProperty(qname); + }; + + var isAnyQueueRunning = function() { + for (var i in queues) { + if (isQueueRunning(i)) return true; + } + return false; + }; + + $.ajaxq.isRunning = function(qname) { + if (qname) return isQueueRunning(qname); + else return isAnyQueueRunning(); + }; + + $.ajaxq.getActiveRequest = function(qname) { + if (!qname) throw ("AjaxQ: queue name is required"); + + return activeReqs[qname]; + }; + + $.ajaxq.abort = function(qname) { + if (!qname) throw ("AjaxQ: queue name is required"); + + var current = $.ajaxq.getActiveRequest(qname); + delete queues[qname]; + delete activeReqs[qname]; + if (current) current.abort(); + }; + + $.ajaxq.clear = function(qname) { + if (!qname) { + for (var i in queues) { + if (queues.hasOwnProperty(i)) { + queues[i] = []; + } + } + } + else { + if (queues[qname]) { + queues[qname] = []; + } + } + }; + +})); diff --git a/frontend/src/index.js b/frontend/src/index.js index 1d82af7c..b796a5d1 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -1,6 +1,11 @@ -// create global references +// make changes to Backbone before loading Metamaps code +import Backbone from 'backbone' +try { Backbone.$ = window.$ } catch (err) {} +Backbone.ajax = (opts) => window.$.ajaxq('backbone-ajaxq', opts) + import _ from 'lodash' import Metamaps from './Metamaps' +// create global references window._ = _ window.Metamaps = Metamaps diff --git a/package.json b/package.json index 01bd6f71..8fadc91c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "homepage": "https://github.com/metamaps/metamaps#readme", "dependencies": { + "ajaxq": "0.0.7", "attachmediastream": "1.4.2", "autolinker": "1.4.0", "babel-cli": "6.22.2", From dc8d2744879bece6a053328132b19b8054c628d4 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 22 Jan 2017 14:07:04 -0500 Subject: [PATCH 18/58] whoops, I guess we do need jquery in package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8fadc91c..88005f30 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "getscreenmedia": "2.0.0", "hark": "git://github.com/otalk/hark#342ef9b7eff2", "howler": "2.0.2", + "jquery": "1.12.4", "json-loader": "0.5.4", "lodash": "4.17.4", "node-uuid": "1.4.7", From 2652d53e9b1dee3bcb4c5586e744d17da8c72826 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 22 Jan 2017 16:41:51 -0500 Subject: [PATCH 19/58] update ruby dependencies too (#1042) * update rubygem dependencies * update backbone * brakeman fix * brakeman * ugh syntax fix --- Gemfile.lock | 201 ++++++++++--------- app/assets/javascripts/application.js | 2 +- app/controllers/api/v2/restful_controller.rb | 1 + package.json | 8 +- 4 files changed, 113 insertions(+), 99 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2397c647..fd414eb2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,57 +1,60 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.0.0.1) - actionpack (= 5.0.0.1) + actioncable (5.0.1) + actionpack (= 5.0.1) nio4r (~> 1.2) websocket-driver (~> 0.6.1) - actionmailer (5.0.0.1) - actionpack (= 5.0.0.1) - actionview (= 5.0.0.1) - activejob (= 5.0.0.1) + actionmailer (5.0.1) + actionpack (= 5.0.1) + actionview (= 5.0.1) + activejob (= 5.0.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.0.1) - actionview (= 5.0.0.1) - activesupport (= 5.0.0.1) + actionpack (5.0.1) + actionview (= 5.0.1) + activesupport (= 5.0.1) rack (~> 2.0) rack-test (~> 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.0.1) - activesupport (= 5.0.0.1) + actionview (5.0.1) + activesupport (= 5.0.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - active_model_serializers (0.10.2) + active_model_serializers (0.10.4) actionpack (>= 4.1, < 6) activemodel (>= 4.1, < 6) - jsonapi (~> 0.1.1.beta2) - railties (>= 4.1, < 6) - activejob (5.0.0.1) - activesupport (= 5.0.0.1) + case_transform (>= 0.2) + jsonapi (= 0.1.1.beta6) + activejob (5.0.1) + activesupport (= 5.0.1) globalid (>= 0.3.6) - activemodel (5.0.0.1) - activesupport (= 5.0.0.1) - activerecord (5.0.0.1) - activemodel (= 5.0.0.1) - activesupport (= 5.0.0.1) + activemodel (5.0.1) + activesupport (= 5.0.1) + activerecord (5.0.1) + activemodel (= 5.0.1) + activesupport (= 5.0.1) arel (~> 7.0) - activesupport (5.0.0.1) + activesupport (5.0.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.3.8) - arel (7.1.2) + addressable (2.5.0) + public_suffix (~> 2.0, >= 2.0.2) + arel (7.1.4) ast (2.3.0) - aws-sdk (2.6.3) - aws-sdk-resources (= 2.6.3) - aws-sdk-core (2.6.3) + aws-sdk (2.7.0) + aws-sdk-resources (= 2.7.0) + aws-sdk-core (2.7.0) + aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.6.3) - aws-sdk-core (= 2.6.3) + aws-sdk-resources (2.7.0) + aws-sdk-core (= 2.7.0) + aws-sigv4 (1.0.0) bcrypt (3.1.11) best_in_place (3.1.0) actionpack (>= 3.2) @@ -62,21 +65,20 @@ GEM rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - brakeman (3.4.0) - builder (3.2.2) - byebug (9.0.5) - carrierwave (0.11.2) - activemodel (>= 3.2.0) - activesupport (>= 3.2.0) - json (>= 1.7) + brakeman (3.4.1) + builder (3.2.3) + byebug (9.0.6) + carrierwave (1.0.0) + activemodel (>= 4.0.0) + activesupport (>= 4.0.0) mime-types (>= 1.16) - mimemagic (>= 0.3.0) - climate_control (0.0.3) - activesupport (>= 3.0) + case_transform (0.2) + activesupport + climate_control (0.1.0) cocaine (0.5.8) climate_control (>= 0.0.3, < 1.0) coderay (1.1.1) - concurrent-ruby (1.0.2) + concurrent-ruby (1.0.4) debug_inspector (0.0.2) delayed_job (4.1.2) activesupport (>= 3.0, < 5.1) @@ -89,23 +91,23 @@ GEM railties (>= 4.1.0, < 5.1) responders warden (~> 1.2.3) - diff-lcs (1.2.5) + diff-lcs (1.3) docile (1.1.5) doorkeeper (4.2.0) railties (>= 4.2) - dotenv (2.1.1) - dotenv-rails (2.1.1) - dotenv (= 2.1.1) - railties (>= 4.0, < 5.1) + dotenv (2.1.2) + dotenv-rails (2.1.2) + dotenv (= 2.1.2) + railties (>= 3.2, < 5.1) erubis (2.7.0) exception_notification (4.2.1) actionmailer (>= 4.0, < 6) activesupport (>= 4.0, < 6) execjs (2.7.0) - factory_girl (4.7.0) + factory_girl (4.8.0) activesupport (>= 3.0.0) - factory_girl_rails (4.7.0) - factory_girl (~> 4.7.0) + factory_girl_rails (4.8.0) + factory_girl (~> 4.8.0) railties (>= 3.0.0) globalid (0.3.7) activesupport (>= 4.1.0) @@ -113,20 +115,32 @@ GEM multi_xml (>= 0.5.2) i18n (0.7.0) jmespath (1.3.1) - jquery-rails (4.2.1) + jquery-rails (4.2.2) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jquery-ui-rails (5.0.5) + jquery-ui-rails (6.0.1) railties (>= 3.2.16) - 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) + json (2.0.3) + json-schema (2.7.0) + addressable (>= 2.4) + jsonapi (0.1.1.beta6) + jsonapi-parser (= 0.1.1.beta3) + jsonapi-renderer (= 0.1.1.beta1) + jsonapi-parser (0.1.1.beta3) + jsonapi-renderer (0.1.1.beta1) + kaminari (1.0.1) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.0.1) + kaminari-activerecord (= 1.0.1) + kaminari-core (= 1.0.1) + kaminari-actionview (1.0.1) + actionview + kaminari-core (= 1.0.1) + kaminari-activerecord (1.0.1) + activerecord + kaminari-core (= 1.0.1) + kaminari-core (1.0.1) loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.4) @@ -140,12 +154,11 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_portile2 (2.1.0) - minitest (5.9.1) - multi_xml (0.5.5) + minitest (5.10.1) + multi_xml (0.6.0) nio4r (1.2.1) - nokogiri (1.6.8) + nokogiri (1.7.0.1) mini_portile2 (~> 2.1.0) - pkg-config (~> 1.1.7) orm_adapter (0.5.0) paperclip (5.1.0) activemodel (>= 4.2.0) @@ -153,20 +166,20 @@ GEM cocaine (~> 0.5.5) mime-types mimemagic (~> 0.3.0) - parser (2.3.1.4) + parser (2.3.3.1) ast (~> 2.2) pg (0.19.0) - pkg-config (1.1.7) powerpack (0.1.1) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - pry-byebug (3.4.0) + pry-byebug (3.4.2) byebug (~> 9.0) pry (~> 0.10) pry-rails (0.3.4) pry (>= 0.9.10) + public_suffix (2.0.5) puma (3.6.2) pundit (1.1.0) activesupport (>= 3.0.0) @@ -177,35 +190,35 @@ GEM rack-cors (0.4.0) rack-test (0.6.3) rack (>= 1.0) - rails (5.0.0.1) - actioncable (= 5.0.0.1) - actionmailer (= 5.0.0.1) - actionpack (= 5.0.0.1) - actionview (= 5.0.0.1) - activejob (= 5.0.0.1) - activemodel (= 5.0.0.1) - activerecord (= 5.0.0.1) - activesupport (= 5.0.0.1) + rails (5.0.1) + actioncable (= 5.0.1) + actionmailer (= 5.0.1) + actionpack (= 5.0.1) + actionview (= 5.0.1) + activejob (= 5.0.1) + activemodel (= 5.0.1) + activerecord (= 5.0.1) + activesupport (= 5.0.1) bundler (>= 1.3.0, < 2.0) - railties (= 5.0.0.1) + railties (= 5.0.1) sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.1) + rails-dom-testing (2.0.2) activesupport (>= 4.2.0, < 6.0) - nokogiri (~> 1.6.0) + nokogiri (~> 1.6) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (5.0.0.1) - actionpack (= 5.0.0.1) - activesupport (= 5.0.0.1) + railties (5.0.1) + actionpack (= 5.0.1) + activesupport (= 5.0.1) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.1.0) - rake (11.3.0) - redis (3.3.1) + rainbow (2.2.1) + rake (12.0.0) + redis (3.3.2) responders (2.3.0) railties (>= 4.2.0, < 5.1) - rspec-core (3.5.3) + rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) @@ -222,14 +235,14 @@ GEM rspec-mocks (~> 3.5.0) rspec-support (~> 3.5.0) rspec-support (3.5.0) - rubocop (0.43.0) - parser (>= 2.3.1.1, < 3.0) + rubocop (0.47.1) + parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-progressbar (1.8.1) - sass (3.4.22) + sass (3.4.23) sass-rails (5.0.6) railties (>= 4.0.0, < 6) sass (~> 3.1) @@ -243,11 +256,11 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) - slack-notifier (1.5.1) + slack-notifier (2.0.0) slop (3.6.0) snorlax (0.1.6) rails (> 4.1) - sprockets (3.7.0) + sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.0) @@ -256,15 +269,15 @@ GEM sprockets (>= 3.0.0) sucker_punch (2.0.2) concurrent-ruby (~> 1.0.0) - thor (0.19.1) + thor (0.19.4) thread_safe (0.3.5) tilt (2.0.5) - tunemygc (1.0.68) + tunemygc (1.0.69) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.2) + uglifier (3.0.4) execjs (>= 0.3.0, < 3) - unicode-display_width (1.1.1) + unicode-display_width (1.1.3) warden (1.2.6) rack (>= 1.0) websocket-driver (0.6.4) @@ -321,4 +334,4 @@ RUBY VERSION ruby 2.3.0p0 BUNDLED WITH - 1.13.6 + 1.13.7 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 6af52fbd..4483452c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,7 +11,7 @@ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // -//= require jquery +//= require jquery3 //= require jquery-ui //= require jquery_ujs //= require action_cable diff --git a/app/controllers/api/v2/restful_controller.rb b/app/controllers/api/v2/restful_controller.rb index 08177ad7..4d122bc8 100644 --- a/app/controllers/api/v2/restful_controller.rb +++ b/app/controllers/api/v2/restful_controller.rb @@ -5,6 +5,7 @@ module Api include Pundit include PunditExtra + protect_from_forgery with: :exception snorlax_used_rest! before_action :load_resource, only: [:show, :update, :destroy] diff --git a/package.json b/package.json index 88005f30..104bcc5e 100644 --- a/package.json +++ b/package.json @@ -29,15 +29,15 @@ "babel-plugin-transform-class-properties": "6.22.0", "babel-preset-es2015": "6.22.0", "babel-preset-react": "6.22.0", - "backbone": "1.0.0", + "backbone": "1.3.3", "clipboard-js": "0.3.2", "commonmark": "0.27.0", "csv-parse": "1.1.10", - "emoji-mart": "0.3.5", + "emoji-mart": "0.3.7", "getscreenmedia": "2.0.0", "hark": "git://github.com/otalk/hark#342ef9b7eff2", "howler": "2.0.2", - "jquery": "1.12.4", + "jquery": "3.1.1", "json-loader": "0.5.4", "lodash": "4.17.4", "node-uuid": "1.4.7", @@ -46,7 +46,7 @@ "react-dom": "15.4.2", "react-dropzone": "3.9.1", "redux": "3.6.0", - "simplewebrtc": "2.2.1", + "simplewebrtc": "2.2.2", "socket.io": "1.3.7", "webpack": "1.14.0" }, From d11278b63bebffb9cecbc68d34195432fa9db7ff Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 22 Jan 2017 16:42:04 -0500 Subject: [PATCH 20/58] map rdf export (fixes #1015) (#1036) * simple rdf export of maps * register ttl mime type * owl * mm * fix up export service * implement base url thing whoo * add more rdf fields * fix rdf syntax errors * hide unused fields in rdf * some code climate fixes * update ontology a bit more * syntax fix * typo --- app/controllers/maps_controller.rb | 5 +++- app/models/synapse.rb | 12 +++++++++ app/models/topic.rb | 13 ++++++++++ app/models/user.rb | 11 ++++++++ app/services/map_export_service.rb | 25 +++++++++++++++++-- config/initializers/mime_types.rb | 3 +++ public/owl/map.owl.ttl | 40 ++++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 public/owl/map.owl.ttl diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb index 189ae550..6e4a9486 100644 --- a/app/controllers/maps_controller.rb +++ b/app/controllers/maps_controller.rb @@ -20,6 +20,7 @@ class MapsController < ApplicationController end format.json { render json: @map } format.csv { redirect_to action: :export, format: :csv } + format.ttl { redirect_to action: :export, format: :ttl } end end @@ -90,10 +91,12 @@ class MapsController < ApplicationController # GET maps/:id/export def export - exporter = MapExportService.new(current_user, @map) + exporter = MapExportService.new(current_user, @map, base_url: request.base_url) + respond_to do |format| format.json { render json: exporter.json } format.csv { send_data exporter.csv } + format.ttl { render text: exporter.rdf } end end diff --git a/app/models/synapse.rb b/app/models/synapse.rb index be57dde1..d6d08bbe 100644 --- a/app/models/synapse.rb +++ b/app/models/synapse.rb @@ -51,6 +51,18 @@ class Synapse < ApplicationRecord super(methods: [:user_name, :user_image, :collaborator_ids]) end + def as_rdf + output = '' + output += %(d:synapse_#{id} a mm:Synapse ;\n) + output += %( mm:topic1 d:topic_#{topic1_id} ;\n) + output += %( mm:topic2 d:topic_#{topic2_id} ;\n) + output += %( mm:direction "#{category}" ;\n) + output += %( rdfs:comment "#{desc}" ;\n) if desc.present? + output[-2] = '.' + output += %(\n) + output + end + def after_updated attrs = ['desc', 'category', 'permission', 'defer_to_map_id'] if attrs.any? {|k| changed_attributes.key?(k)} diff --git a/app/models/topic.rb b/app/models/topic.rb index 90443862..2273fd7e 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -82,6 +82,19 @@ class Topic < ApplicationRecord map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user])) end + def as_rdf + output = '' + output += %(d:topic_#{id} a mm:Topic ;\n) + output += %( rdfs:label "#{name}" ;\n) + output += %( rdfs:comment "#{desc}" ;\n) if desc.present? + output += %( foaf:homepage <#{link}> ;\n) if link.present? + output += %( mm:mapper d:mapper_#{user_id} ;\n) + output += %( mm:metacode "#{metacode.name}" ;\n) + output[-2] = '.' # change last ; to a . + output += %(\n) + output + end + def collaborator_ids if defer_to_map defer_to_map.editors.select { |mapper| mapper != user }.map(&:id) diff --git a/app/models/user.rb b/app/models/user.rb index f6fcb60e..17d9c8d4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -67,6 +67,17 @@ class User < ApplicationRecord json end + def as_rdf(opts = {}) + base_url = opts[:base_url] || 'https://metamaps.cc' + output = '' + output += %(d:mapper_#{id} a foaf:OnlineAccount ;\n) + output += %( foaf:accountName "#{name}" ;\n) + output += %( foaf:accountServiceHomepage "#{base_url}/mapper/#{id}" ;\n) + output[-2] = '.' # change last ; to a . + output += %(\n) + output + end + def all_accessible_maps maps + shared_maps end diff --git a/app/services/map_export_service.rb b/app/services/map_export_service.rb index 3b76cea8..e500575e 100644 --- a/app/services/map_export_service.rb +++ b/app/services/map_export_service.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true class MapExportService - attr_reader :user, :map - def initialize(user, map) + attr_reader :user, :map, :base_url + + def initialize(user, map, opts = {}) @user = user @map = map + @base_url = opts[:base_url] || 'https://metamaps.cc' end def json @@ -22,6 +24,25 @@ class MapExportService end end + def rdf + output = '' + output += "PREFIX d: <#{base_url}/maps/#{map.id}>\n" + output += "PREFIX mm: <#{base_url}/owl/map.owl.ttl>\n" + output += "PREFIX rdfs: \n" + output += "PREFIX foaf: \n" + output += "\n" + map.contributors.each do |mapper| + output += mapper.as_rdf(base_url: base_url) + end + map.topics.each do |topic| + output += topic.as_rdf + end + map.synapses.each do |synapse| + output += synapse.as_rdf + end + output + end + private def topic_headings diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index 6e1d16f0..2e0132a6 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -3,3 +3,6 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf + +# RDF export +Mime::Type.register 'text/turtle', :ttl diff --git a/public/owl/map.owl.ttl b/public/owl/map.owl.ttl new file mode 100644 index 00000000..725e039a --- /dev/null +++ b/public/owl/map.owl.ttl @@ -0,0 +1,40 @@ +@prefix owl: . +@prefix xsd: . +@prefix rdfs: . +@prefix foaf: . + +@prefix : . +@prefix mm: . + +: a owl:Ontology ; + rdfs:label "Metamaps Map"@en . + +mm:Topic a owl:Class ; + rdfs:label "One topic on a metamap"@en . + +mm:Synapse a owl:Class ; + rdfs:label "Link between two topics on a metamap"@en . + +mm:topic1 a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "first topic of a synapse"@en ; + rdfs:domain mm:Synapse ; + rdfs:range mm:Topic . + +mm:topic2 a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "second topic of a synapse"@en ; + rdfs:domain mm:Topic ; + rdfs:range mm:Topic . + +mm:mapper a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "Metamaps user who created this topic"@en ; + rdfs:domain mm:Topic ; + rdfs:range foaf:OnlineAccount . + +mm:direction a owl:ObjectProperty ; + a owl:FunctionalProperty ; + rdfs:label "from-to, both, or none"@en ; + rdfs:domain mm:Synapse ; + rdfs:range [ owl:oneOf mm:from-to, mm:both, mm:none ] . From 0ad10c0f5aea00dd543952f809df45d9a5ff82eb Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Mon, 23 Jan 2017 14:02:14 -0500 Subject: [PATCH 21/58] fix style of thumb button on map card (#1044) --- app/assets/stylesheets/application.scss.erb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/application.scss.erb b/app/assets/stylesheets/application.scss.erb index 35665918..3bb0b369 100644 --- a/app/assets/stylesheets/application.scss.erb +++ b/app/assets/stylesheets/application.scss.erb @@ -2013,6 +2013,7 @@ input.collaboratorSearchField { position: relative; cursor: pointer; display: none; + padding: 0 2px; } .mapInfoShareIcon { width: 24px; @@ -2060,10 +2061,10 @@ and it won't be important on password protected instances */ height: 32px; & > span { - bottom: -9px; - right: 3px; - font-size: 10px; - color: #eee; + bottom: -8px; + right: 2px; + font-size: 12px; + color: #e0e0e0; &:hover { color: white; From d16709e8e77dab26ec87b50f2cbcc190d2d41bd6 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Mon, 23 Jan 2017 19:30:13 -0500 Subject: [PATCH 22/58] fix codeclimate style issues (#1046) * bunch of code climate fixes * more --- .rubocop.yml | 3 + Gemfile | 8 +-- app/assets/config/manifest.js | 1 + app/assets/javascripts/application.js | 5 +- .../javascripts/homepageVimeoFallback.js | 4 +- app/channels/application_cable/channel.rb | 1 + app/channels/map_channel.rb | 1 + app/controllers/access_controller.rb | 6 +- app/controllers/api/v2/restful_controller.rb | 4 +- app/controllers/hacks_controller.rb | 1 - app/controllers/metacode_sets_controller.rb | 25 ++++---- app/controllers/search_controller.rb | 35 ++++++----- app/controllers/synapses_controller.rb | 4 +- app/controllers/topics_controller.rb | 38 +++++++----- app/controllers/users/passwords_controller.rb | 16 ++--- .../users/registrations_controller.rb | 60 ++++++++++--------- app/helpers/application_helper.rb | 9 ++- app/helpers/topics_helper.rb | 6 +- app/models/access_request.rb | 2 +- app/models/event.rb | 8 +-- .../events/conversation_started_on_map.rb | 16 ++--- app/models/events/synapse_added_to_map.rb | 18 +++--- app/models/events/synapse_removed_from_map.rb | 18 +++--- app/models/events/synapse_updated.rb | 16 ++--- app/models/events/topic_added_to_map.rb | 18 +++--- app/models/events/topic_moved_on_map.rb | 18 +++--- app/models/events/topic_removed_from_map.rb | 18 +++--- app/models/events/topic_updated.rb | 16 ++--- app/models/events/user_present_on_map.rb | 16 ++--- app/models/map.rb | 29 +++++---- app/models/mapping.rb | 11 ++-- app/models/message.rb | 6 +- app/models/synapse.rb | 16 ++--- app/models/topic.rb | 16 ++--- app/models/user.rb | 2 +- app/models/user_preference.rb | 2 +- .../slack/synapse_removed_from_map.rb | 2 +- realtime/map.js | 2 +- webpack.config.js | 2 +- 39 files changed, 266 insertions(+), 213 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 6bdcbfc3..e7819c17 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -19,3 +19,6 @@ Metrics/AbcSize: Style/Documentation: Enabled: false + +Style/EmptyMethod: + EnforcedStyle: expanded diff --git a/Gemfile b/Gemfile index 56ee0bd2..cf3eecb1 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,6 @@ gem 'aws-sdk' gem 'best_in_place' gem 'delayed_job' gem 'delayed_job_active_record' -gem 'sucker_punch' gem 'devise' gem 'doorkeeper' gem 'dotenv-rails' @@ -20,6 +19,7 @@ gem 'kaminari' gem 'mailboxer' gem 'paperclip' gem 'pg' +gem 'puma' gem 'pundit' gem 'pundit_extra' gem 'rack-attack' @@ -27,7 +27,7 @@ gem 'rack-cors' gem 'redis' gem 'slack-notifier' gem 'snorlax' -gem 'puma' +gem 'sucker_punch' # asset stuff gem 'jquery-rails' @@ -36,12 +36,12 @@ gem 'sass-rails' gem 'uglifier' group :test do + gem 'brakeman', require: false gem 'factory_girl_rails' gem 'json-schema' gem 'rspec-rails' gem 'shoulda-matchers' gem 'simplecov', require: false - gem 'brakeman', require: false end group :development, :test do @@ -49,6 +49,6 @@ group :development, :test do gem 'binding_of_caller' gem 'pry-byebug' gem 'pry-rails' - gem 'tunemygc' gem 'rubocop' + gem 'tunemygc' end diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index 72a7189c..41328039 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,3 +1,4 @@ +// eslint-disable spaced-comment // JS and CSS bundles //= link_directory ../javascripts .js //= link_directory ../stylesheets .css diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4483452c..529ab13e 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,4 +1,3 @@ -// eslint-disable spaced-comment // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // @@ -10,7 +9,8 @@ // // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. -// +// +/* eslint-disable spaced-comment */ //= require jquery3 //= require jquery-ui //= require jquery_ujs @@ -19,3 +19,4 @@ //= require ./webpacked/metamaps.bundle //= require ./Metamaps.ServerData //= require homepageVimeoFallback +/* eslint-enable spaced-comment */ diff --git a/app/assets/javascripts/homepageVimeoFallback.js b/app/assets/javascripts/homepageVimeoFallback.js index e4f5a67a..53c691eb 100644 --- a/app/assets/javascripts/homepageVimeoFallback.js +++ b/app/assets/javascripts/homepageVimeoFallback.js @@ -1,11 +1,11 @@ /* global $ */ -$(document).ready(function () { +$(document).ready(function() { if (window.location.pathname === '/') { $.ajax({ type: 'GET', url: 'https://player.vimeo.com', - error: function (e) { + error: function(e) { $('.homeVideo').hide() $('.homeVideo').replaceWith($('
diff --git a/config/routes.rb b/config/routes.rb index 9d0a894c..1eae4b96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,9 +37,11 @@ Metamaps::Application.routes.draw do default: { format: :json } post 'approve_access/:request_id', to: 'access#approve_access_post', + as: :approve_access_post, default: { format: :json } post 'deny_access/:request_id', to: 'access#deny_access_post', + as: :deny_access_post, default: { format: :json } post :access, to: 'access#access', default: { format: :json } From 2d50f24be6a544c827468c745a730f6a59654672 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Sat, 11 Feb 2017 14:21:47 +0000 Subject: [PATCH 50/58] var misnamed --- app/views/topic_mailer/connected.text.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/topic_mailer/connected.text.erb b/app/views/topic_mailer/connected.text.erb index e173ae4d..33afd027 100644 --- a/app/views/topic_mailer/connected.text.erb +++ b/app/views/topic_mailer/connected.text.erb @@ -3,6 +3,6 @@ topic2 = (topic1.id == synapse.topic1_id ? synapse.topic2 : synapse.topic1) %> <%= synapse.user.name %> connected topic <%= topic1.name %> to topic <%= topic2.name %> -<%= synapse.desc.length > 0 ? ' with the description' + event.desc : '' %> +<%= synapse.desc.length > 0 ? ' with the description' + synapse.desc : '' %> <%= topic_url(topic1) %> \ No newline at end of file From 2d0d0403b172e0b8a7341f604a800bbd347eaf79 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Sat, 11 Feb 2017 19:50:59 +0000 Subject: [PATCH 51/58] little fixes for deploy --- app/services/follow_service.rb | 2 +- .../notification_mailer/new_notification_email.html.erb | 1 + frontend/src/components/NotificationIcon.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 4fa6dd9d..22a1786d 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -4,7 +4,7 @@ class FollowService def self.follow(entity, user, reason) - #return unless is_tester(user) + return unless is_tester(user) follow = Follow.where(followed: entity, user: user).first_or_create if FollowReason::REASONS.include?(reason) && !follow.follow_reason.read_attribute(reason) diff --git a/app/views/mailboxer/notification_mailer/new_notification_email.html.erb b/app/views/mailboxer/notification_mailer/new_notification_email.html.erb index ad90419f..f0f0e44b 100644 --- a/app/views/mailboxer/notification_mailer/new_notification_email.html.erb +++ b/app/views/mailboxer/notification_mailer/new_notification_email.html.erb @@ -2,5 +2,6 @@
<%= raw @notification.body %>

Make sense with Metamaps

+
<%= render partial: 'shared/mailer_unsubscribe_link' %>
diff --git a/frontend/src/components/NotificationIcon.js b/frontend/src/components/NotificationIcon.js index e7225f04..201020b5 100644 --- a/frontend/src/components/NotificationIcon.js +++ b/frontend/src/components/NotificationIcon.js @@ -18,7 +18,7 @@ class NotificationIcon extends Component { } return ( - +
Notifications
From 1374da35dad8c046b91befc56674cc1a1f7535f4 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Sat, 11 Feb 2017 15:29:31 -0500 Subject: [PATCH 52/58] Update notification_service.rb --- app/services/notification_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index fa429f2e..b140f7f8 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -35,7 +35,7 @@ class NotificationService body = renderer.render(template: settings[:template], locals: { entity: entity, event: event }, layout: false) follows.each{|follow| # this handles email and in-app notifications, in the future, include push - follow.user.notify(settings[:subject], body, event, false, event_type, (follow.user.emails_allowed && follow.email), event.user) + follow.user.notify(settings[:subject], body, event, false, event_type, follow.user.emails_allowed, event.user) # push could be handled with Actioncable to send transient notifications to the UI # the receipt from the notify call could be used to link to the full notification } From d8698ef6f221aea6829b2acbf4f849e26a9d053c Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Sat, 11 Feb 2017 19:29:03 -0500 Subject: [PATCH 53/58] api stuffs (#1069) * Update restful_controller.rb * Update tokens_controller.rb * /tokens/new form * thats all --- app/controllers/api/v2/restful_controller.rb | 3 +-- app/controllers/api/v2/tokens_controller.rb | 8 ++++++++ app/controllers/tokens_controller.rb | 9 +++++++++ app/views/tokens/new.html.erb | 5 +++++ config/routes.rb | 2 ++ 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 app/controllers/tokens_controller.rb create mode 100644 app/views/tokens/new.html.erb diff --git a/app/controllers/api/v2/restful_controller.rb b/app/controllers/api/v2/restful_controller.rb index d09f4cc0..417f7bc9 100644 --- a/app/controllers/api/v2/restful_controller.rb +++ b/app/controllers/api/v2/restful_controller.rb @@ -5,7 +5,6 @@ module Api include Pundit include PunditExtra - protect_from_forgery with: :exception snorlax_used_rest! before_action :load_resource, only: [:show, :update, :destroy] @@ -46,7 +45,7 @@ module Api end def current_user - token_user || doorkeeper_user || super + token_user || doorkeeper_user end def load_resource diff --git a/app/controllers/api/v2/tokens_controller.rb b/app/controllers/api/v2/tokens_controller.rb index e0474e25..28dfc120 100644 --- a/app/controllers/api/v2/tokens_controller.rb +++ b/app/controllers/api/v2/tokens_controller.rb @@ -2,6 +2,8 @@ module Api module V2 class TokensController < RestfulController + protect_from_forgery + def searchable_columns [:description] end @@ -18,6 +20,12 @@ module Api create_action respond_with_resource end + + private + + def current_user + token_user || doorkeeper_user || method(:current_user).super_method.super_method.call + end end end end diff --git a/app/controllers/tokens_controller.rb b/app/controllers/tokens_controller.rb new file mode 100644 index 00000000..b434d122 --- /dev/null +++ b/app/controllers/tokens_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true +class TokensController < ApplicationController + before_action :require_user, only: [:new] + + def new + @token = Token.new(user: current_user) + render :new, layout: false + end +end diff --git a/app/views/tokens/new.html.erb b/app/views/tokens/new.html.erb new file mode 100644 index 00000000..e655010d --- /dev/null +++ b/app/views/tokens/new.html.erb @@ -0,0 +1,5 @@ +<%= form_for @token, url: '/api/v2/tokens', method: :post do |form| %> +

Request new API Token

+ <%= form.text_field :description, placeholder: "Token description..." %> + <%= form.submit %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 1eae4b96..f2850c81 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -89,6 +89,8 @@ Metamaps::Application.routes.draw do end end + resources :tokens, only: [:new] + devise_for :users, skip: :sessions, controllers: { registrations: 'users/registrations', passwords: 'users/passwords', From d455ced683659670defdab3cad76271f7645b3bc Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 11 Feb 2017 19:30:58 -0800 Subject: [PATCH 54/58] send mail by default is false in message from devs. also fixes a bug where the option didn't do anything --- app/services/notification_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index b140f7f8..177489e1 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -82,7 +82,7 @@ class NotificationService obj = opts[:obj] || nil sanitize_text = opts[:sanitize_text] || false notification_code = opts[:notification_code] || MESSAGE_FROM_DEVS - send_mail = opts[:send_mail] || true + send_mail = opts[:send_mail] ? true : false sender = opts[:sender] || User.find_by(email: 'ishanshapiro@gmail.com') Mailboxer::Notification.notify_all(users, subject, body, obj, sanitize_text, notification_code, send_mail, sender) end From 53d4beddecb0344ea9c2d9f52b7d9286504f094c Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sat, 11 Feb 2017 19:35:23 -0800 Subject: [PATCH 55/58] move hr tag in notification emails --- .../notification_mailer/new_notification_email.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/mailboxer/notification_mailer/new_notification_email.html.erb b/app/views/mailboxer/notification_mailer/new_notification_email.html.erb index f0f0e44b..b696c649 100644 --- a/app/views/mailboxer/notification_mailer/new_notification_email.html.erb +++ b/app/views/mailboxer/notification_mailer/new_notification_email.html.erb @@ -1,7 +1,7 @@
<%= raw @notification.body %> -

Make sense with Metamaps


+

Make sense with Metamaps

<%= render partial: 'shared/mailer_unsubscribe_link' %>
From 95901e17e8c7a7146fd1fc840c7f40345c4e67f4 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 12 Feb 2017 09:53:04 -0800 Subject: [PATCH 56/58] fix travis (#1071) * fix topic spec * fix synapse/mapping spec * brakeman csrf warning suppressed :| --- app/services/follow_service.rb | 54 ++++++++++---------- config/brakeman.ignore | 32 ++++++------ db/schema.rb | 4 +- spec/controllers/synapses_controller_spec.rb | 5 +- spec/controllers/topics_controller_spec.rb | 5 +- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 22a1786d..9c0693de 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -1,35 +1,35 @@ # frozen_string_literal: true class FollowService - + class << self + def follow(entity, user, reason) - def self.follow(entity, user, reason) + return unless is_tester(user) - return unless is_tester(user) - - follow = Follow.where(followed: entity, user: user).first_or_create - if FollowReason::REASONS.include?(reason) && !follow.follow_reason.read_attribute(reason) - follow.follow_reason.update_attribute(reason, true) - end - end - - def self.unfollow(entity, user) - Follow.where(followed: entity, user: user).destroy_all - end - - def self.remove_reason(entity, user, reason) - return unless FollowReason::REASONS.include?(reason) - follow = Follow.where(followed: entity, user: user).first - if follow - follow.follow_reason.update_attribute(reason, false) - if !follow.follow_reason.has_reason - follow.destroy + follow = Follow.where(followed: entity, user: user).first_or_create + if FollowReason::REASONS.include?(reason) && !follow.follow_reason.read_attribute(reason) + follow.follow_reason.update_attribute(reason, true) end end - end - - protected - - def is_tester(user) - %w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email) + + def unfollow(entity, user) + Follow.where(followed: entity, user: user).destroy_all + end + + def remove_reason(entity, user, reason) + return unless FollowReason::REASONS.include?(reason) + follow = Follow.where(followed: entity, user: user).first + if follow + follow.follow_reason.update_attribute(reason, false) + if !follow.follow_reason.has_reason + follow.destroy + end + end + end + + protected + + def is_tester(user) + %w(connorturland@gmail.com devin@callysto.com chessscholar@gmail.com solaureum@gmail.com ishanshapiro@gmail.com).include?(user.email) + end end end diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 9e29ff0d..c2491dcd 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,24 +1,24 @@ { "ignored_warnings": [ { - "warning_type": "Cross Site Scripting", - "warning_code": 2, - "fingerprint": "88694dca0bcc2226859746f9ed40cc682d6e5eaec1e73f2be557770a854ede0b", - "message": "Unescaped model attribute", - "file": "app/views/notifications/show.html.erb", - "line": 7, - "link": "http://brakemanscanner.org/docs/warning_types/cross_site_scripting", - "code": "current_user.mailbox.notifications.find_by(:id => params[:id]).body", - "render_path": [{"type":"controller","class":"NotificationsController","method":"show","line":24,"file":"app/controllers/notifications_controller.rb"}], + "warning_type": "Cross-Site Request Forgery", + "warning_code": 7, + "fingerprint": "59d73ce0b791aa7ed532510c780235a8b23f7cd1246dbf9da258e36f5d1e2b0a", + "message": "'protect_from_forgery' should be called in Api::V2::RestfulController", + "file": "app/controllers/api/v2/restful_controller.rb", + "line": 4, + "link": "http://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/", + "code": null, + "render_path": null, "location": { - "type": "template", - "template": "notifications/show" + "type": "controller", + "controller": "Api::V2::RestfulController" }, - "user_input": "current_user.mailbox.notifications", - "confidence": "Weak", - "note": "" + "user_input": null, + "confidence": "High", + "note": "Cookie-based auth is disabled for the API except for the tokens endpoint. We're hoping this is sufficiently secure, because CSRF-forged links might get clicked on another site, but the generated tokens won't go back to the attacker. Also, an attacker would need a token to delete it, which means they've got access at that point anyways. - Devin, Feb 2017" } ], - "updated": "2016-11-29 13:01:34 -0500", - "brakeman_version": "3.4.0" + "updated": "2017-02-11 20:00:09 -0800", + "brakeman_version": "3.4.1" } diff --git a/db/schema.rb b/db/schema.rb index 66bbf9cd..21a2447b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -84,8 +84,8 @@ ActiveRecord::Schema.define(version: 20170209215911) do t.integer "user_id" t.string "followed_type" t.integer "followed_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["followed_type", "followed_id"], name: "index_follows_on_followed_type_and_followed_id", using: :btree t.index ["user_id"], name: "index_follows_on_user_id", using: :btree end diff --git a/spec/controllers/synapses_controller_spec.rb b/spec/controllers/synapses_controller_spec.rb index 7abeb2ee..21151ffc 100644 --- a/spec/controllers/synapses_controller_spec.rb +++ b/spec/controllers/synapses_controller_spec.rb @@ -2,11 +2,12 @@ require 'rails_helper' RSpec.describe SynapsesController, type: :controller do - let(:synapse) { create(:synapse) } + let(:user) { create(:user) } + let(:synapse) { create(:synapse, user: user, updated_by: user) } let(:valid_attributes) { synapse.attributes.except('id') } let(:invalid_attributes) { { permission: :invalid_lol } } before :each do - sign_in create(:user) + sign_in(user) end describe 'POST #create' do diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb index 96689403..16526835 100644 --- a/spec/controllers/topics_controller_spec.rb +++ b/spec/controllers/topics_controller_spec.rb @@ -3,12 +3,11 @@ require 'rails_helper' RSpec.describe TopicsController, type: :controller do let(:user) { create(:user) } - let(:topic) { create(:topic, user: user) } + let(:topic) { create(:topic, user: user, updated_by: user) } let(:valid_attributes) { topic.attributes.except('id') } let(:invalid_attributes) { { permission: :invalid_lol } } before :each do - sign_in :user - + sign_in(user) end describe 'POST #create' do From 545706e17aa7f9fbd804789a0e71c25b92b484f7 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 12 Feb 2017 09:54:54 -0800 Subject: [PATCH 57/58] disable cookie based auth on the API - mostly (#1070) --- doc/api/api.raml | 2 +- doc/api/apis/mappings.raml | 4 ++-- doc/api/apis/maps.raml | 4 ++-- doc/api/apis/metacodes.raml | 4 ++-- doc/api/apis/synapses.raml | 4 ++-- doc/api/apis/tokens.raml | 3 +++ doc/api/apis/topics.raml | 4 ++-- doc/api/apis/users.raml | 4 ++-- doc/api/pages/cookie_tutorial.md | 3 --- doc/api/pages/getting-started.md | 2 +- doc/api/pages/token_tutorial.md | 17 +++++++++-------- doc/api/securitySchemes/cookie.raml | 3 +-- 12 files changed, 27 insertions(+), 27 deletions(-) delete mode 100644 doc/api/pages/cookie_tutorial.md diff --git a/doc/api/api.raml b/doc/api/api.raml index 45969271..d051b099 100644 --- a/doc/api/api.raml +++ b/doc/api/api.raml @@ -13,7 +13,7 @@ securitySchemes: cookie: !include securitySchemes/cookie.raml token: !include securitySchemes/token.raml oauth_2_0: !include securitySchemes/oauth_2_0.raml -securedBy: [ token, oauth_2_0, cookie ] +securedBy: [ token, oauth_2_0 ] traits: pageable: !include traits/pageable.raml diff --git a/doc/api/apis/mappings.raml b/doc/api/apis/mappings.raml index af4965cb..35d9353d 100644 --- a/doc/api/apis/mappings.raml +++ b/doc/api/apis/mappings.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ embeddable: { embedFields: "user,updated_by,map" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: @@ -32,7 +32,7 @@ post: #type: item get: is: [ embeddable: { embedFields: "user,updated_by,map" } ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: diff --git a/doc/api/apis/maps.raml b/doc/api/apis/maps.raml index fe9fed67..b147bd80 100644 --- a/doc/api/apis/maps.raml +++ b/doc/api/apis/maps.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ searchable: { searchFields: "name, desc" }, embeddable: { embedFields: "user,source,topics,synapses,mappings,contributors,collaborators" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] queryParameters: user_id: description: | @@ -40,7 +40,7 @@ post: #type: item get: is: [ embeddable: { embedFields: "user,source,topics,synapses,mappings,contributors,collaborators" } ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: diff --git a/doc/api/apis/metacodes.raml b/doc/api/apis/metacodes.raml index b2a48eeb..5e35d68f 100644 --- a/doc/api/apis/metacodes.raml +++ b/doc/api/apis/metacodes.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ searchable: { searchFields: "name" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: @@ -9,7 +9,7 @@ get: example: !include ../examples/metacodes.json /{id}: #type: item - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] get: responses: 200: diff --git a/doc/api/apis/synapses.raml b/doc/api/apis/synapses.raml index c9b37e9f..181d60f9 100644 --- a/doc/api/apis/synapses.raml +++ b/doc/api/apis/synapses.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ searchable: { searchFields: "desc" }, embeddable: { embedFields: "topic1,topic2,user" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: @@ -34,7 +34,7 @@ post: #type: item get: is: [ embeddable: { embedFields: "topic1,topic2,user" } ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: diff --git a/doc/api/apis/tokens.raml b/doc/api/apis/tokens.raml index 5d4eb191..b827acd3 100644 --- a/doc/api/apis/tokens.raml +++ b/doc/api/apis/tokens.raml @@ -3,12 +3,14 @@ get: description: | A list of the current user's tokens. is: [ searchable: { searchFields: description }, pageable, orderable ] + securedBy: [ token, oauth_2_0, cookie ] responses: 200: body: application/json: example: !include ../examples/tokens.json post: + securedBy: [ token, oauth_2_0, cookie ] body: application/json: properties: @@ -22,6 +24,7 @@ post: example: !include ../examples/token.json /{id}: #type: item + securedBy: [ token, oauth_2_0, cookie ] delete: responses: 204: diff --git a/doc/api/apis/topics.raml b/doc/api/apis/topics.raml index c1bce96e..704fce19 100644 --- a/doc/api/apis/topics.raml +++ b/doc/api/apis/topics.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ searchable: { searchFields: "name, desc, link" }, embeddable: { embedFields: "user,metacode" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: @@ -31,7 +31,7 @@ post: #type: item get: is: [ embeddable: { embedFields: "user,metacode" } ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: diff --git a/doc/api/apis/users.raml b/doc/api/apis/users.raml index 082af2f0..ec2e7d17 100644 --- a/doc/api/apis/users.raml +++ b/doc/api/apis/users.raml @@ -1,7 +1,7 @@ #type: collection get: is: [ searchable: { searchFields: "name" }, orderable, pageable ] - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] responses: 200: body: @@ -9,7 +9,7 @@ get: example: !include ../examples/users.json /{id}: #type: item - securedBy: [ null, token, oauth_2_0, cookie ] + securedBy: [ null, token, oauth_2_0 ] get: responses: 200: diff --git a/doc/api/pages/cookie_tutorial.md b/doc/api/pages/cookie_tutorial.md deleted file mode 100644 index 7bfa0825..00000000 --- a/doc/api/pages/cookie_tutorial.md +++ /dev/null @@ -1,3 +0,0 @@ -One way to access the API is through your browser. Log into metamaps.cc normally, then browse manually to https://metamaps.cc/api/v2/users/current. You should see a JSON description of your own user object in the database. You can browse any GET endpoint by simply going to that URL and appending query parameters in the URI. - -To run a POST or DELETE request, you can use the Fetch API. See the example in the next section. diff --git a/doc/api/pages/getting-started.md b/doc/api/pages/getting-started.md index 687cfa3f..184ffce3 100644 --- a/doc/api/pages/getting-started.md +++ b/doc/api/pages/getting-started.md @@ -1,2 +1,2 @@ -There are three ways to log in: cookie-based authentication, token-based authentication, or OAuth 2. If you're testing the API or making simple scripts, cookie-based or token-based is the best. If you're developing an app and want users to be able to log into Metamaps inside your app, you'll be able to use the OAuth 2 mechanism. Check the security tab of any of the endpoints above for instructions on logging in. +There are two ways to log in: token-based authentication, or OAuth 2. If you're testing the API or making simple scripts, token-based is the best. If you're developing an app and want users to be able to log into Metamaps inside your app, you'll be able to use the OAuth 2 mechanism. Check the security tab of any of the endpoints above for instructions on logging in. diff --git a/doc/api/pages/token_tutorial.md b/doc/api/pages/token_tutorial.md index b0d20ca4..7278073b 100644 --- a/doc/api/pages/token_tutorial.md +++ b/doc/api/pages/token_tutorial.md @@ -1,25 +1,26 @@ -If you are logged into the API via another means, you can create a token. Once you have this token, you can append it to a request. For example, opening a private window in your browser and browsing to `https://metamaps.cc/api/v2/users/current?token=...token here...` would show you your current user, even without logging in by another means. +You can create a token by using the API, or you can get your first token at https://metamaps.cc/tokens/new. Once you have this token, you can append it to a request. For example, opening a private window in your browser and browsing to `https://metamaps.cc/api/v2/users/current?token=...token here...` would show you your current user, even without logging in by another means. -To get a list of your current tokens, you can log in using cookie-based authentication and run the following fetch request in your browser console (assuming the current tab is on some page within the `metamaps.cc` website. +To get a list of your current tokens (while logged in to the main site), you can run the following fetch request in your browser console (assuming the current tab is on some page within the `metamaps.cc` website. The token you need to append to the url will look something like `T1ZI012rseqF1XZWFBVj4JSXR5g3OpYC`, but this example token won't work for you. You need your own. ``` fetch('/api/v2/tokens', { method: 'GET', - credentials: 'same-origin' // needed to use the cookie-based auth + credentials: 'same-origin', // needed so the API knows which account you're logged in to }).then(response => { return response.json() }).then(console.log).catch(console.error) ``` -If this is your first time accessing the API, this list wil be empty. You can create a token using a similar method: +If this is your first time accessing the API, this list wil be empty. You can create a token over the API using a similar method: ``` -fetch('/api/v2/tokens', { - method: 'POST', - credentials: 'same-origin' +fetch('/api/v2/tokens?token=T1ZI012rseqF1XZWFBVj4JSXR5g3OpYC', { + method: 'POST' }).then(response => { return response.json() -}).then(console.log).catch(console.error) +}).then(payload => { + console.log(payload) +}).catch(console.error) ``` `payload.data.token` will contain a string which you can use to append to requests to access the API from anywhere. diff --git a/doc/api/securitySchemes/cookie.raml b/doc/api/securitySchemes/cookie.raml index fb1041b1..19c80ea8 100644 --- a/doc/api/securitySchemes/cookie.raml +++ b/doc/api/securitySchemes/cookie.raml @@ -1,3 +1,2 @@ -description: !include ../pages/cookie_tutorial.md type: x-cookie -displayName: Secured by cookie-based authentication +displayName: Accessible using cookie-based authentication From 9d52aa9c741c115c1bd5dc18792a7cba860c0917 Mon Sep 17 00:00:00 2001 From: Devin Howard Date: Sun, 12 Feb 2017 15:08:42 -0800 Subject: [PATCH 58/58] tag v3.3 --- config/initializers/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/version.rb b/config/initializers/version.rb index a1e20598..06e4b075 100644 --- a/config/initializers/version.rb +++ b/config/initializers/version.rb @@ -1,4 +1,4 @@ # frozen_string_literal: true -METAMAPS_VERSION = '3.2' +METAMAPS_VERSION = '3.3' METAMAPS_BUILD = `git log -1 --pretty=%H`.chomp[0..11].freeze METAMAPS_LAST_UPDATED = `git log -1 --pretty='%ad'`.split(' ').values_at(1, 2, 4).join(' ').freeze