2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-10-03 21:19:35 +08:00
|
|
|
require_dependency 'compression/zip'
|
2019-07-23 18:57:06 +08:00
|
|
|
|
2019-01-23 22:40:21 +08:00
|
|
|
module ThemeStore; end
|
|
|
|
|
2019-10-03 21:19:35 +08:00
|
|
|
class ThemeStore::ZipExporter
|
2019-01-23 22:40:21 +08:00
|
|
|
|
|
|
|
def initialize(theme)
|
|
|
|
@theme = theme
|
|
|
|
@temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_#{SecureRandom.hex}"
|
2019-02-01 01:46:39 +08:00
|
|
|
@export_name = @theme.name.downcase.gsub(/[^0-9a-z.\-]/, '-')
|
2019-01-28 19:29:29 +08:00
|
|
|
@export_name = "discourse-#{@export_name}" unless @export_name.starts_with?("discourse")
|
2019-01-23 22:40:21 +08:00
|
|
|
end
|
|
|
|
|
2019-05-03 09:43:54 +08:00
|
|
|
def export_name
|
|
|
|
@export_name
|
|
|
|
end
|
|
|
|
|
2019-01-23 22:40:21 +08:00
|
|
|
def package_filename
|
|
|
|
export_package
|
|
|
|
end
|
|
|
|
|
|
|
|
def cleanup!
|
|
|
|
FileUtils.rm_rf(@temp_folder)
|
|
|
|
end
|
|
|
|
|
2021-04-27 21:33:43 +08:00
|
|
|
def with_export_dir(**kwargs)
|
|
|
|
export_to_folder(**kwargs)
|
|
|
|
|
|
|
|
yield File.join(@temp_folder, @export_name)
|
|
|
|
ensure
|
|
|
|
cleanup!
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def export_to_folder(extra_scss_only: false)
|
2019-11-13 17:57:39 +08:00
|
|
|
destination_folder = File.join(@temp_folder, @export_name)
|
|
|
|
FileUtils.mkdir_p(destination_folder)
|
|
|
|
|
|
|
|
@theme.theme_fields.each do |field|
|
2021-04-27 21:33:43 +08:00
|
|
|
next if extra_scss_only && !field.extra_scss_field?
|
2019-11-13 17:57:39 +08:00
|
|
|
next unless path = field.file_path
|
|
|
|
|
|
|
|
# Belt and braces approach here. All the user input should already be
|
|
|
|
# sanitized, but check for attempts to leave the temp directory anyway
|
|
|
|
pathname = Pathname.new(File.join(destination_folder, path))
|
|
|
|
folder_path = pathname.parent.cleanpath
|
|
|
|
raise RuntimeError.new("Theme exporter tried to leave directory") unless folder_path.to_s.starts_with?(destination_folder)
|
|
|
|
pathname.parent.mkpath
|
|
|
|
path = pathname.realdirpath
|
|
|
|
raise RuntimeError.new("Theme exporter tried to leave directory") unless path.to_s.starts_with?(destination_folder)
|
|
|
|
|
|
|
|
if ThemeField.types[field.type_id] == :theme_upload_var
|
|
|
|
filename = Discourse.store.path_for(field.upload)
|
|
|
|
content = filename ? File.read(filename) : Discourse.store.download(field.upload).read
|
|
|
|
else
|
|
|
|
content = field.value
|
2019-01-23 22:40:21 +08:00
|
|
|
end
|
2019-11-13 17:57:39 +08:00
|
|
|
File.write(path, content)
|
2019-01-23 22:40:21 +08:00
|
|
|
end
|
2019-11-13 17:57:39 +08:00
|
|
|
|
2021-04-27 21:33:43 +08:00
|
|
|
if !extra_scss_only
|
|
|
|
File.write(
|
|
|
|
File.join(destination_folder, "about.json"),
|
|
|
|
JSON.pretty_generate(@theme.generate_metadata_hash)
|
|
|
|
)
|
|
|
|
end
|
2019-11-13 17:57:39 +08:00
|
|
|
|
2019-01-23 22:40:21 +08:00
|
|
|
@temp_folder
|
|
|
|
end
|
|
|
|
|
|
|
|
def export_package
|
|
|
|
export_to_folder
|
|
|
|
|
2019-11-13 17:57:39 +08:00
|
|
|
Compression::Zip.new.compress(@temp_folder, @export_name)
|
2019-07-18 20:34:48 +08:00
|
|
|
end
|
2019-01-23 22:40:21 +08:00
|
|
|
end
|