import { ajax } from 'discourse/lib/ajax'; import RestModel from 'discourse/models/rest'; import computed from 'ember-addons/ember-computed-decorators'; import { on } from 'ember-addons/ember-computed-decorators'; import PermissionType from 'discourse/models/permission-type'; const Category = RestModel.extend({ @on('init') setupGroupsAndPermissions() { const availableGroups = this.get('available_groups'); if (!availableGroups) { return; } this.set("availableGroups", availableGroups); const groupPermissions = this.get('group_permissions'); if (groupPermissions) { this.set('permissions', groupPermissions.map((elem) => { availableGroups.removeObject(elem.group_name); return { group_name: elem.group_name, permission: PermissionType.create({ id: elem.permission_type }) }; })); } }, @computed availablePermissions() { return [ PermissionType.create({ id: PermissionType.FULL }), PermissionType.create({ id: PermissionType.CREATE_POST }), PermissionType.create({ id: PermissionType.READONLY }) ]; }, @computed("id") searchContext(id) { return { type: 'category', id, category: this }; }, @computed("name") url() { return Discourse.getURL("/c/") + Category.slugFor(this); }, @computed("url") fullSlug(url) { return url.slice(3).replace("/", "-"); }, @computed("name") nameLower(name) { return name.toLowerCase(); }, @computed("url") unreadUrl(url) { return `${url}/l/unread`; }, @computed("url") newUrl(url) { return `${url}/l/new`; }, @computed("color", "text_color") style(color, textColor) { return `background-color: #${color}; color: #${textColor}`; }, @computed("topic_count") moreTopics(topicCount) { return topicCount > Discourse.SiteSettings.category_featured_topics; }, save() { const id = this.get("id"); const url = id ? `/categories/${id}` : "/categories"; return 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'), permissions: this.get('permissionsForUpdate'), auto_close_hours: this.get('auto_close_hours'), auto_close_based_on_last_post: this.get("auto_close_based_on_last_post"), position: this.get('position'), 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'), allow_badges: this.get('allow_badges'), custom_fields: this.get('custom_fields'), topic_template: this.get('topic_template'), suppress_from_homepage: this.get('suppress_from_homepage'), allowed_tags: this.get('allowed_tags'), allowed_tag_groups: this.get('allowed_tag_groups') }, type: id ? 'PUT' : 'POST' }); }, @computed("permissions") permissionsForUpdate(permissions) { let rval = {}; permissions.forEach(p => rval[p.group_name] = p.permission.id); return rval; }, destroy() { return ajax(`/categories/${this.get('id') || this.get('slug')}`, { type: 'DELETE' }); }, addPermission(permission) { this.get("permissions").addObject(permission); this.get("availableGroups").removeObject(permission.group_name); }, removePermission(permission) { this.get("permissions").removeObject(permission); this.get("availableGroups").addObject(permission.group_name); }, @computed permissions() { return Em.A([ { group_name: "everyone", permission: PermissionType.create({id: 1}) }, { group_name: "admins", permission: PermissionType.create({id: 2}) }, { group_name: "crap", permission: PermissionType.create({id: 3}) } ]); }, @computed("topics") latestTopic(topics) { if (topics && topics.length) { return topics[0]; } }, @computed("topics") featuredTopics(topics) { if (topics && topics.length) { return topics.slice(0, Discourse.SiteSettings.category_featured_topics || 2); } }, @computed("id", "topicTrackingState.messageCount") unreadTopics(id) { return this.topicTrackingState.countUnread(id); }, @computed("id", "topicTrackingState.messageCount") newTopics(id) { return this.topicTrackingState.countNew(id); }, setNotification(notification_level) { this.set('notification_level', notification_level); const url = `/category/${this.get('id')}/notifications`; return ajax(url, { data: { notification_level }, type: 'POST' }); }, @computed("id") isUncategorizedCategory(id) { return id === Discourse.Site.currentProp("uncategorized_category_id"); } }); var _uncategorized; Category.reopenClass({ findUncategorized() { _uncategorized = _uncategorized || Category.list().findBy('id', Discourse.Site.currentProp('uncategorized_category_id')); return _uncategorized; }, slugFor(category, separator = "/") { if (!category) return ""; const parentCategory = Em.get(category, 'parentCategory'); let result = ""; if (parentCategory) { result = Category.slugFor(parentCategory) + separator; } const id = Em.get(category, 'id'), slug = Em.get(category, 'slug'); return !slug || slug.trim().length === 0 ? `${result}${id}-category` : result + slug; }, list() { return Discourse.SiteSettings.fixed_category_positions ? Discourse.Site.currentProp('categories') : Discourse.Site.currentProp('sortedCategories'); }, listByActivity() { return Discourse.Site.currentProp('sortedCategories'); }, idMap() { return Discourse.Site.currentProp('categoriesById'); }, findSingleBySlug(slug) { return Category.list().find(c => Category.slugFor(c) === slug); }, findById(id) { if (!id) { return; } return Category.idMap()[id]; }, findByIds(ids) { const categories = []; _.each(ids, id => { const found = Category.findById(id); if (found) { categories.push(found); } }); return categories; }, findBySlug(slug, parentSlug) { const categories = Category.list(); let category; if (parentSlug) { const parentCategory = Category.findSingleBySlug(parentSlug); if (parentCategory) { if (slug === 'none') { return parentCategory; } category = categories.find(item => { return item && item.get('parentCategory') === parentCategory && Category.slugFor(item) === (parentSlug + "/" + slug); }); } } else { category = Category.findSingleBySlug(slug); // If we have a parent category, we need to enforce it if (category && category.get('parentCategory')) return; } // In case the slug didn't work, try to find it by id instead. if (!category) { category = categories.findBy('id', parseInt(slug, 10)); } return category; }, reloadById(id) { return ajax(`/c/${id}/show.json`); }, reloadBySlug(slug, parentSlug) { return parentSlug ? ajax(`/c/${parentSlug}/${slug}/find_by_slug.json`) : ajax(`/c/${slug}/find_by_slug.json`); }, search(term, opts) { var limit = 5; if (opts) { if (opts.limit === 0) { return []; } else if (opts.limit) { limit = opts.limit; } } const emptyTerm = (term === ""); let slugTerm = term; if (!emptyTerm) { term = term.toLowerCase(); slugTerm = term; term = term.replace(/-/g, " "); } const categories = Category.listByActivity(); const length = categories.length; var i; var data = []; const done = () => { return data.length === limit; }; for (i = 0; i < length && !done(); i++) { const category = categories[i]; if ((emptyTerm && !category.get('parent_category_id')) || (!emptyTerm && (category.get('name').toLowerCase().indexOf(term) === 0 || category.get('slug').toLowerCase().indexOf(slugTerm) === 0))) { data.push(category); } } if (!done()) { for (i = 0; i < length && !done(); i++) { const category = categories[i]; if (!emptyTerm && (category.get('name').toLowerCase().indexOf(term) > 0 || category.get('slug').toLowerCase().indexOf(slugTerm) > 0)) { if (data.indexOf(category) === -1) data.push(category); } } } return _.sortBy(data, (category) => { return category.get('read_restricted'); }); } }); export default Category;