category.js 1.9 KB

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