From bc0b9af576c7a99f4f89be0bf10aa3c9b3697c77 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 9 May 2017 17:20:28 -0400 Subject: [PATCH] FEATURE: support uploads for themes This allows themes to bundle various assets --- .../admin-customize-themes-show.js.es6 | 17 ++++++ .../modals/admin-add-upload.js.es6 | 43 +++++++++++++ .../javascripts/admin/models/theme.js.es6 | 60 ++++++++++++++++--- .../admin/templates/customize-themes-show.hbs | 20 ++++++- .../templates/modal/admin-add-upload.hbs | 12 ++++ .../stylesheets/common/admin/customize.scss | 16 +++++ app/controllers/admin/themes_controller.rb | 26 +++++++- app/models/remote_theme.rb | 29 ++++++++- app/models/theme.rb | 11 ++-- app/models/theme_field.rb | 4 +- app/models/upload.rb | 8 ++- app/serializers/theme_serializer.rb | 22 ++++++- config/locales/client.en.yml | 6 ++ config/locales/server.en.yml | 1 + config/routes.rb | 1 + config/site_settings.yml | 3 + lib/git_importer.rb | 15 ++++- lib/stylesheet/compiler.rb | 1 + lib/stylesheet/importer.rb | 9 ++- lib/validators/upload_validator.rb | 27 +++++---- .../admin/themes_controller_spec.rb | 35 +++++++++-- spec/fixtures/woff2/fake.woff2 | 1 + spec/models/remote_theme_spec.rb | 32 ++++++++-- spec/models/theme_spec.rb | 3 + .../admin/models/theme-test.js.es6 | 17 ++++++ 25 files changed, 368 insertions(+), 51 deletions(-) create mode 100644 app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 create mode 100644 app/assets/javascripts/admin/templates/modal/admin-add-upload.hbs create mode 100644 spec/fixtures/woff2/fake.woff2 create mode 100644 test/javascripts/admin/models/theme-test.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 index 3b2c2d9683e..65f3dbc5624 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 @@ -1,6 +1,9 @@ import { default as computed } from 'ember-addons/ember-computed-decorators'; import { url } from 'discourse/lib/computed'; import { popupAjaxError } from 'discourse/lib/ajax-error'; +import showModal from 'discourse/lib/show-modal'; + +const THEME_UPLOAD_VAR = 2; export default Ember.Controller.extend({ @@ -96,6 +99,16 @@ export default Ember.Controller.extend({ }); }, + addUploadModal() { + showModal('admin-add-upload', {admin: true, name: ''}); + }, + + addUpload(info) { + let model = this.get("model"); + model.setField('common', info.name, '', info.upload_id, THEME_UPLOAD_VAR); + model.saveChanges('theme_fields').catch(e => popupAjaxError(e)); + }, + cancelChangeScheme() { this.set("colorSchemeId", this.get("model.color_scheme_id")); }, @@ -154,6 +167,10 @@ export default Ember.Controller.extend({ this.get("model").addChildTheme(theme); }, + removeUpload(upload) { + this.get("model").removeField(upload); + }, + removeChildTheme(theme) { this.get("model").removeChildTheme(theme); }, diff --git a/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 new file mode 100644 index 00000000000..9b29d3b0d53 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 @@ -0,0 +1,43 @@ +import ModalFunctionality from 'discourse/mixins/modal-functionality'; +import { ajax } from 'discourse/lib/ajax'; +// import computed from 'ember-addons/ember-computed-decorators'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; + +export default Ember.Controller.extend(ModalFunctionality, { + adminCustomizeThemesShow: Ember.inject.controller(), + + actions: { + updateName() { + let name = this.get('name'); + if (Em.isEmpty(name)) { + name = $('#file-input')[0].files[0].name; + this.set('name', name.split(".")[0]); + } + }, + upload() { + + let options = { + type: 'POST' + }; + + options.processData = false; + options.contentType = false; + options.data = new FormData(); + let file = $('#file-input')[0].files[0]; + options.data.append('file', file); + + ajax('/admin/themes/upload_asset', options).then(result=>{ + let upload = { + upload_id: result.upload_id, + name: this.get('name'), + original_filename: file.name + }; + this.get('adminCustomizeThemesShow').send('addUpload', upload); + this.send('closeModal'); + }).catch(e => { + popupAjaxError(e); + }); + + } + } +}); diff --git a/app/assets/javascripts/admin/models/theme.js.es6 b/app/assets/javascripts/admin/models/theme.js.es6 index 229d7ee0c01..3da681477aa 100644 --- a/app/assets/javascripts/admin/models/theme.js.es6 +++ b/app/assets/javascripts/admin/models/theme.js.es6 @@ -1,6 +1,8 @@ import RestModel from 'discourse/models/rest'; import { default as computed } from 'ember-addons/ember-computed-decorators'; +const THEME_UPLOAD_VAR = 2; + const Theme = RestModel.extend({ @computed('theme_fields') @@ -14,12 +16,26 @@ const Theme = RestModel.extend({ let hash = {}; if (fields) { fields.forEach(field=>{ - hash[field.target + " " + field.name] = field; + if (!field.type_id || field.type_id < THEME_UPLOAD_VAR) { + hash[this.getKey(field)] = field; + } }); } return hash; }, + @computed('theme_fields', 'theme_fields.@each') + uploads(fields) { + if (!fields) { + return []; + } + return fields.filter((f)=> f.target === 'common' && f.type_id === THEME_UPLOAD_VAR); + }, + + getKey(field){ + return field.target + " " + field.name; + }, + hasEdited(target, name){ if (name) { return !Em.isEmpty(this.getField(target, name)); @@ -31,30 +47,56 @@ const Theme = RestModel.extend({ getError(target, name) { let themeFields = this.get("themeFields"); - let key = target + " " + name; + let key = this.getKey({target,name}); let field = themeFields[key]; return field ? field.error : ""; }, getField(target, name) { let themeFields = this.get("themeFields"); - let key = target + " " + name; + let key = this.getKey({target, name}) let field = themeFields[key]; return field ? field.value : ""; }, - setField(target, name, value) { + removeField(field) { this.set("changed", true); + field.upload_id = null; + field.value = null; + + return this.saveChanges("theme_fields"); + }, + + setField(target, name, value, upload_id, type_id) { + this.set("changed", true); let themeFields = this.get("themeFields"); - let key = target + " " + name; - let field = themeFields[key]; - if (!field) { - field = {name, target, value}; + let field = {name, target, value, upload_id, type_id}; + + // slow path for uploads and so on + if (type_id && type_id > 1) { + let fields = this.get("theme_fields"); + let existing = fields.find((f) => + f.target === target && + f.name === name && + f.type_id === type_id); + if (existing) { + existing.value = value; + existing.upload_id = upload_id; + } else { + fields.push(field); + } + return; + } + + // fast path + let key = this.getKey({target,name}); + let existingField = themeFields[key]; + if (!existingField) { this.theme_fields.push(field); themeFields[key] = field; } else { - field.value = value; + existingField.value = value; } }, diff --git a/app/assets/javascripts/admin/templates/customize-themes-show.hbs b/app/assets/javascripts/admin/templates/customize-themes-show.hbs index 55c2c5bb399..b4908d71430 100644 --- a/app/assets/javascripts/admin/templates/customize-themes-show.hbs +++ b/app/assets/javascripts/admin/templates/customize-themes-show.hbs @@ -51,7 +51,6 @@

{{i18n "admin.customize.theme.css_html"}}

{{#if hasEditedFields}} -

{{i18n "admin.customize.theme.custom_sections"}}