Merge branch 'develop' into feature/realtime.video
This commit is contained in:
commit
604087c592
74 changed files with 1475 additions and 568 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@
|
|||
#assety stuff
|
||||
realtime/node_modules
|
||||
public/assets
|
||||
public/metamaps_mobile
|
||||
vendor/
|
||||
|
||||
#secrets and config
|
||||
|
|
9
.travis.yml
Normal file
9
.travis.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
sudo: false
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.1.3
|
||||
before_script:
|
||||
- export RAILS_ENV=test
|
||||
- cp .example-env .env
|
||||
- bundle exec rake db:create
|
||||
- bundle exec rake db:schema:load
|
10
Gemfile
10
Gemfile
|
@ -6,7 +6,9 @@ gem 'rails', '4.2.4'
|
|||
gem 'devise'
|
||||
gem 'redis'
|
||||
gem 'pg'
|
||||
gem 'cancancan'
|
||||
gem 'pundit'
|
||||
gem 'cancan'
|
||||
gem 'pundit_extra'
|
||||
gem 'formula'
|
||||
gem 'formtastic'
|
||||
gem 'json'
|
||||
|
@ -15,6 +17,12 @@ gem 'best_in_place' #in-place editing
|
|||
gem 'kaminari' # pagination
|
||||
gem 'uservoice-ruby'
|
||||
gem 'dotenv'
|
||||
gem 'snorlax', '~> 0.1.3'
|
||||
gem 'httparty'
|
||||
gem 'sequenced', '~> 2.0.0'
|
||||
gem 'active_model_serializers', '~> 0.8.1'
|
||||
gem 'delayed_job', '~> 4.0.2'
|
||||
gem 'delayed_job_active_record', '~> 4.0.1'
|
||||
|
||||
gem 'paperclip'
|
||||
gem 'aws-sdk', '< 2.0'
|
||||
|
|
137
Gemfile.lock
137
Gemfile.lock
|
@ -20,6 +20,8 @@ GEM
|
|||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
active_model_serializers (0.8.3)
|
||||
activemodel (>= 3.0)
|
||||
activejob (4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
globalid (>= 0.3.0)
|
||||
|
@ -43,7 +45,7 @@ GEM
|
|||
aws-sdk-v1 (1.66.0)
|
||||
json (~> 1.4)
|
||||
nokogiri (>= 1.4.4)
|
||||
bcrypt (3.1.10)
|
||||
bcrypt (3.1.11)
|
||||
best_in_place (3.1.0)
|
||||
actionpack (>= 3.2)
|
||||
railties (>= 3.2)
|
||||
|
@ -54,24 +56,30 @@ GEM
|
|||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
builder (3.2.2)
|
||||
byebug (5.0.0)
|
||||
columnize (= 0.9.0)
|
||||
cancancan (1.13.1)
|
||||
byebug (8.2.2)
|
||||
cancan (1.6.10)
|
||||
cancancan (1.10.1)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cocaine (0.5.8)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.1.0)
|
||||
coffee-rails (4.1.0)
|
||||
coderay (1.1.1)
|
||||
coffee-rails (4.1.1)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
railties (>= 4.0.0, < 5.1.x)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
columnize (0.9.0)
|
||||
concurrent-ruby (1.0.1)
|
||||
debug_inspector (0.0.2)
|
||||
devise (3.5.2)
|
||||
delayed_job (4.0.6)
|
||||
activesupport (>= 3.0, < 5.0)
|
||||
delayed_job_active_record (4.0.3)
|
||||
activerecord (>= 3.0, < 5.0)
|
||||
delayed_job (>= 3.0, < 4.1)
|
||||
devise (3.5.6)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 3.2.6, < 5)
|
||||
|
@ -80,13 +88,13 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
diff-lcs (1.2.5)
|
||||
docile (1.1.5)
|
||||
dotenv (2.0.2)
|
||||
dotenv (2.1.0)
|
||||
erubis (2.7.0)
|
||||
execjs (2.6.0)
|
||||
ezcrypto (0.7.2)
|
||||
factory_girl (4.5.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.5.0)
|
||||
factory_girl_rails (4.6.0)
|
||||
factory_girl (~> 4.5.0)
|
||||
railties (>= 3.0.0)
|
||||
formtastic (3.1.3)
|
||||
|
@ -95,18 +103,21 @@ GEM
|
|||
rails (> 3.0.0)
|
||||
globalid (0.3.6)
|
||||
activesupport (>= 4.1.0)
|
||||
httparty (0.13.7)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.7.0)
|
||||
jbuilder (2.3.2)
|
||||
activesupport (>= 3.0.0, < 5)
|
||||
jbuilder (2.4.1)
|
||||
activesupport (>= 3.0.0, < 5.1)
|
||||
multi_json (~> 1.2)
|
||||
jquery-rails (4.0.5)
|
||||
rails-dom-testing (~> 1.0)
|
||||
jquery-rails (4.1.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (5.0.5)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
json-schema (2.6.0)
|
||||
json-schema (2.6.1)
|
||||
addressable (~> 2.3.8)
|
||||
kaminari (0.16.3)
|
||||
actionpack (>= 3.0.0)
|
||||
|
@ -116,31 +127,35 @@ GEM
|
|||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.6.2)
|
||||
mime-types (2.99.1)
|
||||
mimemagic (0.3.0)
|
||||
mini_portile2 (2.0.0)
|
||||
minitest (5.8.2)
|
||||
minitest (5.8.4)
|
||||
multi_json (1.11.2)
|
||||
nokogiri (1.6.7)
|
||||
multi_xml (0.5.5)
|
||||
nokogiri (1.6.7.2)
|
||||
mini_portile2 (~> 2.0.0.rc2)
|
||||
oauth (0.4.7)
|
||||
oauth (0.5.1)
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (4.3.1)
|
||||
paperclip (4.3.5)
|
||||
activemodel (>= 3.2.0)
|
||||
activesupport (>= 3.2.0)
|
||||
cocaine (~> 0.5.5)
|
||||
mime-types
|
||||
mimemagic (= 0.3.0)
|
||||
pg (0.18.3)
|
||||
pg (0.18.4)
|
||||
pry (0.10.3)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pry-byebug (3.2.0)
|
||||
byebug (~> 5.0)
|
||||
pry-byebug (3.3.0)
|
||||
byebug (~> 8.0)
|
||||
pry (~> 0.10)
|
||||
pry-rails (0.3.4)
|
||||
pry (>= 0.9.10)
|
||||
pundit (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
pundit_extra (0.1.1)
|
||||
quiet_assets (1.1.0)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.6.4)
|
||||
|
@ -163,66 +178,73 @@ GEM
|
|||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.2)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails3-jquery-autocomplete (1.0.15)
|
||||
rails (>= 3.2)
|
||||
rails_12factor (0.0.3)
|
||||
rails_serve_static_assets
|
||||
rails_stdout_logging
|
||||
rails_serve_static_assets (0.0.4)
|
||||
rails_serve_static_assets (0.0.5)
|
||||
rails_stdout_logging (0.0.4)
|
||||
railties (4.2.4)
|
||||
actionpack (= 4.2.4)
|
||||
activesupport (= 4.2.4)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.4.2)
|
||||
rake (11.1.0)
|
||||
redis (3.2.2)
|
||||
responders (2.1.0)
|
||||
railties (>= 4.2.0, < 5)
|
||||
rspec-core (3.3.2)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-expectations (3.3.1)
|
||||
responders (2.1.1)
|
||||
railties (>= 4.2.0, < 5.1)
|
||||
rspec-core (3.4.4)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-expectations (3.4.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-mocks (3.3.2)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-mocks (3.4.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-rails (3.3.3)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-rails (3.4.2)
|
||||
actionpack (>= 3.0, < 4.3)
|
||||
activesupport (>= 3.0, < 4.3)
|
||||
railties (>= 3.0, < 4.3)
|
||||
rspec-core (~> 3.3.0)
|
||||
rspec-expectations (~> 3.3.0)
|
||||
rspec-mocks (~> 3.3.0)
|
||||
rspec-support (~> 3.3.0)
|
||||
rspec-support (3.3.0)
|
||||
sass (3.4.19)
|
||||
rspec-core (~> 3.4.0)
|
||||
rspec-expectations (~> 3.4.0)
|
||||
rspec-mocks (~> 3.4.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-support (3.4.1)
|
||||
sass (3.4.21)
|
||||
sass-rails (5.0.4)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
shoulda-matchers (3.0.1)
|
||||
sequenced (2.0.0)
|
||||
activerecord (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
shoulda-matchers (3.1.1)
|
||||
activesupport (>= 4.0.0)
|
||||
simplecov (0.11.1)
|
||||
simplecov (0.11.2)
|
||||
docile (~> 1.1.0)
|
||||
json (~> 1.8)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
slop (3.6.0)
|
||||
sprockets (3.4.0)
|
||||
snorlax (0.1.4)
|
||||
cancancan (~> 1.10.1)
|
||||
rails (> 4.1)
|
||||
sprockets (3.5.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (2.3.3)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (3.0.4)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
tilt (2.0.1)
|
||||
tunemygc (1.0.61)
|
||||
tilt (2.0.2)
|
||||
tunemygc (1.0.65)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (2.7.2)
|
||||
|
@ -232,24 +254,28 @@ GEM
|
|||
ezcrypto (>= 0.7.2)
|
||||
json (>= 1.7.5)
|
||||
oauth (>= 0.4.7)
|
||||
warden (1.2.3)
|
||||
warden (1.2.6)
|
||||
rack (>= 1.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
active_model_serializers (~> 0.8.1)
|
||||
aws-sdk (< 2.0)
|
||||
best_in_place
|
||||
better_errors
|
||||
binding_of_caller
|
||||
cancancan
|
||||
cancan
|
||||
coffee-rails
|
||||
delayed_job (~> 4.0.2)
|
||||
delayed_job_active_record (~> 4.0.1)
|
||||
devise
|
||||
dotenv
|
||||
factory_girl_rails
|
||||
formtastic
|
||||
formula
|
||||
httparty
|
||||
jbuilder
|
||||
jquery-rails
|
||||
jquery-ui-rails
|
||||
|
@ -260,6 +286,8 @@ DEPENDENCIES
|
|||
pg
|
||||
pry-byebug
|
||||
pry-rails
|
||||
pundit
|
||||
pundit_extra
|
||||
quiet_assets
|
||||
rails (= 4.2.4)
|
||||
rails3-jquery-autocomplete
|
||||
|
@ -267,8 +295,13 @@ DEPENDENCIES
|
|||
redis
|
||||
rspec-rails
|
||||
sass-rails
|
||||
sequenced (~> 2.0.0)
|
||||
shoulda-matchers
|
||||
simplecov
|
||||
snorlax (~> 0.1.3)
|
||||
tunemygc
|
||||
uglifier
|
||||
uservoice-ruby
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
|
|
2
Procfile
2
Procfile
|
@ -1 +1,3 @@
|
|||
web: bundle exec rails server -p $PORT
|
||||
worker: bundle exec rake jobs:work
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ Metamaps
|
|||
=======
|
||||
|
||||
[![Join the chat at https://gitter.im/metamaps/metamaps_gen002](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/metamaps/metamaps_gen002?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Build Status](https://jenkins.devinhoward.ca/job/metamaps_gen002.develop/badge/icon)](https://jenkins.devinhoward.ca/job/metamaps_gen002.develop/)
|
||||
[![Build Status](https://travis-ci.org/metamaps/metamaps_gen002.svg)](https://travis-ci.org/metamaps/metamaps_gen002)
|
||||
|
||||
Welcome to the Metamaps GitHub repo.
|
||||
Welcome to the Metamaps GitHub repo.
|
||||
|
||||
## About
|
||||
|
||||
|
@ -12,7 +12,7 @@ Metamaps is a free and AGPL open source technology for changemakers, innovators,
|
|||
|
||||
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in a private beta.
|
||||
|
||||
Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter.
|
||||
Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter.
|
||||
|
||||
To get connected with the community interested in Metamaps, join our [Google+ community][community].
|
||||
|
||||
|
@ -52,7 +52,7 @@ We haven't figured out Vagrant for Windows yet, but we have a set of manual inst
|
|||
|
||||
## Contributing
|
||||
|
||||
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
|
||||
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
|
||||
|
||||
## Community
|
||||
|
||||
|
|
1
Vagrantfile
vendored
1
Vagrantfile
vendored
|
@ -16,7 +16,6 @@ sudo apt-get install nodejs -y
|
|||
sudo apt-get install npm -y
|
||||
sudo apt-get install postgresql -y
|
||||
sudo apt-get install libpq-dev -y
|
||||
sudo apt-get install redis-server -y
|
||||
|
||||
# get imagemagick
|
||||
sudo apt-get install imagemagick --fix-missing
|
||||
|
|
3
app/controllers/api/mappings_controller.rb
Normal file
3
app/controllers/api/mappings_controller.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class Api::MappingsController < API::RestfulController
|
||||
|
||||
end
|
3
app/controllers/api/maps_controller.rb
Normal file
3
app/controllers/api/maps_controller.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class Api::MapsController < API::RestfulController
|
||||
|
||||
end
|
49
app/controllers/api/restful_controller.rb
Normal file
49
app/controllers/api/restful_controller.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
class API::RestfulController < ActionController::Base
|
||||
include Pundit
|
||||
include PunditExtra
|
||||
|
||||
snorlax_used_rest!
|
||||
|
||||
rescue_from(Pundit::NotAuthorizedError) { |e| respond_with_standard_error e, 403 }
|
||||
load_and_authorize_resource only: [:show, :update, :destroy]
|
||||
|
||||
def create
|
||||
authorize resource_class
|
||||
instantiate_resouce
|
||||
resource.user = current_user
|
||||
create_action
|
||||
respond_with_resource
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resource_serializer
|
||||
"new_#{resource_name}_serializer".camelize.constantize
|
||||
end
|
||||
|
||||
def accessible_records
|
||||
if current_user
|
||||
visible_records
|
||||
else
|
||||
public_records
|
||||
end
|
||||
end
|
||||
|
||||
def current_user
|
||||
super || token_user || nil
|
||||
end
|
||||
|
||||
def token_user
|
||||
authenticate_with_http_token do |token, options|
|
||||
access_token = Token.find_by_token(token)
|
||||
if access_token
|
||||
@token_user ||= access_token.user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
@permitted_params ||= PermittedParams.new(params)
|
||||
end
|
||||
|
||||
end
|
3
app/controllers/api/synapses_controller.rb
Normal file
3
app/controllers/api/synapses_controller.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class Api::SynapsesController < API::RestfulController
|
||||
|
||||
end
|
19
app/controllers/api/tokens_controller.rb
Normal file
19
app/controllers/api/tokens_controller.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
class Api::TokensController < API::RestfulController
|
||||
|
||||
def my_tokens
|
||||
raise Pundit::NotAuthorizedError.new unless current_user
|
||||
instantiate_collection page_collection: false, timeframe_collection: false
|
||||
respond_with_collection
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resource_serializer
|
||||
"#{resource_name}_serializer".camelize.constantize
|
||||
end
|
||||
|
||||
def visible_records
|
||||
current_user.tokens
|
||||
end
|
||||
|
||||
end
|
3
app/controllers/api/topics_controller.rb
Normal file
3
app/controllers/api/topics_controller.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class Api::TopicsController < API::RestfulController
|
||||
|
||||
end
|
|
@ -1,9 +1,16 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
include Pundit
|
||||
include PunditExtra
|
||||
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
|
||||
protect_from_forgery
|
||||
|
||||
before_filter :get_invite_link
|
||||
before_action :get_invite_link
|
||||
after_action :allow_embedding
|
||||
|
||||
def default_serializer_options
|
||||
{ root: false }
|
||||
end
|
||||
|
||||
# this is for global login
|
||||
include ContentHelper
|
||||
|
||||
|
@ -12,13 +19,7 @@ class ApplicationController < ActionController::Base
|
|||
helper_method :admin?
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
unsafe_uri = request.env["REQUEST_URI"]
|
||||
if unsafe_uri.starts_with?('http') && !unsafe_uri.starts_with?('https')
|
||||
protocol = 'http'
|
||||
else
|
||||
protocol = 'https'
|
||||
end
|
||||
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => protocol)
|
||||
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => 'https')
|
||||
|
||||
if request.referer == sign_in_url
|
||||
super
|
||||
|
@ -29,6 +30,10 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def handle_unauthorized
|
||||
head :forbidden # TODO make this better
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_no_user
|
||||
|
|
|
@ -3,20 +3,20 @@ class MainController < ApplicationController
|
|||
include MapsHelper
|
||||
include UsersHelper
|
||||
include SynapsesHelper
|
||||
|
||||
after_action :verify_policy_scoped
|
||||
|
||||
respond_to :html, :json
|
||||
|
||||
# home page
|
||||
def home
|
||||
@current = current_user
|
||||
|
||||
@maps = policy_scope(Map).order("updated_at DESC").page(1).per(20)
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
if authenticated?
|
||||
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(1).per(20)
|
||||
respond_with(@maps, @current)
|
||||
if not authenticated?
|
||||
render 'main/home'
|
||||
else
|
||||
respond_with(@current)
|
||||
render 'maps/activemaps'
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -59,69 +59,35 @@ class MainController < ApplicationController
|
|||
filterByMetacode = m
|
||||
end
|
||||
end
|
||||
|
||||
search = '%' + term.downcase + '%'
|
||||
builder = policy_scope(Topic)
|
||||
|
||||
if filterByMetacode
|
||||
if term == ""
|
||||
@topics = []
|
||||
builder = builder.none
|
||||
else
|
||||
search = term.downcase + '%'
|
||||
|
||||
if user
|
||||
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
|
||||
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
|
||||
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
|
||||
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
|
||||
else
|
||||
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
|
||||
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
|
||||
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
|
||||
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
|
||||
end
|
||||
|
||||
#get unique elements only through the magic of Sets
|
||||
@topics = (@topics + @topics2 + @topics3 + @topics4).to_a
|
||||
builder = builder.where('LOWER("name") like ? OR
|
||||
LOWER("desc") like ? OR
|
||||
LOWER("link") like ?', search, search, search)
|
||||
builder = builder.where(metacode_id: filterByMetacode.id)
|
||||
end
|
||||
elsif desc
|
||||
search = '%' + term.downcase + '%'
|
||||
if !user
|
||||
@topics = Topic.where('LOWER("desc") like ?', search).order('"name"')
|
||||
elsif user
|
||||
@topics = Topic.where('LOWER("desc") like ?', search).where('user_id = ?', user).order('"name"')
|
||||
end
|
||||
builder = builder.where('LOWER("desc") like ?', search)
|
||||
elsif link
|
||||
search = '%' + term.downcase + '%'
|
||||
if !user
|
||||
@topics = Topic.where('LOWER("link") like ?', search).order('"name"')
|
||||
elsif user
|
||||
@topics = Topic.where('LOWER("link") like ?', search).where('user_id = ?', user).order('"name"')
|
||||
end
|
||||
builder = builder.where('LOWER("link") like ?', search)
|
||||
else #regular case, just search the name
|
||||
search = term.downcase + '%'
|
||||
if !user
|
||||
@topics = Topic.where('LOWER("name") like ?', search).order('"name"')
|
||||
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).order('"name"')
|
||||
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).order('"name"')
|
||||
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).order('"name"')
|
||||
@topics = @topics + (@topics2 - @topics)
|
||||
@topics = @topics + (@topics3 - @topics)
|
||||
@topics = @topics + (@topics4 - @topics)
|
||||
elsif user
|
||||
@topics = Topic.where('LOWER("name") like ?', search).where('user_id = ?', user).order('"name"')
|
||||
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).where('user_id = ?', user).order('"name"')
|
||||
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).where('user_id = ?', user).order('"name"')
|
||||
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).where('user_id = ?', user).order('"name"')
|
||||
@topics = @topics + (@topics2 - @topics)
|
||||
@topics = @topics + (@topics3 - @topics)
|
||||
@topics = @topics + (@topics4 - @topics)
|
||||
end
|
||||
builder = builder.where('LOWER("name") like ? OR
|
||||
LOWER("desc") like ? OR
|
||||
LOWER("link") like ?', search, search, search)
|
||||
end
|
||||
|
||||
builder = builder.where(user: user) if user
|
||||
@topics = builder.order(:name)
|
||||
else
|
||||
@topics = []
|
||||
end
|
||||
|
||||
#read this next line as 'delete a topic if its private and you're either 1. logged out or 2. logged in but not the topic creator
|
||||
@topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
|
||||
|
||||
|
||||
render json: autocomplete_array_json(@topics)
|
||||
end
|
||||
|
||||
|
@ -141,21 +107,21 @@ class MainController < ApplicationController
|
|||
term = term[5..-1]
|
||||
desc = true
|
||||
end
|
||||
|
||||
search = '%' + term.downcase + '%'
|
||||
query = desc ? 'LOWER("desc") like ?' : 'LOWER("name") like ?'
|
||||
if !user
|
||||
# !connor why is the limit 5 done here and not above? also, why not limit after sorting alphabetically?
|
||||
@maps = Map.where(query, search).limit(5).order('"name"')
|
||||
elsif user
|
||||
@maps = Map.where(query, search).where('user_id = ?', user).order('"name"')
|
||||
builder = policy_scope(Map)
|
||||
|
||||
if desc
|
||||
builder = builder.where('LOWER("desc") like ?', search)
|
||||
else
|
||||
builder = builder.where('LOWER("name") like ?', search)
|
||||
end
|
||||
builder = builder.where(user: user) if user
|
||||
@maps = builder.order(:name)
|
||||
else
|
||||
@maps = []
|
||||
end
|
||||
|
||||
#read this next line as 'delete a map if its private and you're either 1. logged out or 2. logged in but not the map creator
|
||||
@maps.to_a.delete_if {|m| m.permission == "private" && (!authenticated? || (authenticated? && current_user.id != m.user_id)) }
|
||||
|
||||
render json: autocomplete_map_array_json(@maps)
|
||||
end
|
||||
|
||||
|
@ -166,7 +132,10 @@ class MainController < ApplicationController
|
|||
|
||||
#remove "mapper:" if appended at beginning
|
||||
term = term[7..-1] if term.downcase[0..6] == "mapper:"
|
||||
@mappers = User.where('LOWER("name") like ?', term.downcase + '%').order('"name"')
|
||||
search = term.downcase + '%'
|
||||
builder = policy_scope(User) # TODO do I need to policy scope? I guess yes to verify_policy_scoped
|
||||
builder = builder.where('LOWER("name") like ?', search)
|
||||
@mappers = builder.order(:name)
|
||||
else
|
||||
@mappers = []
|
||||
end
|
||||
|
@ -181,7 +150,7 @@ class MainController < ApplicationController
|
|||
topic2id = params[:topic2id]
|
||||
|
||||
if term && !term.empty?
|
||||
@synapses = Synapse.where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
|
||||
@synapses = policy_scope(Synapse).where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
|
||||
|
||||
# remove any duplicate synapse types that just differ by
|
||||
# leading or trailing whitespaces
|
||||
|
@ -195,23 +164,18 @@ class MainController < ApplicationController
|
|||
boolean = true
|
||||
end
|
||||
}
|
||||
|
||||
#limit to 5 results
|
||||
@synapses = @synapses.slice(0,5)
|
||||
elsif topic1id && !topic1id.empty?
|
||||
@one = Synapse.where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
|
||||
@two = Synapse.where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
|
||||
@one = policy_scope(Synapse).where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
|
||||
@two = policy_scope(Synapse).where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
|
||||
@synapses = @one + @two
|
||||
@synapses.sort! {|s1,s2| s1.desc <=> s2.desc }.to_a
|
||||
|
||||
#permissions
|
||||
@synapses.delete_if {|s| s.permission == "private" && !authenticated? }
|
||||
@synapses.delete_if {|s| s.permission == "private" && authenticated? && current_user.id != s.user_id }
|
||||
else
|
||||
@synapses = []
|
||||
end
|
||||
|
||||
#limit to 5 results
|
||||
@synapses = @synapses.slice(0,5)
|
||||
|
||||
render json: autocomplete_synapse_array_json(@synapses)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
class MappingsController < ApplicationController
|
||||
|
||||
before_filter :require_user, only: [:create, :update, :destroy]
|
||||
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
after_action :verify_authorized, except: :index
|
||||
after_action :verify_policy_scoped, only: :index
|
||||
|
||||
respond_to :json
|
||||
|
||||
# GET /mappings/1.json
|
||||
def show
|
||||
@mapping = Mapping.find(params[:id])
|
||||
authorize @mapping
|
||||
|
||||
render json: @mapping
|
||||
end
|
||||
|
@ -14,9 +17,12 @@ class MappingsController < ApplicationController
|
|||
# POST /mappings.json
|
||||
def create
|
||||
@mapping = Mapping.new(mapping_params)
|
||||
authorize @mapping
|
||||
@mapping.user = current_user
|
||||
|
||||
if @mapping.save
|
||||
render json: @mapping, status: :created
|
||||
Events::NewMapping.publish!(@mapping, current_user)
|
||||
else
|
||||
render json: @mapping.errors, status: :unprocessable_entity
|
||||
end
|
||||
|
@ -25,6 +31,7 @@ class MappingsController < ApplicationController
|
|||
# PUT /mappings/1.json
|
||||
def update
|
||||
@mapping = Mapping.find(params[:id])
|
||||
authorize @mapping
|
||||
|
||||
if @mapping.update_attributes(mapping_params)
|
||||
head :no_content
|
||||
|
@ -36,7 +43,7 @@ class MappingsController < ApplicationController
|
|||
# DELETE /mappings/1.json
|
||||
def destroy
|
||||
@mapping = Mapping.find(params[:id])
|
||||
@map = @mapping.map
|
||||
authorize @mapping
|
||||
|
||||
@mapping.destroy
|
||||
|
||||
|
@ -46,6 +53,6 @@ class MappingsController < ApplicationController
|
|||
private
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def mapping_params
|
||||
params.require(:mapping).permit(:id, :xloc, :yloc, :mappable_id, :mappable_type, :map_id, :user_id)
|
||||
params.require(:mapping).permit(:id, :xloc, :yloc, :mappable_id, :mappable_type, :map_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,67 +1,84 @@
|
|||
class MapsController < ApplicationController
|
||||
before_filter :require_user, only: [:create, :update, :screenshot, :destroy]
|
||||
|
||||
before_action :require_user, only: [:create, :update, :screenshot, :destroy]
|
||||
after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :usermaps]
|
||||
after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :usermaps]
|
||||
|
||||
respond_to :html, :json, :csv
|
||||
|
||||
autocomplete :map, :name, :full => true, :extra_data => [:user_id]
|
||||
|
||||
# GET /explore/active
|
||||
# GET /explore/featured
|
||||
# GET /explore/mapper/:id
|
||||
def index
|
||||
return redirect_to activemaps_url if request.path == "/explore"
|
||||
|
||||
@current = current_user
|
||||
@maps = []
|
||||
def activemaps
|
||||
page = params[:page].present? ? params[:page] : 1
|
||||
|
||||
if request.path.index("/explore/active") != nil
|
||||
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(page).per(20)
|
||||
@request = "active"
|
||||
elsif request.path.index("/explore/featured") != nil
|
||||
@maps = Map.where("maps.featured = ? AND maps.permission != ?", true, "private").order("updated_at DESC").page(page).per(20)
|
||||
@request = "featured"
|
||||
elsif request.path.index('/explore/mine') != nil # looking for maps by me
|
||||
return redirect_to activemaps_url if !authenticated?
|
||||
|
||||
# don't need to exclude private maps because they all belong to you
|
||||
@maps = Map.where("maps.user_id = ?", @current.id).order("updated_at DESC").page(page).per(20)
|
||||
@request = "you"
|
||||
elsif request.path.index('/explore/mapper/') != nil # looking for maps by a mapper
|
||||
@user = User.find(params[:id])
|
||||
@maps = Map.where("maps.user_id = ? AND maps.permission != ?", @user.id, "private").order("updated_at DESC").page(page).per(20)
|
||||
@request = "mapper"
|
||||
end
|
||||
@maps = policy_scope(Map).order("updated_at DESC")
|
||||
.page(page).per(20)
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
if @request == "active" && authenticated?
|
||||
redirect_to root_url and return
|
||||
end
|
||||
respond_with(@maps, @request, @user)
|
||||
format.html {
|
||||
# root url => main/home. main/home renders maps/activemaps view.
|
||||
redirect_to root_url and return if authenticated?
|
||||
respond_with(@maps, @user)
|
||||
}
|
||||
format.json { render json: @maps }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /explore/featured
|
||||
def featuredmaps
|
||||
page = params[:page].present? ? params[:page] : 1
|
||||
@maps = policy_scope(
|
||||
Map.where("maps.featured = ? AND maps.permission != ?",
|
||||
true, "private")
|
||||
).order("updated_at DESC").page(page).per(20)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { respond_with(@maps, @user) }
|
||||
format.json { render json: @maps }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /explore/mine
|
||||
def mymaps
|
||||
return redirect_to activemaps_url if !authenticated?
|
||||
|
||||
page = params[:page].present? ? params[:page] : 1
|
||||
@maps = policy_scope(
|
||||
Map.where("maps.user_id = ?", current_user.id)
|
||||
).order("updated_at DESC").page(page).per(20)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { respond_with(@maps, @user) }
|
||||
format.json { render json: @maps }
|
||||
end
|
||||
end
|
||||
|
||||
# GET /explore/mapper/:id
|
||||
def usermaps
|
||||
page = params[:page].present? ? params[:page] : 1
|
||||
@user = User.find(params[:id])
|
||||
@maps = policy_scope(Map.where(user: @user))
|
||||
.order("updated_at DESC").page(page).per(20)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { respond_with(@maps, @user) }
|
||||
format.json { render json: @maps }
|
||||
end
|
||||
end
|
||||
|
||||
# GET maps/:id
|
||||
def show
|
||||
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id]).authorize_to_show(@current)
|
||||
|
||||
if not @map
|
||||
redirect_to root_url, notice: "Access denied. That map is private." and return
|
||||
end
|
||||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@allmappers = @map.contributors
|
||||
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
|
||||
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
|
||||
@allmappings = @map.mappings.to_a.delete_if {|m|
|
||||
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
|
||||
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && current_user.id != s.user_id)) }
|
||||
@allmappings = @map.mappings.to_a.delete_if {|m|
|
||||
object = m.mappable
|
||||
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id)))
|
||||
!object || (object.permission == "private" && (!authenticated? || (authenticated? && current_user.id != object.user_id)))
|
||||
}
|
||||
@allmessages = @map.messages.sort_by(&:created_at)
|
||||
|
||||
|
@ -75,20 +92,15 @@ class MapsController < ApplicationController
|
|||
|
||||
# GET maps/:id/contains
|
||||
def contains
|
||||
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id]).authorize_to_show(@current)
|
||||
|
||||
if not @map
|
||||
redirect_to root_url, notice: "Access denied. That map is private." and return
|
||||
end
|
||||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
|
||||
@allmappers = @map.contributors
|
||||
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
|
||||
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
|
||||
@allmappings = @map.mappings.to_a.delete_if {|m|
|
||||
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
|
||||
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && current_user.id != s.user_id)) }
|
||||
@allmappings = @map.mappings.to_a.delete_if {|m|
|
||||
object = m.mappable
|
||||
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id)))
|
||||
!object || (object.permission == "private" && (!authenticated? || (authenticated? && current_user.id != object.user_id)))
|
||||
}
|
||||
|
||||
@json = Hash.new()
|
||||
|
@ -125,6 +137,7 @@ class MapsController < ApplicationController
|
|||
mapping.xloc = topic[1]
|
||||
mapping.yloc = topic[2]
|
||||
@map.topicmappings << mapping
|
||||
authorize mapping, :create
|
||||
mapping.save
|
||||
end
|
||||
|
||||
|
@ -137,6 +150,7 @@ class MapsController < ApplicationController
|
|||
mapping.map = @map
|
||||
mapping.mappable = Synapse.find(synapse_id)
|
||||
@map.synapsemappings << mapping
|
||||
authorize mapping, :create
|
||||
mapping.save
|
||||
end
|
||||
end
|
||||
|
@ -144,6 +158,8 @@ class MapsController < ApplicationController
|
|||
@map.arranged = true
|
||||
end
|
||||
|
||||
authorize @map
|
||||
|
||||
if @map.save
|
||||
respond_to do |format|
|
||||
format.json { render :json => @map }
|
||||
|
@ -157,13 +173,11 @@ class MapsController < ApplicationController
|
|||
|
||||
# PUT maps/:id
|
||||
def update
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id]).authorize_to_edit(@current)
|
||||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
|
||||
respond_to do |format|
|
||||
if !@map
|
||||
format.json { render json: "unauthorized" }
|
||||
elsif @map.update_attributes(map_params)
|
||||
if @map.update_attributes(map_params)
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @map.errors, status: :unprocessable_entity }
|
||||
|
@ -173,51 +187,42 @@ class MapsController < ApplicationController
|
|||
|
||||
# POST maps/:id/upload_screenshot
|
||||
def screenshot
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id]).authorize_to_edit(@current)
|
||||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
|
||||
if @map
|
||||
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
|
||||
StringIO.open(png) do |data|
|
||||
data.class.class_eval { attr_accessor :original_filename, :content_type }
|
||||
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
|
||||
data.content_type = "image/png"
|
||||
@map.screenshot = data
|
||||
end
|
||||
|
||||
if @map.save
|
||||
render :json => {:message => "Successfully uploaded the map screenshot."}
|
||||
else
|
||||
render :json => {:message => "Failed to upload image."}
|
||||
end
|
||||
else
|
||||
render :json => {:message => "Unauthorized to set map screenshot."}
|
||||
end
|
||||
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
|
||||
StringIO.open(png) do |data|
|
||||
data.class.class_eval { attr_accessor :original_filename, :content_type }
|
||||
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
|
||||
data.content_type = "image/png"
|
||||
@map.screenshot = data
|
||||
end
|
||||
|
||||
if @map.save
|
||||
render :json => {:message => "Successfully uploaded the map screenshot."}
|
||||
else
|
||||
render :json => {:message => "Failed to upload image."}
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE maps/:id
|
||||
def destroy
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
|
||||
@map = Map.find(params[:id]).authorize_to_delete(@current)
|
||||
@map.delete
|
||||
|
||||
@map.delete if @map
|
||||
|
||||
respond_to do |format|
|
||||
format.json {
|
||||
if @map
|
||||
render json: "success"
|
||||
else
|
||||
render json: "unauthorized"
|
||||
end
|
||||
}
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :no_content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Never trust parameters from the scary internet, only allow the white list through.
|
||||
def map_params
|
||||
params.require(:map).permit(:id, :name, :arranged, :desc, :permission, :user_id)
|
||||
params.require(:map).permit(:id, :name, :arranged, :desc, :permission)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class MetacodeSetsController < ApplicationController
|
||||
|
||||
before_filter :require_admin
|
||||
before_action :require_admin
|
||||
|
||||
# GET /metacode_sets
|
||||
# GET /metacode_sets.json
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class MetacodesController < ApplicationController
|
||||
before_filter :require_admin, except: [:index]
|
||||
before_action :require_admin, except: [:index]
|
||||
|
||||
# GET /metacodes
|
||||
# GET /metacodes.json
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
class SynapsesController < ApplicationController
|
||||
include TopicsHelper
|
||||
|
||||
before_filter :require_user, only: [:create, :update, :destroy]
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
after_action :verify_authorized, except: :index
|
||||
after_action :verify_policy_scoped, only: :index
|
||||
|
||||
respond_to :json
|
||||
|
||||
# GET /synapses/1.json
|
||||
def show
|
||||
@synapse = Synapse.find(params[:id])
|
||||
authorize @synapse
|
||||
|
||||
#.authorize_to_show(@current)
|
||||
|
||||
#if not @synapse
|
||||
# redirect_to root_url and return
|
||||
#end
|
||||
|
||||
render json: @synapse
|
||||
end
|
||||
|
||||
|
@ -23,6 +20,7 @@ class SynapsesController < ApplicationController
|
|||
def create
|
||||
@synapse = Synapse.new(synapse_params)
|
||||
@synapse.desc = "" if @synapse.desc.nil?
|
||||
authorize @synapse
|
||||
|
||||
respond_to do |format|
|
||||
if @synapse.save
|
||||
|
@ -38,6 +36,7 @@ class SynapsesController < ApplicationController
|
|||
def update
|
||||
@synapse = Synapse.find(params[:id])
|
||||
@synapse.desc = "" if @synapse.desc.nil?
|
||||
authorize @synapse
|
||||
|
||||
respond_to do |format|
|
||||
if @synapse.update_attributes(synapse_params)
|
||||
|
@ -50,8 +49,9 @@ class SynapsesController < ApplicationController
|
|||
|
||||
# DELETE synapses/:id
|
||||
def destroy
|
||||
@synapse = Synapse.find(params[:id]).authorize_to_delete(current_user)
|
||||
@synapse.delete if @synapse
|
||||
@synapse = Synapse.find(params[:id])
|
||||
authorize @synapse
|
||||
@synapse.delete
|
||||
|
||||
respond_to do |format|
|
||||
format.json { head :no_content }
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
class TopicsController < ApplicationController
|
||||
include TopicsHelper
|
||||
|
||||
before_filter :require_user, only: [:create, :update, :destroy]
|
||||
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
after_action :verify_authorized, except: :autocomplete_topic
|
||||
|
||||
respond_to :html, :js, :json
|
||||
|
||||
# GET /topics/autocomplete_topic
|
||||
def autocomplete_topic
|
||||
@current = current_user
|
||||
term = params[:term]
|
||||
if term && !term.empty?
|
||||
@topics = Topic.where('LOWER("name") like ?', term.downcase + '%').order('"name"')
|
||||
|
||||
#read this next line as 'delete a topic if its private and you're either
|
||||
#1. logged out or 2. logged in but not the topic creator
|
||||
@topics.to_a.delete_if {|t| t.permission == "private" &&
|
||||
(!authenticated? || (authenticated? && @current.id != t.user_id)) }
|
||||
@topics = policy_scope(Topic.where('LOWER("name") like ?', term.downcase + '%')).order('"name"')
|
||||
else
|
||||
@topics = []
|
||||
end
|
||||
|
@ -24,29 +19,16 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id
|
||||
def show
|
||||
@current = current_user
|
||||
@topic = Topic.find(params[:id]).authorize_to_show(@current)
|
||||
|
||||
if not @topic
|
||||
redirect_to root_url, notice: "Access denied. That topic is private." and return
|
||||
end
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@alltopics = ([@topic] + @topic.relatives).delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } # should limit to topics visible to user
|
||||
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
|
||||
@alltopics = ([@topic] + policy_scope(Topic.relatives(@topic.id)))
|
||||
@allsynapses = policy_scope(Synapse.for_topic(@topic.id))
|
||||
|
||||
@allcreators = []
|
||||
@alltopics.each do |t|
|
||||
if @allcreators.index(t.user) == nil
|
||||
@allcreators.push(t.user)
|
||||
end
|
||||
end
|
||||
@allsynapses.each do |s|
|
||||
if @allcreators.index(s.user) == nil
|
||||
@allcreators.push(s.user)
|
||||
end
|
||||
end
|
||||
@allcreators = @alltopics.map(&:user).uniq
|
||||
@allcreators += @allsynapses.map(&:user).uniq
|
||||
|
||||
respond_with(@allsynapses, @alltopics, @allcreators, @topic)
|
||||
}
|
||||
|
@ -56,28 +38,15 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/network
|
||||
def network
|
||||
@current = current_user
|
||||
@topic = Topic.find(params[:id]).authorize_to_show(@current)
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
if not @topic
|
||||
redirect_to root_url, notice: "Access denied. That topic is private." and return
|
||||
end
|
||||
@alltopics = [@topic] + policy_scope(@topic.relatives)
|
||||
@allsynapses = policy_scope(@topic.synapses)
|
||||
|
||||
@allcreators = @alltopics.map(&:user).uniq
|
||||
@allcreators += @allsynapses.map(&:user).uniq
|
||||
|
||||
@alltopics = @topic.relatives.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
|
||||
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
|
||||
@allcreators = []
|
||||
@allcreators.push(@topic.user)
|
||||
@alltopics.each do |t|
|
||||
if @allcreators.index(t.user) == nil
|
||||
@allcreators.push(t.user)
|
||||
end
|
||||
end
|
||||
@allsynapses.each do |s|
|
||||
if @allcreators.index(s.user) == nil
|
||||
@allcreators.push(s.user)
|
||||
end
|
||||
end
|
||||
|
||||
@json = Hash.new()
|
||||
@json['topic'] = @topic
|
||||
@json['creators'] = @allcreators
|
||||
|
@ -91,121 +60,99 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/relative_numbers
|
||||
def relative_numbers
|
||||
@current = current_user
|
||||
@topic = Topic.find(params[:id]).authorize_to_show(@current)
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
if not @topic
|
||||
redirect_to root_url, notice: "Access denied. That topic is private." and return
|
||||
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
@alltopics = policy_scope(@topic.relatives).to_a.uniq
|
||||
@alltopics.delete_if! do |topic|
|
||||
topicsAlreadyHas.index(topic.id) != nil
|
||||
end
|
||||
|
||||
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
|
||||
|
||||
@alltopics = @topic.relatives.to_a.delete_if {|t|
|
||||
@topicsAlreadyHas.index(t.id.to_s) != nil ||
|
||||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
|
||||
}
|
||||
|
||||
@alltopics.uniq!
|
||||
|
||||
@json = Hash.new()
|
||||
@json = Hash.new(0)
|
||||
@alltopics.each do |t|
|
||||
if @json[t.metacode.id]
|
||||
@json[t.metacode.id] += 1
|
||||
else
|
||||
@json[t.metacode.id] = 1
|
||||
end
|
||||
@json[t.metacode.id] += 1
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: @json }
|
||||
format.json { render json: @json }
|
||||
end
|
||||
end
|
||||
|
||||
# GET topics/:id/relatives
|
||||
def relatives
|
||||
@current = current_user
|
||||
@topic = Topic.find(params[:id]).authorize_to_show(@current)
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
if not @topic
|
||||
redirect_to root_url, notice: "Access denied. That topic is private." and return
|
||||
end
|
||||
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
|
||||
alltopics = policy_scope(@topic.relatives).to_a.uniq.delete_if do |topic|
|
||||
topicsAlreadyHas.index(topic.id.to_s) != nil
|
||||
end
|
||||
|
||||
@alltopics = @topic.relatives.to_a.delete_if {|t|
|
||||
@topicsAlreadyHas.index(t.id.to_s) != nil ||
|
||||
(params[:metacode] && t.metacode_id.to_s != params[:metacode]) ||
|
||||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
|
||||
}
|
||||
#find synapses between topics in alltopics array
|
||||
allsynapses = policy_scope(@topic.synapses)
|
||||
synapse_ids = (allsynapses.map(&:topic1_id) + allsynapses.map(&:topic2_id)).uniq
|
||||
allsynapses.delete_if! do |synapse|
|
||||
synapse_ids.index(synapse.id) != nil
|
||||
end
|
||||
|
||||
@alltopics.uniq!
|
||||
creatorsAlreadyHas = params[:creators] ? params[:creators].split(',').map(&:to_i) : []
|
||||
allcreators = (alltopics.map(&:user) + allsynapses.map(&:user)).uniq.delete_if do |user|
|
||||
creatorsAlreadyHas.index(user.id) != nil
|
||||
end
|
||||
|
||||
@allsynapses = @topic.synapses.to_a.delete_if {|s|
|
||||
(s.topic1 == @topic && @alltopics.index(s.topic2) == nil) ||
|
||||
(s.topic2 == @topic && @alltopics.index(s.topic1) == nil)
|
||||
}
|
||||
@json = Hash.new()
|
||||
@json['topics'] = alltopics
|
||||
@json['synapses'] = allsynapses
|
||||
@json['creators'] = allcreators
|
||||
|
||||
@creatorsAlreadyHas = params[:creators] ? params[:creators].split(',') : []
|
||||
@allcreators = []
|
||||
@alltopics.each do |t|
|
||||
if @allcreators.index(t.user) == nil && @creatorsAlreadyHas.index(t.user_id.to_s) == nil
|
||||
@allcreators.push(t.user)
|
||||
end
|
||||
end
|
||||
@allsynapses.each do |s|
|
||||
if @allcreators.index(s.user) == nil && @creatorsAlreadyHas.index(s.user_id.to_s) == nil
|
||||
@allcreators.push(s.user)
|
||||
end
|
||||
end
|
||||
|
||||
@json = Hash.new()
|
||||
@json['topics'] = @alltopics
|
||||
@json['synapses'] = @allsynapses
|
||||
@json['creators'] = @allcreators
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: @json }
|
||||
end
|
||||
respond_to do |format|
|
||||
format.json { render json: @json }
|
||||
end
|
||||
end
|
||||
|
||||
# POST /topics
|
||||
# POST /topics.json
|
||||
def create
|
||||
@topic = Topic.new(topic_params)
|
||||
# POST /topics
|
||||
# POST /topics.json
|
||||
def create
|
||||
@topic = Topic.new(topic_params)
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
if @topic.save
|
||||
format.json { render json: @topic, status: :created }
|
||||
else
|
||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
if @topic.save
|
||||
format.json { render json: @topic, status: :created }
|
||||
else
|
||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# PUT /topics/1
|
||||
# PUT /topics/1.json
|
||||
def update
|
||||
@topic = Topic.find(params[:id])
|
||||
# PUT /topics/1
|
||||
# PUT /topics/1.json
|
||||
def update
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
if @topic.update_attributes(topic_params)
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
if @topic.update_attributes(topic_params)
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE topics/:id
|
||||
def destroy
|
||||
@current = current_user
|
||||
@topic = Topic.find(params[:id]).authorize_to_delete(@current)
|
||||
@topic.delete if @topic
|
||||
# DELETE topics/:id
|
||||
def destroy
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
format.json { head :no_content }
|
||||
end
|
||||
@topic.delete
|
||||
respond_to do |format|
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Users::RegistrationsController < Devise::RegistrationsController
|
||||
before_filter :configure_sign_up_params, only: [:create]
|
||||
before_filter :configure_account_update_params, only: [:update]
|
||||
before_action :configure_sign_up_params, only: [:create]
|
||||
before_action :configure_account_update_params, only: [:update]
|
||||
|
||||
protected
|
||||
def after_sign_up_path_for(resource)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class UsersController < ApplicationController
|
||||
before_filter :require_user, only: [:edit, :update, :updatemetacodes]
|
||||
before_action :require_user, only: [:edit, :update, :updatemetacodes]
|
||||
|
||||
respond_to :html, :json
|
||||
|
||||
|
|
10
app/models/concerns/routing.rb
Normal file
10
app/models/concerns/routing.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
module Routing
|
||||
extend ActiveSupport::Concern
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
included do
|
||||
def default_url_options
|
||||
ActionMailer::Base.default_url_options
|
||||
end
|
||||
end
|
||||
end
|
34
app/models/event.rb
Normal file
34
app/models/event.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
class Event < ActiveRecord::Base
|
||||
KINDS = %w[topic_added_to_map synapse_added_to_map]
|
||||
|
||||
#has_many :notifications, dependent: :destroy
|
||||
belongs_to :eventable, polymorphic: true
|
||||
belongs_to :map
|
||||
belongs_to :user
|
||||
|
||||
scope :sequenced, -> { where('sequence_id is not null').order('sequence_id asc') }
|
||||
scope :chronologically, -> { order('created_at asc') }
|
||||
|
||||
after_create :notify_webhooks!, if: :map
|
||||
|
||||
validates_inclusion_of :kind, :in => KINDS
|
||||
validates_presence_of :eventable
|
||||
|
||||
acts_as_sequenced scope: :map_id, column: :sequence_id, skip: lambda {|e| e.map.nil? || e.map_id.nil? }
|
||||
|
||||
#def notify!(user)
|
||||
# notifications.create!(user: user)
|
||||
#end
|
||||
|
||||
def belongs_to?(this_user)
|
||||
self.user_id == this_user.id
|
||||
end
|
||||
|
||||
def notify_webhooks!
|
||||
#group = self.discussion.group
|
||||
self.map.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
|
||||
#group.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
|
||||
end
|
||||
handle_asynchronously :notify_webhooks!
|
||||
|
||||
end
|
18
app/models/events/new_mapping.rb
Normal file
18
app/models/events/new_mapping.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class Events::NewMapping < Event
|
||||
#after_create :notify_users!
|
||||
|
||||
def self.publish!(mapping, user)
|
||||
create!(kind: mapping.mappable_type == "Topic" ? "topic_added_to_map" : "synapse_added_to_map",
|
||||
eventable: mapping,
|
||||
map: mapping.map,
|
||||
user: user)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
#def notify_users!
|
||||
# unless comment_vote.user == comment_vote.comment_user
|
||||
# notify!(comment_vote.comment_user)
|
||||
# end
|
||||
#end
|
||||
end
|
|
@ -8,6 +8,9 @@ class Map < ActiveRecord::Base
|
|||
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse"
|
||||
has_many :messages, as: :resource, dependent: :destroy
|
||||
|
||||
has_many :webhooks, as: :hookable
|
||||
has_many :events, -> { includes :user }, as: :eventable, dependent: :destroy
|
||||
|
||||
# This method associates the attribute ":image" with a file attachment
|
||||
has_attached_file :screenshot, :styles => {
|
||||
:thumb => ['188x126#', :png]
|
||||
|
@ -98,36 +101,7 @@ class Map < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
##### PERMISSIONS ######
|
||||
|
||||
def authorize_to_delete(user)
|
||||
if (self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
# returns false if user not allowed to 'show' Topic, Synapse, or Map
|
||||
def authorize_to_show(user)
|
||||
if (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
|
||||
def authorize_to_edit(user)
|
||||
if !user
|
||||
return false
|
||||
elsif (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
elsif (self.permission == "public" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
def decode_base64(imgBase64)
|
||||
decoded_data = Base64.decode64(imgBase64)
|
||||
|
||||
|
|
|
@ -25,5 +25,5 @@ class Mapping < ActiveRecord::Base
|
|||
def as_json(options={})
|
||||
super(:methods =>[:user_name, :user_image])
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
33
app/models/permitted_params.rb
Normal file
33
app/models/permitted_params.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
class PermittedParams < Struct.new(:params)
|
||||
|
||||
%w[map synapse topic mapping token].each do |kind|
|
||||
define_method(kind) do
|
||||
permitted_attributes = self.send("#{kind}_attributes")
|
||||
params.require(kind).permit(*permitted_attributes)
|
||||
end
|
||||
alias_method :"api_#{kind}", kind.to_sym
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
def token_attributes
|
||||
[:description]
|
||||
end
|
||||
|
||||
def map_attributes
|
||||
[:name, :desc, :permission, :arranged]
|
||||
end
|
||||
|
||||
def synapse_attributes
|
||||
[:desc, :category, :weight, :permission, :node1_id, :node2_id]
|
||||
end
|
||||
|
||||
def topic_attributes
|
||||
[:name, :desc, :link, :permission, :metacode_id]
|
||||
end
|
||||
|
||||
def mapping_attributes
|
||||
[:xloc, :yloc, :map_id, :mappable_type, :mappable_id]
|
||||
end
|
||||
|
||||
end
|
|
@ -10,10 +10,16 @@ class Synapse < ActiveRecord::Base
|
|||
validates :desc, length: { minimum: 0, allow_nil: false }
|
||||
|
||||
validates :permission, presence: true
|
||||
validates :node1_id, presence: true
|
||||
validates :node2_id, presence: true
|
||||
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
|
||||
|
||||
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true }
|
||||
|
||||
scope :for_topic, ->(topic_id = nil) {
|
||||
where("node1_id = ? OR node2_id = ?", topic_id, topic_id)
|
||||
}
|
||||
|
||||
# :nocov:
|
||||
def user_name
|
||||
user.name
|
||||
|
@ -32,30 +38,4 @@ class Synapse < ActiveRecord::Base
|
|||
end
|
||||
# :nocov:
|
||||
|
||||
##### PERMISSIONS ######
|
||||
|
||||
# returns false if user not allowed to 'show' Topic, Synapse, or Map
|
||||
def authorize_to_show(user)
|
||||
if (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
|
||||
def authorize_to_edit(user)
|
||||
if (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
elsif (self.permission == "public" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
def authorize_to_delete(user)
|
||||
if (self.user == user || user.admin)
|
||||
return self
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
|
22
app/models/token.rb
Normal file
22
app/models/token.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
class Token < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
before_create :assign_token
|
||||
|
||||
CHARS = 32
|
||||
|
||||
private
|
||||
def assign_token
|
||||
self.token = generate_token
|
||||
end
|
||||
|
||||
def generate_token
|
||||
loop do
|
||||
candidate = SecureRandom.base64(CHARS).gsub(/\W/, '')
|
||||
if candidate.size >= CHARS
|
||||
return candidate[0...CHARS]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -41,6 +41,13 @@ class Topic < ActiveRecord::Base
|
|||
|
||||
belongs_to :metacode
|
||||
|
||||
scope :relatives, ->(topic_id = nil) {
|
||||
includes(:synapses1)
|
||||
.includes(:synapses2)
|
||||
.where('synapses.node1_id = ? OR synapses.node2_id = ?', topic_id, topic_id)
|
||||
.references(:synapses)
|
||||
}
|
||||
|
||||
def user_name
|
||||
user.name
|
||||
end
|
||||
|
@ -119,31 +126,4 @@ class Topic < ActiveRecord::Base
|
|||
end
|
||||
output
|
||||
end
|
||||
|
||||
##### PERMISSIONS ######
|
||||
|
||||
# returns false if user not allowed to 'show' Topic, Synapse, or Map
|
||||
def authorize_to_show(user)
|
||||
if (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
|
||||
def authorize_to_edit(user)
|
||||
if (self.permission == "private" && self.user != user)
|
||||
return false
|
||||
elsif (self.permission == "public" && self.user != user)
|
||||
return false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
def authorize_to_delete(user)
|
||||
if (self.user == user || user.admin)
|
||||
return self
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ class User < ActiveRecord::Base
|
|||
has_many :synapses
|
||||
has_many :maps
|
||||
has_many :mappings
|
||||
has_many :tokens
|
||||
|
||||
after_create :generate_code
|
||||
|
||||
|
|
13
app/models/webhook.rb
Normal file
13
app/models/webhook.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
class Webhook < ActiveRecord::Base
|
||||
belongs_to :hookable, polymorphic: true
|
||||
|
||||
validates :uri, presence: true
|
||||
validates :hookable, presence: true
|
||||
validates_inclusion_of :kind, in: %w[slack]
|
||||
validates :event_types, length: { minimum: 1 }
|
||||
|
||||
def headers
|
||||
{}
|
||||
end
|
||||
|
||||
end
|
72
app/models/webhooks/slack/base.rb
Normal file
72
app/models/webhooks/slack/base.rb
Normal file
|
@ -0,0 +1,72 @@
|
|||
Webhooks::Slack::Base = Struct.new(:event) do
|
||||
include Routing
|
||||
|
||||
def username
|
||||
"Metamaps Bot"
|
||||
end
|
||||
|
||||
def icon_url
|
||||
"https://pbs.twimg.com/profile_images/539300245029392385/dJ1bwnw7.jpeg"
|
||||
end
|
||||
|
||||
def text
|
||||
"something"
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{
|
||||
title: attachment_title,
|
||||
text: attachment_text,
|
||||
fields: attachment_fields,
|
||||
fallback: attachment_fallback
|
||||
}]
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
private
|
||||
|
||||
#def motion_vote_field
|
||||
# {
|
||||
# title: "Vote on this proposal",
|
||||
# value: "#{proposal_link(eventable, "yes")} · " +
|
||||
# "#{proposal_link(eventable, "abstain")} · " +
|
||||
# "#{proposal_link(eventable, "no")} · " +
|
||||
# "#{proposal_link(eventable, "block")}"
|
||||
# }
|
||||
#end
|
||||
|
||||
def view_map_on_metamaps(text = nil)
|
||||
"<#{map_url(eventable.map)}|#{text || eventable.map.name}>"
|
||||
end
|
||||
|
||||
#def view_discussion_on_loomio(params = {})
|
||||
# { value: discussion_link(I18n.t(:"webhooks.slack.view_it_on_loomio"), params) }
|
||||
#end
|
||||
|
||||
#def proposal_link(proposal, position = nil)
|
||||
# discussion_link position || proposal.name, { proposal: proposal.key, position: position }
|
||||
#end
|
||||
|
||||
#def discussion_link(text = nil, params = {})
|
||||
# "<#{discussion_url(eventable.map, params)}|#{text || eventable.discussion.title}>"
|
||||
#end
|
||||
|
||||
def eventable
|
||||
@eventable ||= event.eventable
|
||||
end
|
||||
|
||||
def author
|
||||
@author ||= eventable.author
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#webhooks:
|
||||
# slack:
|
||||
# motion_closed: "*%{name}* has closed"
|
||||
# motion_closing_soon: "*%{name}* has a proposal closing in 24 hours"
|
||||
# motion_outcome_created: "*%{author}* published an outcome in *%{name}*"
|
||||
# motion_outcome_updated: "*%{author}* updated the outcome for *%{name}*"
|
||||
# new_motion: "*%{author}* started a new proposal in *%{name}*"
|
||||
# view_it_on_loomio: "View it on Loomio"
|
26
app/models/webhooks/slack/synapse_added_to_map.rb
Normal file
26
app/models/webhooks/slack/synapse_added_to_map.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class Webhooks::Slack::SynapseAddedToMap < Webhooks::Slack::Base
|
||||
|
||||
def text
|
||||
"\"*#{eventable.mappable.topic1.name}* #{eventable.mappable.desc || '->'} *#{eventable.mappable.topic2.name}*\" was added as a connection to the map *#{view_map_on_metamaps()}*"
|
||||
end
|
||||
|
||||
def attachment_fallback
|
||||
"" #{}"*#{eventable.name}*\n#{eventable.description}\n"
|
||||
end
|
||||
|
||||
def attachment_title
|
||||
"" #proposal_link(eventable)
|
||||
end
|
||||
|
||||
def attachment_text
|
||||
"" # "#{eventable.description}\n"
|
||||
end
|
||||
|
||||
def attachment_fields
|
||||
[{
|
||||
title: "nothing",
|
||||
value: "nothing"
|
||||
}] #[motion_vote_field]
|
||||
end
|
||||
|
||||
end
|
27
app/models/webhooks/slack/topic_added_to_map.rb
Normal file
27
app/models/webhooks/slack/topic_added_to_map.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
class Webhooks::Slack::TopicAddedToMap < Webhooks::Slack::Base
|
||||
|
||||
def text
|
||||
"New #{eventable.mappable.metacode.name} topic *#{eventable.mappable.name}* was added to the map *#{view_map_on_metamaps()}*"
|
||||
end
|
||||
# todo: it would be sweet if it sends it with the metacode as the icon_url
|
||||
|
||||
def attachment_fallback
|
||||
"" #{}"*#{eventable.name}*\n#{eventable.description}\n"
|
||||
end
|
||||
|
||||
def attachment_title
|
||||
"" #proposal_link(eventable)
|
||||
end
|
||||
|
||||
def attachment_text
|
||||
"" # "#{eventable.description}\n"
|
||||
end
|
||||
|
||||
def attachment_fields
|
||||
[{
|
||||
title: "nothing",
|
||||
value: "nothing"
|
||||
}] #[motion_vote_field]
|
||||
end
|
||||
|
||||
end
|
61
app/policies/application_policy.rb
Normal file
61
app/policies/application_policy.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
class ApplicationPolicy
|
||||
attr_reader :user, :record
|
||||
|
||||
def initialize(user, record)
|
||||
@user = user
|
||||
@record = record
|
||||
end
|
||||
|
||||
def index?
|
||||
false
|
||||
end
|
||||
|
||||
def show?
|
||||
scope.where(:id => record.id).exists?
|
||||
end
|
||||
|
||||
def create?
|
||||
false
|
||||
end
|
||||
|
||||
def new?
|
||||
create?
|
||||
end
|
||||
|
||||
def update?
|
||||
false
|
||||
end
|
||||
|
||||
def edit?
|
||||
update?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
false
|
||||
end
|
||||
|
||||
# TODO update this function to enable some flag in the interface
|
||||
# so that admins usually can't do super admin stuff unless they
|
||||
# explicitly say they want to (E.g. seeing/editing/deleting private
|
||||
# maps - they should be able to, but not by accident)
|
||||
def admin_override
|
||||
user && user.admin
|
||||
end
|
||||
|
||||
def scope
|
||||
Pundit.policy_scope!(user, record.class)
|
||||
end
|
||||
|
||||
class Scope
|
||||
attr_reader :user, :scope
|
||||
|
||||
def initialize(user, scope)
|
||||
@user = user
|
||||
@scope = scope
|
||||
end
|
||||
|
||||
def resolve
|
||||
scope
|
||||
end
|
||||
end
|
||||
end
|
26
app/policies/main_policy.rb
Normal file
26
app/policies/main_policy.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
class MainPolicy < ApplicationPolicy
|
||||
def initialize(user, record)
|
||||
@user = user
|
||||
@record = nil
|
||||
end
|
||||
|
||||
def home?
|
||||
true
|
||||
end
|
||||
|
||||
def searchtopics?
|
||||
true
|
||||
end
|
||||
|
||||
def searchmaps?
|
||||
true
|
||||
end
|
||||
|
||||
def searchmappers?
|
||||
true
|
||||
end
|
||||
|
||||
def searchsynapses?
|
||||
true
|
||||
end
|
||||
end
|
53
app/policies/map_policy.rb
Normal file
53
app/policies/map_policy.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
class MapPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
visible = ['public', 'commons']
|
||||
permission = 'maps.permission IN (?)'
|
||||
if user
|
||||
scope.where(permission + ' OR maps.user_id = ?', visible, user.id)
|
||||
else
|
||||
scope.where(permission, visible)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def activemaps?
|
||||
user.blank? # redirect to root url if authenticated for some reason
|
||||
end
|
||||
|
||||
def featuredmaps?
|
||||
true
|
||||
end
|
||||
|
||||
def mymaps?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def usermaps?
|
||||
true
|
||||
end
|
||||
|
||||
def show?
|
||||
record.permission == 'commons' || record.permission == 'public' || record.user == user
|
||||
end
|
||||
|
||||
def contains?
|
||||
show?
|
||||
end
|
||||
|
||||
def create?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.present? && (record.permission == 'commons' || record.user == user)
|
||||
end
|
||||
|
||||
def screenshot?
|
||||
update?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
record.user == user || admin_override
|
||||
end
|
||||
end
|
35
app/policies/mapping_policy.rb
Normal file
35
app/policies/mapping_policy.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
class MappingPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
# TODO base this on the map policy
|
||||
# it would be nice if we could also base this on the mappable, but that
|
||||
# gets really complicated. Devin thinks it's OK to SHOW a mapping for
|
||||
# a private topic, since you can't see the private topic anyways
|
||||
visible = ['public', 'commons']
|
||||
permission = 'maps.permission IN (?)'
|
||||
if user
|
||||
scope.joins(:maps).where(permission + ' OR maps.user_id = ?', visible, user.id)
|
||||
else
|
||||
scope.where(permission, visible)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show?
|
||||
map = Pundit.policy(user, record.map)
|
||||
mappable = Pundit.policy(user, record.mappable)
|
||||
map.show? && mappable.show?
|
||||
end
|
||||
|
||||
def create?
|
||||
Pundit.policy(user, record.map).update?
|
||||
end
|
||||
|
||||
def update?
|
||||
Pundit.policy(user, record.map).update?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
record.user == user || admin_override
|
||||
end
|
||||
end
|
30
app/policies/synapse_policy.rb
Normal file
30
app/policies/synapse_policy.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
class SynapsePolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
visible = ['public', 'commons']
|
||||
permission = 'synapses.permission IN (?)'
|
||||
if user
|
||||
scope.where(permission + ' OR synapses.user_id = ?', visible, user.id)
|
||||
else
|
||||
scope.where(permission, visible)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create?
|
||||
user.present?
|
||||
# todo add validation against whether you can see both topics
|
||||
end
|
||||
|
||||
def show?
|
||||
record.permission == 'commons' || record.permission == 'public' || record.user == user
|
||||
end
|
||||
|
||||
def update?
|
||||
user.present? && (record.permission == 'commons' || record.user == user)
|
||||
end
|
||||
|
||||
def destroy?
|
||||
record.user == user || admin_override
|
||||
end
|
||||
end
|
24
app/policies/token_policy.rb
Normal file
24
app/policies/token_policy.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
class TokenPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user
|
||||
scope.where('tokens.user_id = ?', user.id)
|
||||
else
|
||||
where(:id => nil).where("id IS NOT ?", nil) # to just return none
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def my_tokens?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.present? && record.user == user
|
||||
end
|
||||
|
||||
end
|
45
app/policies/topic_policy.rb
Normal file
45
app/policies/topic_policy.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
class TopicPolicy < ApplicationPolicy
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
visible = ['public', 'commons']
|
||||
permission = 'topics.permission IN (?)'
|
||||
if user
|
||||
scope.where(permission + ' OR topics.user_id = ?', visible, user.id)
|
||||
else
|
||||
scope.where(permission, visible)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def show?
|
||||
record.permission == 'commons' || record.permission == 'public' || record.user == user
|
||||
end
|
||||
|
||||
def update?
|
||||
user.present? && (record.permission == 'commons' || record.user == user)
|
||||
end
|
||||
|
||||
def destroy?
|
||||
record.user == user || admin_override
|
||||
end
|
||||
|
||||
def autocomplete_topic?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def network?
|
||||
show?
|
||||
end
|
||||
|
||||
def relative_numbers?
|
||||
show?
|
||||
end
|
||||
|
||||
def relatives?
|
||||
show?
|
||||
end
|
||||
end
|
15
app/serializers/event_serializer.rb
Normal file
15
app/serializers/event_serializer.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class EventSerializer < ActiveModel::Serializer
|
||||
embed :ids, include: true
|
||||
attributes :id, :sequence_id, :kind, :map_id, :created_at
|
||||
|
||||
has_one :actor, serializer: NewUserSerializer, root: 'users'
|
||||
has_one :map, serializer: NewMapSerializer
|
||||
|
||||
def actor
|
||||
object.user || object.eventable.try(:user)
|
||||
end
|
||||
|
||||
def map
|
||||
object.eventable.try(:map) || object.eventable.map
|
||||
end
|
||||
end
|
16
app/serializers/new_map_serializer.rb
Normal file
16
app/serializers/new_map_serializer.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class NewMapSerializer < ActiveModel::Serializer
|
||||
embed :ids, include: true
|
||||
attributes :id,
|
||||
:name,
|
||||
:desc,
|
||||
:permission,
|
||||
:screenshot,
|
||||
:created_at,
|
||||
:updated_at
|
||||
|
||||
has_many :topics, serializer: NewTopicSerializer
|
||||
has_many :synapses, serializer: NewSynapseSerializer
|
||||
has_many :mappings, serializer: NewMappingSerializer
|
||||
has_many :contributors, root: :users, serializer: NewUserSerializer
|
||||
|
||||
end
|
19
app/serializers/new_mapping_serializer.rb
Normal file
19
app/serializers/new_mapping_serializer.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
class NewMappingSerializer < ActiveModel::Serializer
|
||||
embed :ids, include: true
|
||||
attributes :id,
|
||||
:xloc,
|
||||
:yloc,
|
||||
:created_at,
|
||||
:updated_at,
|
||||
:mappable_id,
|
||||
:mappable_type
|
||||
|
||||
has_one :user, serializer: NewUserSerializer
|
||||
has_one :map, serializer: NewMapSerializer
|
||||
|
||||
def filter(keys)
|
||||
keys.delete(:xloc) unless object.mappable_type == "Topic"
|
||||
keys.delete(:yloc) unless object.mappable_type == "Topic"
|
||||
keys
|
||||
end
|
||||
end
|
7
app/serializers/new_metacode_serializer.rb
Normal file
7
app/serializers/new_metacode_serializer.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class NewMetacodeSerializer < ActiveModel::Serializer
|
||||
attributes :id,
|
||||
:name,
|
||||
:manual_icon,
|
||||
:color,
|
||||
:aws_icon
|
||||
end
|
15
app/serializers/new_synapse_serializer.rb
Normal file
15
app/serializers/new_synapse_serializer.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class NewSynapseSerializer < ActiveModel::Serializer
|
||||
embed :ids, include: true
|
||||
attributes :id,
|
||||
:desc,
|
||||
:category,
|
||||
:weight,
|
||||
:permission,
|
||||
:created_at,
|
||||
:updated_at
|
||||
|
||||
has_one :topic1, root: :topics, serializer: NewTopicSerializer
|
||||
has_one :topic2, root: :topics, serializer: NewTopicSerializer
|
||||
has_one :user, serializer: NewUserSerializer
|
||||
|
||||
end
|
14
app/serializers/new_topic_serializer.rb
Normal file
14
app/serializers/new_topic_serializer.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
class NewTopicSerializer < ActiveModel::Serializer
|
||||
embed :ids, include: true
|
||||
attributes :id,
|
||||
:name,
|
||||
:desc,
|
||||
:link,
|
||||
:permission,
|
||||
:created_at,
|
||||
:updated_at
|
||||
|
||||
has_one :user, serializer: NewUserSerializer
|
||||
has_one :metacode, serializer: NewMetacodeSerializer
|
||||
|
||||
end
|
15
app/serializers/new_user_serializer.rb
Normal file
15
app/serializers/new_user_serializer.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class NewUserSerializer < ActiveModel::Serializer
|
||||
attributes :id,
|
||||
:name,
|
||||
:avatar,
|
||||
:is_admin,
|
||||
:generation
|
||||
|
||||
def avatar
|
||||
object.image.url(:sixtyfour)
|
||||
end
|
||||
|
||||
def is_admin
|
||||
object.admin
|
||||
end
|
||||
end
|
8
app/serializers/token_serializer.rb
Normal file
8
app/serializers/token_serializer.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class TokenSerializer < ActiveModel::Serializer
|
||||
attributes :id,
|
||||
:token,
|
||||
:description,
|
||||
:created_at,
|
||||
:updated_at
|
||||
|
||||
end
|
3
app/serializers/webhook_serializer.rb
Normal file
3
app/serializers/webhook_serializer.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class WebhookSerializer < ActiveModel::Serializer
|
||||
attributes :text, :username, :icon_url #, :attachments
|
||||
end
|
18
app/services/webhook_service.rb
Normal file
18
app/services/webhook_service.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class WebhookService
|
||||
|
||||
def self.publish!(webhook:, event:)
|
||||
return false unless webhook.event_types.include? event.kind
|
||||
HTTParty.post webhook.uri, body: payload_for(webhook, event), headers: webhook.headers
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.payload_for(webhook, event)
|
||||
WebhookSerializer.new(webhook_object_for(webhook, event), root: false).to_json
|
||||
end
|
||||
|
||||
def self.webhook_object_for(webhook, event)
|
||||
"Webhooks::#{webhook.kind.classify}::#{event.kind.classify}".constantize.new(event)
|
||||
end
|
||||
|
||||
end
|
|
@ -81,7 +81,7 @@
|
|||
classes += controller_name == "maps" && action_name == "index" ? " explorePage" : ""
|
||||
if controller_name == "maps" && action_name == "show"
|
||||
classes += " mapPage"
|
||||
if @map.authorize_to_edit(current_user)
|
||||
if policy(@map).update?
|
||||
classes += " canEditMap"
|
||||
end
|
||||
if @map.permission == "commons"
|
||||
|
|
|
@ -2,52 +2,42 @@
|
|||
# @file
|
||||
# Located at /
|
||||
# Shows 3 most recently created topics, synapses, and maps.
|
||||
#%>
|
||||
|
||||
<% if !authenticated? %>
|
||||
<% content_for :title, "Home | Metamaps" %>
|
||||
<div id="yield">
|
||||
<div class="homeWrapper homeText">
|
||||
<div class="homeTitle">Make Sense with Metamaps</div>
|
||||
<div class="homeIntro">
|
||||
<span class="green din-medium">METAMAPS.CC</span> is a free and open source platform that supports real-time sense-making, distributed collaboration, and the creative intelligence of individuals, organizations and communities. We are currently in an <span class="din-medium">invite-only beta.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fullWidthWrapper withVideo">
|
||||
<div class="homeWrapper">
|
||||
<iframe class="homeVideo" src="//player.vimeo.com/video/113154814" width="560" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
<div class="callToAction">
|
||||
<h3>Who finds it useful?</h3>
|
||||
<p>Designers, inventors, artists, educators, strategists, consultants, facilitators, entrepreneurs, systems thinkers, changemakers, analysts, students, researchers... maybe you!</p>
|
||||
<button type="button" class="button learnMoreCTA" onclick="Metamaps.GlobalUI.openLightbox('about');">LEARN MORE</button>
|
||||
<a href="/explore/featured" class="exploreFeaturedCTA">EXPLORE FEATURED MAPS</a>
|
||||
<a href="/request" class="requestInviteCTA" data-bypass="true">REQUEST INVITE</a>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fullWidthWrapper withPartners">
|
||||
<div class="homeWrapper homePartners">
|
||||
<% # our partners %>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- end yield -->
|
||||
<div class="github-fork-ribbon-wrapper right-bottom">
|
||||
<div class="github-fork-ribbon">
|
||||
<a href="https://github.com/metamaps/metamaps_gen002" target="_blank">Fork me on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
Metamaps.currentSection = "";
|
||||
Metamaps.currentPage = "";
|
||||
</script>
|
||||
<% elsif authenticated? %>
|
||||
<% content_for :title, "Explore Active Maps | Metamaps" %>
|
||||
<script>
|
||||
Metamaps.Maps.Active = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentSection = "";
|
||||
Metamaps.currentPage = "";
|
||||
Metamaps.GlobalUI.Search.open();
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
||||
<% end %>
|
||||
#
|
||||
%>
|
||||
|
||||
<% content_for :title, "Home | Metamaps" %>
|
||||
<div id="yield">
|
||||
<div class="homeWrapper homeText">
|
||||
<div class="homeTitle">Make Sense with Metamaps</div>
|
||||
<div class="homeIntro">
|
||||
<span class="green din-medium">METAMAPS.CC</span> is a free and open source platform that supports real-time sense-making, distributed collaboration, and the creative intelligence of individuals, organizations and communities. We are currently in an <span class="din-medium">invite-only beta.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fullWidthWrapper withVideo">
|
||||
<div class="homeWrapper">
|
||||
<iframe class="homeVideo" src="https://player.vimeo.com/video/113154814" width="560" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
<div class="callToAction">
|
||||
<h3>Who finds it useful?</h3>
|
||||
<p>Designers, inventors, artists, educators, strategists, consultants, facilitators, entrepreneurs, systems thinkers, changemakers, analysts, students, researchers... maybe you!</p>
|
||||
<button type="button" class="button learnMoreCTA" onclick="Metamaps.GlobalUI.openLightbox('about');">LEARN MORE</button>
|
||||
<a href="/explore/featured" class="exploreFeaturedCTA">EXPLORE FEATURED MAPS</a>
|
||||
<a href="/request" class="requestInviteCTA" data-bypass="true">REQUEST INVITE</a>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fullWidthWrapper withPartners">
|
||||
<div class="homeWrapper homePartners">
|
||||
<% # our partners %>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- end yield -->
|
||||
<div class="github-fork-ribbon-wrapper right-bottom">
|
||||
<div class="github-fork-ribbon">
|
||||
<a href="https://github.com/metamaps/metamaps_gen002" target="_blank">Fork me on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
Metamaps.currentSection = "";
|
||||
Metamaps.currentPage = "";
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#%>
|
||||
<div class="mapInfoBox mapElement mapElementHidden permission
|
||||
<%= @map && @map.user == user ? " yourMap" : "" %>
|
||||
<%= @map && @map.authorize_to_edit(user) ? " canEdit" : "" %>
|
||||
<%= @map && policy(@map).update? ? " canEdit" : "" %>
|
||||
<%= @map && @map.permission != 'private' ? " shareable" : "" %>">
|
||||
|
||||
<% if @map %>
|
||||
|
@ -41,7 +41,7 @@
|
|||
</div>
|
||||
|
||||
<div class="mapInfoDesc" id="mapInfoDesc">
|
||||
<% if (authenticated? && @map.authorize_to_edit(user)) || (!authenticated? && @map.desc != "" && @map.desc != nil )%>
|
||||
<% if (authenticated? && policy(@map).update?) || (!authenticated? && @map.desc != "" && @map.desc != nil )%>
|
||||
<%= best_in_place @map, :desc, :activator => "#mapInfoDesc", :as => :textarea, :placeholder => "Click to add description...", :class => 'best_in_place_desc' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
15
app/views/maps/activemaps.html.erb
Normal file
15
app/views/maps/activemaps.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% #
|
||||
# @file
|
||||
# Shows a list of recently active maps
|
||||
# GET /explore/active(.:format)
|
||||
# %>
|
||||
|
||||
<script>
|
||||
Metamaps.Maps.Active = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "active";
|
||||
<% content_for :title, "Explore Active Maps | Metamaps" %>
|
||||
|
||||
Metamaps.currentSection = "explore";
|
||||
Metamaps.GlobalUI.Search.isOpen = true;
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
15
app/views/maps/featuredmaps.html.erb
Normal file
15
app/views/maps/featuredmaps.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% #
|
||||
# @file
|
||||
# Shows a list of featured maps
|
||||
# GET /explore/featured(.:format)
|
||||
# %>
|
||||
|
||||
<script>
|
||||
Metamaps.Maps.Featured = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "featured";
|
||||
<% content_for :title, "Explore Featured Maps | Metamaps" %>
|
||||
|
||||
Metamaps.currentSection = "explore";
|
||||
Metamaps.GlobalUI.Search.isOpen = true;
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
|
@ -1,38 +0,0 @@
|
|||
<% #
|
||||
# @file
|
||||
# Shows a list of all maps, or just a user's maps.
|
||||
# GET /explore/active(.:format)
|
||||
# GET /explore/featured(.:format)
|
||||
# GET /explore/mine(.:format)
|
||||
# GET /explore/mapper/:id(.:format)
|
||||
# GET /maps(.:format)
|
||||
# %>
|
||||
|
||||
<script>
|
||||
<% if @request == "you" %>
|
||||
Metamaps.Maps.Mine = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "mine";
|
||||
<% content_for :title, "Explore My Maps | Metamaps" %>
|
||||
|
||||
<% elsif @request == "featured" %>
|
||||
Metamaps.Maps.Featured = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "featured";
|
||||
<% content_for :title, "Explore Featured Maps | Metamaps" %>
|
||||
|
||||
<% elsif @request == "active" %>
|
||||
Metamaps.Maps.Active = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "active";
|
||||
<% content_for :title, "Explore Active Maps | Metamaps" %>
|
||||
|
||||
<% elsif @request == "mapper" %>
|
||||
Metamaps.Maps.Mapper = {
|
||||
models: <%= @maps.to_json.html_safe %>,
|
||||
id: <%= params[:id] %>
|
||||
};
|
||||
Metamaps.currentPage = "mapper";
|
||||
<% content_for :title, @user.name + " | Metamaps" %>
|
||||
<% end %>
|
||||
Metamaps.currentSection = "explore";
|
||||
Metamaps.GlobalUI.Search.isOpen = true;
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
15
app/views/maps/mymaps.html.erb
Normal file
15
app/views/maps/mymaps.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% #
|
||||
# @file
|
||||
# Shows a list of current user's maps
|
||||
# GET /explore/mine(.:format)
|
||||
# %>
|
||||
|
||||
<script>
|
||||
Metamaps.Maps.Mine = <%= @maps.to_json.html_safe %>;
|
||||
Metamaps.currentPage = "mine";
|
||||
<% content_for :title, "Explore My Maps | Metamaps" %>
|
||||
|
||||
Metamaps.currentSection = "explore";
|
||||
Metamaps.GlobalUI.Search.isOpen = true;
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
18
app/views/maps/usermaps.html.erb
Normal file
18
app/views/maps/usermaps.html.erb
Normal file
|
@ -0,0 +1,18 @@
|
|||
<% #
|
||||
# @file
|
||||
# Shows a list of a user's maps
|
||||
# GET /explore/mapper/:id(.:format)
|
||||
# %>
|
||||
|
||||
<script>
|
||||
Metamaps.Maps.Mapper = {
|
||||
models: <%= @maps.to_json.html_safe %>,
|
||||
id: <%= params[:id] %>
|
||||
};
|
||||
Metamaps.currentPage = "mapper";
|
||||
<% content_for :title, @user.name + " | Metamaps" %>
|
||||
|
||||
Metamaps.currentSection = "explore";
|
||||
Metamaps.GlobalUI.Search.isOpen = true;
|
||||
Metamaps.GlobalUI.Search.lock();
|
||||
</script>
|
5
bin/delayed_job
Executable file
5
bin/delayed_job
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
|
||||
require 'delayed/command'
|
||||
Delayed::Command.new(ARGV).daemonize
|
|
@ -11,6 +11,7 @@ Dotenv.load ".env.#{ENV["RAILS_ENV"]}", '.env'
|
|||
|
||||
module Metamaps
|
||||
class Application < Rails::Application
|
||||
config.active_job.queue_adapter = :delayed_job
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
|
@ -54,5 +55,8 @@ module Metamaps
|
|||
g.test_framework :rspec
|
||||
end
|
||||
config.active_record.raise_in_transactional_callbacks = true
|
||||
|
||||
# pundit errors return 403 FORBIDDEN
|
||||
config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,16 @@ Metamaps::Application.routes.draw do
|
|||
get 'search/mappers', to: 'main#searchmappers', as: :searchmappers
|
||||
get 'search/synapses', to: 'main#searchsynapses', as: :searchsynapses
|
||||
|
||||
namespace :api, path: '/api/v1', defaults: {format: :json} do
|
||||
resources :maps, only: [:create, :show, :update, :destroy]
|
||||
resources :synapses, only: [:create, :show, :update, :destroy]
|
||||
resources :topics, only: [:create, :show, :update, :destroy]
|
||||
resources :mappings, only: [:create, :show, :update, :destroy]
|
||||
resources :tokens, only: [ :create, :destroy] do
|
||||
get :my_tokens, on: :collection
|
||||
end
|
||||
end
|
||||
|
||||
resources :messages, only: [:show, :create, :update, :destroy]
|
||||
resources :mappings, except: [:index, :new, :edit]
|
||||
resources :metacode_sets, :except => [:show]
|
||||
|
@ -21,11 +31,12 @@ Metamaps::Application.routes.draw do
|
|||
get 'topics/:id/relative_numbers', to: 'topics#relative_numbers', as: :relative_numbers
|
||||
get 'topics/:id/relatives', to: 'topics#relatives', as: :relatives
|
||||
|
||||
get 'explore/active', to: 'maps#index', as: :activemaps
|
||||
get 'explore/featured', to: 'maps#index', as: :featuredmaps
|
||||
get 'explore/mine', to: 'maps#index', as: :mymaps
|
||||
get 'explore/mapper/:id', to: 'maps#index', as: :usermaps
|
||||
resources :maps, except: [:new, :edit]
|
||||
resources :maps, except: [:index, :new, :edit]
|
||||
get 'explore/active', to: 'maps#activemaps'
|
||||
get 'explore/featured', to: 'maps#featuredmaps'
|
||||
get 'explore/mine', to: 'maps#mymaps'
|
||||
get 'explore/mapper/:id', to: 'maps#usermaps'
|
||||
|
||||
get 'maps/:id/contains', to: 'maps#contains', as: :contains
|
||||
post 'maps/:id/upload_screenshot', to: 'maps#screenshot', as: :screenshot
|
||||
|
||||
|
|
11
db/migrate/20160310200131_create_tokens.rb
Normal file
11
db/migrate/20160310200131_create_tokens.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
class CreateTokens < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :tokens do |t|
|
||||
t.string :token
|
||||
t.string :description
|
||||
t.references :user, index: true, foreign_key: true
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
end
|
13
db/migrate/20160312234946_create_events.rb
Normal file
13
db/migrate/20160312234946_create_events.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
class CreateEvents < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :events do |t|
|
||||
t.string :kind, limit: 255
|
||||
t.references :eventable, polymorphic: true, index: true
|
||||
t.references :user, index: true
|
||||
t.references :map, index: true
|
||||
t.integer :sequence_id, index: true, default: nil, null: true
|
||||
t.timestamps
|
||||
end
|
||||
add_index :events, [:map_id, :sequence_id], unique: true
|
||||
end
|
||||
end
|
10
db/migrate/20160312235006_create_webhooks.rb
Normal file
10
db/migrate/20160312235006_create_webhooks.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class CreateWebhooks < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :webhooks do |t|
|
||||
t.references :hookable, polymorphic: true, index: true
|
||||
t.string :kind, null: false
|
||||
t.string :uri, null: false
|
||||
t.text :event_types, array: true, default: []
|
||||
end
|
||||
end
|
||||
end
|
22
db/migrate/20160313003721_create_delayed_jobs.rb
Normal file
22
db/migrate/20160313003721_create_delayed_jobs.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
class CreateDelayedJobs < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :delayed_jobs, force: true do |table|
|
||||
table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
|
||||
table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
|
||||
table.text :handler, null: false # YAML-encoded string of the object that will do work
|
||||
table.text :last_error # reason for last failure (See Note below)
|
||||
table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
|
||||
table.datetime :locked_at # Set when a client is working on this object
|
||||
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
|
||||
table.string :locked_by # Who is working on this object (if locked)
|
||||
table.string :queue # The name of the queue this job is in
|
||||
table.timestamps null: true
|
||||
end
|
||||
|
||||
add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :delayed_jobs
|
||||
end
|
||||
end
|
56
db/schema.rb
56
db/schema.rb
|
@ -11,11 +11,44 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160223061711) do
|
||||
ActiveRecord::Schema.define(version: 20160313003721) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "delayed_jobs", force: :cascade do |t|
|
||||
t.integer "priority", default: 0, null: false
|
||||
t.integer "attempts", default: 0, null: false
|
||||
t.text "handler", null: false
|
||||
t.text "last_error"
|
||||
t.datetime "run_at"
|
||||
t.datetime "locked_at"
|
||||
t.datetime "failed_at"
|
||||
t.string "locked_by"
|
||||
t.string "queue"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
|
||||
|
||||
create_table "events", force: :cascade do |t|
|
||||
t.string "kind", limit: 255
|
||||
t.integer "eventable_id"
|
||||
t.string "eventable_type"
|
||||
t.integer "user_id"
|
||||
t.integer "map_id"
|
||||
t.integer "sequence_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id", using: :btree
|
||||
add_index "events", ["map_id", "sequence_id"], name: "index_events_on_map_id_and_sequence_id", unique: true, using: :btree
|
||||
add_index "events", ["map_id"], name: "index_events_on_map_id", using: :btree
|
||||
add_index "events", ["sequence_id"], name: "index_events_on_sequence_id", using: :btree
|
||||
add_index "events", ["user_id"], name: "index_events_on_user_id", using: :btree
|
||||
|
||||
create_table "in_metacode_sets", force: :cascade do |t|
|
||||
t.integer "metacode_id"
|
||||
t.integer "metacode_set_id"
|
||||
|
@ -117,6 +150,16 @@ ActiveRecord::Schema.define(version: 20160223061711) do
|
|||
add_index "synapses", ["node2_id"], name: "index_synapses_on_node2_id", using: :btree
|
||||
add_index "synapses", ["user_id"], name: "index_synapses_on_user_id", using: :btree
|
||||
|
||||
create_table "tokens", force: :cascade do |t|
|
||||
t.string "token"
|
||||
t.string "description"
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "tokens", ["user_id"], name: "index_tokens_on_user_id", using: :btree
|
||||
|
||||
create_table "topics", force: :cascade do |t|
|
||||
t.text "name"
|
||||
t.text "desc"
|
||||
|
@ -171,4 +214,15 @@ ActiveRecord::Schema.define(version: 20160223061711) do
|
|||
|
||||
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
|
||||
|
||||
create_table "webhooks", force: :cascade do |t|
|
||||
t.integer "hookable_id"
|
||||
t.string "hookable_type"
|
||||
t.string "kind", null: false
|
||||
t.string "uri", null: false
|
||||
t.text "event_types", default: [], array: true
|
||||
end
|
||||
|
||||
add_index "webhooks", ["hookable_type", "hookable_id"], name: "index_webhooks_on_hookable_type_and_hookable_id", using: :btree
|
||||
|
||||
add_foreign_key "tokens", "users"
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ RSpec.describe MapsController, type: :controller do
|
|||
|
||||
describe 'GET #index' do
|
||||
it 'viewable maps as @maps' do
|
||||
get :index, {}
|
||||
get :activemaps
|
||||
expect(assigns(:maps)).to eq([map])
|
||||
end
|
||||
end
|
||||
|
|
10
spec/models/token_spec.rb
Normal file
10
spec/models/token_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Token, type: :model do
|
||||
context "#generate_token" do
|
||||
subject (:token) { Token.new }
|
||||
it "should generate an alphanumeric token of 32 characters" do
|
||||
expect(token.send(:generate_token)).to match /^[a-zA-Z0-9]{32}$/
|
||||
end
|
||||
end
|
||||
end
|
97
spec/policies/map_policy_spec.rb
Normal file
97
spec/policies/map_policy_spec.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe MapPolicy, type: :policy do
|
||||
subject { described_class }
|
||||
|
||||
context 'unauthenticated' do
|
||||
context 'commons' do
|
||||
let(:map) { create(:map, permission: :commons) }
|
||||
permissions :show? do
|
||||
it 'can view' do
|
||||
expect(subject).to permit(nil, map)
|
||||
end
|
||||
end
|
||||
permissions :create?, :update?, :destroy? do
|
||||
it 'can not modify' do
|
||||
expect(subject).to_not permit(nil, map)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'private' do
|
||||
let(:map) { create(:map, permission: :private) }
|
||||
permissions :show?, :create?, :update?, :destroy? do
|
||||
it 'can not view or modify' do
|
||||
expect(subject).to_not permit(nil, map)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Now begin the logged-in tests
|
||||
#
|
||||
|
||||
context 'logged in' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'commons' do
|
||||
let(:owner) { create(:user) }
|
||||
let(:map) { create(:map, permission: :commons, user: owner) }
|
||||
permissions :show?, :create?, :update? do
|
||||
it 'can view and modify' do
|
||||
expect(subject).to permit(user, map)
|
||||
end
|
||||
end
|
||||
permissions :destroy? do
|
||||
it 'can not destroy' do
|
||||
expect(subject).to_not permit(user, map)
|
||||
end
|
||||
it 'owner can destroy' do
|
||||
expect(subject).to permit(owner, map)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'public' do
|
||||
let(:owner) { create(:user) }
|
||||
let(:map) { create(:map, permission: :public, user: owner) }
|
||||
permissions :show? do
|
||||
it 'can view' do
|
||||
expect(subject).to permit(user, map)
|
||||
end
|
||||
end
|
||||
permissions :create? do
|
||||
it 'can create' do
|
||||
expect(subject).to permit(user, map)
|
||||
end
|
||||
end
|
||||
permissions :update?, :destroy? do
|
||||
it 'can not update/destroy' do
|
||||
expect(subject).to_not permit(user, map)
|
||||
end
|
||||
it 'owner can update/destroy' do
|
||||
expect(subject).to permit(owner, map)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'private' do
|
||||
let(:owner) { create(:user) }
|
||||
let(:map) { create(:map, permission: :private, user: owner) }
|
||||
permissions :create? do
|
||||
it 'can create' do
|
||||
expect(subject).to permit(user, map)
|
||||
end
|
||||
end
|
||||
permissions :show?, :update?, :destroy? do
|
||||
it 'can not view or modify' do
|
||||
expect(subject).to_not permit(user, map)
|
||||
end
|
||||
it 'owner can view and modify' do
|
||||
expect(subject).to permit(owner, map)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,6 @@
|
|||
require 'simplecov'
|
||||
require 'support/controller_helpers'
|
||||
require 'pundit/rspec'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.expect_with :rspec do |expectations|
|
||||
|
|
Loading…
Reference in a new issue