boutique 0.0.2 → 0.0.3

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