layers_of_london-booth-map_tool 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +621 -0
  3. data/README.md +28 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/config/layers_of_london_booth_map_tool_manifest.js +2 -0
  6. data/app/assets/javascripts/layers_of_london/booth/map_tool/application.js +15 -0
  7. data/app/assets/javascripts/layers_of_london/booth/map_tool/maptools.js +2 -0
  8. data/app/assets/javascripts/layers_of_london/booth/map_tool/polygons.js +2 -0
  9. data/app/assets/javascripts/layers_of_london/booth/map_tool/squares.js +2 -0
  10. data/app/assets/stylesheets/layers_of_london/booth/map_tool/application.css +15 -0
  11. data/app/assets/stylesheets/layers_of_london/booth/map_tool/maptools.css +4 -0
  12. data/app/assets/stylesheets/layers_of_london/booth/map_tool/polygons.css +4 -0
  13. data/app/assets/stylesheets/layers_of_london/booth/map_tool/squares.css +4 -0
  14. data/app/controllers/layers_of_london/booth/map_tool/application_controller.rb +35 -0
  15. data/app/controllers/layers_of_london/booth/map_tool/maptools_controller.rb +8 -0
  16. data/app/controllers/layers_of_london/booth/map_tool/polygons_controller.rb +68 -0
  17. data/app/controllers/layers_of_london/booth/map_tool/squares_controller.rb +79 -0
  18. data/app/helpers/layers_of_london/booth/map_tool/application_helper.rb +8 -0
  19. data/app/helpers/layers_of_london/booth/map_tool/maptools_helper.rb +4 -0
  20. data/app/helpers/layers_of_london/booth/map_tool/polygons_helper.rb +4 -0
  21. data/app/helpers/layers_of_london/booth/map_tool/squares_helper.rb +4 -0
  22. data/app/jobs/layers_of_london/booth/map_tool/application_job.rb +8 -0
  23. data/app/mailers/layers_of_london/booth/map_tool/application_mailer.rb +10 -0
  24. data/app/models/layers_of_london/booth/map_tool/application_record.rb +9 -0
  25. data/app/models/layers_of_london/booth/map_tool/polygon.rb +20 -0
  26. data/app/models/layers_of_london/booth/map_tool/square.rb +146 -0
  27. data/app/policies/layers_of_london/booth/map_tool/polygon_policy.rb +25 -0
  28. data/app/views/layers_of_london/booth/map_tool/maptools/show.html.erb +2 -0
  29. data/app/views/layers_of_london/booth/map_tool/polygons/create.html.erb +2 -0
  30. data/app/views/layers_of_london/booth/map_tool/polygons/destroy.html.erb +2 -0
  31. data/app/views/layers_of_london/booth/map_tool/polygons/index.html.erb +2 -0
  32. data/app/views/layers_of_london/booth/map_tool/polygons/update.html.erb +2 -0
  33. data/app/views/layers_of_london/booth/map_tool/squares/create.html.erb +2 -0
  34. data/app/views/layers_of_london/booth/map_tool/squares/edit.html.erb +2 -0
  35. data/app/views/layers_of_london/booth/map_tool/squares/index.html.erb +2 -0
  36. data/app/views/layers_of_london/booth/map_tool/squares/show.html.erb +2 -0
  37. data/app/views/layers_of_london/booth/map_tool/squares/update.html.erb +2 -0
  38. data/app/views/layouts/layers_of_london/booth/map_tool/application.html.erb +16 -0
  39. data/config/routes.rb +17 -0
  40. data/db/migrate/20190724120049_create_layers_of_london_booth_map_tool_squares.rb +7 -0
  41. data/db/migrate/20190724120136_create_layers_of_london_booth_map_tool_polygons.rb +10 -0
  42. data/db/migrate/20190731111508_add_aasm_state_to_squares.rb +5 -0
  43. data/db/migrate/20190802100700_add_locations_to_squares.rb +10 -0
  44. data/db/migrate/20190802120000_add_north_west_south_east_to_squares.rb +12 -0
  45. data/db/migrate/20190806161900_add_row_col_to_squares.rb +9 -0
  46. data/db/migrate/20190809151958_add_user_tracking_to_square.rb +5 -0
  47. data/lib/generators/map_tool/grid_generator.rb +28 -0
  48. data/lib/layers_of_london/booth/map_tool.rb +46 -0
  49. data/lib/layers_of_london/booth/map_tool/engine.rb +27 -0
  50. data/lib/layers_of_london/booth/map_tool/version.rb +7 -0
  51. data/lib/tasks/layers_of_london/booth/map_tool_tasks.rake +4 -0
  52. metadata +164 -0
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # LayersOfLondon::Booth::MapTool
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'layers_of_london-booth-map_tool'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install layers_of_london-booth-map_tool
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [GPL-3 License](https://opensource.org/licenses/GPL-3.0).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'LayersOfLondon::Booth::MapTool'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/layers_of_london/booth/map_tool .js
2
+ //= link_directory ../stylesheets/layers_of_london/booth/map_tool .css
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,35 @@
1
+ module LayersOfLondon
2
+ module Booth
3
+ module MapTool
4
+ class ApplicationController < ActionController::Base
5
+ include Pundit
6
+
7
+ protect_from_forgery with: :exception
8
+
9
+ after_action :verify_authorized
10
+ skip_after_action :verify_authorized, only: :session
11
+
12
+ skip_before_action :authenticate_user! rescue nil
13
+ skip_before_action :verify_authenticity_token rescue nil
14
+
15
+ # def current_user
16
+ # byebug
17
+ # main_app.scope.request.env['warden'].user
18
+ # end
19
+
20
+ def session
21
+ return render json: {} unless current_user.present?
22
+
23
+ render json: {
24
+ id: current_user.id,
25
+ email: current_user.email,
26
+ title: current_user.title,
27
+ first_name: current_user.first_name,
28
+ last_name: current_user.last_name,
29
+ role: current_user.role
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+ require_dependency "layers_of_london/booth/map_tool/application_controller"
2
+
3
+ module LayersOfLondon::Booth::MapTool
4
+ class MaptoolsController < ApplicationController
5
+ def show
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,68 @@
1
+ require_dependency "layers_of_london/booth/map_tool/application_controller"
2
+
3
+ module LayersOfLondon::Booth::MapTool
4
+ class PolygonsController < ApplicationController
5
+ def index
6
+ skip_authorization
7
+ features = LayersOfLondon::Booth::MapTool::Polygon.all.collect do |poly|
8
+ user_can_edit = LayersOfLondon::Booth::MapTool::PolygonPolicy.new(current_user, poly).update?
9
+ poly.to_json(user_can_edit: user_can_edit)
10
+ end
11
+
12
+ feature = {
13
+ type: "FeatureCollection",
14
+ features: features
15
+ }
16
+ render json: feature
17
+ end
18
+
19
+ def show
20
+ poly = LayersOfLondon::Booth::MapTool::Polygon.find(params[:id])
21
+ authorize poly
22
+
23
+ user_can_edit = LayersOfLondon::Booth::MapTool::PolygonPolicy.new(current_user, poly).update?
24
+ render json: poly.to_json(user_can_edit: user_can_edit)
25
+ end
26
+
27
+ def create
28
+ square = LayersOfLondon::Booth::MapTool::Square.find(params[:square_id]) rescue LayersOfLondon::Booth::MapTool::Square.create
29
+ poly = square.polygons.create(user: current_user, feature: polygon_params)
30
+ authorize poly
31
+
32
+ render json: poly.to_json(user_can_edit: true)
33
+ end
34
+
35
+ def update
36
+ poly = LayersOfLondon::Booth::MapTool::Polygon.find(params[:id])
37
+ authorize poly
38
+
39
+ return render json: {data: "Error"}, status: :unprocessable_entity unless poly
40
+
41
+ poly.assign_attributes(feature: polygon_params)
42
+
43
+ if poly.save
44
+ render json: poly.to_json(user_can_edit: true)
45
+ else
46
+ render json: {data: "Error"}, status: :unprocessable_entity
47
+ end
48
+ end
49
+
50
+ def destroy
51
+ poly = LayersOfLondon::Booth::MapTool::Polygon.find(params[:id])
52
+ authorize poly
53
+
54
+ return render json: {data: "Error"}, status: :unprocessable_entity unless poly
55
+
56
+ if poly.destroy
57
+ render json: :ok, status: :ok
58
+ else
59
+ render json: :error, status: :unprocessable_entity
60
+ end
61
+ end
62
+
63
+ private
64
+ def polygon_params
65
+ params.require(:feature)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,79 @@
1
+ require_dependency "layers_of_london/booth/map_tool/application_controller"
2
+
3
+ module LayersOfLondon::Booth::MapTool
4
+ class SquaresController < ApplicationController
5
+ skip_after_action :verify_authorized rescue nil
6
+
7
+ def index
8
+ squares = LayersOfLondon::Booth::MapTool::Square.where.not(aasm_state: :not_started)
9
+ render json: {
10
+ type: "FeatureCollection",
11
+ features: squares.collect(&:to_geojson)
12
+ }
13
+ end
14
+
15
+ def grid
16
+ render json: {
17
+ type: "FeatureCollection",
18
+ features: Square.grid_coordinates.collect do |coords|
19
+ {
20
+ type: "Feature",
21
+ geometry: {
22
+ type: "LineString",
23
+ coordinates: coords
24
+ },
25
+ properties: {}
26
+ }
27
+ end
28
+ }
29
+ end
30
+
31
+ def coordinates
32
+ squares = LayersOfLondon::Booth::MapTool::Square.all
33
+ square_data = squares.collect do |square|
34
+ {
35
+ id: square.id,
36
+ nw: square.north_west.to_a,
37
+ se: square.south_east.to_a
38
+ }
39
+ end
40
+
41
+ render json: square_data
42
+
43
+ end
44
+
45
+ def polygons
46
+ features = LayersOfLondon::Booth::MapTool::Polygon.all.collect do |polygon|
47
+ user_can_edit = LayersOfLondon::Booth::MapTool::PolygonPolicy.new(current_user, polygon).update?
48
+ polygon.to_json(user_can_edit: user_can_edit)
49
+ end
50
+
51
+ feature_collection = {
52
+ type: "FeatureCollection",
53
+ features: features
54
+ }
55
+
56
+ render json: feature_collection
57
+ end
58
+
59
+ def update
60
+ square = LayersOfLondon::Booth::MapTool::Square.find(params[:id])
61
+ proposed_state = params[:state]
62
+
63
+ if square.send("may_mark_as_#{proposed_state}?")
64
+ square.send("mark_as_#{proposed_state}")
65
+ square.user = current_user if square.aasm_state === "done"
66
+ square.save
67
+
68
+ render json: square.to_json
69
+ else
70
+ render json: {}, status: :unprocessable_entity
71
+ end
72
+ end
73
+
74
+ def show
75
+ square = LayersOfLondon::Booth::MapTool::Square.find(params[:id]) rescue LayersOfLondon::Booth::MapTool::Square.create
76
+ render json: square.to_json(padding: 20)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,8 @@
1
+ module LayersOfLondon
2
+ module Booth
3
+ module MapTool
4
+ module ApplicationHelper
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module LayersOfLondon::Booth::MapTool
2
+ module MaptoolsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module LayersOfLondon::Booth::MapTool
2
+ module PolygonsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module LayersOfLondon::Booth::MapTool
2
+ module SquaresHelper
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module LayersOfLondon
2
+ module Booth
3
+ module MapTool
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module LayersOfLondon
2
+ module Booth
3
+ module MapTool
4
+ class ApplicationMailer < ActionMailer::Base
5
+ default from: 'from@example.com'
6
+ layout 'mailer'
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module LayersOfLondon
2
+ module Booth
3
+ module MapTool
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module LayersOfLondon::Booth::MapTool
2
+ class Polygon < ApplicationRecord
3
+ belongs_to :square, optional: true
4
+ belongs_to :user
5
+
6
+ serialize :feature, JSON
7
+
8
+ def to_json(user_can_edit: false)
9
+ json_feature = {'properties' => {}}.merge(feature)
10
+ json_feature.inject({}) do |hash, (k,v)|
11
+ if k === 'properties'
12
+ v.merge!({'id' => id, 'userCanEdit': user_can_edit, 'square' => square.try(:to_json)})
13
+ end
14
+
15
+ hash[k] = v
16
+ hash
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,146 @@
1
+ require 'cmath'
2
+ module LayersOfLondon::Booth::MapTool
3
+ class Square < ApplicationRecord
4
+ has_many :polygons, dependent: :destroy
5
+
6
+ belongs_to :user, optional: true
7
+
8
+
9
+ validates_presence_of :north_west_lat, :north_west_lng, :south_east_lat, :south_east_lng, :square_size
10
+
11
+ before_validation on: :create do
12
+ self.north_west_lat = self.north_west_lat
13
+ self.north_west_lng = self.north_west_lng
14
+ self.square_size = LayersOfLondon::Booth::MapTool.configuration.square_size
15
+ self.south_east_lat = south_east.lat
16
+ self.south_east_lng = south_east.lng
17
+ self.geojson = self.to_geojson
18
+ end
19
+
20
+ serialize :geojson, JSON
21
+
22
+ include AASM
23
+ aasm do
24
+ state :not_started, initial: true
25
+ state :in_progress
26
+ state :done
27
+ state :verified
28
+ state :flagged
29
+
30
+ event :mark_as_in_progress do
31
+ transitions from: :not_started, to: [:in_progress]
32
+ end
33
+
34
+ event :mark_as_done do
35
+ transitions from: [:in_progress, :flagged], to: :done
36
+ end
37
+
38
+ event :mark_as_verified do
39
+ transitions from: [:done], to: :verified
40
+ end
41
+
42
+ event :mark_as_flagged do
43
+ transitions from: [:in_progress, :done, :flagged], to: :flagged
44
+ end
45
+
46
+ event :mark_as_back_in_progress do
47
+ transitions from: [:flagged, :done, :verified], to: :in_progress
48
+ end
49
+ end
50
+
51
+ def self.grid_coordinates
52
+ config = LayersOfLondon::Booth::MapTool.configuration
53
+ down = (config.squares_x + 1).times.collect do |col|
54
+ top = config.north_west.endpoint(90,col*config.square_size, units: :meters)
55
+ bottom = top.endpoint(180, config.squares_y*config.square_size, units: :meters)
56
+ [
57
+ top.to_a.reverse,
58
+ bottom.to_a.reverse
59
+ ]
60
+ end
61
+
62
+ across = (config.squares_y + 1).times.collect do |col|
63
+ left = config.north_west.endpoint(180,col*config.square_size, units: :meters)
64
+ right = left.endpoint(90, config.squares_x*config.square_size, units: :meters)
65
+ [
66
+ left.to_a.reverse,
67
+ right.to_a.reverse
68
+ ]
69
+ end
70
+
71
+ down + across
72
+ end
73
+
74
+ def to_json(padding: 0)
75
+ # {id: id, state: {label: aasm_state, description: aasm_state.humanize}, geojson: to_geojson(padding: padding)}
76
+ #
77
+ state = {label: aasm_state, description: aasm_state.humanize}
78
+ state.merge!({user: {id: user.id}}) if aasm_state === "done"
79
+
80
+ {id: id, geojson: to_geojson(padding: padding)}.merge({state: state})
81
+ end
82
+
83
+ def to_geojson(padding: 0)
84
+ distance_diagonally = CMath.sqrt((padding * padding) + (padding * padding))
85
+ north_west_padded = padding.zero? ? north_west : north_west.endpoint(315,distance_diagonally, units: :meters)
86
+ north_east_padded = padding.zero? ? north_east : north_east.endpoint(45,distance_diagonally, units: :meters)
87
+ south_east_padded = padding.zero? ? south_east : south_east.endpoint(135,distance_diagonally, units: :meters)
88
+ south_west_padded = padding.zero? ? south_west : south_west.endpoint(225,distance_diagonally, units: :meters)
89
+ {
90
+ type: "Feature",
91
+ geometry: {
92
+ type: "MultiPolygon",
93
+ coordinates: [
94
+ [
95
+ [
96
+ north_west_padded.to_a.reverse,
97
+ south_west_padded.to_a.reverse,
98
+ south_east_padded.to_a.reverse,
99
+ north_east_padded.to_a.reverse,
100
+ north_west_padded.to_a.reverse
101
+ ],
102
+ [
103
+ LayersOfLondon::Booth::MapTool.configuration.north_west.to_a.reverse,
104
+ LayersOfLondon::Booth::MapTool.configuration.north_east.to_a.reverse,
105
+ LayersOfLondon::Booth::MapTool.configuration.south_east.to_a.reverse,
106
+ LayersOfLondon::Booth::MapTool.configuration.south_west.to_a.reverse,
107
+ LayersOfLondon::Booth::MapTool.configuration.north_west.to_a.reverse,
108
+ ]
109
+ ]
110
+
111
+ ]
112
+ },
113
+ properties: {
114
+ id: id,
115
+ state: aasm_state,
116
+ centroid: centroid.to_a.collect {|coord| coord.round(5)}
117
+ }
118
+ }
119
+ end
120
+
121
+ def north_west
122
+ Geokit::LatLng.new(north_west_lat, north_west_lng)
123
+ end
124
+
125
+ def north_east
126
+ north_west.endpoint(90, square_size, units: :meters)
127
+ end
128
+
129
+ def south_west
130
+ north_west.endpoint(180, square_size, units: :meters)
131
+ end
132
+
133
+ def south_east
134
+ south_west.endpoint(90, square_size, units: :meters)
135
+ end
136
+
137
+ def centroid
138
+ north_west.midpoint_to(south_east)
139
+ end
140
+
141
+ def editable?
142
+ !aasm_state.in?(["done", "flagged", "verified"])
143
+ end
144
+
145
+ end
146
+ end