n8n
Version:
n8n Workflow Automation Tool
202 lines • 10 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FavoritesService = void 0;
const di_1 = require("@n8n/di");
const db_1 = require("@n8n/db");
const permissions_1 = require("@n8n/permissions");
const typeorm_1 = require("@n8n/typeorm");
const user_favorite_repository_1 = require("./database/repositories/user-favorite.repository");
const bad_request_error_1 = require("../../errors/response-errors/bad-request.error");
const not_found_error_1 = require("../../errors/response-errors/not-found.error");
const data_table_repository_1 = require("../../modules/data-table/data-table.repository");
const idsOfType = (favorites, type) => favorites.filter((f) => f.resourceType === type).map((f) => f.resourceId);
const enrichWithName = (fav, name) => name === undefined ? [] : [{ ...fav, resourceName: name }];
const enrichWithMeta = (fav, meta) => meta === undefined
? []
: [{ ...fav, resourceName: meta.name, resourceProjectId: meta.projectId }];
let FavoritesService = class FavoritesService {
constructor(userFavoriteRepository, workflowRepository, projectRepository, sharedWorkflowRepository, dataTableRepository, folderRepository) {
this.userFavoriteRepository = userFavoriteRepository;
this.workflowRepository = workflowRepository;
this.projectRepository = projectRepository;
this.sharedWorkflowRepository = sharedWorkflowRepository;
this.dataTableRepository = dataTableRepository;
this.folderRepository = folderRepository;
this.MAX_FAVORITES = 200;
}
async getEnrichedFavorites(user) {
const favorites = await this.userFavoriteRepository.findByUser(user.id);
if (favorites.length === 0)
return [];
const ids = {
workflow: idsOfType(favorites, 'workflow'),
project: idsOfType(favorites, 'project'),
dataTable: idsOfType(favorites, 'dataTable'),
folder: idsOfType(favorites, 'folder'),
};
const accessibleProjects = await this.projectRepository.getAccessibleProjects(user.id);
const accessibleProjectIds = new Set(accessibleProjects.map((p) => p.id));
const [workflowNames, projectNames, dataTableMeta, folderMeta] = await Promise.all([
this.enrichWorkflowFavorites(user, ids.workflow, accessibleProjectIds),
this.enrichProjectFavorites(user, ids.project, accessibleProjects),
this.enrichDataTableFavorites(user, ids.dataTable, accessibleProjectIds),
this.enrichFolderFavorites(user, ids.folder, accessibleProjectIds),
]);
return favorites.flatMap((fav) => {
switch (fav.resourceType) {
case 'workflow':
return enrichWithName(fav, workflowNames.get(fav.resourceId));
case 'project':
return enrichWithName(fav, projectNames.get(fav.resourceId));
case 'dataTable':
return enrichWithMeta(fav, dataTableMeta.get(fav.resourceId));
case 'folder':
return enrichWithMeta(fav, folderMeta.get(fav.resourceId));
default:
return [];
}
});
}
async enrichWorkflowFavorites(user, workflowIds, accessibleProjectIds) {
const result = new Map();
if (workflowIds.length === 0)
return result;
const hasGlobalAccess = (0, permissions_1.hasGlobalScope)(user, 'workflow:read');
if (!hasGlobalAccess && accessibleProjectIds.size === 0)
return result;
const [workflows, sharedWorkflows] = await Promise.all([
this.workflowRepository.findByIds(workflowIds, { fields: ['id', 'name'] }),
hasGlobalAccess
? Promise.resolve([])
: this.sharedWorkflowRepository.find({
select: { workflowId: true },
where: { workflowId: (0, typeorm_1.In)(workflowIds), projectId: (0, typeorm_1.In)([...accessibleProjectIds]) },
}),
]);
const accessibleIds = hasGlobalAccess
? new Set(workflows.map((wf) => wf.id))
: new Set(sharedWorkflows.map((sw) => sw.workflowId));
for (const wf of workflows) {
if (accessibleIds.has(wf.id))
result.set(wf.id, wf.name);
}
return result;
}
async enrichProjectFavorites(user, projectFavoriteIds, accessibleProjects) {
const result = new Map(accessibleProjects.map((p) => [p.id, p.name ?? '']));
if (projectFavoriteIds.length === 0)
return result;
if (!(0, permissions_1.hasGlobalScope)(user, 'project:read'))
return result;
const missingIds = projectFavoriteIds.filter((id) => !result.has(id));
if (missingIds.length === 0)
return result;
const additional = await this.projectRepository.find({
where: { id: (0, typeorm_1.In)(missingIds) },
select: { id: true, name: true },
});
for (const p of additional) {
result.set(p.id, p.name ?? '');
}
return result;
}
async enrichDataTableFavorites(user, dataTableIds, accessibleProjectIds) {
const result = new Map();
if (dataTableIds.length === 0)
return result;
const hasGlobalAccess = (0, permissions_1.hasGlobalScope)(user, 'dataTable:read');
const dataTables = await this.dataTableRepository.find({ where: { id: (0, typeorm_1.In)(dataTableIds) } });
for (const dt of dataTables) {
if (hasGlobalAccess || accessibleProjectIds.has(dt.projectId)) {
result.set(dt.id, { name: dt.name, projectId: dt.projectId });
}
}
return result;
}
async enrichFolderFavorites(user, folderIds, accessibleProjectIds) {
const result = new Map();
if (folderIds.length === 0)
return result;
const hasGlobalAccess = (0, permissions_1.hasGlobalScope)(user, 'folder:read');
const folders = await this.folderRepository.find({
where: { id: (0, typeorm_1.In)(folderIds) },
relations: { homeProject: true },
});
for (const folder of folders) {
const projectId = folder.homeProject?.id;
if (projectId && (hasGlobalAccess || accessibleProjectIds.has(projectId))) {
result.set(folder.id, { name: folder.name, projectId });
}
}
return result;
}
async addFavorite(userId, resourceId, resourceType) {
const existing = await this.userFavoriteRepository.findOne({
where: { userId, resourceId, resourceType },
});
if (existing)
return existing;
await this.assertResourceExists(resourceId, resourceType);
const count = await this.userFavoriteRepository.count({ where: { userId } });
if (count >= this.MAX_FAVORITES) {
throw new bad_request_error_1.BadRequestError(`Favorites limit of ${this.MAX_FAVORITES} reached`);
}
const favorite = this.userFavoriteRepository.create({ userId, resourceId, resourceType });
return await this.userFavoriteRepository.save(favorite);
}
async assertResourceExists(resourceId, resourceType) {
let exists;
switch (resourceType) {
case 'workflow':
exists = await this.workflowRepository.existsBy({ id: resourceId });
break;
case 'project':
exists = await this.projectRepository.existsBy({ id: resourceId });
break;
case 'dataTable':
exists = await this.dataTableRepository.existsBy({ id: resourceId });
break;
case 'folder':
exists = await this.folderRepository.existsBy({ id: resourceId });
break;
}
if (!exists) {
throw new not_found_error_1.NotFoundError(`${resourceType} with id "${resourceId}" not found`);
}
}
async removeFavorite(userId, resourceId, resourceType) {
const favorite = await this.userFavoriteRepository.findOne({
where: { userId, resourceId, resourceType },
});
if (!favorite) {
throw new not_found_error_1.NotFoundError('Favorite not found');
}
await this.userFavoriteRepository.remove(favorite);
}
async deleteByResource(resourceId, resourceType) {
await this.userFavoriteRepository.deleteByResourceId(resourceId, resourceType);
}
async deleteByResourceIds(resourceIds, resourceType) {
await this.userFavoriteRepository.deleteByResourceIds(resourceIds, resourceType);
}
};
exports.FavoritesService = FavoritesService;
exports.FavoritesService = FavoritesService = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [user_favorite_repository_1.UserFavoriteRepository,
db_1.WorkflowRepository,
db_1.ProjectRepository,
db_1.SharedWorkflowRepository,
data_table_repository_1.DataTableRepository,
db_1.FolderRepository])
], FavoritesService);
//# sourceMappingURL=favorites.service.js.map