diff --git a/app/controllers/admin/themes_controller.rb b/app/controllers/admin/themes_controller.rb index 1ba250abf3..5416f10d50 100644 --- a/app/controllers/admin/themes_controller.rb +++ b/app/controllers/admin/themes_controller.rb @@ -1,4 +1,5 @@ require_dependency 'upload_creator' +require 'base64' class Admin::ThemesController < Admin::AdminController @@ -31,7 +32,28 @@ class Admin::ThemesController < Admin::AdminController @theme = Theme.new(name: theme["name"], user_id: current_user.id) theme["theme_fields"]&.each do |field| - @theme.set_field(target: field["target"], name: field["name"], value: field["value"]) + + if field["raw_upload"] + begin + tmp = Tempfile.new + tmp.binmode + file = Base64.decode64(field["raw_upload"]) + tmp.write(file) + tmp.rewind + upload = UploadCreator.new(tmp, field["filename"]).create_for(current_user.id) + field["upload_id"] = upload.id + ensure + tmp.unlink + end + end + + @theme.set_field( + target: field["target"], + name: field["name"], + value: field["value"], + type_id: field["type_id"], + upload_id: field["upload_id"] + ) end if @theme.save @@ -168,7 +190,7 @@ class Admin::ThemesController < Admin::AdminController response.headers['Content-Disposition'] = "attachment; filename=#{@theme.name.parameterize}.dcstyle.json" response.sending_file = true - render json: ThemeSerializer.new(@theme) + render json: ThemeWithEmbeddedUploadsSerializer.new(@theme, root: 'theme') end end diff --git a/app/serializers/theme_serializer.rb b/app/serializers/theme_serializer.rb index 4f8864158a..78532e399a 100644 --- a/app/serializers/theme_serializer.rb +++ b/app/serializers/theme_serializer.rb @@ -1,3 +1,5 @@ +require 'base64' + class ThemeFieldSerializer < ApplicationSerializer attributes :name, :target, :value, :error, :type_id, :upload_id, :url, :filename @@ -68,3 +70,28 @@ class ThemeSerializer < ChildThemeSerializer object.child_themes.order(:name) end end + +class ThemeFieldWithEmbeddedUploadsSerializer < ThemeFieldSerializer + attributes :raw_upload + + def include_raw_upload? + object.upload + end + + def raw_upload + filename = Discourse.store.path_for(object.upload) + raw = nil + + if filename + raw = File.read(filename) + else + raw = Discourse.store.download(object.upload).read + end + + Base64.encode64(raw) + end +end + +class ThemeWithEmbeddedUploadsSerializer < ThemeSerializer + has_many :theme_fields, serializer: ThemeFieldWithEmbeddedUploadsSerializer, embed: :objects +end diff --git a/spec/controllers/admin/themes_controller_spec.rb b/spec/controllers/admin/themes_controller_spec.rb index ee4dc41930..1418f165a8 100644 --- a/spec/controllers/admin/themes_controller_spec.rb +++ b/spec/controllers/admin/themes_controller_spec.rb @@ -1,4 +1,5 @@ require 'rails_helper' +require_dependency 'theme_serializer' describe Admin::ThemesController do @@ -34,6 +35,39 @@ describe Admin::ThemesController do Rack::Test::UploadedFile.new(file_from_fixtures("sam-s-simple-theme.dcstyle.json", "json")) end + let :image do + file_from_fixtures("logo.png") + end + + it 'can import a theme with an upload' do + upload = Fabricate(:upload) + theme = Theme.new(name: 'with-upload', user_id: -1) + upload = UploadCreator.new(image, "logo.png").create_for(-1) + theme.set_field(target: :common, name: :logo, upload_id: upload.id, type: :theme_upload_var) + theme.save + + json = ThemeWithEmbeddedUploadsSerializer.new(theme, root: 'theme').to_json + theme.destroy + + temp = Tempfile.new + temp.write(json) + temp.rewind + + uploaded_json = Rack::Test::UploadedFile.new(temp) + upload.destroy + + post :import, params: { theme: uploaded_json }, format: :json + expect(response).to be_success + temp.unlink + + theme = Theme.last + expect(theme.theme_fields.count).to eq(1) + expect(theme.theme_fields.first.upload).not_to eq(nil) + expect(theme.theme_fields.first.upload.filesize).to eq(upload.filesize) + expect(theme.theme_fields.first.upload.sha1).to eq(upload.sha1) + expect(theme.theme_fields.first.upload.original_filename).to eq(upload.original_filename) + end + it 'imports a theme' do post :import, params: { theme: theme_file }, format: :json expect(response).to be_success