mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-07-26 11:59:14 +00:00
Add ability to manage the 'managedBy' attribute for AD objects
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/2b2008cc-a510-433c-9379-89ffac9ce6a0.jpg
This commit is contained in:
@@ -196,6 +196,75 @@ class LdapClient extends EventEmitter {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Get the managed by attribute for an object
|
||||
async getManagedBy(connectionId: number, dn: string): Promise<string | null> {
|
||||
const client = this.getClient(connectionId);
|
||||
if (!client) throw new Error('LDAP connection not established');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
client.search(dn, {
|
||||
scope: 'base',
|
||||
attributes: ['managedBy']
|
||||
}, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
let managedBy: string | null = null;
|
||||
|
||||
res.on('searchEntry', (entry) => {
|
||||
const attrs = entry.attributes;
|
||||
for (const attr of attrs) {
|
||||
if (attr.type === 'managedBy' && attr.vals && attr.vals.length > 0) {
|
||||
managedBy = attr.vals[0].toString();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
res.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
res.on('end', (result) => {
|
||||
if (result.status !== 0) {
|
||||
reject(new Error(`LDAP search error: ${result.errorMessage}`));
|
||||
return;
|
||||
}
|
||||
resolve(managedBy);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Set the managed by attribute for an object
|
||||
async setManagedBy(connectionId: number, dn: string, managerDn: string | null): Promise<boolean> {
|
||||
const client = this.getClient(connectionId);
|
||||
if (!client) throw new Error('LDAP connection not established');
|
||||
|
||||
const changes = [];
|
||||
|
||||
if (managerDn === null) {
|
||||
// Remove the managedBy attribute
|
||||
changes.push(new ldap.Change({
|
||||
operation: 'delete',
|
||||
modification: {
|
||||
managedBy: []
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
// Add or replace the managedBy attribute
|
||||
changes.push(new ldap.Change({
|
||||
operation: 'replace',
|
||||
modification: {
|
||||
managedBy: managerDn
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return this.updateEntry(connectionId, dn, changes);
|
||||
}
|
||||
}
|
||||
|
||||
export const ldapClient = new LdapClient();
|
||||
|
||||
+282
-1
@@ -9,7 +9,8 @@ import {
|
||||
moveComputerSchema,
|
||||
moveUserSchema,
|
||||
addToGroupSchema,
|
||||
removeFromGroupSchema
|
||||
removeFromGroupSchema,
|
||||
updateManagedBySchema
|
||||
} from "@shared/schema";
|
||||
import { ZodError } from "zod";
|
||||
import rateLimit from "express-rate-limit";
|
||||
@@ -3083,6 +3084,286 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/managed-by:
|
||||
* get:
|
||||
* summary: Get the 'managedBy' attribute for an AD object
|
||||
* tags: [AD Objects]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* - name: objectGUID
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - name: objectType
|
||||
* in: query
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* enum: [user, group, computer, organizationalUnit]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The managedBy attribute
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* managedBy:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Object not found
|
||||
*/
|
||||
app.get("/api/connections/:connectionId/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
const objectGUID = req.query.objectGUID as string;
|
||||
const objectType = req.query.objectType as string;
|
||||
|
||||
if (!objectGUID || !objectType) {
|
||||
return res.status(400).json({ message: "objectGUID and objectType are required query parameters" });
|
||||
}
|
||||
|
||||
if (!['user', 'group', 'computer', 'organizationalUnit'].includes(objectType)) {
|
||||
return res.status(400).json({ message: "objectType must be one of: user, group, computer, organizationalUnit" });
|
||||
}
|
||||
|
||||
// Get the object distinguished name
|
||||
let objectDN;
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
const adUser = await storage.getAdUserByObjectGUID(connectionId, objectGUID);
|
||||
if (!adUser) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
objectDN = adUser.distinguishedName;
|
||||
break;
|
||||
case 'group':
|
||||
const adGroup = await storage.getAdGroupByObjectGUID(connectionId, objectGUID);
|
||||
if (!adGroup) {
|
||||
return res.status(404).json({ message: "Group not found" });
|
||||
}
|
||||
objectDN = adGroup.distinguishedName;
|
||||
break;
|
||||
case 'computer':
|
||||
const adComputer = await storage.getAdComputerByObjectGUID(connectionId, objectGUID);
|
||||
if (!adComputer) {
|
||||
return res.status(404).json({ message: "Computer not found" });
|
||||
}
|
||||
objectDN = adComputer.distinguishedName;
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
const adOU = await storage.getAdOrgUnitByObjectGUID(connectionId, objectGUID);
|
||||
if (!adOU) {
|
||||
return res.status(404).json({ message: "Organizational Unit not found" });
|
||||
}
|
||||
objectDN = adOU.distinguishedName;
|
||||
break;
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the managedBy attribute
|
||||
const managedBy = await ldapClient.getManagedBy(connectionId, objectDN);
|
||||
|
||||
return res.status(200).json({ managedBy });
|
||||
} catch (error) {
|
||||
console.error("Error getting managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to get managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/managed-by:
|
||||
* post:
|
||||
* summary: Set the 'managedBy' attribute for an AD object
|
||||
* tags: [AD Objects]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - objectGUID
|
||||
* - objectType
|
||||
* properties:
|
||||
* objectGUID:
|
||||
* type: string
|
||||
* managerDistinguishedName:
|
||||
* type: string
|
||||
* nullable: true
|
||||
* objectType:
|
||||
* type: string
|
||||
* enum: [user, group, computer, organizationalUnit]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: ManagedBy attribute updated successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* description: Object not found
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/managed-by", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
// Parse and validate request body
|
||||
try {
|
||||
updateManagedBySchema.parse(req.body);
|
||||
} catch (err) {
|
||||
if (err instanceof ZodError) {
|
||||
return handleZodError(err, res);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
const { objectGUID, managerDistinguishedName, objectType } = req.body;
|
||||
|
||||
// Get the object distinguished name
|
||||
let objectDN;
|
||||
let objectName;
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
const adUser = await storage.getAdUserByObjectGUID(connectionId, objectGUID);
|
||||
if (!adUser) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
objectDN = adUser.distinguishedName;
|
||||
objectName = adUser.displayName || adUser.sAMAccountName;
|
||||
break;
|
||||
case 'group':
|
||||
const adGroup = await storage.getAdGroupByObjectGUID(connectionId, objectGUID);
|
||||
if (!adGroup) {
|
||||
return res.status(404).json({ message: "Group not found" });
|
||||
}
|
||||
objectDN = adGroup.distinguishedName;
|
||||
objectName = adGroup.sAMAccountName;
|
||||
break;
|
||||
case 'computer':
|
||||
const adComputer = await storage.getAdComputerByObjectGUID(connectionId, objectGUID);
|
||||
if (!adComputer) {
|
||||
return res.status(404).json({ message: "Computer not found" });
|
||||
}
|
||||
objectDN = adComputer.distinguishedName;
|
||||
objectName = adComputer.name;
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
const adOU = await storage.getAdOrgUnitByObjectGUID(connectionId, objectGUID);
|
||||
if (!adOU) {
|
||||
return res.status(404).json({ message: "Organizational Unit not found" });
|
||||
}
|
||||
objectDN = adOU.distinguishedName;
|
||||
objectName = adOU.name;
|
||||
break;
|
||||
}
|
||||
|
||||
// Connect to LDAP
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
console.error("LDAP connection error:", error);
|
||||
return res.status(500).json({ message: "Failed to connect to LDAP server", error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the managedBy attribute
|
||||
await ldapClient.setManagedBy(connectionId, objectDN, managerDistinguishedName);
|
||||
|
||||
// Update the database record
|
||||
const updateData = { managedBy: managerDistinguishedName };
|
||||
switch (objectType) {
|
||||
case 'user':
|
||||
await storage.updateAdUserByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'group':
|
||||
await storage.updateAdGroupByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'computer':
|
||||
await storage.updateAdComputerByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
case 'organizationalUnit':
|
||||
await storage.updateAdOrgUnitByObjectGUID(connectionId, objectGUID, updateData);
|
||||
break;
|
||||
}
|
||||
|
||||
// Log the action
|
||||
await storage.createAuditLogEntry({
|
||||
action: `update_managed_by:${objectType}`,
|
||||
targetId: objectGUID,
|
||||
details: {
|
||||
objectDN,
|
||||
managerDN: managerDistinguishedName
|
||||
},
|
||||
userId: req.user?.id,
|
||||
connectionId
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
message: `ManagedBy attribute successfully updated for ${objectName}`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error updating managedBy attribute:", error);
|
||||
return res.status(500).json({ message: "Failed to update managedBy attribute", error: error.message });
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/audit-logs:
|
||||
|
||||
@@ -80,29 +80,37 @@ export interface IStorage {
|
||||
|
||||
// AD Users
|
||||
getAdUser(id: number): Promise<AdUser | undefined>;
|
||||
getAdUserByObjectGUID(connectionId: number, objectGUID: string): Promise<AdUser | undefined>;
|
||||
createAdUser(user: InsertAdUser): Promise<AdUser>;
|
||||
updateAdUser(id: number, user: Partial<AdUser>): Promise<AdUser | undefined>;
|
||||
updateAdUserByObjectGUID(connectionId: number, objectGUID: string, user: Partial<AdUser>): Promise<AdUser | undefined>;
|
||||
deleteAdUser(id: number): Promise<boolean>;
|
||||
listAdUsers(connectionId: number, query?: any): Promise<AdUser[]>;
|
||||
|
||||
// AD Groups
|
||||
getAdGroup(id: number): Promise<AdGroup | undefined>;
|
||||
getAdGroupByObjectGUID(connectionId: number, objectGUID: string): Promise<AdGroup | undefined>;
|
||||
createAdGroup(group: InsertAdGroup): Promise<AdGroup>;
|
||||
updateAdGroup(id: number, group: Partial<AdGroup>): Promise<AdGroup | undefined>;
|
||||
updateAdGroupByObjectGUID(connectionId: number, objectGUID: string, group: Partial<AdGroup>): Promise<AdGroup | undefined>;
|
||||
deleteAdGroup(id: number): Promise<boolean>;
|
||||
listAdGroups(connectionId: number, query?: any): Promise<AdGroup[]>;
|
||||
|
||||
// AD Organizational Units
|
||||
getAdOrgUnit(id: number): Promise<AdOrgUnit | undefined>;
|
||||
getAdOrgUnitByObjectGUID(connectionId: number, objectGUID: string): Promise<AdOrgUnit | undefined>;
|
||||
createAdOrgUnit(ou: InsertAdOrgUnit): Promise<AdOrgUnit>;
|
||||
updateAdOrgUnit(id: number, ou: Partial<AdOrgUnit>): Promise<AdOrgUnit | undefined>;
|
||||
updateAdOrgUnitByObjectGUID(connectionId: number, objectGUID: string, ou: Partial<AdOrgUnit>): Promise<AdOrgUnit | undefined>;
|
||||
deleteAdOrgUnit(id: number): Promise<boolean>;
|
||||
listAdOrgUnits(connectionId: number, query?: any): Promise<AdOrgUnit[]>;
|
||||
|
||||
// AD Computers
|
||||
getAdComputer(id: number): Promise<AdComputer | undefined>;
|
||||
getAdComputerByObjectGUID(connectionId: number, objectGUID: string): Promise<AdComputer | undefined>;
|
||||
createAdComputer(computer: InsertAdComputer): Promise<AdComputer>;
|
||||
updateAdComputer(id: number, computer: Partial<AdComputer>): Promise<AdComputer | undefined>;
|
||||
updateAdComputerByObjectGUID(connectionId: number, objectGUID: string, computer: Partial<AdComputer>): Promise<AdComputer | undefined>;
|
||||
deleteAdComputer(id: number): Promise<boolean>;
|
||||
listAdComputers(connectionId: number, query?: any): Promise<AdComputer[]>;
|
||||
|
||||
@@ -558,6 +566,18 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.select().from(adUsers).where(eq(adUsers.id, id));
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async getAdUserByObjectGUID(connectionId: number, objectGUID: string): Promise<AdUser | undefined> {
|
||||
const result = await db.select()
|
||||
.from(adUsers)
|
||||
.where(
|
||||
and(
|
||||
eq(adUsers.connectionId, connectionId),
|
||||
eq(adUsers.objectGUID, objectGUID)
|
||||
)
|
||||
);
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async createAdUser(user: InsertAdUser): Promise<AdUser> {
|
||||
const result = await db.insert(adUsers).values(user).returning();
|
||||
@@ -568,6 +588,19 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.update(adUsers).set(userData).where(eq(adUsers.id, id)).returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async updateAdUserByObjectGUID(connectionId: number, objectGUID: string, userData: Partial<AdUser>): Promise<AdUser | undefined> {
|
||||
const result = await db.update(adUsers)
|
||||
.set(userData)
|
||||
.where(
|
||||
and(
|
||||
eq(adUsers.connectionId, connectionId),
|
||||
eq(adUsers.objectGUID, objectGUID)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async deleteAdUser(id: number): Promise<boolean> {
|
||||
const result = await db.delete(adUsers).where(eq(adUsers.id, id)).returning({ id: adUsers.id });
|
||||
@@ -647,6 +680,18 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.select().from(adGroups).where(eq(adGroups.id, id));
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async getAdGroupByObjectGUID(connectionId: number, objectGUID: string): Promise<AdGroup | undefined> {
|
||||
const result = await db.select()
|
||||
.from(adGroups)
|
||||
.where(
|
||||
and(
|
||||
eq(adGroups.connectionId, connectionId),
|
||||
eq(adGroups.objectGUID, objectGUID)
|
||||
)
|
||||
);
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async createAdGroup(group: InsertAdGroup): Promise<AdGroup> {
|
||||
const result = await db.insert(adGroups).values(group).returning();
|
||||
@@ -657,6 +702,19 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.update(adGroups).set(groupData).where(eq(adGroups.id, id)).returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async updateAdGroupByObjectGUID(connectionId: number, objectGUID: string, groupData: Partial<AdGroup>): Promise<AdGroup | undefined> {
|
||||
const result = await db.update(adGroups)
|
||||
.set(groupData)
|
||||
.where(
|
||||
and(
|
||||
eq(adGroups.connectionId, connectionId),
|
||||
eq(adGroups.objectGUID, objectGUID)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async deleteAdGroup(id: number): Promise<boolean> {
|
||||
const result = await db.delete(adGroups).where(eq(adGroups.id, id)).returning({ id: adGroups.id });
|
||||
@@ -736,6 +794,18 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.select().from(adOrgUnits).where(eq(adOrgUnits.id, id));
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async getAdOrgUnitByObjectGUID(connectionId: number, objectGUID: string): Promise<AdOrgUnit | undefined> {
|
||||
const result = await db.select()
|
||||
.from(adOrgUnits)
|
||||
.where(
|
||||
and(
|
||||
eq(adOrgUnits.connectionId, connectionId),
|
||||
eq(adOrgUnits.objectGUID, objectGUID)
|
||||
)
|
||||
);
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async createAdOrgUnit(ou: InsertAdOrgUnit): Promise<AdOrgUnit> {
|
||||
const result = await db.insert(adOrgUnits).values(ou).returning();
|
||||
@@ -746,6 +816,19 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.update(adOrgUnits).set(ouData).where(eq(adOrgUnits.id, id)).returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async updateAdOrgUnitByObjectGUID(connectionId: number, objectGUID: string, ouData: Partial<AdOrgUnit>): Promise<AdOrgUnit | undefined> {
|
||||
const result = await db.update(adOrgUnits)
|
||||
.set(ouData)
|
||||
.where(
|
||||
and(
|
||||
eq(adOrgUnits.connectionId, connectionId),
|
||||
eq(adOrgUnits.objectGUID, objectGUID)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async deleteAdOrgUnit(id: number): Promise<boolean> {
|
||||
const result = await db.delete(adOrgUnits).where(eq(adOrgUnits.id, id)).returning({ id: adOrgUnits.id });
|
||||
@@ -779,6 +862,18 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.select().from(adComputers).where(eq(adComputers.id, id));
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async getAdComputerByObjectGUID(connectionId: number, objectGUID: string): Promise<AdComputer | undefined> {
|
||||
const result = await db.select()
|
||||
.from(adComputers)
|
||||
.where(
|
||||
and(
|
||||
eq(adComputers.connectionId, connectionId),
|
||||
eq(adComputers.objectGUID, objectGUID)
|
||||
)
|
||||
);
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async createAdComputer(computer: InsertAdComputer): Promise<AdComputer> {
|
||||
const result = await db.insert(adComputers).values(computer).returning();
|
||||
@@ -789,6 +884,19 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.update(adComputers).set(computerData).where(eq(adComputers.id, id)).returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async updateAdComputerByObjectGUID(connectionId: number, objectGUID: string, computerData: Partial<AdComputer>): Promise<AdComputer | undefined> {
|
||||
const result = await db.update(adComputers)
|
||||
.set(computerData)
|
||||
.where(
|
||||
and(
|
||||
eq(adComputers.connectionId, connectionId),
|
||||
eq(adComputers.objectGUID, objectGUID)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async deleteAdComputer(id: number): Promise<boolean> {
|
||||
const result = await db.delete(adComputers).where(eq(adComputers.id, id)).returning({ id: adComputers.id });
|
||||
|
||||
@@ -160,6 +160,7 @@ export const adUsers = pgTable("ad_users", {
|
||||
email: text("email"),
|
||||
enabled: boolean("enabled").default(true),
|
||||
lastLogon: timestamp("last_logon"),
|
||||
managedBy: text("managed_by"),
|
||||
memberOf: jsonb("member_of"),
|
||||
adProperties: jsonb("ad_properties"),
|
||||
});
|
||||
@@ -174,6 +175,7 @@ export const adGroups = pgTable("ad_groups", {
|
||||
sAMAccountName: text("sam_account_name").notNull(),
|
||||
groupType: text("group_type"),
|
||||
description: text("description"),
|
||||
managedBy: text("managed_by"),
|
||||
members: jsonb("members"),
|
||||
adProperties: jsonb("ad_properties"),
|
||||
});
|
||||
@@ -187,6 +189,7 @@ export const adOrgUnits = pgTable("ad_org_units", {
|
||||
cn: text("cn"),
|
||||
name: text("name").notNull(),
|
||||
description: text("description"),
|
||||
managedBy: text("managed_by"),
|
||||
adProperties: jsonb("ad_properties"),
|
||||
});
|
||||
|
||||
@@ -204,6 +207,7 @@ export const adComputers = pgTable("ad_computers", {
|
||||
operatingSystemVersion: text("operating_system_version"),
|
||||
lastLogon: timestamp("last_logon"),
|
||||
enabled: boolean("enabled").default(true),
|
||||
managedBy: text("managed_by"),
|
||||
memberOf: jsonb("member_of"),
|
||||
adProperties: jsonb("ad_properties"),
|
||||
});
|
||||
@@ -307,6 +311,13 @@ export const removeFromGroupSchema = z.object({
|
||||
objectType: z.enum(["user", "computer"]),
|
||||
});
|
||||
|
||||
// ManagedBy operation schema
|
||||
export const updateManagedBySchema = z.object({
|
||||
objectGUID: z.string().min(1, "Object GUID is required"),
|
||||
managerDistinguishedName: z.string().nullable(),
|
||||
objectType: z.enum(["user", "group", "computer", "organizationalUnit"]),
|
||||
});
|
||||
|
||||
// Export types
|
||||
export type Role = typeof roles.$inferSelect;
|
||||
export type InsertRole = z.infer<typeof insertRoleSchema>;
|
||||
@@ -339,6 +350,7 @@ export type MoveComputer = z.infer<typeof moveComputerSchema>;
|
||||
export type MoveUser = z.infer<typeof moveUserSchema>;
|
||||
export type AddToGroup = z.infer<typeof addToGroupSchema>;
|
||||
export type RemoveFromGroup = z.infer<typeof removeFromGroupSchema>;
|
||||
export type UpdateManagedBy = z.infer<typeof updateManagedBySchema>;
|
||||
|
||||
// LDAP Query Builder schemas
|
||||
export const ldapFilterObjectClasses = ["user", "group", "organizationalUnit", "computer", "domain"] as const;
|
||||
|
||||
Reference in New Issue
Block a user