@ozdao/martyrs 0.2.473 → 0.2.474

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/dist/{Media-DW8RLbfM.js → Media-_vz04tII.js} +1 -1
  2. package/dist/{Media-y_TX6us_.mjs → Media-sGk7Bp9b.mjs} +1 -1
  3. package/dist/auth.server.js +6 -2
  4. package/dist/auth.server.mjs +6 -2
  5. package/dist/authJwt-CELQKF2s.js +82 -0
  6. package/dist/authJwt-DnXu3BFq.mjs +83 -0
  7. package/dist/builder.js +7 -4
  8. package/dist/builder.mjs +7 -4
  9. package/dist/chats.server.js +1 -1
  10. package/dist/chats.server.mjs +1 -1
  11. package/dist/community.server.js +4 -4
  12. package/dist/community.server.mjs +4 -4
  13. package/dist/events.server.js +4 -4
  14. package/dist/events.server.mjs +4 -4
  15. package/dist/files.server.js +1 -1
  16. package/dist/files.server.mjs +1 -1
  17. package/dist/gallery.server.js +3 -3
  18. package/dist/gallery.server.mjs +3 -3
  19. package/dist/{globals.abac-DT0VjfaZ.js → globals.abac-Bn-4tbX8.js} +110 -16
  20. package/dist/{globals.abac-CvmZM8XG.mjs → globals.abac-DZpTRxKR.mjs} +110 -16
  21. package/dist/globals.server.js +70 -10
  22. package/dist/globals.server.mjs +70 -10
  23. package/dist/{globals.verifier-C_VZYebB.mjs → globals.verifier-BdJxc8-8.mjs} +34 -0
  24. package/dist/{globals.verifier-ChDpCdy_.js → globals.verifier-CKYpYfQl.js} +34 -0
  25. package/dist/{index-CVXl1rB5.js → index-BOmxJQ5W.js} +7 -86
  26. package/dist/{index-Df8vtZx7.mjs → index-C_Fw0Umg.mjs} +7 -86
  27. package/dist/{main-CgmHzhq5.mjs → main-CqMtW7Hq.mjs} +274 -276
  28. package/dist/{main-CCfQH-Dd.js → main-CsGkbSyK.js} +2 -2
  29. package/dist/martyrs/src/components/Select/Select.vue.cjs +4 -4
  30. package/dist/martyrs/src/components/Select/Select.vue.cjs.map +1 -1
  31. package/dist/martyrs/src/components/Select/Select.vue.js +4 -4
  32. package/dist/martyrs/src/components/Select/Select.vue.js.map +1 -1
  33. package/dist/martyrs/src/modules/community/community.client.js +27 -27
  34. package/dist/martyrs/src/modules/community/community.client.js.map +1 -1
  35. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs +2 -3
  36. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs.map +1 -1
  37. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js +2 -3
  38. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js.map +1 -1
  39. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +88 -27
  40. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
  41. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +89 -28
  42. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
  43. package/dist/martyrs/src/modules/orders/store/shopcart.cjs +1 -0
  44. package/dist/martyrs/src/modules/orders/store/shopcart.cjs.map +1 -1
  45. package/dist/martyrs/src/modules/orders/store/shopcart.js +1 -0
  46. package/dist/martyrs/src/modules/orders/store/shopcart.js.map +1 -1
  47. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +19 -0
  48. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs.map +1 -1
  49. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +19 -0
  50. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
  51. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs +1 -0
  52. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs.map +1 -1
  53. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -0
  54. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
  55. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +2 -2
  56. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs.map +1 -1
  57. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
  58. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js.map +1 -1
  59. package/dist/martyrs/src/modules/products/store/categories.cjs +2 -0
  60. package/dist/martyrs/src/modules/products/store/categories.cjs.map +1 -1
  61. package/dist/martyrs/src/modules/products/store/categories.js +2 -0
  62. package/dist/martyrs/src/modules/products/store/categories.js.map +1 -1
  63. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs +30 -24
  64. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs.map +1 -1
  65. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +30 -24
  66. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js.map +1 -1
  67. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs +807 -0
  68. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs.map +1 -0
  69. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +807 -0
  70. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js.map +1 -0
  71. package/dist/martyrs/src/modules/spots/store/spots.cjs +4 -1
  72. package/dist/martyrs/src/modules/spots/store/spots.cjs.map +1 -1
  73. package/dist/martyrs/src/modules/spots/store/spots.js +4 -1
  74. package/dist/martyrs/src/modules/spots/store/spots.js.map +1 -1
  75. package/dist/martyrs.cjs.js +1 -1
  76. package/dist/martyrs.css +1 -1
  77. package/dist/martyrs.es.js +1 -1
  78. package/dist/notifications.server.js +1 -1
  79. package/dist/notifications.server.mjs +1 -1
  80. package/dist/orders.server.js +5 -4
  81. package/dist/orders.server.mjs +5 -4
  82. package/dist/organizations.server.js +120 -47
  83. package/dist/organizations.server.mjs +120 -47
  84. package/dist/{ownership.schema-C0w02Vw1.mjs → ownership.schema-CNCotD3D.mjs} +10 -4
  85. package/dist/{ownership.schema-Ck2H9clB.js → ownership.schema-MxfJlPtq.js} +10 -4
  86. package/dist/products.server.js +415 -149
  87. package/dist/products.server.mjs +415 -149
  88. package/dist/{profile.schema-h61hhB2w.js → profile.schema-BLSuV_VC.js} +0 -4
  89. package/dist/{profile.schema-kP_zKXNt.mjs → profile.schema-BRuvQ7QV.mjs} +0 -4
  90. package/dist/{queryProcessor-CWnMIe2U.mjs → queryProcessor-CVKI651_.mjs} +62 -8
  91. package/dist/{queryProcessor-D6GuKfTV.js → queryProcessor-DSUqSk3I.js} +62 -8
  92. package/dist/rents.server.js +4 -4
  93. package/dist/rents.server.mjs +4 -4
  94. package/dist/spots.server.js +162 -8
  95. package/dist/spots.server.mjs +162 -8
  96. package/dist/style.css +27 -4
  97. package/dist/wallet.server.js +2 -2
  98. package/dist/wallet.server.mjs +2 -2
  99. package/package.json +1 -1
  100. package/src/builder/rspack/rspack.config.base.js +1 -1
  101. package/src/builder/rspack/rspack.config.client.js +13 -5
  102. package/src/components/Select/Select.vue +4 -2
  103. package/src/modules/auth/models/user.model.js +4 -1
  104. package/src/modules/community/components/sections/HotPosts.vue +1 -1
  105. package/src/modules/globals/controllers/classes/globals.abac.js +148 -23
  106. package/src/modules/globals/controllers/classes/globals.validator.js +37 -0
  107. package/src/modules/globals/controllers/classes/globals.verifier.js +2 -0
  108. package/src/modules/globals/controllers/policies/globals.policies.js +91 -74
  109. package/src/modules/globals/controllers/utils/queryProcessor.js +59 -11
  110. package/src/modules/globals/models/schemas/ownership.schema.js +11 -6
  111. package/src/modules/globals/models/schemas/profile.schema.js +0 -4
  112. package/src/modules/music/components/layouts/MusicLayout.vue +10 -58
  113. package/src/modules/music/components/pages/MusicHome.vue +5 -5
  114. package/src/modules/orders/components/pages/OrderCreate.vue +85 -12
  115. package/src/modules/orders/controllers/orders.controller.js +3 -0
  116. package/src/modules/orders/store/shopcart.js +1 -0
  117. package/src/modules/organizations/models/schemas/accesses.schema.js +18 -0
  118. package/src/modules/organizations/policies/organizations.policies.js +117 -61
  119. package/src/modules/products/components/pages/CategoryEdit.vue +27 -2
  120. package/src/modules/products/components/pages/Product.vue +1 -0
  121. package/src/modules/products/components/pages/ProductEdit.vue +2 -2
  122. package/src/modules/products/controllers/categories.controller.js +297 -133
  123. package/src/modules/products/middlewares/categories.verifier.js +177 -0
  124. package/src/modules/products/models/category.model.js +12 -14
  125. package/src/modules/products/routes/categories.routes.js +50 -11
  126. package/src/modules/products/store/categories.js +2 -0
  127. package/src/modules/spots/components/pages/SpotEdit.vue +21 -17
  128. package/src/modules/spots/components/sections/WorktimeEdit.vue +840 -0
  129. package/src/modules/spots/controllers/queries/getIsOpenNowStage.js +109 -0
  130. package/src/modules/spots/controllers/spots.controller.js +2 -1
  131. package/src/modules/spots/models/spot.model.js +59 -13
  132. package/src/modules/spots/store/spots.js +4 -1
  133. package/src/modules/products/middlewares/index.js +0 -11
  134. package/src/modules/products/middlewares/verifyCategory.js +0 -25
@@ -1,10 +1,18 @@
1
1
  import { g as getDefaultExportFromCjs } from "./_commonjsHelpers-CUmg6egw.mjs";
2
- import { r as requireOwnership_schema } from "./ownership.schema-C0w02Vw1.mjs";
2
+ import { r as requireOwnership_schema } from "./ownership.schema-CNCotD3D.mjs";
3
+ import { r as requireCommon_schema } from "./common.schema-C2m3O1XY.mjs";
4
+ import { r as requireMetadata_schema } from "./metadata.schema--tle-GU8.mjs";
5
+ import { r as requireEngagement_schema } from "./engagement.schema-DnDD7Bn3.mjs";
3
6
  import require$$0 from "uuid";
4
7
  import require$$0$1 from "mongoose";
5
8
  import "path";
6
9
  import require$$3 from "openai";
7
- import { r as requireQueryProcessor } from "./queryProcessor-CWnMIe2U.mjs";
10
+ import { r as requireQueryProcessor } from "./queryProcessor-CVKI651_.mjs";
11
+ import { r as requireGlobals_logger } from "./globals.logger-DusiFsxN.mjs";
12
+ import { r as requireGlobals_cache } from "./globals.cache-BT6q3vOf.mjs";
13
+ import { r as requireGlobals_verifier, a as requireGlobals_validator } from "./globals.verifier-BdJxc8-8.mjs";
14
+ import { r as requireAuthJwt } from "./authJwt-DnXu3BFq.mjs";
15
+ import { r as requireGlobals_abac } from "./globals.abac-DZpTRxKR.mjs";
8
16
  var product_model;
9
17
  var hasRequiredProduct_model;
10
18
  function requireProduct_model() {
@@ -130,25 +138,21 @@ function requireCategory_model() {
130
138
  const CategorySchema = new db.mongoose.Schema({
131
139
  name: { type: String, required: true, trim: true },
132
140
  description: { type: String, trim: true },
133
- photo: {
134
- type: String
135
- },
136
- status: {
137
- type: String,
138
- enum: ["draft", "internal", "published", "removed"],
139
- default: "draft",
140
- required: true
141
- },
141
+ photo: { type: String },
142
142
  order: { type: Number, required: true },
143
- url: { type: String, required: true, trim: true },
143
+ url: { type: String, required: true, trim: true, unique: true },
144
144
  parent: { type: db.mongoose.Schema.Types.ObjectId, ref: "Category" },
145
145
  localization: { type: Array },
146
146
  filters: { type: Array }
147
147
  }, {
148
148
  timestamps: { currentTime: () => Date.now() }
149
149
  });
150
+ requireCommon_schema()(CategorySchema, db);
151
+ requireOwnership_schema()(CategorySchema, db);
152
+ requireMetadata_schema()(CategorySchema, db);
153
+ requireEngagement_schema()(CategorySchema, db);
150
154
  CategorySchema.index({ parent: 1 });
151
- CategorySchema.index({ "owner.target": 1, "creator.target": 1 });
155
+ CategorySchema.index({ name: 1 });
152
156
  const Category = db.mongoose.model("Category", CategorySchema, "categories");
153
157
  return Category;
154
158
  };
@@ -630,78 +634,61 @@ var hasRequiredCategories_controller;
630
634
  function requireCategories_controller() {
631
635
  if (hasRequiredCategories_controller) return categories_controller;
632
636
  hasRequiredCategories_controller = 1;
637
+ const globalsQuery = requireQueryProcessor();
638
+ const Logger = requireGlobals_logger();
639
+ const Cache = requireGlobals_cache();
633
640
  const controllerFactory = (db) => {
634
641
  const Category = db.category;
642
+ const logger = new Logger(db);
643
+ const cache = new Cache();
635
644
  return {
636
645
  async read(req, res) {
637
646
  try {
638
- let buildAdjacencyTree = function(categories, sortParam2, sortOrder2) {
639
- const categoryMap = /* @__PURE__ */ new Map();
640
- categories.forEach((category) => {
641
- categoryMap.set(category._id.toString(), {
642
- ...category,
643
- children: []
644
- });
645
- });
646
- const rootCategories = [];
647
- categories.forEach((category) => {
648
- const categoryWithChildren = categoryMap.get(category._id.toString());
649
- if (category.parent && categoryMap.has(category.parent.toString())) {
650
- const parentCategory = categoryMap.get(category.parent.toString());
651
- parentCategory.children.push(categoryWithChildren);
652
- } else if (!category.parent) {
653
- rootCategories.push(categoryWithChildren);
654
- }
655
- });
656
- function sortCategories(nodes) {
657
- if (!nodes || nodes.length === 0) {
658
- return nodes;
659
- }
660
- nodes.sort((a, b) => {
661
- const valueA = a[sortParam2] ?? (sortParam2 === "order" ? Number.MAX_SAFE_INTEGER : "");
662
- const valueB = b[sortParam2] ?? (sortParam2 === "order" ? Number.MAX_SAFE_INTEGER : "");
663
- if (typeof valueA === "number" && typeof valueB === "number") {
664
- return sortOrder2 === "asc" ? valueA - valueB : valueB - valueA;
665
- } else {
666
- const stringA = String(valueA);
667
- const stringB = String(valueB);
668
- return sortOrder2 === "asc" ? stringA.localeCompare(stringB) : stringB.localeCompare(stringA);
669
- }
670
- });
671
- nodes.forEach((node) => {
672
- if (node.children && node.children.length > 0) {
673
- sortCategories(node.children);
674
- }
675
- });
676
- return nodes;
677
- }
678
- return sortCategories(rootCategories);
679
- };
680
- let {
647
+ const {
681
648
  parent,
682
649
  url,
683
650
  search,
684
- sortParam = "order",
685
- sortOrder = "asc",
686
- skip = 0,
687
- limit = 10,
688
- excludeChildren = "true",
689
- rootOnly = false
690
- } = req.query;
651
+ sortParam,
652
+ sortOrder,
653
+ skip,
654
+ limit,
655
+ excludeChildren,
656
+ rootOnly,
657
+ type
658
+ } = req.verifiedQuery;
659
+ const cacheKey = JSON.stringify(req.verifiedQuery);
660
+ let cachedResult = await cache.get(cacheKey);
661
+ if (cachedResult) {
662
+ return res.status(200).json(cachedResult);
663
+ }
691
664
  const matchStage = {
692
665
  ...req.query.status && { status: req.query.status },
693
- ...req.query.url && { url: req.query.url },
666
+ ...url && { url },
694
667
  ...search && { name: { $regex: search, $options: "i" } },
695
668
  ...parent ? { parent: new db.mongoose.Types.ObjectId(parent) } : {},
696
669
  ...rootOnly === "true" && !search ? { parent: null } : {}
697
670
  };
698
- console.log("matchStage", matchStage);
699
- if (search) excludeChildren = "true";
671
+ if (type === "platform") {
672
+ matchStage["owner.type"] = "platform";
673
+ } else if (type === "organization" && req.query.organizationId) {
674
+ matchStage["owner.type"] = "organization";
675
+ matchStage["owner.target"] = new db.mongoose.Types.ObjectId(req.query.organizationId);
676
+ }
677
+ if (search) {
678
+ excludeChildren = "true";
679
+ }
700
680
  const pipeline = [
701
681
  { $match: matchStage },
682
+ globalsQuery.getCreatorUserLookupStage(),
683
+ globalsQuery.getCreatorOrganizationLookupStage(),
684
+ // For owner
685
+ globalsQuery.getOwnerUserLookupStage(),
686
+ globalsQuery.getOwnerOrganizationLookupStage(),
687
+ globalsQuery.getAddFieldsCreatorOwnerStage(),
702
688
  { $sort: { [sortParam]: sortOrder === "asc" ? 1 : -1 } },
703
689
  { $skip: Number(skip) },
704
- { $limit: Number(limit) }
690
+ { $limit: Number(limit) },
691
+ globalsQuery.removeTempPropeties()
705
692
  ];
706
693
  if (excludeChildren !== "true") {
707
694
  pipeline.push({
@@ -716,69 +703,106 @@ function requireCategories_controller() {
716
703
  });
717
704
  }
718
705
  const results = await Category.aggregate(pipeline);
706
+ let response;
719
707
  if (excludeChildren === "true") {
720
- console.log(results);
721
- res.status(200).json(results);
722
- return;
723
- }
724
- const allCategories = [];
725
- results.forEach((doc) => {
726
- const category = { ...doc };
727
- delete category.allDescendants;
728
- allCategories.push(category);
729
- if (doc.allDescendants && doc.allDescendants.length > 0) {
730
- allCategories.push(...doc.allDescendants);
731
- }
732
- });
733
- const uniqueCategories = Array.from(
734
- new Map(allCategories.map((item) => [item._id.toString(), item])).values()
735
- );
736
- const tree = buildAdjacencyTree(uniqueCategories, sortParam, sortOrder);
737
- if (rootOnly === "true") {
738
- res.json(tree);
708
+ response = results;
739
709
  } else {
740
- const requestedCategoryIds = results.map((r) => r._id.toString());
741
- const filteredTree = tree.filter(
742
- (category) => requestedCategoryIds.includes(category._id.toString())
710
+ const allCategories = [];
711
+ results.forEach((doc) => {
712
+ const category = { ...doc };
713
+ delete category.allDescendants;
714
+ allCategories.push(category);
715
+ if (doc.allDescendants && doc.allDescendants.length > 0) {
716
+ allCategories.push(...doc.allDescendants);
717
+ }
718
+ });
719
+ const uniqueCategories = Array.from(
720
+ new Map(allCategories.map((item) => [item._id.toString(), item])).values()
743
721
  );
744
- res.status(200).json(filteredTree);
722
+ const tree = buildAdjacencyTree(uniqueCategories, sortParam, sortOrder);
723
+ if (rootOnly === "true") {
724
+ response = tree;
725
+ } else {
726
+ const requestedCategoryIds = results.map((r) => r._id.toString());
727
+ response = tree.filter(
728
+ (category) => requestedCategoryIds.includes(category._id.toString())
729
+ );
730
+ }
731
+ }
732
+ const tags = ["categories"];
733
+ if (type === "organization" && req.query.organizationId) {
734
+ tags.push(`organization_${req.query.organizationId}`);
735
+ }
736
+ for (const cat of response) {
737
+ if (cat._id) {
738
+ tags.push(`category_${cat._id}`);
739
+ }
745
740
  }
741
+ await cache.setWithTags(cacheKey, response, tags);
742
+ res.status(200).json(response);
746
743
  } catch (err) {
744
+ logger.error(`Error reading categories: ${err.message}`);
747
745
  res.status(500).json({ message: err.message });
748
746
  }
749
747
  },
750
748
  async create(req, res) {
751
749
  try {
750
+ const categoryData = req.verifiedBody;
751
+ if (!categoryData.creator && req.userId) {
752
+ categoryData.creator = {
753
+ type: "user",
754
+ target: req.userId
755
+ };
756
+ }
757
+ if (!categoryData.owner) {
758
+ if (req.query.organizationId) {
759
+ categoryData.owner = {
760
+ type: "organization",
761
+ target: req.query.organizationId
762
+ };
763
+ } else {
764
+ categoryData.owner = {
765
+ type: "platform",
766
+ target: null
767
+ };
768
+ }
769
+ }
752
770
  const highestOrder = await Category.findOne().sort("-order");
753
771
  const order = highestOrder ? highestOrder.order + 1 : 1;
754
- const category = new Category({ ...req.body, order });
755
- if (req.body.parent) {
772
+ const category = new Category({
773
+ ...categoryData,
774
+ order
775
+ });
776
+ if (categoryData.parent) {
756
777
  const parent = await Category.findByIdAndUpdate(
757
- req.body.parent,
778
+ categoryData.parent,
758
779
  { $push: { children: category._id } },
759
780
  { new: true }
760
781
  );
761
782
  if (!parent) throw new Error("Parent category not found");
762
783
  category.parent = parent._id;
763
784
  }
764
- if (req.body.children && req.body.children.length > 0) {
785
+ if (categoryData.children && categoryData.children.length > 0) {
765
786
  await Category.updateMany(
766
- { _id: { $in: req.body.children } },
787
+ { _id: { $in: categoryData.children } },
767
788
  { $set: { parent: category._id } }
768
789
  );
769
790
  }
770
791
  await category.save();
792
+ await cache.delByTags(["categories"]);
793
+ if (category.owner.type === "organization") {
794
+ await cache.delByTag(`organization_${category.owner.target}`);
795
+ }
796
+ logger.info(`Category created: ${category._id}`);
771
797
  res.status(201).json(category);
772
798
  } catch (err) {
799
+ logger.error(`Error creating category: ${err.message}`);
773
800
  res.status(err.message === "Parent category not found" ? 404 : 500).json({ message: err.message });
774
801
  }
775
802
  },
776
803
  async update(req, res) {
777
804
  try {
778
- const category = req.body;
779
- if (!category || !category._id) {
780
- return res.status(400).json({ message: "Category ID is required" });
781
- }
805
+ const category = req.verifiedBody;
782
806
  const updatedCategory = await Category.findByIdAndUpdate(
783
807
  category._id,
784
808
  { $set: category },
@@ -787,15 +811,21 @@ function requireCategories_controller() {
787
811
  if (!updatedCategory) {
788
812
  return res.status(404).json({ message: "Category not found" });
789
813
  }
814
+ await cache.delByTag(`category_${category._id}`);
815
+ await cache.delByTags(["categories"]);
816
+ if (updatedCategory.owner && updatedCategory.owner.type === "organization") {
817
+ await cache.delByTag(`organization_${updatedCategory.owner.target}`);
818
+ }
819
+ logger.info(`Category updated: ${category._id}`);
790
820
  res.status(200).json(updatedCategory);
791
821
  } catch (err) {
792
- console.error("Category update error:", err);
822
+ logger.error(`Category update error: ${err.message}`);
793
823
  res.status(500).json({ message: "Failed to update category" });
794
824
  }
795
825
  },
796
826
  async updateOrder(req, res) {
797
827
  try {
798
- const { categories } = req.body;
828
+ const { categories } = req.verifiedBody;
799
829
  const bulkOps = categories.map((category) => ({
800
830
  updateOne: {
801
831
  filter: { _id: category._id },
@@ -808,18 +838,44 @@ function requireCategories_controller() {
808
838
  }
809
839
  }));
810
840
  await Category.bulkWrite(bulkOps);
811
- const updatedCategories = await Category.find().sort({ order: "asc" }).lean();
812
- res.status(200).json(updatedCategories);
841
+ const categoryIds = categories.map((cat) => cat._id);
842
+ const organizationIds = /* @__PURE__ */ new Set();
843
+ const updatedCategories = await Category.find({ _id: { $in: categoryIds } }).lean();
844
+ updatedCategories.forEach((cat) => {
845
+ if (cat.owner && cat.owner.type === "organization") {
846
+ organizationIds.add(cat.owner.target.toString());
847
+ }
848
+ });
849
+ await cache.delByTags(["categories"]);
850
+ for (const catId of categoryIds) {
851
+ await cache.delByTag(`category_${catId}`);
852
+ }
853
+ for (const orgId of organizationIds) {
854
+ await cache.delByTag(`organization_${orgId}`);
855
+ }
856
+ let query = {};
857
+ if (req.query.type === "platform") {
858
+ query = { "owner.type": "platform" };
859
+ } else if (req.query.type === "organization" && req.query.organizationId) {
860
+ query = {
861
+ "owner.type": "organization",
862
+ "owner.target": new db.mongoose.Types.ObjectId(req.query.organizationId)
863
+ };
864
+ }
865
+ const result = await Category.find(query).sort({ order: "asc" }).lean();
866
+ logger.info(`Categories order updated: ${categoryIds.join(", ")}`);
867
+ res.status(200).json(result);
813
868
  } catch (err) {
814
- console.error("Category update error:", err);
815
- res.status(500).json({ message: "Failed to update categories" });
869
+ logger.error(`Category order update error: ${err.message}`);
870
+ res.status(500).json({ message: "Failed to update categories order" });
816
871
  }
817
872
  },
818
873
  async delete(req, res) {
819
874
  try {
820
- const category = await Category.findOne({ url: req.body.url });
821
- if (!category) {
822
- return res.status(404).json({ message: "Category not found" });
875
+ const category = req.currentResource;
876
+ let ownerOrgId = null;
877
+ if (category.owner && category.owner.type === "organization") {
878
+ ownerOrgId = category.owner.target;
823
879
  }
824
880
  const result = await Category.aggregate([
825
881
  { $match: { _id: category._id } },
@@ -837,72 +893,282 @@ function requireCategories_controller() {
837
893
  }
838
894
  ]);
839
895
  const idsToDelete = [category._id, ...(result[0]?.descendants || []).map(({ _id }) => _id)];
896
+ const categoryIdsTags = idsToDelete.map((id) => `category_${id}`);
840
897
  await Category.deleteMany({ _id: { $in: idsToDelete } });
898
+ await cache.delByTags(["categories"]);
899
+ await cache.delByTags(categoryIdsTags);
900
+ if (ownerOrgId) {
901
+ await cache.delByTag(`organization_${ownerOrgId}`);
902
+ }
903
+ logger.info(`Category and its subcategories deleted: ${category.url}`);
841
904
  res.status(200).json({ message: "Category and its subcategories deleted successfully" });
842
905
  } catch (err) {
843
- console.error(err);
906
+ logger.error(`Error deleting category: ${err.message}`);
844
907
  res.status(500).json({ message: err.message || "Internal server error" });
845
908
  }
846
909
  }
847
910
  };
911
+ function buildAdjacencyTree(categories, sortParam, sortOrder) {
912
+ const categoryMap = /* @__PURE__ */ new Map();
913
+ categories.forEach((category) => {
914
+ categoryMap.set(category._id.toString(), {
915
+ ...category,
916
+ children: []
917
+ });
918
+ });
919
+ const rootCategories = [];
920
+ categories.forEach((category) => {
921
+ const categoryWithChildren = categoryMap.get(category._id.toString());
922
+ if (category.parent && categoryMap.has(category.parent.toString())) {
923
+ const parentCategory = categoryMap.get(category.parent.toString());
924
+ parentCategory.children.push(categoryWithChildren);
925
+ } else if (!category.parent) {
926
+ rootCategories.push(categoryWithChildren);
927
+ }
928
+ });
929
+ function sortCategories(nodes) {
930
+ if (!nodes || nodes.length === 0) {
931
+ return nodes;
932
+ }
933
+ nodes.sort((a, b) => {
934
+ const valueA = a[sortParam] ?? (sortParam === "order" ? Number.MAX_SAFE_INTEGER : "");
935
+ const valueB = b[sortParam] ?? (sortParam === "order" ? Number.MAX_SAFE_INTEGER : "");
936
+ if (typeof valueA === "number" && typeof valueB === "number") {
937
+ return sortOrder === "asc" ? valueA - valueB : valueB - valueA;
938
+ } else {
939
+ const stringA = String(valueA);
940
+ const stringB = String(valueB);
941
+ return sortOrder === "asc" ? stringA.localeCompare(stringB) : stringB.localeCompare(stringA);
942
+ }
943
+ });
944
+ nodes.forEach((node) => {
945
+ if (node.children && node.children.length > 0) {
946
+ sortCategories(node.children);
947
+ }
948
+ });
949
+ return nodes;
950
+ }
951
+ return sortCategories(rootCategories);
952
+ }
848
953
  };
849
954
  categories_controller = controllerFactory;
850
955
  return categories_controller;
851
956
  }
852
- var verifyCategory;
853
- var hasRequiredVerifyCategory;
854
- function requireVerifyCategory() {
855
- if (hasRequiredVerifyCategory) return verifyCategory;
856
- hasRequiredVerifyCategory = 1;
857
- const middlewareFactory = (db) => {
858
- const Category = db.category;
859
- const checkCategoryExistOrNot = async (req, res, next) => {
860
- try {
861
- const category = await Category.findOne({ url: req.body.url });
862
- if (category) {
863
- res.status(400).send({ message: "Failed! Category with this URL is already in use!" });
864
- return;
865
- }
866
- next();
867
- } catch (err) {
868
- res.status(500).send({ message: err });
957
+ var categories_verifier;
958
+ var hasRequiredCategories_verifier;
959
+ function requireCategories_verifier() {
960
+ if (hasRequiredCategories_verifier) return categories_verifier;
961
+ hasRequiredCategories_verifier = 1;
962
+ const Verifier = requireGlobals_verifier();
963
+ const Validator = requireGlobals_validator();
964
+ categories_verifier = function(db) {
965
+ const queryValidatorConfig = {
966
+ parent: { allowed: true, validator: Validator.schema().string() },
967
+ url: { allowed: true, validator: Validator.schema().string() },
968
+ search: { allowed: true, validator: Validator.schema().string() },
969
+ sortParam: { allowed: true, validator: Validator.schema().string().oneOf(["order", "name", "createdAt", "updatedAt"]), default: "order" },
970
+ sortOrder: { allowed: true, validator: Validator.schema().string().oneOf(["asc", "desc"]), default: "asc" },
971
+ skip: { allowed: true, validator: Validator.schema().number().integer().min(0), default: 0 },
972
+ limit: { allowed: true, validator: Validator.schema().number().integer().min(1).max(100), default: 10 },
973
+ excludeChildren: { allowed: true, validator: Validator.schema().string().oneOf(["true", "false"]), default: "true" },
974
+ rootOnly: { allowed: true, validator: Validator.schema().string().oneOf(["true", "false"]), default: "false" },
975
+ status: { allowed: true, validator: Validator.schema().string().oneOf(["draft", "internal", "published", "removed"]) },
976
+ type: { allowed: true, validator: Validator.schema().string().oneOf(["platform", "organization", "all"]), default: "all" },
977
+ organizationId: { allowed: true, validator: Validator.schema().string() }
978
+ };
979
+ const bodyValidatorConfig = {
980
+ _id: { allowed: true, validator: Validator.schema().string() },
981
+ name: { allowed: true, validator: Validator.schema().string().required() },
982
+ description: { allowed: true, validator: Validator.schema().string() },
983
+ photo: { allowed: true, validator: Validator.schema().string() },
984
+ status: { allowed: true, validator: Validator.schema().string().oneOf(["draft", "internal", "published", "removed"]), default: "draft" },
985
+ url: { allowed: true, validator: Validator.schema().string().required() },
986
+ parent: { allowed: true, validator: Validator.schema().oneOfTypes(["string", "null"]) },
987
+ localization: { allowed: true },
988
+ filters: { allowed: true },
989
+ owner: { allowed: true, validator: Validator.schema().object({
990
+ type: Validator.schema().string().oneOf(["platform", "organization"]).required(),
991
+ target: Validator.schema().string()
992
+ }) },
993
+ creator: { allowed: true, validator: Validator.schema().object({
994
+ type: Validator.schema().string().oneOf(["user", "organization"]).required(),
995
+ target: Validator.schema().string()
996
+ }) },
997
+ children: { allowed: true, validator: Validator.schema().array() },
998
+ order: { allowed: true, validator: Validator.schema().number() }
999
+ };
1000
+ const orderBodyValidatorConfig = {
1001
+ categories: {
1002
+ allowed: true,
1003
+ validator: Validator.schema().array().required(),
1004
+ default: []
869
1005
  }
870
1006
  };
871
- return {
872
- checkCategoryExistOrNot
1007
+ const deleteBodyValidatorConfig = {
1008
+ url: {
1009
+ allowed: true,
1010
+ validator: Validator.schema().string().required()
1011
+ }
873
1012
  };
874
- };
875
- verifyCategory = middlewareFactory;
876
- return verifyCategory;
877
- }
878
- var middlewares;
879
- var hasRequiredMiddlewares;
880
- function requireMiddlewares() {
881
- if (hasRequiredMiddlewares) return middlewares;
882
- hasRequiredMiddlewares = 1;
883
- const middlewareIndexFactory = (db) => {
884
- const verifyCategory2 = requireVerifyCategory()(db);
1013
+ const queryVerifier = new Verifier(queryValidatorConfig);
1014
+ const bodyVerifier = new Verifier(bodyValidatorConfig);
1015
+ const orderBodyVerifier = new Verifier(orderBodyValidatorConfig);
1016
+ const deleteBodyVerifier = new Verifier(deleteBodyValidatorConfig);
885
1017
  return {
886
- verifyCategory: verifyCategory2
1018
+ // Верификация параметров запроса
1019
+ verifyQuery(req, res, next) {
1020
+ const verification = queryVerifier.verify(req.query);
1021
+ if (!verification.isValid) {
1022
+ return res.status(400).json({
1023
+ errors: verification.verificationErrors,
1024
+ message: "Invalid query parameters"
1025
+ });
1026
+ }
1027
+ req.verifiedQuery = verification.verifiedData;
1028
+ next();
1029
+ },
1030
+ // Верификация тела запроса для создания/обновления категории
1031
+ verifyBody(req, res, next) {
1032
+ const verification = bodyVerifier.verify(req.body);
1033
+ if (!verification.isValid) {
1034
+ return res.status(400).json({
1035
+ errors: verification.verificationErrors,
1036
+ message: "Invalid request data"
1037
+ });
1038
+ }
1039
+ req.verifiedBody = verification.verifiedData;
1040
+ next();
1041
+ },
1042
+ // Верификация тела запроса для обновления порядка категорий
1043
+ verifyOrderBody(req, res, next) {
1044
+ const verification = orderBodyVerifier.verify(req.body);
1045
+ if (!verification.isValid) {
1046
+ return res.status(400).json({
1047
+ errors: verification.verificationErrors,
1048
+ message: "Invalid request data"
1049
+ });
1050
+ }
1051
+ req.verifiedBody = verification.verifiedData;
1052
+ next();
1053
+ },
1054
+ // Верификация тела запроса для удаления категории
1055
+ verifyDeleteBody(req, res, next) {
1056
+ const verification = deleteBodyVerifier.verify(req.body);
1057
+ if (!verification.isValid) {
1058
+ return res.status(400).json({
1059
+ errors: verification.verificationErrors,
1060
+ message: "Invalid request data"
1061
+ });
1062
+ }
1063
+ req.verifiedBody = verification.verifiedData;
1064
+ next();
1065
+ },
1066
+ // Проверка на существование категории с тем же URL (для создания)
1067
+ async checkCategoryExistOrNot(req, res, next) {
1068
+ try {
1069
+ if (!req.verifiedBody.url) {
1070
+ return res.status(400).json({ message: "URL is required" });
1071
+ }
1072
+ const existingCategory = await db.category.findOne({ url: req.verifiedBody.url });
1073
+ if (existingCategory) {
1074
+ return res.status(409).json({
1075
+ message: "Category with this URL already exists",
1076
+ category: existingCategory
1077
+ });
1078
+ }
1079
+ next();
1080
+ } catch (error) {
1081
+ res.status(500).json({ message: error.message });
1082
+ }
1083
+ },
1084
+ // Загрузка категории для проверки ABAC (для обновления и удаления)
1085
+ async loadCategoryForUpdate(req, res, next) {
1086
+ try {
1087
+ const categoryId = req.verifiedBody._id;
1088
+ if (!categoryId) {
1089
+ return res.status(400).json({ message: "Category ID is required" });
1090
+ }
1091
+ const category = await db.category.findById(categoryId).lean();
1092
+ if (!category) {
1093
+ return res.status(404).json({ message: "Category not found" });
1094
+ }
1095
+ req.currentResource = category;
1096
+ next();
1097
+ } catch (error) {
1098
+ res.status(500).json({ message: error.message });
1099
+ }
1100
+ },
1101
+ // Загрузка категории по URL для удаления
1102
+ async loadCategoryForDelete(req, res, next) {
1103
+ try {
1104
+ const url = req.verifiedBody.url;
1105
+ if (!url) {
1106
+ return res.status(400).json({ message: "Category URL is required" });
1107
+ }
1108
+ const category = await db.category.findOne({ url }).lean();
1109
+ if (!category) {
1110
+ return res.status(404).json({ message: "Category not found" });
1111
+ }
1112
+ req.currentResource = category;
1113
+ next();
1114
+ } catch (error) {
1115
+ res.status(500).json({ message: error.message });
1116
+ }
1117
+ }
887
1118
  };
888
1119
  };
889
- middlewares = middlewareIndexFactory;
890
- return middlewares;
1120
+ return categories_verifier;
891
1121
  }
892
1122
  var hasRequiredCategories_routes;
893
1123
  function requireCategories_routes() {
894
1124
  if (hasRequiredCategories_routes) return categories_routes.exports;
895
1125
  hasRequiredCategories_routes = 1;
896
1126
  const controllerFactory = requireCategories_controller();
897
- const middlewareFactoryProducts = requireMiddlewares();
1127
+ const verifierFactory = requireCategories_verifier();
1128
+ const jwtFactory = requireAuthJwt();
1129
+ const { getInstance } = requireGlobals_abac();
898
1130
  categories_routes.exports = function(app, db) {
1131
+ const jwt = jwtFactory(db);
1132
+ const verifier = verifierFactory(db);
1133
+ const abac = getInstance(db);
899
1134
  const controller = controllerFactory(db);
900
- const { verifyCategory: verifyCategory2 } = middlewareFactoryProducts(db);
901
- app.get("/api/categories", controller.read);
902
- app.post("/api/categories/create", [verifyCategory2.checkCategoryExistOrNot], controller.create);
903
- app.post("/api/categories/update", controller.update);
904
- app.post("/api/categories/updateOrder", controller.updateOrder);
905
- app.post("/api/categories/delete", controller.delete);
1135
+ app.get(
1136
+ "/api/categories",
1137
+ jwt.verifyToken(true),
1138
+ verifier.verifyQuery,
1139
+ controller.read
1140
+ );
1141
+ app.post(
1142
+ "/api/categories/create",
1143
+ jwt.verifyToken(),
1144
+ verifier.verifyBody,
1145
+ verifier.checkCategoryExistOrNot,
1146
+ abac.middleware("category", "create"),
1147
+ controller.create
1148
+ );
1149
+ app.post(
1150
+ "/api/categories/update",
1151
+ jwt.verifyToken(),
1152
+ verifier.verifyBody,
1153
+ verifier.loadCategoryForUpdate,
1154
+ abac.middleware("category", "edit"),
1155
+ controller.update
1156
+ );
1157
+ app.post(
1158
+ "/api/categories/updateOrder",
1159
+ jwt.verifyToken(),
1160
+ verifier.verifyOrderBody,
1161
+ abac.middleware("category", "edit"),
1162
+ controller.updateOrder
1163
+ );
1164
+ app.post(
1165
+ "/api/categories/delete",
1166
+ jwt.verifyToken(),
1167
+ verifier.verifyDeleteBody,
1168
+ verifier.loadCategoryForDelete,
1169
+ abac.middleware("category", "delete"),
1170
+ controller.delete
1171
+ );
906
1172
  };
907
1173
  categories_routes.exports.controllerFactory = controllerFactory;
908
1174
  return categories_routes.exports;