wagn 1.14.1 → 1.14.2

Sign up to get free protection for your applications and to get access to all the features.
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
+