diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6 index 1a8261dd178..37cfd9f2977 100644 --- a/app/assets/javascripts/discourse/models/category.js.es6 +++ b/app/assets/javascripts/discourse/models/category.js.es6 @@ -286,6 +286,10 @@ Category.reopenClass({ return Discourse.ajax(`/c/${id}/show.json`); }, + reloadBySlug(slug, parentSlug) { + return parentSlug ? Discourse.ajax(`/c/${parentSlug}/${slug}/find_by_slug.json`) : Discourse.ajax(`/c/${slug}/find_by_slug.json`); + }, + search(term, opts) { var limit = 5; diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 index f182d2fea5d..b22694a20f2 100644 --- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 @@ -2,6 +2,8 @@ import { filterQueryParams, findTopicList } from 'discourse/routes/build-topic-r import { queryParams } from 'discourse/controllers/discovery-sortable'; import TopicList from 'discourse/models/topic-list'; import PermissionType from 'discourse/models/permission-type'; +import CategoryList from 'discourse/models/category-list'; +import Category from 'discourse/models/category'; // A helper function to create a category route with parameters export default (filter, params) => { @@ -9,7 +11,19 @@ export default (filter, params) => { queryParams, model(modelParams) { - return { category: Discourse.Category.findBySlug(modelParams.slug, modelParams.parentSlug) }; + const category = Category.findBySlug(modelParams.slug, modelParams.parentSlug); + if (!category) { + return Category.reloadBySlug(modelParams.slug, modelParams.parentSlug).then((atts) => { + if (modelParams.parentSlug) { + atts.category.parentCategory = Category.findBySlug(modelParams.parentSlug); + } + const record = this.store.createRecord('category', atts.category); + record.setupGroupsAndPermissions(); + this.site.updateCategory(record); + return { category: Category.findBySlug(modelParams.slug, modelParams.parentSlug) }; + }) + }; + return { category }; }, afterModel(model, transition) { @@ -38,7 +52,6 @@ export default (filter, params) => { _createSubcategoryList(category) { this._categoryList = null; if (Em.isNone(category.get('parentCategory')) && Discourse.SiteSettings.show_subcategory_list) { - const CategoryList = require('discourse/models/category-list').default; return CategoryList.listForParent(this.store, category).then(list => this._categoryList = list); } diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index e99e39aa6dc..5eea9591f08 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -2,7 +2,7 @@ require_dependency 'category_serializer' class CategoriesController < ApplicationController - before_filter :ensure_logged_in, except: [:index, :show, :redirect] + before_filter :ensure_logged_in, except: [:index, :show, :redirect, :find_by_slug] before_filter :fetch_category, only: [:show, :update, :destroy] before_filter :initialize_staff_action_logger, only: [:create, :update, :destroy] skip_before_filter :check_xhr, only: [:index, :redirect] @@ -153,6 +153,15 @@ class CategoriesController < ApplicationController render json: success_json end + def find_by_slug + params.require(:category_slug) + @category = Category.find_by_slug(params[:category_slug], params[:parent_category_slug]) + guardian.ensure_can_see!(@category) + + @category.permission = CategoryGroup.permission_types[:full] if Category.topic_create_allowed(guardian).where(id: @category.id).exists? + render_serialized(@category, CategorySerializer) + end + private def required_param_keys diff --git a/app/models/category.rb b/app/models/category.rb index dfb3eca6178..5dcaaa46bfd 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -450,6 +450,15 @@ SQL def publish_discourse_stylesheet DiscourseStylesheets.cache.clear end + + def self.find_by_slug(category_slug, parent_category_slug=nil) + if parent_category_slug + parent_category_id = self.where(slug: parent_category_slug, parent_category_id: nil).pluck(:id).first + self.where(slug: category_slug, parent_category_id: parent_category_id).first + else + self.where(slug: category_slug, parent_category_id: nil).first + end + end end # == Schema Information diff --git a/config/routes.rb b/config/routes.rb index db70aabf1a9..a3e5a772d96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -430,6 +430,8 @@ Discourse::Application.routes.draw do put "category/:category_id/slug" => "categories#update_slug" get "c/:id/show" => "categories#show" + get "c/:category_slug/find_by_slug" => "categories#find_by_slug" + get "c/:parent_category_slug/:category_slug/find_by_slug" => "categories#find_by_slug" get "c/:category.rss" => "list#category_feed", format: :rss get "c/:parent_category/:category.rss" => "list#category_feed", format: :rss get "c/:category" => "list#category_latest" diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index ff253badbb8..4506c0bbe36 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -583,4 +583,14 @@ describe Category do end end + describe "find_by_slug" do + it "finds with category and sub category" do + category = Fabricate(:category, slug: 'awesome-category') + sub_category = Fabricate(:category, parent_category_id: category.id, slug: 'awesome-sub-category') + + expect(Category.find_by_slug('awesome-category')).to eq(category) + expect(Category.find_by_slug('awesome-sub-category', 'awesome-category')).to eq(sub_category) + end + end + end