Browse Source

add pagination and sorting to clients list

pull/2433/head
Владислав Прийма 6 months ago
parent
commit
aac3b82fd2
  1. 33
      src/app/components/Clients/Pagination.vue
  2. 6
      src/app/components/Clients/Sort.vue
  3. 5
      src/app/pages/index.vue
  4. 38
      src/app/stores/clients.ts
  5. 3
      src/app/stores/global.ts
  6. 18284
      src/package-lock.json
  7. 6
      src/server/api/client/index.get.ts
  8. 280
      src/server/database/repositories/client/service.ts
  9. 17
      src/server/database/repositories/client/types.ts
  10. 4
      src/server/routes/metrics/json.get.ts
  11. 2
      src/server/routes/metrics/prometheus.get.ts
  12. 58
      src/server/utils/WireGuard.ts

33
src/app/components/Clients/Pagination.vue

@ -0,0 +1,33 @@
<template>
<div
class="mt-4 flex items-center justify-center gap-2"
>
<button
class="btn"
v-if="clientsStore.page > 1"
@click="setPage(clientsStore.page - 1)"
>
</button>
<span class="text-sm text-gray-500">
{{ clientsStore.page }} / {{ clientsStore.totalPages }}
</span>
<button
class="btn"
v-if="clientsStore.page < clientsStore.totalPages"
@click="setPage(clientsStore.page + 1)"
>
</button>
</div>
</template>
<script setup lang="ts">
const clientsStore = useClientsStore();
function setPage(p: number) {
clientsStore.setPageQuery(p);
}
</script>

6
src/app/components/Clients/Sort.vue

@ -1,7 +1,7 @@
<template> <template>
<BasePrimaryButton @click="toggleSort"> <BasePrimaryButton @click="toggleSort">
<IconsArrowDown <IconsArrowDown
v-if="globalStore.sortClient === true" v-if="clientsStore.sortClient === true"
class="w-4 md:mr-2" class="w-4 md:mr-2"
/> />
<IconsArrowUp v-else class="w-4 md:mr-2" /> <IconsArrowUp v-else class="w-4 md:mr-2" />
@ -10,11 +10,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const globalStore = useGlobalStore();
const clientsStore = useClientsStore(); const clientsStore = useClientsStore();
function toggleSort() { function toggleSort() {
globalStore.sortClient = !globalStore.sortClient; clientsStore.setSortClientQuery(!clientsStore.sortClient)
clientsStore.refresh().catch(console.error);
} }
</script> </script>

5
src/app/pages/index.vue

@ -15,6 +15,11 @@
v-if="clientsStore.clients && clientsStore.clients.length > 0" v-if="clientsStore.clients && clientsStore.clients.length > 0"
/> />
</div> </div>
<div>
<ClientsPagination
v-if="clientsStore.totalPages > 1"
/>
</div>
<ClientsEmpty <ClientsEmpty
v-if="clientsStore.clients && clientsStore.clients.length === 0" v-if="clientsStore.clients && clientsStore.clients.length === 0"
/> />

38
src/app/stores/clients.ts

@ -6,7 +6,7 @@ type WGClientReturn = TypedInternalResponse<
'/api/client', '/api/client',
unknown, unknown,
'get' 'get'
>[number]; >['clients'][number];
export type LocalClient = WGClientReturn & { export type LocalClient = WGClientReturn & {
avatar?: string; avatar?: string;
@ -30,9 +30,16 @@ export const useClientsStore = defineStore('Clients', () => {
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const clients = ref<null | LocalClient[]>(null); const clients = ref<null | LocalClient[]>(null);
const clientsPersist = ref<Record<string, ClientPersist>>({}); const clientsPersist = ref<Record<string, ClientPersist>>({});
const sortClient = ref<boolean>(true)
const page = ref<number>(1);
const limit = ref<number>(10);
const totalPages = ref<number>(1);
const searchParams = ref({ const searchParams = ref({
filter: undefined as string | undefined, filter: undefined as string | undefined,
page: page,
limit: limit,
sortClient: sortClient
}); });
const { data: _clients, refresh: _refresh } = useFetch('/api/client', { const { data: _clients, refresh: _refresh } = useFetch('/api/client', {
@ -43,7 +50,7 @@ export const useClientsStore = defineStore('Clients', () => {
// TODO: rewrite // TODO: rewrite
async function refresh({ updateCharts = false } = {}) { async function refresh({ updateCharts = false } = {}) {
await _refresh(); await _refresh();
let transformedClients = _clients.value?.map((client) => { let transformedClients = _clients.value?.clients.map((client) => {
let avatar = undefined; let avatar = undefined;
if (client.name.includes('@') && client.name.includes('.')) { if (client.name.includes('@') && client.name.includes('.')) {
avatar = `https://gravatar.com/avatar/${sha256(client.name.toLowerCase().trim())}.jpg`; avatar = `https://gravatar.com/avatar/${sha256(client.name.toLowerCase().trim())}.jpg`;
@ -125,16 +132,11 @@ export const useClientsStore = defineStore('Clients', () => {
}; };
}); });
// TODO: move sort to backend
if (transformedClients !== undefined) {
transformedClients = sortByProperty(
transformedClients,
'name',
globalStore.sortClient
);
}
clients.value = transformedClients ?? null; clients.value = transformedClients ?? null;
if (_clients.value){
let total = (_clients.value?.total ?? _clients.value?.clients?.length) ?? 0;
totalPages.value = total <= limit.value ? 1 : Math.ceil(total / limit.value);
}
} }
function setSearchQuery(filter: string) { function setSearchQuery(filter: string) {
@ -142,5 +144,17 @@ export const useClientsStore = defineStore('Clients', () => {
searchParams.value.filter = filter || undefined; searchParams.value.filter = filter || undefined;
} }
return { clients, clientsPersist, refresh, _clients, setSearchQuery }; function setPageQuery(value: number) {
clients.value = null;
page.value = value;
searchParams.value.page = value;
}
function setSortClientQuery(value: boolean) {
clients.value = null;
sortClient.value = value;
searchParams.value.sortClient = value;
}
return { clients, clientsPersist, sortClient, page, totalPages, refresh, _clients, setSearchQuery, setPageQuery, setSortClientQuery };
}); });

3
src/app/stores/global.ts

@ -3,8 +3,6 @@ export const useGlobalStore = defineStore('Global', () => {
method: 'get', method: 'get',
}); });
const sortClient = ref(true); // Sort clients by name, true = asc, false = desc
const uiShowCharts = useCookie<boolean>('uiShowCharts', { const uiShowCharts = useCookie<boolean>('uiShowCharts', {
default: () => false, default: () => false,
maxAge: 365 * 24 * 60 * 60, maxAge: 365 * 24 * 60 * 60,
@ -20,7 +18,6 @@ export const useGlobalStore = defineStore('Global', () => {
}); });
return { return {
sortClient,
information, information,
uiShowCharts, uiShowCharts,
toggleCharts, toggleCharts,

18284
src/package-lock.json

File diff suppressed because it is too large

6
src/server/api/client/index.get.ts

@ -4,14 +4,14 @@ export default definePermissionEventHandler(
'clients', 'clients',
'custom', 'custom',
async ({ event, user }) => { async ({ event, user }) => {
const { filter } = await getValidatedQuery( const { filter, page, limit, sortClient } = await getValidatedQuery(
event, event,
validateZod(ClientQuerySchema, event) validateZod(ClientQuerySchema, event)
); );
if (user.role === roles.ADMIN) { if (user.role === roles.ADMIN) {
return WireGuard.getAllClients(filter); return WireGuard.getAllClients({ filter: filter, page: page, limit: limit, sortClient: sortClient });
} }
return WireGuard.getClientsForUser(user.id, filter); return WireGuard.getClientsForUser(user.id, { filter: filter, page: page, limit: limit, sortClient: sortClient });
} }
); );

280
src/server/database/repositories/client/service.ts

@ -9,13 +9,14 @@ import type {
import type { DBType } from '#db/sqlite'; import type { DBType } from '#db/sqlite';
import { wgInterface, userConfig } from '#db/schema'; import { wgInterface, userConfig } from '#db/schema';
function createPreparedStatement(db: DBType) { function createPreparedStatement(db: DBType, direction: 'ASC' | 'DESC') {
return { return {
findAll: db.query.client findAll: db.query.client
.findMany({ .findMany({
with: { with: {
oneTimeLink: true, oneTimeLink: true,
}, },
orderBy: sql`${client.name} ${sql.raw(direction)}`,
}) })
.prepare(), .prepare(),
findAllPublic: db.query.client findAllPublic: db.query.client
@ -27,6 +28,27 @@ function createPreparedStatement(db: DBType) {
privateKey: false, privateKey: false,
preSharedKey: false, preSharedKey: false,
}, },
orderBy: sql`${client.name} ${sql.raw(direction)}`,
})
.prepare(),
countAll: db
.select({
total: sql<number>`count(*)`
})
.from(client)
.prepare(),
findPaginatedListPublic: db.query.client
.findMany({
with: {
oneTimeLink: true,
},
columns: {
privateKey: false,
preSharedKey: false,
},
limit: sql.placeholder('limit'),
offset: sql.placeholder('offset'),
orderBy: sql`${client.name} ${sql.raw(direction)}`,
}) })
.prepare(), .prepare(),
findById: db.query.client findById: db.query.client
@ -40,6 +62,31 @@ function createPreparedStatement(db: DBType) {
privateKey: false, privateKey: false,
preSharedKey: false, preSharedKey: false,
}, },
orderBy: sql`${client.name} ${sql.raw(direction)}`,
})
.prepare(),
countByUserId: db
.select({
total: sql<number>`count(*)`
})
.from(client)
.where(
and(
eq(client.userId, sql.placeholder('userId'))
)
)
.prepare(),
findPaginatedListByUserId: db.query.client
.findMany({
where: eq(client.userId, sql.placeholder('userId')),
with: { oneTimeLink: true },
columns: {
privateKey: false,
preSharedKey: false,
},
limit: sql.placeholder('limit'),
offset: sql.placeholder('offset'),
orderBy: sql`${client.name} ${sql.raw(direction)}`,
}) })
.prepare(), .prepare(),
findAllPublicFiltered: db.query.client findAllPublicFiltered: db.query.client
@ -56,6 +103,41 @@ function createPreparedStatement(db: DBType) {
privateKey: false, privateKey: false,
preSharedKey: false, preSharedKey: false,
}, },
orderBy: sql`${client.name} ${sql.raw(direction)}`,
})
.prepare(),
countAllFiltered: db
.select({
total: sql<number>`count(*)`
})
.from(client)
.where(
and(
or(
like(client.name, sql.placeholder('filter')),
like(client.ipv4Address, sql.placeholder('filter')),
like(client.ipv6Address, sql.placeholder('filter'))
)
)
)
.prepare(),
findPaginatedListPublicFiltered: db.query.client
.findMany({
where: or(
like(client.name, sql.placeholder('filter')),
like(client.ipv4Address, sql.placeholder('filter')),
like(client.ipv6Address, sql.placeholder('filter'))
),
with: {
oneTimeLink: true,
},
columns: {
privateKey: false,
preSharedKey: false,
},
limit: sql.placeholder('limit'),
offset: sql.placeholder('offset'),
orderBy: sql`${client.name} ${sql.raw(direction)}`,
}) })
.prepare(), .prepare(),
findByUserIdFiltered: db.query.client findByUserIdFiltered: db.query.client
@ -73,6 +155,43 @@ function createPreparedStatement(db: DBType) {
privateKey: false, privateKey: false,
preSharedKey: false, preSharedKey: false,
}, },
orderBy: sql`${client.name} ${sql.raw(direction)}`,
})
.prepare(),
countByUserIdFiltered: db
.select({
total: sql<number>`count(*)`
})
.from(client)
.where(
and(
eq(client.userId, sql.placeholder('userId')),
or(
like(client.name, sql.placeholder('filter')),
like(client.ipv4Address, sql.placeholder('filter')),
like(client.ipv6Address, sql.placeholder('filter'))
)
)
)
.prepare(),
findPaginatedListByUserIdFiltered: db.query.client
.findMany({
where: and(
eq(client.userId, sql.placeholder('userId')),
or(
like(client.name, sql.placeholder('filter')),
like(client.ipv4Address, sql.placeholder('filter')),
like(client.ipv6Address, sql.placeholder('filter'))
)
),
with: { oneTimeLink: true },
columns: {
privateKey: false,
preSharedKey: false,
},
limit: sql.placeholder('limit'),
offset: sql.placeholder('offset'),
orderBy: sql`${client.name} ${sql.raw(direction)}`,
}) })
.prepare(), .prepare(),
toggle: db toggle: db
@ -89,15 +208,39 @@ function createPreparedStatement(db: DBType) {
export class ClientService { export class ClientService {
#db: DBType; #db: DBType;
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) { constructor(db: DBType) {
this.#db = db; this.#db = db;
this.#statements = createPreparedStatement(db);
} }
async getForUser(userId: ID) { getStatements(direction?: 'ASC' | 'DESC'){
const result = await this.#statements.findByUserId.execute({ userId }); return createPreparedStatement(this.#db, direction ?? "ASC");
}
async getForUser(userId: ID, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const result = await this.getStatements(direction).findByUserId.execute({ userId });
return result.map((row) => ({
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt),
}));
}
async countForUser(userId: ID) {
const result = await this.getStatements().countByUserId.execute({ userId });
return result?.at(0)?.total ?? 0;
}
async getPaginatedListForUser(userId: ID, page: number, limit: number, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const offset = (page - 1) * limit;
const result = await this.getStatements(direction).findPaginatedListByUserId.execute({
userId,
limit,
offset });
return result.map((row) => ({ return result.map((row) => ({
...row, ...row,
createdAt: new Date(row.createdAt), createdAt: new Date(row.createdAt),
@ -108,8 +251,9 @@ export class ClientService {
/** /**
* Never return values directly from this function. Use {@link getAllPublic} instead. * Never return values directly from this function. Use {@link getAllPublic} instead.
*/ */
async getAll() { async getAll(sortClient: boolean) {
const result = await this.#statements.findAll.execute(); const direction = sortClient ? 'ASC' : 'DESC';
const result = await this.getStatements(direction).findAll.execute();
return result.map((row) => ({ return result.map((row) => ({
...row, ...row,
createdAt: new Date(row.createdAt), createdAt: new Date(row.createdAt),
@ -120,8 +264,38 @@ export class ClientService {
/** /**
* Returns all clients without sensitive data * Returns all clients without sensitive data
*/ */
async getAllPublic() { async getAllPublic(sortClient: boolean) {
const result = await this.#statements.findAllPublic.execute(); const direction = sortClient ? 'ASC' : 'DESC';
const result = await this.getStatements(direction).findAllPublic.execute();
return result.map((row) => ({
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt),
}));
}
/**
* Returns count all clients
*/
async countAll() {
const result = await this.getStatements().countAll.execute();
return result?.at(0)?.total ?? 0;
}
/**
* Get a paginated list of clients without sensitive data
*/
async getPaginatedListPublic(page: number, limit: number, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const offset = (page - 1) * limit;
const result = await this.getStatements(direction).findPaginatedListPublic.execute({
limit,
offset,
});
return result.map((row) => ({ return result.map((row) => ({
...row, ...row,
createdAt: new Date(row.createdAt), createdAt: new Date(row.createdAt),
@ -132,10 +306,11 @@ export class ClientService {
/** /**
* Get clients based on user ID and filter conditions * Get clients based on user ID and filter conditions
*/ */
async getForUserFiltered(userId: ID, filter: string) { async getForUserFiltered(userId: ID, filter: string, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const filterPattern = `%${filter.toLowerCase()}%`; const filterPattern = `%${filter.toLowerCase()}%`;
const result = await this.#statements.findByUserIdFiltered.execute({ const result = await this.getStatements(direction).findByUserIdFiltered.execute({
userId, userId,
filter: filterPattern, filter: filterPattern,
}); });
@ -147,14 +322,87 @@ export class ClientService {
})); }));
} }
/**
* Get count clients based on user ID and filter conditions
*/
async countForUserFiltered(userId: ID, filter: string) {
const filterPattern = `%${filter.toLowerCase()}%`;
const result = await this.getStatements().countByUserIdFiltered.execute({
userId,
filter: filterPattern,
});
return result?.at(0)?.total ?? 0;
}
/**
* Get a paginated list of clients based on user ID and filter conditions
*/
async getPaginatedListForUserFiltered(userId: ID, filter: string, page: number, limit: number, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const filterPattern = `%${filter.toLowerCase()}%`;
const offset = (page - 1) * limit;
const result = await this.getStatements(direction).findPaginatedListByUserIdFiltered.execute({
userId,
filter: filterPattern,
limit,
offset
});
return result.map((row) => ({
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt),
}));
}
/** /**
* Get all clients based on filter conditions without sensitive data * Get all clients based on filter conditions without sensitive data
*/ */
async getAllPublicFiltered(filter: string) { async getAllPublicFiltered(filter: string, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const filterPattern = `%${filter.toLowerCase()}%`; const filterPattern = `%${filter.toLowerCase()}%`;
const result = await this.#statements.findAllPublicFiltered.execute({ const result = await this.getStatements(direction).findAllPublicFiltered.execute({
filter: filterPattern,
});
return result.map((row) => ({
...row,
createdAt: new Date(row.createdAt),
updatedAt: new Date(row.updatedAt),
}));
}
/**
* Get count all clients based on filter conditions
*/
async countAllFiltered(filter: string) {
const filterPattern = `%${filter.toLowerCase()}%`;
const result = await this.getStatements().countAllFiltered.execute({
filter: filterPattern,
});
return result?.at(0)?.total ?? 0;
}
/**
* Get a paginated list of clients based on filter conditions without sensitive data.
*/
async getPaginatedListPublicFiltered(filter: string, page: number, limit: number, sortClient: boolean) {
const direction = sortClient ? 'ASC' : 'DESC';
const filterPattern = `%${filter.toLowerCase()}%`;
const offset = (page - 1) * limit;
const result = await this.getStatements(direction).findPaginatedListPublicFiltered.execute({
filter: filterPattern, filter: filterPattern,
limit,
offset,
sortClient
}); });
return result.map((row) => ({ return result.map((row) => ({
@ -165,7 +413,7 @@ export class ClientService {
} }
get(id: ID) { get(id: ID) {
return this.#statements.findById.execute({ id }); return this.getStatements().findById.execute({ id });
} }
async create({ name, expiresAt }: ClientCreateType) { async create({ name, expiresAt }: ClientCreateType) {
@ -232,11 +480,11 @@ export class ClientService {
} }
toggle(id: ID, enabled: boolean) { toggle(id: ID, enabled: boolean) {
return this.#statements.toggle.execute({ id, enabled }); return this.getStatements().toggle.execute({ id, enabled });
} }
delete(id: ID) { delete(id: ID) {
return this.#statements.delete.execute({ id }); return this.getStatements().delete.execute({ id });
} }
update(id: ID, data: UpdateClientType) { update(id: ID, data: UpdateClientType) {

17
src/server/database/repositories/client/types.ts

@ -41,6 +41,20 @@ const address6 = z
const filter = z.string().optional(); const filter = z.string().optional();
const page = z.coerce.number().int().optional();
const limit = z.coerce.number().int().optional();
const sortClient = z
.coerce
.string()
.optional()
.transform((value) => {
if (value === "true") return true;
else if (value === "false") return false;
return undefined;
});
const serverAllowedIps = z.array(AddressSchema, { const serverAllowedIps = z.array(AddressSchema, {
message: t('zod.client.serverAllowedIps'), message: t('zod.client.serverAllowedIps'),
}); });
@ -54,6 +68,9 @@ export type ClientCreateType = z.infer<typeof ClientCreateSchema>;
export const ClientQuerySchema = z.object({ export const ClientQuerySchema = z.object({
filter: filter, filter: filter,
page: page,
limit: limit,
sortClient: sortClient,
}); });
export type ClientQueryType = z.infer<typeof ClientQuerySchema>; export type ClientQueryType = z.infer<typeof ClientQuerySchema>;

4
src/server/routes/metrics/json.get.ts

@ -7,7 +7,7 @@ async function getMetricsJSON() {
let wireguardPeerCount = 0; let wireguardPeerCount = 0;
let wireguardEnabledPeersCount = 0; let wireguardEnabledPeersCount = 0;
let wireguardConnectedPeersCount = 0; let wireguardConnectedPeersCount = 0;
for (const client of clients) { for (const client of clients.clients) {
wireguardPeerCount++; wireguardPeerCount++;
if (client.enabled === true) { if (client.enabled === true) {
wireguardEnabledPeersCount++; wireguardEnabledPeersCount++;
@ -20,7 +20,7 @@ async function getMetricsJSON() {
wireguard_configured_peers: wireguardPeerCount, wireguard_configured_peers: wireguardPeerCount,
wireguard_enabled_peers: wireguardEnabledPeersCount, wireguard_enabled_peers: wireguardEnabledPeersCount,
wireguard_connected_peers: wireguardConnectedPeersCount, wireguard_connected_peers: wireguardConnectedPeersCount,
clients: clients.map((client) => ({ clients: clients.clients.map((client) => ({
name: client.name, name: client.name,
enabled: client.enabled, enabled: client.enabled,
ipv4Address: client.ipv4Address, ipv4Address: client.ipv4Address,

2
src/server/routes/metrics/prometheus.get.ts

@ -12,7 +12,7 @@ async function getPrometheusResponse() {
const wireguardSentBytes = []; const wireguardSentBytes = [];
const wireguardReceivedBytes = []; const wireguardReceivedBytes = [];
const wireguardLatestHandshakeSeconds = []; const wireguardLatestHandshakeSeconds = [];
for (const client of clients) { for (const client of clients.clients) {
wireguardPeerCount++; wireguardPeerCount++;
if (client.enabled === true) { if (client.enabled === true) {
wireguardEnabledPeersCount++; wireguardEnabledPeersCount++;

58
src/server/utils/WireGuard.ts

@ -24,7 +24,7 @@ class WireGuard {
* Make sure to pass an updated InterfaceType object * Make sure to pass an updated InterfaceType object
*/ */
async #saveWireguardConfig(wgInterface: InterfaceType) { async #saveWireguardConfig(wgInterface: InterfaceType) {
const clients = await Database.clients.getAll(); const clients = await Database.clients.getAll(true);
const hooks = await Database.hooks.get(); const hooks = await Database.hooks.get();
const result = []; const result = [];
@ -64,14 +64,28 @@ class WireGuard {
WG_DEBUG('Config synced successfully.'); WG_DEBUG('Config synced successfully.');
} }
async getClientsForUser(userId: ID, filter?: string) { async getClientsForUser(userId: ID, options?: { filter?: string; page?: number; limit?: number, sortClient?: boolean }) {
const { filter, page, limit } = options || {};
const sortClient = options?.sortClient ?? true;
const wgInterface = await Database.interfaces.get(); const wgInterface = await Database.interfaces.get();
let dbClients; let dbClients;
if (filter?.trim()) { let total: number = 0;
dbClients = await Database.clients.getForUserFiltered(userId, filter); if (page && limit && filter?.trim()){
dbClients = await Database.clients.getPaginatedListForUserFiltered(userId, filter, page, limit, sortClient);
total = await Database.clients.countForUserFiltered(userId, filter);
}
else if (page && limit){
dbClients = await Database.clients.getPaginatedListForUser(userId, page, limit, sortClient);
total = await Database.clients.countForUser(userId);
}
else if (filter?.trim()) {
dbClients = await Database.clients.getForUserFiltered(userId, filter, sortClient);
total = dbClients.length;
} else { } else {
dbClients = await Database.clients.getForUser(userId); dbClients = await Database.clients.getForUser(userId, sortClient);
total = dbClients.length;
} }
const clients = dbClients.map((client) => ({ const clients = dbClients.map((client) => ({
@ -98,7 +112,10 @@ class WireGuard {
} }
); );
return clients; return {
total: 1,
clients: clients
};
} }
async dumpByPublicKey(publicKey: string) { async dumpByPublicKey(publicKey: string) {
@ -112,14 +129,28 @@ class WireGuard {
return clientDump; return clientDump;
} }
async getAllClients(filter?: string) { async getAllClients(options?: { filter?: string; page?: number; limit?: number, sortClient?: boolean }) {
const { filter, page, limit } = options || {};
const sortClient = options?.sortClient ?? true;
const wgInterface = await Database.interfaces.get(); const wgInterface = await Database.interfaces.get();
let dbClients; let dbClients;
if (filter?.trim()) { let total: number = 0;
dbClients = await Database.clients.getAllPublicFiltered(filter); if (page && limit && filter?.trim()){
dbClients = await Database.clients.getPaginatedListPublicFiltered(filter, page, limit, sortClient);
total = await Database.clients.countAllFiltered(filter);
}
else if (page && limit){
dbClients = await Database.clients.getPaginatedListPublic(page, limit, sortClient);
total = await Database.clients.countAll();
}
else if (filter?.trim()) {
dbClients = await Database.clients.getAllPublicFiltered(filter, sortClient);
total = dbClients.length;
} else { } else {
dbClients = await Database.clients.getAllPublic(); dbClients = await Database.clients.getAllPublic(sortClient);
total = dbClients.length;
} }
const clients = dbClients.map((client) => ({ const clients = dbClients.map((client) => ({
@ -146,7 +177,10 @@ class WireGuard {
} }
); );
return clients; return {
total: total,
clients: clients
};
} }
async getClientConfiguration({ clientId }: { clientId: ID }) { async getClientConfiguration({ clientId }: { clientId: ID }) {
@ -277,7 +311,7 @@ class WireGuard {
} }
async cronJob() { async cronJob() {
const clients = await Database.clients.getAll(); const clients = await Database.clients.getAll(true);
let needsSave = false; let needsSave = false;
// Expires Feature // Expires Feature
for (const client of clients) { for (const client of clients) {

Loading…
Cancel
Save