fix(registry): align registry integrations with updated auth, storage, repository, and audit models
This commit is contained in:
@@ -109,7 +109,7 @@ export class AdminAuthApi {
|
||||
},
|
||||
attributeMapping: body.attributeMapping,
|
||||
provisioning: body.provisioning,
|
||||
createdById: ctx.actor!.userId,
|
||||
createdById: ctx.actor!.userId!,
|
||||
});
|
||||
} else if (body.type === 'ldap' && body.ldapConfig) {
|
||||
// Encrypt bind password
|
||||
@@ -124,7 +124,7 @@ export class AdminAuthApi {
|
||||
},
|
||||
attributeMapping: body.attributeMapping,
|
||||
provisioning: body.provisioning,
|
||||
createdById: ctx.actor!.userId,
|
||||
createdById: ctx.actor!.userId!,
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
@@ -138,11 +138,10 @@ export class AdminAuthApi {
|
||||
actorId: ctx.actor!.userId,
|
||||
actorType: 'user',
|
||||
actorIp: ctx.ip,
|
||||
}).log('ORGANIZATION_CREATED', 'system', {
|
||||
}).log('AUTH_PROVIDER_CREATED', 'auth_provider', {
|
||||
resourceId: provider.id,
|
||||
success: true,
|
||||
metadata: {
|
||||
action: 'auth_provider_created',
|
||||
providerName: provider.name,
|
||||
providerType: provider.type,
|
||||
},
|
||||
@@ -270,11 +269,10 @@ export class AdminAuthApi {
|
||||
actorId: ctx.actor!.userId,
|
||||
actorType: 'user',
|
||||
actorIp: ctx.ip,
|
||||
}).log('ORGANIZATION_UPDATED', 'system', {
|
||||
}).log('AUTH_PROVIDER_UPDATED', 'auth_provider', {
|
||||
resourceId: provider.id,
|
||||
success: true,
|
||||
metadata: {
|
||||
action: 'auth_provider_updated',
|
||||
providerName: provider.name,
|
||||
},
|
||||
});
|
||||
@@ -321,11 +319,10 @@ export class AdminAuthApi {
|
||||
actorId: ctx.actor!.userId,
|
||||
actorType: 'user',
|
||||
actorIp: ctx.ip,
|
||||
}).log('ORGANIZATION_DELETED', 'system', {
|
||||
}).log('AUTH_PROVIDER_DELETED', 'auth_provider', {
|
||||
resourceId: provider.id,
|
||||
success: true,
|
||||
metadata: {
|
||||
action: 'auth_provider_disabled',
|
||||
providerName: provider.name,
|
||||
},
|
||||
});
|
||||
@@ -360,11 +357,10 @@ export class AdminAuthApi {
|
||||
actorId: ctx.actor!.userId,
|
||||
actorType: 'user',
|
||||
actorIp: ctx.ip,
|
||||
}).log('ORGANIZATION_UPDATED', 'system', {
|
||||
}).log('AUTH_PROVIDER_TESTED', 'auth_provider', {
|
||||
resourceId: id,
|
||||
success: result.success,
|
||||
metadata: {
|
||||
action: 'auth_provider_tested',
|
||||
result: result.success ? 'success' : 'failure',
|
||||
latencyMs: result.latencyMs,
|
||||
error: result.error,
|
||||
@@ -433,12 +429,9 @@ export class AdminAuthApi {
|
||||
actorId: ctx.actor!.userId,
|
||||
actorType: 'user',
|
||||
actorIp: ctx.ip,
|
||||
}).log('ORGANIZATION_UPDATED', 'system', {
|
||||
}).log('PLATFORM_SETTINGS_UPDATED', 'platform_settings', {
|
||||
resourceId: 'platform-settings',
|
||||
success: true,
|
||||
metadata: {
|
||||
action: 'platform_settings_updated',
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -39,7 +39,13 @@ export class OrganizationApi {
|
||||
if (ctx.actor.user?.isSystemAdmin) {
|
||||
organizations = await Organization.getInstances({});
|
||||
} else {
|
||||
organizations = await OrganizationMember.getUserOrganizations(ctx.actor.userId);
|
||||
const memberships = await OrganizationMember.getUserOrganizations(ctx.actor.userId);
|
||||
const orgs: Organization[] = [];
|
||||
for (const m of memberships) {
|
||||
const org = await Organization.findById(m.organizationId);
|
||||
if (org) orgs.push(org);
|
||||
}
|
||||
organizations = orgs;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -155,8 +161,8 @@ export class OrganizationApi {
|
||||
membership.organizationId = org.id;
|
||||
membership.userId = ctx.actor.userId;
|
||||
membership.role = 'owner';
|
||||
membership.addedById = ctx.actor.userId;
|
||||
membership.addedAt = new Date();
|
||||
membership.invitedBy = ctx.actor.userId;
|
||||
membership.joinedAt = new Date();
|
||||
|
||||
await membership.save();
|
||||
|
||||
@@ -310,7 +316,7 @@ export class OrganizationApi {
|
||||
return {
|
||||
userId: m.userId,
|
||||
role: m.role,
|
||||
addedAt: m.addedAt,
|
||||
addedAt: m.joinedAt,
|
||||
user: user
|
||||
? {
|
||||
username: user.username,
|
||||
@@ -384,8 +390,8 @@ export class OrganizationApi {
|
||||
membership.organizationId = org.id;
|
||||
membership.userId = userId;
|
||||
membership.role = role;
|
||||
membership.addedById = ctx.actor.userId;
|
||||
membership.addedAt = new Date();
|
||||
membership.invitedBy = ctx.actor.userId;
|
||||
membership.joinedAt = new Date();
|
||||
|
||||
await membership.save();
|
||||
|
||||
@@ -398,7 +404,7 @@ export class OrganizationApi {
|
||||
body: {
|
||||
userId: membership.userId,
|
||||
role: membership.role,
|
||||
addedAt: membership.addedAt,
|
||||
addedAt: membership.joinedAt,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
@@ -174,7 +174,7 @@ export class PackageApi {
|
||||
publishedAt: data.publishedAt,
|
||||
size: data.size,
|
||||
downloads: data.downloads,
|
||||
checksum: data.checksum,
|
||||
checksum: data.metadata?.checksum,
|
||||
}));
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { IApiContext, IApiResponse } from '../router.ts';
|
||||
import { PermissionService } from '../../services/permission.service.ts';
|
||||
import { AuditService } from '../../services/audit.service.ts';
|
||||
import { Repository, Organization } from '../../models/index.ts';
|
||||
import type { TRegistryProtocol } from '../../interfaces/auth.interfaces.ts';
|
||||
import type { TRegistryProtocol, TRepositoryVisibility } from '../../interfaces/auth.interfaces.ts';
|
||||
|
||||
export class RepositoryApi {
|
||||
private permissionService: PermissionService;
|
||||
@@ -26,7 +26,6 @@ export class RepositoryApi {
|
||||
const { orgId } = ctx.params;
|
||||
|
||||
try {
|
||||
// Get accessible repositories
|
||||
const repositories = await this.permissionService.getAccessibleRepositories(
|
||||
ctx.actor.userId,
|
||||
orgId
|
||||
@@ -38,9 +37,9 @@ export class RepositoryApi {
|
||||
repositories: repositories.map((repo) => ({
|
||||
id: repo.id,
|
||||
name: repo.name,
|
||||
displayName: repo.displayName,
|
||||
description: repo.description,
|
||||
protocols: repo.protocols,
|
||||
protocol: repo.protocol,
|
||||
visibility: repo.visibility,
|
||||
isPublic: repo.isPublic,
|
||||
packageCount: repo.packageCount,
|
||||
createdAt: repo.createdAt,
|
||||
@@ -84,11 +83,10 @@ export class RepositoryApi {
|
||||
id: repo.id,
|
||||
organizationId: repo.organizationId,
|
||||
name: repo.name,
|
||||
displayName: repo.displayName,
|
||||
description: repo.description,
|
||||
protocols: repo.protocols,
|
||||
protocol: repo.protocol,
|
||||
visibility: repo.visibility,
|
||||
isPublic: repo.isPublic,
|
||||
settings: repo.settings,
|
||||
packageCount: repo.packageCount,
|
||||
storageBytes: repo.storageBytes,
|
||||
createdAt: repo.createdAt,
|
||||
@@ -118,17 +116,22 @@ export class RepositoryApi {
|
||||
|
||||
try {
|
||||
const body = await ctx.request.json();
|
||||
const { name, displayName, description, protocols, isPublic, settings } = body;
|
||||
const { name, description, protocol, visibility } = body as {
|
||||
name: string;
|
||||
description?: string;
|
||||
protocol?: TRegistryProtocol;
|
||||
visibility?: TRepositoryVisibility;
|
||||
};
|
||||
|
||||
if (!name) {
|
||||
return { status: 400, body: { error: 'Repository name is required' } };
|
||||
}
|
||||
|
||||
// Validate name format
|
||||
if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(name)) {
|
||||
if (!/^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$/.test(name)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: { error: 'Name must be lowercase alphanumeric with optional hyphens' },
|
||||
body: { error: 'Name must be lowercase alphanumeric with optional dots, hyphens, or underscores' },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,30 +141,15 @@ export class RepositoryApi {
|
||||
return { status: 404, body: { error: 'Organization not found' } };
|
||||
}
|
||||
|
||||
// Check if name is taken in this org
|
||||
const existing = await Repository.findByName(orgId, name);
|
||||
if (existing) {
|
||||
return { status: 409, body: { error: 'Repository name already taken in this organization' } };
|
||||
}
|
||||
|
||||
// Create repository
|
||||
const repo = new Repository();
|
||||
repo.id = await Repository.getNewId();
|
||||
repo.organizationId = orgId;
|
||||
repo.name = name;
|
||||
repo.displayName = displayName || name;
|
||||
repo.description = description;
|
||||
repo.protocols = protocols || ['npm'];
|
||||
repo.isPublic = isPublic ?? false;
|
||||
repo.settings = settings || {
|
||||
allowOverwrite: false,
|
||||
immutableTags: false,
|
||||
retentionDays: 0,
|
||||
};
|
||||
repo.createdAt = new Date();
|
||||
repo.createdById = ctx.actor.userId;
|
||||
|
||||
await repo.save();
|
||||
// Create repository using the model's factory method
|
||||
const repo = await Repository.createRepository({
|
||||
organizationId: orgId,
|
||||
name,
|
||||
description,
|
||||
protocol: protocol || 'npm',
|
||||
visibility: visibility || 'private',
|
||||
createdById: ctx.actor.userId,
|
||||
});
|
||||
|
||||
// Audit log
|
||||
await AuditService.withContext({
|
||||
@@ -177,9 +165,9 @@ export class RepositoryApi {
|
||||
id: repo.id,
|
||||
organizationId: repo.organizationId,
|
||||
name: repo.name,
|
||||
displayName: repo.displayName,
|
||||
description: repo.description,
|
||||
protocols: repo.protocols,
|
||||
protocol: repo.protocol,
|
||||
visibility: repo.visibility,
|
||||
isPublic: repo.isPublic,
|
||||
createdAt: repo.createdAt,
|
||||
},
|
||||
@@ -217,13 +205,13 @@ export class RepositoryApi {
|
||||
}
|
||||
|
||||
const body = await ctx.request.json();
|
||||
const { displayName, description, protocols, isPublic, settings } = body;
|
||||
const { description, visibility } = body as {
|
||||
description?: string;
|
||||
visibility?: TRepositoryVisibility;
|
||||
};
|
||||
|
||||
if (displayName !== undefined) repo.displayName = displayName;
|
||||
if (description !== undefined) repo.description = description;
|
||||
if (protocols !== undefined) repo.protocols = protocols;
|
||||
if (isPublic !== undefined) repo.isPublic = isPublic;
|
||||
if (settings !== undefined) repo.settings = { ...repo.settings, ...settings };
|
||||
if (visibility !== undefined) repo.visibility = visibility;
|
||||
|
||||
await repo.save();
|
||||
|
||||
@@ -232,11 +220,10 @@ export class RepositoryApi {
|
||||
body: {
|
||||
id: repo.id,
|
||||
name: repo.name,
|
||||
displayName: repo.displayName,
|
||||
description: repo.description,
|
||||
protocols: repo.protocols,
|
||||
protocol: repo.protocol,
|
||||
visibility: repo.visibility,
|
||||
isPublic: repo.isPublic,
|
||||
settings: repo.settings,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
@@ -137,8 +137,8 @@ export class UserApi {
|
||||
user.username = username;
|
||||
user.passwordHash = passwordHash;
|
||||
user.displayName = displayName || username;
|
||||
user.isSystemAdmin = isSystemAdmin || false;
|
||||
user.isActive = true;
|
||||
user.isPlatformAdmin = isSystemAdmin || false;
|
||||
user.status = 'active';
|
||||
user.createdAt = new Date();
|
||||
|
||||
await user.save();
|
||||
@@ -189,8 +189,8 @@ export class UserApi {
|
||||
|
||||
// Only admins can change these
|
||||
if (ctx.actor.user?.isSystemAdmin) {
|
||||
if (isActive !== undefined) user.isActive = isActive;
|
||||
if (isSystemAdmin !== undefined) user.isSystemAdmin = isSystemAdmin;
|
||||
if (isActive !== undefined) user.status = isActive ? 'active' : 'suspended';
|
||||
if (isSystemAdmin !== undefined) user.isPlatformAdmin = isSystemAdmin;
|
||||
}
|
||||
|
||||
// Password change
|
||||
@@ -245,7 +245,7 @@ export class UserApi {
|
||||
}
|
||||
|
||||
// Soft delete - deactivate instead of removing
|
||||
user.isActive = false;
|
||||
user.status = 'suspended';
|
||||
await user.save();
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user