wagn 1.14.1 → 1.14.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.tm_properties +2 -1
  3. data/VERSION +1 -1
  4. data/app/controllers/card_controller.rb +4 -3
  5. data/db/bootstrap/card_acts.yml +1 -1
  6. data/db/bootstrap/cards.yml +1028 -1028
  7. data/db/migrate_core_cards/20140629222005_add_email_cards.rb +2 -25
  8. data/db/migrate_core_cards/20141204061304_watchers_to_following.rb +38 -0
  9. data/db/version_core_cards.txt +1 -1
  10. data/features/history.feature +21 -0
  11. data/features/step_definitions/history_steps.rb +3 -0
  12. data/features/step_definitions/wagn_steps.rb +10 -1
  13. data/lib/card/act.rb +2 -2
  14. data/lib/card/action.rb +9 -9
  15. data/lib/card/diff.rb +370 -211
  16. data/lib/card/exceptions.rb +2 -0
  17. data/lib/card/format.rb +5 -3
  18. data/lib/card/query.rb +4 -4
  19. data/lib/card/query/card_spec.rb +69 -51
  20. data/lib/card/set.rb +3 -2
  21. data/lib/wagn.rb +15 -3
  22. data/lib/wagn/all.rb +1 -3
  23. data/lib/wagn/application.rb +10 -1
  24. data/lib/wagn/generators/wagn/templates/Gemfile +6 -1
  25. data/lib/wagn/log.rb +69 -0
  26. data/lib/wagn/tasks/wagn.rake +1 -1
  27. data/mod/01_core/set/all/collection.rb +8 -5
  28. data/mod/01_core/set/all/content.rb +1 -1
  29. data/mod/01_core/set/all/fetch.rb +34 -32
  30. data/mod/01_core/set/all/notify.rb +2 -2
  31. data/mod/01_core/set/all/phases.rb +5 -0
  32. data/mod/01_core/set/all/trash.rb +1 -1
  33. data/mod/02_basic_types/set/type/pointer.rb +4 -0
  34. data/mod/03_machines/set/type/coffee_script.rb +10 -0
  35. data/mod/03_machines/set/type/css.rb +9 -0
  36. data/mod/03_machines/set/type/java_script.rb +5 -0
  37. data/mod/03_machines/set/type/scss.rb +8 -2
  38. data/mod/05_standard/set/all/history.rb +10 -1
  39. data/mod/05_standard/set/type/html.rb +4 -0
  40. data/mod/05_standard/spec/set/all/base_spec.rb +2 -0
  41. data/mod/05_standard/spec/set/all/history_spec.rb +12 -0
  42. data/mod/06_email/set/all/email_html.rb +0 -4
  43. data/mod/06_email/set/type/email_template.rb +6 -2
  44. data/spec/lib/card/diff_spec.rb +207 -107
  45. data/spec/lib/card/query_spec.rb +14 -13
  46. data/test/fixtures/card_actions.yml +21 -0
  47. data/test/fixtures/card_acts.yml +103 -85
  48. data/test/fixtures/card_changes.yml +53 -23
  49. data/test/fixtures/cards.yml +1349 -1331
  50. data/test/seed.rb +5 -1
  51. metadata +8 -3
  52. data/lib/wagn/config/initializers/airbrake.rb +0 -9
@@ -2,6 +2,7 @@
2
2
 
3
3
  class Card
4
4
  class Error < StandardError #code problem
5
+ cattr_accessor :current
5
6
  end
6
7
 
7
8
  class Oops < Error # wagneer problem (rename!)
@@ -36,4 +37,5 @@ class Card
36
37
  end
37
38
 
38
39
  end
40
+
39
41
  end
@@ -183,7 +183,9 @@ class Card
183
183
  @current_view = view = ok_view canonicalize_view( view ), args
184
184
  args = default_render_args view, args
185
185
  with_inclusion_mode view do
186
- send "_view_#{ view }", args
186
+ Wagn.with_logging card.name, :view, view, args do
187
+ send "_view_#{ view }", args
188
+ end
187
189
  end
188
190
  end
189
191
  rescue => e
@@ -244,9 +246,9 @@ class Card
244
246
  if Rails.env =~ /^cucumber|test$/
245
247
  raise e
246
248
  else
247
- controller.send :notify_airbrake, e if Airbrake.configuration.api_key
248
249
  Rails.logger.info "\nError rendering #{error_cardname} / #{view}: #{e.class} : #{e.message}"
249
- Rails.logger.debug "BT: #{e.backtrace*"\n "}"
250
+ Card::Error.current = e
251
+ card.notable_exception_raised
250
252
  rendering_error e, view
251
253
  end
252
254
  end
@@ -27,6 +27,7 @@ class Card::Query
27
27
  end
28
28
 
29
29
  def run
30
+ # puts "~~~~~~~~~~~~~~\nCARD SPEC =\n#{@card_spec.rawspec}\n\n-----\n\nSQL=\n#{sql}"
30
31
  rows = ActiveRecord::Base.connection.select_all( sql )
31
32
  retrn = query[:return].present? ? query[:return].to_s : 'card'
32
33
  case retrn
@@ -66,10 +67,9 @@ class Card::Query
66
67
  end
67
68
 
68
69
  def to_s
69
- "(
70
- select #{fields.reject(&:blank?).join(', ')} from #{tables} #{joins.join(' ')}
71
- where #{conditions.reject(&:blank?).join(' and ')} #{group} #{order} #{limit} #{offset}
72
- )"
70
+ select = fields.reject(&:blank?) * ', '
71
+ where = conditions.reject(&:blank?) * ' and '
72
+ ['(SELECT', select, 'FROM', tables, joins, 'WHERE', where, group, order, limit, offset, ')'].compact * ' '
73
73
  end
74
74
  end
75
75
 
@@ -17,7 +17,7 @@ class Card
17
17
  CONJUNCTIONS = { :any=>:or, :in=>:or, :or=>:or, :all=>:and, :and=>:and }
18
18
 
19
19
  attr_reader :sql, :query, :rawspec, :selfname
20
- attr_accessor :joins
20
+ attr_accessor :joins, :join_count
21
21
 
22
22
  class << self
23
23
  def build query
@@ -185,7 +185,7 @@ class Card
185
185
  #~~~~~~ RELATIONAL
186
186
 
187
187
  def type val
188
- merge field(:type_id) => id_or_subspec(val)
188
+ restrict :type_id, val
189
189
  end
190
190
 
191
191
  def part val
@@ -193,12 +193,13 @@ class Card
193
193
  subcondition :left=>val, :right=>right, :conj=>:or
194
194
  end
195
195
 
196
+
196
197
  def left val
197
- merge field(:left_id) => id_or_subspec(val)
198
+ restrict :left_id, val
198
199
  end
199
200
 
200
201
  def right val
201
- merge field(:right_id) => id_or_subspec(val)
202
+ restrict :right_id, val
202
203
  end
203
204
 
204
205
  def editor_of val
@@ -210,19 +211,19 @@ class Card
210
211
  end
211
212
 
212
213
  def last_editor_of val
213
- merge field(:id) => subspec(val, :return=>'updater_id')
214
+ restrict_by_join :id, val, :return=>'updater_id'
214
215
  end
215
216
 
216
217
  def last_edited_by val
217
- merge field(:updater_id) => id_or_subspec(val)
218
+ restrict :updater_id, val
218
219
  end
219
220
 
220
221
  def creator_of val
221
- merge field(:id)=>subspec(val,:return=>'creator_id')
222
+ restrict_by_join :id, val, :return=>'creator_id'
222
223
  end
223
224
 
224
225
  def created_by val
225
- merge field(:creator_id) => id_or_subspec(val)
226
+ restrict :creator_id, val
226
227
  end
227
228
 
228
229
  def member_of val
@@ -236,18 +237,21 @@ class Card
236
237
 
237
238
  #~~~~~~ PLUS RELATIONAL
238
239
 
239
- def left_plus(val)
240
- part_spec, junc_spec = val.is_a?(Array) ? val : [ val, {} ]
241
- merge( field(:id) => subspec(junc_spec, :return=>'right_id', :left =>part_spec))
240
+ def left_plus val
241
+ junction :left, val
242
242
  end
243
243
 
244
- def right_plus(val)
245
- part_spec, junc_spec = val.is_a?(Array) ? val : [ val, {} ]
246
- merge( field(:id) => subspec(junc_spec, :return=>'left_id', :right=> part_spec ))
244
+ def right_plus val
245
+ junction :right, val
247
246
  end
248
247
 
249
- def plus(val)
250
- subcondition( { :left_plus=>val, :right_plus=>val.deep_clone }, :conj=>:or )
248
+ def plus val
249
+ any( { :left_plus=>val, :right_plus=>val.deep_clone } )
250
+ end
251
+
252
+ def junction side, val
253
+ part_spec, junction_spec = val.is_a?(Array) ? val : [ val, {} ]
254
+ restrict_by_join :id, junction_spec, side=>part_spec, :return=>"#{ side==:left ? :right : :left}_id"
251
255
  end
252
256
 
253
257
 
@@ -280,23 +284,23 @@ class Card
280
284
  unless c && [SearchTypeID,SetID].include?(c.type_id)
281
285
  raise BadQuery, %{"found_by" value needs to be valid Search, but #{c.name} is a #{c.type_name}}
282
286
  end
283
- found_by_spec = CardSpec.new(c.get_spec).rawspec
284
- merge(field(:id) => subspec(found_by_spec))
287
+ restrict_by_join :id, CardSpec.new(c.get_spec).rawspec
285
288
  end
286
289
  end
287
290
 
288
291
  def not val
289
- merge field(:id) => subspec( val, {:return=>'id'}, negate=true )
292
+ subselect = CardSpec.build(:return=>:id, :_parent=>self).merge(val).to_sql
293
+ join_alias = add_join :not, subselect, :id, :id, :side=>'LEFT'
294
+ merge field(:cond) => SqlCond.new("#{join_alias}.id is null")
290
295
  end
291
296
 
292
297
  def sort val
293
298
  return nil if @parent
294
299
  val[:return] = val[:return] ? safe_sql(val[:return]) : 'db_content'
295
- @mods[:sort] = "t_sort.#{val[:return]}"
296
300
  item = val.delete(:item) || 'left'
297
301
 
298
302
  if val[:return] == 'count'
299
- cs_args = { :return=>'count', :group=>'sort_join_field' }
303
+ cs_args = { :return=>'count', :group=>'sort_join_field', :_parent=>self }
300
304
  @mods[:sort] = "coalesce(#{@mods[:sort]},0)"
301
305
  case item
302
306
  when 'referred_to'
@@ -316,7 +320,9 @@ class Card
316
320
  end
317
321
 
318
322
  cs.sql.fields << "#{cs.table_alias}.#{join_field} as sort_join_field"
319
- add_join :sort, cs.to_sql, :id, :sort_join_field, :side=>'LEFT'
323
+ join_table = add_join :sort, cs.to_sql, :id, :sort_join_field, :side=>'LEFT'
324
+ @mods[:sort] = "#{join_table}.#{val[:return]}"
325
+
320
326
  end
321
327
 
322
328
  def match(val)
@@ -345,8 +351,9 @@ class Card
345
351
  end
346
352
 
347
353
  def extension_type val
348
- # DEPRECATED!!!
349
- add_join :usr, :users, :id, :card_id
354
+ # DEPRECATED LONG AGO!!!
355
+ Rails.logger.info "using DEPRECATED extension_type in WQL"
356
+ merge field(:right_plus) => AccountID
350
357
  end
351
358
 
352
359
 
@@ -367,8 +374,16 @@ class Card
367
374
  end
368
375
 
369
376
  def add_join(name, table, cardfield, otherfield, opts={})
370
- join_alias = "#{table_alias}_#{name}"
371
- @joins[join_alias] = "#{opts[:side]} JOIN #{table} AS #{join_alias} ON #{table_alias}.#{cardfield} = #{join_alias}.#{otherfield}"
377
+ root.join_count = root.join_count.to_i + 1
378
+ join_alias = "#{name}_#{root.join_count}"
379
+ on = "#{table_alias}.#{cardfield} = #{join_alias}.#{otherfield}"
380
+ is_subselect = !table.is_a?( Symbol )
381
+
382
+ if @mods[:conj] == 'or' and is_subselect
383
+ opts[:side] ||= 'LEFT'
384
+ merge field(:cond) => SqlCond.new(on)
385
+ end
386
+ @joins[join_alias] = ["\n ", opts[:side], 'JOIN', table, 'AS', join_alias, 'ON', on, "\n"].compact.join ' '
372
387
  join_alias
373
388
  end
374
389
 
@@ -376,11 +391,11 @@ class Card
376
391
  @fields ||= {}
377
392
  @fields[name] ||= 0
378
393
  @fields[name] += 1
379
- "#{ name }:#{ @fields[name] }"
394
+ "#{ name }_#{ @fields[name] }"
380
395
  end
381
396
 
382
397
  def field_root key
383
- key.to_s.gsub /\:\d+/, ''
398
+ key.to_s.gsub /\_\d+/, ''
384
399
  end
385
400
 
386
401
  def subcondition(val, args={})
@@ -388,34 +403,34 @@ class Card
388
403
  cardspec = CardSpec.build( args )
389
404
  merge field(:cond) => cardspec.merge(val)
390
405
  self.joins.merge! cardspec.joins
391
- end
392
-
393
- # def revision_spec(field, linkfield, val)
394
- # card_select = CardSpec.build(:_parent=>self, :return=>'id').merge(val).to_sql
395
- # add_join :ed, "(select distinct #{field} from card_revisions where #{linkfield} in #{card_select})", :id, field
396
- # end
397
-
406
+ end
398
407
 
399
408
  def action_spec(field, linkfield, val)
400
409
  card_select = CardSpec.build(:_parent=>self, :return=>'id').merge(val).to_sql
401
410
  sql = "(SELECT DISTINCT #{field} AS join_card_id FROM card_acts INNER JOIN card_actions ON card_acts.id = card_act_id "
402
- sql += " WHERE #{linkfield} IN #{card_select} AND (draft=0 OR draft IS NULL))"
411
+ sql += " JOIN (#{card_select}) AS ss ON #{linkfield}=ss.id AND (draft is false OR draft is null))"
403
412
  add_join :ac, sql, :id, :join_card_id
404
413
  end
405
414
 
406
-
407
- def subspec(spec, additions={ :return=>'id'}, negate=false)
408
- additions = additions.merge(:_parent=>self)
409
- operator = negate ? 'not in' : 'in'
410
- ValueSpec.new([operator,CardSpec.build(additions).merge(spec)], self)
415
+ def id_from_spec spec
416
+ case spec
417
+ when Integer ; spec
418
+ when String ; Card.fetch_id(spec)
419
+ end
411
420
  end
412
-
413
- def id_or_subspec spec
414
- id = case spec
415
- when Integer ; spec
416
- when String ; Card.fetch_id(spec)
417
- end
418
- id or subspec spec
421
+
422
+ def restrict id_field, val, opts={}
423
+ if id = id_from_spec(val)
424
+ merge field(id_field) => id
425
+ else
426
+ restrict_by_join id_field, val, opts
427
+ end
428
+ end
429
+
430
+ def restrict_by_join id_field, val, opts={}
431
+ opts.reverse_merge!(:return=>:id, :_parent=>self)
432
+ subselect = CardSpec.build(opts).merge(val).to_sql
433
+ add_join "card_#{id_field}", subselect, id_field, opts[:return]
419
434
  end
420
435
 
421
436
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -425,8 +440,11 @@ class Card
425
440
 
426
441
  def to_sql *args
427
442
  sql.conditions << basic_conditions
428
-
429
- return "(" + sql.conditions.last + ")" if @mods[:return]=='condition'
443
+
444
+ if @mods[:return]=='condition'
445
+ conds = sql.conditions.last
446
+ return conds.blank? ? nil : "(#{conds})"
447
+ end
430
448
 
431
449
  if pconds = permission_conditions
432
450
  sql.conditions << pconds
@@ -451,7 +469,7 @@ class Card
451
469
  end
452
470
 
453
471
  def basic_conditions
454
- @spec.map { |key, val| val.to_sql field_root(key) }.join " #{ current_conjunction } "
472
+ @spec.map { |key, val| val.to_sql field_root(key) }.compact.join " #{ current_conjunction } "
455
473
  end
456
474
 
457
475
  def current_conjunction
@@ -135,8 +135,9 @@ class Card
135
135
 
136
136
  define_method event do
137
137
  run_callbacks event do
138
- #puts event
139
- send final_method
138
+ Wagn.with_logging self.name, :event, event, opts do
139
+ send final_method
140
+ end
140
141
  end
141
142
  end
142
143
  end
@@ -1,10 +1,9 @@
1
1
  # should be able to move these to more appropriate places
2
-
3
2
  WAGN_GEM_ROOT = File.expand_path('../..', __FILE__)
4
3
 
5
4
  module Wagn
6
5
 
7
- class << self
6
+ class << self
8
7
  def root
9
8
  Rails.root
10
9
  end
@@ -25,9 +24,22 @@ module Wagn
25
24
  WAGN_GEM_ROOT
26
25
  end
27
26
 
27
+ def with_logging cardname, method, message, details, &block
28
+ if Wagn.config.performance_logger and
29
+ Wagn.config.performance_logger[:methods] and
30
+ Wagn.config.performance_logger[:methods].include? method
31
+ Wagn::Log.start_block :cardname=>cardname, :method=>method, :message=>message, :details=>details
32
+ result = block.call
33
+ Wagn::Log.finish_block
34
+ result
35
+ else
36
+ block.call
37
+ end
38
+ end
39
+
28
40
  def future_stamp
29
41
  ## used in test data
30
42
  @@future_stamp ||= Time.local 2020,1,1,0,0,0
31
43
  end
32
44
  end
33
- end
45
+ end
@@ -1,16 +1,14 @@
1
1
  require 'rails/all'
2
2
 
3
+ require 'builder'
3
4
  require 'htmlentities'
4
5
  require 'recaptcha'
5
- require 'airbrake'
6
6
  require 'RMagick'
7
7
  require 'paperclip'
8
8
  require 'coderay'
9
9
  require 'haml'
10
10
  require 'kaminari'
11
11
  require 'diff/lcs'
12
- require 'diffy'
13
- #require 'scheduler_daemon'
14
12
 
15
13
  require 'wagn/application'
16
14
 
@@ -9,6 +9,14 @@ if defined?(Bundler)
9
9
  # Bundler.require(:default, :assets, Rails.env)
10
10
  end
11
11
 
12
+ module ActiveSupport::BufferedLogger::Severity
13
+ WAGN = UNKNOWN + 1
14
+
15
+ def wagn progname, &block
16
+ add(WAGN, nil, progname, &block)
17
+ end
18
+ end
19
+
12
20
 
13
21
  module Wagn
14
22
  class Application < Rails::Application
@@ -28,7 +36,7 @@ module Wagn
28
36
  end
29
37
 
30
38
  initializer :load_mod_initializers, :after => :load_wagn_config_initializers do
31
- paths.add 'mod-initializers', :with=>'mod', :glob=>"**/initializers/*.rb"
39
+ paths.add 'mod-initializers', :with=>'mod', :glob=>"**{,/*/**}/initializers/*.rb"
32
40
  config.paths['mod-initializers'].existent.sort.each do |initializer|
33
41
  load(initializer)
34
42
  end
@@ -76,6 +84,7 @@ module Wagn
76
84
  config.token_expiry = 2.days
77
85
  config.revisions_per_page = 10
78
86
  config.request_logger = false
87
+ config.performance_logger = false
79
88
 
80
89
  config
81
90
  end
@@ -65,7 +65,7 @@ group :test do
65
65
 
66
66
  # CUKES see features dir
67
67
  gem 'cucumber-rails', '~> 1.3', :require=>false # feature-driven-development suite
68
- gem 'capybara', '~> 2.2.1' # note, selectors were breaking when we used 2.0.1
68
+ gem 'capybara', '~> 2.4.4'
69
69
  gem 'selenium-webdriver', '~> 2.39'
70
70
  # gem 'capybara-webkit'
71
71
  gem 'launchy' # lets cucumber launch browser windows
@@ -97,3 +97,8 @@ group :debug do
97
97
  end
98
98
  end
99
99
  <% end %>
100
+
101
+ Dir.glob(File.join(File.dirname(__FILE__), '*','**{,/*/**}','Gemfile')).each do |gemfile|
102
+ instance_eval(File.read(gemfile))
103
+ end
104
+
@@ -0,0 +1,69 @@
1
+
2
+ class Wagn::Log
3
+ TAB_SIZE = 2
4
+ @@log = []
5
+ @@last_toplevel_card = nil
6
+
7
+ class << self
8
+
9
+ # args:
10
+ # :method => :view|:event|:fetch|:search
11
+ # :cardname, :message, :details
12
+ def start_block args
13
+ level = @@log.last ? @@log.last[:level] + 1 : 1
14
+ @@log << args.merge( :start => Time.now, :level=>level, :subtree =>[] )
15
+ end
16
+
17
+ def finish_block
18
+ log = @@log.pop
19
+ duration = (Time.now - log[:start]) * 1000
20
+ return if limit = Wagn.config.performance_logger[:limit] and limit > 0 and duration < limit
21
+
22
+ log_msg = "#{ indent log[:level] }(%d.2ms) #{ log[:method] }: #{ log[:message] }" % duration
23
+ log_msg += details log if Wagn.config.performance_logger[:details]
24
+ log_msg += subtree log
25
+
26
+ if log_parent = @@log.last
27
+ if sibling = log_parent[:subtree].last and ( sibling[:card] == log[:cardname] or not log[:cardname] )
28
+ sibling[:lines] << log_msg
29
+ else
30
+ log_parent[:subtree] << {:card=>log[:cardname], :lines=>[log_msg]}
31
+ end
32
+ else
33
+ if log[:cardname] and @@last_toplevel_card != log[:cardname]
34
+ @@last_toplevel_card = log[:cardname]
35
+ Rails.logger.wagn log[:cardname]
36
+ end
37
+ Rails.logger.wagn log_msg
38
+ end
39
+ end
40
+
41
+
42
+ def indent level, args={}
43
+ res = (' '*TAB_SIZE + '|') * level
44
+ res += args[:no_link] ? ' ' : '--'
45
+ end
46
+
47
+ def details log
48
+ if log[:details]
49
+ ", " + log[:details].to_s.gsub( "\n", "\n#{ indent( log[:level]+1, :no_link=>true) }" )
50
+ else
51
+ ''
52
+ end
53
+ end
54
+
55
+ def subtree log
56
+ if log[:subtree].present?
57
+ "\n" + log[:subtree].map do |subentry|
58
+ msg = subentry[:card] ? "#{ indent(log[:level]) }#{ subentry[:card] }\n" : ''
59
+ msg += subentry[:lines].join("\n")
60
+ end.join("\n")
61
+ else
62
+ ''
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+