layers_of_london-booth-map_tool 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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