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.
- checksums.yaml +7 -0
- data/LICENSE +621 -0
- data/README.md +28 -0
- data/Rakefile +32 -0
- data/app/assets/config/layers_of_london_booth_map_tool_manifest.js +2 -0
- data/app/assets/javascripts/layers_of_london/booth/map_tool/application.js +15 -0
- data/app/assets/javascripts/layers_of_london/booth/map_tool/maptools.js +2 -0
- data/app/assets/javascripts/layers_of_london/booth/map_tool/polygons.js +2 -0
- data/app/assets/javascripts/layers_of_london/booth/map_tool/squares.js +2 -0
- data/app/assets/stylesheets/layers_of_london/booth/map_tool/application.css +15 -0
- data/app/assets/stylesheets/layers_of_london/booth/map_tool/maptools.css +4 -0
- data/app/assets/stylesheets/layers_of_london/booth/map_tool/polygons.css +4 -0
- data/app/assets/stylesheets/layers_of_london/booth/map_tool/squares.css +4 -0
- data/app/controllers/layers_of_london/booth/map_tool/application_controller.rb +35 -0
- data/app/controllers/layers_of_london/booth/map_tool/maptools_controller.rb +8 -0
- data/app/controllers/layers_of_london/booth/map_tool/polygons_controller.rb +68 -0
- data/app/controllers/layers_of_london/booth/map_tool/squares_controller.rb +79 -0
- data/app/helpers/layers_of_london/booth/map_tool/application_helper.rb +8 -0
- data/app/helpers/layers_of_london/booth/map_tool/maptools_helper.rb +4 -0
- data/app/helpers/layers_of_london/booth/map_tool/polygons_helper.rb +4 -0
- data/app/helpers/layers_of_london/booth/map_tool/squares_helper.rb +4 -0
- data/app/jobs/layers_of_london/booth/map_tool/application_job.rb +8 -0
- data/app/mailers/layers_of_london/booth/map_tool/application_mailer.rb +10 -0
- data/app/models/layers_of_london/booth/map_tool/application_record.rb +9 -0
- data/app/models/layers_of_london/booth/map_tool/polygon.rb +20 -0
- data/app/models/layers_of_london/booth/map_tool/square.rb +146 -0
- data/app/policies/layers_of_london/booth/map_tool/polygon_policy.rb +25 -0
- data/app/views/layers_of_london/booth/map_tool/maptools/show.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/polygons/create.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/polygons/destroy.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/polygons/index.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/polygons/update.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/squares/create.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/squares/edit.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/squares/index.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/squares/show.html.erb +2 -0
- data/app/views/layers_of_london/booth/map_tool/squares/update.html.erb +2 -0
- data/app/views/layouts/layers_of_london/booth/map_tool/application.html.erb +16 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20190724120049_create_layers_of_london_booth_map_tool_squares.rb +7 -0
- data/db/migrate/20190724120136_create_layers_of_london_booth_map_tool_polygons.rb +10 -0
- data/db/migrate/20190731111508_add_aasm_state_to_squares.rb +5 -0
- data/db/migrate/20190802100700_add_locations_to_squares.rb +10 -0
- data/db/migrate/20190802120000_add_north_west_south_east_to_squares.rb +12 -0
- data/db/migrate/20190806161900_add_row_col_to_squares.rb +9 -0
- data/db/migrate/20190809151958_add_user_tracking_to_square.rb +5 -0
- data/lib/generators/map_tool/grid_generator.rb +28 -0
- data/lib/layers_of_london/booth/map_tool.rb +46 -0
- data/lib/layers_of_london/booth/map_tool/engine.rb +27 -0
- data/lib/layers_of_london/booth/map_tool/version.rb +7 -0
- data/lib/tasks/layers_of_london/booth/map_tool_tasks.rake +4 -0
- 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,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,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,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,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,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
|