cartoonist 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,11 +9,17 @@ class AdminController < CartoonistController
9
9
  def backup
10
10
  respond_to do |format|
11
11
  format.html { redirect_to "/admin/main" }
12
- format.json do
13
- prefix = "dev-" unless Rails.env.production?
14
- filename = "#{prefix}comics-backup-#{Time.now.strftime("%Y-%m-%d_%H%M%S")}.json"
15
- headers["Content-Disposition"] = "attachment; filename=\"#{filename}\""
16
- render :text => Backup.all.to_json, :content_type => "application/json"
12
+
13
+ format.tgz do
14
+ backup = Backup.new :tgz
15
+ headers["Content-Disposition"] = backup.content_disposition
16
+ self.response_body = backup.response_body
17
+ end
18
+
19
+ format.zip do
20
+ backup = Backup.new :zip
21
+ headers["Content-Disposition"] = backup.content_disposition
22
+ self.response_body = backup.response_body
17
23
  end
18
24
  end
19
25
  end
@@ -46,6 +46,21 @@ class CartoonistController < ActionController::Base
46
46
  end
47
47
 
48
48
  def cache_page_as(path)
49
+ if block_given?
50
+ expiration = expiration_for path
51
+ response.headers["Expires"] = CGI.rfc1123_date expiration.from_now
52
+ expires_in expiration, :public => true
53
+ yield
54
+ end
55
+
49
56
  cache_page @response, "/cache/#{path}"
50
57
  end
58
+
59
+ def expiration_for(path)
60
+ if path =~ /\.tmp\.[^.]*$/
61
+ 2.hours
62
+ else
63
+ 7.days
64
+ end
65
+ end
51
66
  end
@@ -5,8 +5,10 @@ class SiteController < CartoonistController
5
5
 
6
6
  format.ico do
7
7
  data = ActionController::Base.helpers.asset_paths.asset_environment[Cartoonist::Theme.favicon].to_s
8
- send_data data, :filename => "favicon.ico", :type => "image/x-icon", :disposition => "inline"
9
- cache_page_as "static/favicon.ico"
8
+
9
+ cache_page_as "static/favicon.ico" do
10
+ send_data data, :filename => "favicon.ico", :type => "image/x-icon", :disposition => "inline"
11
+ end
10
12
  end
11
13
  end
12
14
  end
@@ -16,8 +18,9 @@ class SiteController < CartoonistController
16
18
  format.html { redirect_to "/" }
17
19
 
18
20
  format.text do
19
- render :layout => false
20
- cache_page_as "static/robots.txt"
21
+ cache_page_as "static/robots.txt" do
22
+ render :layout => false
23
+ end
21
24
  end
22
25
  end
23
26
  end
data/app/models/backup.rb CHANGED
@@ -1,11 +1,110 @@
1
1
  class Backup
2
+ ALLOWED_EXTENSIONS = [:tgz, :zip]
3
+
4
+ def initialize(extension)
5
+ raise "Invalid extension '#{extension}'" unless ALLOWED_EXTENSIONS.include? extension.to_sym
6
+ @extension = extension.to_sym
7
+ end
8
+
9
+ def content_disposition
10
+ %{attachment; filename="#{filename}"}
11
+ end
12
+
13
+ def filename
14
+ prefix = "dev-" unless Rails.env.production?
15
+ "#{prefix}cartoonist-backup-#{Time.now.strftime("%Y-%m-%d_%H%M%S")}.#{@extension}"
16
+ end
17
+
18
+ def response_body
19
+ Enumerator.new do |out|
20
+ send @extension, out
21
+ end
22
+ end
23
+
24
+ def zip(out)
25
+ buffer = Zip::ZipOutputStream.write_buffer do |zos|
26
+ Backup.each do |entry|
27
+ zos.put_next_entry entry.path
28
+ zos.write entry.content
29
+ end
30
+ end
31
+
32
+ out << buffer.string
33
+ end
34
+
35
+ def tgz(out)
36
+ gzip = Zlib::GzipWriter.new Backup::ResponseOutWriter.new(out)
37
+
38
+ begin
39
+ Archive::Tar::Minitar::Writer.open gzip do |tar|
40
+ Backup.each do |entry|
41
+ tar.add_file_simple entry.path, :mode => 0644, :size => entry.content.length do |output|
42
+ output.write entry.content
43
+ end
44
+ end
45
+ end
46
+ ensure
47
+ gzip.close
48
+ end
49
+ end
50
+
51
+ class ResponseOutWriter < Struct.new(:stream)
52
+ def write(content)
53
+ stream << content
54
+ end
55
+ end
56
+
2
57
  class << self
3
- def all
4
- result = Cartoonist::Backup.all.map do |key, value|
5
- [key, value.call]
58
+ def each
59
+ Cartoonist::Backup.all.each do |key, proc|
60
+ proc.call.find_each do |value|
61
+ if value.respond_to? :to_backup_entries
62
+ value.to_backup_entries.each do |entry|
63
+ yield entry.with_key(key)
64
+ end
65
+ else
66
+ yield Backup::Entry.from_record(value).with_key(key)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ class Entry
74
+ attr_reader :key, :filename, :content
75
+
76
+ def initialize(id, title, extension, content)
77
+ if title
78
+ title = "%05d_%s" % [id, title]
79
+ else
80
+ title = "%05d" % id
6
81
  end
7
82
 
8
- Hash[result]
83
+ title = DatabaseFile.sanitize title
84
+ extension = DatabaseFile.sanitize(extension || "")
85
+ extension = ".#{extension}" if extension.present?
86
+ @filename = "#{title}#{extension}"
87
+ @content = content
88
+ end
89
+
90
+ def with_key(key)
91
+ @key = key
92
+ self
93
+ end
94
+
95
+ def safe_key
96
+ DatabaseFile.sanitize key.to_s
97
+ end
98
+
99
+ def path
100
+ "#{safe_key}/#{filename}"
101
+ end
102
+
103
+ class << self
104
+ def from_record(record)
105
+ title = record.zip_title if record.respond_to? :zip_title
106
+ new record.id, title, "json", record.to_json
107
+ end
9
108
  end
10
109
  end
11
110
  end
@@ -1,3 +1,36 @@
1
1
  class DatabaseFile < ActiveRecord::Base
2
- attr_accessible :filename, :content
2
+ attr_accessible :filename, :extension, :content
3
+
4
+ def to_backup_entries
5
+ if filename
6
+ meta_name = "#{filename}.meta"
7
+ else
8
+ meta_name = "meta"
9
+ end
10
+
11
+ file = Backup::Entry.new id, filename, extension, content
12
+ meta = Backup::Entry.new id, meta_name, "json", to_json(:except => :content)
13
+ [file, meta]
14
+ end
15
+
16
+ class << self
17
+ def sanitize(value)
18
+ value.gsub(/\s+/, "_").gsub(/[^0-9a-zA-Z.\-_]/, "")
19
+ end
20
+
21
+ def create_from_param(file, options = {})
22
+ original_filename = file.original_filename
23
+ extension = File.extname original_filename
24
+ filename = File.basename original_filename, extension
25
+ filename = nil if filename.blank?
26
+ extension = extension[/^\.?(.*?)$/, 1].downcase if extension
27
+ extension = nil if extension.blank?
28
+
29
+ if options.include?(:allowed_extensions) && !options[:allowed_extensions].map(&:downcase).include?(extension)
30
+ raise "Extension must be one of: #{options[:allowed_extensions].join ", "}"
31
+ end
32
+
33
+ create :filename => filename, :extension => extension, :content => file.read
34
+ end
35
+ end
3
36
  end
@@ -1,13 +1,33 @@
1
1
  class Markdown
2
+ class LinkToAbsoluteRenderer < Redcarpet::Render::HTML
3
+ def link(link, title, content)
4
+ link = "http://#{Setting[:domain]}#{link}" if link =~ /^\//
5
+ title = %{ title="#{title}"} if title
6
+ %{<a href="#{link}"#{title}>#{content}</a>}
7
+ end
8
+ end
9
+
2
10
  class << self
3
- def config
4
- @markdown ||= Redcarpet::Markdown.new Redcarpet::Render::HTML
11
+ RENDER_DEFAULTS = { :html_safe => true, :link_to_absolute => false }
12
+
13
+ def standard_renderer
14
+ @standard_renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML)
5
15
  end
6
16
 
7
- def render(text, safe = true)
8
- result = config.render text
17
+ def link_to_absolute_renderer
18
+ @link_to_absolute_renderer ||= Redcarpet::Markdown.new(LinkToAbsoluteRenderer.new)
19
+ end
20
+
21
+ def render(text, options = {})
22
+ options = RENDER_DEFAULTS.merge options
23
+
24
+ if options[:link_to_absolute]
25
+ result = link_to_absolute_renderer.render text
26
+ else
27
+ result = standard_renderer.render text
28
+ end
9
29
 
10
- if safe
30
+ if options[:html_safe]
11
31
  result.html_safe
12
32
  else
13
33
  result
@@ -1,6 +1,10 @@
1
1
  class Setting < ActiveRecord::Base
2
2
  attr_accessible :label, :value, :locked
3
3
 
4
+ def zip_title
5
+ label
6
+ end
7
+
4
8
  class << self
5
9
  def [](label)
6
10
  raise "Invalid label" unless label.present?
data/app/models/user.rb CHANGED
@@ -4,6 +4,10 @@ class User < ActiveRecord::Base
4
4
  # Setup accessible (or protected) attributes for your model
5
5
  attr_accessible :email, :password, :password_confirmation, :remember_me, :name
6
6
 
7
+ def zip_title
8
+ name
9
+ end
10
+
7
11
  class << self
8
12
  def create_user(params)
9
13
  create :email => params[:email], :name => params[:name], :password => params[:password], :password_confirmation => params[:confirm_password]
@@ -3,5 +3,9 @@
3
3
  </p>
4
4
 
5
5
  <p>
6
- <a href="/admin/backup.json"><%= t "admin.general.actions.backup" %></a>
6
+ <a href="/admin/backup.tgz"><%= t "admin.general.actions.backup_tgz" %></a>
7
+ </p>
8
+
9
+ <p>
10
+ <a href="/admin/backup.zip"><%= t "admin.general.actions.backup_zip" %></a>
7
11
  </p>
data/cartoonist.gemspec CHANGED
@@ -14,4 +14,6 @@ Gem::Specification.new do |s|
14
14
  s.add_dependency "jquery-rails", "~> 2.0.0"
15
15
  s.add_dependency "railties", "~> 3.2.0"
16
16
  s.add_dependency "redcarpet", "~> 2.1.0"
17
+ s.add_dependency "rubyzip", "~> 0.9.0"
18
+ s.add_dependency "minitar", "~> 0.5.0"
17
19
  end
@@ -34,7 +34,8 @@ en:
34
34
  users: Users
35
35
  general:
36
36
  actions:
37
- backup: Download Backup
37
+ backup_tgz: Download Backup (tarball)
38
+ backup_zip: Download Backup (zip)
38
39
  reload: Update and Reload
39
40
  layout:
40
41
  actions: Actions
@@ -0,0 +1,6 @@
1
+ class AddExtensionToDatabaseFiles < ActiveRecord::Migration
2
+ def change
3
+ add_column :database_files, :extension, :string
4
+ DatabaseFile.update_all :extension => "png"
5
+ end
6
+ end
@@ -294,19 +294,20 @@ module Cartoonist
294
294
  end
295
295
 
296
296
  Mime::Type.register "image/x-icon", :ico
297
+ Mime::Type.register "application/octet-stream", :tgz
297
298
  Cartoonist::Admin::Tab.add :general, :url => "/admin", :order => 3
298
299
  Cartoonist::Migration.add_for self
299
300
 
300
301
  Cartoonist::Backup.for :files do
301
- DatabaseFile.order(:id).all
302
+ DatabaseFile.order(:id)
302
303
  end
303
304
 
304
305
  Cartoonist::Backup.for :settings do
305
- Setting.order(:id).all
306
+ Setting.order(:id)
306
307
  end
307
308
 
308
309
  Cartoonist::Backup.for :users do
309
- User.order(:id).all
310
+ User.order(:id)
310
311
  end
311
312
 
312
313
  Cartoonist::Cron.add do
data/lib/cartoonist.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require "devise"
2
2
  require "jquery-rails"
3
3
  require "redcarpet"
4
+ require "zlib"
5
+ require "archive/tar/minitar"
6
+ require "zip/zip"
4
7
 
5
8
  module Cartoonist
6
9
  module Admin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cartoonist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-15 00:00:00.000000000 Z
12
+ date: 2012-05-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: devise
16
- requirement: &11950700 !ruby/object:Gem::Requirement
16
+ requirement: &12204220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *11950700
24
+ version_requirements: *12204220
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: jquery-rails
27
- requirement: &11937860 !ruby/object:Gem::Requirement
27
+ requirement: &12203580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.0.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *11937860
35
+ version_requirements: *12203580
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: railties
38
- requirement: &11935680 !ruby/object:Gem::Requirement
38
+ requirement: &12203040 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 3.2.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *11935680
46
+ version_requirements: *12203040
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: redcarpet
49
- requirement: &11934640 !ruby/object:Gem::Requirement
49
+ requirement: &12273440 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,7 +54,29 @@ dependencies:
54
54
  version: 2.1.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *11934640
57
+ version_requirements: *12273440
58
+ - !ruby/object:Gem::Dependency
59
+ name: rubyzip
60
+ requirement: &12272860 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 0.9.0
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *12272860
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitar
71
+ requirement: &12272340 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.5.0
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *12272340
58
80
  description: This provides the main functionality and plugin api for Cartoonist.
59
81
  email: reasonnumber@gmail.com
60
82
  executables: []
@@ -110,6 +132,7 @@ files:
110
132
  - db/migrate/20120320043253_create_database_files.rb
111
133
  - db/migrate/20120401014029_create_settings.rb
112
134
  - db/migrate/20120417075756_devise_create_users.rb
135
+ - db/migrate/20120524032959_add_extension_to_database_files.rb
113
136
  - lib/cartoonist.rb
114
137
  - lib/cartoonist/engine.rb
115
138
  - public/errors/404.html