boutique 0.0.11 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+ .boutique,
2
+ .boutique .start,
3
+ .boutique .subscribed,
4
+ .boutique .confirmed,
5
+ .boutique .unsubscribed {
6
+ display: none;
7
+ }
8
+ .boutique.start .start,
9
+ .boutique.subscribed .subscribed,
10
+ .boutique.confirmed .confirmed,
11
+ .boutique.unsubscribed .unsubscribed {
12
+ display: block;
13
+ }
14
+ .boutique {
15
+ position: fixed;
16
+ width: 100%;
17
+ height: 100%;
18
+ left: 0;
19
+ top: 0;
20
+ background: rgba(0,0,0,0.5);
21
+ text-align: center;
22
+ overflow-y: auto;
23
+ }
24
+ .boutique-modal {
25
+ background: #f9f9f9;
26
+ font-size: 16px;
27
+ max-width: 25em;
28
+ position: relative;
29
+ border-radius: 2px;
30
+ margin: 5em auto;
31
+ text-align: left;
32
+ box-shadow: #333 0 0 2px;
33
+ }
34
+ .boutique-close {
35
+ font-family: helvetica, sans-serif;
36
+ position: absolute;
37
+ top: -0.7em;
38
+ left: -0.7em;
39
+ color: #fff;
40
+ background: #000;
41
+ border-radius: 1.4em;
42
+ border: 2px solid #fff;
43
+ line-height: 1.3em;
44
+ cursor: pointer;
45
+ height: 1.4em;
46
+ width: 1.4em;
47
+ text-align: center;
48
+ }
49
+ .boutique-head {
50
+ background: #111;
51
+ border-top-left-radius: 2px;
52
+ border-top-right-radius: 2px;
53
+ text-align: center;
54
+ color: #fff;
55
+ text-shadow: #111 1px 1px 1px;
56
+ padding: 1em 0.5em 1.1em;
57
+ font-size: 1.5em;
58
+ line-height: 1.3em;
59
+ }
60
+ .boutique-body {
61
+ color: #333;
62
+ padding: 2em;
63
+ line-height: 1.6em;
64
+ }
65
+ .boutique-body p {
66
+ line-height: 1.6em;
67
+ margin: 1.5em 0;
68
+ }
69
+ .boutique-body p:first-child {
70
+ margin-top: 0;
71
+ }
72
+ .boutique-body p:last-child {
73
+ margin-bottom: 0;
74
+ }
75
+ .boutique-body form {
76
+ margin-bottom: 0.5em;
77
+ }
78
+ .boutique-body form label {
79
+ font-weight: bold;
80
+ }
81
+ .boutique-body form input[type=text], .boutique-body form input[type=email] {
82
+ border: 1px solid #ccc;
83
+ border-radius: 2px;
84
+ padding: 0.5em 2%;
85
+ font-size: 1em;
86
+ width: 95%;
87
+ }
88
+ .boutique-body form input[type=submit],
89
+ .boutique-body a.boutique-button {
90
+ background: #ed3b19;
91
+ border: 1px solid #ed3b19;
92
+ border-radius: 4px;
93
+ display: inline-block;
94
+ color: #fff;
95
+ font-size: 1em;
96
+ font-weight: bold;
97
+ cursor: pointer;
98
+ padding: 0.5em 0;
99
+ text-align: center;
100
+ text-decoration: none;
101
+ width: 100%;
102
+ }
103
+ .boutique-body form input[type=submit].inlined,
104
+ .boutique-body a.boutique-button.inlined {
105
+ margin-top: 1em;
106
+ }
107
+ .boutique-body form input[type=submit]:hover,
108
+ .boutique-body a.boutique-button:hover {
109
+ background: #fe5b3b;
110
+ }
111
+ .boutique-body form input[type=submit][disabled],
112
+ .boutique-body form input[type=submit][disabled]:hover,
113
+ .boutique-body a.boutique-button[disabled],
114
+ .boutique-body a.boutique-button[disabled]:hover {
115
+ border: 1px solid #777;
116
+ background: #777;
117
+ cursor: default;
118
+ }
119
+ @media screen and (max-width: 420px) {
120
+ .boutique-modal {
121
+ margin: 1em;
122
+ }
123
+ }
@@ -1,39 +1,60 @@
1
- require File.expand_path('helper', File.dirname(__FILE__))
1
+ require_relative 'helper'
2
2
 
3
3
  class AppTest < BoutiqueTest
4
4
  include Rack::Test::Methods
5
5
 
6
6
  def test_subscribe
7
7
  list = new_list
8
- post "/subscribe/#{list.key}", email: 'john@mailinator.com'
8
+ get "/subscribe/#{list.key}", email: 'john@mailinator.com', jsonp: 'callback'
9
9
  assert(last_response.ok?)
10
+ assert_equal('"callback()"', last_response.body.inspect)
10
11
  assert_equal(1, Boutique::Subscriber.count)
11
12
  assert_equal(1, Boutique::Email.count)
12
13
  refute_nil(Pony.last_mail)
13
14
  subscriber = Boutique::Subscriber.first
14
- refute(subscriber.confirmed?)
15
+ refute(subscriber.confirmed)
16
+ end
17
+
18
+ def test_subscribe_invalid
19
+ list = new_list
20
+ get "/subscribe/#{list.key}", email: 'invalid-email'
21
+ assert_equal(400, last_response.status)
22
+ end
23
+
24
+ def test_subscribe_error
25
+ list = new_list
26
+ find_or_create = lambda { |*args| raise('Stubbed Error') }
27
+ Boutique::Subscriber.stub(:find_or_create, find_or_create) do
28
+ assert_raises(RuntimeError) do
29
+ get "/subscribe/#{list.key}", email: 'john@mailinator.com'
30
+ end
31
+ end
32
+ mail = Pony.last_mail
33
+ assert_equal('dev@localhost', mail[:to])
34
+ assert_equal('[Boutique Error] Stubbed Error', mail[:subject])
35
+ assert(mail[:body])
15
36
  end
16
37
 
17
38
  def test_confirm
18
39
  list = new_list
19
- subscriber = Boutique::Subscriber.create(
20
- list_key: list.key, email: 'john@mailinator.com')
21
- refute(subscriber.confirmed?)
22
- post "/confirm/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
40
+ subscriber = Boutique::Subscriber.create(list_key: list.key, email: 'john@mailinator.com')
41
+ refute(subscriber.confirmed)
42
+ get "/confirm/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
23
43
  assert(last_response.ok?)
24
- subscriber = Boutique::Subscriber.get(subscriber.id)
25
- assert(subscriber.confirmed?)
44
+ subscriber = Boutique::Subscriber[subscriber.id]
45
+ assert(subscriber.confirmed)
26
46
  end
27
47
 
28
48
  def test_unsubscribe
29
49
  list = new_list
30
- subscriber = Boutique::Subscriber.create(
31
- list_key: list.key, email: 'john@mailinator.com', confirmed: true)
32
- assert(subscriber.confirmed?)
33
- post "/unsubscribe/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
50
+ subscriber = Boutique::Subscriber.new(list_key: list.key, email: 'john@mailinator.com')
51
+ subscriber.confirmed = true
52
+ subscriber.save
53
+ assert(subscriber.confirmed)
54
+ get "/unsubscribe/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
34
55
  assert(last_response.ok?)
35
- subscriber = Boutique::Subscriber.get(subscriber.id)
36
- refute(subscriber.confirmed?)
56
+ subscriber = Boutique::Subscriber[subscriber.id]
57
+ refute(subscriber.confirmed)
37
58
  end
38
59
 
39
60
  private
@@ -1,8 +1,8 @@
1
- require File.expand_path('helper', File.dirname(__FILE__))
1
+ require_relative 'helper'
2
2
 
3
3
  class ConfigTest < BoutiqueTest
4
4
  def test_db
5
- assert_equal('dev@localhost', Boutique.config.dev_email)
5
+ assert_equal('dev@localhost', Boutique.config.error_email)
6
6
  assert_equal(
7
7
  'sk_test_abcdefghijklmnopqrstuvwxyz',
8
8
  Boutique.config.stripe_api_key)
@@ -10,13 +10,7 @@ class ConfigTest < BoutiqueTest
10
10
  assert_equal(
11
11
  File.expand_path('../temp', File.dirname(__FILE__)),
12
12
  Boutique.config.download_dir)
13
- assert_equal({
14
- adapter: 'sqlite3',
15
- host: 'localhost',
16
- username: 'root',
17
- password: 'secret',
18
- database: 'db.sqlite3'},
19
- Boutique.config.db_options)
13
+ assert_equal('sqlite::memory:', Boutique.config.db_options)
20
14
  assert_equal({via: :sendmail}, Boutique.config.email_options)
21
15
  end
22
16
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path('helper', File.dirname(__FILE__))
1
+ require_relative 'helper'
2
2
  require 'redcarpet'
3
3
 
4
4
  class EmailerTest < BoutiqueTest
@@ -45,7 +45,7 @@ class EmailerTest < BoutiqueTest
45
45
  subscriber.save
46
46
  assert_equal(0, subscriber.drip_day)
47
47
  @emailer.drip
48
- subscriber = Boutique::Subscriber.get(subscriber.id)
48
+ subscriber = Boutique::Subscriber[subscriber.id]
49
49
  assert_equal(1, subscriber.drip_day)
50
50
  refute_nil(Pony.last_mail)
51
51
  assert_equal(1, Boutique::Email.count)
@@ -53,7 +53,7 @@ class EmailerTest < BoutiqueTest
53
53
 
54
54
  Pony.mail(nil)
55
55
  @emailer.drip
56
- subscriber = Boutique::Subscriber.get(subscriber.id)
56
+ subscriber = Boutique::Subscriber[subscriber.id]
57
57
  assert_equal(1, subscriber.drip_day)
58
58
  assert_nil(Pony.last_mail)
59
59
  assert_equal(1, Boutique::Email.count)
@@ -61,7 +61,9 @@ class EmailerTest < BoutiqueTest
61
61
 
62
62
  private
63
63
  def create_subscriber
64
- Boutique::Subscriber.create(
65
- list_key: @list.key, email: 'john@mailinator.com', confirmed: true)
64
+ subscriber = Boutique::Subscriber.new(list_key: @list.key, email: 'john@mailinator.com')
65
+ subscriber.confirmed = true
66
+ subscriber.save
67
+ subscriber
66
68
  end
67
69
  end
@@ -1,13 +1,22 @@
1
- require File.expand_path('../lib/boutique', File.dirname(__FILE__))
2
- require 'dm-migrations'
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require_relative '../lib/boutique'
3
4
  require 'minitest/autorun'
4
5
  require 'rack'
5
6
  require 'rack/test'
6
7
  require 'rack/server'
7
8
  require 'fileutils'
9
+ require 'sequel'
8
10
 
9
- DataMapper.setup(:default, 'sqlite::memory:')
10
- DataMapper.auto_migrate!
11
+ Boutique.configure do |c|
12
+ c.error_email 'dev@localhost'
13
+ c.stripe_api_key 'sk_test_abcdefghijklmnopqrstuvwxyz'
14
+ c.download_path '/download'
15
+ c.download_dir File.expand_path('../temp', File.dirname(__FILE__))
16
+ c.db_options 'sqlite::memory:'
17
+ c.email_options via: :sendmail
18
+ end
19
+ Boutique::Migrate.run
11
20
 
12
21
  module Pony
13
22
  def self.mail(fields)
@@ -19,25 +28,13 @@ module Pony
19
28
  end
20
29
  end
21
30
 
22
- class BoutiqueTest < MiniTest::Test
31
+ class BoutiqueTest < Minitest::Test
23
32
  def setup
24
- Boutique::Purchase.all.destroy
25
- Boutique::Subscriber.all.destroy
26
- Boutique::Email.all.destroy
33
+ # Boutique::Purchase.all.delete
34
+ Boutique::Email.select_all.delete
35
+ Boutique::Subscriber.select_all.delete
27
36
  Boutique::List.reset_db
28
37
  Boutique::Product.reset_db
29
- Boutique.configure(false) do |c|
30
- c.dev_email 'dev@localhost'
31
- c.stripe_api_key 'sk_test_abcdefghijklmnopqrstuvwxyz'
32
- c.download_path '/download'
33
- c.download_dir File.expand_path('../temp', File.dirname(__FILE__))
34
- c.db_options(adapter: 'sqlite3',
35
- host: 'localhost',
36
- username: 'root',
37
- password: 'secret',
38
- database: 'db.sqlite3')
39
- c.email_options(via: :sendmail)
40
- end
41
38
  Pony.mail(nil)
42
39
  end
43
40
 
@@ -55,13 +52,13 @@ class BoutiqueTest < MiniTest::Test
55
52
  Boutique::List['learn-icon']
56
53
  end
57
54
 
58
- def ebook_product
59
- Boutique::Product.new(
60
- :code => 'ebook',
61
- :name => 'Ebook',
62
- :files => [File.expand_path('../README.md', File.dirname(__FILE__))],
63
- :price => 10.5,
64
- :return_url => 'http://zincmade.com',
65
- :support_email => 'support@zincmade.com')
66
- end
55
+ #def ebook_product
56
+ # Boutique::Product.new(
57
+ # :code => 'ebook',
58
+ # :name => 'Ebook',
59
+ # :files => [File.expand_path('../README.md', File.dirname(__FILE__))],
60
+ # :price => 10.5,
61
+ # :return_url => 'http://zincmade.com',
62
+ # :support_email => 'support@zincmade.com')
63
+ #end
67
64
  end
@@ -1,6 +1,11 @@
1
- require File.expand_path('helper', File.dirname(__FILE__))
1
+ require_relative 'helper'
2
2
 
3
3
  class ModelTest < BoutiqueTest
4
+ def test_migrate
5
+ versions = Boutique.database.select(:version).from(:schema_info).all
6
+ assert_equal([{version: 1}], versions)
7
+ end
8
+
4
9
  def test_product
5
10
  Boutique.product('icon-set') do |p|
6
11
  p.from 'support@zincmade.com'
@@ -32,7 +37,7 @@ class ModelTest < BoutiqueTest
32
37
  list_key: 'learn-icon',
33
38
  email: 'john@mailinator.com')
34
39
  subscriber.save
35
- refute(subscriber.confirmed?)
40
+ refute(subscriber.confirmed)
36
41
  refute_nil(subscriber.secret)
37
42
  assert_equal(1, list.subscribers.count)
38
43
  assert_equal(subscriber, list.subscribers.first)
@@ -49,7 +54,7 @@ class ModelTest < BoutiqueTest
49
54
  end
50
55
 
51
56
  def test_subscriber_email_validation
52
- list = new_list
57
+ list = new_list
53
58
  subscriber = Boutique::Subscriber.new(
54
59
  list_key: 'learn-icon',
55
60
  email: 'invalid-email')
metadata CHANGED
@@ -1,176 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boutique
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Hugh Bien
9
8
  autorequire:
10
- bindir: .
9
+ bindir: bin
11
10
  cert_chain: []
12
- date: 2013-09-11 00:00:00.000000000 Z
11
+ date: 2014-08-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: sinatra
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
19
+ version: '1.4'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '0'
26
+ version: '1.4'
30
27
  - !ruby/object:Gem::Dependency
31
- name: data_mapper
28
+ name: sequel
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: '0'
33
+ version: '4.12'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: '0'
40
+ version: '4.12'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: pony
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
- version: '0'
47
+ version: '1.10'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - "~>"
60
53
  - !ruby/object:Gem::Version
61
- version: '0'
54
+ version: '1.10'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: tilt
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - "~>"
68
60
  - !ruby/object:Gem::Version
69
- version: '0'
61
+ version: '1.4'
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - "~>"
76
67
  - !ruby/object:Gem::Version
77
- version: '0'
68
+ version: '1.4'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: preamble
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - "~>"
84
74
  - !ruby/object:Gem::Version
85
- version: '0'
75
+ version: '0.0'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - "~>"
92
81
  - !ruby/object:Gem::Version
93
- version: '0'
82
+ version: '0.0'
94
83
  - !ruby/object:Gem::Dependency
95
- name: minitest
84
+ name: shotgun
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - "~>"
100
88
  - !ruby/object:Gem::Version
101
- version: '0'
89
+ version: '0.0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - "~>"
108
95
  - !ruby/object:Gem::Version
109
- version: '0'
96
+ version: '0.0'
110
97
  - !ruby/object:Gem::Dependency
111
- name: shotgun
98
+ name: sqlite3
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ! '>='
101
+ - - "~>"
116
102
  - !ruby/object:Gem::Version
117
- version: '0'
103
+ version: '1.3'
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
- - - ! '>='
108
+ - - "~>"
124
109
  - !ruby/object:Gem::Version
125
- version: '0'
110
+ version: '1.3'
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: rack-test
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
- - - ! '>='
115
+ - - "~>"
132
116
  - !ruby/object:Gem::Version
133
- version: '0'
117
+ version: '0.6'
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
- - - ! '>='
122
+ - - "~>"
140
123
  - !ruby/object:Gem::Version
141
- version: '0'
124
+ version: '0.6'
142
125
  - !ruby/object:Gem::Dependency
143
- name: dm-sqlite-adapter
126
+ name: redcarpet
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
- - - ! '>='
129
+ - - "~>"
148
130
  - !ruby/object:Gem::Version
149
- version: '0'
131
+ version: '3.1'
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
- - - ! '>='
136
+ - - "~>"
156
137
  - !ruby/object:Gem::Version
157
- version: '0'
138
+ version: '3.1'
158
139
  - !ruby/object:Gem::Dependency
159
- name: redcarpet
140
+ name: minitest
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
- - - ! '>='
143
+ - - "~>"
164
144
  - !ruby/object:Gem::Version
165
- version: '0'
145
+ version: '5.4'
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
- - - ! '>='
150
+ - - "~>"
172
151
  - !ruby/object:Gem::Version
173
- version: '0'
152
+ version: '5.4'
174
153
  description: A Sinatra app that adds product checkouts and drip emails support to
175
154
  any websites (both UI + backend).
176
155
  email:
@@ -182,40 +161,44 @@ extra_rdoc_files: []
182
161
  files:
183
162
  - LICENSE.md
184
163
  - README.md
164
+ - bin/boutique
185
165
  - config.ru
186
- - boutique
187
166
  - lib/boutique.rb
167
+ - lib/boutique/app.rb
168
+ - lib/boutique/config.rb
169
+ - lib/boutique/emailer.rb
170
+ - lib/boutique/model.rb
171
+ - lib/boutique/version.rb
172
+ - migrate/001_init_schema.rb
173
+ - public/boutique/script.js
174
+ - public/boutique/styles.css
175
+ - test/app_test.rb
176
+ - test/config_test.rb
177
+ - test/emailer_test.rb
188
178
  - test/helper.rb
189
179
  - test/model_test.rb
190
- - test/emailer_test.rb
191
- - test/config_test.rb
192
- - test/app_test.rb
193
- - ./boutique
194
180
  homepage: https://github.com/hughbien/boutique
195
- licenses: []
181
+ licenses:
182
+ - BSD
183
+ metadata: {}
196
184
  post_install_message:
197
185
  rdoc_options: []
198
186
  require_paths:
199
187
  - lib
200
188
  required_ruby_version: !ruby/object:Gem::Requirement
201
- none: false
202
189
  requirements:
203
- - - ! '>='
190
+ - - ">="
204
191
  - !ruby/object:Gem::Version
205
192
  version: '0'
206
- segments:
207
- - 0
208
- hash: -1016337613
209
193
  required_rubygems_version: !ruby/object:Gem::Requirement
210
- none: false
211
194
  requirements:
212
- - - ! '>='
195
+ - - ">="
213
196
  - !ruby/object:Gem::Version
214
- version: 1.3.6
197
+ version: '0'
215
198
  requirements: []
216
199
  rubyforge_project:
217
- rubygems_version: 1.8.23
200
+ rubygems_version: 2.2.0
218
201
  signing_key:
219
- specification_version: 3
220
- summary: Sinatra app product checkouts and drip emails
202
+ specification_version: 4
203
+ summary: Sinatra app for product checkouts and drip emails
221
204
  test_files: []