@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.
- package/dist/{Media-DW8RLbfM.js → Media-_vz04tII.js} +1 -1
- package/dist/{Media-y_TX6us_.mjs → Media-sGk7Bp9b.mjs} +1 -1
- package/dist/auth.server.js +6 -2
- package/dist/auth.server.mjs +6 -2
- package/dist/authJwt-CELQKF2s.js +82 -0
- package/dist/authJwt-DnXu3BFq.mjs +83 -0
- package/dist/builder.js +7 -4
- package/dist/builder.mjs +7 -4
- package/dist/chats.server.js +1 -1
- package/dist/chats.server.mjs +1 -1
- package/dist/community.server.js +4 -4
- package/dist/community.server.mjs +4 -4
- package/dist/events.server.js +4 -4
- package/dist/events.server.mjs +4 -4
- package/dist/files.server.js +1 -1
- package/dist/files.server.mjs +1 -1
- package/dist/gallery.server.js +3 -3
- package/dist/gallery.server.mjs +3 -3
- package/dist/{globals.abac-DT0VjfaZ.js → globals.abac-Bn-4tbX8.js} +110 -16
- package/dist/{globals.abac-CvmZM8XG.mjs → globals.abac-DZpTRxKR.mjs} +110 -16
- package/dist/globals.server.js +70 -10
- package/dist/globals.server.mjs +70 -10
- package/dist/{globals.verifier-C_VZYebB.mjs → globals.verifier-BdJxc8-8.mjs} +34 -0
- package/dist/{globals.verifier-ChDpCdy_.js → globals.verifier-CKYpYfQl.js} +34 -0
- package/dist/{index-CVXl1rB5.js → index-BOmxJQ5W.js} +7 -86
- package/dist/{index-Df8vtZx7.mjs → index-C_Fw0Umg.mjs} +7 -86
- package/dist/{main-CgmHzhq5.mjs → main-CqMtW7Hq.mjs} +274 -276
- package/dist/{main-CCfQH-Dd.js → main-CsGkbSyK.js} +2 -2
- package/dist/martyrs/src/components/Select/Select.vue.cjs +4 -4
- package/dist/martyrs/src/components/Select/Select.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Select/Select.vue.js +4 -4
- package/dist/martyrs/src/components/Select/Select.vue.js.map +1 -1
- package/dist/martyrs/src/modules/community/community.client.js +27 -27
- package/dist/martyrs/src/modules/community/community.client.js.map +1 -1
- package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs +2 -3
- package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js +2 -3
- package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +88 -27
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +89 -28
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
- package/dist/martyrs/src/modules/orders/store/shopcart.cjs +1 -0
- package/dist/martyrs/src/modules/orders/store/shopcart.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/store/shopcart.js +1 -0
- package/dist/martyrs/src/modules/orders/store/shopcart.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +19 -0
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +19 -0
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs +1 -0
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -0
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +2 -2
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/store/categories.cjs +2 -0
- package/dist/martyrs/src/modules/products/store/categories.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/store/categories.js +2 -0
- package/dist/martyrs/src/modules/products/store/categories.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs +30 -24
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +30 -24
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs +807 -0
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs.map +1 -0
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +807 -0
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js.map +1 -0
- package/dist/martyrs/src/modules/spots/store/spots.cjs +4 -1
- package/dist/martyrs/src/modules/spots/store/spots.cjs.map +1 -1
- package/dist/martyrs/src/modules/spots/store/spots.js +4 -1
- package/dist/martyrs/src/modules/spots/store/spots.js.map +1 -1
- package/dist/martyrs.cjs.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/notifications.server.js +1 -1
- package/dist/notifications.server.mjs +1 -1
- package/dist/orders.server.js +5 -4
- package/dist/orders.server.mjs +5 -4
- package/dist/organizations.server.js +120 -47
- package/dist/organizations.server.mjs +120 -47
- package/dist/{ownership.schema-C0w02Vw1.mjs → ownership.schema-CNCotD3D.mjs} +10 -4
- package/dist/{ownership.schema-Ck2H9clB.js → ownership.schema-MxfJlPtq.js} +10 -4
- package/dist/products.server.js +415 -149
- package/dist/products.server.mjs +415 -149
- package/dist/{profile.schema-h61hhB2w.js → profile.schema-BLSuV_VC.js} +0 -4
- package/dist/{profile.schema-kP_zKXNt.mjs → profile.schema-BRuvQ7QV.mjs} +0 -4
- package/dist/{queryProcessor-CWnMIe2U.mjs → queryProcessor-CVKI651_.mjs} +62 -8
- package/dist/{queryProcessor-D6GuKfTV.js → queryProcessor-DSUqSk3I.js} +62 -8
- package/dist/rents.server.js +4 -4
- package/dist/rents.server.mjs +4 -4
- package/dist/spots.server.js +162 -8
- package/dist/spots.server.mjs +162 -8
- package/dist/style.css +27 -4
- package/dist/wallet.server.js +2 -2
- package/dist/wallet.server.mjs +2 -2
- package/package.json +1 -1
- package/src/builder/rspack/rspack.config.base.js +1 -1
- package/src/builder/rspack/rspack.config.client.js +13 -5
- package/src/components/Select/Select.vue +4 -2
- package/src/modules/auth/models/user.model.js +4 -1
- package/src/modules/community/components/sections/HotPosts.vue +1 -1
- package/src/modules/globals/controllers/classes/globals.abac.js +148 -23
- package/src/modules/globals/controllers/classes/globals.validator.js +37 -0
- package/src/modules/globals/controllers/classes/globals.verifier.js +2 -0
- package/src/modules/globals/controllers/policies/globals.policies.js +91 -74
- package/src/modules/globals/controllers/utils/queryProcessor.js +59 -11
- package/src/modules/globals/models/schemas/ownership.schema.js +11 -6
- package/src/modules/globals/models/schemas/profile.schema.js +0 -4
- package/src/modules/music/components/layouts/MusicLayout.vue +10 -58
- package/src/modules/music/components/pages/MusicHome.vue +5 -5
- package/src/modules/orders/components/pages/OrderCreate.vue +85 -12
- package/src/modules/orders/controllers/orders.controller.js +3 -0
- package/src/modules/orders/store/shopcart.js +1 -0
- package/src/modules/organizations/models/schemas/accesses.schema.js +18 -0
- package/src/modules/organizations/policies/organizations.policies.js +117 -61
- package/src/modules/products/components/pages/CategoryEdit.vue +27 -2
- package/src/modules/products/components/pages/Product.vue +1 -0
- package/src/modules/products/components/pages/ProductEdit.vue +2 -2
- package/src/modules/products/controllers/categories.controller.js +297 -133
- package/src/modules/products/middlewares/categories.verifier.js +177 -0
- package/src/modules/products/models/category.model.js +12 -14
- package/src/modules/products/routes/categories.routes.js +50 -11
- package/src/modules/products/store/categories.js +2 -0
- package/src/modules/spots/components/pages/SpotEdit.vue +21 -17
- package/src/modules/spots/components/sections/WorktimeEdit.vue +840 -0
- package/src/modules/spots/controllers/queries/getIsOpenNowStage.js +109 -0
- package/src/modules/spots/controllers/spots.controller.js +2 -1
- package/src/modules/spots/models/spot.model.js +59 -13
- package/src/modules/spots/store/spots.js +4 -1
- package/src/modules/products/middlewares/index.js +0 -11
- package/src/modules/products/middlewares/verifyCategory.js +0 -25
package/dist/products.server.mjs
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { g as getDefaultExportFromCjs } from "./_commonjsHelpers-CUmg6egw.mjs";
|
|
2
|
-
import { r as requireOwnership_schema } from "./ownership.schema-
|
|
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-
|
|
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({
|
|
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
|
-
|
|
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
|
|
685
|
-
sortOrder
|
|
686
|
-
skip
|
|
687
|
-
limit
|
|
688
|
-
excludeChildren
|
|
689
|
-
rootOnly
|
|
690
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
699
|
-
|
|
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
|
-
|
|
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
|
|
741
|
-
|
|
742
|
-
|
|
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
|
-
|
|
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({
|
|
755
|
-
|
|
772
|
+
const category = new Category({
|
|
773
|
+
...categoryData,
|
|
774
|
+
order
|
|
775
|
+
});
|
|
776
|
+
if (categoryData.parent) {
|
|
756
777
|
const parent = await Category.findByIdAndUpdate(
|
|
757
|
-
|
|
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 (
|
|
785
|
+
if (categoryData.children && categoryData.children.length > 0) {
|
|
765
786
|
await Category.updateMany(
|
|
766
|
-
{ _id: { $in:
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
|
812
|
-
|
|
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
|
-
|
|
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 =
|
|
821
|
-
|
|
822
|
-
|
|
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
|
-
|
|
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
|
|
853
|
-
var
|
|
854
|
-
function
|
|
855
|
-
if (
|
|
856
|
-
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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
|
-
|
|
872
|
-
|
|
1007
|
+
const deleteBodyValidatorConfig = {
|
|
1008
|
+
url: {
|
|
1009
|
+
allowed: true,
|
|
1010
|
+
validator: Validator.schema().string().required()
|
|
1011
|
+
}
|
|
873
1012
|
};
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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;
|