graph_starter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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