feat(ldap): individual user search + selective import with dedup
Tessera CI/CD / Lint & Type Check (push) Successful in 49s
Tessera CI/CD / Tests (push) Successful in 47s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m45s

Add an AD single-user search (by cn/sAMAccountName/displayName/mail) and a
selective import to the LDAP admin page, alongside the existing group/OU
filter. Imported users are deduped against existing ones by (ldapDn, then
username): a manually-imported user carries its ldapDn, so a later
department/group sync matches and updates it in place instead of creating a
duplicate. Search results flag alreadyImported; import skips existing users
and links a missing ldapDn. Extracted shared mapEntry/upsertMappedUser
helpers so sync and manual import resolve identity identically.

Backend: GET /ldap/users/search, POST /ldap/users/import (RFC-4515 escaped
query, ADMIN-guarded). 6 new service specs (search flags, create, skip,
ldapDn-link, denylist). Full API suite 215 green, both apps tsc clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-22 13:52:50 +02:00
parent 0dd104054b
commit 38face43b4
7 changed files with 744 additions and 59 deletions
+11
View File
@@ -1,5 +1,6 @@
import { PartialType } from '@nestjs/mapped-types';
import {
ArrayNotEmpty,
IsArray,
IsBoolean,
IsInt,
@@ -93,3 +94,13 @@ export class CreateFieldMappingDto {
@IsOptional()
isDefault?: boolean;
}
/**
* DTO for POST /ldap/users/import — the DNs of AD users to import individually.
*/
export class ImportUsersDto {
@IsArray()
@ArrayNotEmpty()
@IsString({ each: true })
dns!: string[];
}