From 9b0487e9a4d01b6e84d4c5687ab2403e0f2811e4 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Fri, 5 Jul 2019 01:52:50 +0530 Subject: [PATCH 01/30] WIP action cable setup --- app/assets/javascripts/cable.js | 13 +++++++++++++ .../javascripts/channels/concurrent_editing.js | 17 +++++++++++++++++ app/channels/application_cable/channel.rb | 4 ++++ app/channels/application_cable/connection.rb | 18 ++++++++++++++++++ app/channels/concurrent_editing_channel.rb | 12 ++++++++++++ app/views/layouts/application.html.erb | 1 + config/cable.yml | 4 +++- config/environments/production.rb | 2 ++ config/routes.rb | 2 ++ 9 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/cable.js create mode 100644 app/assets/javascripts/channels/concurrent_editing.js create mode 100644 app/channels/application_cable/channel.rb create mode 100644 app/channels/application_cable/connection.rb create mode 100644 app/channels/concurrent_editing_channel.rb diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 000000000..739aa5f02 --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js new file mode 100644 index 000000000..169d14131 --- /dev/null +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -0,0 +1,17 @@ +App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChannel", { + connected: function() { + // Called when the subscription is ready for use on the server + }, + + disconnected: function() { + // Called when the subscription has been terminated by the server + }, + + received: function(data) { + // Called when there's incoming data on the websocket for this channel + }, + + speak: function() { + return this.perform('speak'); + } +}); diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 000000000..7f5c00f22 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end \ No newline at end of file diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 000000000..681d8df73 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,18 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + identified_by :current_user + + def connect + self.current_user = find_verified_user + end + + private + def find_verified_user + if verified_user = User.find_by(id: session[:user_id]) + return verified_user + else + return nil + end + end + end +end \ No newline at end of file diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb new file mode 100644 index 000000000..9f58cfb2e --- /dev/null +++ b/app/channels/concurrent_editing_channel.rb @@ -0,0 +1,12 @@ +class ConcurrentEditingChannel < ApplicationCable::Channel + def subscribed + # stream_from "some_channel" + end + + def unsubscribed + # Any cleanup needed when channel is unsubscribed + end + + def speak + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 85bdb4cdf..4c6c92f4e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,6 +14,7 @@ <%= stylesheet_link_tag 'application' %> <%= javascript_include_tag 'application' %> + <%= action_cable_meta_tag %> <%= render 'layouts/header' %> diff --git a/config/cable.yml b/config/cable.yml index 8648dafa2..200f4b6d9 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,5 +1,7 @@ development: - adapter: async + adapter: redis + url: <%= "redis://localhost:6379/0" %> + channel_prefix: mapknitter_development test: adapter: async diff --git a/config/environments/production.rb b/config/environments/production.rb index a963d8cd9..db995c1ad 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -102,4 +102,6 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/] end diff --git a/config/routes.rb b/config/routes.rb index 8f4ba2ca2..dbd9cbe0f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,8 @@ root to: 'front_ui#index' + mount ActionCable.server => '/cable' + get 'front-page', to: 'front_ui#index' get 'mappers', to: 'front_ui#nearby_mappers' get 'about', to: 'front_ui#about' From 3b7b2bf08eb516ca7b4bd82f0adf2447be0c7833 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sat, 6 Jul 2019 23:46:51 +0530 Subject: [PATCH 02/30] basic action cable setup complete --- Gemfile | 3 ++- app/assets/javascripts/application.js | 2 ++ app/assets/javascripts/cable.js | 2 -- app/assets/javascripts/channels/concurrent_editing.js | 9 +++++++-- app/channels/application_cable/connection.rb | 2 +- app/channels/concurrent_editing_channel.rb | 5 +++-- app/controllers/application_controller.rb | 1 + app/views/layouts/application.html.erb | 2 +- config/cable.yml | 4 +--- config/environments/development.rb | 3 +++ 10 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index f8f9c3ab3..6e469fe5d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -ruby '2.4.6' +# ruby '2.4.6' gem 'rails', '~> 5.2.3' gem 'rake', '~> 12.3.2' gem 'tzinfo-data' @@ -64,6 +64,7 @@ group :development, :test do gem 'byebug', '~> 11.0.1', platforms: [:mri, :mingw, :x64_mingw] gem 'faker', '~> 1.9.3' gem 'pry-rails', '~> 0.3.9' + gem 'puma' end group :development do diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 04ad5432d..8ce9dd608 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -29,3 +29,5 @@ //= require annotations-legacy.js //= require glfx-js/dist/glfx.js //= require webgl-distort/dist/webgl-distort.js +//= require cable.js +//= require_tree . diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js index 739aa5f02..f613e17f5 100644 --- a/app/assets/javascripts/cable.js +++ b/app/assets/javascripts/cable.js @@ -1,5 +1,3 @@ -// Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the `rails generate channel` command. // //= require action_cable //= require_self diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js index 169d14131..2705876ed 100644 --- a/app/assets/javascripts/channels/concurrent_editing.js +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -1,17 +1,22 @@ App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChannel", { connected: function() { // Called when the subscription is ready for use on the server + console.log("Connected"); }, disconnected: function() { // Called when the subscription has been terminated by the server + console.log("bye"); }, received: function(data) { // Called when there's incoming data on the websocket for this channel + console.log(data); }, - speak: function() { - return this.perform('speak'); + speak: function(changes) { + return this.perform("sync", { + changes: changes + }); } }); diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 681d8df73..31bed6179 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -8,7 +8,7 @@ def connect private def find_verified_user - if verified_user = User.find_by(id: session[:user_id]) + if verified_user = User.find_by(id: cookies.signed["user_id"]) return verified_user else return nil diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb index 9f58cfb2e..2ce2941d4 100644 --- a/app/channels/concurrent_editing_channel.rb +++ b/app/channels/concurrent_editing_channel.rb @@ -1,12 +1,13 @@ class ConcurrentEditingChannel < ApplicationCable::Channel def subscribed - # stream_from "some_channel" + stream_from "concurrent_editing_channel" end def unsubscribed # Any cleanup needed when channel is unsubscribed end - def speak + def sync changes + ActionCable.server.broadcast 'concurrent_editing_channel', changes end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4d4bf7521..8f0f95404 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,6 +14,7 @@ def current_user if user_id begin @user = User.find(user_id) + cookies.signed["user_id"] = @current_user.id rescue StandardError @user = nil end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4c6c92f4e..2f5c573b9 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -13,8 +13,8 @@ <%= stylesheet_link_tag 'application' %> - <%= javascript_include_tag 'application' %> <%= action_cable_meta_tag %> + <%= javascript_include_tag 'application' %> <%= render 'layouts/header' %> diff --git a/config/cable.yml b/config/cable.yml index 200f4b6d9..8648dafa2 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,7 +1,5 @@ development: - adapter: redis - url: <%= "redis://localhost:6379/0" %> - channel_prefix: mapknitter_development + adapter: async test: adapter: async diff --git a/config/environments/development.rb b/config/environments/development.rb index d4ca60dce..2e870ab0e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -74,4 +74,7 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + config.action_cable.url = "ws://localhost:3000/cable" + config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/] end From 10d42f494b0c9f2ecdd2367671e3b73cb174b2fc Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sat, 6 Jul 2019 23:48:11 +0530 Subject: [PATCH 03/30] minor change --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 6e469fe5d..f91e960cf 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -# ruby '2.4.6' +ruby '2.4.6' gem 'rails', '~> 5.2.3' gem 'rake', '~> 12.3.2' gem 'tzinfo-data' From c7af51593c4f560b5e215213feaa7f8750fa3e4d Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 11 Jul 2019 00:25:56 +0530 Subject: [PATCH 04/30] minor changes --- app/controllers/application_controller.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8f0f95404..8357487a3 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,8 +13,9 @@ def current_user user_id = session[:user_id] if user_id begin - @user = User.find(user_id) - cookies.signed["user_id"] = @current_user.id + u = User.find(user_id) + cookies.signed["user_id"] = u.id + @user = u rescue StandardError @user = nil end From 826745f30a49853330ff04577c726e1d83a7b74a Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sun, 14 Jul 2019 14:09:52 +0530 Subject: [PATCH 05/30] few changes --- app/assets/javascripts/mapknitter/Map.js | 3 +++ app/controllers/images_controller.rb | 3 ++- app/models/map.rb | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/mapknitter/Map.js b/app/assets/javascripts/mapknitter/Map.js index c3d4fb373..926e2f2ae 100644 --- a/app/assets/javascripts/mapknitter/Map.js +++ b/app/assets/javascripts/mapknitter/Map.js @@ -499,6 +499,9 @@ MapKnitter.Map = MapKnitter.Class.extend({ beforeSend: function (e) { $('.mk-save').removeClass('fa-check-circle fa-times-circle fa-green fa-red').addClass('fa-spinner fa-spin') }, + success: function(data) { + App.concurrent_editing.speak(data); + }, complete: function (e) { $('.mk-save').removeClass('fa-spinner fa-spin').addClass('fa-check-circle fa-green') }, diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index af14b8ec7..97518a19d 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -93,7 +93,8 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save - render html: 'success' + data = Map.fetch_map_data + render json: data end def destroy diff --git a/app/models/map.rb b/app/models/map.rb index 2bd9d6c3a..5e87e3abb 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -267,4 +267,9 @@ def add_tag(tagname, user) tagname = tagname.downcase tags.create(name: tagname, user_id: user.id, map_id: id) unless has_tag(tagname) end + + def self.fetch_map_data + data = {} + data + end end From 6e8e33bf187263a43b60ed8359ce6b5e297e9696 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 18 Jul 2019 12:10:01 +0530 Subject: [PATCH 06/30] initial working functionality complete --- .../channels/concurrent_editing.js | 2 +- app/assets/javascripts/mapknitter/Map.js | 22 +++++++++++++++++++ app/controllers/images_controller.rb | 2 +- app/models/map.rb | 6 ++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js index 2705876ed..079c7933e 100644 --- a/app/assets/javascripts/channels/concurrent_editing.js +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -11,7 +11,7 @@ App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChanne received: function(data) { // Called when there's incoming data on the websocket for this channel - console.log(data); + window.mapKnitter.synchronizeData(data.changes); }, speak: function(changes) { diff --git a/app/assets/javascripts/mapknitter/Map.js b/app/assets/javascripts/mapknitter/Map.js index 926e2f2ae..0b42c6f37 100644 --- a/app/assets/javascripts/mapknitter/Map.js +++ b/app/assets/javascripts/mapknitter/Map.js @@ -462,6 +462,28 @@ MapKnitter.Map = MapKnitter.Class.extend({ if (this.editing._mode != "lock") e.stopPropagation() }, + synchronizeData: function(warpables) { + var layers = []; + map.eachLayer(function(l) {layers.push(l)}); + layers = layers.filter(image => (image._url!=undefined || image._url!=null)); + warpables.forEach(function(warpable) { + corners = []; + warpable.nodes.forEach(function(node) { + corners.push(L.latLng(node.lat, node.lon)); + }); + + x = corners[2]; + y = corners [3]; + corners [2] = y; + corners [3] = x; + + console.log(corners); + + layer = layers.filter(l => l._url==warpable.srcmedium)[0]; + layer.setCorners(corners); + }); + }, + saveImageIfChanged: function () { var img = this // check if image state has changed at all before saving! diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 97518a19d..31b741181 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -93,7 +93,7 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save - data = Map.fetch_map_data + data = @warpable.map.fetch_map_data render json: data end diff --git a/app/models/map.rb b/app/models/map.rb index 5e87e3abb..e0a51cac3 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -268,8 +268,8 @@ def add_tag(tagname, user) tags.create(name: tagname, user_id: user.id, map_id: id) unless has_tag(tagname) end - def self.fetch_map_data - data = {} - data + def fetch_map_data + data = warpables + return data.to_json end end From 193f553437d4a51f778b4cfafb1e67b4b16a5622 Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Tue, 30 Jul 2019 15:35:22 -0300 Subject: [PATCH 07/30] Refactoring code --- app/channels/application_cable/channel.rb | 2 +- app/channels/application_cable/connection.rb | 9 +++------ app/channels/concurrent_editing_channel.rb | 2 +- app/models/map.rb | 2 +- yarn.lock | 11 +++-------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index 7f5c00f22..d67269728 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,4 +1,4 @@ module ApplicationCable class Channel < ActionCable::Channel::Base end -end \ No newline at end of file +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 31bed6179..bfb67cc7a 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -7,12 +7,9 @@ def connect end private + def find_verified_user - if verified_user = User.find_by(id: cookies.signed["user_id"]) - return verified_user - else - return nil - end + User.find(id: cookies.signed["user_id"]) end end -end \ No newline at end of file +end diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb index 2ce2941d4..c3a58a43b 100644 --- a/app/channels/concurrent_editing_channel.rb +++ b/app/channels/concurrent_editing_channel.rb @@ -7,7 +7,7 @@ def unsubscribed # Any cleanup needed when channel is unsubscribed end - def sync changes + def sync(changes) ActionCable.server.broadcast 'concurrent_editing_channel', changes end end diff --git a/app/models/map.rb b/app/models/map.rb index 8d182f305..9da67ac91 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -276,6 +276,6 @@ def add_tag(tagname, user) def fetch_map_data data = warpables - return data.to_json + data.to_json end end diff --git a/yarn.lock b/yarn.lock index 8027feb8c..754337165 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3348,9 +3348,9 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" -"leaflet-blurred-location@git://github.com/publiclab/leaflet-blurred-location.git#main": +"leaflet-blurred-location@git://github.com/publiclab/leaflet-blurred-location#main": version "1.3.0" - resolved "git://github.com/publiclab/leaflet-blurred-location.git#1bff37cb96518bd87192277b14c290cba3c138ba" + resolved "git://github.com/publiclab/leaflet-blurred-location#1bff37cb96518bd87192277b14c290cba3c138ba" dependencies: haversine-distance "^1.1.4" jquery "^3.2.1" @@ -3453,12 +3453,7 @@ leaflet.blurred-location-display@^1.1.0: jquery "^3.3.1" leaflet-blurred-location "git://github.com/publiclab/leaflet-blurred-location#main" -leaflet@*, leaflet@^1.3.1, leaflet@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.5.1.tgz#9afb9d963d66c870066b1342e7a06f92840f46bf" - integrity sha512-ekM9KAeG99tYisNBg0IzEywAlp0hYI5XRipsqRXyRTeuU8jcuntilpp+eFf5gaE0xubc9RuSNIVtByEKwqFV0w== - -leaflet@Leaflet/Leaflet#^1.0.0: +leaflet@*, leaflet@Leaflet/Leaflet#^1.0.0, leaflet@^1.3.1, leaflet@^1.3.3: version "1.5.1" resolved "https://codeload.github.com/Leaflet/Leaflet/tar.gz/2e3e0ffbe87f246eb76d86d2633ddd59b262830b" From 852d5f982b5b1761935e24e56d9086d6efa21e9a Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Sat, 3 Aug 2019 22:50:23 -0300 Subject: [PATCH 08/30] Adding Foreman gem --- Gemfile | 3 +++ Gemfile.lock | 5 ++++- Procfile | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Procfile diff --git a/Gemfile b/Gemfile index dacbd97da..6183e2dac 100644 --- a/Gemfile +++ b/Gemfile @@ -36,6 +36,9 @@ group :dependencies do # compiling markdown to html gem 'rdiscount', '2.2.0.1' + # Process manager for applications with multiple components + gem "foreman", "~> 0.85.0" + # asset pipelining gem 'bootstrap-sass' gem 'sassc-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 689a3f023..43a39c938 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,6 +77,8 @@ GEM faker (1.9.6) i18n (>= 0.7) ffi (1.11.1) + foreman (0.85.0) + thor (~> 0.19.1) friendly_id (5.2.5) activerecord (>= 4.0.0) geokit (1.13.1) @@ -270,7 +272,7 @@ GEM sqlite3 (1.4.1) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) - thor (0.20.3) + thor (0.19.4) thread_safe (0.3.6) tilt (2.0.9) turbolinks (5.2.0) @@ -309,6 +311,7 @@ DEPENDENCIES byebug (~> 11.0.1) codecov faker (~> 1.9.3) + foreman (~> 0.85.0) friendly_id geokit-rails (= 1.1.4) httparty diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..841da4133 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +passenger: passenger start +puma: puma -C config/puma.rb From 8fd235d472a0a1cdc6ed5946ae1be42cc7ca8673 Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Sat, 3 Aug 2019 22:51:27 -0300 Subject: [PATCH 09/30] Scheduling Puma and Passenger servers --- config/puma.rb | 5 +++++ start.sh | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 config/puma.rb diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 000000000..a6860886a --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,5 @@ +#!/usr/bin/env puma + +environment ENV.fetch("RAILS_ENV") { "production" } + +pidfile '/app/tmp/pids/puma.pid' \ No newline at end of file diff --git a/start.sh b/start.sh index 517a983d1..d2287d916 100755 --- a/start.sh +++ b/start.sh @@ -6,6 +6,7 @@ bump_database(){ bundle exec rails db:schema:load || bundle exec rails db:migrate } +bundle update bundle check || bundle install if bundle exec rails db:exists; then @@ -24,4 +25,4 @@ if [ -f $pidfile ] ; then rm $pidfile; fi -bundle exec passenger start +bundle exec foreman start From a158e775552b5aebf63a4f280ac72aacf07011f3 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Fri, 5 Jul 2019 01:52:50 +0530 Subject: [PATCH 10/30] WIP action cable setup --- app/assets/javascripts/cable.js | 13 +++++++++++++ .../javascripts/channels/concurrent_editing.js | 17 +++++++++++++++++ app/channels/application_cable/channel.rb | 4 ++++ app/channels/application_cable/connection.rb | 18 ++++++++++++++++++ app/channels/concurrent_editing_channel.rb | 12 ++++++++++++ app/views/layouts/application.html.erb | 1 + config/cable.yml | 4 +++- config/environments/production.rb | 2 ++ config/routes.rb | 2 ++ 9 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/cable.js create mode 100644 app/assets/javascripts/channels/concurrent_editing.js create mode 100644 app/channels/application_cable/channel.rb create mode 100644 app/channels/application_cable/connection.rb create mode 100644 app/channels/concurrent_editing_channel.rb diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 000000000..739aa5f02 --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js new file mode 100644 index 000000000..169d14131 --- /dev/null +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -0,0 +1,17 @@ +App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChannel", { + connected: function() { + // Called when the subscription is ready for use on the server + }, + + disconnected: function() { + // Called when the subscription has been terminated by the server + }, + + received: function(data) { + // Called when there's incoming data on the websocket for this channel + }, + + speak: function() { + return this.perform('speak'); + } +}); diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 000000000..7f5c00f22 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end \ No newline at end of file diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 000000000..681d8df73 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,18 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + identified_by :current_user + + def connect + self.current_user = find_verified_user + end + + private + def find_verified_user + if verified_user = User.find_by(id: session[:user_id]) + return verified_user + else + return nil + end + end + end +end \ No newline at end of file diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb new file mode 100644 index 000000000..9f58cfb2e --- /dev/null +++ b/app/channels/concurrent_editing_channel.rb @@ -0,0 +1,12 @@ +class ConcurrentEditingChannel < ApplicationCable::Channel + def subscribed + # stream_from "some_channel" + end + + def unsubscribed + # Any cleanup needed when channel is unsubscribed + end + + def speak + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 85bdb4cdf..4c6c92f4e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,6 +14,7 @@ <%= stylesheet_link_tag 'application' %> <%= javascript_include_tag 'application' %> + <%= action_cable_meta_tag %> <%= render 'layouts/header' %> diff --git a/config/cable.yml b/config/cable.yml index 8648dafa2..200f4b6d9 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,5 +1,7 @@ development: - adapter: async + adapter: redis + url: <%= "redis://localhost:6379/0" %> + channel_prefix: mapknitter_development test: adapter: async diff --git a/config/environments/production.rb b/config/environments/production.rb index a963d8cd9..db995c1ad 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -102,4 +102,6 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/] end diff --git a/config/routes.rb b/config/routes.rb index 29ca5d840..0363342d9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,8 @@ root to: 'front_ui#index' + mount ActionCable.server => '/cable' + get 'front-page', to: 'front_ui#index' get 'mappers', to: 'front_ui#nearby_mappers' get 'about', to: 'front_ui#about' From 35aa34fa4a4f02fc44b1043fe563e298c74bb9f9 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sat, 6 Jul 2019 23:46:51 +0530 Subject: [PATCH 11/30] basic action cable setup complete --- Gemfile | 3 ++- app/assets/javascripts/cable.js | 2 -- app/assets/javascripts/channels/concurrent_editing.js | 9 +++++++-- app/channels/application_cable/connection.rb | 2 +- app/channels/concurrent_editing_channel.rb | 5 +++-- app/controllers/application_controller.rb | 1 + app/views/layouts/application.html.erb | 2 +- config/cable.yml | 4 +--- config/environments/development.rb | 3 +++ 9 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 1e6127ee5..02d3d3bf0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -ruby '2.4.6' +# ruby '2.4.6' gem 'rails', '~> 5.2.3' gem 'rake', '~> 12.3.2' gem 'tzinfo-data' @@ -64,6 +64,7 @@ group :development, :test do gem 'byebug', '~> 11.0.1', platforms: [:mri, :mingw, :x64_mingw] gem 'faker', '~> 1.9.3' gem 'pry-rails', '~> 0.3.9' + gem 'puma' end group :development do diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js index 739aa5f02..f613e17f5 100644 --- a/app/assets/javascripts/cable.js +++ b/app/assets/javascripts/cable.js @@ -1,5 +1,3 @@ -// Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the `rails generate channel` command. // //= require action_cable //= require_self diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js index 169d14131..2705876ed 100644 --- a/app/assets/javascripts/channels/concurrent_editing.js +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -1,17 +1,22 @@ App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChannel", { connected: function() { // Called when the subscription is ready for use on the server + console.log("Connected"); }, disconnected: function() { // Called when the subscription has been terminated by the server + console.log("bye"); }, received: function(data) { // Called when there's incoming data on the websocket for this channel + console.log(data); }, - speak: function() { - return this.perform('speak'); + speak: function(changes) { + return this.perform("sync", { + changes: changes + }); } }); diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 681d8df73..31bed6179 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -8,7 +8,7 @@ def connect private def find_verified_user - if verified_user = User.find_by(id: session[:user_id]) + if verified_user = User.find_by(id: cookies.signed["user_id"]) return verified_user else return nil diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb index 9f58cfb2e..2ce2941d4 100644 --- a/app/channels/concurrent_editing_channel.rb +++ b/app/channels/concurrent_editing_channel.rb @@ -1,12 +1,13 @@ class ConcurrentEditingChannel < ApplicationCable::Channel def subscribed - # stream_from "some_channel" + stream_from "concurrent_editing_channel" end def unsubscribed # Any cleanup needed when channel is unsubscribed end - def speak + def sync changes + ActionCable.server.broadcast 'concurrent_editing_channel', changes end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4d4bf7521..8f0f95404 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,6 +14,7 @@ def current_user if user_id begin @user = User.find(user_id) + cookies.signed["user_id"] = @current_user.id rescue StandardError @user = nil end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4c6c92f4e..2f5c573b9 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -13,8 +13,8 @@ <%= stylesheet_link_tag 'application' %> - <%= javascript_include_tag 'application' %> <%= action_cable_meta_tag %> + <%= javascript_include_tag 'application' %> <%= render 'layouts/header' %> diff --git a/config/cable.yml b/config/cable.yml index 200f4b6d9..8648dafa2 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,7 +1,5 @@ development: - adapter: redis - url: <%= "redis://localhost:6379/0" %> - channel_prefix: mapknitter_development + adapter: async test: adapter: async diff --git a/config/environments/development.rb b/config/environments/development.rb index d4ca60dce..2e870ab0e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -74,4 +74,7 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + config.action_cable.url = "ws://localhost:3000/cable" + config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/] end From 26105221eaa588261c69504113aeedfeb73a742f Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sat, 6 Jul 2019 23:48:11 +0530 Subject: [PATCH 12/30] minor change --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 02d3d3bf0..dacbd97da 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -# ruby '2.4.6' +ruby '2.4.6' gem 'rails', '~> 5.2.3' gem 'rake', '~> 12.3.2' gem 'tzinfo-data' From 4040bc302027b66f775d0aa76e22dc48574ff46c Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 11 Jul 2019 00:25:56 +0530 Subject: [PATCH 13/30] minor changes --- app/controllers/application_controller.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8f0f95404..8357487a3 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,8 +13,9 @@ def current_user user_id = session[:user_id] if user_id begin - @user = User.find(user_id) - cookies.signed["user_id"] = @current_user.id + u = User.find(user_id) + cookies.signed["user_id"] = u.id + @user = u rescue StandardError @user = nil end From e2314189b538cf6cec36baef19c3947b8ae66c81 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sun, 14 Jul 2019 14:09:52 +0530 Subject: [PATCH 14/30] few changes --- app/assets/javascripts/mapknitter/Map.js | 3 +++ app/controllers/images_controller.rb | 3 ++- app/models/map.rb | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/mapknitter/Map.js b/app/assets/javascripts/mapknitter/Map.js index 0e2cf570c..3e31dbc58 100644 --- a/app/assets/javascripts/mapknitter/Map.js +++ b/app/assets/javascripts/mapknitter/Map.js @@ -499,6 +499,9 @@ MapKnitter.Map = MapKnitter.Class.extend({ beforeSend: function (e) { $('.mk-save').removeClass('fa-check-circle fa-times-circle fa-green fa-red').addClass('fa-spinner fa-spin') }, + success: function(data) { + App.concurrent_editing.speak(data); + }, complete: function (e) { $('.mk-save').removeClass('fa-spinner fa-spin').addClass('fa-check-circle fa-green') }, diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index af14b8ec7..97518a19d 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -93,7 +93,8 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save - render html: 'success' + data = Map.fetch_map_data + render json: data end def destroy diff --git a/app/models/map.rb b/app/models/map.rb index 7d65e3ecb..e9030cd09 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -273,4 +273,9 @@ def add_tag(tagname, user) tagname = tagname.downcase tags.create(name: tagname, user_id: user.id, map_id: id) unless has_tag(tagname) end + + def self.fetch_map_data + data = {} + data + end end From 55baec467ca478aec20b304b5203e529f5f7bfcd Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 18 Jul 2019 12:10:01 +0530 Subject: [PATCH 15/30] initial working functionality complete --- .../channels/concurrent_editing.js | 2 +- app/assets/javascripts/mapknitter/Map.js | 22 +++++++++++++++++++ app/controllers/images_controller.rb | 2 +- app/models/map.rb | 6 ++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js index 2705876ed..079c7933e 100644 --- a/app/assets/javascripts/channels/concurrent_editing.js +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -11,7 +11,7 @@ App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChanne received: function(data) { // Called when there's incoming data on the websocket for this channel - console.log(data); + window.mapKnitter.synchronizeData(data.changes); }, speak: function(changes) { diff --git a/app/assets/javascripts/mapknitter/Map.js b/app/assets/javascripts/mapknitter/Map.js index 3e31dbc58..b433d973e 100644 --- a/app/assets/javascripts/mapknitter/Map.js +++ b/app/assets/javascripts/mapknitter/Map.js @@ -462,6 +462,28 @@ MapKnitter.Map = MapKnitter.Class.extend({ if (this.editing._mode != "lock") e.stopPropagation() }, + synchronizeData: function(warpables) { + var layers = []; + map.eachLayer(function(l) {layers.push(l)}); + layers = layers.filter(image => (image._url!=undefined || image._url!=null)); + warpables.forEach(function(warpable) { + corners = []; + warpable.nodes.forEach(function(node) { + corners.push(L.latLng(node.lat, node.lon)); + }); + + x = corners[2]; + y = corners [3]; + corners [2] = y; + corners [3] = x; + + console.log(corners); + + layer = layers.filter(l => l._url==warpable.srcmedium)[0]; + layer.setCorners(corners); + }); + }, + saveImageIfChanged: function () { var img = this // check if image state has changed at all before saving! diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 97518a19d..31b741181 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -93,7 +93,7 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save - data = Map.fetch_map_data + data = @warpable.map.fetch_map_data render json: data end diff --git a/app/models/map.rb b/app/models/map.rb index e9030cd09..8d182f305 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -274,8 +274,8 @@ def add_tag(tagname, user) tags.create(name: tagname, user_id: user.id, map_id: id) unless has_tag(tagname) end - def self.fetch_map_data - data = {} - data + def fetch_map_data + data = warpables + return data.to_json end end From 4904217e191d4b2b1e2c52e38335838b55d52f1d Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Tue, 30 Jul 2019 15:35:22 -0300 Subject: [PATCH 16/30] Refactoring code --- app/channels/application_cable/channel.rb | 2 +- app/channels/application_cable/connection.rb | 9 +++------ app/channels/concurrent_editing_channel.rb | 2 +- app/models/map.rb | 2 +- yarn.lock | 11 +++-------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index 7f5c00f22..d67269728 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,4 +1,4 @@ module ApplicationCable class Channel < ActionCable::Channel::Base end -end \ No newline at end of file +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 31bed6179..bfb67cc7a 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -7,12 +7,9 @@ def connect end private + def find_verified_user - if verified_user = User.find_by(id: cookies.signed["user_id"]) - return verified_user - else - return nil - end + User.find(id: cookies.signed["user_id"]) end end -end \ No newline at end of file +end diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb index 2ce2941d4..c3a58a43b 100644 --- a/app/channels/concurrent_editing_channel.rb +++ b/app/channels/concurrent_editing_channel.rb @@ -7,7 +7,7 @@ def unsubscribed # Any cleanup needed when channel is unsubscribed end - def sync changes + def sync(changes) ActionCable.server.broadcast 'concurrent_editing_channel', changes end end diff --git a/app/models/map.rb b/app/models/map.rb index 8d182f305..9da67ac91 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -276,6 +276,6 @@ def add_tag(tagname, user) def fetch_map_data data = warpables - return data.to_json + data.to_json end end diff --git a/yarn.lock b/yarn.lock index 8027feb8c..754337165 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3348,9 +3348,9 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" -"leaflet-blurred-location@git://github.com/publiclab/leaflet-blurred-location.git#main": +"leaflet-blurred-location@git://github.com/publiclab/leaflet-blurred-location#main": version "1.3.0" - resolved "git://github.com/publiclab/leaflet-blurred-location.git#1bff37cb96518bd87192277b14c290cba3c138ba" + resolved "git://github.com/publiclab/leaflet-blurred-location#1bff37cb96518bd87192277b14c290cba3c138ba" dependencies: haversine-distance "^1.1.4" jquery "^3.2.1" @@ -3453,12 +3453,7 @@ leaflet.blurred-location-display@^1.1.0: jquery "^3.3.1" leaflet-blurred-location "git://github.com/publiclab/leaflet-blurred-location#main" -leaflet@*, leaflet@^1.3.1, leaflet@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.5.1.tgz#9afb9d963d66c870066b1342e7a06f92840f46bf" - integrity sha512-ekM9KAeG99tYisNBg0IzEywAlp0hYI5XRipsqRXyRTeuU8jcuntilpp+eFf5gaE0xubc9RuSNIVtByEKwqFV0w== - -leaflet@Leaflet/Leaflet#^1.0.0: +leaflet@*, leaflet@Leaflet/Leaflet#^1.0.0, leaflet@^1.3.1, leaflet@^1.3.3: version "1.5.1" resolved "https://codeload.github.com/Leaflet/Leaflet/tar.gz/2e3e0ffbe87f246eb76d86d2633ddd59b262830b" From 53084a1f2befdc3a6a17f3aef1c0df5b79c3c3c6 Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Sat, 3 Aug 2019 22:50:23 -0300 Subject: [PATCH 17/30] Adding Foreman gem --- Gemfile | 3 +++ Gemfile.lock | 5 ++++- Procfile | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Procfile diff --git a/Gemfile b/Gemfile index dacbd97da..6183e2dac 100644 --- a/Gemfile +++ b/Gemfile @@ -36,6 +36,9 @@ group :dependencies do # compiling markdown to html gem 'rdiscount', '2.2.0.1' + # Process manager for applications with multiple components + gem "foreman", "~> 0.85.0" + # asset pipelining gem 'bootstrap-sass' gem 'sassc-rails' diff --git a/Gemfile.lock b/Gemfile.lock index c2af24df3..2099beaf5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,6 +77,8 @@ GEM faker (1.9.6) i18n (>= 0.7) ffi (1.11.1) + foreman (0.85.0) + thor (~> 0.19.1) friendly_id (5.2.5) activerecord (>= 4.0.0) geokit (1.13.1) @@ -268,7 +270,7 @@ GEM sqlite3 (1.4.1) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) - thor (0.20.3) + thor (0.19.4) thread_safe (0.3.6) tilt (2.0.9) turbolinks (5.2.0) @@ -307,6 +309,7 @@ DEPENDENCIES byebug (~> 11.0.1) codecov faker (~> 1.9.3) + foreman (~> 0.85.0) friendly_id geokit-rails (= 1.1.4) httparty diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..841da4133 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +passenger: passenger start +puma: puma -C config/puma.rb From add9f169bef4e709e759f01716a2dda2d6bfaee3 Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Sat, 3 Aug 2019 22:51:27 -0300 Subject: [PATCH 18/30] Scheduling Puma and Passenger servers --- config/puma.rb | 5 +++++ start.sh | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 config/puma.rb diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 000000000..a6860886a --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,5 @@ +#!/usr/bin/env puma + +environment ENV.fetch("RAILS_ENV") { "production" } + +pidfile '/app/tmp/pids/puma.pid' \ No newline at end of file diff --git a/start.sh b/start.sh index 517a983d1..d2287d916 100755 --- a/start.sh +++ b/start.sh @@ -6,6 +6,7 @@ bump_database(){ bundle exec rails db:schema:load || bundle exec rails db:migrate } +bundle update bundle check || bundle install if bundle exec rails db:exists; then @@ -24,4 +25,4 @@ if [ -f $pidfile ] ; then rm $pidfile; fi -bundle exec passenger start +bundle exec foreman start From 87deccd226db8846b36d89ad8358c2e28e26bdbf Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sun, 4 Aug 2019 21:21:15 +0530 Subject: [PATCH 19/30] few minor fix --- app/channels/application_cable/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index bfb67cc7a..ce6a480e6 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -9,7 +9,7 @@ def connect private def find_verified_user - User.find(id: cookies.signed["user_id"]) + User.find_by(id: cookies.signed["user_id"]) end end end From 24328056e7273dacc5516993636ed3a453b76b8c Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Tue, 6 Aug 2019 23:37:17 +0530 Subject: [PATCH 20/30] added a few tests --- Gemfile | 1 + app/channels/application_cable/connection.rb | 6 +++- .../concurrent_editing_channel_test.rb | 10 ++++++ test/channels/connection_test.rb | 32 +++++++++++++++++++ test/fixtures/maps.yml | 4 +-- 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 test/channels/concurrent_editing_channel_test.rb create mode 100644 test/channels/connection_test.rb diff --git a/Gemfile b/Gemfile index 6183e2dac..fb3362f78 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,7 @@ group :development, :test do gem 'faker', '~> 1.9.3' gem 'pry-rails', '~> 0.3.9' gem 'puma' + gem 'action-cable-testing' end group :development do diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index ce6a480e6..705088557 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -9,7 +9,11 @@ def connect private def find_verified_user - User.find_by(id: cookies.signed["user_id"]) + if current_user = User.find_by(id: cookies.signed["user_id"]) + current_user + else + reject_unauthorized_connection + end end end end diff --git a/test/channels/concurrent_editing_channel_test.rb b/test/channels/concurrent_editing_channel_test.rb new file mode 100644 index 000000000..a3cd24773 --- /dev/null +++ b/test/channels/concurrent_editing_channel_test.rb @@ -0,0 +1,10 @@ +require 'test_helper' + +class ConcurrentEditingChannelTest < ActionCable::Channel::TestCase + # test "the truth" do + # assert true + # end + # + + +end diff --git a/test/channels/connection_test.rb b/test/channels/connection_test.rb new file mode 100644 index 000000000..b2341ffd3 --- /dev/null +++ b/test/channels/connection_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' +require 'byebug' + +module ApplicationCable + class ConnectionTest < ActionCable::Connection::TestCase + def test_connection_with_user + cookies.signed["user_id"] = users(:chris) + + #this simulates the connection + connect + + # assert connected user + assert_equal "chris", connection.current_user.login + end + + def test_does_not_connect_without_user + + # user not logged in + begin + # trying to connect but fails + connect + rescue Exception=>e + + #compare the error class + assert_equal e.class, ActionCable::Connection::Authorization::UnauthorizedError + end + + #check is connection is nil(which it should be) + assert_equal nil, connection + end + end +end diff --git a/test/fixtures/maps.yml b/test/fixtures/maps.yml index 2e9c1f20d..76dab52c6 100644 --- a/test/fixtures/maps.yml +++ b/test/fixtures/maps.yml @@ -34,7 +34,7 @@ nairobi: lat: -1.2920659 lon: 36.8219462 description: Capital of Kenya - created_at: <% Time.now %> + created_at: <%= Time.now %> license: publicdomain user_id: 2 author: aaron @@ -47,7 +47,7 @@ village: lat: -0.023559 lon: 37.90619300000003 description: A mall in Nairobi - created_at: <% Time.now %> + created_at: <%= Time.now %> license: publicdomain user_id: 2 author: aaron From 54b5ef740618be135e7cbb642082a23c8a4d209d Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Tue, 6 Aug 2019 15:47:45 -0300 Subject: [PATCH 21/30] Refactoring connection module --- app/channels/application_cable/connection.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index c8e8904ce..b50f7585a 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -9,10 +9,9 @@ def connect private def find_verified_user - User.find(id: cookies.signed["user_id"]) - rescue + User.find(cookies.signed["user_id"]) + rescue ActiveRecord::RecordNotFound reject_unauthorized_connection - end - + end end end From 9191cf6996b3626478dab9383615a87d534d0022 Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Tue, 6 Aug 2019 16:08:51 -0300 Subject: [PATCH 22/30] Using strong params in requests --- app/controllers/images_controller.rb | 4 ++-- test/controllers/images_controller_test.rb | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 6ef5d486b..d96348659 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -1,8 +1,8 @@ require 'open-uri' class ImagesController < ApplicationController rescue_from Errno::ENOENT, Errno::ETIMEDOUT, - OpenURI::HTTPError, Timeout::Error, - with: :url_upload_not_found + OpenURI::HTTPError, Timeout::Error, + with: :url_upload_not_found protect_from_forgery except: %i(update delete) # Convert model to json without including root name. Eg. 'warpable' ActiveRecord::Base.include_root_in_json = false diff --git a/test/controllers/images_controller_test.rb b/test/controllers/images_controller_test.rb index bf0628f5a..99ef9c2c8 100644 --- a/test/controllers/images_controller_test.rb +++ b/test/controllers/images_controller_test.rb @@ -83,7 +83,7 @@ def fetch_in_production test 'creates version after image creation' do session[:user_id] = 1 assert_difference 'PaperTrail::Version.count', 1 do - post :create, map_id: @map.slug, uploaded_data: @uploaded_data + post :create, params: { map_id: @map.slug, uploaded_data: @uploaded_data } end warp = Warpable.last assert warp.versions.present? @@ -94,7 +94,7 @@ def fetch_in_production session[:user_id] = 1 assert_difference 'PaperTrail::Version.count', 1 do - patch :update, id: @map.id, warpable_id: @warp.id, locked: false, points: points + patch :update, params: { id: @map.id, warpable_id: @warp.id, locked: false, points: points } end assert_response :success assert @warp.versions.present? @@ -106,12 +106,12 @@ def fetch_in_production points1 = "-72.39,41.83:-72.39,41.83:-72.39,41.83:-72.39,41.84" points2 = "-72.39,40.83:-72.39,41.83:-72.39,41.83:-71.39,45.84" - patch :update, id: @map.id, warpable_id: @warp.id, locked: false, points: points1 + patch :update, params: { id: @map.id, warpable_id: @warp.id, locked: false, points: points1 } @warp.reload nodes_latest = @warp.nodes - patch :update, id: @map.id, warpable_id: @warp.id, locked: false, points: points2 + patch :update, params: { id: @map.id, warpable_id: @warp.id, locked: false, points: points2 } assert_difference 'PaperTrail::Version.count', 1 do - get :revert, id: @warp.id, version: @warp.versions.last + get :revert, params: { id: @warp.id, version: @warp.versions.last } end @warp.reload assert_equal(nodes_latest, @warp.nodes) From f271a84f7444bca64bab57d16cdcad82fa77c80a Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 15 Aug 2019 00:38:04 +0530 Subject: [PATCH 23/30] added documentation --- app/assets/javascripts/channels/concurrent_editing.js | 8 ++++++-- app/assets/javascripts/mapknitter/Map.js | 4 ++++ app/channels/concurrent_editing_channel.rb | 4 ++++ app/controllers/images_controller.rb | 2 ++ app/models/map.rb | 1 + 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/channels/concurrent_editing.js b/app/assets/javascripts/channels/concurrent_editing.js index 079c7933e..f93e01e45 100644 --- a/app/assets/javascripts/channels/concurrent_editing.js +++ b/app/assets/javascripts/channels/concurrent_editing.js @@ -1,12 +1,12 @@ +/* Handles all the frontend interactions with action cable and the server. */ + App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChannel", { connected: function() { // Called when the subscription is ready for use on the server - console.log("Connected"); }, disconnected: function() { // Called when the subscription has been terminated by the server - console.log("bye"); }, received: function(data) { @@ -15,6 +15,10 @@ App.concurrent_editing = App.cable.subscriptions.create("ConcurrentEditingChanne }, speak: function(changes) { + /* Called when an image is updated from Map.js ('saveImage' function). + * This function calls concurrent_editing_channel.rb's 'sync' method + * which is responsible for broadcasting the updated warpables + * to all the user's connected to the concurrent_editing channel. */ return this.perform("sync", { changes: changes }); diff --git a/app/assets/javascripts/mapknitter/Map.js b/app/assets/javascripts/mapknitter/Map.js index b7058dc39..67363f518 100644 --- a/app/assets/javascripts/mapknitter/Map.js +++ b/app/assets/javascripts/mapknitter/Map.js @@ -388,6 +388,10 @@ MapKnitter.Map = MapKnitter.Class.extend({ if (this.editing._mode !== "lock") { e.stopPropagation(); } }, + /* Called by the concurrent_editing.js channel's 'received' function (app/assets/javascripts/channels/concurrent_editing.js). + * It recieves a list of updated warpables,i.e. list of images with updated corner points. The aim of writing this function + * is to reposition the updated images onto the map on every connected browser (via the ActionCable). */ + synchronizeData: function(warpables) { var layers = []; map.eachLayer(function(l) {layers.push(l)}); diff --git a/app/channels/concurrent_editing_channel.rb b/app/channels/concurrent_editing_channel.rb index c3a58a43b..79991c3b1 100644 --- a/app/channels/concurrent_editing_channel.rb +++ b/app/channels/concurrent_editing_channel.rb @@ -1,5 +1,8 @@ class ConcurrentEditingChannel < ApplicationCable::Channel + # This class handles the server side logic of the actioncable communication. + def subscribed + # Called first to connect user to the channel. stream_from "concurrent_editing_channel" end @@ -8,6 +11,7 @@ def unsubscribed end def sync(changes) + # Responsible for broadcasting the updated warpables or simply images to the user's connected on this channel. ActionCable.server.broadcast 'concurrent_editing_channel', changes end end diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index d96348659..04eb10558 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -92,6 +92,8 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save + data = @warpable.map.fetch_map_data # Get the updated warpable data + render json: data render html: 'success' else render plain: 'You must be logged in to update the image, unless the map is anonymous.' diff --git a/app/models/map.rb b/app/models/map.rb index 9da67ac91..ab001ff16 100755 --- a/app/models/map.rb +++ b/app/models/map.rb @@ -275,6 +275,7 @@ def add_tag(tagname, user) end def fetch_map_data + # fetches a list of updated warpables along with their corners in a json format. data = warpables data.to_json end From fe95fc8eaad8e2671eefb4f7b67a7581b93add8e Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 15 Aug 2019 00:39:33 +0530 Subject: [PATCH 24/30] added more docs --- SYNCHRONOUS_EDITING.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 SYNCHRONOUS_EDITING.md diff --git a/SYNCHRONOUS_EDITING.md b/SYNCHRONOUS_EDITING.md new file mode 100644 index 000000000..66819275f --- /dev/null +++ b/SYNCHRONOUS_EDITING.md @@ -0,0 +1,30 @@ +The new synchronous editing feature +=================================== + +With the introduction of ActionCable to our system, it has been possible +to do perform real-time tasks quite easily. We have used rail's default +action cable to make a _concurrent_editing_channel.rb_ in the _app/channels_ folder, +to handle all the incoming requests and consists of all the business +logic as well. At the frontend we have, _app/javascripts/channels/concurrent_editing.js_ which +handles the logic at the browser or the frontend. + +## Flow of the feature: + +1. When the map is updated, the _speak_ method of _concurrent_editing.js_ is called which requests +the _sync_ method of _concurrent_editing_channel.rb_ to broadcast the updated data to +the connected users. + +2. The broadcasted data is finally caught by the _received_ function of _app/javascripts/channels/concurrent_editing.js_ + +3. Finally the _received_ function calls the _synchronizeData_ function to update + all the fresh data on the map. + + +## Testing: + +1. The _action-cable-testing_ gem is used for the feature's testing. It has some really +cool testing functionality which was required for our use case. + +2. Currently we have separate tests written for connection related features and channel +specific features. The relevant files are test/channels/concurrent_editing_channel_test.rb and +test/channels/connection_test.rb \ No newline at end of file From 53bd5aba0bdc0b995649f1560c507cbde5da98dc Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Thu, 15 Aug 2019 00:43:30 +0530 Subject: [PATCH 25/30] added tests --- .../concurrent_editing_channel_test.rb | 23 +++++++++++++++---- test/channels/connection_test.rb | 1 - 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/test/channels/concurrent_editing_channel_test.rb b/test/channels/concurrent_editing_channel_test.rb index a3cd24773..b458255e3 100644 --- a/test/channels/concurrent_editing_channel_test.rb +++ b/test/channels/concurrent_editing_channel_test.rb @@ -1,10 +1,23 @@ require 'test_helper' -class ConcurrentEditingChannelTest < ActionCable::Channel::TestCase - # test "the truth" do - # assert true - # end - # +module ApplicationCable + class ConcurrentEditingChannelTest < ActionCable::Channel::TestCase + def test_synch_editing_broadcast_count + channel_name = "concurrent_editing_channel" + assert_broadcasts channel_name, 0 + ActionCable.server.broadcast channel_name, data: {} + assert_broadcasts channel_name, 1 + end + + def test_synch_editing_broadcast_message + channel_name = "concurrent_editing_channel" + changes = { :image_change => "test" } + ActionCable.server.broadcast channel_name, data: changes + assert_broadcast_on(channel_name, data: changes) do + ActionCable.server.broadcast channel_name, data: changes + end + end + end end diff --git a/test/channels/connection_test.rb b/test/channels/connection_test.rb index b2341ffd3..309565779 100644 --- a/test/channels/connection_test.rb +++ b/test/channels/connection_test.rb @@ -1,5 +1,4 @@ require 'test_helper' -require 'byebug' module ApplicationCable class ConnectionTest < ActionCable::Connection::TestCase From ac8e40cf036eada9f684ba11cefcda769b2b546b Mon Sep 17 00:00:00 2001 From: Alax Alves Date: Fri, 16 Aug 2019 16:26:52 -0300 Subject: [PATCH 26/30] Using puma as dependency and correct image controller --- Gemfile | 7 +++---- Gemfile.lock | 2 +- app/channels/application_cable/connection.rb | 2 +- app/controllers/images_controller.rb | 6 ++---- start.sh | 1 - 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index a707d4813..f650ef928 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,7 @@ group :dependencies do gem 'bootsnap', '~> 1.4.4' gem 'turbolinks', '~> 5' gem 'mini_magick', '~> 4.8' + gem 'puma', '~> 4.1.0' # if you use amazon s3 for warpable image storage gem 'aws-sdk', '~> 1.5.7' @@ -38,14 +39,14 @@ group :dependencies do gem 'rdiscount', '2.2.0.1' # Process manager for applications with multiple components - gem "foreman", "~> 0.85.0" + gem 'foreman', '~> 0.85.0' # asset pipelining gem 'bootstrap-sass' gem 'sassc-rails' gem 'jquery-rails' gem 'sprockets', '3.7.2' - gem "sprockets-rails" + gem 'sprockets-rails' gem 'sass', require: 'sass' gem 'autoprefixer-rails', '~> 9.5.1.1' gem 'uglifier', '~> 4.1.20' @@ -66,12 +67,10 @@ end group :development, :test do gem 'capybara' - gem 'puma' gem 'selenium-webdriver' gem 'byebug', '~> 11.0.1', platforms: [:mri, :mingw, :x64_mingw] gem 'faker', '~> 2.1.2' gem 'pry-rails', '~> 0.3.9' - gem 'puma' gem 'action-cable-testing' end diff --git a/Gemfile.lock b/Gemfile.lock index 44924c3f5..af271d710 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -360,7 +360,7 @@ DEPENDENCIES passenger popper_js (~> 1.11, >= 1.11.1) pry-rails (~> 0.3.9) - puma + puma (~> 4.1.0) rails (~> 5.2.3) rails-controller-testing rails-perftest diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index b50f7585a..a76243b26 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -12,6 +12,6 @@ def find_verified_user User.find(cookies.signed["user_id"]) rescue ActiveRecord::RecordNotFound reject_unauthorized_connection - end + end end end diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 04eb10558..6ef5d486b 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -1,8 +1,8 @@ require 'open-uri' class ImagesController < ApplicationController rescue_from Errno::ENOENT, Errno::ETIMEDOUT, - OpenURI::HTTPError, Timeout::Error, - with: :url_upload_not_found + OpenURI::HTTPError, Timeout::Error, + with: :url_upload_not_found protect_from_forgery except: %i(update delete) # Convert model to json without including root name. Eg. 'warpable' ActiveRecord::Base.include_root_in_json = false @@ -92,8 +92,6 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save - data = @warpable.map.fetch_map_data # Get the updated warpable data - render json: data render html: 'success' else render plain: 'You must be logged in to update the image, unless the map is anonymous.' diff --git a/start.sh b/start.sh index d2287d916..674e2b563 100755 --- a/start.sh +++ b/start.sh @@ -6,7 +6,6 @@ bump_database(){ bundle exec rails db:schema:load || bundle exec rails db:migrate } -bundle update bundle check || bundle install if bundle exec rails db:exists; then From f002ad0dbbf689fe81b7b8426b6fbe3b25ebd6e8 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sun, 18 Aug 2019 18:28:48 +0530 Subject: [PATCH 27/30] added a few tests --- test/fixtures/nodes.yml | 13 +++++++++++++ test/system/synchronous_editing_test.rb | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/system/synchronous_editing_test.rb diff --git a/test/fixtures/nodes.yml b/test/fixtures/nodes.yml index 3759b4cee..d16cde45c 100644 --- a/test/fixtures/nodes.yml +++ b/test/fixtures/nodes.yml @@ -56,3 +56,16 @@ four: way_order: 0 body: nil +five: + id: 5 + color: "black" + author: "anonymous" + lat: 42.8377535388083 + lon: -75.3981708900972 + way_id: 0 + order: 0 + name: "" + description: "" + map_id: 1 + way_order: 0 + body: nil diff --git a/test/system/synchronous_editing_test.rb b/test/system/synchronous_editing_test.rb new file mode 100644 index 000000000..04acbfd85 --- /dev/null +++ b/test/system/synchronous_editing_test.rb @@ -0,0 +1,16 @@ +require 'application_system_test_case' + +class SynchronousTest < ApplicationSystemTestCase + setup do + Capybara.current_driver = Capybara.javascript_driver + Capybara.asset_host = "http://localhost:3000" + end + + test 'warpables change flow' do + map = maps(:saugus) + original_data = map.fetch_map_data + map.warpables.first.update(nodes: "2,5,1,3") + updated_data = map.fetch_map_data + assert_not_equal updated_data, original_data + end +end \ No newline at end of file From 1464157c3531f7ff7dc709edf9b73e9b77011c39 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Sun, 18 Aug 2019 19:56:14 +0530 Subject: [PATCH 28/30] a few changes --- app/controllers/images_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 6ef5d486b..954e34eb0 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -92,6 +92,12 @@ def update @warpable.locked = params[:locked] @warpable.cm_per_pixel = @warpable.get_cm_per_pixel @warpable.save + + respond_to do |format| + format.html { render html: 'success' } + format.json { render json: @warpable.map.fetch_map_data } + end + render html: 'success' else render plain: 'You must be logged in to update the image, unless the map is anonymous.' From b033cc5273d423648287b7621c7e07af49af0338 Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Mon, 19 Aug 2019 20:31:57 +0530 Subject: [PATCH 29/30] remove unnecessary render --- app/controllers/images_controller.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 954e34eb0..cf773b22b 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -97,8 +97,6 @@ def update format.html { render html: 'success' } format.json { render json: @warpable.map.fetch_map_data } end - - render html: 'success' else render plain: 'You must be logged in to update the image, unless the map is anonymous.' end From e568fbea32b198a1037321bfa5572e626248651e Mon Sep 17 00:00:00 2001 From: viditchitkara Date: Tue, 20 Aug 2019 10:24:52 +0530 Subject: [PATCH 30/30] few test fixes --- test/system/synchronous_editing_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/system/synchronous_editing_test.rb b/test/system/synchronous_editing_test.rb index 04acbfd85..2dde3353a 100644 --- a/test/system/synchronous_editing_test.rb +++ b/test/system/synchronous_editing_test.rb @@ -9,7 +9,7 @@ class SynchronousTest < ApplicationSystemTestCase test 'warpables change flow' do map = maps(:saugus) original_data = map.fetch_map_data - map.warpables.first.update(nodes: "2,5,1,3") + map.warpables.first.update_column(:nodes, "2,5,1,3") updated_data = map.fetch_map_data assert_not_equal updated_data, original_data end