Skip to content

Commit

Permalink
nested namespace is supported now!
Browse files Browse the repository at this point in the history
  • Loading branch information
alphamarket committed May 6, 2017
1 parent 7850ee1 commit be37c86
Show file tree
Hide file tree
Showing 35 changed files with 623 additions and 87 deletions.
33 changes: 17 additions & 16 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ GIT
PATH
remote: .
specs:
rails-acu (2.2.0)
rails-acu (3.0.0)
rails (~> 5.0.0, >= 5.0.0)

GEM
Expand Down Expand Up @@ -72,7 +72,7 @@ GEM
thor (>= 0.14, < 2.0)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.4)
mail (2.6.5)
mime-types (>= 1.16, < 4)
method_source (0.8.2)
mime-types (3.1)
Expand Down Expand Up @@ -115,25 +115,26 @@ GEM
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.0.0)
responders (2.3.0)
railties (>= 4.2.0, < 5.1)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
rspec-core (3.6.0)
rspec-support (~> 3.6.0)
rspec-expectations (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-mocks (3.5.0)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-rails (3.5.2)
rspec-support (~> 3.6.0)
rspec-rails (3.6.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.5.0)
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-support (~> 3.5.0)
rspec-support (3.5.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-support (3.6.0)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ Acu::Rules.define do
}
end
end

# nested namespace (since v3.0.0)
namespace :admin do
namespace :chat do
allow :client
end
end
end
```

Expand All @@ -95,7 +102,7 @@ As we define our rules at the first line, we have to say who are the entities? _
Once we defined our entities we can set their binary access permissions at namespace/controller/action levels using `allow` and `deny` helpers. **that is it, we are done tutorialing; from now on is just tiny details. :)**

> **Scenario:** We have a *public* site which serves to its client's; we have 2 namespaces on this site, one is the _default_ namespace with _home_ controller in it, and the second namespace belongs to the _admin_ of site which has many controllers and also a _contact_ controller.<br />
We want to grant access to everyone for all of _home_ controller actions in _default_ namespace **except** the `some_secret_action1` and `some_secret_action2`; but these `some_secret_action*` can be accessed via the `:admin` and `:client` entities. By default only `:admin` can access to everywhere, but in namespace `admin` we made an exception for 2 actions in the `Admin::ContactController` which everyone can `send_message` to the admin and only clients can ask for `support`. Finally we want to grant access to everyone for _public_ controllers in our 2 namespaces _the default_ and _admin_. <br />
We want to grant access to everyone for all of _home_ controller actions in _default_ namespace **except** the `some_secret_action1` and `some_secret_action2`; but these `some_secret_action*` can be accessed via the `:admin` and `:client` entities. By default only `:admin` can access to everywhere, but in namespace `admin` we made an exception for 2 actions in the `Admin::ContactController` which everyone can `send_message` to the admin and only clients can ask for `support`. Finally we want to grant access to everyone for _public_ controllers in our 2 namespaces _the default_ and _admin_. Also clients can access to everything in namespace _chat_.<br />
If you back trace it in the above example you can easily find this scenario in the rules, plain and simple.

### Gaurding the requests
Expand Down Expand Up @@ -240,6 +247,14 @@ defined in the `Acu::Rules.override` which enables the previously defined rule t
[...]
```

## Change Logs

### v3.0.0
* Nested namespace support

### Before `v3.0.0`
* Core functionalities implemented and stabilized


## Contributing
In order contributing to this project:
Expand Down
28 changes: 18 additions & 10 deletions lib/acu/monitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,24 @@ def gaurd by: { }
{namespace: nil, controller: :namespace, action: :controller}.each do |current, parent|
t = -1
# either mentioned explicitly
if cond[current]
t = (cond[current][:name].to_s == eval("_info.#{current}").to_s) ? 1 : 0
if cond[current] and not cond[current].empty?
# hierarchical match `_info[current]` with `cond[current]` to support nested namespace (since v3.0.0)
cond[current].map { |c| c[:name].to_s }.each.with_index do |c, index|
t = (c == eval("_info.#{current}")[index].to_s) ? 1 : 0
break if t == 0
end
# or in `only|except` tags
elsif parent and cond[parent]
elsif parent and cond[parent] and not cond[parent].empty?
# if nothing mentioned in parent, assume for all
t = 1 if not(cond[parent][:only] or cond[parent][:except])
t = 1 if not cond[parent].map { |c| c[:only] or c[:except] }.all?
# flag true if it checked in namespace's only tag
{only: {on_true: 1, on_false: 0} , except: {on_true: 0, on_false: 1}}.each do |tag, val|
if cond[parent][tag]
case cond[parent][tag].include? eval("_info.#{current}").to_sym
# fetch all `tag` names
tag_list = cond[parent].map { |c| c[tag] }.flatten - [nil]
# if any tag is present?
if not tag_list.empty? and tag_list.any?
# if `current` is mentioned in `tag_list`?
case not (tag_list.map(&:to_s) & eval("_info.#{current}").map(&:to_s)).empty?
when true
t = val[:on_true]
break
Expand Down Expand Up @@ -189,13 +197,13 @@ def process request
p = request[:parameters]
# try find the namespace/controller set
nc = p["controller"].split('/');

n = nc.length > 1 ? nc.first : nil
c = nc.length > 1 ? nc.second : nc.first
# considering multi layer namespaces
n = nc.length > 1 ? nc[0..-2] : nil
c = nc.length > 1 ? nc.last : nc.first
a = p["action"]

# return it with structure
Struct.new(:namespace, :controller, :action).new(n, c, a)
Struct.new(:namespace, :controller, :action).new([n].flatten, [c].flatten, [a].flatten)
end

end # /class << self
Expand Down
12 changes: 8 additions & 4 deletions lib/acu/rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def initialize

def reset
@rules = { }
@_params = { }
@entities = { }
end

Expand All @@ -34,6 +35,7 @@ def namespace *names, except: nil, only: nil
names = [nil] if names.empty?
only = nil if only and not (only.kind_of?(Array) or only.length == 0)
except = nil if except and not (except.kind_of?(Array) or except.length == 0)
raise Errors::AmbiguousRule.new("there is already an `except` or `only` constraints defined in container namespace `#{@_params[:namespace].map { |i| i[:name] }.join('::')}`") if (except or only) and @_params[:namespace] and @_params[:namespace].find { |n| n[:except] or n[:only] }
raise Errors::AmbiguousRule.new('cannot have both `only` and `except` options at the same time for namespace(s) `%s`' %names.join(', ')) if only and except
names.each do |name|
pass namespace: { name: name ? name.downcase : name, except: except, only: only } do
Expand All @@ -48,7 +50,8 @@ def controller *names, except: nil, only: nil
names = [names].flatten if name
only = nil if only and not (only.kind_of?(Array) or only.length == 0)
except = nil if except and not (except.kind_of?(Array) or except.length == 0)
raise Errors::AmbiguousRule.new("there is already an `except` or `only` constraints defined in container namespace `#{@_params[:namespace][:name]}`") if @_params[:namespace] and (@_params[:namespace][:except] || @_params[:namespace][:only])
raise Errors::InvalidSyntax.new("nested controllers are not allowed!") if @_params[:controller] and not @_params[:controller].empty?
raise Errors::AmbiguousRule.new("there is already an `except` or `only` constraints defined in container namespace `#{@_params[:namespace].map { |i| i[:name] }.join('::')}`") if @_params[:namespace] and @_params[:namespace].find { |n| n[:except] or n[:only] }
raise Errors::AmbiguousRule.new('cannot have both `only` and `except` options at the same time for controller(s) `%s`' %names.join(', ')) if only and except
names.each do |name|
pass controller: { name: name.downcase, except: except, only: only } do
Expand All @@ -59,8 +62,9 @@ def controller *names, except: nil, only: nil

def action *names
names = [names].flatten if name
raise Errors::InvalidSyntax.new("nested actions are not allowed!") if @_params[:action] and not @_params[:action].empty?
raise Errors::AmbiguousRule.new("at least one of the parent `controller` or `namespace` needs to be defined for the this action") if not (@_params[:namespace] || @_params[:controller])
raise Errors::AmbiguousRule.new("there is already an `except` or `only` constraints defined in container controller(s) `#{@_params[:controller][:name]}`") if @_params[:controller] and (@_params[:controller][:except] || @_params[:controller][:only])
raise Errors::AmbiguousRule.new("there is already an `except` or `only` constraints defined in container controller(s) `#{@_params[:controller].map { |i| i[:name] }.join('::')}`") if @_params[:controller] and @_params[:controller].find { |n| n[:except] or n[:only] }
names.each do |name|
pass action: { name: name.downcase } do
yield
Expand Down Expand Up @@ -120,8 +124,8 @@ def op *symbol, opr, on
end

def build_rule rule
@rules[@_params.clone] ||= {}
@rules[@_params.clone] = rules[@_params.clone].merge(rule);
@rules[@_params.deep_dup] ||= {}
@rules[@_params.deep_dup] = rules[@_params.clone].merge(rule);
end

def build_rule_entry
Expand Down
6 changes: 5 additions & 1 deletion lib/acu/utilities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ def helper_initialize
end
def pass args = {}
helper_initialize
args.each { |k, v| @_params[k] = v }
args.each do |k, v|
@_params[k] ||= []
@_params[k] << v
@_params[k].flatten
end
yield
args.each { |k, _| @_params.delete k }
end
Expand Down
2 changes: 1 addition & 1 deletion lib/acu/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Acu
VERSION = '2.2.0'
VERSION = '3.0.0'
end
2 changes: 2 additions & 0 deletions spec/dummy/app/assets/javascripts/admin/booking/chats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
2 changes: 2 additions & 0 deletions spec/dummy/app/assets/javascripts/admin/booking/lists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
4 changes: 4 additions & 0 deletions spec/dummy/app/assets/stylesheets/admin/booking/chats.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/
4 changes: 4 additions & 0 deletions spec/dummy/app/assets/stylesheets/admin/booking/lists.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/
58 changes: 58 additions & 0 deletions spec/dummy/app/controllers/admin/booking/chats_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
class Admin::Booking::ChatsController < ApplicationController
before_action :set_admin_booking_chat, only: [:show, :edit, :update, :destroy]

# GET /admin/booking/chats
def index
@admin_booking_chats = Admin::Booking::Chat.all
end

# GET /admin/booking/chats/1
def show
end

# GET /admin/booking/chats/new
def new
@admin_booking_chat = Admin::Booking::Chat.new
end

# GET /admin/booking/chats/1/edit
def edit
end

# POST /admin/booking/chats
def create
@admin_booking_chat = Admin::Booking::Chat.new(admin_booking_chat_params)

if @admin_booking_chat.save
redirect_to @admin_booking_chat, notice: 'Chat was successfully created.'
else
render :new
end
end

# PATCH/PUT /admin/booking/chats/1
def update
if @admin_booking_chat.update(admin_booking_chat_params)
redirect_to @admin_booking_chat, notice: 'Chat was successfully updated.'
else
render :edit
end
end

# DELETE /admin/booking/chats/1
def destroy
@admin_booking_chat.destroy
redirect_to admin_booking_chats_url, notice: 'Chat was successfully destroyed.'
end

private
# Use callbacks to share common setup or constraints between actions.
def set_admin_booking_chat
@admin_booking_chat = Admin::Booking::Chat.find(params[:id])
end

# Only allow a trusted parameter "white list" through.
def admin_booking_chat_params
params.require(:admin_booking_chat).permit(:name)
end
end
9 changes: 9 additions & 0 deletions spec/dummy/app/controllers/admin/booking/lists_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Admin::Booking::ListsController < ApplicationController
# GET /admin/booking/lists
def index
end

# GET /admin/booking/lists/1
def show
end
end
2 changes: 2 additions & 0 deletions spec/dummy/app/helpers/admin/booking/chats_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Admin::Booking::ChatsHelper
end
2 changes: 2 additions & 0 deletions spec/dummy/app/helpers/admin/booking/lists_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Admin::Booking::ListsHelper
end
5 changes: 5 additions & 0 deletions spec/dummy/app/models/admin/booking.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Admin::Booking
def self.table_name_prefix
'admin_booking_'
end
end
2 changes: 2 additions & 0 deletions spec/dummy/app/models/admin/booking/chat.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Admin::Booking::Chat < ApplicationRecord
end
2 changes: 2 additions & 0 deletions spec/dummy/app/models/admin/booking/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Admin::Booking::List < ApplicationRecord
end
22 changes: 22 additions & 0 deletions spec/dummy/app/views/admin/booking/chats/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%= form_for(admin_booking_chat) do |f| %>
<% if admin_booking_chat.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(admin_booking_chat.errors.count, "error") %> prohibited this admin_booking_chat from being saved:</h2>

<ul>
<% admin_booking_chat.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>

<div class="actions">
<%= f.submit %>
</div>
<% end %>
6 changes: 6 additions & 0 deletions spec/dummy/app/views/admin/booking/chats/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>Editing Admin Booking Chat</h1>

<%= render 'form', admin_booking_chat: @admin_booking_chat %>

<%= link_to 'Show', @admin_booking_chat %> |
<%= link_to 'Back', admin_booking_chats_path %>
27 changes: 27 additions & 0 deletions spec/dummy/app/views/admin/booking/chats/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<p id="notice"><%= notice %></p>

<h1>Admin Booking Chats</h1>

<table>
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>

<tbody>
<% @admin_booking_chats.each do |admin_booking_chat| %>
<tr>
<td><%= admin_booking_chat.name %></td>
<td><%= link_to 'Show', admin_booking_chat %></td>
<td><%= link_to 'Edit', edit_admin_booking_chat_path(admin_booking_chat) %></td>
<td><%= link_to 'Destroy', admin_booking_chat, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>

<br>

<%= link_to 'New Admin Booking Chat', new_admin_booking_chat_path %>
5 changes: 5 additions & 0 deletions spec/dummy/app/views/admin/booking/chats/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1>New Admin Booking Chat</h1>

<%= render 'form', admin_booking_chat: @admin_booking_chat %>

<%= link_to 'Back', admin_booking_chats_path %>
9 changes: 9 additions & 0 deletions spec/dummy/app/views/admin/booking/chats/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<p id="notice"><%= notice %></p>

<p>
<strong>Name:</strong>
<%= @admin_booking_chat.name %>
</p>

<%= link_to 'Edit', edit_admin_booking_chat_path(@admin_booking_chat) %> |
<%= link_to 'Back', admin_booking_chats_path %>
Loading

0 comments on commit be37c86

Please sign in to comment.