setup unifi wlans
This commit is contained in:
@@ -12,10 +12,21 @@ export const companies = {
|
||||
|
||||
if (!search) throw new Error("Unknown company.");
|
||||
|
||||
const freshCwData = await connectWiseApi.get(
|
||||
const freshCwData: { data: Company } = await connectWiseApi.get(
|
||||
`/company/companies/${search.cw_CompanyId}`,
|
||||
);
|
||||
return new CompanyController(search, freshCwData.data);
|
||||
const defaultContactData = await connectWiseApi.get(
|
||||
(freshCwData.data as Company).defaultContact._info.contact_href,
|
||||
);
|
||||
const allContactsData = await connectWiseApi.get(
|
||||
`${freshCwData.data._info.contacts_href}&pageSize=1000`,
|
||||
);
|
||||
|
||||
return new CompanyController(search, {
|
||||
company: freshCwData.data,
|
||||
defaultContact: defaultContactData.data,
|
||||
allContacts: allContactsData.data,
|
||||
});
|
||||
},
|
||||
|
||||
async count() {
|
||||
|
||||
@@ -79,8 +79,6 @@ export const credentialTypes = {
|
||||
});
|
||||
}
|
||||
|
||||
console.log(data.fields);
|
||||
|
||||
const credentialType = await prisma.credentialType.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
|
||||
+288
-26
@@ -4,10 +4,28 @@ import { fieldValidator } from "../modules/credentials/fieldValidator";
|
||||
import {
|
||||
CredentialField,
|
||||
CredentialTypeField,
|
||||
ValueType,
|
||||
} from "../modules/credentials/credentialTypeDefs";
|
||||
import { generateSecureValue } from "../modules/credentials/generateSecureValue";
|
||||
import GenericError from "../Errors/GenericError";
|
||||
|
||||
/**
|
||||
* Standard include clause used by every credential query.
|
||||
* Includes the credential type, company, secure values, and one level of sub-credentials.
|
||||
*/
|
||||
const credentialInclude = {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
subCredentials: {
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const credentials = {
|
||||
/**
|
||||
* Fetch Credential
|
||||
@@ -20,11 +38,7 @@ export const credentials = {
|
||||
async fetch(id: string): Promise<CredentialController> {
|
||||
const credential = await prisma.credential.findFirst({
|
||||
where: { id },
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
include: credentialInclude,
|
||||
});
|
||||
|
||||
if (!credential) {
|
||||
@@ -42,19 +56,17 @@ export const credentials = {
|
||||
/**
|
||||
* Fetch Credentials by Company
|
||||
*
|
||||
* Fetch all credentials associated with a specific company.
|
||||
* Fetch all top-level credentials associated with a specific company.
|
||||
* Sub-credentials are excluded from the top-level list and instead
|
||||
* included nested under their parent credential.
|
||||
*
|
||||
* @param companyId - The company ID to fetch credentials for
|
||||
* @returns {Promise<CredentialController[]>} - Array of credential controllers
|
||||
*/
|
||||
async fetchByCompany(companyId: string): Promise<CredentialController[]> {
|
||||
const credentialsList = await prisma.credential.findMany({
|
||||
where: { companyId },
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
where: { companyId, subCredentialOfId: null },
|
||||
include: credentialInclude,
|
||||
});
|
||||
|
||||
return credentialsList.map((cred) => new CredentialController(cred));
|
||||
@@ -68,6 +80,10 @@ export const credentials = {
|
||||
* the credential type, encrypting secure fields, and inserting everything
|
||||
* into the database atomically.
|
||||
*
|
||||
* When the credential type contains multi-credential fields, pass
|
||||
* `subCredentials` keyed by the multi-credential field ID. Each entry
|
||||
* is an array of sub-credential objects with their own name and fields.
|
||||
*
|
||||
* @param data - The credential data to create
|
||||
* @returns {Promise<CredentialController>} - The created credential controller
|
||||
*/
|
||||
@@ -80,6 +96,10 @@ export const credentials = {
|
||||
fieldId: string;
|
||||
value: string;
|
||||
}[];
|
||||
subCredentials?: Record<
|
||||
string,
|
||||
{ name: string; fields: { fieldId: string; value: string }[] }[]
|
||||
>;
|
||||
}): Promise<CredentialController> {
|
||||
// Fetch the credential type to get acceptable fields
|
||||
const credentialType = await prisma.credentialType.findFirst({
|
||||
@@ -95,22 +115,31 @@ export const credentials = {
|
||||
});
|
||||
}
|
||||
|
||||
// Validate the fields against acceptable fields
|
||||
const acceptableFields = (
|
||||
credentialType.fields! as any as CredentialTypeField[]
|
||||
).map((f: { id: string; name: string; secure: boolean }) => ({
|
||||
const typeFields = credentialType.fields! as any as CredentialTypeField[];
|
||||
|
||||
// Validate the fields against acceptable fields (exclude multi-credential fields
|
||||
// from value validation since they don't carry a direct value).
|
||||
const acceptableFields = typeFields.map((f) => ({
|
||||
id: f.id,
|
||||
name: f.name,
|
||||
secure: f.secure,
|
||||
required: f.required,
|
||||
valueType: f.valueType,
|
||||
subFields: f.subFields,
|
||||
})) as CredentialTypeField[];
|
||||
|
||||
const validatedFields = await fieldValidator(
|
||||
data.fields as any as CredentialField[],
|
||||
acceptableFields,
|
||||
);
|
||||
|
||||
// Separate secure and non-secure fields
|
||||
const secureFields = validatedFields.filter((f) => f.secure);
|
||||
const nonSecureFields = validatedFields.filter((f) => !f.secure);
|
||||
// Separate secure, non-secure, and multi-credential fields
|
||||
const secureFields = validatedFields.filter(
|
||||
(f) => f.secure && !f.isMultiCredential,
|
||||
);
|
||||
const nonSecureFields = validatedFields.filter(
|
||||
(f) => !f.secure && !f.isMultiCredential,
|
||||
);
|
||||
|
||||
// Build fields object for non-secure fields
|
||||
const fieldsObject: Record<string, any> = {};
|
||||
@@ -118,6 +147,13 @@ export const credentials = {
|
||||
fieldsObject[field.fieldId] = field.value;
|
||||
});
|
||||
|
||||
// Initialise multi-credential field slots with empty arrays
|
||||
typeFields
|
||||
.filter((f) => f.valueType === ValueType.MULTI_CREDENTIAL)
|
||||
.forEach((f) => {
|
||||
fieldsObject[f.id] = [];
|
||||
});
|
||||
|
||||
// Encrypt secure field values
|
||||
const secureValueData = secureFields.map((field) => {
|
||||
const { encrypted, hash } = generateSecureValue(field.value);
|
||||
@@ -128,7 +164,7 @@ export const credentials = {
|
||||
};
|
||||
});
|
||||
|
||||
// Create credential and all secure values in a transaction
|
||||
// Create the parent credential first
|
||||
const credential = await prisma.credential.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
@@ -140,20 +176,246 @@ export const credentials = {
|
||||
create: secureValueData,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
type: true,
|
||||
company: true,
|
||||
securevalues: true,
|
||||
},
|
||||
});
|
||||
|
||||
return new CredentialController(credential);
|
||||
// Create inline sub-credentials when provided
|
||||
if (data.subCredentials) {
|
||||
for (const [fieldId, subCredDataList] of Object.entries(
|
||||
data.subCredentials,
|
||||
)) {
|
||||
const fieldDef = typeFields.find((f) => f.id === fieldId);
|
||||
|
||||
if (!fieldDef || fieldDef.valueType !== ValueType.MULTI_CREDENTIAL) {
|
||||
throw new GenericError({
|
||||
message: `Field '${fieldId}' is not a multi-credential field`,
|
||||
name: "InvalidMultiCredentialField",
|
||||
cause: `Cannot create sub-credentials for field '${fieldId}' because it is not a multi-credential field.`,
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const subFieldDefs = (fieldDef.subFields ??
|
||||
[]) as CredentialTypeField[];
|
||||
const subCredIds: string[] = [];
|
||||
|
||||
for (const subCredData of subCredDataList) {
|
||||
const validatedSubFields = await fieldValidator(
|
||||
subCredData.fields as any as CredentialField[],
|
||||
subFieldDefs,
|
||||
);
|
||||
|
||||
const subSecure = validatedSubFields.filter((f) => f.secure);
|
||||
const subNonSecure = validatedSubFields.filter((f) => !f.secure);
|
||||
|
||||
const subFieldsObject: Record<string, any> = {};
|
||||
subNonSecure.forEach((f) => {
|
||||
subFieldsObject[f.fieldId] = f.value;
|
||||
});
|
||||
|
||||
const subSecureValueData = subSecure.map((f) => {
|
||||
const { encrypted, hash } = generateSecureValue(f.value);
|
||||
return { name: f.fieldId, content: encrypted, hash };
|
||||
});
|
||||
|
||||
const subCred = await prisma.credential.create({
|
||||
data: {
|
||||
name: subCredData.name,
|
||||
typeId: data.typeId,
|
||||
companyId: data.companyId,
|
||||
subCredentialOfId: credential.id,
|
||||
fields: subFieldsObject,
|
||||
securevalues: { create: subSecureValueData },
|
||||
},
|
||||
});
|
||||
|
||||
subCredIds.push(subCred.id);
|
||||
}
|
||||
|
||||
fieldsObject[fieldId] = subCredIds;
|
||||
}
|
||||
|
||||
// Persist the sub-credential ID arrays on the parent
|
||||
await prisma.credential.update({
|
||||
where: { id: credential.id },
|
||||
data: { fields: fieldsObject },
|
||||
});
|
||||
}
|
||||
|
||||
// Re-fetch with full includes
|
||||
const completeCredential = await prisma.credential.findFirst({
|
||||
where: { id: credential.id },
|
||||
include: credentialInclude,
|
||||
});
|
||||
|
||||
return new CredentialController(completeCredential!);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add Sub-Credential
|
||||
*
|
||||
* Create a new sub-credential under an existing parent credential
|
||||
* for a specific multi-credential field.
|
||||
*
|
||||
* @param parentId - The parent credential ID
|
||||
* @param fieldId - The multi-credential field this sub-credential belongs to
|
||||
* @param data - The sub-credential data (name and fields)
|
||||
* @returns {Promise<CredentialController>} - The created sub-credential controller
|
||||
*/
|
||||
async addSubCredential(
|
||||
parentId: string,
|
||||
fieldId: string,
|
||||
data: {
|
||||
name: string;
|
||||
fields: { fieldId: string; value: string }[];
|
||||
},
|
||||
): Promise<CredentialController> {
|
||||
const parent = await prisma.credential.findFirst({
|
||||
where: { id: parentId },
|
||||
include: { type: true },
|
||||
});
|
||||
|
||||
if (!parent) {
|
||||
throw new GenericError({
|
||||
message: "Parent credential not found",
|
||||
name: "CredentialNotFound",
|
||||
cause: `No credential exists with ID '${parentId}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
const typeFields = parent.type.fields as any as CredentialTypeField[];
|
||||
const fieldDef = typeFields.find((f) => f.id === fieldId);
|
||||
|
||||
if (!fieldDef || fieldDef.valueType !== ValueType.MULTI_CREDENTIAL) {
|
||||
throw new GenericError({
|
||||
message: `Field '${fieldId}' is not a multi-credential field`,
|
||||
name: "InvalidMultiCredentialField",
|
||||
cause: `Cannot create sub-credentials for field '${fieldId}' because it is not a multi-credential field.`,
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const subFieldDefs = (fieldDef.subFields ?? []) as CredentialTypeField[];
|
||||
const validatedFields = await fieldValidator(
|
||||
data.fields as any as CredentialField[],
|
||||
subFieldDefs,
|
||||
);
|
||||
|
||||
const secureFields = validatedFields.filter((f) => f.secure);
|
||||
const nonSecureFields = validatedFields.filter((f) => !f.secure);
|
||||
|
||||
const subFieldsObject: Record<string, any> = {};
|
||||
nonSecureFields.forEach((f) => {
|
||||
subFieldsObject[f.fieldId] = f.value;
|
||||
});
|
||||
|
||||
const secureValueData = secureFields.map((f) => {
|
||||
const { encrypted, hash } = generateSecureValue(f.value);
|
||||
return { name: f.fieldId, content: encrypted, hash };
|
||||
});
|
||||
|
||||
const subCredential = await prisma.credential.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
typeId: parent.typeId,
|
||||
companyId: parent.companyId,
|
||||
subCredentialOfId: parentId,
|
||||
fields: subFieldsObject,
|
||||
securevalues: { create: secureValueData },
|
||||
},
|
||||
include: credentialInclude,
|
||||
});
|
||||
|
||||
// Update parent's fields JSON to include the new sub-credential ID
|
||||
const parentFields = parent.fields as Record<string, any>;
|
||||
const subCredIds: string[] = parentFields[fieldId] ?? [];
|
||||
subCredIds.push(subCredential.id);
|
||||
parentFields[fieldId] = subCredIds;
|
||||
|
||||
await prisma.credential.update({
|
||||
where: { id: parentId },
|
||||
data: { fields: parentFields },
|
||||
});
|
||||
|
||||
return new CredentialController(subCredential);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove Sub-Credential
|
||||
*
|
||||
* Delete a sub-credential and remove its reference from the parent credential's
|
||||
* multi-credential field.
|
||||
*
|
||||
* @param parentId - The parent credential ID
|
||||
* @param subCredentialId - The sub-credential ID to remove
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async removeSubCredential(
|
||||
parentId: string,
|
||||
subCredentialId: string,
|
||||
): Promise<void> {
|
||||
const subCredential = await prisma.credential.findFirst({
|
||||
where: { id: subCredentialId, subCredentialOfId: parentId },
|
||||
});
|
||||
|
||||
if (!subCredential) {
|
||||
throw new GenericError({
|
||||
message: "Sub-credential not found",
|
||||
name: "SubCredentialNotFound",
|
||||
cause: `No sub-credential with ID '${subCredentialId}' exists under credential '${parentId}'`,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
// Delete the sub-credential (cascade removes its secure values)
|
||||
await prisma.credential.delete({
|
||||
where: { id: subCredentialId },
|
||||
});
|
||||
|
||||
// Remove the sub-credential ID from the parent's fields JSON
|
||||
const parent = await prisma.credential.findFirst({
|
||||
where: { id: parentId },
|
||||
});
|
||||
|
||||
if (parent) {
|
||||
const parentFields = parent.fields as Record<string, any>;
|
||||
for (const key of Object.keys(parentFields)) {
|
||||
if (Array.isArray(parentFields[key])) {
|
||||
parentFields[key] = parentFields[key].filter(
|
||||
(id: string) => id !== subCredentialId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.credential.update({
|
||||
where: { id: parentId },
|
||||
data: { fields: parentFields },
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch Sub-Credentials
|
||||
*
|
||||
* Fetch all sub-credentials that belong to a specific parent credential.
|
||||
*
|
||||
* @param parentId - The parent credential ID
|
||||
* @returns {Promise<CredentialController[]>} - Array of sub-credential controllers
|
||||
*/
|
||||
async fetchSubCredentials(parentId: string): Promise<CredentialController[]> {
|
||||
const subCredentials = await prisma.credential.findMany({
|
||||
where: { subCredentialOfId: parentId },
|
||||
include: credentialInclude,
|
||||
});
|
||||
|
||||
return subCredentials.map((sc) => new CredentialController(sc));
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete Credential
|
||||
*
|
||||
* Delete a credential by its ID.
|
||||
* Sub-credentials are cascade-deleted automatically by the database.
|
||||
*
|
||||
* @param id - The credential ID to delete
|
||||
* @returns {Promise<void>}
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
import { prisma, unifi, unifiUsername, unifiPassword } from "../constants";
|
||||
import GenericError from "../Errors/GenericError";
|
||||
import { UnifiSite } from "../../generated/prisma/client";
|
||||
|
||||
let loggedIn = false;
|
||||
|
||||
async function ensureLoggedIn(): Promise<void> {
|
||||
if (loggedIn) return;
|
||||
if (!unifiPassword)
|
||||
throw new GenericError({
|
||||
name: "UnifiConfigError",
|
||||
message: "UniFi controller credentials are not configured.",
|
||||
status: 503,
|
||||
});
|
||||
await unifi.login(unifiUsername, unifiPassword);
|
||||
loggedIn = true;
|
||||
}
|
||||
|
||||
export const unifiSites = {
|
||||
/**
|
||||
* Fetch a UniFi site record from the database by its internal ID.
|
||||
*/
|
||||
async fetch(id: string): Promise<UnifiSite> {
|
||||
const site = await prisma.unifiSite.findFirst({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!site)
|
||||
throw new GenericError({
|
||||
name: "UnifiSiteNotFound",
|
||||
message: `UniFi site with id '${id}' was not found.`,
|
||||
status: 404,
|
||||
});
|
||||
|
||||
return site;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch all UniFi site records from the database.
|
||||
*/
|
||||
async fetchAll(): Promise<UnifiSite[]> {
|
||||
return prisma.unifiSite.findMany({
|
||||
include: { company: true },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch all UniFi site records linked to a specific company.
|
||||
*/
|
||||
async fetchByCompany(companyId: string): Promise<UnifiSite[]> {
|
||||
return prisma.unifiSite.findMany({
|
||||
where: { companyId },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Link a UniFi site to a company.
|
||||
*/
|
||||
async linkToCompany(siteId: string, companyId: string): Promise<UnifiSite> {
|
||||
const site = await prisma.unifiSite.findFirst({ where: { id: siteId } });
|
||||
if (!site)
|
||||
throw new GenericError({
|
||||
name: "UnifiSiteNotFound",
|
||||
message: `UniFi site '${siteId}' was not found.`,
|
||||
status: 404,
|
||||
});
|
||||
|
||||
const company = await prisma.company.findFirst({
|
||||
where: { id: companyId },
|
||||
});
|
||||
if (!company)
|
||||
throw new GenericError({
|
||||
name: "CompanyNotFound",
|
||||
message: `Company '${companyId}' was not found.`,
|
||||
status: 404,
|
||||
});
|
||||
|
||||
return prisma.unifiSite.update({
|
||||
where: { id: siteId },
|
||||
data: { companyId },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Unlink a UniFi site from its company.
|
||||
*/
|
||||
async unlinkFromCompany(siteId: string): Promise<UnifiSite> {
|
||||
return prisma.unifiSite.update({
|
||||
where: { id: siteId },
|
||||
data: { companyId: null },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sync all sites from the UniFi controller into the database.
|
||||
* Creates new records for sites not yet tracked, updates names for existing ones.
|
||||
*/
|
||||
async syncSites(): Promise<UnifiSite[]> {
|
||||
await ensureLoggedIn();
|
||||
|
||||
// Fetch all sites from the controller
|
||||
const allSites = await unifi.getAllSites();
|
||||
|
||||
const results: UnifiSite[] = [];
|
||||
|
||||
for (const site of allSites) {
|
||||
const existing = await prisma.unifiSite.findFirst({
|
||||
where: { siteId: site.name },
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
const updated = await prisma.unifiSite.update({
|
||||
where: { id: existing.id },
|
||||
data: { name: site.description },
|
||||
});
|
||||
results.push(updated);
|
||||
} else {
|
||||
const created = await prisma.unifiSite.create({
|
||||
data: {
|
||||
name: site.description,
|
||||
siteId: site.name,
|
||||
},
|
||||
});
|
||||
results.push(created);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get live site overview from the UniFi controller.
|
||||
*/
|
||||
async getSiteOverview(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getSiteOverview(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get live devices from the UniFi controller for a site.
|
||||
*/
|
||||
async getDevices(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getDevices(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get live WiFi networks (WLANs) from the UniFi controller for a site.
|
||||
*/
|
||||
async getWlanConf(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getWlanConf(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a WiFi network on the UniFi controller.
|
||||
*/
|
||||
async updateWlanConf(
|
||||
siteId: string,
|
||||
wlanId: string,
|
||||
updates: Parameters<typeof unifi.updateWlanConf>[2],
|
||||
) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.updateWlanConf(siteId, wlanId, updates);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get live network configurations from the UniFi controller for a site.
|
||||
*/
|
||||
async getNetworks(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getNetworks(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new site on the UniFi controller and track it in the database.
|
||||
*/
|
||||
async createSite(description: string): Promise<UnifiSite> {
|
||||
await ensureLoggedIn();
|
||||
|
||||
const created = await unifi.createSite(description);
|
||||
|
||||
return prisma.unifiSite.create({
|
||||
data: {
|
||||
name: created.description,
|
||||
siteId: created.name,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get WLAN groups from the UniFi controller for a site.
|
||||
*/
|
||||
async getWlanGroups(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getWlanGroups(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new WLAN group (AP broadcasting group) on the UniFi controller.
|
||||
*/
|
||||
async createWlanGroup(
|
||||
siteId: string,
|
||||
input: Parameters<typeof unifi.createWlanGroup>[1],
|
||||
) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.createWlanGroup(siteId, input);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get user groups (speed profiles) from the UniFi controller for a site.
|
||||
*/
|
||||
async getUserGroups(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getUserGroups(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new user group (speed profile) on the UniFi controller.
|
||||
*/
|
||||
async createUserGroup(
|
||||
siteId: string,
|
||||
input: Parameters<typeof unifi.createUserGroup>[1],
|
||||
) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.createUserGroup(siteId, input);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get AP groups from the UniFi controller for a site.
|
||||
*/
|
||||
async getApGroups(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getApGroups(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new AP group on the UniFi controller.
|
||||
*/
|
||||
async createApGroup(
|
||||
siteId: string,
|
||||
name: string,
|
||||
deviceMacs: string[],
|
||||
forWlanconf: boolean = false,
|
||||
) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.createApGroup(siteId, name, deviceMacs, forWlanconf);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update an existing AP group's device MACs on the UniFi controller.
|
||||
*/
|
||||
async updateApGroup(siteId: string, groupId: string, deviceMacs: string[]) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.updateApGroup(siteId, groupId, deviceMacs);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get access points only from the UniFi controller for a site.
|
||||
*/
|
||||
async getAccessPoints(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getAccessPoints(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get WiFi SSID limits per AP per radio band.
|
||||
*/
|
||||
async getWifiLimits(siteId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getWifiLimits(siteId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get private pre-shared keys for a specific WLAN.
|
||||
*/
|
||||
async getPrivatePSKs(siteId: string, wlanId: string) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.getPrivatePSKs(siteId, wlanId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a private pre-shared key on a specific WLAN.
|
||||
*/
|
||||
async createPrivatePSK(
|
||||
siteId: string,
|
||||
wlanId: string,
|
||||
psk: Parameters<typeof unifi.createPrivatePSK>[2],
|
||||
) {
|
||||
await ensureLoggedIn();
|
||||
return unifi.createPrivatePSK(siteId, wlanId, psk);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user