boutique 0.0.2 → 0.0.3

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.
data/README.md CHANGED
@@ -74,7 +74,7 @@ the included command line application.
74
74
  % boutique --stats productcode
75
75
  % boutique --expire
76
76
  % boutique --expire id
77
- % boutique --remove id
77
+ % boutique --delete id
78
78
 
79
79
  Development
80
80
  ===========
@@ -85,7 +85,6 @@ via `rake`.
85
85
  TODO
86
86
  ====
87
87
 
88
- * boutique command line
89
88
  * email customer + recover action
90
89
  * email exceptions to developer
91
90
 
data/boutique CHANGED
@@ -2,15 +2,82 @@
2
2
  require 'optparse'
3
3
  require File.expand_path('lib/boutique', File.dirname(__FILE__))
4
4
  require 'dm-migrations'
5
+ require 'date'
6
+ require 'fileutils'
5
7
 
6
8
  ENV['BOUTIQUE_CMD'] = '1'
7
- load(ENV['BOUTIQUE_CONFIG'] || 'config.ru')
8
9
 
9
10
  module Boutique
10
11
  class Command
12
+ def self.delete(id)
13
+ purchase = expire(id)
14
+ purchase.destroy if !purchase.nil?
15
+ end
16
+
17
+ def self.expire(id)
18
+ load_config
19
+ purchase = Boutique::Purchase.get(id.to_i)
20
+ if purchase.nil?
21
+ puts "Purchase #{id} not found"
22
+ return
23
+ end
24
+ purchase.downloads.each do |download|
25
+ FileUtils.rm_rf(File.dirname(
26
+ "#{Boutique.config.download_dir}#{download.sub(Boutique.config.download_path, '')}"))
27
+ end
28
+ purchase
29
+ end
30
+
31
+ def self.expire_old
32
+ load_config
33
+ threshold = (Date.today - 1).strftime("%Y%m%d")
34
+ dirs = Dir.glob("#{Boutique.config.download_dir}/*").
35
+ map {|f| File.basename(f) }.
36
+ select {|f| f < threshold }
37
+ dirs.each {|d| FileUtils.rm_rf("#{Boutique.config.download_dir}/#{d}") }
38
+
39
+ Boutique::Purchase.all(
40
+ :transaction_id => nil,
41
+ :created_at.lt => (Date.today - 1)).destroy
42
+ end
43
+
11
44
  def self.migrate
45
+ load_config rescue DataObjects::SyntaxError
12
46
  DataMapper.auto_upgrade!
13
47
  end
48
+
49
+ def self.stats(code)
50
+ load_config
51
+ product = Boutique::Product.first(:code => code)
52
+ if product.nil?
53
+ puts "Product #{code} not found"
54
+ return
55
+ end
56
+
57
+ puts "Code: #{product.code}"
58
+ puts "Name: #{product.name}"
59
+ puts "Files: #{product.files.join("\n ")}"
60
+ printf("Price: $%.2f\n" % product.price)
61
+ puts "Return: #{product.return_url}"
62
+
63
+ puts ('-' * 40)
64
+
65
+ purchases = product.purchases
66
+ puts "* #{purchases.select {|p| p.completed?}.size} purchases have been completed"
67
+ puts "* #{purchases.reduce(0) {|sum,p| sum + p.counter}} downloads linked"
68
+
69
+ puts ('-' * 40)
70
+
71
+ puts "id, links, email" if purchases.size > 0
72
+ purchases.sort_by {|p| p.counter }.reverse.each do |purchase|
73
+ puts "* #{purchase.id}, #{purchase.counter}, #{purchase.email}" if purchase.completed?
74
+ end
75
+ end
76
+
77
+ private
78
+ def self.load_config
79
+ load(ENV['BOUTIQUE_CONFIG'] || 'config.ru')
80
+ end
14
81
  end
15
82
  end
16
83
 
@@ -18,7 +85,11 @@ ARGV.options do |o|
18
85
  o.set_summary_indent(' ')
19
86
  o.banner = "Usage: #{File.basename($0)} [OPTION]"
20
87
  o.define_head "Admin for boutique"
88
+ o.on('-d', '--delete [id]', 'delete purchase') { |id| Boutique::Command.delete(id); exit }
89
+ o.on('-e', '--expire [id]', 'expire purchase') { |id| Boutique::Command.expire(id); exit }
90
+ o.on('-E', '--expire-old', 'expire old data') { Boutique::Command.expire_old; exit }
21
91
  o.on('-m', '--migrate', 'initial migration') { Boutique::Command.migrate; exit }
92
+ o.on('-s', '--stats [product]', String, 'show stats on product') { |p| Boutique::Command.stats(p); exit }
22
93
  o.on('-h', '--help', 'show this help message') { puts o; exit }
23
94
  o.parse!
24
95
  puts o
data/config.ru CHANGED
@@ -15,4 +15,11 @@ Boutique.configure(!ENV['BOUTIQUE_CMD'].nil?) do |c|
15
15
  c.pp_url 'http://localhost'
16
16
  end
17
17
 
18
+ Boutique.product('readme') do |p|
19
+ p.name 'README document'
20
+ p.files File.expand_path('README.md', File.dirname(__FILE__))
21
+ p.price 1.5
22
+ p.return_url 'http://localhost'
23
+ end
24
+
18
25
  run Boutique::App if !ENV['BOUTIQUE_CMD']
data/lib/boutique.rb CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
2
2
  require 'sinatra/base'
3
3
  require 'dm-core'
4
4
  require 'dm-types'
5
+ require 'dm-timestamps'
5
6
  require 'cgi'
6
7
  require 'date'
7
8
  require 'digest/sha1'
@@ -9,7 +10,7 @@ require 'json'
9
10
  require 'openssl'
10
11
 
11
12
  module Boutique
12
- VERSION = '0.0.2'
13
+ VERSION = '0.0.3'
13
14
 
14
15
  class << self
15
16
  def configure(setup_db=true)
data/test/model_test.rb CHANGED
@@ -15,6 +15,7 @@ class ModelTest < BoutiqueTest
15
15
  assert_nil(purchase.completed_at)
16
16
  assert_nil(purchase.downloads)
17
17
  refute_nil(purchase.secret)
18
+ refute_nil(purchase.created_at)
18
19
  refute(purchase.completed?)
19
20
 
20
21
  purchase.complete('1', 'john@mailinator.com', 'John')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boutique
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: .
11
11
  cert_chain: []
12
- date: 2012-01-28 00:00:00.000000000 Z
12
+ date: 2012-01-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: &70111143120740 !ruby/object:Gem::Requirement
16
+ requirement: &70293142732840 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,32 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70111143120740
24
+ version_requirements: *70293142732840
25
+ - !ruby/object:Gem::Dependency
26
+ name: data_mapper
27
+ requirement: &70293142731600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70293142731600
36
+ - !ruby/object:Gem::Dependency
37
+ name: pony
38
+ requirement: &70293142730680 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70293142730680
25
47
  - !ruby/object:Gem::Dependency
26
48
  name: minitest
27
- requirement: &70111143120020 !ruby/object:Gem::Requirement
49
+ requirement: &70293142729840 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ! '>='
@@ -32,10 +54,10 @@ dependencies:
32
54
  version: '0'
33
55
  type: :development
34
56
  prerelease: false
35
- version_requirements: *70111143120020
57
+ version_requirements: *70293142729840
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: shotgun
38
- requirement: &70111143119480 !ruby/object:Gem::Requirement
60
+ requirement: &70293142729040 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ! '>='
@@ -43,7 +65,7 @@ dependencies:
43
65
  version: '0'
44
66
  type: :development
45
67
  prerelease: false
46
- version_requirements: *70111143119480
68
+ version_requirements: *70293142729040
47
69
  description: A Sinatra module which accepts payments via PayPal and gives customers
48
70
  a secret URL to download your product.
49
71
  email: