| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- # app/design/site.coffee
- class SiteDesignDocuments
- constructor: ->
- @designDocs = {
- products: @getProductsDesignDoc()
- categories: @getCategoriesDesignDoc()
- orders: @getOrdersDesignDoc()
- validation: @getValidationDesignDoc()
- }
- getProductsDesignDoc: ->
- {
- _id: '_design/products'
- views:
- by_category:
- map: """
- function(doc) {
- if (doc.type === 'product' && doc.active !== false) {
- emit([doc.category, doc.name], {
- _id: doc._id,
- name: doc.name,
- price: doc.price,
- images: doc.images,
- inStock: doc.inStock,
- brand: doc.brand
- });
- }
- }
- """
- by_brand:
- map: """
- function(doc) {
- if (doc.type === 'product' && doc.active !== false) {
- emit([doc.brand, doc.category], {
- _id: doc._id,
- name: doc.name,
- price: doc.price,
- category: doc.category
- });
- }
- }
- """
- by_sku:
- map: """
- function(doc) {
- if (doc.type === 'product') {
- emit(doc.sku, {
- _id: doc._id,
- name: doc.name,
- price: doc.price
- });
- }
- }
- """
- search_index:
- map: """
- function(doc) {
- if (doc.type === 'product' && doc.active !== false) {
- var searchable = [
- doc.name,
- doc.brand,
- doc.category,
- doc.description
- ].join(' ').toLowerCase();
-
- var words = searchable.split(/\\\\s+/);
- words.forEach(function(word) {
- if (word.length > 2) {
- emit(word, 1);
- }
- });
- }
- }
- """
- reduce: "_sum"
- language: "javascript"
- }
- getCategoriesDesignDoc: ->
- {
- _id: '_design/categories'
- views:
- hierarchical:
- map: """
- function(doc) {
- if (doc.type === 'category') {
- // Для построения иерархии категорий
- var path = doc.parent ? [doc._id] : [doc.parent, doc._id];
- emit(path, {
- _id: doc._id,
- name: doc.name,
- parent: doc.parent,
- order: doc.order,
- image: doc.image
- });
- }
- }
- """
- by_slug:
- map: """
- function(doc) {
- if (doc.type === 'category') {
- emit(doc.slug, {
- _id: doc._id,
- name: doc.name,
- parent: doc.parent
- });
- }
- }
- """
- active_categories:
- map: """
- function(doc) {
- if (doc.type === 'category' && doc.active !== false) {
- emit(doc.order, {
- _id: doc._id,
- name: doc.name,
- image: doc.image
- });
- }
- }
- """
- language: "javascript"
- }
- getOrdersDesignDoc: ->
- {
- _id: '_design/orders'
- views:
- by_user:
- map: """
- function(doc) {
- if (doc.type === 'order') {
- emit([doc.userId, doc.createdAt], {
- _id: doc._id,
- total: doc.total,
- status: doc.status,
- items: doc.items.length
- });
- }
- }
- """
- by_status:
- map: """
- function(doc) {
- if (doc.type === 'order') {
- emit([doc.status, doc.createdAt], {
- _id: doc._id,
- userId: doc.userId,
- total: doc.total
- });
- }
- }
- """
- language: "javascript"
- }
- getValidationDesignDoc: ->
- {
- _id: '_design/validation'
- validate_doc_update: """
- function(newDoc, oldDoc, userCtx, secObj) {
- // Функция проверки документов при сохранении :cite[2]:cite[10]
-
- // Проверка типа документа
- if (newDoc.type) {
- var validTypes = [
- 'product', 'category', 'order', 'user',
- 'domain_settings', 'hero_slide', 'blog_article'
- ];
-
- if (validTypes.indexOf(newDoc.type) === -1) {
- throw({forbidden: 'Invalid document type: ' + newDoc.type});
- }
- }
-
- // Проверка обязательных полей для товаров :cite[2]
- if (newDoc.type === 'product') {
- if (!newDoc.name) {
- throw({forbidden: 'Product must have a name'});
- }
- if (!newDoc.sku) {
- throw({forbidden: 'Product must have SKU'});
- }
- if (typeof newDoc.price !== 'number' || newDoc.price < 0) {
- throw({forbidden: 'Product must have valid price'});
- }
- }
-
- // Проверка категорий
- if (newDoc.type === 'category') {
- if (!newDoc.name) {
- throw({forbidden: 'Category must have a name'});
- }
- if (!newDoc.slug) {
- throw({forbidden: 'Category must have a slug'});
- }
- }
-
- // Проверка заказов
- if (newDoc.type === 'order') {
- if (!newDoc.userId) {
- throw({forbidden: 'Order must have user ID'});
- }
- if (!Array.isArray(newDoc.items) || newDoc.items.length === 0) {
- throw({forbidden: 'Order must have items'});
- }
- }
-
- // Проверка неизменяемых полей
- if (oldDoc) {
- if (oldDoc.type !== newDoc.type) {
- throw({forbidden: 'Document type cannot be changed'});
- }
- if (oldDoc.createdAt !== newDoc.createdAt) {
- throw({forbidden: 'Creation date cannot be changed'});
- }
- }
-
- // Проверка прав доступа :cite[2]
- if (newDoc.type === 'order' || newDoc.type === 'user') {
- if (userCtx.roles.indexOf('_admin') === -1 &&
- userCtx.roles.indexOf('user') === -1) {
- throw({unauthorized: 'You are not authorized to modify this document'});
- }
- }
- }
- """
- language: "javascript"
- }
- saveDesignDocs: (pouchService) ->
- log '💾 Сохранение дизайн-документов в базу...'
-
- promises = []
- for name, doc of @designDocs
- promises.push(
- pouchService.saveDocument(doc)
- .then ->
- log "✅ Дизайн-документ сохранен: #{name}"
- .catch (error) ->
- if error.status == 409
- log "⚠️ Дизайн-документ уже существует: #{name}"
- else
- log "❌ Ошибка сохранения дизайн-документа #{name}:", error
- )
-
- return Promise.all(promises)
- module.exports = new SiteDesignDocuments()
|