feat: add invitations management and import wizard; enhance audit logging and member detail fetching
This commit is contained in:
@@ -172,3 +172,102 @@ export const lockRecord = authActionClient
|
||||
|
||||
return { success: true, data: record };
|
||||
});
|
||||
|
||||
export const bulkImportRecords = authActionClient
|
||||
.inputSchema(
|
||||
z.object({
|
||||
moduleId: z.string().uuid(),
|
||||
accountId: z.string().uuid(),
|
||||
records: z.array(z.record(z.string(), z.unknown())).min(1).max(1000),
|
||||
dryRun: z.boolean().default(false),
|
||||
}),
|
||||
)
|
||||
.action(async ({ parsedInput: input, ctx }) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const logger = await getLogger();
|
||||
const api = createModuleBuilderApi(client);
|
||||
const userId = ctx.user.id;
|
||||
|
||||
const moduleWithFields = await api.modules.getModuleWithFields(
|
||||
input.moduleId,
|
||||
);
|
||||
|
||||
if (!moduleWithFields) {
|
||||
throw new Error('Module not found');
|
||||
}
|
||||
|
||||
const { fields } = moduleWithFields;
|
||||
const errors: Array<{ row: number; field: string; message: string }> = [];
|
||||
const validRows: Array<Record<string, unknown>> = [];
|
||||
|
||||
for (let i = 0; i < input.records.length; i++) {
|
||||
const row = input.records[i]!;
|
||||
const validation = validateRecordData(
|
||||
row,
|
||||
fields as Parameters<typeof validateRecordData>[1],
|
||||
);
|
||||
|
||||
if (!validation.success) {
|
||||
for (const err of validation.errors) {
|
||||
errors.push({ row: i + 1, field: err.field, message: err.message });
|
||||
}
|
||||
} else {
|
||||
validRows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.dryRun) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
totalRows: input.records.length,
|
||||
validRows: validRows.length,
|
||||
errorCount: errors.length,
|
||||
errors: errors.slice(0, 50),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
return {
|
||||
success: false,
|
||||
error: `${errors.length} Validierungsfehler in ${new Set(errors.map((e) => e.row)).size} Zeilen`,
|
||||
validationErrors: errors.slice(0, 50).map((e) => ({
|
||||
field: `Zeile ${e.row}: ${e.field}`,
|
||||
message: e.message,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
logger.info(
|
||||
{
|
||||
name: 'records.bulkImport',
|
||||
moduleId: input.moduleId,
|
||||
count: validRows.length,
|
||||
},
|
||||
'Bulk importing records...',
|
||||
);
|
||||
|
||||
const insertData = validRows.map((row) => ({
|
||||
module_id: input.moduleId,
|
||||
account_id: input.accountId,
|
||||
data: row as any,
|
||||
status: 'active' as const,
|
||||
created_by: userId,
|
||||
updated_by: userId,
|
||||
}));
|
||||
|
||||
const { error } = await client.from('module_records').insert(insertData);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
logger.info(
|
||||
{ name: 'records.bulkImport', count: validRows.length },
|
||||
'Bulk import complete',
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: { imported: validRows.length },
|
||||
};
|
||||
});
|
||||
|
||||
@@ -34,5 +34,36 @@ export function createAuditService(client: SupabaseClient<Database>) {
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async query(opts?: {
|
||||
accountId?: string;
|
||||
userId?: string;
|
||||
tableName?: string;
|
||||
action?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}) {
|
||||
let q = client
|
||||
.from('audit_log')
|
||||
.select('*', { count: 'exact' })
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
if (opts?.accountId) q = q.eq('account_id', opts.accountId);
|
||||
if (opts?.userId) q = q.eq('user_id', opts.userId);
|
||||
if (opts?.tableName) q = q.eq('table_name', opts.tableName);
|
||||
if (opts?.action)
|
||||
q = q.eq(
|
||||
'action',
|
||||
opts.action as 'insert' | 'update' | 'delete' | 'lock',
|
||||
);
|
||||
|
||||
const page = opts?.page ?? 1;
|
||||
const pageSize = opts?.pageSize ?? 50;
|
||||
q = q.range((page - 1) * pageSize, page * pageSize - 1);
|
||||
|
||||
const { data, error, count } = await q;
|
||||
if (error) throw error;
|
||||
return { data: data ?? [], total: count ?? 0, page, pageSize };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user