graph_starter 0.15.6 → 0.16.0

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.
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