<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>engines/adva_themes/test/fixtures/theme-for-import.zip</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -84,3 +84,4 @@ Marko Sepp&#228;
 Clemens Kofler
 Priit Tamboom
 Thomas R. Koll
+Joshua Harvey</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -38,22 +38,6 @@ map.connect                     'admin/sites/:site_id/sections',
                                 :action       =&gt; 'update_all',
                                 :conditions   =&gt; { :method =&gt; :put }
 
-map.resources :themes,          :controller  =&gt; 'admin/themes',
-                                :path_prefix =&gt; 'admin/sites/:site_id',
-                                :name_prefix =&gt; 'admin_',
-                                :collection  =&gt; { :import =&gt; :any },
-                                :member      =&gt; { :export =&gt; :get }
-
-map.admin_site_selected_themes  'admin/sites/:site_id/themes/selected',
-                                :controller   =&gt; 'admin/themes',
-                                :action       =&gt; 'select',
-                                :conditions   =&gt; { :method =&gt; :post }
-
-map.admin_site_selected_theme   'admin/sites/:site_id/themes/selected/:id',
-                                :controller   =&gt; 'admin/themes',
-                                :action       =&gt; 'unselect',
-                                :conditions   =&gt; { :method =&gt; :delete }
-
 map.connect 'cached_pages',     :controller  =&gt; 'admin/cached_pages',
                                 :action      =&gt; 'clear',
                                 :path_prefix =&gt; 'admin/sites/:site_id',
@@ -68,11 +52,6 @@ map.resources :plugins,         :controller  =&gt; 'admin/plugins', # TODO map manu
                                 :path_prefix =&gt; 'admin/sites/:site_id',
                                 :name_prefix =&gt; 'admin_'
 
-map.resources :files,           :controller  =&gt; 'admin/theme_files',
-                                :path_prefix =&gt; 'admin/sites/:site_id/themes/:theme_id',
-                                :name_prefix =&gt; 'admin_theme_',
-                                :collection  =&gt; { :import =&gt; :any }
-
 map.resources :articles,        :path_prefix =&gt; &quot;admin/sites/:site_id/sections/:section_id&quot;,
                                 :name_prefix =&gt; &quot;admin_&quot;,
                                 :namespace   =&gt; &quot;admin/&quot;</diff>
      <filename>engines/adva_cms/routes.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@ class Admin::ThemesController &lt; Admin::BaseController
   layout &quot;admin&quot;
 
   before_filter :set_theme, :only =&gt; [:show, :use, :edit, :update, :destroy, :export, :select, :unselect]
-  before_filter :ensure_uploaded_theme_file_saved!, :only =&gt; :import
+  # before_filter :ensure_uploaded_theme_file_saved!, :only =&gt; :import
   
   guards_permissions :theme, :update =&gt; [:select, :unselect], :manage =&gt; [:index, :show, :export], :create =&gt; :import
 
@@ -53,11 +53,13 @@ class Admin::ThemesController &lt; Admin::BaseController
   end
 
   def import
-    return unless request.post?
+    render and return unless request.post? # renders the import form
     
-    if params[:theme][:file].blank?
+    # uploads and imports the theme
+    file = params[:theme] ? params[:theme][:file] : nil
+    if file.blank?
       flash.now[:error] = t(:'adva.themes.flash.import.error_filename_blank')
-    elsif @site.themes.import @file
+    elsif @site.themes.import(file)
       flash.now[:notice] = t(:'adva.themes.flash.import.success')
       redirect_to admin_themes_path
     else
@@ -69,7 +71,7 @@ class Admin::ThemesController &lt; Admin::BaseController
     zip_path = @theme.export
     send_file(zip_path.to_s, :stream =&gt; false) rescue raise &quot;Error sending #{zip_path} file&quot;
   ensure
-    FileUtils.rm_r File.dirname(zip_path)
+    FileUtils.rm_r File.dirname(zip_path) rescue nil
   end
 
   def select
@@ -95,6 +97,7 @@ class Admin::ThemesController &lt; Admin::BaseController
     end
 
     def ensure_uploaded_theme_file_saved!
+      return
       return if request.get? || params[:theme][:file].blank?
       
       file = params[:theme][:file]</diff>
      <filename>engines/adva_themes/app/controllers/admin/themes_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,45 +1,45 @@
-class ThemeController &lt; ApplicationController
-  before_filter :set_file, :only =&gt; :file
-  after_filter :cache_file, :only =&gt; :file
-
-  def file
-    if @file.text?
-      headers['Content-Type'] = @file.content_type
-      render :text =&gt; @file.data
-    else
-      send_data @file.data, :filename =&gt; @file.basename.to_s, :type =&gt; @file.content_type, :disposition =&gt; 'inline'
-    end
-  end
-
-  def error
-    render :nothing =&gt; true, :status =&gt; 404
-  end
-
-private
-
-  def set_file
-    theme = find_theme or return error
-    @file = if params[:file].first == 'preview.png'
-      theme.preview
-    else
-      theme.files.find Theme::File.to_id(params.values_at(:type, :file))
-    end or return error
-  end
-
-  def find_theme
-    if params[:subdir]
-      Theme.find(params[:theme_id], params[:subdir])
-    else
-      site = Site.find_by_host(request.host_with_port)
-      site.themes.find(params[:theme_id])
-    end
-  end
-
-  def cache_file
-    self.class.cache_page response.body, request.request_uri
-  rescue
-    STERR.puts &quot;Cache Exception: #{$!}&quot;
-  end
-end
+# class ThemeController &lt; ApplicationController
+#   before_filter :set_file, :only =&gt; :file
+#   after_filter :cache_file, :only =&gt; :file
+# 
+#   def file
+#     if @file.text?
+#       headers['Content-Type'] = @file.content_type
+#       render :text =&gt; @file.data
+#     else
+#       send_data @file.data, :filename =&gt; @file.basename.to_s, :type =&gt; @file.content_type, :disposition =&gt; 'inline'
+#     end
+#   end
+# 
+#   def error
+#     render :nothing =&gt; true, :status =&gt; 404
+#   end
+# 
+# private
+# 
+#   def set_file
+#     theme = find_theme or return error
+#     @file = if params[:file].first == 'preview.png'
+#       theme.preview
+#     else
+#       theme.files.find Theme::File.to_id(params.values_at(:type, :file))
+#     end or return error
+#   end
+# 
+#   def find_theme
+#     if params[:subdir]
+#       Theme.find(params[:theme_id], params[:subdir])
+#     else
+#       site = Site.find_by_host(request.host_with_port)
+#       site.themes.find(params[:theme_id])
+#     end
+#   end
+# 
+#   def cache_file
+#     self.class.cache_page response.body, request.request_uri
+#   rescue
+#     STERR.puts &quot;Cache Exception: #{$!}&quot;
+#   end
+# end
 
 </diff>
      <filename>engines/adva_themes/app/controllers/theme_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 require_dependency 'theme/file'
-  
+
 # root_dir  &#187; #{RAILS_ROOT}/public/themes
 # base_dir  &#187; #{RAILS_ROOT}/public/themes/#{site.host}
 # path      &#187; #{RAILS_ROOT}/public/themes/#{site.host}/#{theme.theme_id}
@@ -15,7 +15,7 @@ class Theme &lt; ActiveRecord::Base
       &quot;#{root_dir}/themes&quot;
     end
   end
-  
+
   belongs_to :site
   has_many :files, :dependent =&gt; :destroy
   has_many :templates
@@ -23,54 +23,103 @@ class Theme &lt; ActiveRecord::Base
   has_many :javascripts
   has_many :stylesheets
   has_one  :preview
-  
-  has_permalink :name, :url_attribute =&gt; :theme_id, :scope =&gt; :site_id, 
+
+  has_permalink :name, :url_attribute =&gt; :theme_id, :scope =&gt; :site_id,
                        :only_when_blank =&gt; false, :sync_url =&gt; true
-  
+
   validates_presence_of :name
-  
+
   after_create  :create_theme_dir, :create_preview
   after_destroy :delete_theme_dir
-  
+
+  class &lt;&lt; self
+    def import(file)
+      name = file.original_filename.gsub(/(^.*(\\|\/))|(\.zip$)/, '').gsub(/[^\w\.\-]/, '_')
+      returning Theme.create(:name =&gt; name) do |theme|
+        theme.import(file)
+      end
+    end
+
+    def make_tmp_dir
+      random = Time.now.to_i.to_s.split('').sort_by{rand}
+      returning Pathname.new(Rails.root + &quot;/tmp/themes/tmp_#{random}/&quot;) do |dir|
+        FileUtils.mkdir_p dir unless dir.exist?
+      end
+    end
+  end
+
+  def about
+    %w(name author version homepage summary).inject({}) do |result, key|
+      result[key] = send(key)
+      result
+    end
+  end
+
   def activate!
     update_attributes! :active =&gt; true
   end
-  
+
   def deactivate!
     update_attributes! :active =&gt; false
   end
-  
+
   def author_link
     name = author.blank? ? I18n.t(:'adva.common.unknown') : author
     homepage.blank? ? name : %(&lt;a href=&quot;#{homepage}&quot;&gt;#{name}&lt;/a&gt;)
   end
-  
+
   def path
-    Site.multi_sites_enabled ? 
-      &quot;#{self.class.base_dir}/site-#{site.id}/#{theme_id}&quot; : 
+    Site.multi_sites_enabled ?
+      &quot;#{self.class.base_dir}/site-#{site.id}/#{theme_id}&quot; :
       &quot;#{self.class.base_dir}/#{theme_id}&quot;
   end
-  
+
   def url
-    Site.multi_sites_enabled ? 
-      &quot;themes/#{site.perma_host}/#{theme_id}&quot; : 
+    Site.multi_sites_enabled ?
+      &quot;themes/#{site.perma_host}/#{theme_id}&quot; :
       &quot;themes/#{theme_id}&quot;
   end
-  
+
+  def import(file)
+    file = returning ActionController::UploadedTempfile.new(&quot;uploaded-theme&quot;) do |f|
+      f.write file.read
+      f.original_path = file.original_path
+      f.read # no idea why we need this here, otherwise the zip can't be opened
+    end unless file.path
+
+    Zip::ZipFile.open(file.path) do |zip|
+      zip.each do |entry|
+        files &lt;&lt; Theme::File.new(:theme =&gt; self, :path =&gt; entry.name, :data =&gt; entry.get_input_stream)
+      end
+    end
+  end
+
+  def export
+    tmp_dir = Theme.make_tmp_dir
+    returning(tmp_dir + &quot;#{name}.zip&quot;) do |file_name|
+      file_name.unlink if file_name.exist?
+      Zip::ZipFile.open(file_name, Zip::ZipFile::CREATE) do |zip|
+        ::File.open(tmp_dir + 'about.yml', 'w') { |file| file.write(about.to_yaml) }
+        zip.add('about.yml', tmp_dir + 'about.yml')
+        files.flatten.each { |file| zip.add(file.base_path, file.path) if File.exists?(file.path) }
+      end
+    end
+  end
+
   # def to_param
   #   theme_id
   # end
-  
+
   protected
-  
+
     def create_theme_dir
       FileUtils.mkdir_p(path)
     end
-  
+
     def create_preview
       self.preview = Preview.create! :theme =&gt; self, :data =&gt; ::File.new(@@default_preview)
     end
-  
+
     def delete_theme_dir
       FileUtils.rm_rf(path)
     end</diff>
      <filename>engines/adva_themes/app/models/theme.rb</filename>
    </modified>
    <modified>
      <diff>@@ -78,6 +78,10 @@ class Theme &lt; ActiveRecord::Base
       [theme.path, directory, name].to_path if name
     end
 
+    def base_path
+      [directory, name].to_path if name
+    end
+
     def url
       [theme.url, directory, name].to_path if name
     end</diff>
      <filename>engines/adva_themes/app/models/theme/file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,8 +2,29 @@
 #              :controller =&gt; 'theme',
 #              :action =&gt; 'file',
 #              :requirements =&gt; { :type =&gt; /stylesheets|javascripts|images/ }
+# 
+# map.connect 'themes/:theme_id/:type/*file',
+#              :controller =&gt; 'theme',
+#              :action =&gt; 'file',
+#              :requirements =&gt; { :type =&gt; /stylesheets|javascripts|images/ }
+
+map.resources :themes,          :controller  =&gt; 'admin/themes',
+                                :path_prefix =&gt; 'admin/sites/:site_id',
+                                :name_prefix =&gt; 'admin_',
+                                :collection  =&gt; { :import =&gt; :any },
+                                :member      =&gt; { :export =&gt; :get }
+
+map.admin_site_selected_themes  'admin/sites/:site_id/themes/selected',
+                                :controller   =&gt; 'admin/themes',
+                                :action       =&gt; 'select',
+                                :conditions   =&gt; { :method =&gt; :post }
+
+map.admin_site_selected_theme   'admin/sites/:site_id/themes/selected/:id',
+                                :controller   =&gt; 'admin/themes',
+                                :action       =&gt; 'unselect',
+                                :conditions   =&gt; { :method =&gt; :delete }
 
-map.connect 'themes/:theme_id/:type/*file',
-             :controller =&gt; 'theme',
-             :action =&gt; 'file',
-             :requirements =&gt; { :type =&gt; /stylesheets|javascripts|images/ }
+map.resources :files,           :controller  =&gt; 'admin/theme_files',
+                                :path_prefix =&gt; 'admin/sites/:site_id/themes/:theme_id',
+                                :name_prefix =&gt; 'admin_theme_',
+                                :collection  =&gt; { :import =&gt; :any }</diff>
      <filename>engines/adva_themes/routes.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,7 @@ theme = site.themes.create! :name     =&gt; 'a theme',
                             :author   =&gt; 'author',
                             :summary  =&gt; 'summary'
 
+
 # theme.templates.create!     :name  =&gt; 'template.html.erb',
 #                             :data =&gt; File.new(&quot;#{File.dirname(__FILE__)}/fixtures/template.html.erb&quot;)
 # </diff>
      <filename>engines/adva_themes/test/fixtures.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + &quot;/../../test_helper&quot;)
 # With.aspects &lt;&lt; :access_control
 
 class AdminThemesControllerTest &lt; ActionController::TestCase
+  include ThemeTestHelper
   tests Admin::ThemesController
 
   with_common :a_site, :a_theme, :is_superuser
@@ -215,6 +216,38 @@ class AdminThemesControllerTest &lt; ActionController::TestCase
     end
   end
 
+  describe &quot;POST to :import&quot; do
+    action { post :import, @params }
+
+    it_guards_permissions :create, :theme
+
+    with :access_granted do
+      with &quot;valid uploaded theme zip file&quot; do
+        before { @params = default_params.merge(:theme =&gt; { :file =&gt; theme_fixture }) }
+        it_redirects_to { admin_themes_path }
+        it_assigns_flash_cookie :notice =&gt; :not_nil
+      end
+      
+      with &quot;no theme zip file uploaded&quot; do
+        before { @params = default_params.merge(:theme =&gt; { :file =&gt; nil }) }
+        it_renders :template, :import
+        it_assigns_flash_cookie :error =&gt; :not_nil
+      end
+    end
+  end
+  
+  describe &quot;GET to :export&quot; do
+    action { get :export, default_params.merge(:id =&gt; @theme.id) }
+
+    it_guards_permissions :manage, :theme
+
+    with :access_granted do
+      # send file matcher?
+      # it_sends_file ...
+      # deletes temp file?
+    end
+  end
+
   # # FIXME specify with valid params
   # describe &quot;POST to :import, without a file&quot; do
   #   action { post :import, default_params.merge(:theme =&gt; {:file =&gt; ''}) }</diff>
      <filename>engines/adva_themes/test/functional/admin/themes_controller_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,18 +13,31 @@ module IntegrationTests
 
     test &quot;Admin creates a new theme, updates its attributes and deletes it&quot; do
       login_as_superuser
-      visits_themes_index_page
-      creates_a_new_theme
-      updates_the_themes_attributes
-      deletes_the_theme
+      visit_themes_index_page
+      create_a_new_theme
+      update_the_themes_attributes
+      delete_the_theme
     end
+    
+    test &quot;Admin creates a new theme with some files, exports the theme and reimports it&quot; do
+      login_as_superuser
+      visit_themes_index_page
+      create_a_new_theme
+
+      click_link 'Edit'
+      creates_a_new_theme_file :filename =&gt; 'layouts/default.html.erb', :data =&gt; 'the theme default layout'
+      creates_a_new_theme_file :filename =&gt; 'effects.js', :data =&gt; 'alert(&quot;booom!&quot;)'
 
-    def visits_themes_index_page
+      export_theme
+      reimport_theme
+    end
+
+    def visit_themes_index_page
       visit @admin_themes_index_page
       assert_template &quot;admin/themes/index&quot;
     end
 
-    def creates_a_new_theme
+    def create_a_new_theme
       click_link 'New theme'
       assert_template &quot;admin/themes/new&quot;
 
@@ -32,8 +45,19 @@ module IntegrationTests
       click_button 'Save'
       assert_template &quot;admin/themes/index&quot;
     end
+    
+    def creates_a_new_theme_file(attributes)
+      click_link 'Create a new file'
+      assert_template &quot;admin/theme_files/new&quot;
+
+      attributes.each do |name, value|
+        fill_in name, :with =&gt; value
+      end
+      click_button 'Save'
+      assert_template &quot;admin/theme_files/show&quot;
+    end
 
-    def updates_the_themes_attributes
+    def update_the_themes_attributes
       click_link 'Edit'
       assert_template &quot;admin/themes/show&quot;
       
@@ -45,9 +69,26 @@ module IntegrationTests
       assert_template &quot;admin/themes/show&quot;
     end
     
-    def deletes_the_theme
+    def delete_the_theme
       click_link 'Delete theme'
       assert_template &quot;admin/themes/index&quot;
     end
+    
+    def export_theme
+      click_link 'Download theme'
+      @exported_theme = Rails.root + &quot;/tmp/themes/imported-theme.zip&quot;
+      ::File.open(@exported_theme, 'w') { |file| file.write(@response.body) }
+    end
+    
+    def reimport_theme
+      assert_difference 'Theme.count' do
+        visit_themes_index_page
+        click_link 'Import theme'
+        attach_file 'Zip file', @exported_theme
+        click_button 'Import'
+        assert_template 'admin/themes/index'
+        has_tag 'h4[title=?]', 'imported-theme', 'imported-theme'
+      end
+    end
   end
 end
\ No newline at end of file</diff>
      <filename>engines/adva_themes/test/integration/admin/themes_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -40,4 +40,8 @@ module ThemeTestHelper
   def uploaded_stylesheet
     Theme::File.create! :theme =&gt; @theme, :path =&gt; 'styles.css', :data =&gt; stylesheet_fixture
   end
+
+  def theme_fixture
+    File.new(&quot;#{File.dirname(__FILE__)}/fixtures/theme-for-import.zip&quot;)
+  end
 end
\ No newline at end of file</diff>
      <filename>engines/adva_themes/test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -83,4 +83,8 @@ class ThemeFileTest &lt; ActiveSupport::TestCase
   
   # INSTANCE METHODS
   
+  test &quot;base_path returns the path relative to the theme directory&quot; do
+    uploaded_template.base_path.should == 'templates/foo/bar/template.html.erb'
+  end
+  
 end
\ No newline at end of file</diff>
      <filename>engines/adva_themes/test/unit/models/theme_file_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -80,29 +80,48 @@ class ThemeTest &lt; ActiveSupport::TestCase
   
   # CLASS METHODS
   
+  test &quot;imports a zip theme&quot; do
+    theme_file = theme_fixture
+    
+    assert_difference '@site.themes.size', +1 do
+      @site.themes.import(theme_file)
+    end
+  end
+  
   # INSTANCE METHODS
+  test &quot;returns about hash&quot; do
+    about_hash =  { &quot;name&quot; =&gt; &quot;a theme&quot;, &quot;author&quot; =&gt; &quot;author&quot;, &quot;version&quot; =&gt; &quot;1.0.0&quot;,
+                    &quot;homepage&quot; =&gt; &quot;http://homepage.org&quot;, &quot;summary&quot; =&gt; &quot;summary&quot; }
+    @theme.about.should == about_hash
+  end
+  
+  test &quot;creates a file when exporting a theme&quot; do
+    theme = @site.themes.create!(:name =&gt; 'export-theme')
+    zip_path = theme.export
+    zip_path.should be_file
+  end
+  
+  test &quot;created ZIP file includes all theme files&quot; do
+    theme = @site.themes.create!(:name =&gt; 'export-theme')
+    theme.files += [uploaded_stylesheet, uploaded_javascript, uploaded_image, uploaded_template]
+p theme.preview.path
+p File.exists?(theme.preview.path)
+    zip_path = theme.export
+    zip_file = Zip::ZipFile.new(zip_path)
+
+    theme.files.each do |file|
+      zip_file.entries.map(&amp;:name).should include(file.base_path)
+    end
+  end
   
   test &quot;activate! activates the theme&quot; do
     @theme.activate!
     @theme.active?.should be_true
   end
   
-  # nope, we stopped doing that
-  # test &quot;activate! exports the theme to the theme base directory&quot; do
-  #   @theme.activate!
-  #   @theme.path.should be_directory
-  # end
-  
   test &quot;deactivate! deactivates the theme&quot; do
     @theme.update_attributes :active =&gt; true
     @theme.deactivate!
     @theme.active?.should be_false
   end
-  
-  # nope, we stopped doing that
-  # test &quot;activate! removes the theme to the theme base directory&quot; do
-  #   @theme.activate! # make sure the directory was there
-  #   @theme.deactivate!
-  #   @theme.path.should_not be_directory
-  # end
 end
\ No newline at end of file</diff>
      <filename>engines/adva_themes/test/unit/models/theme_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>09d833c9f9c24c1df7016cab0165f41a5f286145</id>
    </parent>
  </parents>
  <author>
    <name>Sven Fuchs</name>
    <email>svenfuchs@artweb-design.de</email>
  </author>
  <url>http://github.com/svenfuchs/adva_cms/commit/0f11cf000d8efe9602bf226688f5e028ac61804b</url>
  <id>0f11cf000d8efe9602bf226688f5e028ac61804b</id>
  <committed-date>2009-02-13T05:56:45-08:00</committed-date>
  <authored-date>2009-02-12T06:19:26-08:00</authored-date>
  <message>Theme import/export </message>
  <tree>efe25dcc0de4f171b482443507c52ea0c1c0b41b</tree>
  <committer>
    <name>Joshua Harvey</name>
    <email>joshmh@gmail.com</email>
  </committer>
</commit>
