diff --git a/app/assets/javascripts/discourse/components/edit-category-images.js.es6 b/app/assets/javascripts/discourse/components/edit-category-images.js.es6 index 885ee5835b2..2aae9d52fff 100644 --- a/app/assets/javascripts/discourse/components/edit-category-images.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-images.js.es6 @@ -1,2 +1,40 @@ import { buildCategoryPanel } from 'discourse/components/edit-category-panel'; -export default buildCategoryPanel('images'); +import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; + +export default buildCategoryPanel('images').extend({ + @computed('category.uploaded_background.url') + backgroundImageUrl(uploadedBackgroundUrl) { + return uploadedBackgroundUrl || ''; + }, + + @computed('category.uploaded_background.id') + backgroundImageId(uploadedBackgroundId) { + return uploadedBackgroundId || null; + }, + + @computed('category.uploaded_logo.url') + logoImageUrl(uploadedLogoUrl) { + return uploadedLogoUrl || ''; + }, + + @computed('category.uploaded_logo.id') + logoImageId(uploadedLogoId) { + return uploadedLogoId || null; + }, + + @observes("backgroundImageUrl", "backgroundImageId") + _setBackgroundUpload() { + this.set("category.uploaded_background", Ember.Object.create({ + id: this.get('backgroundImageId'), + url: this.get('backgroundImageUrl') + })); + }, + + @observes("logoImageUrl", "logoImageId") + _setLogoUpload() { + this.set("category.uploaded_logo", Ember.Object.create({ + id: this.get('logoImageId'), + url: this.get('logoImageUrl') + })); + } +}); diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6 index 8e7d0420c61..afa00fcfb30 100644 --- a/app/assets/javascripts/discourse/components/image-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6 @@ -12,11 +12,13 @@ export default Em.Component.extend(UploadMixin, { uploadDone(upload) { this.set("imageUrl", upload.url); + this.set("imageId", upload.id); }, actions: { trash() { this.set("imageUrl", null); + this.set("imageId", null); } } }); diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6 index fc56790194d..a8657ad16ab 100644 --- a/app/assets/javascripts/discourse/models/category.js.es6 +++ b/app/assets/javascripts/discourse/models/category.js.es6 @@ -91,8 +91,8 @@ const Category = RestModel.extend({ email_in: this.get('email_in'), email_in_allow_strangers: this.get('email_in_allow_strangers'), parent_category_id: this.get('parent_category_id'), - logo_url: this.get('logo_url'), - background_url: this.get('background_url'), + uploaded_logo_id: this.get('uploaded_logo.id'), + uploaded_background_id: this.get('uploaded_background.id'), allow_badges: this.get('allow_badges'), custom_fields: this.get('custom_fields'), topic_template: this.get('topic_template'), diff --git a/app/assets/javascripts/discourse/templates/components/categories-only.hbs b/app/assets/javascripts/discourse/templates/components/categories-only.hbs index 6f6a674c51d..f2db6778627 100644 --- a/app/assets/javascripts/discourse/templates/components/categories-only.hbs +++ b/app/assets/javascripts/discourse/templates/components/categories-only.hbs @@ -11,7 +11,7 @@ {{#each categories as |c|}} - +
{{category-title-link category=c}} diff --git a/app/assets/javascripts/discourse/templates/components/category-title-link.hbs b/app/assets/javascripts/discourse/templates/components/category-title-link.hbs index 827130eac49..49e3b088f18 100644 --- a/app/assets/javascripts/discourse/templates/components/category-title-link.hbs +++ b/app/assets/javascripts/discourse/templates/components/category-title-link.hbs @@ -5,7 +5,7 @@ {{category.name}} - {{#if category.logo_url}} -
{{cdn-img src=category.logo_url class="category-logo"}}
+ {{#if category.uploaded_logo.url}} +
{{cdn-img src=category.uploaded_logo.url class="category-logo"}}
{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs index 84139b501d4..02f655c57e4 100644 --- a/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs +++ b/app/assets/javascripts/discourse/templates/components/edit-category-images.hbs @@ -1,9 +1,16 @@
- {{image-uploader imageUrl=category.logo_url type="category_logo" class="no-repeat"}} + {{image-uploader + imageId=logoImageId + imageUrl=logoImageUrl + type="category_logo" + class="no-repeat"}}
- {{image-uploader imageUrl=category.background_url type="category_background"}} + {{image-uploader + imageId=backgroundImageId + imageUrl=backgroundImageUrl + type="category_background"}}
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 9890a40c4b4..5887ec71971 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -233,8 +233,8 @@ class CategoriesController < ApplicationController :parent_category_id, :auto_close_hours, :auto_close_based_on_last_post, - :logo_url, - :background_url, + :uploaded_logo_id, + :uploaded_background_id, :slug, :allow_badges, :topic_template, diff --git a/app/jobs/scheduled/clean_up_uploads.rb b/app/jobs/scheduled/clean_up_uploads.rb index 07aef08d580..9a12757609c 100644 --- a/app/jobs/scheduled/clean_up_uploads.rb +++ b/app/jobs/scheduled/clean_up_uploads.rb @@ -21,12 +21,12 @@ module Jobs .joins("LEFT JOIN users u ON u.uploaded_avatar_id = uploads.id") .joins("LEFT JOIN user_avatars ua ON (ua.gravatar_upload_id = uploads.id OR ua.custom_upload_id = uploads.id)") .joins("LEFT JOIN user_profiles up ON up.profile_background = uploads.url OR up.card_background = uploads.url") - .joins("LEFT JOIN categories c ON c.logo_url = uploads.url OR c.background_url = uploads.url") + .joins("LEFT JOIN categories c ON c.uploaded_logo_id = uploads.id OR c.uploaded_background_id = uploads.id") .where("pu.upload_id IS NULL") .where("u.uploaded_avatar_id IS NULL") .where("ua.gravatar_upload_id IS NULL AND ua.custom_upload_id IS NULL") .where("up.profile_background IS NULL AND up.card_background IS NULL") - .where("c.logo_url IS NULL AND c.background_url IS NULL") + .where("c.uploaded_logo_id IS NULL AND c.uploaded_background_id IS NULL") .where("uploads.url NOT IN (?)", ignore_urls) result.find_each do |upload| diff --git a/app/models/category.rb b/app/models/category.rb index e2dd126701e..5aabe1cbece 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -15,6 +15,8 @@ class Category < ActiveRecord::Base belongs_to :user belongs_to :latest_post, class_name: "Post" + belongs_to :uploaded_logo, class_name: "Upload" + belongs_to :uploaded_background, class_name: "Upload" has_many :topics has_many :category_users @@ -38,9 +40,6 @@ class Category < ActiveRecord::Base validate :email_in_validator - validates :logo_url, upload_url: true, if: :logo_url_changed? - validates :background_url, upload_url: true, if: :background_url_changed? - validate :ensure_slug before_save :apply_permissions before_save :downcase_email diff --git a/app/models/category_list.rb b/app/models/category_list.rb index 6ccf8bb9d13..f8ff57a007e 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -49,7 +49,13 @@ class CategoryList end def find_categories - @categories = Category.includes(:topic_only_relative_url, subcategories: [:topic_only_relative_url]).secured(@guardian) + @categories = Category.includes( + :uploaded_background, + :uploaded_logo, + :topic_only_relative_url, + subcategories: [:topic_only_relative_url] + ).secured(@guardian) + @categories = @categories.where(suppress_from_homepage: false) if @options[:is_homepage] @categories = @categories.where("categories.parent_category_id = ?", @options[:parent_category_id].to_i) if @options[:parent_category_id].present? diff --git a/app/models/site.rb b/app/models/site.rb index 3a3d0396a71..e97252a7686 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -28,6 +28,7 @@ class Site def categories @categories ||= begin categories = Category + .includes(:uploaded_logo, :uploaded_background) .secured(@guardian) .joins('LEFT JOIN topics t on t.id = categories.topic_id') .select('categories.*, t.slug topic_slug') diff --git a/app/serializers/basic_category_serializer.rb b/app/serializers/basic_category_serializer.rb index 96d6ec6b836..d79f06c4be9 100644 --- a/app/serializers/basic_category_serializer.rb +++ b/app/serializers/basic_category_serializer.rb @@ -11,8 +11,6 @@ class BasicCategorySerializer < ApplicationSerializer :description, :description_text, :topic_url, - :logo_url, - :background_url, :read_restricted, :permission, :parent_category_id, @@ -23,6 +21,9 @@ class BasicCategorySerializer < ApplicationSerializer :sort_order, :sort_ascending + has_one :uploaded_logo, embed: :object, serializer: CategoryUploadSerializer + has_one :uploaded_background, embed: :object, serializer: CategoryUploadSerializer + def include_parent_category_id? parent_category_id end diff --git a/app/serializers/category_upload_serializer.rb b/app/serializers/category_upload_serializer.rb new file mode 100644 index 00000000000..f537c1a3362 --- /dev/null +++ b/app/serializers/category_upload_serializer.rb @@ -0,0 +1,3 @@ +class CategoryUploadSerializer < ApplicationSerializer + attributes :id, :url +end diff --git a/db/migrate/20161202034856_add_uploads_to_categories.rb b/db/migrate/20161202034856_add_uploads_to_categories.rb new file mode 100644 index 00000000000..f2d232e1749 --- /dev/null +++ b/db/migrate/20161202034856_add_uploads_to_categories.rb @@ -0,0 +1,21 @@ +class AddUploadsToCategories < ActiveRecord::Migration + def up + add_column :categories, :uploaded_logo_id, :integer, index: true + add_column :categories, :uploaded_background_id, :integer, index: true + + transaction do + Category.find_each do |category| + logo_upload = Upload.find_by(url: category.logo_url) + category.uploaded_logo_id = logo_upload.id if logo_upload + + background_upload = Upload.find_by(url: category.background_url) + category.uploaded_background_id = background_upload.id if background_upload + + category.save! + end + end + + remove_column :categories, :logo_url, :string + remove_column :categories, :background_url, :string + end +end diff --git a/lib/import_export/category_exporter.rb b/lib/import_export/category_exporter.rb index 4036ed783f4..745c9f9dbdb 100644 --- a/lib/import_export/category_exporter.rb +++ b/lib/import_export/category_exporter.rb @@ -24,7 +24,7 @@ module ImportExport CATEGORY_ATTRS = [:id, :name, :color, :created_at, :user_id, :slug, :description, :text_color, - :auto_close_hours, :logo_url, :background_url, :auto_close_based_on_last_post, + :auto_close_hours, :auto_close_based_on_last_post, :topic_template, :suppress_from_homepage, :permissions_params] def export_categories diff --git a/lib/sass/discourse_sass_importer.rb b/lib/sass/discourse_sass_importer.rb index 3a6f9dea68f..a3e877b8e50 100644 --- a/lib/sass/discourse_sass_importer.rb +++ b/lib/sass/discourse_sass_importer.rb @@ -23,7 +23,7 @@ class DiscourseSassImporter < Sass::Importers::Filesystem "plugins_desktop" => DiscoursePluginRegistry.desktop_stylesheets, "plugins_variables" => DiscoursePluginRegistry.sass_variables, "theme_variables" => [ColorScheme::BASE_COLORS_FILE], - "category_backgrounds" => Proc.new { |c| "body.category-#{c.full_slug} { background-image: url(#{apply_cdn(c.background_url)}) }\n" } + "category_backgrounds" => Proc.new { |c| "body.category-#{c.full_slug} { background-image: url(#{apply_cdn(c.uploaded_background.url)}) }\n" } } end @@ -53,8 +53,8 @@ class DiscourseSassImporter < Sass::Importers::Filesystem end when "category_backgrounds" contents = "" - Category.where('background_url IS NOT NULL').each do |c| - contents << special_imports[name].call(c) if c.background_url.present? + Category.where('uploaded_background_id IS NOT NULL').each do |c| + contents << special_imports[name].call(c) if c.uploaded_background end else stylesheets = special_imports[name] diff --git a/lib/sass/discourse_stylesheets.rb b/lib/sass/discourse_stylesheets.rb index f92c63124d2..cce67137e19 100644 --- a/lib/sass/discourse_stylesheets.rb +++ b/lib/sass/discourse_stylesheets.rb @@ -160,7 +160,7 @@ class DiscourseStylesheets def digest @digest ||= begin theme = (cs = ColorScheme.enabled) ? "#{cs.id}-#{cs.version}" : false - category_updated = Category.where("background_url IS NOT NULL and background_url != ''").last_updated_at + category_updated = Category.where("uploaded_background_id IS NOT NULL").last_updated_at if theme || category_updated > 0 Digest::SHA1.hexdigest "#{RailsMultisite::ConnectionManagement.current_db}-#{theme}-#{DiscourseStylesheets.last_file_updated}-#{category_updated}" diff --git a/spec/jobs/clean_up_uploads_spec.rb b/spec/jobs/clean_up_uploads_spec.rb index 6e7c77cfc33..7f0bf461ae0 100644 --- a/spec/jobs/clean_up_uploads_spec.rb +++ b/spec/jobs/clean_up_uploads_spec.rb @@ -55,7 +55,7 @@ describe Jobs::CleanUpUploads do it "does not delete category logo uploads" do category_logo_upload = fabricate_upload - Fabricate(:category, logo_url: category_logo_upload.url) + Fabricate(:category, uploaded_logo: category_logo_upload) Jobs::CleanUpUploads.new.execute(nil) @@ -64,13 +64,13 @@ describe Jobs::CleanUpUploads do end it "does not delete category background url uploads" do - category_background_url = fabricate_upload - Fabricate(:category, background_url: category_background_url.url) + category_logo_upload = fabricate_upload + Fabricate(:category, uploaded_background: category_logo_upload) Jobs::CleanUpUploads.new.execute(nil) expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: category_background_url.id)).to eq(category_background_url) + expect(Upload.find_by(id: category_logo_upload.id)).to eq(category_logo_upload) end it "does not delete post uploads" do diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index efe28cb6be7..71902361af1 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -12,24 +12,6 @@ describe Category do is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_category_id) end - context "url validation" do - let(:user) { Fabricate(:user) } - - let(:upload) { Fabricate(:upload) } - - it "ensures logo_url is valid" do - expect(Fabricate.build(:category, user: user, logo_url: "---%")).not_to be_valid - expect(Fabricate.build(:category, user: user, logo_url: "http://example.com/made-up.jpg")).not_to be_valid - expect(Fabricate.build(:category, user: user, logo_url: upload.url)).to be_valid - end - - it "ensures background_url is valid" do - expect(Fabricate.build(:category, user: user, background_url: ";test")).not_to be_valid - expect(Fabricate.build(:category, user: user, background_url: "http://example.com/no.jpg")).not_to be_valid - expect(Fabricate.build(:category, user: user, background_url: upload.url)).to be_valid - end - end - it 'validates uniqueness in case insensitive way' do Fabricate(:category, name: "Cats") cats = Fabricate.build(:category, name: "cats")