Merge branch 'feature/pundit' into develop

This commit is contained in:
Connor Turland 2016-03-12 21:26:06 +11:00
commit f58185fd40
30 changed files with 692 additions and 489 deletions

View file

@ -6,7 +6,7 @@ gem 'rails', '4.2.4'
gem 'devise' gem 'devise'
gem 'redis' gem 'redis'
gem 'pg' gem 'pg'
gem 'cancancan' gem 'pundit'
gem 'formula' gem 'formula'
gem 'formtastic' gem 'formtastic'
gem 'json' gem 'json'

View file

@ -56,7 +56,6 @@ GEM
builder (3.2.2) builder (3.2.2)
byebug (5.0.0) byebug (5.0.0)
columnize (= 0.9.0) columnize (= 0.9.0)
cancancan (1.13.1)
climate_control (0.0.3) climate_control (0.0.3)
activesupport (>= 3.0) activesupport (>= 3.0)
cocaine (0.5.7) cocaine (0.5.7)
@ -141,6 +140,8 @@ GEM
pry (~> 0.10) pry (~> 0.10)
pry-rails (0.3.4) pry-rails (0.3.4)
pry (>= 0.9.10) pry (>= 0.9.10)
pundit (1.1.0)
activesupport (>= 3.0.0)
quiet_assets (1.1.0) quiet_assets (1.1.0)
railties (>= 3.1, < 5.0) railties (>= 3.1, < 5.0)
rack (1.6.4) rack (1.6.4)
@ -243,7 +244,6 @@ DEPENDENCIES
best_in_place best_in_place
better_errors better_errors
binding_of_caller binding_of_caller
cancancan
coffee-rails coffee-rails
devise devise
dotenv dotenv
@ -260,6 +260,7 @@ DEPENDENCIES
pg pg
pry-byebug pry-byebug
pry-rails pry-rails
pundit
quiet_assets quiet_assets
rails (= 4.2.4) rails (= 4.2.4)
rails3-jquery-autocomplete rails3-jquery-autocomplete

View file

@ -1,4 +1,7 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
include Pundit
include PunditExtra
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
protect_from_forgery protect_from_forgery
before_action :get_invite_link before_action :get_invite_link
@ -22,6 +25,10 @@ class ApplicationController < ActionController::Base
stored_location_for(resource) || request.referer || root_path stored_location_for(resource) || request.referer || root_path
end end
end end
def handle_unauthorized
head :forbidden # TODO make this better
end
private private

View file

@ -3,20 +3,20 @@ class MainController < ApplicationController
include MapsHelper include MapsHelper
include UsersHelper include UsersHelper
include SynapsesHelper include SynapsesHelper
after_action :verify_policy_scoped
respond_to :html, :json respond_to :html, :json
# home page # home page
def home def home
@current = current_user @maps = policy_scope(Map).order("updated_at DESC").page(1).per(20)
respond_to do |format| respond_to do |format|
format.html { format.html {
if authenticated? if not authenticated?
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(1).per(20) render 'main/home'
respond_with(@maps, @current)
else else
respond_with(@current) render 'maps/activemaps'
end end
} }
end end
@ -59,69 +59,35 @@ class MainController < ApplicationController
filterByMetacode = m filterByMetacode = m
end end
end end
search = '%' + term.downcase + '%'
builder = policy_scope(Topic)
if filterByMetacode if filterByMetacode
if term == "" if term == ""
@topics = [] builder = builder.none
else else
search = term.downcase + '%' builder = builder.where('LOWER("name") like ? OR
LOWER("desc") like ? OR
if user LOWER("link") like ?', search, search, search)
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')) builder = builder.where(metacode_id: filterByMetacode.id)
@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
end end
elsif desc elsif desc
search = '%' + term.downcase + '%' builder = builder.where('LOWER("desc") like ?', search)
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
elsif link elsif link
search = '%' + term.downcase + '%' builder = builder.where('LOWER("link") like ?', search)
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
else #regular case, just search the name else #regular case, just search the name
search = term.downcase + '%' builder = builder.where('LOWER("name") like ? OR
if !user LOWER("desc") like ? OR
@topics = Topic.where('LOWER("name") like ?', search).order('"name"') LOWER("link") like ?', search, search, search)
@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
end end
builder = builder.where(user: user) if user
@topics = builder.order(:name)
else else
@topics = [] @topics = []
end 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) render json: autocomplete_array_json(@topics)
end end
@ -141,21 +107,21 @@ class MainController < ApplicationController
term = term[5..-1] term = term[5..-1]
desc = true desc = true
end end
search = '%' + term.downcase + '%' search = '%' + term.downcase + '%'
query = desc ? 'LOWER("desc") like ?' : 'LOWER("name") like ?' builder = policy_scope(Map)
if !user
# !connor why is the limit 5 done here and not above? also, why not limit after sorting alphabetically? if desc
@maps = Map.where(query, search).limit(5).order('"name"') builder = builder.where('LOWER("desc") like ?', search)
elsif user else
@maps = Map.where(query, search).where('user_id = ?', user).order('"name"') builder = builder.where('LOWER("name") like ?', search)
end end
builder = builder.where(user: user) if user
@maps = builder.order(:name)
else else
@maps = [] @maps = []
end 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) render json: autocomplete_map_array_json(@maps)
end end
@ -166,7 +132,10 @@ class MainController < ApplicationController
#remove "mapper:" if appended at beginning #remove "mapper:" if appended at beginning
term = term[7..-1] if term.downcase[0..6] == "mapper:" 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 else
@mappers = [] @mappers = []
end end
@ -181,7 +150,7 @@ class MainController < ApplicationController
topic2id = params[:topic2id] topic2id = params[:topic2id]
if term && !term.empty? 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 # remove any duplicate synapse types that just differ by
# leading or trailing whitespaces # leading or trailing whitespaces
@ -195,23 +164,18 @@ class MainController < ApplicationController
boolean = true boolean = true
end end
} }
#limit to 5 results
@synapses = @synapses.slice(0,5)
elsif topic1id && !topic1id.empty? elsif topic1id && !topic1id.empty?
@one = Synapse.where('node1_id = ? AND node2_id = ?', topic1id, topic2id) @one = policy_scope(Synapse).where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
@two = Synapse.where('node2_id = ? AND node1_id = ?', topic1id, topic2id) @two = policy_scope(Synapse).where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
@synapses = @one + @two @synapses = @one + @two
@synapses.sort! {|s1,s2| s1.desc <=> s2.desc }.to_a @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 else
@synapses = [] @synapses = []
end end
#limit to 5 results
@synapses = @synapses.slice(0,5)
render json: autocomplete_synapse_array_json(@synapses) render json: autocomplete_synapse_array_json(@synapses)
end end
end end

View file

@ -1,12 +1,15 @@
class MappingsController < ApplicationController class MappingsController < ApplicationController
before_action :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 respond_to :json
# GET /mappings/1.json # GET /mappings/1.json
def show def show
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
authorize @mapping
render json: @mapping render json: @mapping
end end
@ -14,6 +17,8 @@ class MappingsController < ApplicationController
# POST /mappings.json # POST /mappings.json
def create def create
@mapping = Mapping.new(mapping_params) @mapping = Mapping.new(mapping_params)
authorize @mapping
@mapping.user = current_user
if @mapping.save if @mapping.save
render json: @mapping, status: :created render json: @mapping, status: :created
@ -25,6 +30,7 @@ class MappingsController < ApplicationController
# PUT /mappings/1.json # PUT /mappings/1.json
def update def update
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
authorize @mapping
if @mapping.update_attributes(mapping_params) if @mapping.update_attributes(mapping_params)
head :no_content head :no_content
@ -36,7 +42,7 @@ class MappingsController < ApplicationController
# DELETE /mappings/1.json # DELETE /mappings/1.json
def destroy def destroy
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
@map = @mapping.map authorize @mapping
@mapping.destroy @mapping.destroy
@ -46,6 +52,6 @@ class MappingsController < ApplicationController
private private
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def mapping_params 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
end end

View file

@ -1,67 +1,84 @@
class MapsController < ApplicationController class MapsController < ApplicationController
before_action :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 respond_to :html, :json
autocomplete :map, :name, :full => true, :extra_data => [:user_id] autocomplete :map, :name, :full => true, :extra_data => [:user_id]
# GET /explore/active # GET /explore/active
# GET /explore/featured def activemaps
# GET /explore/mapper/:id
def index
return redirect_to activemaps_url if request.path == "/explore"
@current = current_user
@maps = []
page = params[:page].present? ? params[:page] : 1 page = params[:page].present? ? params[:page] : 1
@maps = policy_scope(Map).order("updated_at DESC")
if request.path.index("/explore/active") != nil .page(page).per(20)
@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
respond_to do |format| respond_to do |format|
format.html { format.html {
if @request == "active" && authenticated? # root url => main/home. main/home renders maps/activemaps view.
redirect_to root_url and return redirect_to root_url and return if authenticated?
end respond_with(@maps, @user)
respond_with(@maps, @request, @user)
} }
format.json { render json: @maps } format.json { render json: @maps }
end end
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 # GET maps/:id
def show def show
@map = Map.find(params[:id])
@current = current_user authorize @map
@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
respond_to do |format| respond_to do |format|
format.html { format.html {
@allmappers = @map.contributors @allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } @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.id != s.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| @allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable 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)))
} }
respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @map) respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @map)
@ -72,20 +89,15 @@ class MapsController < ApplicationController
# GET maps/:id/contains # GET maps/:id/contains
def contains def contains
@map = Map.find(params[:id])
@current = current_user authorize @map
@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
@allmappers = @map.contributors @allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } @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.id != s.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| @allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable 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() @json = Hash.new()
@ -121,6 +133,7 @@ class MapsController < ApplicationController
mapping.xloc = topic[1] mapping.xloc = topic[1]
mapping.yloc = topic[2] mapping.yloc = topic[2]
@map.topicmappings << mapping @map.topicmappings << mapping
authorize mapping, :create
mapping.save mapping.save
end end
@ -133,6 +146,7 @@ class MapsController < ApplicationController
mapping.map = @map mapping.map = @map
mapping.mappable = Synapse.find(synapse_id) mapping.mappable = Synapse.find(synapse_id)
@map.synapsemappings << mapping @map.synapsemappings << mapping
authorize mapping, :create
mapping.save mapping.save
end end
end end
@ -140,6 +154,8 @@ class MapsController < ApplicationController
@map.arranged = true @map.arranged = true
end end
authorize @map
if @map.save if @map.save
respond_to do |format| respond_to do |format|
format.json { render :json => @map } format.json { render :json => @map }
@ -153,13 +169,11 @@ class MapsController < ApplicationController
# PUT maps/:id # PUT maps/:id
def update def update
@current = current_user @map = Map.find(params[:id])
@map = Map.find(params[:id]).authorize_to_edit(@current) authorize @map
respond_to do |format| respond_to do |format|
if !@map if @map.update_attributes(map_params)
format.json { render json: "unauthorized" }
elsif @map.update_attributes(map_params)
format.json { head :no_content } format.json { head :no_content }
else else
format.json { render json: @map.errors, status: :unprocessable_entity } format.json { render json: @map.errors, status: :unprocessable_entity }
@ -169,51 +183,42 @@ class MapsController < ApplicationController
# POST maps/:id/upload_screenshot # POST maps/:id/upload_screenshot
def screenshot def screenshot
@current = current_user @map = Map.find(params[:id])
@map = Map.find(params[:id]).authorize_to_edit(@current) authorize @map
if @map png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1]) StringIO.open(png) do |data|
StringIO.open(png) do |data| data.class.class_eval { attr_accessor :original_filename, :content_type }
data.class.class_eval { attr_accessor :original_filename, :content_type } data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png" data.content_type = "image/png"
data.content_type = "image/png" @map.screenshot = data
@map.screenshot = data end
end
if @map.save if @map.save
render :json => {:message => "Successfully uploaded the map screenshot."} render :json => {:message => "Successfully uploaded the map screenshot."}
else else
render :json => {:message => "Failed to upload image."} render :json => {:message => "Failed to upload image."}
end end
else
render :json => {:message => "Unauthorized to set map screenshot."}
end
end end
# DELETE maps/:id # DELETE maps/:id
def destroy 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 do
respond_to do |format| head :no_content
format.json {
if @map
render json: "success"
else
render json: "unauthorized"
end
}
end end
end
end end
private private
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def map_params 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
end end

View file

@ -2,19 +2,16 @@ class SynapsesController < ApplicationController
include TopicsHelper include TopicsHelper
before_action :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 respond_to :json
# GET /synapses/1.json # GET /synapses/1.json
def show def show
@synapse = Synapse.find(params[:id]) @synapse = Synapse.find(params[:id])
authorize @synapse
#.authorize_to_show(@current)
#if not @synapse
# redirect_to root_url and return
#end
render json: @synapse render json: @synapse
end end
@ -23,6 +20,7 @@ class SynapsesController < ApplicationController
def create def create
@synapse = Synapse.new(synapse_params) @synapse = Synapse.new(synapse_params)
@synapse.desc = "" if @synapse.desc.nil? @synapse.desc = "" if @synapse.desc.nil?
authorize @synapse
respond_to do |format| respond_to do |format|
if @synapse.save if @synapse.save
@ -38,6 +36,7 @@ class SynapsesController < ApplicationController
def update def update
@synapse = Synapse.find(params[:id]) @synapse = Synapse.find(params[:id])
@synapse.desc = "" if @synapse.desc.nil? @synapse.desc = "" if @synapse.desc.nil?
authorize @synapse
respond_to do |format| respond_to do |format|
if @synapse.update_attributes(synapse_params) if @synapse.update_attributes(synapse_params)
@ -50,8 +49,9 @@ class SynapsesController < ApplicationController
# DELETE synapses/:id # DELETE synapses/:id
def destroy def destroy
@synapse = Synapse.find(params[:id]).authorize_to_delete(current_user) @synapse = Synapse.find(params[:id])
@synapse.delete if @synapse authorize @synapse
@synapse.delete
respond_to do |format| respond_to do |format|
format.json { head :no_content } format.json { head :no_content }

View file

@ -2,20 +2,15 @@ class TopicsController < ApplicationController
include TopicsHelper include TopicsHelper
before_action :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 respond_to :html, :js, :json
# GET /topics/autocomplete_topic # GET /topics/autocomplete_topic
def autocomplete_topic def autocomplete_topic
@current = current_user
term = params[:term] term = params[:term]
if term && !term.empty? if term && !term.empty?
@topics = Topic.where('LOWER("name") like ?', term.downcase + '%').order('"name"') @topics = policy_scope(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)) }
else else
@topics = [] @topics = []
end end
@ -24,29 +19,16 @@ class TopicsController < ApplicationController
# GET topics/:id # GET topics/:id
def show def show
@current = current_user @topic = Topic.find(params[:id])
@topic = Topic.find(params[:id]).authorize_to_show(@current) authorize @topic
if not @topic
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
respond_to do |format| respond_to do |format|
format.html { 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 @alltopics = ([@topic] + policy_scope(Topic.relatives(@topic.id)))
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) } @allsynapses = policy_scope(Synapse.for_topic(@topic.id))
@allcreators = [] @allcreators = @alltopics.map(&:user).uniq
@alltopics.each do |t| @allcreators += @allsynapses.map(&:user).uniq
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
respond_with(@allsynapses, @alltopics, @allcreators, @topic) respond_with(@allsynapses, @alltopics, @allcreators, @topic)
} }
@ -56,28 +38,15 @@ class TopicsController < ApplicationController
# GET topics/:id/network # GET topics/:id/network
def network def network
@current = current_user @topic = Topic.find(params[:id])
@topic = Topic.find(params[:id]).authorize_to_show(@current) authorize @topic
if not @topic @alltopics = [@topic] + policy_scope(@topic.relatives)
redirect_to root_url, notice: "Access denied. That topic is private." and return @allsynapses = policy_scope(@topic.synapses)
end
@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 = Hash.new()
@json['topic'] = @topic @json['topic'] = @topic
@json['creators'] = @allcreators @json['creators'] = @allcreators
@ -91,121 +60,99 @@ class TopicsController < ApplicationController
# GET topics/:id/relative_numbers # GET topics/:id/relative_numbers
def relative_numbers def relative_numbers
@current = current_user @topic = Topic.find(params[:id])
@topic = Topic.find(params[:id]).authorize_to_show(@current) authorize @topic
if not @topic topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
redirect_to root_url, notice: "Access denied. That topic is private." and return
@alltopics = policy_scope(@topic.relatives).to_a.uniq
@alltopics.delete_if! do |topic|
topicsAlreadyHas.index(topic.id) != nil
end end
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : [] @json = Hash.new(0)
@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()
@alltopics.each do |t| @alltopics.each do |t|
if @json[t.metacode.id] @json[t.metacode.id] += 1
@json[t.metacode.id] += 1
else
@json[t.metacode.id] = 1
end
end end
respond_to do |format| respond_to do |format|
format.json { render json: @json } format.json { render json: @json }
end end
end end
# GET topics/:id/relatives # GET topics/:id/relatives
def relatives def relatives
@current = current_user @topic = Topic.find(params[:id])
@topic = Topic.find(params[:id]).authorize_to_show(@current) authorize @topic
if not @topic topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
@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| #find synapses between topics in alltopics array
@topicsAlreadyHas.index(t.id.to_s) != nil || allsynapses = policy_scope(@topic.synapses)
(params[:metacode] && t.metacode_id.to_s != params[:metacode]) || synapse_ids = (allsynapses.map(&:topic1_id) + allsynapses.map(&:topic2_id)).uniq
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id))) 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| @json = Hash.new()
(s.topic1 == @topic && @alltopics.index(s.topic2) == nil) || @json['topics'] = alltopics
(s.topic2 == @topic && @alltopics.index(s.topic1) == nil) @json['synapses'] = allsynapses
} @json['creators'] = allcreators
@creatorsAlreadyHas = params[:creators] ? params[:creators].split(',') : [] respond_to do |format|
@allcreators = [] format.json { render json: @json }
@alltopics.each do |t| end
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
end end
# POST /topics # POST /topics
# POST /topics.json # POST /topics.json
def create def create
@topic = Topic.new(topic_params) @topic = Topic.new(topic_params)
authorize @topic
respond_to do |format| respond_to do |format|
if @topic.save if @topic.save
format.json { render json: @topic, status: :created } format.json { render json: @topic, status: :created }
else else
format.json { render json: @topic.errors, status: :unprocessable_entity } format.json { render json: @topic.errors, status: :unprocessable_entity }
end end
end
end end
end
# PUT /topics/1 # PUT /topics/1
# PUT /topics/1.json # PUT /topics/1.json
def update def update
@topic = Topic.find(params[:id]) @topic = Topic.find(params[:id])
authorize @topic
respond_to do |format| respond_to do |format|
if @topic.update_attributes(topic_params) if @topic.update_attributes(topic_params)
format.json { head :no_content } format.json { head :no_content }
else else
format.json { render json: @topic.errors, status: :unprocessable_entity } format.json { render json: @topic.errors, status: :unprocessable_entity }
end end
end
end end
end
# DELETE topics/:id # DELETE topics/:id
def destroy def destroy
@current = current_user @topic = Topic.find(params[:id])
@topic = Topic.find(params[:id]).authorize_to_delete(@current) authorize @topic
@topic.delete if @topic
respond_to do |format| @topic.delete
format.json { head :no_content } respond_to do |format|
end format.json { head :no_content }
end end
end
private private

View file

@ -78,36 +78,7 @@ class Map < ActiveRecord::Base
json[:updated_at_clean] = updated_at_str json[:updated_at_clean] = updated_at_str
json json
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) def decode_base64(imgBase64)
decoded_data = Base64.decode64(imgBase64) decoded_data = Base64.decode64(imgBase64)

View file

@ -14,6 +14,10 @@ class Synapse < ActiveRecord::Base
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true } 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: # :nocov:
def user_name def user_name
user.name user.name
@ -32,30 +36,4 @@ class Synapse < ActiveRecord::Base
end end
# :nocov: # :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 end

View file

@ -41,6 +41,13 @@ class Topic < ActiveRecord::Base
belongs_to :metacode 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 def user_name
user.name user.name
end end
@ -87,31 +94,4 @@ class Topic < ActiveRecord::Base
end end
result result
end 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 end

View 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

View 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

View file

@ -0,0 +1,47 @@
class MapPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.where('maps.permission IN (?) OR maps.user_id = ?', ["public", "commons"], user.id)
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

View file

@ -0,0 +1,30 @@
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
scope.joins(:maps).where('maps.permission IN (?) OR maps.user_id = ?',
["public", "commons"], user.id)
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

View file

@ -0,0 +1,24 @@
class SynapsePolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.where('synapses.permission IN (?) OR synapses.user_id = ?', ["public", "commons"], user.id)
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

View file

@ -0,0 +1,39 @@
class TopicPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.where('topics.permission IN (?) OR topics.user_id = ?', ["public", "commons"], user.id)
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

View file

@ -81,7 +81,7 @@
classes += controller_name == "maps" && action_name == "index" ? " explorePage" : "" classes += controller_name == "maps" && action_name == "index" ? " explorePage" : ""
if controller_name == "maps" && action_name == "show" if controller_name == "maps" && action_name == "show"
classes += " mapPage" classes += " mapPage"
if @map.authorize_to_edit(current_user) if policy(@map).update?
classes += " canEditMap" classes += " canEditMap"
end end
if @map.permission == "commons" if @map.permission == "commons"

View file

@ -2,52 +2,42 @@
# @file # @file
# Located at / # Located at /
# Shows 3 most recently created topics, synapses, and maps. # Shows 3 most recently created topics, synapses, and maps.
#%> #
%>
<% if !authenticated? %>
<% content_for :title, "Home | Metamaps" %> <% content_for :title, "Home | Metamaps" %>
<div id="yield"> <div id="yield">
<div class="homeWrapper homeText"> <div class="homeWrapper homeText">
<div class="homeTitle">Make Sense with Metamaps</div> <div class="homeTitle">Make Sense with Metamaps</div>
<div class="homeIntro"> <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> <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> </div>
<div class="fullWidthWrapper withVideo"> <div class="fullWidthWrapper withVideo">
<div class="homeWrapper"> <div class="homeWrapper">
<iframe class="homeVideo" src="//player.vimeo.com/video/113154814" width="560" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <iframe class="homeVideo" src="https://player.vimeo.com/video/113154814" width="560" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
<div class="callToAction"> <div class="callToAction">
<h3>Who finds it useful?</h3> <h3>Who finds it useful?</h3>
<p>Designers, inventors, artists, educators, strategists, consultants, facilitators, entrepreneurs, systems thinkers, changemakers, analysts, students, researchers... maybe you!</p> <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> <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="/explore/featured" class="exploreFeaturedCTA">EXPLORE FEATURED MAPS</a>
<a href="/request" class="requestInviteCTA" data-bypass="true">REQUEST INVITE</a> <a href="/request" class="requestInviteCTA" data-bypass="true">REQUEST INVITE</a>
</div> </div>
<div class="clearfloat"></div> <div class="clearfloat"></div>
</div> </div>
</div> </div>
<div class="fullWidthWrapper withPartners"> <div class="fullWidthWrapper withPartners">
<div class="homeWrapper homePartners"> <div class="homeWrapper homePartners">
<% # our partners %> <% # our partners %>
</div> </div>
</div> </div>
</div><!-- end yield --> </div><!-- end yield -->
<div class="github-fork-ribbon-wrapper right-bottom"> <div class="github-fork-ribbon-wrapper right-bottom">
<div class="github-fork-ribbon"> <div class="github-fork-ribbon">
<a href="https://github.com/metamaps/metamaps_gen002" target="_blank">Fork me on GitHub</a> <a href="https://github.com/metamaps/metamaps_gen002" target="_blank">Fork me on GitHub</a>
</div> </div>
</div> </div>
<script> <script>
Metamaps.currentSection = ""; Metamaps.currentSection = "";
Metamaps.currentPage = ""; Metamaps.currentPage = "";
</script> </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 %>

View file

@ -4,7 +4,7 @@
#%> #%>
<div class="mapInfoBox mapElement mapElementHidden permission <div class="mapInfoBox mapElement mapElementHidden permission
<%= @map && @map.user == user ? " yourMap" : "" %> <%= @map && @map.user == user ? " yourMap" : "" %>
<%= @map && @map.authorize_to_edit(user) ? " canEdit" : "" %> <%= @map && policy(@map).update? ? " canEdit" : "" %>
<%= @map && @map.permission != 'private' ? " shareable" : "" %>"> <%= @map && @map.permission != 'private' ? " shareable" : "" %>">
<% if @map %> <% if @map %>
@ -41,7 +41,7 @@
</div> </div>
<div class="mapInfoDesc" id="mapInfoDesc"> <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' %> <%= best_in_place @map, :desc, :activator => "#mapInfoDesc", :as => :textarea, :placeholder => "Click to add description...", :class => 'best_in_place_desc' %>
<% end %> <% end %>
</div> </div>

View 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>

View 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>

View file

@ -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>

View 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>

View 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>

View file

@ -53,5 +53,8 @@ module Metamaps
g.test_framework :rspec g.test_framework :rspec
end end
config.active_record.raise_in_transactional_callbacks = true config.active_record.raise_in_transactional_callbacks = true
# pundit errors return 403 FORBIDDEN
config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden
end end
end end

View file

@ -20,11 +20,12 @@ Metamaps::Application.routes.draw do
get 'topics/:id/relative_numbers', to: 'topics#relative_numbers', as: :relative_numbers get 'topics/:id/relative_numbers', to: 'topics#relative_numbers', as: :relative_numbers
get 'topics/:id/relatives', to: 'topics#relatives', as: :relatives get 'topics/:id/relatives', to: 'topics#relatives', as: :relatives
get 'explore/active', to: 'maps#index', as: :activemaps resources :maps, except: [:index, :new, :edit]
get 'explore/featured', to: 'maps#index', as: :featuredmaps get 'explore/active', to: 'maps#activemaps'
get 'explore/mine', to: 'maps#index', as: :mymaps get 'explore/featured', to: 'maps#featuredmaps'
get 'explore/mapper/:id', to: 'maps#index', as: :usermaps get 'explore/mine', to: 'maps#mymaps'
resources :maps, except: [:new, :edit] get 'explore/mapper/:id', to: 'maps#usermaps'
get 'maps/:id/contains', to: 'maps#contains', as: :contains get 'maps/:id/contains', to: 'maps#contains', as: :contains
post 'maps/:id/upload_screenshot', to: 'maps#screenshot', as: :screenshot post 'maps/:id/upload_screenshot', to: 'maps#screenshot', as: :screenshot

View file

@ -10,7 +10,7 @@ RSpec.describe MapsController, type: :controller do
describe 'GET #index' do describe 'GET #index' do
it 'viewable maps as @maps' do it 'viewable maps as @maps' do
get :index, {} get :activemaps
expect(assigns(:maps)).to eq([map]) expect(assigns(:maps)).to eq([map])
end end
end end

View 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

View file

@ -1,5 +1,6 @@
require 'simplecov' require 'simplecov'
require 'support/controller_helpers' require 'support/controller_helpers'
require 'pundit/rspec'
RSpec.configure do |config| RSpec.configure do |config|
config.expect_with :rspec do |expectations| config.expect_with :rspec do |expectations|