Setup unifi wlans
This commit is contained in:
@@ -11,6 +11,8 @@ export const optima = {
|
||||
role: (await import("./optima-api/modules/roles")).role,
|
||||
permission: (await import("./optima-api/modules/permissions")).permission,
|
||||
user,
|
||||
users: (await import("./optima-api/modules/users")).users,
|
||||
unifi: (await import("./optima-api/modules/unifi")).unifi,
|
||||
};
|
||||
/**
|
||||
* @TODO
|
||||
|
||||
@@ -4,10 +4,16 @@ export const company = {
|
||||
async fetch(
|
||||
accessToken: string,
|
||||
id: string,
|
||||
options?: { includeAddress?: boolean },
|
||||
options?: {
|
||||
includeAddress?: boolean;
|
||||
includePrimaryContact?: boolean;
|
||||
includeAllContacts?: boolean;
|
||||
},
|
||||
) {
|
||||
const params: Record<string, string> = {};
|
||||
if (options?.includeAddress) params.includeAddress = "true";
|
||||
if (options?.includePrimaryContact) params.includePrimaryContact = "true";
|
||||
if (options?.includeAllContacts) params.includeAllContacts = "true";
|
||||
|
||||
const company = await api.get(`/v1/company/companies/${id}`, {
|
||||
params,
|
||||
|
||||
@@ -5,7 +5,8 @@ export interface CredentialTypeField {
|
||||
name: string;
|
||||
required: boolean;
|
||||
secure: boolean;
|
||||
valueType: "plain_text" | "password" | "number" | "email" | "url";
|
||||
valueType: string;
|
||||
subFields?: CredentialTypeField[];
|
||||
}
|
||||
|
||||
export interface CredentialType {
|
||||
|
||||
@@ -2,15 +2,20 @@ import api from "../axios";
|
||||
|
||||
export interface CredentialField {
|
||||
id: string;
|
||||
fieldId: string;
|
||||
name: string;
|
||||
secure: boolean;
|
||||
required: boolean;
|
||||
valueType: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Credential {
|
||||
id: string;
|
||||
name: string;
|
||||
notes?: string;
|
||||
typeId: string;
|
||||
companyId: string;
|
||||
subCredentialOfId?: string;
|
||||
fields: CredentialField[];
|
||||
type?: {
|
||||
id: string;
|
||||
@@ -45,6 +50,7 @@ export const credential = {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -62,7 +68,11 @@ export const credential = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async update(accessToken: string, id: string, data: { name: string }) {
|
||||
async update(
|
||||
accessToken: string,
|
||||
id: string,
|
||||
data: { name?: string; notes?: string },
|
||||
) {
|
||||
const response = await api.patch(`/v1/credential/credentials/${id}`, data, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
@@ -96,4 +106,79 @@ export const credential = {
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async fetchSecureValue(
|
||||
accessToken: string,
|
||||
credentialId: string,
|
||||
fieldId: string,
|
||||
) {
|
||||
const response = await api.get(
|
||||
`/v1/credential/credentials/${credentialId}/secure-values/${fieldId}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async fetchValueTypes(accessToken: string) {
|
||||
const response = await api.get("/v1/credential/valuetypes", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async fetchSubCredentials(accessToken: string, credentialId: string) {
|
||||
const response = await api.get(
|
||||
`/v1/credential/credentials/${credentialId}/sub-credentials`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async addSubCredential(
|
||||
accessToken: string,
|
||||
credentialId: string,
|
||||
data: {
|
||||
fieldId: string;
|
||||
name: string;
|
||||
fields: Array<{ fieldId: string; value: string }>;
|
||||
},
|
||||
) {
|
||||
const response = await api.post(
|
||||
`/v1/credential/credentials/${credentialId}/sub-credentials`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async removeSubCredential(
|
||||
accessToken: string,
|
||||
credentialId: string,
|
||||
subId: string,
|
||||
) {
|
||||
const response = await api.delete(
|
||||
`/v1/credential/credentials/${credentialId}/sub-credentials/${subId}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
import api from "../axios";
|
||||
|
||||
export interface UnifiSite {
|
||||
id: string;
|
||||
name: string;
|
||||
siteId: string;
|
||||
companyId: string | null;
|
||||
company?: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface UnifiSiteOverview {
|
||||
health: Array<{
|
||||
subsystem: string;
|
||||
status: string;
|
||||
numAdopted?: number;
|
||||
numGateway?: number;
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
sysInfo: {
|
||||
timezone?: string;
|
||||
hostname?: string;
|
||||
version?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
siteInfo: {
|
||||
description?: string;
|
||||
name?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export interface UnifiDevice {
|
||||
id: string;
|
||||
mac: string;
|
||||
model: string;
|
||||
name: string;
|
||||
type: string;
|
||||
state: string | number;
|
||||
ip: string;
|
||||
version: string;
|
||||
uptime: number;
|
||||
radios?: unknown[];
|
||||
uplink?: unknown;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface UnifiWifiNetwork {
|
||||
id: string;
|
||||
name?: string;
|
||||
siteId?: string;
|
||||
enabled?: boolean;
|
||||
security?: string;
|
||||
wpaMode?: string;
|
||||
wpaEnc?: string;
|
||||
wpa3Support?: boolean;
|
||||
wpa3Transition?: boolean;
|
||||
wpa3FastRoaming?: boolean;
|
||||
wpa3Enhanced192?: boolean;
|
||||
passphrase?: string;
|
||||
passphraseAutogenerated?: boolean;
|
||||
hideSSID?: boolean;
|
||||
isGuest?: boolean;
|
||||
band?: string;
|
||||
bands?: string[];
|
||||
networkconfId?: string;
|
||||
usergroupId?: string;
|
||||
apGroupIds?: string[];
|
||||
apGroupMode?: string;
|
||||
pmfMode?: string;
|
||||
groupRekey?: number;
|
||||
dtimMode?: string;
|
||||
dtimNg?: number;
|
||||
dtimNa?: number;
|
||||
dtim6e?: number;
|
||||
l2Isolation?: boolean;
|
||||
fastRoamingEnabled?: boolean;
|
||||
bssTransition?: boolean;
|
||||
uapsdEnabled?: boolean;
|
||||
iappEnabled?: boolean;
|
||||
proxyArp?: boolean;
|
||||
mcastenhanceEnabled?: boolean;
|
||||
macFilterEnabled?: boolean;
|
||||
macFilterPolicy?: string;
|
||||
macFilterList?: string[];
|
||||
radiusDasEnabled?: boolean;
|
||||
radiusMacAuthEnabled?: boolean;
|
||||
radiusMacaclFormat?: string;
|
||||
minrateSettingPreference?: string;
|
||||
minrateNgEnabled?: boolean;
|
||||
minrateNgDataRateKbps?: number;
|
||||
minrateNgAdvertisingRates?: boolean;
|
||||
minrateNaEnabled?: boolean;
|
||||
minrateNaDataRateKbps?: number;
|
||||
minrateNaAdvertisingRates?: boolean;
|
||||
settingPreference?: string;
|
||||
no2ghzOui?: boolean;
|
||||
privatePreSharedKeysEnabled?: boolean;
|
||||
privatePreSharedKeys?: unknown[];
|
||||
saeGroups?: unknown[];
|
||||
saePsk?: unknown[];
|
||||
schedule?: unknown[];
|
||||
scheduleWithDuration?: unknown[];
|
||||
bcFilterList?: unknown[];
|
||||
externalId?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface UnifiNetwork {
|
||||
id: string;
|
||||
name: string;
|
||||
purpose: string;
|
||||
subnet: string;
|
||||
vlanId: number | null;
|
||||
dhcpEnabled: boolean;
|
||||
dhcpStart: string;
|
||||
dhcpStop: string;
|
||||
domainName: string;
|
||||
isNat: boolean;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface UnifiWlanGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
siteId: string;
|
||||
noDelete: boolean;
|
||||
noEdit: boolean;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
export interface UnifiApGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
deviceMacs: string[];
|
||||
noDelete: boolean;
|
||||
}
|
||||
|
||||
export interface UnifiAccessPoint {
|
||||
id: string;
|
||||
mac: string;
|
||||
model: string;
|
||||
type: string;
|
||||
name: string;
|
||||
state: number;
|
||||
adopted: boolean;
|
||||
ip: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface UnifiSpeedProfile {
|
||||
id: string;
|
||||
name: string;
|
||||
siteId: string;
|
||||
noDelete: boolean;
|
||||
downloadLimitKbps: number;
|
||||
uploadLimitKbps: number;
|
||||
}
|
||||
|
||||
export interface UnifiPPSK {
|
||||
key: string;
|
||||
name: string;
|
||||
mac: string | null;
|
||||
vlanId: number | null;
|
||||
}
|
||||
|
||||
export const unifi = {
|
||||
/** Fetch all UniFi sites */
|
||||
async fetchSites(accessToken: string) {
|
||||
const response = await api.get("/v1/unifi/sites", {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Sync sites from UniFi controller */
|
||||
async syncSites(accessToken: string) {
|
||||
const response = await api.post(
|
||||
"/v1/unifi/sites/sync",
|
||||
{},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Create a new UniFi site */
|
||||
async createSite(accessToken: string, description: string) {
|
||||
const response = await api.post(
|
||||
"/v1/unifi/sites/create",
|
||||
{ description },
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Fetch a single UniFi site */
|
||||
async fetchSite(accessToken: string, id: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${id}`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Fetch UniFi sites linked to a company */
|
||||
async fetchCompanySites(accessToken: string, companyId: string) {
|
||||
const response = await api.get(
|
||||
`/v1/company/companies/${companyId}/unifi/sites`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Link a site to a company */
|
||||
async linkSite(accessToken: string, siteId: string, companyId: string) {
|
||||
const response = await api.post(
|
||||
`/v1/unifi/site/${siteId}/link`,
|
||||
{ companyId },
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Unlink a site from its company */
|
||||
async unlinkSite(accessToken: string, siteId: string) {
|
||||
const response = await api.post(
|
||||
`/v1/unifi/site/${siteId}/unlink`,
|
||||
{},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get site overview (health, sysInfo, siteInfo) */
|
||||
async fetchSiteOverview(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/overview`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get site devices */
|
||||
async fetchSiteDevices(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/devices`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get site WiFi networks */
|
||||
async fetchSiteWifi(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/wifi`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Update a WiFi network */
|
||||
async updateWifi(
|
||||
accessToken: string,
|
||||
siteId: string,
|
||||
wlanId: string,
|
||||
data: Record<string, unknown>,
|
||||
) {
|
||||
const response = await api.patch(
|
||||
`/v1/unifi/site/${siteId}/wifi/${wlanId}`,
|
||||
data,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get site networks */
|
||||
async fetchSiteNetworks(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/networks`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get WLAN groups */
|
||||
async fetchWlanGroups(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/wlan-groups`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get AP groups (collections of access points for broadcasting) */
|
||||
async fetchApGroups(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/ap-groups`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get access points */
|
||||
async fetchAccessPoints(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/access-points`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get speed profiles (user groups) */
|
||||
async fetchSpeedProfiles(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/speed-profiles`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Create a speed profile */
|
||||
async createSpeedProfile(
|
||||
accessToken: string,
|
||||
siteId: string,
|
||||
data: {
|
||||
name: string;
|
||||
downloadLimitKbps?: number;
|
||||
uploadLimitKbps?: number;
|
||||
},
|
||||
) {
|
||||
const response = await api.post(
|
||||
`/v1/unifi/site/${siteId}/speed-profiles`,
|
||||
data,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get private PSKs for a WLAN */
|
||||
async fetchPPSKs(accessToken: string, siteId: string, wlanId: string) {
|
||||
const response = await api.get(
|
||||
`/v1/unifi/site/${siteId}/wifi/${wlanId}/ppsk`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Create a private PSK on a WLAN */
|
||||
async createPPSK(
|
||||
accessToken: string,
|
||||
siteId: string,
|
||||
wlanId: string,
|
||||
data: { key: string; name: string; mac?: string; vlanId?: number },
|
||||
) {
|
||||
const response = await api.post(
|
||||
`/v1/unifi/site/${siteId}/wifi/${wlanId}/ppsk`,
|
||||
data,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/** Get WiFi limits per AP per radio */
|
||||
async fetchWifiLimits(accessToken: string, siteId: string) {
|
||||
const response = await api.get(`/v1/unifi/site/${siteId}/wifi-limits`, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
@@ -89,8 +89,8 @@ export const user = {
|
||||
} catch {}
|
||||
reject(new Error("Timed out waiting for auth callback"));
|
||||
},
|
||||
2 * 60 * 1000,
|
||||
); // 2 minutes
|
||||
5 * 60 * 1000,
|
||||
); // 5 minutes
|
||||
|
||||
const handlePayload = (payload: any) => {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import api from "../axios";
|
||||
import type { Role } from "./roles";
|
||||
|
||||
export interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
login: string;
|
||||
image?: string;
|
||||
roles: string[];
|
||||
permissions?: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface PermissionCheckResult {
|
||||
permission: string;
|
||||
hasPermission: boolean;
|
||||
}
|
||||
|
||||
export const users = {
|
||||
/**
|
||||
* Fetch all users.
|
||||
* Requires: user.read.other, user.list.other
|
||||
*/
|
||||
async fetchAll(accessToken: string): Promise<{ data: User[] }> {
|
||||
const response = await api.get("/v1/user/users", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch a specific user by their ID.
|
||||
* Requires: user.read.other
|
||||
*/
|
||||
async fetch(
|
||||
accessToken: string,
|
||||
identifier: string,
|
||||
): Promise<{ data: User }> {
|
||||
const response = await api.get(`/v1/user/users/${identifier}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a specific user's information.
|
||||
* Requires: user.write.other
|
||||
* Conditional: user.roles.other (if roles included), user.permissions.other (if permissions included)
|
||||
*/
|
||||
async update(
|
||||
accessToken: string,
|
||||
identifier: string,
|
||||
updates: {
|
||||
name?: string;
|
||||
image?: string;
|
||||
roles?: string[];
|
||||
permissions?: string[];
|
||||
},
|
||||
): Promise<{ data: User }> {
|
||||
const response = await api.patch(`/v1/user/users/${identifier}`, updates, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete a specific user.
|
||||
* Requires: user.delete.other
|
||||
*/
|
||||
async delete(
|
||||
accessToken: string,
|
||||
identifier: string,
|
||||
): Promise<{ data: User }> {
|
||||
const response = await api.delete(`/v1/user/users/${identifier}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch all roles assigned to a specific user.
|
||||
* Requires: user.read.other, role.read
|
||||
*/
|
||||
async fetchRoles(
|
||||
accessToken: string,
|
||||
identifier: string,
|
||||
): Promise<{ data: Role[] }> {
|
||||
const response = await api.get(`/v1/user/users/${identifier}/roles`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a specific user has certain permissions.
|
||||
* Requires: user.read.other
|
||||
*/
|
||||
async checkPermissions(
|
||||
accessToken: string,
|
||||
identifier: string,
|
||||
permissions: string[],
|
||||
): Promise<{ data: { results: PermissionCheckResult[] } }> {
|
||||
const response = await api.post(
|
||||
`/v1/user/users/${identifier}/check-permission`,
|
||||
{ permissions },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user