category.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. 'use strict';
  2. const Schema = require('warehouse').Schema;
  3. const util = require('hexo-util');
  4. const slugize = util.slugize;
  5. module.exports = ctx => {
  6. const Category = new Schema({
  7. name: {type: String, required: true},
  8. parent: {type: Schema.Types.CUID, ref: 'Category'}
  9. });
  10. Category.virtual('slug').get(function() {
  11. const map = ctx.config.category_map || {};
  12. let name = this.name;
  13. let str = '';
  14. if (!name) return;
  15. if (this.parent) {
  16. const parent = ctx.model('Category').findById(this.parent);
  17. str += `${parent.slug}/`;
  18. }
  19. name = map[name] || name;
  20. str += slugize(name, {transform: ctx.config.filename_case});
  21. return str;
  22. });
  23. Category.virtual('path').get(function() {
  24. let catDir = ctx.config.category_dir;
  25. if (catDir === '/') catDir = '';
  26. if (catDir.length && catDir[catDir.length - 1] !== '/') catDir += '/';
  27. return `${catDir + this.slug}/`;
  28. });
  29. Category.virtual('permalink').get(function() {
  30. return `${ctx.config.url}/${this.path}`;
  31. });
  32. Category.virtual('posts').get(function() {
  33. const PostCategory = ctx.model('PostCategory');
  34. const ids = PostCategory.find({category_id: this._id}).map(item => item.post_id);
  35. return ctx.locals.get('posts').find({
  36. _id: {$in: ids}
  37. });
  38. });
  39. Category.virtual('length').get(function() {
  40. return this.posts.length;
  41. });
  42. // Check whether a category exists
  43. Category.pre('save', data => {
  44. const name = data.name;
  45. const parent = data.parent;
  46. if (!name) return;
  47. const Category = ctx.model('Category');
  48. const cat = Category.findOne({
  49. name,
  50. parent: parent || {$exists: false}
  51. }, {lean: true});
  52. if (cat) {
  53. throw new Error(`Category \`${name}\` has already existed!`);
  54. }
  55. });
  56. // Remove PostCategory references
  57. Category.pre('remove', data => {
  58. const PostCategory = ctx.model('PostCategory');
  59. return PostCategory.remove({category_id: data._id});
  60. });
  61. return Category;
  62. };