declarative_authorization 0.3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/CHANGELOG +83 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +510 -0
  4. data/Rakefile +43 -0
  5. data/app/controllers/authorization_rules_controller.rb +259 -0
  6. data/app/controllers/authorization_usages_controller.rb +23 -0
  7. data/app/helpers/authorization_rules_helper.rb +187 -0
  8. data/app/views/authorization_rules/_change.erb +58 -0
  9. data/app/views/authorization_rules/_show_graph.erb +37 -0
  10. data/app/views/authorization_rules/_suggestions.erb +48 -0
  11. data/app/views/authorization_rules/change.html.erb +152 -0
  12. data/app/views/authorization_rules/graph.dot.erb +68 -0
  13. data/app/views/authorization_rules/graph.html.erb +40 -0
  14. data/app/views/authorization_rules/index.html.erb +17 -0
  15. data/app/views/authorization_usages/index.html.erb +36 -0
  16. data/authorization_rules.dist.rb +20 -0
  17. data/config/routes.rb +7 -0
  18. data/garlic_example.rb +20 -0
  19. data/init.rb +5 -0
  20. data/lib/declarative_authorization.rb +15 -0
  21. data/lib/declarative_authorization/authorization.rb +634 -0
  22. data/lib/declarative_authorization/development_support/analyzer.rb +252 -0
  23. data/lib/declarative_authorization/development_support/change_analyzer.rb +253 -0
  24. data/lib/declarative_authorization/development_support/change_supporter.rb +620 -0
  25. data/lib/declarative_authorization/development_support/development_support.rb +243 -0
  26. data/lib/declarative_authorization/helper.rb +60 -0
  27. data/lib/declarative_authorization/in_controller.rb +597 -0
  28. data/lib/declarative_authorization/in_model.rb +159 -0
  29. data/lib/declarative_authorization/maintenance.rb +182 -0
  30. data/lib/declarative_authorization/obligation_scope.rb +308 -0
  31. data/lib/declarative_authorization/rails_legacy.rb +14 -0
  32. data/lib/declarative_authorization/reader.rb +441 -0
  33. data/test/authorization_test.rb +827 -0
  34. data/test/controller_filter_resource_access_test.rb +394 -0
  35. data/test/controller_test.rb +386 -0
  36. data/test/dsl_reader_test.rb +157 -0
  37. data/test/helper_test.rb +171 -0
  38. data/test/maintenance_test.rb +46 -0
  39. data/test/model_test.rb +1308 -0
  40. data/test/schema.sql +54 -0
  41. data/test/test_helper.rb +118 -0
  42. metadata +105 -0
@@ -0,0 +1,58 @@
1
+ <form>
2
+ <h2>Which permission to change?</h2>
3
+ <p class="action-options">
4
+ <label>Privilege</label>
5
+ <%= select_tag :privilege, options_for_select(@privileges.map(&:to_s).sort, @privilege.to_s) %>
6
+ <br/>
7
+ <label>On</label>
8
+ <%= select_tag :context, options_for_select(@contexts.map(&:to_s).sort, @context.to_s) %>
9
+ <br/>
10
+ <label></label>
11
+ <%= link_to_function "Show current permissions", "show_current_permissions()", :class => 'unimportant' %>
12
+ <br/><br/>
13
+ How many users should be <strong>affected</strong>?
14
+ <br/>
15
+ <label></label>
16
+ <%= radio_button_tag :affected_users, :few, params[:affected_users] == 'few' %>
17
+ <label class="inline">A <strong>few</strong> users</label>
18
+ <%= radio_button_tag :affected_users, :many, params[:affected_users] == 'many' %>
19
+ <label class="inline"><strong>Many</strong> users</label>
20
+ </p>
21
+
22
+ <h2>Whose permission should be changed?</h2>
23
+ <table class="change-options">
24
+ <thead>
25
+ <tr>
26
+ <td>User</td>
27
+ <td>Current roles</td>
28
+ <td class="choose">?</td>
29
+ <td class="choose">Yes</td>
30
+ <td class="choose">No</td>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <% @users.each do |user| %>
35
+ <tr class="<%= controller.authorization_engine.permit?(@privilege, :context => @context, :user => user, :skip_attribute_test => true) ? 'permitted' : 'not-permitted' %>">
36
+ <td class="user_id"><%=h user.id %></td>
37
+ <td style="font-weight:bold"><%=h user.login %></td>
38
+ <td><%=h user.role_symbols * ', ' %></td>
39
+ <td><%= radio_button_tag "user[#{user.id}][permission]", "undetermined", true %></td>
40
+ <td class="yes"><%= radio_button_tag "user[#{user.id}][permission]", "yes" %></td>
41
+ <td class="no"><%= radio_button_tag "user[#{user.id}][permission]", "no" %></td>
42
+ </tr>
43
+ <% end %>
44
+ <tr>
45
+ <td colspan="5" style="text-align:right; padding-top:0.5em" class="unimportant">
46
+ <span style="background: #FFE599;">&nbsp; &nbsp;</span> Current permission
47
+ </td>
48
+ </tr>
49
+ </tbody>
50
+ </table>
51
+
52
+ <h2 style="display:none">Prohibited actions</h2>
53
+ <ul id="prohibited_actions"></ul>
54
+
55
+ <p class="submit">
56
+ <%= button_to_function "Suggest Changes", "suggest_changes()" %>
57
+ </p>
58
+ </form>
@@ -0,0 +1,37 @@
1
+ <% javascript_tag do %>
2
+ function show_graph (privilege, context, user_ids) {
3
+ var params = {
4
+ privilege_hierarchy: 1,
5
+ highlight_privilege: privilege,
6
+ filter_contexts: context
7
+ };
8
+ if (user_ids)
9
+ params['user_ids[]'] = user_ids;
10
+ show_graph_with_params('graph', params);
11
+ }
12
+
13
+ var graph_params = {};
14
+ function show_graph_with_params (graph_id, params) {
15
+ graph_params[graph_id] = params;
16
+ base_url = "<%= graph_authorization_rules_path('svg') %>";
17
+ $(graph_id).data = base_url + '?' + Object.toQueryString(params);
18
+ $(graph_id).up().show();
19
+ }
20
+
21
+ function update_graph_params (graph_id, params) {
22
+ show_graph_with_params(graph_id,
23
+ $H(graph_params[graph_id] || {}).merge(params).toObject());
24
+ }
25
+
26
+ function toggle_graph_params (graph_id) {
27
+ var opts = {}
28
+ $A(arguments).slice(1).each(function (param) {
29
+ opts[param] = graph_params[graph_id][param] ? null : '1';
30
+ });
31
+ update_graph_params(graph_id, opts)
32
+ }
33
+ <% end %>
34
+ <div id="graph-container" style="display:none">
35
+ <%= link_to_function "Hide", "$('graph-container').hide()", :class => 'important' %><br/>
36
+ <object id="graph" data="" type="image/svg+xml" style="max-width:100%;margin-top: 0.5em"/>
37
+ </div>
@@ -0,0 +1,48 @@
1
+ <h2>Suggestions</h2>
2
+
3
+ <% if @approaches.length > 0 %>
4
+ <% if @approaches.first.changes.empty? %>
5
+ <p>No changes necessary.</p>
6
+ <% else %>
7
+ <p class="unimportant">
8
+ <%= pluralize(@approaches.length, 'approach') %> in
9
+ <%= pluralize(@grouped_approaches.length, 'group') %>
10
+ <%= params[:affected_users] ? "– #{params[:affected_users] == 'few' ? "fewer" : "most"} affected users first" : "" %>
11
+ </p>
12
+ <ul>
13
+ <% @grouped_approaches.each_with_index do |grouped_approach, group_index| %>
14
+ <% ([grouped_approach.approach] + grouped_approach.similar_approaches).each_with_index do |approach, index| %>
15
+ <li <%= (group_index < 3 || params[:show_all]) && index == 0 ? '' : 'style="display: none"' %> class="<%= index == 0 ? 'primary' : "secondary" %> group-<%= group_index %>">
16
+ <!--<span class="ord"><%= (index + 1) %></span>-->
17
+ <span class="unimportant">Affected users</span> <strong><%= affected_users_count(approach) %></strong> &nbsp;
18
+ <span class="unimportant">Complexity</span> <strong><%= approach.weight %></strong> &nbsp;
19
+ <%= link_to_function "Diagram", "show_suggest_graph('#{serialize_changes(approach)}', '#{serialize_relevant_roles(approach)}', '#{@context}', relevant_user_ids())", :class => "show-approach" %>
20
+ <ul>
21
+ <% approach.changes.each do |action| %>
22
+ <% (action.to_a[0].is_a?(Enumerable) ? action.to_a : [action.to_a]).each do |step| %>
23
+ <li>
24
+ <%= describe_step(step.to_a, :with_removal => true) %>
25
+ </li>
26
+ <% end %>
27
+ <% end %>
28
+ </ul>
29
+ <% if index == 0 %>
30
+ <% if grouped_approach.similar_approaches.empty? %>
31
+ <span class="unimportant show-others-in-group">No further suggestions in this group</span>
32
+ <% else %>
33
+ <%= link_to_function "Show further #{pluralize grouped_approach.similar_approaches.length, "suggestion"} in this group", "show_group_approaches(#{group_index})", :class => "show-others-in-group" %>
34
+ <% end %>
35
+ <% end %>
36
+ <%= link_to_function "Hide further suggestions", "hide_group_approaches(#{group_index})" if index > 0 and index == grouped_approach.similar_approaches.length %>
37
+ </li>
38
+ <% if index == 0 and group_index == 2 and @grouped_approaches.length > 3 %>
39
+ <li <%= !params[:show_all] ? '' : 'style="display: none"' %>><%= link_to_function "Show further #{pluralize(@grouped_approaches.length - 3, 'group')}", "show_all_groups(); $(this).up().hide()" %></li>
40
+ <% end %>
41
+ <% end %>
42
+ <% end %>
43
+ </ul>
44
+
45
+ <% end %>
46
+ <% else %>
47
+ <p><strong>No approach found.</strong></p>
48
+ <% end %>
@@ -0,0 +1,152 @@
1
+ <h1>Suggestions on Authorization Rules Change</h1>
2
+ <p><%= navigation %></p>
3
+ <div style="display:none" id="suggest-graph-container">
4
+ <%= link_to_function "Hide", "$(this).up().hide()", :class => 'important' %>
5
+ <%= link_to_function "Toggle stacked roles", "toggle_graph_params('suggest-graph', 'stacked_roles');" %>
6
+ <%= link_to_function "Toggle only users' roles", "toggle_graph_params('suggest-graph', 'only_relevant_roles');" %><br/>
7
+ <object id="suggest-graph" data="" type="image/svg+xml" style="max-width: 98%;max-height: 95%;margin-top: 0.5em"/>
8
+ </div>
9
+ <%= render 'show_graph' %>
10
+
11
+ <style type="text/css">
12
+ .action-options label { display: block; float: left; width: 7em; padding-bottom: 0.5em }
13
+ .action-options label.inline { display: inline; float: none }
14
+ .action-options select { float: left; }
15
+ .action-options br { clear: both; }
16
+ .action-options { margin-bottom: 2em }
17
+ .change-options { margin-bottom: 1em }
18
+ .change-options td.user_id { display: none }
19
+ .change-options td { padding-right: 1em; padding-left: 0.5em }
20
+ .change-options thead td { border-bottom: 1px solid lightgrey }
21
+ .change-options thead td.choose { text-align: center; font-weight: bold }
22
+ .change-options tr.permitted td.yes,
23
+ .change-options tr.not-permitted td.no { background: #FFE599 }
24
+ .submit { margin-top: 0 }
25
+ .submit input { font-weight: bold; font-size: 120% }
26
+ #suggest-result {
27
+ position: absolute; left: 55%; right: 10px;
28
+ border-left: 1px solid grey;
29
+ padding-left: 2em;
30
+ z-index: 10;
31
+ }
32
+ #suggest-result>ul { padding-left: 0 }
33
+ #suggest-result>ul>li { list-style: none; margin-bottom: 1em }
34
+ #suggest-result>ul>li.secondary { padding-left: 2em }
35
+ #suggest-result li { padding-left: 0 }
36
+ #suggest-result ul ul { padding-left: 2em }
37
+ #suggest-result .ord { float: left; display: block; width: 2em; font-weight: bold; color: grey }
38
+ .show-approach, .show-others-in-group { visibility: hidden }
39
+ .prohibit { text-decoration: none; visibility: hidden }
40
+ li:hover .show-approach, li:hover .prohibit,
41
+ li:hover .show-others-in-group { visibility: visible }
42
+ #suggest-graph-container {
43
+ background: white; border:1px solid grey;
44
+ position:fixed; z-index: 20;
45
+ left:10%; bottom: 10%; right: 10%; top: 10%;
46
+ padding: 0.5em
47
+ }
48
+ #graph-container {
49
+ background: white; margin: 1em; border:1px solid grey; padding: 0.5em;
50
+ max-width:50%; position:fixed; z-index: 20; right:0;
51
+ }
52
+ .unimportant, .remove, .prohibit { color: grey }
53
+ .important { font-weight: bold }
54
+ .remove { cursor: pointer }
55
+ </style>
56
+ <% javascript_tag do %>
57
+ function suggest_changes (refresh) {
58
+ if (!refresh)
59
+ $("suggest-result").innerHTML = "Searching...";
60
+ $("suggest-result").show();
61
+ new Ajax.Updater({success: 'suggest-result'}, '<%= suggest_change_authorization_rules_path %>', {
62
+ method: 'get',
63
+ onFailure: function(request) {
64
+ $("suggest-result").innerHTML = "Error while searching."
65
+ },
66
+ parameters: $H($('change').down('form').serialize(true)).merge(refresh ? {show_all: "true"} : {}).toQueryString()
67
+ });
68
+ if (!refresh)
69
+ location.hash = 'suggest-result';
70
+ }
71
+
72
+ function show_suggest_graph (changes, filter_roles_params, filter_context, user_ids) {
73
+ var params = {changes: changes, highlight_privilege: $F('privilege')};
74
+ if (filter_context)
75
+ params['filter_contexts'] = filter_context;
76
+ if (user_ids)
77
+ params['user_ids[]'] = user_ids;
78
+ show_graph_with_params('suggest-graph', params);
79
+ }
80
+
81
+ document.observe('dom:loaded', function() {
82
+ install_change_observers();
83
+ });
84
+
85
+ function install_change_observers () {
86
+ $$('#change select').each(function (el) {
87
+ el.observe('change', function (event) {
88
+ var form = $('change').down('form');
89
+ new Ajax.Updater({success: 'change'}, '<%= url_for %>', {
90
+ parameters: Form.serializeElements(form.select('select').concat(form.getInputs('radio', 'affected_users')), true),
91
+ method: 'get',
92
+ onComplete: function () {
93
+ install_change_observers();
94
+ if ($('graph-container').visible())
95
+ show_current_permissions();
96
+ }
97
+ });
98
+ });
99
+ });
100
+ $('prohibited_actions').observe('click', function (event) {
101
+ var target = event.findElement();
102
+ if (target.hasClassName('remove')) {
103
+ target.up().remove();
104
+ if ($('prohibited_actions').childElements().length == 0)
105
+ $('prohibited_actions').previous().hide();
106
+ suggest_changes();
107
+ }
108
+ });
109
+ }
110
+
111
+ function show_current_permissions () {
112
+ show_graph($F('privilege'), $F('context')/*, relevant_user_ids()*/);
113
+ }
114
+
115
+ function show_all_groups () {
116
+ $$('#suggest-result>ul>li.primary').invoke("show");
117
+ }
118
+
119
+ function show_group_approaches (group_no) {
120
+ $$('#suggest-result>ul>li.secondary.group-' + group_no).invoke("show");
121
+ $$('#suggest-result>ul>li.primary.group-' + group_no + ' a.show-others-in-group').invoke("hide");
122
+ }
123
+
124
+ function hide_group_approaches (group_no) {
125
+ $$('#suggest-result>ul>li.secondary.group-' + group_no).invoke("hide");
126
+ $$('#suggest-result>ul>li.primary.group-' + group_no + ' a.show-others-in-group').invoke("show");
127
+ }
128
+
129
+ function relevant_user_ids () {
130
+ return $$('#change .user_id').collect(function (el) {
131
+ return el.innerHTML;
132
+ }).reject(function (id) {
133
+ return $('user_' + id + '_permission_undetermined').checked;
134
+ });
135
+ }
136
+
137
+ var prohibited_action_template =
138
+ new Template('<li>#{description} <span class="remove">[x]</span><input type="hidden" name="prohibited_action[]" value="#{action}"></li>');
139
+ function prohibit_action (action, description) {
140
+ $('prohibited_actions').previous().show();
141
+ $('prohibited_actions').insert(
142
+ {bottom: prohibited_action_template.evaluate({action: action, description: description}) }
143
+ );
144
+ suggest_changes(true);
145
+ }
146
+ <% end %>
147
+
148
+ <div id="suggest-result" style="display:none"></div>
149
+
150
+ <div id="change">
151
+ <%= render 'change' %>
152
+ </div>
@@ -0,0 +1,68 @@
1
+
2
+ digraph rules {
3
+ compound = true
4
+ edge [arrowhead=open]
5
+ node [shape=box,fontname="sans-serif",fontsize="16"]
6
+ fontname="sans-serif";fontsize="16"
7
+ ranksep = "0.3"
8
+ //concentrate = true
9
+ rankdir = TB
10
+
11
+ <% unless @users.blank? %>
12
+ {
13
+ rank = source
14
+ node [shape=polygon,style=filled,fillcolor="#eeeeee"]
15
+ <% @users.each do |user| %>
16
+ "<%= user.login %>"
17
+ <% end %>
18
+ }
19
+ <% end %>
20
+
21
+ {
22
+ node [shape=ellipse,style=filled]
23
+ <%= @stacked_roles ? '' : "rank = same" %>
24
+ <% @roles.each do |role| %>
25
+ "<%= role.inspect %>" [fillcolor="<%= role_fill_color(role) %>"]
26
+ // ,URL="javascript:set_filter({roles: '<%= role %>'})"
27
+ <% end %>
28
+ <% @roles.each do |role| %>
29
+ <% (@role_hierarchy[role] || []).select {|lower_role| @roles.include?(lower_role)}.each do |lower_role| %>
30
+ "<%= role.inspect %>" -> "<%= lower_role.inspect %>" [arrowhead=empty]
31
+ <% end %>
32
+ <% end %>
33
+ }
34
+
35
+ <% unless @users.blank? %>
36
+ <% @users.each do |user| %>
37
+ <% user.role_symbols.select {|role| @roles.include?(role)}.each do |role| %>
38
+ "<%= user.login %>" -> "<%= role.inspect %>" [color="<%= has_changed(:assign_role_to_user, role, user.login) ? '#00dd00' : (has_changed(:remove_role_from_user, role, user.login) ? '#dd0000' : '#000000') %>"]
39
+ <% end %>
40
+ <% end %>
41
+ <% end %>
42
+
43
+ <% @contexts.each do |context| %>
44
+ subgraph cluster_<%= context %> {
45
+ label = "<%= context.inspect %>"
46
+ style=filled; fillcolor="#eeeeee"
47
+ node[fillcolor=white,style=filled]
48
+ <% (@context_privs[context] || []).each do |priv| %>
49
+ <%= priv %>_<%= context %> [label="<%= priv.inspect %>"<%= ',fontcolor="#ff0000"' if @highlight_privilege == priv %>]
50
+ <% end %>
51
+ <% (@context_privs[context] || []).each do |priv| %>
52
+ <% (@privilege_hierarchy[priv] || []).
53
+ select {|p,c| (c.nil? or c == context) and @context_privs[context].include?(p)}.
54
+ each do |lower_priv, c| %>
55
+ <%= priv %>_<%= context %> -> <%= lower_priv %>_<%= context %> [arrowhead=empty]
56
+ <% end %>
57
+ <% end %>
58
+ //read_conferences -> update_conferences [style=invis]
59
+ //create_conferences -> delete_conferences [style=invis]
60
+ }
61
+ <% end %>
62
+
63
+ <% @roles.each do |role| %>
64
+ <% (@role_privs[role] || []).each do |context, privilege, unconditionally, attribute_string| %>
65
+ "<%= role.inspect %>" -> <%= privilege %>_<%= context %> [color="<%= privilege_color(privilege, context, role) %>", minlen=3<%= ", arrowhead=opendot, URL=\"javascript:\", edgetooltip=\"#{attribute_string.gsub('"','')}\"" unless unconditionally %>]
66
+ <% end %>
67
+ <% end %>
68
+ }
@@ -0,0 +1,40 @@
1
+ <h1>Authorization Rules Graph</h1>
2
+ <p>Currently active rules in this application.</p>
3
+ <p><%= navigation %></p>
4
+
5
+ <% javascript_tag do %>
6
+ function update_graph (form) {
7
+ base_url = "<%= url_for :format => 'svg' %>";
8
+ $('graph').data = base_url + '?' + form.serialize();
9
+ }
10
+
11
+ function set_filter (filter) {
12
+ for (f in filter) {
13
+ var select = $("filter_" + f);
14
+ if (select) {
15
+ var opt = select.down("option[value='"+ filter[f] + "']");
16
+ if (opt) {
17
+ opt.selected = true;
18
+ update_graph(select.form);
19
+ }
20
+ }
21
+ }
22
+ }
23
+ <% end %>
24
+ <p>
25
+ <% form_tag do %>
26
+ <%#= link_to_graph "Rules" %>
27
+ <%#= link_to_graph "Privilege hierarchy", :type => 'priv_hierarchy' %>
28
+
29
+ <%= select_tag "filter_roles", options_for_select([["All roles",'']] + controller.authorization_engine.roles.map(&:to_s).sort), :onchange => 'update_graph(this.form)' %>
30
+ <%= select_tag "filter_contexts", options_for_select([["All contexts",'']] + controller.authorization_engine.auth_rules.collect {|ar| ar.contexts.to_a}.flatten.uniq.map(&:to_s).sort), :onchange => 'update_graph(this.form)' %>
31
+ <%= check_box_tag "effective_role_privs", "1", false, :onclick => 'update_graph(this.form)' %> <%= label_tag "effective_role_privs", "Effective privileges" %>
32
+ <%= check_box_tag "privilege_hierarchy", "1", false, :onclick => 'update_graph(this.form)' %> <%= label_tag "privilege_hierarchy", "Show full privilege hierarchy" %>
33
+ <%= check_box_tag "stacked_roles", "1", false, :onclick => 'update_graph(this.form)' %> <%= label_tag "stacked_roles", "Stacked roles" %>
34
+ <% end %>
35
+ </p>
36
+ <div style="margin: 1em;border:1px solid #ccc;max-width:95%">
37
+ <object id="graph" data="<%= url_for :format => 'svg' %>" type="image/svg+xml" style="max-width:100%"/>
38
+ </div>
39
+ <%= button_to_function "Zoom in", '$("graph").style.maxWidth = "";$(this).toggle();$(this).next().toggle()' %>
40
+ <%= button_to_function "Zoom out", '$("graph").style.maxWidth = "100%";$(this).toggle();$(this).previous().toggle()', :style => 'display:none' %>
@@ -0,0 +1,17 @@
1
+ <h1>Authorization Rules</h1>
2
+ <p>Currently active rules in this application.</p>
3
+ <p><%= navigation %></p>
4
+ <style type="text/css">
5
+ pre .constant {color: #a00;}
6
+ pre .special {color: red;}
7
+ pre .operator {color: red;}
8
+ pre .statement {color: #00a;}
9
+ pre .proc {color: #0a0;}
10
+ pre .privilege, pre .context {font-weight: bold}
11
+ pre .preproc, pre .comment, pre .comment span {color: grey !important;}
12
+ pre .note {color: #a00; position:absolute; cursor: help; left: 15px }
13
+ pre.with-notes {padding-left: 35px}
14
+ </style>
15
+ <pre class="with-notes">
16
+ <%= policy_analysis_hints(syntax_highlight(h(@auth_rules_script)), @auth_rules_script) %>
17
+ </pre>
@@ -0,0 +1,36 @@
1
+ <h1>Authorization Usage</h1>
2
+ <%= render 'authorization_rules/show_graph' %>
3
+ <p>Filter rules in actions by controller:</p>
4
+ <p><%= navigation %></p>
5
+ <style type="text/css">
6
+ .auth-usages th { text-align: left; padding-top: 1em }
7
+ .auth-usages td { padding-right: 1em }
8
+ .auth-usages tr.action { cursor: pointer }
9
+ .auth-usages tr.unprotected { background: #FFA399 }
10
+ .auth-usages tr.no-attribute-check { background: #FFE599 }
11
+ /*.auth-usages tr.catch-all td.privilege,*/
12
+ .auth-usages tr.default-privilege td.privilege,
13
+ .auth-usages tr.default-context td.context { color: #888888 }
14
+ #graph-container {margin: 1em; border:1px solid #ccc; max-width:50%; position:fixed; right:0;}
15
+ </style>
16
+ <table class="auth-usages">
17
+ <% @auth_usages_by_controller.keys.sort {|c1, c2| c1.name <=> c2.name}.each do |controller| %>
18
+ <% default_context = controller.controller_name.to_sym rescue nil %>
19
+ <tr>
20
+ <th colspan="3"><%= h controller.controller_name %></th>
21
+ </tr>
22
+ <% @auth_usages_by_controller[controller].keys.sort {|c1, c2| c1.to_s <=> c2.to_s}.each do |action| %>
23
+ <% auth_info = @auth_usages_by_controller[controller][action] %>
24
+ <% first_permission = auth_info[:controller_permissions] && auth_info[:controller_permissions][0] %>
25
+ <tr class="action <%= auth_usage_info_classes(auth_info) %>" title="<%= auth_usage_info_title(auth_info) %>" onclick="show_graph('<%= auth_info[:privilege] || action %>','<%= auth_info[:context] || default_context %>')">
26
+ <td><%= h action %></td>
27
+ <% if first_permission %>
28
+ <td class="privilege"><%= h auth_info[:privilege] || action %></td>
29
+ <td class="context"><%= h auth_info[:context] || default_context %></td>
30
+ <% else %>
31
+ <td></td><td></td>
32
+ <% end %>
33
+ </tr>
34
+ <% end %>
35
+ <% end %>
36
+ </table>