card 1.16.3 → 1.16.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +1 -1
  4. data/db/migrate_core_cards/20150724123438_update_file_and_image_cards.rb +1 -1
  5. data/db/migrate_core_cards/20150824135418_update_file_history.rb +20 -0
  6. data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +13 -0
  7. data/db/seed/new/card_actions.yml +16 -0
  8. data/db/seed/new/card_acts.yml +1 -1
  9. data/db/seed/new/card_changes.yml +56 -80
  10. data/db/seed/new/card_references.yml +282 -58
  11. data/db/seed/new/cards.yml +1348 -1312
  12. data/db/seed/test/fixtures/card_actions.yml +884 -868
  13. data/db/seed/test/fixtures/card_acts.yml +250 -250
  14. data/db/seed/test/fixtures/card_changes.yml +1935 -1959
  15. data/db/seed/test/fixtures/card_references.yml +1024 -800
  16. data/db/seed/test/fixtures/cards.yml +2402 -2366
  17. data/db/version_core_cards.txt +1 -1
  18. data/lib/card.rb +3 -1
  19. data/lib/card/cache.rb +5 -5
  20. data/lib/card/chunk.rb +2 -0
  21. data/lib/card/env.rb +1 -1
  22. data/lib/card/query/card_clause.rb +59 -58
  23. data/lib/card/set.rb +7 -0
  24. data/lib/card/success.rb +143 -0
  25. data/mod/01_core/chunk/query_reference.rb +16 -7
  26. data/mod/01_core/chunk/reference.rb +3 -3
  27. data/mod/01_core/set/all/collection.rb +1 -1
  28. data/mod/01_core/set/all/name.rb +2 -1
  29. data/mod/01_core/set/all/phases.rb +12 -2
  30. data/mod/01_core/set/all/type.rb +5 -5
  31. data/mod/01_history/set/all/actions.rb +6 -2
  32. data/mod/01_history/set/all/content_history.rb +17 -2
  33. data/mod/01_history/set/all/history.rb +1 -1
  34. data/mod/02_basic_types/set/all/file.rb +0 -31
  35. data/mod/03_machines/lib/javascript/jquery.fileupload.js +539 -182
  36. data/mod/03_machines/lib/javascript/wagn.js.coffee +3 -0
  37. data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +20 -18
  38. data/mod/03_machines/lib/stylesheets/style_cards.scss +28 -1
  39. data/mod/05_email/set/all/notify.rb +1 -1
  40. data/mod/05_standard/file/favicon/image-icon.png +0 -0
  41. data/mod/05_standard/file/favicon/image-large.png +0 -0
  42. data/mod/05_standard/file/favicon/image-medium.png +0 -0
  43. data/mod/05_standard/file/favicon/image-original.png +0 -0
  44. data/mod/05_standard/file/favicon/image-small.png +0 -0
  45. data/mod/05_standard/lib/carrier_wave/cardmount.rb +25 -6
  46. data/mod/05_standard/lib/file_uploader.rb +27 -11
  47. data/mod/05_standard/lib/image_uploader.rb +7 -4
  48. data/mod/05_standard/set/abstract/attachment.rb +132 -14
  49. data/mod/05_standard/set/right/account.rb +2 -2
  50. data/mod/05_standard/set/self/signin.rb +0 -1
  51. data/mod/05_standard/set/type/file.rb +48 -19
  52. data/mod/05_standard/set/type/image.rb +9 -12
  53. data/mod/05_standard/spec/chunk/include_spec.rb +13 -12
  54. data/mod/05_standard/spec/chunk/query_reference_spec.rb +50 -0
  55. data/mod/05_standard/spec/set/right/account_spec.rb +24 -25
  56. data/mod/05_standard/spec/set/type/file_spec.rb +1 -1
  57. data/spec/lib/card/reference_spec.rb +14 -0
  58. data/spec/lib/card/success_spec.rb +142 -0
  59. data/tmpsets/set/mod001-01_core/all/collection.rb +1 -1
  60. data/tmpsets/set/mod001-01_core/all/name.rb +2 -1
  61. data/tmpsets/set/mod001-01_core/all/phases.rb +12 -2
  62. data/tmpsets/set/mod001-01_core/all/type.rb +5 -5
  63. data/tmpsets/set/mod002-01_history/all/actions.rb +6 -2
  64. data/tmpsets/set/mod002-01_history/all/content_history.rb +17 -2
  65. data/tmpsets/set/mod002-01_history/all/history.rb +1 -1
  66. data/tmpsets/set/mod003-02_basic_types/all/file.rb +0 -24
  67. data/tmpsets/set/mod003-02_basic_types/all/rss.rb +8 -5
  68. data/tmpsets/set/mod003-02_basic_types/type/pointer.rb +2 -2
  69. data/tmpsets/set/mod005-04_settings/right/structure.rb +7 -2
  70. data/tmpsets/set/mod006-05_email/all/notify.rb +1 -1
  71. data/tmpsets/set/mod007-05_standard/abstract/attachment.rb +132 -14
  72. data/tmpsets/set/mod007-05_standard/all/links.rb +8 -0
  73. data/tmpsets/set/mod007-05_standard/all/rich_html/header.rb +5 -7
  74. data/tmpsets/set/mod007-05_standard/right/account.rb +2 -2
  75. data/tmpsets/set/mod007-05_standard/self/signin.rb +0 -1
  76. data/tmpsets/set/mod007-05_standard/type/file.rb +49 -20
  77. data/tmpsets/set/mod007-05_standard/type/image.rb +9 -12
  78. data/tmpsets/set/mod007-05_standard/type/search_type.rb +40 -22
  79. data/tmpsets/set/mod008-06_bootstrap/self/bootswatch_shared.rb +1 -1
  80. metadata +10 -4
@@ -94,11 +94,11 @@ event :reset_password, :on=>:update, :before=>:approve, :when=>proc{ |c| c.has_r
94
94
  case ( result = authenticate_by_token @env_token )
95
95
  when Integer
96
96
  Auth.signin result
97
- Env.params[:success] = edit_password_success_args
97
+ success << edit_password_success_args
98
98
  abort :success
99
99
  when :token_expired
100
100
  send_reset_password_token
101
- Env.params[:success] = {
101
+ success << {
102
102
  :id => '_self',
103
103
  :view => 'message',
104
104
  :message => "Sorry, this token has expired. Please check your email for a new password reset link."
@@ -30,7 +30,6 @@ format :html do
30
30
 
31
31
  view :core do |args|
32
32
  account = card.fetch :trait=>:account, :new=>{}
33
-
34
33
  form_args = {
35
34
  :hidden => { :success=>"REDIRECT: #{interrupted_action || '*previous'}" },
36
35
  :recaptcha => :off
@@ -1,7 +1,4 @@
1
- include Abstract::Attachment
2
-
3
- set_specific_attributes :file, :remote_file_url
4
- mount_uploader :file, FileUploader
1
+ attachment :file, :uploader=>FileUploader
5
2
 
6
3
  format do
7
4
  view :source do |args|
@@ -66,29 +63,61 @@ format :html do
66
63
  end
67
64
 
68
65
  view :editor do |args|
69
- #Rails.logger.debug "editor for file #{card.inspect}"
70
66
  file_chooser args
71
67
  end
72
68
 
73
- def file_chooser args, db_column=:file
74
- preview =
75
- if !card.new_card?
76
- content_tag :div, _render_core(args).html_safe,
77
- :class=>'attachment-preview', :id=>"#{card.attachment.filename}-preview"
78
- end
79
69
 
70
+ def preview args
71
+ ''
72
+ end
73
+
74
+ view :preview_editor, :tags=>:unknown_ok do |args|
75
+ <<-HTML
76
+ <div class="chosen-file">
77
+ <input type="hidden" name="cached_upload" value="#{card.selected_action_id}">
78
+ <table role="presentation" class="table table-striped"><tbody class="files">
79
+ <tr class="template-download fade in">
80
+ <td>
81
+ <span class="preview">
82
+ #{preview(args)}
83
+ </span>
84
+ </td>
85
+ <td>
86
+ <p class="name">
87
+ #{card.original_filename}
88
+ </p>
89
+ </td>
90
+ <td>
91
+ <span class="size">#{number_to_human_size(card.attachment.size)}</span>
92
+ </td>
93
+ <td class="pull-right">
94
+ <button class="btn btn-danger delete cancel-upload" data-type="DELETE">
95
+ <i class="glyphicon glyphicon-trash"></i>
96
+ <span>Delete</span>
97
+ </button>
98
+ </td>
99
+ </tr></tbody>
100
+ </table>
101
+ </div>
102
+ HTML
103
+ end
104
+
105
+ def file_chooser args
80
106
  <<-HTML
81
107
  <div class="choose-file">
82
- #{preview}
83
- <div>#{file_field db_column, :class=>'file-upload slotter'}</div>
108
+ #{preview(args)}
109
+ <span class="btn btn-success fileinput-button">
110
+ <i class="glyphicon glyphicon-cloud-upload"></i>
111
+ <span>
112
+ #{@slot_view == :edit ? 'Replace' : 'Add'} #{card.attachment_name}...
113
+ </span>
114
+ #{file_field card.attachment_name, :class=>'file-upload slotter'}
115
+ </span>
84
116
  </div>
85
- <div class="chosen-file" style="display:none">
86
- <div>
87
- <label>File chosen:</label>
88
- <span class="chosen-filename"></span>
89
- </div>
90
- <div><a class="cancel-upload">Unchoose</a></div>
117
+ <div id="progress" class="progress" style="display: none;">
118
+ <div class="progress-bar progress-bar-success" style="width: 0%;"></div>
91
119
  </div>
120
+ <div class="chosen-file"></div>
92
121
  HTML
93
122
  end
94
123
 
@@ -1,7 +1,4 @@
1
- include Abstract::Attachment
2
- set_specific_attributes :image, :remote_image_url
3
- mount_uploader :image, ImageUploader
4
-
1
+ attachment :image, :uploader=>ImageUploader
5
2
 
6
3
  format do
7
4
 
@@ -31,28 +28,28 @@ end
31
28
  format :html do
32
29
  include File::HtmlFormat
33
30
 
34
-
35
- view :editor do |args|
36
- file_chooser args, :image
37
- end
38
-
39
-
40
31
  view :core do |args|
41
32
  handle_source args do |source|
42
33
  source == 'missing' ? "<!-- image missing #{@card.name} -->" : image_tag(source)
43
34
  end
44
35
  end
45
36
 
37
+ def preview args
38
+ if !card.new_card? || card.preliminary_upload?
39
+ content_tag( :div, _render_core(args.merge(:size=>:medium)).html_safe,
40
+ :class=>'attachment-preview', :id=>"#{card.attachment.filename}-preview")
41
+ end
42
+ end
46
43
 
47
44
  view :content_changes do |args|
48
45
  out = ''
49
46
  size = args[:diff_type]==:summary ? :icon : :medium
50
47
  if !args[:hide_diff] and args[:action] and last_change = card.last_change_on(:db_content,:before=>args[:action])
51
48
  card.selected_action_id=last_change.card_action_id
52
- out << Card::Diff.render_added_chunk(_render_core(:size=>size))
49
+ out << Card::Diff.render_deleted_chunk(_render_core(:size=>size))
53
50
  end
54
51
  card.selected_action_id=args[:action].id
55
- out << Card::Diff.render_deleted_chunk(_render_core(:size=>size))
52
+ out << Card::Diff.render_added_chunk(_render_core(:size=>size))
56
53
  out
57
54
  end
58
55
 
@@ -7,16 +7,16 @@ describe Card::Chunk::Include, "Inclusion" do
7
7
  @class= Card::Chunk::Include
8
8
  end
9
9
 
10
- it "should ignore invisible comments" do
10
+ it "ignores invisible comments" do
11
11
  expect(render_content("{{## now you see nothing}}")).to eq('')
12
12
  end
13
13
 
14
- it "should handle visible comments" do
14
+ it "handles visible comments" do
15
15
  expect(render_content("{{# now you see me}}")).to eq('<!-- # now you see me -->')
16
16
  expect(render_content("{{# -->}}")).to eq('<!-- # --&gt; -->')
17
17
  end
18
18
 
19
- it "should handle empty inclusions" do
19
+ it "handles empty inclusions" do
20
20
  instance = @class.new( @class.full_match( '{{ }}' ) , nil )
21
21
  expect(instance.name).to eq('')
22
22
  expect(instance.options[:inc_syntax]).to eq(' ')
@@ -26,25 +26,25 @@ describe Card::Chunk::Include, "Inclusion" do
26
26
 
27
27
  end
28
28
 
29
- it "should handle no pipes" do
29
+ it "handles no pipes" do
30
30
  instance = @class.new( @class.full_match( '{{toy}}') , nil )
31
31
  expect(instance.name).to eq('toy')
32
32
  expect(instance.options[:inc_name]).to eq('toy')
33
33
  expect(instance.options.key?(:view)).to eq(false)
34
34
  end
35
35
 
36
- it "should strip the name" do
36
+ it "strips the name" do
37
37
  expect(@class.new( @class.full_match( '{{ toy }}') , nil ).name).to eq('toy')
38
38
  end
39
39
 
40
- it 'should strip html tags' do
40
+ it 'strips html tags' do
41
41
  expect(@class.new( @class.full_match( '{{ <span>toy</span> }}') , nil ).name).to eq('toy')
42
42
  instance = @class.new( @class.full_match( '{{ <span>toy|open</span> }}') , nil )
43
43
  expect(instance.name).to eq('toy')
44
44
  expect(instance.options[:view]).to eq('open')
45
45
  end
46
46
 
47
- it "should handle single pipe" do
47
+ it "handles single pipe" do
48
48
  options = @class.new( @class.full_match('{{toy|view:link;hide:me}}'), nil ).options
49
49
  expect(options[:inc_name]).to eq('toy')
50
50
  expect(options[:view]).to eq('link')
@@ -52,7 +52,7 @@ describe Card::Chunk::Include, "Inclusion" do
52
52
  expect(options.key?(:items)).to eq(false)
53
53
  end
54
54
 
55
- it "should handle multiple pipes" do
55
+ it "handles multiple pipes" do
56
56
  options = @class.new( @class.full_match('{{box|open|closed}}'), nil ).options
57
57
  expect(options[:inc_name]).to eq('box')
58
58
  expect(options[:view]).to eq('open')
@@ -60,31 +60,32 @@ describe Card::Chunk::Include, "Inclusion" do
60
60
  expect(options[:items].key?(:items)).to eq(false)
61
61
  end
62
62
 
63
- it "should handle multiple pipes with blank lists" do
63
+ it "handles multiple pipes with blank lists" do
64
64
  options = @class.new( @class.full_match('{{box||closed}}'), nil ).options
65
65
  expect(options[:inc_name]).to eq('box')
66
66
  expect(options[:view]).to eq(nil)
67
67
  expect(options[:items][:view]).to eq('closed')
68
68
  end
69
69
 
70
- it "should treat :item as view of next level" do
70
+ it "treats :item as view of next level" do
71
71
  options = @class.new( @class.full_match('{{toy|link;item:name}}'), nil ).options
72
72
  expect(options[:inc_name]).to eq('toy')
73
73
  expect(options[:view]).to eq('link')
74
74
  expect(options[:items][:view]).to eq('name')
75
75
  end
76
+
76
77
  end
77
78
 
78
79
  context "rendering" do
79
80
 
80
- it "should handle absolute names" do
81
+ it "handles absolute names" do
81
82
  alpha = newcard 'Alpha', "Pooey"
82
83
  beta = newcard 'Beta', "{{Alpha}}"
83
84
  result = beta.format.render_core
84
85
  assert_view_select result, 'div[class~="card-content"]', "Pooey"
85
86
  end
86
87
 
87
- it "should handle simple relative names" do
88
+ it "handles simple relative names" do
88
89
  alpha = newcard 'Alpha', "{{#{Card::Name.joint}Beta}}"
89
90
  beta = newcard 'Beta'
90
91
  alpha_beta = Card.create :name=>"#{alpha.name}#{Card::Name.joint}Beta", :content=>"Woot"
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ describe Card::Chunk::QueryReference, "QueryReference" do
4
+
5
+ context "syntax parsing" do
6
+ before do
7
+ @class= Card::Chunk::QueryReference
8
+ end
9
+
10
+ let :query_refs do
11
+ content = Card::Content.new @content, Card.new(:type=>'Search')
12
+ content.find_chunks(Card::Chunk::QueryReference)
13
+ end
14
+
15
+ subject { query_refs.first.name }
16
+
17
+ it "handles simple search" do
18
+ @content = '{"name":"Waldo"}'
19
+ is_expected.to eq 'Waldo'
20
+ end
21
+
22
+ it "handles operators" do
23
+ @content = '{"name":["eq","Waldo"]}'
24
+ is_expected.to eq 'Waldo'
25
+ end
26
+
27
+ it "handles multiple values for operators" do
28
+ @content = '{"name":["in","Where","Waldo"]}'
29
+ expect(query_refs[1].name).to eq 'Waldo'
30
+ end
31
+
32
+ it "handles plus attributes" do
33
+ @content = '{"right_plus":["Waldo",{"content":"here"}]}'
34
+ is_expected.to eq 'Waldo'
35
+ end
36
+
37
+ it "handles nested query structures" do
38
+ @content = '{"any":{"content":"Where", "right_plus":["is",{"name":"Waldo"}]}}'
39
+ expect(query_refs[0].name).to eq 'Where'
40
+ expect(query_refs[1].name).to eq 'is'
41
+ expect(query_refs[2].name).to eq 'Waldo'
42
+ end
43
+
44
+ it "handles contextual names" do
45
+ @content = '{"name":"_+Waldo"}'
46
+ is_expected.to eq '_+Waldo'
47
+ end
48
+ end
49
+
50
+ end
@@ -1,35 +1,35 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  describe Card::Set::Right::Account do
4
-
4
+
5
5
  describe '#create' do
6
6
  context "valid user" do
7
7
  #note - much of this is tested in account_request_spec
8
8
  before do
9
9
  Card::Auth.as_bot do
10
- @user_card = Card.create! :name=>'TmpUser', :type_id=>Card::UserID, '+*account'=>{
10
+ @user_card = Card.create! :name=>'TmpUser', :type_id=>Card::UserID, '+*account'=>{
11
11
  '+*email'=>'tmpuser@wagn.org', '+*password'=>'tmp_pass'
12
12
  }
13
13
  end
14
-
14
+
15
15
  end
16
-
16
+
17
17
  it 'should create an authenticable password' do
18
18
  expect(Card::Auth.password_authenticated?( @user_card.account, 'tmp_pass')).to be_truthy
19
19
  end
20
20
  end
21
-
21
+
22
22
  it "should check accountability of 'accounted' card" do
23
23
  @unaccountable = Card.create :name=>'BasicUnaccountable', '+*account'=>{ '+*email'=>'tmpuser@wagn.org', '+*password'=>'tmp_pass' }
24
24
  expect(@unaccountable.errors['+*account'].first).to eq('not allowed on this card')
25
25
  end
26
-
26
+
27
27
  it "should require email" do
28
28
  @no_email = Card.create :name=>'TmpUser', :type_id=>Card::UserID, '+*account'=>{ '+*password'=>'tmp_pass' }
29
29
  expect(@no_email.errors['+*account'].first).to match(/email required/)
30
30
  end
31
31
  end
32
-
32
+
33
33
  describe '#send_account_verification_email' do
34
34
  before do
35
35
  @email = 'joe@user.com'
@@ -77,10 +77,10 @@ describe Card::Set::Right::Account do
77
77
  expect(@mail.parts[0].body.raw_source).to include("valid for #{Card.config.token_expiry / 1.day } days")
78
78
  end
79
79
  end
80
-
81
-
82
-
83
-
80
+
81
+
82
+
83
+
84
84
  describe '#update_attributes' do
85
85
  before :each do
86
86
  @user_card = Card::Auth[ 'joe@user.com' ]
@@ -90,14 +90,14 @@ describe Card::Set::Right::Account do
90
90
  @user_card.account.password_card.update_attributes!(:content => 'new password')
91
91
  assert_equal @user_card.id, Card::Auth.authenticate('joe@user.com', 'new password')
92
92
  end
93
-
93
+
94
94
  it 'should not rehash password when updating email' do
95
95
  @user_card.account.email_card.update_attributes!(:content => 'joe2@user.com')
96
96
  assert_equal @user_card.id, Card::Auth.authenticate('joe2@user.com', 'joe_pass')
97
97
  end
98
98
  end
99
-
100
-
99
+
100
+
101
101
  describe '#reset_password' do
102
102
  before :each do
103
103
  @email = 'joe@user.com'
@@ -116,33 +116,32 @@ describe Card::Set::Right::Account do
116
116
  expect(@account.fetch(:trait => :token)).to be_nil
117
117
  expect(@account.save).to be_falsey
118
118
  end
119
-
119
+
120
120
  it 'should not work if token is expired' do
121
121
  @account.token_card.update_column :updated_at, 3.days.ago.strftime("%F %T")
122
122
  @account.token_card.expire
123
-
123
+
124
124
  result = @account.save
125
125
  expect(result).to eq(true) # successfully completes save
126
126
  expect(@account.token).not_to eq(@token) # token gets updated
127
- success = Card::Env.params[:success]
128
- expect(success[:message]).to match(/expired/) # user notified of expired token
127
+ expect(@account.success.message).to match(/expired/) # user notified of expired token
129
128
  end
130
-
129
+
131
130
  it 'should not work if token is wrong' do
132
131
  Card::Env.params[:reset_token] = @token + 'xxx'
133
132
  @account.save
134
133
  expect(@account.errors[:abort].first).to match(/incorrect_token/)
135
- end
136
-
134
+ end
135
+
137
136
  end
138
-
139
-
137
+
138
+
140
139
  describe '#send_change_notice' do
141
140
  it 'send multipart email' do
142
141
  skip
143
142
  # pending
144
143
  end
145
-
144
+
146
145
  context 'denied access' do
147
146
  it 'excludes protected subcards' do
148
147
  skip
@@ -152,7 +151,7 @@ describe Card::Set::Right::Account do
152
151
  a = Card.fetch "A"
153
152
  a.update_attributes( :content=> "new content", :subcards=>{'+B'=>{:content=>'hidden content'}})
154
153
  end
155
-
154
+
156
155
  it 'sends no email if changes not visible' do
157
156
  skip
158
157
  end
@@ -21,7 +21,7 @@ describe Card::Set::Type::File do
21
21
  expect(subject.last_action.comment).to eq "file1.txt"
22
22
  end
23
23
 
24
- it "has correct originalf filename" do
24
+ it "has correct original filename" do
25
25
  expect(subject.original_filename).to eq "file1.txt"
26
26
  end
27
27
 
@@ -169,6 +169,20 @@ describe Card::Reference do
169
169
  expect(Card['search with references'].referees.map(&:name).sort).to eq ["A","B","X","Y"]
170
170
  end
171
171
 
172
+ it "handles contextual names in Basic cards" do
173
+ card = Card.create :type=>'Basic', :name=>'basic with references',
174
+ :content=>'{{_+A}}'
175
+ Card['A'].update_attributes! :name=>'AAA', :update_referencers=>true
176
+ expect(Card['basic with references'].content).to eq '{{_+AAA}}'
177
+ end
178
+
179
+ it "handles contextual names in Search cards" do
180
+ card = Card.create :type=>'Search', :name=>'search with references',
181
+ :content=>'{"name":"_+A"}'
182
+ Card['A'].update_attributes! :name=>'AAA', :update_referencers=>true
183
+ expect(Card['search with references'].content).to eq '{"name":"_+AAA"}'
184
+ end
185
+
172
186
  it "should handle commented inclusion" do
173
187
  c = Card.create :name=>'inclusion comment test', :content=>'{{## hi mom }}'
174
188
  expect(c.errors.any?).to be_falsey