|
@@ -37,6 +37,7 @@ import { JobQueue } from '../../job-queue/job-queue';
|
|
|
import { JobQueueService } from '../../job-queue/job-queue.service';
|
|
import { JobQueueService } from '../../job-queue/job-queue.service';
|
|
|
import { WorkerService } from '../../worker/worker.service';
|
|
import { WorkerService } from '../../worker/worker.service';
|
|
|
import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
|
|
import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
|
|
|
|
|
+import { SlugValidator } from '../helpers/slug-validator/slug-validator';
|
|
|
import { TranslatableSaver } from '../helpers/translatable-saver/translatable-saver';
|
|
import { TranslatableSaver } from '../helpers/translatable-saver/translatable-saver';
|
|
|
import { findOneInChannel } from '../helpers/utils/channel-aware-orm-utils';
|
|
import { findOneInChannel } from '../helpers/utils/channel-aware-orm-utils';
|
|
|
import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';
|
|
import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';
|
|
@@ -63,6 +64,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
private workerService: WorkerService,
|
|
private workerService: WorkerService,
|
|
|
private jobQueueService: JobQueueService,
|
|
private jobQueueService: JobQueueService,
|
|
|
private configService: ConfigService,
|
|
private configService: ConfigService,
|
|
|
|
|
+ private slugValidator: SlugValidator,
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
onModuleInit() {
|
|
onModuleInit() {
|
|
@@ -71,18 +73,18 @@ export class CollectionService implements OnModuleInit {
|
|
|
|
|
|
|
|
merge(productEvents$, variantEvents$)
|
|
merge(productEvents$, variantEvents$)
|
|
|
.pipe(debounceTime(50))
|
|
.pipe(debounceTime(50))
|
|
|
- .subscribe(async (event) => {
|
|
|
|
|
|
|
+ .subscribe(async event => {
|
|
|
const collections = await this.connection.getRepository(Collection).find();
|
|
const collections = await this.connection.getRepository(Collection).find();
|
|
|
this.applyFiltersQueue.add({
|
|
this.applyFiltersQueue.add({
|
|
|
ctx: event.ctx.serialize(),
|
|
ctx: event.ctx.serialize(),
|
|
|
- collectionIds: collections.map((c) => c.id),
|
|
|
|
|
|
|
+ collectionIds: collections.map(c => c.id),
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
this.applyFiltersQueue = this.jobQueueService.createQueue({
|
|
this.applyFiltersQueue = this.jobQueueService.createQueue({
|
|
|
name: 'apply-collection-filters',
|
|
name: 'apply-collection-filters',
|
|
|
concurrency: 1,
|
|
concurrency: 1,
|
|
|
- process: async (job) => {
|
|
|
|
|
|
|
+ process: async job => {
|
|
|
const collections = await this.connection
|
|
const collections = await this.connection
|
|
|
.getRepository(Collection)
|
|
.getRepository(Collection)
|
|
|
.findByIds(job.data.collectionIds);
|
|
.findByIds(job.data.collectionIds);
|
|
@@ -106,7 +108,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
})
|
|
})
|
|
|
.getManyAndCount()
|
|
.getManyAndCount()
|
|
|
.then(async ([collections, totalItems]) => {
|
|
.then(async ([collections, totalItems]) => {
|
|
|
- const items = collections.map((collection) =>
|
|
|
|
|
|
|
+ const items = collections.map(collection =>
|
|
|
translateDeep(collection, ctx.languageCode, ['parent']),
|
|
translateDeep(collection, ctx.languageCode, ['parent']),
|
|
|
);
|
|
);
|
|
|
return {
|
|
return {
|
|
@@ -128,7 +130,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
getAvailableFilters(ctx: RequestContext): ConfigurableOperationDefinition[] {
|
|
getAvailableFilters(ctx: RequestContext): ConfigurableOperationDefinition[] {
|
|
|
- return this.configService.catalogOptions.collectionFilters.map((x) =>
|
|
|
|
|
|
|
+ return this.configService.catalogOptions.collectionFilters.map(x =>
|
|
|
configurableDefToOperation(ctx, x),
|
|
configurableDefToOperation(ctx, x),
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
@@ -139,7 +141,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
.createQueryBuilder('collection')
|
|
.createQueryBuilder('collection')
|
|
|
.leftJoinAndSelect('collection.translations', 'translation')
|
|
.leftJoinAndSelect('collection.translations', 'translation')
|
|
|
.where(
|
|
.where(
|
|
|
- (qb) =>
|
|
|
|
|
|
|
+ qb =>
|
|
|
`collection.id = ${qb
|
|
`collection.id = ${qb
|
|
|
.subQuery()
|
|
.subQuery()
|
|
|
.select('child.parentId')
|
|
.select('child.parentId')
|
|
@@ -188,7 +190,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
const result = await qb.getMany();
|
|
const result = await qb.getMany();
|
|
|
|
|
|
|
|
- return result.map((collection) => translateDeep(collection, ctx.languageCode));
|
|
|
|
|
|
|
+ return result.map(collection => translateDeep(collection, ctx.languageCode));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -214,7 +216,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const descendants = await getChildren(rootId);
|
|
const descendants = await getChildren(rootId);
|
|
|
- return descendants.map((c) => translateDeep(c, ctx.languageCode));
|
|
|
|
|
|
|
+ return descendants.map(c => translateDeep(c, ctx.languageCode));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -246,18 +248,19 @@ export class CollectionService implements OnModuleInit {
|
|
|
|
|
|
|
|
return this.connection
|
|
return this.connection
|
|
|
.getRepository(Collection)
|
|
.getRepository(Collection)
|
|
|
- .findByIds(ancestors.map((c) => c.id))
|
|
|
|
|
- .then((categories) => {
|
|
|
|
|
- return ctx ? categories.map((c) => translateDeep(c, ctx.languageCode)) : categories;
|
|
|
|
|
|
|
+ .findByIds(ancestors.map(c => c.id))
|
|
|
|
|
+ .then(categories => {
|
|
|
|
|
+ return ctx ? categories.map(c => translateDeep(c, ctx.languageCode)) : categories;
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async create(ctx: RequestContext, input: CreateCollectionInput): Promise<Translated<Collection>> {
|
|
async create(ctx: RequestContext, input: CreateCollectionInput): Promise<Translated<Collection>> {
|
|
|
|
|
+ await this.slugValidator.validateSlugs(input, CollectionTranslation);
|
|
|
const collection = await this.translatableSaver.create({
|
|
const collection = await this.translatableSaver.create({
|
|
|
input,
|
|
input,
|
|
|
entityType: Collection,
|
|
entityType: Collection,
|
|
|
translationType: CollectionTranslation,
|
|
translationType: CollectionTranslation,
|
|
|
- beforeSave: async (coll) => {
|
|
|
|
|
|
|
+ beforeSave: async coll => {
|
|
|
await this.channelService.assignToCurrentChannel(coll, ctx);
|
|
await this.channelService.assignToCurrentChannel(coll, ctx);
|
|
|
const parent = await this.getParentCollection(ctx, input.parentId);
|
|
const parent = await this.getParentCollection(ctx, input.parentId);
|
|
|
if (parent) {
|
|
if (parent) {
|
|
@@ -277,11 +280,12 @@ export class CollectionService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async update(ctx: RequestContext, input: UpdateCollectionInput): Promise<Translated<Collection>> {
|
|
async update(ctx: RequestContext, input: UpdateCollectionInput): Promise<Translated<Collection>> {
|
|
|
|
|
+ await this.slugValidator.validateSlugs(input, CollectionTranslation);
|
|
|
const collection = await this.translatableSaver.update({
|
|
const collection = await this.translatableSaver.update({
|
|
|
input,
|
|
input,
|
|
|
entityType: Collection,
|
|
entityType: Collection,
|
|
|
translationType: CollectionTranslation,
|
|
translationType: CollectionTranslation,
|
|
|
- beforeSave: async (coll) => {
|
|
|
|
|
|
|
+ beforeSave: async coll => {
|
|
|
if (input.filters) {
|
|
if (input.filters) {
|
|
|
coll.filters = this.getCollectionFiltersFromInput(input);
|
|
coll.filters = this.getCollectionFiltersFromInput(input);
|
|
|
}
|
|
}
|
|
@@ -325,7 +329,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
|
|
|
|
|
if (
|
|
if (
|
|
|
idsAreEqual(input.parentId, target.id) ||
|
|
idsAreEqual(input.parentId, target.id) ||
|
|
|
- descendants.some((cat) => idsAreEqual(input.parentId, cat.id))
|
|
|
|
|
|
|
+ descendants.some(cat => idsAreEqual(input.parentId, cat.id))
|
|
|
) {
|
|
) {
|
|
|
throw new IllegalOperationError(`error.cannot-move-collection-into-self`);
|
|
throw new IllegalOperationError(`error.cannot-move-collection-into-self`);
|
|
|
}
|
|
}
|
|
@@ -382,13 +386,13 @@ export class CollectionService implements OnModuleInit {
|
|
|
collections: Collection[],
|
|
collections: Collection[],
|
|
|
job: Job<ApplyCollectionFiletersJobData>,
|
|
job: Job<ApplyCollectionFiletersJobData>,
|
|
|
): Promise<void> {
|
|
): Promise<void> {
|
|
|
- const collectionIds = collections.map((c) => c.id);
|
|
|
|
|
|
|
+ const collectionIds = collections.map(c => c.id);
|
|
|
const requestContext = RequestContext.deserialize(ctx);
|
|
const requestContext = RequestContext.deserialize(ctx);
|
|
|
|
|
|
|
|
this.workerService.send(new ApplyCollectionFiltersMessage({ collectionIds })).subscribe({
|
|
this.workerService.send(new ApplyCollectionFiltersMessage({ collectionIds })).subscribe({
|
|
|
next: ({ total, completed, duration, collectionId, affectedVariantIds }) => {
|
|
next: ({ total, completed, duration, collectionId, affectedVariantIds }) => {
|
|
|
const progress = Math.ceil((completed / total) * 100);
|
|
const progress = Math.ceil((completed / total) * 100);
|
|
|
- const collection = collections.find((c) => idsAreEqual(c.id, collectionId));
|
|
|
|
|
|
|
+ const collection = collections.find(c => idsAreEqual(c.id, collectionId));
|
|
|
if (collection) {
|
|
if (collection) {
|
|
|
this.eventBus.publish(
|
|
this.eventBus.publish(
|
|
|
new CollectionModificationEvent(requestContext, collection, affectedVariantIds),
|
|
new CollectionModificationEvent(requestContext, collection, affectedVariantIds),
|
|
@@ -399,7 +403,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
complete: () => {
|
|
complete: () => {
|
|
|
job.complete();
|
|
job.complete();
|
|
|
},
|
|
},
|
|
|
- error: (err) => {
|
|
|
|
|
|
|
+ error: err => {
|
|
|
Logger.error(err);
|
|
Logger.error(err);
|
|
|
job.fail(err);
|
|
job.fail(err);
|
|
|
},
|
|
},
|
|
@@ -411,14 +415,14 @@ export class CollectionService implements OnModuleInit {
|
|
|
*/
|
|
*/
|
|
|
async getCollectionProductVariantIds(collection: Collection): Promise<ID[]> {
|
|
async getCollectionProductVariantIds(collection: Collection): Promise<ID[]> {
|
|
|
if (collection.productVariants) {
|
|
if (collection.productVariants) {
|
|
|
- return collection.productVariants.map((v) => v.id);
|
|
|
|
|
|
|
+ return collection.productVariants.map(v => v.id);
|
|
|
} else {
|
|
} else {
|
|
|
const productVariants = await this.connection
|
|
const productVariants = await this.connection
|
|
|
.getRepository(ProductVariant)
|
|
.getRepository(ProductVariant)
|
|
|
.createQueryBuilder('variant')
|
|
.createQueryBuilder('variant')
|
|
|
.innerJoin('variant.collections', 'collection', 'collection.id = :id', { id: collection.id })
|
|
.innerJoin('variant.collections', 'collection', 'collection.id = :id', { id: collection.id })
|
|
|
.getMany();
|
|
.getMany();
|
|
|
- return productVariants.map((v) => v.id);
|
|
|
|
|
|
|
+ return productVariants.map(v => v.id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -480,6 +484,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
languageCode: this.configService.defaultLanguageCode,
|
|
languageCode: this.configService.defaultLanguageCode,
|
|
|
name: ROOT_COLLECTION_NAME,
|
|
name: ROOT_COLLECTION_NAME,
|
|
|
description: 'The root of the Collection tree.',
|
|
description: 'The root of the Collection tree.',
|
|
|
|
|
+ slug: ROOT_COLLECTION_NAME,
|
|
|
}),
|
|
}),
|
|
|
);
|
|
);
|
|
|
|
|
|
|
@@ -497,7 +502,7 @@ export class CollectionService implements OnModuleInit {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private getFilterByCode(code: string): CollectionFilter<any> {
|
|
private getFilterByCode(code: string): CollectionFilter<any> {
|
|
|
- const match = this.configService.catalogOptions.collectionFilters.find((a) => a.code === code);
|
|
|
|
|
|
|
+ const match = this.configService.catalogOptions.collectionFilters.find(a => a.code === code);
|
|
|
if (!match) {
|
|
if (!match) {
|
|
|
throw new UserInputError(`error.adjustment-operation-with-code-not-found`, { code });
|
|
throw new UserInputError(`error.adjustment-operation-with-code-not-found`, { code });
|
|
|
}
|
|
}
|