refactor(quick-260921-m34): Aufgabe 1 - Mandantenbindung entzaubert, 105 unnoetige any-Zusicherungen entfernt
- prisma-tenant.extension.ts: (prisma as any) und die Handannotation an
$allOperations in forTenant()/forSystem() entfernt; Kopfkommentar
unveraendert. .then((results: any[]) => ...) auf unknown[] umgestellt.
- 105 Aufrufstellen `const X = forTenant(...) as any` / `forSystem(...) as
any` von der Zusicherung befreit, Zuweisungsform woertlich erhalten
(rls-access-inventory.spec.ts bleibt scharf, 30/30 gruen einzeln
geprueft).
- withTenantTransaction(): Prisma.TransactionClient fuer tx probiert,
gemessen verworfen - bricht das Testdoppel in
prisma-tenant.extension.spec.ts (TS2322 auf einem absichtlich
unvollstaendigen Fake-Objekt). tx bleibt any, mit Begruendung am Typ.
- Gefolge des jetzt getypten Klienten entfernt: any[]-Annotationen und
.map((x: any) => ...) in groups.service.ts, module-grants.service.ts,
dkv.service.ts, ldap-config.service.ts, tenders.controller.ts:270.
- Befund (D-03): tender-matching.service.ts:159 trug eine Handannotation
(match: { tender: unknown }), die den Wert nur deshalb auf unknown
verengte, um TS7006 unter dem alten any-Klienten zu vermeiden - mit dem
getypten Klienten war das falsch. Annotation geloescht, kein Ersatz
durch Zusicherung.
- Zwei any bleiben gezielt in groups.service.ts (u/a in
ensureDefaultGroup(), gefolge von tx: any) - Begruendung am Code.
noExplicitAny apps/api/src: 288 -> 149 (Schranke 155). type-check 4/4,
lint 5/5 (0 error). apps/api 72/1143 gruen, apps/web 73/531 gruen,
rls-access-inventory.spec.ts 30/30 gruen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -53,20 +53,14 @@ export class GroupsService {
|
||||
* Mitgliederzahl. Ein Mandant ohne Gruppen liefert ein leeres Array.
|
||||
*/
|
||||
async listForTenant(tenantId: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
// Explizit als any[] annotiert (nicht nur der Rueckgabewert von await):
|
||||
// ohne diese Array-Verankerung inferiert TypeScript den Rueckgabewert
|
||||
// dieser Methode als bloss `any` statt `any[]`, und Aufrufer, die auf
|
||||
// dem Ergebnis `.find()` aufrufen, wuerden TS7006 (impliziter any-Typ
|
||||
// im Callback-Parameter) melden, obwohl der gebundene Client bewusst
|
||||
// `any` ist (siehe forTenant()-Aufrufe in dieser Datei).
|
||||
const groups: any[] = await tenantPrisma.group.findMany({
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const groups = await tenantPrisma.group.findMany({
|
||||
where: { tenantId },
|
||||
orderBy: { name: 'asc' },
|
||||
include: { _count: { select: { memberships: true } } },
|
||||
});
|
||||
|
||||
return groups.map((g: any) => ({
|
||||
return groups.map((g) => ({
|
||||
id: g.id,
|
||||
tenantId: g.tenantId,
|
||||
name: g.name,
|
||||
@@ -92,7 +86,7 @@ export class GroupsService {
|
||||
throw new BadRequestException('Gruppenname darf nicht leer sein');
|
||||
}
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
try {
|
||||
return await tenantPrisma.group.create({
|
||||
data: { tenantId, name },
|
||||
@@ -112,7 +106,7 @@ export class GroupsService {
|
||||
* Mandanten liefert NotFoundException statt eines Treffers.
|
||||
*/
|
||||
private async findOwned(tenantId: string, id: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const group = await tenantPrisma.group.findFirst({
|
||||
where: { id, tenantId },
|
||||
});
|
||||
@@ -188,7 +182,7 @@ export class GroupsService {
|
||||
|
||||
try {
|
||||
if (data.isDefault === true) {
|
||||
const updated = await withTenantTransaction(this.prisma, tenantId, async (tx: any) => {
|
||||
const updated = await withTenantTransaction(this.prisma, tenantId, async (tx) => {
|
||||
await tx.group.updateMany({
|
||||
where: { tenantId, isDefault: true },
|
||||
data: { isDefault: false },
|
||||
@@ -205,7 +199,7 @@ export class GroupsService {
|
||||
updateData.isDefault = false;
|
||||
}
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
return await tenantPrisma.group.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
@@ -227,7 +221,7 @@ export class GroupsService {
|
||||
async getImpact(tenantId: string, id: string) {
|
||||
await this.findOwned(tenantId, id);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const [memberCount, grantCount] = await Promise.all([
|
||||
tenantPrisma.groupMembership.count({ where: { groupId: id } }),
|
||||
tenantPrisma.moduleGrant.count({ where: { groupId: id } }),
|
||||
@@ -247,7 +241,7 @@ export class GroupsService {
|
||||
async remove(tenantId: string, id: string) {
|
||||
await this.findOwned(tenantId, id);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
try {
|
||||
return await tenantPrisma.group.delete({ where: { id } });
|
||||
} catch (err: any) {
|
||||
@@ -265,7 +259,7 @@ export class GroupsService {
|
||||
async listMembers(tenantId: string, id: string) {
|
||||
await this.findOwned(tenantId, id);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
return tenantPrisma.groupMembership.findMany({
|
||||
where: { groupId: id },
|
||||
include: {
|
||||
@@ -286,12 +280,12 @@ export class GroupsService {
|
||||
async addMembers(tenantId: string, id: string, userIds: string[]) {
|
||||
await this.findOwned(tenantId, id);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const validUsers = await tenantPrisma.user.findMany({
|
||||
where: { id: { in: userIds }, tenantId },
|
||||
select: { id: true },
|
||||
});
|
||||
const validIds = validUsers.map((u: any) => u.id);
|
||||
const validIds = validUsers.map((u) => u.id);
|
||||
if (validIds.length === 0) {
|
||||
return { added: 0 };
|
||||
}
|
||||
@@ -316,7 +310,7 @@ export class GroupsService {
|
||||
async removeMember(tenantId: string, id: string, userId: string) {
|
||||
await this.findOwned(tenantId, id);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
await tenantPrisma.groupMembership.deleteMany({
|
||||
where: { groupId: id, userId, source: MembershipSource.MANUAL },
|
||||
});
|
||||
@@ -354,14 +348,14 @@ export class GroupsService {
|
||||
* propagieren.
|
||||
*/
|
||||
async ensureDefaultGroup(tenantId: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const existingCount = await tenantPrisma.group.count({ where: { tenantId } });
|
||||
if (existingCount > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return await withTenantTransaction(this.prisma, tenantId, async (tx: any) => {
|
||||
return await withTenantTransaction(this.prisma, tenantId, async (tx) => {
|
||||
const group = await tx.group.create({
|
||||
data: { tenantId, name: DEFAULT_GROUP_NAME, isDefault: true },
|
||||
});
|
||||
@@ -372,6 +366,9 @@ export class GroupsService {
|
||||
});
|
||||
if (users.length > 0) {
|
||||
await tx.groupMembership.createMany({
|
||||
// u: any bleibt (gemessen, Aufgabe 1 260921-m34) - tx ist selbst
|
||||
// any (siehe Begruendung an withTenantTransaction()), any.map()
|
||||
// gibt hier keine kontextuelle Typisierung des Parameters.
|
||||
data: users.map((u: any) => ({
|
||||
groupId: group.id,
|
||||
userId: u.id,
|
||||
@@ -387,6 +384,8 @@ export class GroupsService {
|
||||
});
|
||||
if (activations.length > 0) {
|
||||
await tx.moduleGrant.createMany({
|
||||
// a: any bleibt (gemessen, Aufgabe 1 260921-m34) - selbe Ursache
|
||||
// wie bei `u` oben: tx ist any.
|
||||
data: activations.map((a: any) => ({
|
||||
tenantId,
|
||||
moduleId: a.moduleId,
|
||||
@@ -435,7 +434,7 @@ export class GroupsService {
|
||||
* werfen — exakt das Muster aus ensureDefaultGroup().
|
||||
*/
|
||||
async reassignDefaultBeforeDelete(tenantId: string, groupId: string): Promise<boolean> {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
|
||||
const group = await tenantPrisma.group.findFirst({
|
||||
where: { id: groupId, tenantId },
|
||||
@@ -458,7 +457,7 @@ export class GroupsService {
|
||||
}
|
||||
|
||||
try {
|
||||
await withTenantTransaction(this.prisma, tenantId, async (tx: any) => {
|
||||
await withTenantTransaction(this.prisma, tenantId, async (tx) => {
|
||||
await tx.group.updateMany({
|
||||
where: { tenantId, isDefault: true },
|
||||
data: { isDefault: false },
|
||||
@@ -497,7 +496,7 @@ export class GroupsService {
|
||||
* Treffer folgenlos zurückkehren statt zu werfen.
|
||||
*/
|
||||
async addUserToDefaultGroup(tenantId: string, userId: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const defaultGroup = await tenantPrisma.group.findFirst({
|
||||
where: { tenantId, isDefault: true },
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ export class ModuleGrantsService {
|
||||
groupId?: string,
|
||||
userId?: string,
|
||||
): Promise<void> {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
if (groupId) {
|
||||
const group = await tenantPrisma.group.findFirst({
|
||||
where: { id: groupId, tenantId },
|
||||
@@ -107,7 +107,7 @@ export class ModuleGrantsService {
|
||||
// Datenbank" entfallen.
|
||||
await this.assertTargetBelongsToTenant(tenantId, groupId, userId);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const activation = await tenantPrisma.tenantModuleActivation.findUnique({
|
||||
where: { tenantId_moduleId: { tenantId, moduleId } },
|
||||
});
|
||||
@@ -166,7 +166,7 @@ export class ModuleGrantsService {
|
||||
const { moduleId, groupId, userId } = data;
|
||||
const target = groupId ? `group=${groupId}` : `user=${userId}`;
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
await tenantPrisma.moduleGrant.deleteMany({
|
||||
where: {
|
||||
tenantId,
|
||||
@@ -189,7 +189,7 @@ export class ModuleGrantsService {
|
||||
* hinweg stabil.
|
||||
*/
|
||||
async getMatrix(tenantId: string) {
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const [activations, groups, groupGrants] = await Promise.all([
|
||||
tenantPrisma.tenantModuleActivation.findMany({
|
||||
where: { tenantId, isActive: true },
|
||||
@@ -206,18 +206,17 @@ export class ModuleGrantsService {
|
||||
]);
|
||||
|
||||
const modules = activations
|
||||
.map((a: any) => a.module)
|
||||
.map((a) => a.module)
|
||||
.sort(
|
||||
(a: any, b: any) =>
|
||||
a.category.localeCompare(b.category) || a.name.localeCompare(b.name),
|
||||
(a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name),
|
||||
);
|
||||
|
||||
return {
|
||||
modules,
|
||||
groups,
|
||||
grants: groupGrants.map((g: any) => ({
|
||||
moduleId: g.moduleId as string,
|
||||
groupId: g.groupId as string,
|
||||
grants: groupGrants.map((g) => ({
|
||||
moduleId: g.moduleId,
|
||||
groupId: g.groupId,
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -246,7 +245,7 @@ export class ModuleGrantsService {
|
||||
async getUserAccess(tenantId: string, userId: string) {
|
||||
await this.assertTargetBelongsToTenant(tenantId, undefined, userId);
|
||||
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId) as any;
|
||||
const tenantPrisma = forTenant(this.prisma, tenantId);
|
||||
const [activations, groupGrants, directGrants, memberships] = await Promise.all([
|
||||
tenantPrisma.tenantModuleActivation.findMany({
|
||||
where: { tenantId, isActive: true },
|
||||
@@ -275,9 +274,9 @@ export class ModuleGrantsService {
|
||||
}),
|
||||
]);
|
||||
|
||||
const directModuleIds = new Set(directGrants.map((g: any) => g.moduleId as string));
|
||||
const directModuleIds = new Set(directGrants.map((g) => g.moduleId));
|
||||
const groupNamesByModule = new Map<string, string[]>();
|
||||
for (const g of groupGrants as any[]) {
|
||||
for (const g of groupGrants) {
|
||||
if (!g.group) continue;
|
||||
const names = groupNamesByModule.get(g.moduleId) ?? [];
|
||||
names.push(g.group.internalName ?? g.group.name);
|
||||
@@ -285,13 +284,12 @@ export class ModuleGrantsService {
|
||||
}
|
||||
|
||||
const modules = activations
|
||||
.map((a: any) => a.module)
|
||||
.map((a) => a.module)
|
||||
.sort(
|
||||
(a: any, b: any) =>
|
||||
a.category.localeCompare(b.category) || a.name.localeCompare(b.name),
|
||||
(a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name),
|
||||
);
|
||||
|
||||
const groups = (memberships as any[])
|
||||
const groups = memberships
|
||||
.filter((m) => m.group)
|
||||
.map((m) => ({
|
||||
id: m.group.id as string,
|
||||
@@ -302,7 +300,7 @@ export class ModuleGrantsService {
|
||||
|
||||
return {
|
||||
groups,
|
||||
modules: modules.map((module: any) => ({
|
||||
modules: modules.map((module) => ({
|
||||
module,
|
||||
viaGroups: groupNamesByModule.get(module.id) ?? [],
|
||||
direct: directModuleIds.has(module.id),
|
||||
|
||||
Reference in New Issue
Block a user