Zhi Chen 2c757c43c5
feat: user data sync plugin (#4986)
* feat: user data sync plugin

* fix: nickname bug

* feat: adjust sync

* fix: delete package-lock.json

* feat: adjust push

* feat: adjust user-data-sync plugin

* fix: delete submodule

* fix: sync bug

* fix: adjust log

* fix: adjust log

* chore: add to build-in

* chore: update version

* chore: add api doc

* chore: add plugin description

* chore: api doc

* chore: change keywords

* feat: add no source type prompt

* chore: text to json

* feat: optimize resource manager

* fix: test & typo

* test: add tests for resource manager & fix bug

* fix: user sync

* chore: remove department resource

* fix: test

* fix: build

* fix: push data

* fix: push api add default sourceName

* test: add api test

* fix: uniqueKey support any

* chore: single user belongs to multi department situation

* chore: department

* fix: fix sync bugs

* fix: sync departments

* chore: remove department logic

* chore: remove department

* fix: fix logger type error

* fix: fix sync bug

* fix: logger & role

* fix: fix sync bugs

* fix: fix sync bug

* fix: fix sync bugs

* test: update test cases

* chore: update

* chore: update

* fix: test

* fix: test

* fix: test

* fix: bugs

* fix: version

---------

Co-authored-by: chenzhi <chenzhi@zhuopaikeji.com>
Co-authored-by: xilesun <2013xile@gmail.com>
2024-08-27 05:25:30 +08:00

107 lines
2.9 KiB
TypeScript

/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Context } from '@nocobase/actions';
import { SyncSourceModel } from './models/sync-source';
import { UserData } from './user-data-resource-manager';
import dayjs from 'dayjs';
export type SyncSourceConfig = {
sourceInstance: SyncSourceModel;
options: {
[key: string]: any;
};
ctx: Context;
};
interface ISyncSource {
pull(): Promise<UserData[]>;
}
export abstract class SyncSource implements ISyncSource {
instance: SyncSourceModel;
protected options: {
[key: string]: any;
};
protected ctx: Context;
constructor(config: SyncSourceConfig) {
const { options, ctx, sourceInstance } = config;
this.instance = sourceInstance;
this.options = options;
this.ctx = ctx;
}
abstract pull(): Promise<UserData[]>;
async newTask() {
const batch = generateUniqueNumber();
return await this.instance.createTask({ batch, status: 'init' });
}
async beginTask(taskId: number) {
const tasks = await this.instance.getTasks({ where: { id: taskId } });
if (!tasks && !tasks.length) {
throw new Error(`Task [${taskId}] is not found.`);
}
const task = tasks[0];
if (task.status !== 'init') {
throw new Error(`Task [${taskId}] is not init.`);
}
task.status = 'processing';
await task.save();
}
async endTask(params: EndTaskParams) {
const { taskId, success, cost, message } = params;
const tasks = await this.instance.getTasks({ where: { id: taskId } });
if (!tasks && !tasks.length) {
throw new Error(`Task [${taskId}] is not found.`);
}
const task = tasks[0];
if (task.status !== 'processing') {
throw new Error(`Task [${taskId}] is not processing.`);
}
task.status = success ? 'success' : 'failed';
task.cost = cost;
task.message = message;
await task.save();
}
async retryTask(taskId: number) {
const tasks = await this.instance.getTasks({ where: { id: taskId } });
if (!tasks && !tasks.length) {
throw new Error(`Task [${taskId}] is not found.`);
}
const task = tasks[0];
if (task.status !== 'failed') {
throw new Error(`Task [${taskId}] is not failed.`);
}
task.status = 'processing';
task.message = '';
await task.save();
return task;
}
}
export type SyncSourceExtend<T extends SyncSource> = new (config: SyncSourceConfig) => T;
type EndTaskParams = {
taskId: number;
success: boolean;
cost?: number;
message?: string;
};
function generateUniqueNumber() {
const formattedDate = dayjs().format('YYYYMMDDHHmmss');
const randomDigits = Math.floor(100000 + Math.random() * 900000);
return formattedDate + randomDigits;
}