graph_starter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +38 -0
  5. data/app/assets/images/missing.png +0 -0
  6. data/app/assets/javascripts/graph_starter/application.coffee.erb +25 -0
  7. data/app/assets/javascripts/graph_starter/ember-template-compiler.js +22130 -0
  8. data/app/assets/javascripts/graph_starter/ember.js +52794 -0
  9. data/app/assets/javascripts/graph_starter/ember_apps/permissions_modal.coffee +146 -0
  10. data/app/assets/javascripts/graph_starter/ember_apps/user_list_dropdown.coffee +22 -0
  11. data/app/assets/javascripts/graph_starter/jquery-ui.min.js +7 -0
  12. data/app/assets/javascripts/graph_starter/underscore.js +1548 -0
  13. data/app/assets/stylesheets/graph_starter/application.scss +9 -0
  14. data/app/controllers/graph_starter/application_controller.rb +11 -0
  15. data/app/controllers/graph_starter/assets_controller.rb +76 -0
  16. data/app/controllers/graph_starter/authorizables_controller.rb +47 -0
  17. data/app/controllers/graph_starter/categories_controller.rb +79 -0
  18. data/app/controllers/graph_starter/groups_controller.rb +85 -0
  19. data/app/controllers/graph_starter/models_controller.rb +11 -0
  20. data/app/controllers/graph_starter/properties_controller.rb +11 -0
  21. data/app/helpers/graph_starter/application_helper.rb +11 -0
  22. data/app/models/concerns/graph_starter/authorizable.rb +30 -0
  23. data/app/models/graph_starter/asset.rb +161 -0
  24. data/app/models/graph_starter/can_access.rb +14 -0
  25. data/app/models/graph_starter/category.rb +24 -0
  26. data/app/models/graph_starter/group.rb +36 -0
  27. data/app/models/graph_starter/image.rb +16 -0
  28. data/app/models/graph_starter/model.rb +23 -0
  29. data/app/models/graph_starter/property.rb +19 -0
  30. data/app/models/graph_starter/view.rb +30 -0
  31. data/app/views/graph_starter/assets/TODO.md +7 -0
  32. data/app/views/graph_starter/assets/_cards.html.slim +34 -0
  33. data/app/views/graph_starter/assets/edit.html.slim +24 -0
  34. data/app/views/graph_starter/assets/home.html.slim +1 -0
  35. data/app/views/graph_starter/assets/index.html.slim +28 -0
  36. data/app/views/graph_starter/assets/show.html.slim +98 -0
  37. data/app/views/graph_starter/authorizables/show.json.jbuilder +20 -0
  38. data/app/views/graph_starter/authorizables/user_and_group_search.json.jbuilder +8 -0
  39. data/app/views/graph_starter/categories/show.html.slim +9 -0
  40. data/app/views/graph_starter/groups/_form.html.slim +30 -0
  41. data/app/views/graph_starter/groups/_list.html.slim +19 -0
  42. data/app/views/graph_starter/groups/edit.html.slim +8 -0
  43. data/app/views/graph_starter/groups/index.html.slim +18 -0
  44. data/app/views/graph_starter/groups/index.json.jbuilder +4 -0
  45. data/app/views/graph_starter/groups/new.html.slim +5 -0
  46. data/app/views/graph_starter/groups/show.html.slim +16 -0
  47. data/app/views/graph_starter/groups/show.json.jbuilder +1 -0
  48. data/app/views/graph_starter/models/index.html.slim +10 -0
  49. data/app/views/graph_starter/properties/_property.html.slim +34 -0
  50. data/app/views/layouts/graph_starter/_change_permissions_modal.html.slim +90 -0
  51. data/app/views/layouts/graph_starter/_custom_menu.html.slim +0 -0
  52. data/app/views/layouts/graph_starter/_menu.html.slim +7 -0
  53. data/app/views/layouts/graph_starter/_twitter_meta_tags.html.slim +17 -0
  54. data/app/views/layouts/graph_starter/application.html.slim +45 -0
  55. data/app/views/layouts/graph_starter/custom_menu.html.slim +0 -0
  56. data/config/routes.rb +24 -0
  57. data/lib/graph_starter.rb +4 -0
  58. data/lib/graph_starter/engine.rb +25 -0
  59. data/lib/graph_starter/query_authorizer.rb +81 -0
  60. data/lib/graph_starter/version.rb +3 -0
  61. data/lib/tasks/graph_starter_tasks.rake +4 -0
  62. data/test/dummy/README.rdoc +28 -0
  63. data/test/dummy/Rakefile +6 -0
  64. data/test/dummy/app/assets/javascripts/application.js +13 -0
  65. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  66. data/test/dummy/app/controllers/application_controller.rb +5 -0
  67. data/test/dummy/app/helpers/application_helper.rb +2 -0
  68. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  69. data/test/dummy/bin/bundle +3 -0
  70. data/test/dummy/bin/rails +4 -0
  71. data/test/dummy/bin/rake +4 -0
  72. data/test/dummy/bin/setup +29 -0
  73. data/test/dummy/config.ru +4 -0
  74. data/test/dummy/config/application.rb +26 -0
  75. data/test/dummy/config/boot.rb +5 -0
  76. data/test/dummy/config/database.yml +25 -0
  77. data/test/dummy/config/environment.rb +5 -0
  78. data/test/dummy/config/environments/development.rb +41 -0
  79. data/test/dummy/config/environments/production.rb +79 -0
  80. data/test/dummy/config/environments/test.rb +42 -0
  81. data/test/dummy/config/initializers/assets.rb +11 -0
  82. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  83. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  84. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  85. data/test/dummy/config/initializers/inflections.rb +16 -0
  86. data/test/dummy/config/initializers/mime_types.rb +4 -0
  87. data/test/dummy/config/initializers/session_store.rb +3 -0
  88. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  89. data/test/dummy/config/locales/en.yml +23 -0
  90. data/test/dummy/config/routes.rb +4 -0
  91. data/test/dummy/config/secrets.yml +22 -0
  92. data/test/dummy/public/404.html +67 -0
  93. data/test/dummy/public/422.html +67 -0
  94. data/test/dummy/public/500.html +66 -0
  95. data/test/dummy/public/favicon.ico +0 -0
  96. data/test/graph_starter_test.rb +7 -0
  97. data/test/integration/navigation_test.rb +10 -0
  98. data/test/test_helper.rb +20 -0
  99. metadata +262 -0
@@ -0,0 +1,19 @@
1
+ - groups.each do |group|
2
+ tr
3
+ td style="padding-left: #{indentation * 10}px"
4
+ i.caret.right.icon
5
+ = group.name
6
+ td = link_to action: :new, parent_id: group do
7
+ i.sitemap.large.icon
8
+ | Create Subgroup
9
+ td = link_to group do
10
+ i.unhide.large.icon
11
+ | Show
12
+ td = link_to edit_group_path(group) do
13
+ i.edit.large.icon
14
+ | Edit
15
+ td = link_to group, data: {:confirm => 'Are you sure?'}, :method => :delete do
16
+ i.remove.large.icon
17
+ | Delete
18
+
19
+ = render partial: 'list', locals: {groups: group.sub_groups, indentation: indentation + 1}
@@ -0,0 +1,8 @@
1
+ h1 Editing group
2
+
3
+ == render 'form'
4
+
5
+ = link_to 'Show', @group
6
+ '|
7
+ = link_to 'Back', groups_path
8
+
@@ -0,0 +1,18 @@
1
+ h1 Listing groups
2
+
3
+ table.ui.padded.table
4
+ thead
5
+ tr
6
+ th Name
7
+ th
8
+ th
9
+ th
10
+ th
11
+
12
+ tbody
13
+ = render partial: 'list', locals: {groups: @groups, indentation: 1}
14
+
15
+
16
+ br
17
+
18
+ = link_to 'New Group', new_group_path
@@ -0,0 +1,4 @@
1
+ json.array!(@groups) do |group|
2
+ json.extract! group, :id
3
+ json.url group_url(group, format: :json)
4
+ end
@@ -0,0 +1,5 @@
1
+ h1 New group
2
+
3
+ == render 'form'
4
+
5
+ = link_to 'Back', groups_path
@@ -0,0 +1,16 @@
1
+ p#notice = notice
2
+
3
+ h1 Viewing group:
4
+
5
+ h2 = @group.name
6
+
7
+ h3 Members
8
+
9
+ .ui.segments
10
+ - @group.members.each do |member|
11
+ .ui.segment
12
+ = link_to member.name, member
13
+
14
+ = link_to 'Edit', edit_group_path(@group)
15
+ '|
16
+ = link_to 'Back', groups_path
@@ -0,0 +1 @@
1
+ json.extract! @group, :id, :created_at, :updated_at
@@ -0,0 +1,10 @@
1
+
2
+ .ui.list
3
+ - @models.each do |model|
4
+ .item
5
+ = model.name
6
+ .content
7
+ .list
8
+ = model.authorized_properties(current_user).each do |property|
9
+ i.tag.icon
10
+ = property.name
@@ -0,0 +1,34 @@
1
+ - can_write = (level == 'write') && !form.nil?
2
+
3
+ - ruby_type = property.ruby_type.to_s
4
+ - case ruby_type
5
+ - when 'Integer'
6
+ - if can_write
7
+ = form.number_field property.name
8
+ - else
9
+ = asset.read_attribute(property.name)
10
+ - when 'DateTime', 'Date'
11
+ - if can_write
12
+ i.calendar.icon
13
+ - if ruby_type == 'DateTime'
14
+ i.wait.icon
15
+ - strftime_format = {'DateTime' => '%Y-%m-%d %H:%M', 'Date' => '%Y-%m-%d'}[ruby_type]
16
+
17
+ - id = SecureRandom.uuid
18
+ - value = asset.read_attribute(property.name)
19
+
20
+ = form.text_field property.name, value: value && value.strftime(strftime_format), id: id
21
+
22
+ - js_options = {'DateTime' => "format:'Y-m-d H:i'", 'Date' => "timepicker:false,format:'Y-m-d'"}[ruby_type]
23
+ javascript:
24
+ $(function(){
25
+ $('##{id}').datetimepicker({#{js_options.html_safe}});
26
+ });
27
+ - else
28
+ = asset.read_attribute(property.name)
29
+
30
+ - else
31
+ - if can_write
32
+ = form.text_field property.name
33
+ - else
34
+ = asset.read_attribute(property.name)
@@ -0,0 +1,90 @@
1
+ script type="text/x-handlebars"
2
+ .ui.modal
3
+ i.close.icon
4
+
5
+ .header Change permissions for {{object.name}}
6
+ .image.content
7
+ | {{#if object.image_url}}
8
+ .ui.medium.image
9
+ img src="{{object.image_url}}"
10
+ | {{/if}}
11
+
12
+ .description
13
+
14
+ <div class="ui search {{if searching 'loading' ''}}">
15
+ .ui.icon.input
16
+ | {{input type="text" placeholder="User or group" class="prompt" value=user_and_group_search}}
17
+ i.add.circle.icon
18
+
19
+ <div id="modal-search-results" class="results transition {{if user_and_group_results_present 'visible' ''}}">
20
+ .ui.two.column.grid
21
+ - %w(user group).each do |result_type|
22
+ | {{#if #{result_type}_results.length}}
23
+ .eight.wide.column
24
+ table.ui.celled.striped.table
25
+ tr
26
+ th colspan="3"
27
+ h2
28
+ i class="#{result_type == 'user' ? 'user' : 'users'} icon"
29
+ = result_type.humanize.pluralize
30
+ | {{#each #{result_type}_results as |result|}}
31
+ tr
32
+ td
33
+ | {{result.name}}
34
+ td
35
+ .ui.large.buttons
36
+ <button {{action "add_#{result_type}" result 'read'}} class="ui button green icon">Read</button>
37
+ .or
38
+ <button {{action "add_#{result_type}" result 'write'}} class="ui button red icon">Write</button>
39
+ | {{/each}}
40
+ | {{/if}}
41
+
42
+ </div>
43
+ </div>
44
+
45
+ .inline.field
46
+ .ui.checkbox
47
+ | {{input type="checkbox" name="private" checked=object.private}}
48
+ label Private?
49
+ - %w(user group).each do |entity_type|
50
+ | {{#if #{entity_type}_permissions}}
51
+ .ui.segment.padded
52
+ .ui.form
53
+ .ui.header
54
+ i class="#{entity_type == 'user' ? 'user' : 'users'} icon"
55
+ | #{entity_type.humanize.pluralize} allowed access
56
+ table.ui.definition.table
57
+ | {{#each object.#{entity_type}_permissions as |#{entity_type}_permission|}}
58
+ tr
59
+ td
60
+ label
61
+ | {{#{entity_type}_permission.#{entity_type}.name}}
62
+ td
63
+ .field
64
+ .ui.radio.checkbox
65
+ | {{ radio-button name=#{entity_type}_permission.#{entity_type}.id value='read' groupValue=#{entity_type}_permission.level }}
66
+ label Read
67
+ td
68
+ .field
69
+ .ui.radio.checkbox
70
+ | {{ radio-button name=#{entity_type}_permission.#{entity_type}.id value='write' groupValue=#{entity_type}_permission.level }}
71
+ label Write
72
+ td
73
+ <button {{action "remove_#{entity_type}_permission" #{entity_type}_permission}} class="ui circular red button"><i class="remove user icon"/></button>
74
+ | {{/each}}
75
+
76
+ | {{/if}}
77
+
78
+ <button {{action "update_permissions" target="controller"}} class="ui button positive icon {{if saving 'loading' ''}}"><i class="write icon"/>Update Permissions</button>
79
+
80
+ .actions
81
+ .ui.positive.right.labeled.icon.button.done
82
+ | Done
83
+ i.checkmark.icon
84
+
85
+ scss:
86
+ .ui.search > #modal-search-results {
87
+ width: 600px;
88
+ padding: 1em;
89
+ }
90
+
@@ -0,0 +1,7 @@
1
+ #menu.ui.secondary.pointing.menu
2
+ - GraphStarter::Asset.descendants.each do |model_class|
3
+ - path = graph_starter.assets_path(model_slug: model_class.model_slug)
4
+ = link_to model_class.name.pluralize.humanize, path, class: "item #{'active' if request.path.match(/^#{path}/)}"
5
+
6
+ - engine_view do
7
+ = render 'layouts/graph_starter/custom_menu'
@@ -0,0 +1,17 @@
1
+ meta name="twitter:site" content="@neo4j"
2
+ meta name="twitter:domain" content="http://neo4j.org"
3
+
4
+ - if @asset
5
+ /- if @asset.creators.count > 0
6
+ / - # Is this the right one? Difference between uploader and author
7
+ / meta name="twitter:creator" content="@#{@asset.creators[0].twitter_username}"
8
+
9
+ - if @asset.title
10
+ meta name="twitter:title" content="#{@asset.title}"
11
+
12
+ meta name="twitter:description" content="#{@asset.summary}"
13
+
14
+ - if @asset.class.has_images?
15
+ meta name="twitter:card" content="#{(@asset.first_image_source ? 'summary_large_image' : 'summary')}"
16
+
17
+ meta name="twitter:image:src" content="#{@asset.first_image_source ? @asset.first_image_source.url : '/assets/img/neo4j/neo4j-logo.png'}"
@@ -0,0 +1,45 @@
1
+ doctype html
2
+
3
+ html
4
+
5
+ head
6
+ title AssetPortal
7
+ = stylesheet_link_tag 'graph_starter/application', media: 'all', 'data-turbolinks-track' => true
8
+
9
+ = render partial: 'layouts/graph_starter/twitter_meta_tags'
10
+
11
+ - if defined?(current_user)
12
+ javascript:
13
+ var current_user = #{current_user.to_json.html_safe}.user;
14
+
15
+ = javascript_include_tag 'graph_starter/application', 'data-turbolinks-track' => true
16
+
17
+ - controller = params[:controller].to_sym
18
+
19
+ - if ![:users, :groups].include?(controller)
20
+ = javascript_include_tag 'ember_apps/permissions_modal', 'data-turbolinks-track' => true
21
+
22
+ = csrf_meta_tags
23
+
24
+ body
25
+
26
+ = render partial: 'layouts/graph_starter/menu'
27
+
28
+ - if notice.present?
29
+ p.ui.green.message
30
+ i.close.icon
31
+ = notice
32
+ - if alert.present?
33
+ p.ui.yellow.message
34
+ i.close.icon
35
+ = alert
36
+
37
+ .ui.container
38
+
39
+ = yield
40
+
41
+ - if @current_user_is_admin
42
+ #change-object-permissions
43
+
44
+ - if !request.env['HTTP_X_XHR_REFERER']
45
+ = render partial: 'layouts/graph_starter/change_permissions_modal', locals: {asset: @asset}
@@ -0,0 +1,24 @@
1
+ GraphStarter::Engine.routes.draw do
2
+ resources :groups
3
+ root 'assets#home'
4
+
5
+ resources :categories
6
+ resources :groups do
7
+ member do
8
+ get :users_to_add
9
+ end
10
+ end
11
+
12
+ get 'models' => 'models#index', as: :models
13
+ get 'models/:name' => 'models#show', as: :model
14
+
15
+ get 'authorizables/user_and_group_search.json' => 'authorizables#user_and_group_search'
16
+ get 'authorizables/:model_slug/:id.:format' => 'authorizables#show'
17
+ put 'authorizables/:model_slug/:id.:format' => 'authorizables#update'
18
+
19
+ get ':model_slug' => 'assets#index', as: :assets
20
+ get ':model_slug/:id' => 'assets#show', as: :asset
21
+ get ':model_slug/:id/edit' => 'assets#edit', as: :edit_asset
22
+ get ':model_slug/search/:query.json' => 'assets#search', as: :search_assets
23
+ patch ':model_slug/:id' => 'assets#update'
24
+ end
@@ -0,0 +1,4 @@
1
+ require "graph_starter/engine"
2
+
3
+ module GraphStarter
4
+ end
@@ -0,0 +1,25 @@
1
+ require 'neo4jrb_paperclip'
2
+ require 'semantic-ui-sass'
3
+
4
+ require 'neo4j-core'
5
+ require 'neo4j'
6
+ require 'neo4j/railtie'
7
+ require 'neo4j/rake_tasks'
8
+ require 'slim-rails'
9
+
10
+ module GraphStarter
11
+ class Engine < ::Rails::Engine
12
+ isolate_namespace GraphStarter
13
+
14
+ config.autoload_paths << File.expand_path("../../", __FILE__)
15
+
16
+ config.neo4j._active_record_destroyed_behavior = true
17
+
18
+ config.assets.precompile += %w(
19
+ missing.png
20
+
21
+ ember_apps/permissions_modal.js
22
+ ember_apps/user_list_dropdown.js
23
+ )
24
+ end
25
+ end
@@ -0,0 +1,81 @@
1
+ module GraphStarter
2
+ class QueryAuthorizer
3
+ # Can take:
4
+ # * a Query
5
+ # * a Proxy object
6
+ # * Anything that responds to #query where a `Query` is returned
7
+ def initialize(query_object)
8
+ validate_query_object!(query_object)
9
+
10
+ @query_object = query_object
11
+ end
12
+
13
+ def authorized_pluck(variable, user)
14
+ authorized_query(variable, user).pluck(variable)
15
+ end
16
+
17
+ def authorized_query(variables, user)
18
+ variables = Array(variables)
19
+
20
+ result_query = query.with(*variables)
21
+
22
+ result_query = authorized_user_query(result_query, user, variables)
23
+
24
+ # Collapse 2D array of all possible levels into one column of levels
25
+ result_query
26
+ .unwind(level_collection: :level_collections)
27
+ .unwind(level: :level_collection).break
28
+ .with(:level, *variables).where_not(level: nil)
29
+ .with('collect(level) AS levels', *variables)
30
+ .with("CASE WHEN 'write' IN levels THEN 'write' ELSE 'read' END AS level", *variables)
31
+ end
32
+
33
+ private
34
+
35
+ def validate_query_object!(query_object)
36
+ return if self.class.queryish?(query_object)
37
+
38
+ fail ArgumentError, "Expected query_object to be queryish. Was: #{query_object.inspect}"
39
+ end
40
+
41
+ def self.queryish?(query_object)
42
+ query_object.is_a?(::Neo4j::Core::Query) ||
43
+ # Working around these two classes for new. They should return `true`
44
+ # for `respond_to(:query)`
45
+ query_object.is_a?(::Neo4j::ActiveNode::HasN::AssociationProxy) ||
46
+ query_object.is_a?(::Neo4j::ActiveNode::Query::QueryProxy) ||
47
+ query_object.respond_to?(:query)
48
+ end
49
+
50
+ def query
51
+ if @query_object.is_a?(::Neo4j::Core::Query)
52
+ @query_object
53
+ else
54
+ @query_object.query
55
+ end
56
+ end
57
+
58
+ def authorized_user_query(query, user, variables, user_variable = :user)
59
+ collect_levels_string = variables.flat_map do |variable|
60
+ ["CASE WHEN (user.admin OR #{variable}_created_rel IS NOT NULL) THEN 'write' WHEN NOT(#{variable}.private) THEN 'read' END",
61
+ "#{variable}_direct_access_rel.level",
62
+ "#{variable}_indirect_can_access_rel.level"]
63
+ end.compact.join(', ')
64
+
65
+ result_query = variables.flat_map { |v| user_authorization_paths(v, user_variable) }
66
+ .inject(query.optional_match_nodes(user_variable => user).break) do |result, clause|
67
+ result.optional_match(clause).break
68
+ end.with('*')
69
+
70
+ result_query
71
+ .with("collect([#{collect_levels_string}]) AS level_collections", *variables)
72
+ end
73
+
74
+ def user_authorization_paths(variable, user_variable = :user)
75
+ ["#{variable}<-[#{variable}_created_rel:CREATED]-#{user_variable}",
76
+ "#{variable}<-[#{variable}_direct_access_rel:CAN_ACCESS]-#{user_variable}",
77
+ "#{variable}<-[#{variable}_indirect_can_access_rel:CAN_ACCESS]-(:Group)<-[:HAS_SUBGROUP*0..5]-(:Group)<-[:BELONGS_TO]-#{user_variable}"]
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,3 @@
1
+ module GraphStarter
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :graph_starter do
3
+ # # Task goes here
4
+ # end