graph_starter 0.15.6 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 846d2b3c24ae439f3e2431a4cfc1662fdf320f47
4
- data.tar.gz: 7d0bb849a37a60e4c77f5318288ee82282fecc5e
3
+ metadata.gz: 62e9a2ebc655144abef8886b72a43477b9c93ec5
4
+ data.tar.gz: 9e40816fa0f5026366513ed85a34932595c9afc5
5
5
  SHA512:
6
- metadata.gz: 1f27817808730ca4c850a96bd5551d843b9fadb1be1d2c76de88dccce7e09da1701d6aa6c891e30aa631fd426a84418a3373bade7fe92481630ee73d31984de9
7
- data.tar.gz: f58a50e1a8dd9b1749c76123d71c647db8c33d3f1fb6b69de20ed6f80dad8ebe875aa38b6729f1dc79e773b8b638075c0bcfc0a9286799114f87ddc5b3d66b1e
6
+ metadata.gz: 021ca13a9adbd7dab7651a9b2a3aebc75ff7e29284f505f620a1b58ad57cd44698008b32a98737e2a8efe7f46505f1fbb003d08bc70d152d89a0e7eb7acd97fa
7
+ data.tar.gz: 4d2a06c175bd8e901479b301b0618bed55bc23fc07025d911aa9ecec57a571dff25dd271a40a831ef209fd9ebb1ff2b884af74e4596ba80156ee3d515e16f0a4
@@ -29,6 +29,13 @@ ready = ->
29
29
  $('.message > .close').on 'click', ->
30
30
  $(@).closest('.message').transition('fade')
31
31
 
32
+
33
+ # Make sure page is in the right place when an anchor is clicked
34
+ # See: https://github.com/twbs/bootstrap/issues/1768
35
+ shiftWindow = -> scrollBy(0, -50)
36
+ shiftWindow() if location.hash
37
+ window.addEventListener('hashchange', shiftWindow)
38
+
32
39
  $(document).ready ready
33
40
  $(document).on 'page:load', ready
34
41
 
@@ -6,6 +6,7 @@ module GraphStarter
6
6
  def index
7
7
  @all_assets = asset_set(:asset, nil)
8
8
  @assets = asset_set.to_a
9
+ @title = model_class.name.tableize.humanize
9
10
 
10
11
  @category_images = Asset.where(id: @assets.map(&:categories).flatten.map(&:id))
11
12
  .query_as(:asset)
@@ -38,15 +39,22 @@ module GraphStarter
38
39
  render json: {results: results_data}.to_json
39
40
  end
40
41
 
41
- def show
42
+ def require_model_class
42
43
  # For cases where the route picked up more than it should have and we try to constantize something wrong
43
44
  begin
44
45
  model_class
45
46
  rescue NameError
46
- return render text: 'Not found', status: :not_found
47
+ render text: 'Not found', status: :not_found
48
+ false
47
49
  end
48
50
 
51
+ end
52
+
53
+ def show
54
+ return if !require_model_class
55
+
49
56
  @asset = asset
57
+ @title = @asset.title
50
58
 
51
59
  if @asset
52
60
  View.record_view(@session_node,
@@ -60,6 +68,7 @@ module GraphStarter
60
68
 
61
69
  def edit
62
70
  @asset, @access_level = asset_with_access_level
71
+ @title = @asset.title.to_s + ' - Edit'
63
72
 
64
73
  render file: 'public/404.html', status: :not_found, layout: false if !@asset
65
74
  end
@@ -68,10 +77,12 @@ module GraphStarter
68
77
  @asset = asset
69
78
  @asset.update(params[params[:model_slug].singularize])
70
79
 
71
- if @asset.class.has_image?
72
- @asset.image = Image.create(source: params[:image])
73
- elsif @asset.class.has_images?
74
- @asset.images << Image.create(source: params[:image])
80
+ if params[:image].present?
81
+ if @asset.class.has_image?
82
+ @asset.image = Image.create(source: params[:image])
83
+ elsif @asset.class.has_images?
84
+ @asset.images << Image.create(source: params[:image])
85
+ end
75
86
  end
76
87
 
77
88
  redirect_to action: :edit
@@ -82,6 +93,8 @@ module GraphStarter
82
93
  end
83
94
 
84
95
  def create
96
+ return if !require_model_class
97
+
85
98
  @asset = model_class.create(params[params[:model_slug].singularize])
86
99
 
87
100
  if @asset.persisted?
@@ -120,6 +133,7 @@ module GraphStarter
120
133
  associations.compact!
121
134
 
122
135
  scope = model_class_scope(var)
136
+ scope = scope.for_category(var, params[:category]) if params[:category].present?
123
137
  scope = yield scope if block_given?
124
138
 
125
139
  scope = scope.limit(limit)
@@ -130,7 +144,7 @@ module GraphStarter
130
144
  end
131
145
 
132
146
  def asset
133
- apply_associations(model_class_scope.where(uuid: params[:id])).to_a[0]
147
+ apply_associations(model_class_scope.as(:asset).where('asset.uuid = {id} OR asset.slug = {id}', id: params[:id])).to_a[0]
134
148
  end
135
149
 
136
150
  def asset_with_access_level
@@ -1,79 +1,21 @@
1
1
  module GraphStarter
2
2
  class CategoriesController < ApplicationController
3
- before_action :set_category, only: [:show, :edit, :update, :destroy]
4
-
5
- # GET /categories
6
- # GET /categories.json
7
- def index
8
- @categories = Category.all
9
- end
10
-
11
- # GET /categories/1
12
- # GET /categories/1.json
13
3
  def show
14
- end
15
-
16
- # GET /categories/new
17
- def new
18
- @category = Category.new
19
- end
20
-
21
- # GET /categories/1/edit
22
- def edit
23
- end
24
-
25
- # POST /categories
26
- # POST /categories.json
27
- def create
28
- @category = Category.new(category_params)
29
-
30
- respond_to do |format|
31
- if @category.save
32
- format.html { redirect_to @category, notice: 'Category was successfully created.' }
33
- format.json { render :show, status: :created, location: @category }
34
- else
35
- format.html { render :new }
36
- format.json { render json: @category.errors, status: :unprocessable_entity }
37
- end
38
- end
39
- end
40
-
41
- # PATCH/PUT /categories/1
42
- # PATCH/PUT /categories/1.json
43
- def update
44
- respond_to do |format|
45
- if @category.update(category_params)
46
- format.html { redirect_to @category, notice: 'Category was successfully updated.' }
47
- format.json { render :show, status: :ok, location: @category }
48
- else
49
- format.html { render :edit }
50
- format.json { render json: @category.errors, status: :unprocessable_entity }
51
- end
52
- end
53
- end
4
+ @category = category
54
5
 
55
- # DELETE /categories/1
56
- # DELETE /categories/1.json
57
- def destroy
58
- @category.destroy
59
- respond_to do |format|
60
- format.html do
61
- redirect_to categories_url, notice: 'Category was successfully destroyed.'
62
- end
63
- format.json { head :no_content }
64
- end
6
+ render json: @category
65
7
  end
66
8
 
67
9
  private
68
10
 
69
11
  # Use callbacks to share common setup or constraints between actions.
70
- def set_category
71
- @category = Category.find(params[:id])
12
+ def category
13
+ Asset.find_by(slug: slug)
72
14
  end
73
15
 
74
16
  # Never trust parameters from the scary internet, only allow the white list through.
75
- def category_params
76
- params[:category]
17
+ def slug
18
+ params.require(:slug)
77
19
  end
78
20
  end
79
21
  end
@@ -1,7 +1,7 @@
1
1
  module GraphStarter
2
2
  module ApplicationHelper
3
3
  def asset_path(asset, options = {})
4
- graph_starter.asset_path({id: asset, model_slug: asset.class.model_slug}.merge(options))
4
+ graph_starter.asset_path({id: asset.slug, model_slug: asset.class.model_slug}.merge(options))
5
5
  end
6
6
 
7
7
  def engine_view(&b)
@@ -3,8 +3,8 @@ module GraphStarter
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- property :private, type: ActiveAttr::Typecasting::Boolean, default: false
7
- validates :private, inclusion: {in: [true, false]}
6
+ property :private, type: ActiveAttr::Typecasting::Boolean, default: nil
7
+ validates :private, inclusion: {in: [true, false, nil]}
8
8
 
9
9
  if GraphStarter.configuration.user_class
10
10
  has_many :in, :allowed_users, rel_class: :'GraphStarter::CanAccess', model_class: GraphStarter.configuration.user_class
@@ -12,30 +12,34 @@ module GraphStarter
12
12
 
13
13
  property :summary
14
14
 
15
-
16
- # This is doing something strange, commenting out for now...
17
- # def self.inherited(subclass)
18
- # subclass.property :slug
19
- # subclass.before_validation :place_slug
20
- # subclass.validates :slug, presence: true
21
- # subclass.constraint :slug, type: :unique
22
- # end
15
+ property :slug
16
+ before_validation :place_slug
17
+ validates :slug, presence: true, uniqueness: true
18
+ constraint :slug, type: :unique
23
19
 
24
20
  def place_slug
25
21
  return if self.slug.present?
26
22
 
27
- name_value = read_attribute(self.class.name_property)
28
- self.slug = self.class.unique_slug_from(name_value)
29
- name_value.to_slug.normalize.to_s if name_value
23
+ self.slug = self.class.unique_slug_from(safe_title)
30
24
  end
31
25
 
32
26
  def self.unique_slug_from(string)
33
- base = string.to_slug.normalize.to_s
27
+ if string.present?
28
+ slug = string.to_slug.normalize.to_s
29
+ while where(slug: slug).count > 0
30
+ if slug.match(/-\d+$/)
31
+ slug.gsub!(/-(\d+)$/) { "-#{$1.to_i + 1}" }
32
+ else
33
+ slug += '-2'
34
+ end
35
+ end
36
+ slug
37
+ end
34
38
  end
35
39
 
36
40
 
37
41
  if GraphStarter.configuration.user_class
38
- #has_many :in, :creators, type: :CREATED, model_class: GraphStarter.configuration.user_class
42
+ has_many :in, :creators, type: :CREATED, model_class: GraphStarter.configuration.user_class
39
43
 
40
44
  has_many :in, :viewer_sessions, rel_class: :'GraphStarter::View', model_class: 'GraphStarter::Session'
41
45
 
@@ -115,6 +119,17 @@ module GraphStarter
115
119
  end
116
120
 
117
121
 
122
+ def self.for_category(node_var, category_slug)
123
+ string = category_associations.map do |association_name|
124
+ association = GraphGist.associations[association_name]
125
+
126
+ "(#{node_var}#{association.arrow_cypher}(:#{association.target_class.mapped_label_name} {slug: {category_slug}}))"
127
+ end.join(' OR ')
128
+
129
+ all.where(string, category_slug: category_slug)
130
+ end
131
+
132
+
118
133
  def self.enumerable_property(property_name, values)
119
134
  fail "values needs to be an Array, was #{values.inspect}" if !values.is_a?(Array)
120
135
 
@@ -219,6 +234,25 @@ module GraphStarter
219
234
  end
220
235
 
221
236
 
237
+ def self.hidden_json_properties(*property_names)
238
+ if property_names.empty?
239
+ @hidden_json_properties || []
240
+ else
241
+ @hidden_json_properties = property_names.map(&:to_sym)
242
+ end
243
+ end
244
+
245
+
246
+ def self.json_methods(*method_names)
247
+ if method_names.empty?
248
+ @json_methods || []
249
+ else
250
+ @json_methods = method_names.map(&:to_sym)
251
+ end
252
+ end
253
+
254
+
255
+
222
256
  def rating_level_for(user)
223
257
  rating = rating_for(user)
224
258
  rating && rating.level
@@ -296,13 +330,19 @@ module GraphStarter
296
330
  id: id,
297
331
  title: title,
298
332
  name: title,
333
+ slug: slug,
299
334
  model_slug: self.class.model_slug,
300
335
  summary: summary,
301
- categories: categories
336
+ categories: categories # DEPRECATED
302
337
  }.tap do |result|
303
338
  result[:image_urls] = image_array.map(&:source_url) if image_array
304
339
  result[:images] = images.map {|image| image.source.url } if self.class.has_images?
305
340
  result[:image] = image.source_url if self.class.has_image? && image
341
+
342
+ self.class.category_associations.each do |association_name|
343
+ result[association_name] = send(association_name)
344
+ result[association_name].uniq! if result[association_name] && result[association_name].respond_to?(:to_a)
345
+ end
306
346
  end
307
347
 
308
348
  options[:root] ? {self.class.model_slug.singularize => data} : data
@@ -336,7 +376,7 @@ module GraphStarter
336
376
  def self.authorized_for(user)
337
377
  require 'graph_starter/query_authorizer'
338
378
 
339
- query, associations = if category_associations.size > 0
379
+ query, var, sec_var = if category_associations.size > 0
340
380
  query = all(:asset).query
341
381
 
342
382
  category_associations
@@ -346,14 +386,14 @@ module GraphStarter
346
386
  query = query.optional_match("(asset)-[:#{relationship_types_cypher}]-(category:Asset)")
347
387
 
348
388
  [query,
349
- [:asset, :category]]
389
+ :asset, [:category]]
350
390
  else
351
391
  [all(:asset),
352
392
  :asset]
353
393
  end
354
394
 
355
395
  ::GraphStarter::QueryAuthorizer.new(query, asset: GraphStarter.configuration.scope_filters[self.name.to_sym])
356
- .authorized_query(associations, user)
396
+ .authorized_query(var, sec_var, user)
357
397
  .with('DISTINCT asset AS asset, level')
358
398
  .break
359
399
  .proxy_as(self, :asset)
@@ -11,8 +11,9 @@
11
11
 
12
12
  .ui.divider
13
13
 
14
- a.ui.labeled.icon.red.button.right.floated href="#{graph_starter.destroy_asset_path(id: asset)}"
15
- i.delete.icon
16
- | Delete
14
+ .ui.buttons
15
+ a.ui.labeled.icon.red.button.right.floated href="#{graph_starter.destroy_asset_path(id: asset)}"
16
+ i.delete.icon
17
+ | Delete
17
18
 
18
19
 
@@ -1,21 +1,22 @@
1
1
  - as_cards = false if !defined?(as_cards)
2
2
 
3
3
  - asset.class.authorized_associations.each do |name, association|
4
- - result = asset.send(name)
5
- - if result.present?
6
- .item
7
- .content
8
- .ui.horizontal.divider = name.to_s.humanize
9
- .description
10
- - if as_cards
11
- .ui.link.cards
12
- - Array(result).each do |object|
13
- = render partial: '/graph_starter/assets/card', locals: {asset: object}
14
- - else
15
- .ui.middle.aligned.big.divided.list
16
- - Array(result).each do |object|
17
- .item
18
- .content
19
- = render partial: '/graph_starter/assets/icon', locals: {asset: object}
20
- = link_to object.title, asset_path(object)
4
+ - if association.target_class.ancestors.include?(GraphStarter::Asset)
5
+ - result = asset.send(name)
6
+ - if result.present?
7
+ .item
8
+ .content
9
+ .ui.horizontal.divider = name.to_s.humanize
10
+ .description
11
+ - if as_cards
12
+ .ui.link.cards
13
+ - Array(result).each do |object|
14
+ = render partial: '/graph_starter/assets/card', locals: {asset: object}
15
+ - else
16
+ .ui.middle.aligned.big.divided.list
17
+ - Array(result).each do |object|
18
+ .item
19
+ .content
20
+ = render partial: '/graph_starter/assets/icon', locals: {asset: object}
21
+ = link_to object.title, asset_path(object)
21
22
 
@@ -7,6 +7,11 @@
7
7
 
8
8
  = file_field_tag 'image'
9
9
 
10
+ .field
11
+ label Summary
12
+
13
+ = f.text_area :summary
14
+
10
15
  - @asset.class.authorized_properties_and_levels(current_user).each do |property, level|
11
16
  .field
12
17
  - editable_properties = GraphStarter.configuration.editable_properties[@asset.class.name.to_sym]
@@ -0,0 +1 @@
1
+ json.array! @assets
@@ -26,6 +26,7 @@ javascript:
26
26
  div class="#{right_width} wide column" id="right-column"
27
27
  - if app_user_is_admin?
28
28
  = render partial: '/graph_starter/assets/admin_buttons', locals: {asset: @asset}
29
+ = render partial: '/graph_starter/assets/extra_admin_buttons', locals: {asset: @asset}
29
30
 
30
31
  - if !asset_presenter.left_sidebar_exists?
31
32
  .ui.items
@@ -1,25 +1,29 @@
1
1
  @asset.class.authorized_properties(current_user).each do |property|
2
+ next if @asset.class.hidden_json_properties.include?(property.name.to_sym)
3
+
2
4
  json.set! property.name, @asset.read_attribute(property.name)
3
5
  end
4
6
 
7
+ @asset.class.json_methods.each do |method_name|
8
+ json.set! method_name, @asset.send(method_name)
9
+ end
10
+
5
11
  json.summary @asset.summary
6
12
 
7
13
  json.image_urls @asset.reload.image_array.map(&:source_url)
8
14
 
9
15
  json.categories @asset.categories
10
16
 
11
- json.associations do
12
- @asset.class.authorized_associations.each do |name, association|
13
- value = case association.type
14
- when :has_many
15
- @asset.send(name).to_a
16
- when :has_one
17
- @asset.send(name)
18
- else
19
- fail "Invalid association: #{association.inspect}"
20
- end
21
-
22
- json.set! name, value
23
- end
17
+ @asset.class.authorized_associations.each do |name, association|
18
+ value = case association.type
19
+ when :has_many
20
+ @asset.send(name).to_a
21
+ when :has_one
22
+ @asset.send(name)
23
+ else
24
+ fail "Invalid association: #{association.inspect}"
25
+ end
26
+
27
+ json.set! name, value
24
28
  end
25
29
 
@@ -5,7 +5,8 @@ doctype html
5
5
  html
6
6
 
7
7
  head
8
- title = @title || Rails.application.class.to_s.split("::").first.tableize.singularize.humanize
8
+ - app_name = Rails.application.class.to_s.split("::").first.tableize.singularize.humanize
9
+ title = @title ? "#{@title} - #{app_name}" : app_name
9
10
  = stylesheet_link_tag 'graph_starter/application', media: 'all', 'data-turbolinks-track' => true
10
11
 
11
12
  = render partial: 'layouts/graph_starter/twitter_meta_tags'
@@ -29,7 +30,7 @@ html
29
30
 
30
31
  = render partial: 'layouts/graph_starter/menu'
31
32
 
32
- #main.ui.container
33
+ #main class="#{@no_ui_container ? '' : 'ui container'}"
33
34
  - if notice.present?
34
35
  p.ui.green.message
35
36
  i.close.icon
@@ -3,7 +3,8 @@ GraphStarter::Engine.routes.draw do
3
3
 
4
4
  root 'assets#home'
5
5
 
6
- resources :categories
6
+ get 'categories/:slug(.:format)' => 'categories#show'
7
+
7
8
  resources :groups do
8
9
  member do
9
10
  get :users_to_add
@@ -12,23 +12,25 @@ module GraphStarter
12
12
  end
13
13
 
14
14
  def authorized_pluck(variable, user)
15
- authorized_query(variable, user).pluck(variable)
15
+ authorized_query(variable, [], user).pluck(variable)
16
16
  end
17
17
 
18
- def authorized_query(variables, user)
19
- variables = Array(variables)
18
+ def authorized_query(variable, secondary_variables, user)
19
+ result_query = query.with(variable, *secondary_variables)
20
20
 
21
- result_query = query.with(*variables)
21
+ result_query = authorized_user_query(result_query, user, variable, secondary_variables)
22
22
 
23
- result_query = authorized_user_query(result_query, user, variables)
23
+ # result_query.print_cypher
24
+ # puts result_query.pluck('*').inspect
25
+
26
+ list_variables = secondary_variables.map { |variable| "#{variable}_list" }
24
27
 
25
28
  # Collapse 2D array of all possible levels into one column of levels
26
29
  result_query
27
- .unwind(level_collection: :level_collections)
30
+ .where_not("'denied' IN level_collection")
28
31
  .unwind(level: :level_collection).break
29
- .with(:level, *variables).where_not(level: nil)
30
- .with('collect(level) AS levels', *variables)
31
- .with("CASE WHEN 'write' IN levels THEN 'write' ELSE 'read' END AS level", *variables)
32
+ .with('collect(level) AS levels', variable, *list_variables)
33
+ .with("CASE WHEN 'write' IN levels THEN 'write' ELSE 'read' END AS level", variable, *list_variables)
32
34
  end
33
35
 
34
36
  private
@@ -56,14 +58,17 @@ module GraphStarter
56
58
  end
57
59
  end
58
60
 
59
- def authorized_user_query(query, user, variables, user_variable = :user)
61
+ def authorized_user_query(query, user, variable, secondary_variables, user_variable = :user)
62
+ variables = [variable] + secondary_variables
60
63
  collect_levels_string = variables.flat_map do |variable|
61
64
  filter = scope_filter(variable)
62
65
 
63
66
  filter_string = filter ? ' AND ' + filter.call(variable) : ''
64
- ["CASE WHEN (user.admin OR #{variable}_created_rel IS NOT NULL) THEN 'write' WHEN NOT(#{variable}.private) #{filter_string} THEN 'read' END",
67
+ secondary = secondary_variables.include?(variable)
68
+ # First lines gives write or read access based on properties of the asset and wether or not user is admin
69
+ ["CASE WHEN (user.admin #{secondary ? nil : "OR #{variable}_created_rel IS NOT NULL"}) THEN 'write' WHEN (#{variable} IS NOT NULL AND (#{secondary ? '' : "#{variable}.private IS NULL OR"} #{variable}.private = false)) #{filter_string} THEN 'read' END",
65
70
  "#{variable}_direct_access_rel.level",
66
- "#{variable}_indirect_can_access_rel.level"]
71
+ (secondary ? nil : "#{variable}_indirect_can_access_rel.level")]
67
72
  end.compact.join(', ')
68
73
 
69
74
  result_query = variables.flat_map { |v| user_authorization_paths(v, user_variable) }
@@ -71,8 +76,8 @@ module GraphStarter
71
76
  result.optional_match(clause).break
72
77
  end.with('*')
73
78
 
74
- result_query
75
- .with("collect([#{collect_levels_string}]) AS level_collections", *variables)
79
+ list_variables = secondary_variables.map { |variable| "collect(#{variable}) AS #{variable}_list" }
80
+ result_query.with("FILTER(i IN REDUCE(a = [], sub_a IN collect([#{collect_levels_string}]) | a + sub_a) WHERE i IS NOT NULL) AS level_collection", variable, *list_variables)
76
81
  end
77
82
 
78
83
  def scope_filter(variable)
@@ -1,3 +1,3 @@
1
1
  module GraphStarter
2
- VERSION = "0.15.6"
2
+ VERSION = "0.16.0"
3
3
  end
@@ -5,14 +5,16 @@ describe 'Asset authorization' do
5
5
 
6
6
  let(:current_user) { nil }
7
7
  let(:asset_attributes) { {} }
8
- let(:asset) { Person.create(asset_attributes) }
8
+ let!(:asset) { create(:person, asset_attributes) }
9
9
 
10
- subject { Person.authorized_for(current_user) }
10
+ let(:category_attributes) { {} }
11
+ let!(:category) { create(:company, category_attributes) }
12
+
13
+ subject { Person.authorized_for(current_user).to_a }
11
14
 
12
15
  it { should include(asset) }
13
16
 
14
- context 'private asset' do
15
- let(:asset_attributes) { {private: true} }
17
+ let_context(asset_attributes: {private: true}) do
16
18
  it { should_not include(asset) }
17
19
 
18
20
  context 'user is logged in' do
@@ -21,8 +23,15 @@ describe 'Asset authorization' do
21
23
 
22
24
  it { should_not include(asset) }
23
25
 
26
+ context 'current_user is the asset creator' do
27
+ before { asset.creators << current_user }
28
+
29
+ it { should include(asset) }
30
+ end
31
+
24
32
  context 'current_user is admin' do
25
33
  let(:current_user_attributes) { {admin: true} }
34
+
26
35
  it { should include(asset) }
27
36
  end
28
37
 
@@ -31,16 +40,134 @@ describe 'Asset authorization' do
31
40
  it { should include(asset) }
32
41
  end
33
42
 
34
- context 'user has access to one of the asset categories' do
35
- let(:category) { Company.create(name: 'Acme Inc. Co.') }
43
+ context 'asset has the category' do
44
+ before { asset.employer = category }
45
+
46
+ it { should_not include(asset) }
47
+
48
+ context 'current_user is admin' do
49
+ let(:current_user_attributes) { {admin: true} }
50
+
51
+ it { should include(asset) }
52
+ end
53
+
54
+ context 'current_user is the category creator' do
55
+ before { category.creators << current_user }
36
56
 
37
- before do
38
- asset.employer = category
39
- category.allowed_users = current_user
57
+ it { should_not include(asset) }
40
58
  end
41
59
 
60
+ context 'current_user has access to the category' do
61
+ before { category.allowed_users = current_user }
62
+
63
+ it { should include(asset) }
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ let_context(asset_attributes: {private: nil}) do
70
+ it { should include(asset) }
71
+
72
+ context 'user is logged in' do
73
+ let(:current_user_attributes) { {} }
74
+ let(:current_user) { User.create(current_user_attributes) }
75
+
76
+ it { should include(asset) }
77
+
78
+ context 'current_user is the asset creator' do
79
+ before { asset.creators << current_user }
80
+
42
81
  it { should include(asset) }
43
82
  end
83
+
84
+ context 'current_user is admin' do
85
+ let(:current_user_attributes) { {admin: true} }
86
+
87
+ it { should include(asset) }
88
+ end
89
+
90
+ context 'user has access to asset' do
91
+ before { asset.allowed_users = current_user }
92
+ it { should include(asset) }
93
+ end
94
+
95
+ context 'asset has the category' do
96
+ before { asset.employer = category }
97
+
98
+ it { should include(asset) }
99
+
100
+ context 'current_user is admin' do
101
+ let(:current_user_attributes) { {admin: true} }
102
+
103
+ it { should include(asset) }
104
+ end
105
+
106
+ context 'current_user is the category creator' do
107
+ before { category.creators << current_user }
108
+
109
+ it { should include(asset) }
110
+ end
111
+
112
+ context 'current_user has access to the category' do
113
+ before { category.allowed_users = current_user }
114
+
115
+ it { should include(asset) }
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ let_context(asset_attributes: {private: false}) do
122
+ it { should include(asset) }
123
+
124
+ context 'user is logged in' do
125
+ let(:current_user_attributes) { {} }
126
+ let(:current_user) { User.create(current_user_attributes) }
127
+
128
+ it { should include(asset) }
129
+
130
+ context 'current_user is the asset creator' do
131
+ before { asset.creators << current_user }
132
+
133
+ it { should include(asset) }
134
+ end
135
+
136
+ context 'current_user is admin' do
137
+ let(:current_user_attributes) { {admin: true} }
138
+
139
+ it { should include(asset) }
140
+ end
141
+
142
+ context 'user has access to asset' do
143
+ before { asset.allowed_users = current_user }
144
+ it { should include(asset) }
145
+ end
146
+
147
+ context 'asset has the category' do
148
+ before { asset.employer = category }
149
+
150
+ it { should include(asset) }
151
+
152
+ context 'current_user is admin' do
153
+ let(:current_user_attributes) { {admin: true} }
154
+
155
+ it { should include(asset) }
156
+ end
157
+
158
+ context 'current_user is the category creator' do
159
+ before { category.creators << current_user }
160
+
161
+ it { should include(asset) }
162
+ end
163
+
164
+ context 'current_user has access to the category' do
165
+ before { category.allowed_users = current_user }
166
+
167
+ it { should include(asset) }
168
+ end
169
+ end
44
170
  end
45
171
  end
172
+
46
173
  end
@@ -1,35 +1,43 @@
1
- # require './spec/rails_helper'
2
- #
3
- # describe 'Asset slugs' do
4
- # class Foo < GraphStarter::Asset
5
- # property :title
6
- #
7
- # name_property :title
8
- # end
9
- #
10
- # before { clear_db }
11
- #
12
- # describe '.unique_slug_from' do
13
- # subject { GraphStarter::Asset.unique_slug_from(string) }
14
- #
15
- # context 'Without assets with slugs' do
16
- # let_context string: 'Test title' do
17
- # it { should eq 'test-title' }
18
- # end
19
- #
20
- # let_context string: 'Gölcük, Turkey Number 2!' do
21
- # it { should eq 'golcuk-turkey-number-2' }
22
- # end
23
- # end
24
- #
25
- # context 'With existing asset slugs' do
26
- # before { Foo.create(title: 'Gölcük, Turkey', slug: 'golcuk-turkey') }
27
- #
28
- # let_context string: 'Gölcük, Turkey!' do
29
- # it { should eq 'golcuk-turkey-2' }
30
- # end
31
- # end
32
- #
33
- # end
34
- # end
1
+ require './spec/rails_helper'
2
+
3
+ describe 'Asset slugs' do
4
+ class Foo < GraphStarter::Asset
5
+ property :title
6
+
7
+ name_property :title
8
+ end
9
+
10
+ before { clear_db }
11
+
12
+ describe '.unique_slug_from' do
13
+ subject { GraphStarter::Asset.unique_slug_from(string) }
14
+
15
+ context 'Without assets with slugs' do
16
+ let_context string: 'Test title' do
17
+ it { should eq 'test-title' }
18
+ end
19
+
20
+ let_context string: 'Gölcük, Turkey Number 2!' do
21
+ it { should eq 'golcuk-turkey-number-2' }
22
+ end
23
+ end
24
+
25
+ context 'With existing asset slug' do
26
+ before { Foo.create(title: 'Gölcük, Turkey', slug: 'golcuk-turkey') }
27
+
28
+ let_context string: 'Gölcük, Turkey!' do
29
+ it { should eq 'golcuk-turkey-2' }
30
+ end
31
+
32
+ context 'With another existing asset slug' do
33
+ before { Foo.create(title: 'Gölcük, Turkey!', slug: 'golcuk-turkey-2') }
34
+
35
+ let_context string: 'Gölcük, Turkey!!' do
36
+ it { should eq 'golcuk-turkey-3' }
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
35
43
 
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :person do
3
+ sequence(:name) { |i| "Person ##{i}" }
4
+ slug { SecureRandom.uuid }
5
+ end
6
+
7
+ factory :company do
8
+ sequence(:name) { |i| "Company ##{i}" }
9
+ slug { SecureRandom.uuid }
10
+ end
11
+ end
@@ -8,11 +8,10 @@ module LetContextHelpers
8
8
  # When a String is specified that becomes the context description
9
9
  # If String isn't specified, Hash#inspect becomes the context description
10
10
  def let_context(*args, &block)
11
- classes = args.map(&:class)
12
11
  context_string, hash =
13
- case classes
12
+ case args.map(&:class)
14
13
  when [String, Hash] then ["#{args[0]} #{args[1]}", args[1]]
15
- when [Hash] then args + args
14
+ when [Hash] then [args[0].inspect, args[0]]
16
15
  end
17
16
 
18
17
  context(context_string) do
@@ -23,6 +22,7 @@ module LetContextHelpers
23
22
  end
24
23
  end
25
24
 
25
+ require 'factory_girl'
26
26
 
27
27
  # This file was generated by the `rails generate rspec:install` command. Conventionally, all
28
28
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
@@ -68,6 +68,8 @@ RSpec.configure do |config|
68
68
 
69
69
  config.extend LetContextHelpers
70
70
 
71
+ config.include FactoryGirl::Syntax::Methods
72
+
71
73
  # The settings below are suggested to provide a good initial experience
72
74
  # with RSpec, but feel free to customize to your heart's content.
73
75
  =begin
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graph_starter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.6
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Underwood
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-10 00:00:00.000000000 Z
11
+ date: 2016-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -195,6 +195,7 @@ files:
195
195
  - app/views/graph_starter/assets/_body.html.slim
196
196
  - app/views/graph_starter/assets/_card.html.slim
197
197
  - app/views/graph_starter/assets/_cards.html.slim
198
+ - app/views/graph_starter/assets/_extra_admin_buttons.html
198
199
  - app/views/graph_starter/assets/_extra_card_content.html.slim
199
200
  - app/views/graph_starter/assets/_form.html.slim
200
201
  - app/views/graph_starter/assets/_icon.html.slim
@@ -205,6 +206,7 @@ files:
205
206
  - app/views/graph_starter/assets/edit.html.slim
206
207
  - app/views/graph_starter/assets/home.html.slim
207
208
  - app/views/graph_starter/assets/index.html.slim
209
+ - app/views/graph_starter/assets/index.json.jbuilder
208
210
  - app/views/graph_starter/assets/new.html.slim
209
211
  - app/views/graph_starter/assets/show.html.slim
210
212
  - app/views/graph_starter/assets/show.json.jbuilder
@@ -276,6 +278,7 @@ files:
276
278
  - spec/dummy/public/422.html
277
279
  - spec/dummy/public/500.html
278
280
  - spec/dummy/public/favicon.ico
281
+ - spec/factories.rb
279
282
  - spec/rails_helper.rb
280
283
  - spec/spec_helper.rb
281
284
  homepage: http://github.com/neo4j-examples/graph_starter
@@ -343,5 +346,6 @@ test_files:
343
346
  - spec/dummy/public/favicon.ico
344
347
  - spec/dummy/Rakefile
345
348
  - spec/dummy/README.rdoc
349
+ - spec/factories.rb
346
350
  - spec/rails_helper.rb
347
351
  - spec/spec_helper.rb