From 1e166d89ff236601329a45a92b8cd3c8a9edeb98 Mon Sep 17 00:00:00 2001 From: Erick Guan Date: Sat, 20 Dec 2014 22:07:29 +0800 Subject: [PATCH] support setting category slug --- .../controllers/edit-category.js.es6 | 4 +- .../javascripts/discourse/models/category.js | 1 + .../templates/modal/edit-category-general.hbs | 10 ++++- app/assets/stylesheets/common/base/modal.scss | 4 ++ app/controllers/categories_controller.rb | 13 +++++++ app/models/category.rb | 23 +++++------ config/locales/client.en.yml | 2 + config/routes.rb | 1 + .../controllers/categories_controller_spec.rb | 38 +++++++++++++++++++ spec/fabricators/category_fabricator.rb | 6 +++ spec/models/category_spec.rb | 5 +++ 11 files changed, 92 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 index 7f0f6654959..443d3bcb7c4 100644 --- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 +++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 @@ -146,9 +146,9 @@ export default ObjectController.extend(ModalFunctionality, { }).catch(function(error) { if (error && error.responseText) { - self.flash($.parseJSON(error.responseText).errors[0]); + self.flash($.parseJSON(error.responseText).errors[0], 'error'); } else { - self.flash(I18n.t('generic_error')); + self.flash(I18n.t('generic_error'), 'error'); } self.set('saving', false); }); diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js index 3f0732328fe..3f8bb6edb67 100644 --- a/app/assets/javascripts/discourse/models/category.js +++ b/app/assets/javascripts/discourse/models/category.js @@ -58,6 +58,7 @@ Discourse.Category = Discourse.Model.extend({ return Discourse.ajax(url, { data: { name: this.get('name'), + slug: this.get('slug'), color: this.get('color'), text_color: this.get('text_color'), secure: this.get('secure'), diff --git a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs b/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs index 096441c01a2..7931c5ef57e 100644 --- a/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs +++ b/app/assets/javascripts/discourse/templates/modal/edit-category-general.hbs @@ -1,7 +1,13 @@
- - {{text-field value=name placeholderKey="category.name_placeholder" maxlength="50"}} +
+ + {{text-field value=name placeholderKey="category.name_placeholder" maxlength="50"}} +
+
+ + {{text-field value=slug placeholderKey="category.slug_placeholder" maxlength="255"}} +
{{#if canSelectParentCategory}} diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 8e35ab13b62..bc77284478b 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -130,6 +130,10 @@ section.field { margin-bottom: 20px; } + section.field .field-item { + display: inline-block; + margin-right: 10px; + } } .reply-where-modal { diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 3fb80f71aef..a97f7ff7706 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -95,6 +95,19 @@ class CategoriesController < ApplicationController end end + def update_slug + @category = Category.find(params[:category_id].to_i) + guardian.ensure_can_edit!(@category) + + custom_slug = params[:slug].to_s + + if custom_slug.present? && @category.update_attributes(slug: custom_slug) + render json: success_json + else + render_json_error(@category) + end + end + def set_notifications category_id = params[:category_id].to_i notification_level = params[:notification_level].to_i diff --git a/app/models/category.rb b/app/models/category.rb index 4103eb86974..3535019b76b 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -201,18 +201,19 @@ SQL end def ensure_slug - if name.present? - self.name.strip! + return unless name.present? - if slug.present? - # custom slug - errors.add(:slug, "is already in use") if duplicate_slug? - else - # auto slug - self.slug = Slug.for(name) - return if self.slug.blank? - self.slug = '' if duplicate_slug? - end + self.name.strip! + + if slug.present? + # santized custom slug + self.slug = Slug.for(slug) + errors.add(:slug, 'is already in use') if duplicate_slug? + else + # auto slug + self.slug = Slug.for(name) + return if self.slug.blank? + self.slug = '' if duplicate_slug? end end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 294010a1cc2..5186255fe70 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1281,6 +1281,8 @@ en: delete: 'Delete Category' create: 'New Category' save: 'Save Category' + slug: 'Category Slug' + slug_placeholder: '(Optional) dashed-words for url' creation_error: There has been an error during the creation of the category. save_error: There was an error saving the category. name: "Category Name" diff --git a/config/routes.rb b/config/routes.rb index 81a8d29efe1..0c883317bdd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -325,6 +325,7 @@ Discourse::Application.routes.draw do post "category/uploads" => "categories#upload" post "category/:category_id/move" => "categories#move" post "category/:category_id/notifications" => "categories#set_notifications" + put "category/:category_id/slug" => "categories#update_slug" get "c/:id/show" => "categories#show" get "c/:category.rss" => "list#category_feed", format: :rss diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb index 9131980c1b6..0dd227c4b1b 100644 --- a/spec/controllers/categories_controller_spec.rb +++ b/spec/controllers/categories_controller_spec.rb @@ -203,4 +203,42 @@ describe CategoriesController do end + describe 'update_slug' do + it 'requires the user to be logged in' do + lambda { xhr :put, :update_slug, category_id: 'category'}.should raise_error(Discourse::NotLoggedIn) + end + + describe 'logged in' do + let(:valid_attrs) { {id: @category.id, slug: 'fff'} } + + before do + @user = log_in(:admin) + @category = Fabricate(:happy_category, user: @user) + end + + it 'rejects blank' do + xhr :put, :update_slug, category_id: @category.id, slug: nil + response.status.should == 422 + end + + it 'accepts valid custom slug' do + xhr :put, :update_slug, category_id: @category.id, slug: 'valid-slug' + response.should be_success + category = Category.find(@category.id) + category.slug.should == 'valid-slug' + end + + it 'accepts not well formed custom slug' do + xhr :put, :update_slug, category_id: @category.id, slug: ' valid slug' + response.should be_success + category = Category.find(@category.id) + category.slug.should == 'valid-slug' + end + + it 'rejects invalid custom slug' do + xhr :put, :update_slug, category_id: @category.id, slug: ' ' + response.status.should == 422 + end + end + end end diff --git a/spec/fabricators/category_fabricator.rb b/spec/fabricators/category_fabricator.rb index dae13377459..1f237b5d684 100644 --- a/spec/fabricators/category_fabricator.rb +++ b/spec/fabricators/category_fabricator.rb @@ -7,3 +7,9 @@ Fabricator(:diff_category, from: :category) do name "Different Category" user end + +Fabricator(:happy_category, from: :category) do + name 'Happy Category' + slug 'happy' + user +end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 9e3cf3d0fd0..93b3cf5ec63 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -198,6 +198,11 @@ describe Category do c.slug.should eq("cats-category") end + it 'and be sanitized' do + c = Fabricate(:category, name: 'Cats', slug: ' invalid slug') + c.slug.should == 'invalid-slug' + end + it 'fails if custom slug is duplicate with existing' do c1 = Fabricate(:category, name: "Cats", slug: "cats") c2 = Fabricate.build(:category, name: "More Cats", slug: "cats")