OK... That's a lot of changes...
This commit is contained in:
parent
3ad1b6e1c7
commit
69575c69d8
14
.prettierrc
Executable file
14
.prettierrc
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.js, *.vue, *.css, *.scss",
|
||||||
|
"excludeFiles": "**/dist/**, **/node_modules/**"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
client: {
|
client: {
|
||||||
includes: ["web/src/**/*.{js,jsx,ts,tsx,vue,gql}"],
|
includes: ['web/src/**/*.{js,jsx,ts,tsx,vue,gql}'],
|
||||||
service: {
|
service: {
|
||||||
name: "ifms-pti-srv",
|
name: 'ifms-pti-srv',
|
||||||
url: "http://localhost:4000/graphql",
|
url: 'http://localhost:4000/graphql'
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:latest
|
image: postgres:latest
|
||||||
restart: 'no'
|
restart: 'no'
|
||||||
|
@ -10,7 +10,7 @@ services:
|
||||||
- 'postgres:/var/lib/postgresql/data'
|
- 'postgres:/var/lib/postgresql/data'
|
||||||
ports:
|
ports:
|
||||||
- '5432:5432'
|
- '5432:5432'
|
||||||
|
|
||||||
pgadmin:
|
pgadmin:
|
||||||
image: dpage/pgadmin4:latest
|
image: dpage/pgadmin4:latest
|
||||||
restart: 'no'
|
restart: 'no'
|
||||||
|
|
|
@ -5,5 +5,10 @@
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"arrowParens": "avoid",
|
"arrowParens": "avoid",
|
||||||
"excludeFiles": "dist/**"
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.js, *.vue, *.css, *.scss",
|
||||||
|
"excludeFiles": "**/dist/**, **/node_modules/**"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Portal de TI - Server
|
# Portal de TI - Server
|
||||||
|
|
||||||
Servidor de API GraphQL para o Portal de TI do IFMS
|
Servidor de API GraphQL para o Portal de TI do IFMS
|
||||||
|
|
||||||
## Requisitos
|
## Requisitos
|
||||||
|
@ -8,30 +9,35 @@ Servidor de API GraphQL para o Portal de TI do IFMS
|
||||||
- Docker Compose
|
- Docker Compose
|
||||||
|
|
||||||
## Desenvolvimento
|
## Desenvolvimento
|
||||||
~~~
|
|
||||||
|
```
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
~~~
|
```
|
||||||
|
|
||||||
Altere as variáveis de ambiente em `.env`
|
Altere as variáveis de ambiente em `.env`
|
||||||
|
|
||||||
~~~
|
```
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
npm run prisma-deploy # Rodar sempre que alterar o schema
|
npm run prisma-deploy # Rodar sempre que alterar o schema
|
||||||
npm run dev
|
npm run dev
|
||||||
~~~
|
```
|
||||||
|
|
||||||
## Compilar para produção
|
## Compilar para produção
|
||||||
~~~
|
|
||||||
|
```
|
||||||
npm run prisma-deploy
|
npm run prisma-deploy
|
||||||
npm run build
|
npm run build
|
||||||
~~~
|
```
|
||||||
|
|
||||||
## Produção
|
## Produção
|
||||||
Não é recomendado usar o arquivo .env em produção.
|
|
||||||
|
Não é recomendado usar o arquivo .env em produção.
|
||||||
Configure as variáveis de ambiente no servidor.
|
Configure as variáveis de ambiente no servidor.
|
||||||
|
|
||||||
~~~
|
```
|
||||||
npm start
|
npm start
|
||||||
~~~
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
Desenvolvido pelo SERTI Ponta Porã
|
|
||||||
|
Desenvolvido pelo SERTI Ponta Porã
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The `uptime` column on the `AccessPoint` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||||
|
- The `uptime` column on the `WifiDevice` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||||
|
- You are about to drop the column `avgSignal` on the `WifiStats` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `maxSignal` on the `WifiStats` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `minSignal` on the `WifiStats` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "AccessPoint" ADD COLUMN "usage" BIGINT,
|
||||||
|
DROP COLUMN "uptime",
|
||||||
|
ADD COLUMN "uptime" INTEGER;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "WifiDevice" DROP COLUMN "uptime",
|
||||||
|
ADD COLUMN "uptime" INTEGER,
|
||||||
|
ALTER COLUMN "usage" SET DATA TYPE BIGINT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "WifiStats" DROP COLUMN "avgSignal",
|
||||||
|
DROP COLUMN "maxSignal",
|
||||||
|
DROP COLUMN "minSignal",
|
||||||
|
ADD COLUMN "avgSignalStrength" INTEGER,
|
||||||
|
ADD COLUMN "maxSignalStrength" INTEGER,
|
||||||
|
ADD COLUMN "minSignalStrength" INTEGER,
|
||||||
|
ALTER COLUMN "avgUsage" SET DATA TYPE BIGINT,
|
||||||
|
ALTER COLUMN "sumUsage" SET DATA TYPE BIGINT;
|
|
@ -89,13 +89,13 @@ model WifiDevice {
|
||||||
notes String?
|
notes String?
|
||||||
|
|
||||||
essid String?
|
essid String?
|
||||||
uptime String?
|
uptime Int?
|
||||||
apName String?
|
apName String?
|
||||||
signalStrength Int?
|
signalStrength Int?
|
||||||
frequency String?
|
frequency String?
|
||||||
protocol String?
|
protocol String?
|
||||||
speed Int?
|
speed Int?
|
||||||
usage Int?
|
usage BigInt?
|
||||||
|
|
||||||
status Status?
|
status Status?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
@ -160,12 +160,14 @@ model AccessPoint {
|
||||||
notes String?
|
notes String?
|
||||||
inventoryTag String?
|
inventoryTag String?
|
||||||
|
|
||||||
uptime String?
|
uptime Int?
|
||||||
controller String?
|
controller String?
|
||||||
model String?
|
model String?
|
||||||
ip String?
|
ip String?
|
||||||
clients Int?
|
clients Int?
|
||||||
|
|
||||||
|
usage BigInt?
|
||||||
|
|
||||||
encryptedSshUser String?
|
encryptedSshUser String?
|
||||||
encryptedSshPassword String?
|
encryptedSshPassword String?
|
||||||
|
|
||||||
|
@ -182,9 +184,9 @@ model WifiStats {
|
||||||
|
|
||||||
clients Int?
|
clients Int?
|
||||||
|
|
||||||
avgSignal Int?
|
avgSignalStrength Int?
|
||||||
minSignal Int?
|
minSignalStrength Int?
|
||||||
maxSignal Int?
|
maxSignalStrength Int?
|
||||||
|
|
||||||
avgSpeed Int?
|
avgSpeed Int?
|
||||||
minSpeed Int?
|
minSpeed Int?
|
||||||
|
@ -193,8 +195,8 @@ model WifiStats {
|
||||||
avgClientUptime Int?
|
avgClientUptime Int?
|
||||||
maxClientUptime Int?
|
maxClientUptime Int?
|
||||||
|
|
||||||
avgUsage Int?
|
avgUsage BigInt?
|
||||||
sumUsage Int?
|
sumUsage BigInt?
|
||||||
|
|
||||||
accessPointId Int
|
accessPointId Int
|
||||||
accessPoint AccessPoint @relation("wifistats_to_ap", fields: [accessPointId], references: [id])
|
accessPoint AccessPoint @relation("wifistats_to_ap", fields: [accessPointId], references: [id])
|
||||||
|
|
|
@ -392,8 +392,9 @@ class User {
|
||||||
})
|
})
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
message: `Importado ${index + 1}/${allAdUsers.length} (${user.sAMAccountName
|
message: `Importado ${index + 1}/${allAdUsers.length} (${
|
||||||
}) ${user.displayName}`,
|
user.sAMAccountName
|
||||||
|
}) ${user.displayName}`,
|
||||||
data: dbUser
|
data: dbUser
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -402,11 +403,12 @@ class User {
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
tags: ['user', 'AD'],
|
tags: ['user', 'AD'],
|
||||||
message: `${allAdUsers.length
|
message: `${
|
||||||
} usuários importados do Active Directory em ${(
|
allAdUsers.length
|
||||||
(endTime - startTime) /
|
} usuários importados do Active Directory em ${(
|
||||||
1000
|
(endTime - startTime) /
|
||||||
).toFixed(2)}s`
|
1000
|
||||||
|
).toFixed(2)}s`
|
||||||
})
|
})
|
||||||
|
|
||||||
return allAdUsers.length
|
return allAdUsers.length
|
||||||
|
|
|
@ -5,7 +5,10 @@ import { User } from './classes/User'
|
||||||
import { deleteOldLogs, logInfo, logSuccess } from './lib/logger'
|
import { deleteOldLogs, logInfo, logSuccess } from './lib/logger'
|
||||||
|
|
||||||
import { updateAccessPoints } from './lib/accessPoints'
|
import { updateAccessPoints } from './lib/accessPoints'
|
||||||
|
import {
|
||||||
|
deleteOldStats,
|
||||||
|
generateStatsForAllAccessPoints
|
||||||
|
} from './lib/wifiStats'
|
||||||
|
|
||||||
// WARNING! All crontasks are blocking! Do not await inside it
|
// WARNING! All crontasks are blocking! Do not await inside it
|
||||||
|
|
||||||
|
@ -41,4 +44,12 @@ cron.schedule('0 0 2 * * *', () => {
|
||||||
|
|
||||||
cron.schedule('0 */2 * * * *', () => {
|
cron.schedule('0 */2 * * * *', () => {
|
||||||
updateAccessPoints().catch(console.log)
|
updateAccessPoints().catch(console.log)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
cron.schedule('0 */5 * * * *', () => {
|
||||||
|
generateStatsForAllAccessPoints()
|
||||||
|
})
|
||||||
|
|
||||||
|
cron.schedule('0 0 2 * * *', () => {
|
||||||
|
deleteOldStats()
|
||||||
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { } from 'dotenv/config'
|
import {} from 'dotenv/config'
|
||||||
import './utils/capitalize'
|
import './utils/capitalize'
|
||||||
import './utils/contains'
|
import './utils/contains'
|
||||||
import './utils/cycle'
|
import './utils/cycle'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import prisma from '../prisma'
|
import prisma from '../prisma'
|
||||||
import { ACCESS_POINTS_UPDATED, pubsub } from '../pubsub'
|
|
||||||
import { getAccessPoints as getCiscoAccessPoints } from './ciscoController'
|
import { getAccessPoints as getCiscoAccessPoints } from './ciscoController'
|
||||||
import { logInfo, logSuccess } from './logger'
|
import { logInfo, logSuccess } from './logger'
|
||||||
import { getAccessPoints as getUnifiAccessPoints } from './unifiController'
|
import { getAccessPoints as getUnifiAccessPoints } from './unifiController'
|
||||||
|
@ -50,7 +50,7 @@ export async function updateAccessPoints() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
uptime: "-1"
|
uptime: -1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ export async function getOnlineWifiDevices() {
|
||||||
lastSeen: now,
|
lastSeen: now,
|
||||||
essid: client.SSID,
|
essid: client.SSID,
|
||||||
ip: client.IP,
|
ip: client.IP,
|
||||||
uptime: client.UT.toString(),
|
uptime: +client.UT,
|
||||||
apName: client.AP,
|
apName: client.AP,
|
||||||
status: client.ST == 'Online' ? 'ONLINE' : 'OFFLINE',
|
status: client.ST == 'Online' ? 'ONLINE' : 'OFFLINE',
|
||||||
controller: 'Cisco',
|
controller: 'Cisco',
|
||||||
|
@ -143,14 +143,15 @@ export function getAccessPoints() {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
|
|
||||||
const restructuredAccessPoints = accessPoints.map(
|
const restructuredAccessPoints = accessPoints.map(
|
||||||
({ Nm, Mc, Md, Ut, A4, Cl }) => ({
|
({ Nm, Mc, Md, Ut, A4, Cl, Vm }) => ({
|
||||||
mac: Mc,
|
mac: Mc,
|
||||||
hostname: Nm,
|
hostname: Nm,
|
||||||
uptime: Ut.toString(),
|
uptime: +Ut,
|
||||||
controller: 'Cisco',
|
controller: 'Cisco',
|
||||||
model: Md,
|
model: Md,
|
||||||
ip: A4,
|
ip: A4,
|
||||||
clients: Cl
|
clients: +Cl,
|
||||||
|
usage: +Vm
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ async function log(
|
||||||
const entryTags = tags.length ? ` [${tags}] ` : ''
|
const entryTags = tags.length ? ` [${tags}] ` : ''
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`${color}[${format(now, 'HH:mm:ss')}]${entryTags ? entryTags : ''
|
`${color}[${format(now, 'HH:mm:ss')}]${
|
||||||
|
entryTags ? entryTags : ''
|
||||||
}\x1b[0m${message}`
|
}\x1b[0m${message}`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,9 @@ async function updateUserIdMappings() {
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
tags: ['paloalto', 'user-id'],
|
tags: ['paloalto', 'user-id'],
|
||||||
message: `Foram mapeados ${devices.length} user-ids em ${pAHost.description || pAHost.cidr
|
message: `Foram mapeados ${devices.length} user-ids em ${
|
||||||
} em ${((endTime - startTime) / 1000).toFixed(2)}s.`,
|
pAHost.description || pAHost.cidr
|
||||||
|
} em ${((endTime - startTime) / 1000).toFixed(2)}s.`,
|
||||||
data: devices
|
data: devices
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -114,8 +115,9 @@ async function updateUserIdMappings() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError({
|
logError({
|
||||||
tags: ['paloalto', 'user-id'],
|
tags: ['paloalto', 'user-id'],
|
||||||
message: `Erro atualizando user-id mappings em ${pAHost.description || pAHost.cidr
|
message: `Erro atualizando user-id mappings em ${
|
||||||
}: ${e.message}`
|
pAHost.description || pAHost.cidr
|
||||||
|
}: ${e.message}`
|
||||||
})
|
})
|
||||||
|
|
||||||
//console.log(e) // Do not add e to log DB for security reasons...
|
//console.log(e) // Do not add e to log DB for security reasons...
|
||||||
|
|
|
@ -187,7 +187,7 @@ export async function getOnlineWifiDevices() {
|
||||||
lastSeen: new Date(client.last_seen * 1000),
|
lastSeen: new Date(client.last_seen * 1000),
|
||||||
essid: client.essid,
|
essid: client.essid,
|
||||||
ip: client.ip,
|
ip: client.ip,
|
||||||
uptime: client.uptime.toString(),
|
uptime: +client.uptime,
|
||||||
apName: accessPoints[0].find(ap => ap.mac === client.ap_mac).name,
|
apName: accessPoints[0].find(ap => ap.mac === client.ap_mac).name,
|
||||||
status: 'ONLINE',
|
status: 'ONLINE',
|
||||||
controller: 'UniFi',
|
controller: 'UniFi',
|
||||||
|
@ -209,14 +209,15 @@ export async function getAccessPoints() {
|
||||||
const accessPoints = await unifiController.getAccessDevices('default')
|
const accessPoints = await unifiController.getAccessDevices('default')
|
||||||
|
|
||||||
const restructuredAccessPoints = accessPoints[0].map(
|
const restructuredAccessPoints = accessPoints[0].map(
|
||||||
({ mac, model, ip, uptime, name, num_sta }) => ({
|
({ mac, model, ip, uptime, name, num_sta, bytes }) => ({
|
||||||
mac,
|
mac,
|
||||||
hostname: name,
|
hostname: name,
|
||||||
uptime: uptime ? uptime.toString() : "-1",
|
uptime: uptime ? +uptime : -1,
|
||||||
controller: 'UniFi',
|
controller: 'UniFi',
|
||||||
model,
|
model,
|
||||||
ip,
|
ip,
|
||||||
clients: num_sta
|
clients: num_sta,
|
||||||
|
usage: +bytes
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,9 @@ let working = false
|
||||||
const wifiControllers = [unifiController, ciscoController]
|
const wifiControllers = [unifiController, ciscoController]
|
||||||
|
|
||||||
async function getOnlineDevices() {
|
async function getOnlineDevices() {
|
||||||
|
const onlineDevicesPromises = wifiControllers.map(wifiController =>
|
||||||
const onlineDevicesPromises = wifiControllers.map(wifiController => wifiController.getOnlineWifiDevices())
|
wifiController.getOnlineWifiDevices()
|
||||||
|
)
|
||||||
|
|
||||||
const onlineDevices = (await Promise.all(onlineDevicesPromises)).flat()
|
const onlineDevices = (await Promise.all(onlineDevicesPromises)).flat()
|
||||||
|
|
||||||
|
@ -86,10 +87,10 @@ async function updateDB(onlineDevices) {
|
||||||
|
|
||||||
const user = device.user
|
const user = device.user
|
||||||
? {
|
? {
|
||||||
connect: {
|
connect: {
|
||||||
sAMAccountName: device.user.replace('IFMS\\', '').toLowerCase()
|
sAMAccountName: device.user.replace('IFMS\\', '').toLowerCase()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
const hostname = device.hostname || mockHostName(device)
|
const hostname = device.hostname || mockHostName(device)
|
||||||
|
@ -184,17 +185,16 @@ function updateDevicesInfo() {
|
||||||
|
|
||||||
onlineDevices.length > 0
|
onlineDevices.length > 0
|
||||||
? resolve(
|
? resolve(
|
||||||
`${onlineDevices.length} atualizados em ${Math.floor(
|
`${onlineDevices.length} atualizados em ${Math.floor(
|
||||||
endTime - startTime
|
endTime - startTime
|
||||||
)}ms, DB em ${Math.floor(endTimeDB - startTimeDB)}ms`
|
)}ms, DB em ${Math.floor(endTimeDB - startTimeDB)}ms`
|
||||||
)
|
)
|
||||||
: reject('Não há dispositivos conectados no momento.')
|
: reject('Não há dispositivos conectados no momento.')
|
||||||
|
|
||||||
pubsub.publish(USER_PRESENCE_UPDATED, {
|
pubsub.publish(USER_PRESENCE_UPDATED, {
|
||||||
userPresenceUpdated: onlineDevices.length
|
userPresenceUpdated: onlineDevices.length
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const updatedDbAccessPoints = await prisma.accessPoint.findMany({
|
const updatedDbAccessPoints = await prisma.accessPoint.findMany({
|
||||||
include: {
|
include: {
|
||||||
wifiDevices: {
|
wifiDevices: {
|
||||||
|
@ -205,12 +205,17 @@ function updateDevicesInfo() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
pubsub.publish(ACCESS_POINTS_UPDATED, { accessPointsUpdated: updatedDbAccessPoints })
|
pubsub.publish(ACCESS_POINTS_UPDATED, {
|
||||||
|
accessPointsUpdated: updatedDbAccessPoints
|
||||||
|
})
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
tags: ['wifiDevices'],
|
tags: ['wifiDevices'],
|
||||||
message: `${onlineDevices.length} dispositivos Wi-Fi atualizados em
|
message: `${onlineDevices.length} dispositivos Wi-Fi atualizados em
|
||||||
${((endTime - startTime) / 1000).toFixed(2)}s. BD em ${((endTimeDB - startTimeDB) / 1000).toFixed(2)}s`
|
${((endTime - startTime) / 1000).toFixed(2)}s. BD em ${(
|
||||||
|
(endTimeDB - startTimeDB) /
|
||||||
|
1000
|
||||||
|
).toFixed(2)}s`
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError({
|
logError({
|
||||||
|
@ -229,7 +234,8 @@ function updateDevicesInfo() {
|
||||||
|
|
||||||
// Delete devices that are offline for more than OLD_DEVICES_THRESHOLD_IN_DAYS days
|
// Delete devices that are offline for more than OLD_DEVICES_THRESHOLD_IN_DAYS days
|
||||||
async function deleteOldDevices() {
|
async function deleteOldDevices() {
|
||||||
const oldDevicesThresholdInMilliseconds = OLD_DEVICES_THRESHOLD_IN_DAYS * 24 * 60 * 60 * 1000
|
const oldDevicesThresholdInMilliseconds =
|
||||||
|
OLD_DEVICES_THRESHOLD_IN_DAYS * 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
const oldDevices = await prisma.wifiDevice.deleteMany({
|
const oldDevices = await prisma.wifiDevice.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import prisma from "../prisma";
|
import prisma from '../prisma'
|
||||||
|
import { logError, logSuccess } from './logger'
|
||||||
|
import { subDays } from 'date-fns'
|
||||||
|
|
||||||
generateStatsForAccessPoint(1)
|
const DAYS_TO_KEEP = 90
|
||||||
|
|
||||||
async function generateStatsForAccessPoint(accessPointId) {
|
async function generateStatsForAccessPoint(mac) {
|
||||||
const timestamp = new Date()
|
const timestamp = new Date()
|
||||||
|
|
||||||
const stats = await prisma.wifiDevice.aggregate({
|
const dbStats = await prisma.wifiDevice.aggregate({
|
||||||
where: {
|
where: {
|
||||||
accessPointId,
|
accessPoint: {
|
||||||
|
mac
|
||||||
|
},
|
||||||
status: 'ONLINE'
|
status: 'ONLINE'
|
||||||
},
|
},
|
||||||
_count: {
|
_count: {
|
||||||
|
@ -16,41 +20,84 @@ async function generateStatsForAccessPoint(accessPointId) {
|
||||||
_avg: {
|
_avg: {
|
||||||
signalStrength: true,
|
signalStrength: true,
|
||||||
speed: true,
|
speed: true,
|
||||||
usage: true
|
usage: true,
|
||||||
|
uptime: true
|
||||||
},
|
},
|
||||||
_max: {
|
_max: {
|
||||||
signalStrength: true,
|
signalStrength: true,
|
||||||
speed: true,
|
speed: true,
|
||||||
usage: true
|
usage: true,
|
||||||
|
uptime: true
|
||||||
},
|
},
|
||||||
_min: {
|
_min: {
|
||||||
signalStrength: true,
|
signalStrength: true,
|
||||||
speed: true,
|
speed: true
|
||||||
|
},
|
||||||
|
_sum: {
|
||||||
|
usage: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(timestamp, stats)
|
const stats = {
|
||||||
|
timestamp: timestamp.toISOString(),
|
||||||
|
clients: dbStats._count._all,
|
||||||
|
|
||||||
|
avgSignalStrength: Math.floor(dbStats._avg.signalStrength, 0),
|
||||||
|
minSignalStrength: dbStats._min.signalStrength,
|
||||||
|
maxSignalStrength: dbStats._max.signalStrength,
|
||||||
|
|
||||||
|
avgSpeed: Math.floor(dbStats._avg.speed, 0),
|
||||||
|
minSpeed: dbStats._min.speed || 0,
|
||||||
|
maxSpeed: dbStats._max.speed || 0,
|
||||||
|
|
||||||
|
avgClientUptime: Math.floor(dbStats._avg.uptime, 0),
|
||||||
|
maxClientUptime: dbStats._max.uptime || 0,
|
||||||
|
|
||||||
|
avgUsage: Math.floor(dbStats._avg.usage, 0),
|
||||||
|
sumUsage: dbStats._sum.usage || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.wifiStats.create({
|
||||||
|
data: {
|
||||||
|
...stats,
|
||||||
|
accessPoint: { connect: { mac } }
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// id Int @id @default(autoincrement())
|
export async function generateStatsForAllAccessPoints() {
|
||||||
// timestamp DateTime @default(now())
|
try {
|
||||||
|
const accessPoints = await prisma.accessPoint.findMany()
|
||||||
|
|
||||||
// clients Int?
|
for (const accessPoint of accessPoints) {
|
||||||
|
await generateStatsForAccessPoint(accessPoint.mac)
|
||||||
|
}
|
||||||
|
|
||||||
// avgSignal Int?
|
logSuccess({
|
||||||
// minSignal Int?
|
tags: ['wifiStats', 'generateStatsForAllAccessPoints'],
|
||||||
// maxSignal Int?
|
message: `Estatísticas geradas para ${accessPoints.length} access points`
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
logError({
|
||||||
|
tags: ['wifiStats', 'generateStatsForAllAccessPoints'],
|
||||||
|
message: 'Erro ao gerar estatísticas para todos os access points',
|
||||||
|
data: e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// avgSpeed Int?
|
export async function deleteOldStats() {
|
||||||
// minSpeed Int?
|
try {
|
||||||
// maxSpeed Int?
|
const stats = await prisma.wifiStats.deleteMany({
|
||||||
|
where: { timestamp: { lt: subDays(new Date(), DAYS_TO_KEEP) } }
|
||||||
|
})
|
||||||
|
|
||||||
// avgClientUptime Int?
|
logSuccess({
|
||||||
// maxClientUptime Int?
|
tags: ['wifiStats', 'deleteOldStats'],
|
||||||
|
message: `${stats.count} estatísticas com mais de ${DAYS_TO_KEEP} dias deletadas.`
|
||||||
// avgUsage Int?
|
})
|
||||||
// sumUsage Int?
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
// accessPointId Int
|
}
|
||||||
// accessPoint AccessPoint @relation("wifistats_to_ap", fields: [accessPointId], references: [id])
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import prisma from "../prisma";
|
import prisma from '../prisma'
|
||||||
import { getSubnetInfo } from "../utils/subnetInfo";
|
import { getSubnetInfo } from '../utils/subnetInfo'
|
||||||
|
|
||||||
export const AccessPoint = {
|
export const AccessPoint = {
|
||||||
updatedAt: (parent, data, context, info) => parent.updatedAt?.toISOString(),
|
updatedAt: (parent, data, context, info) => parent.updatedAt?.toISOString(),
|
||||||
|
|
||||||
async clients(parent, data, context, info) {
|
async clients(parent, data, context, info) {
|
||||||
|
|
||||||
const clientsCount = await prisma.wifiDevice.count({
|
const clientsCount = await prisma.wifiDevice.count({
|
||||||
where: {
|
where: {
|
||||||
status: 'ONLINE',
|
status: 'ONLINE',
|
||||||
|
@ -15,8 +14,9 @@ export const AccessPoint = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return clientsCount;
|
return clientsCount
|
||||||
},
|
},
|
||||||
subnetInfo: parent => getSubnetInfo(parent.ip)
|
subnetInfo: parent => getSubnetInfo(parent.ip),
|
||||||
|
|
||||||
|
usage: (parent, data, context, info) => parent.usage.toString()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,4 @@ export async function addPAHost(
|
||||||
})
|
})
|
||||||
|
|
||||||
return host
|
return host
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@ import { ResetToken } from '../../classes/ResetToken'
|
||||||
|
|
||||||
export async function createResetToken(parent, { data }, { auth }) {
|
export async function createResetToken(parent, { data }, { auth }) {
|
||||||
return ResetToken.createToken(data.username, auth.sAMAccountName)
|
return ResetToken.createToken(data.username, auth.sAMAccountName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,4 @@ export async function delPAHost(parent, { id }, { auth }) {
|
||||||
throw new Error('Você não pode apagar o host de outro usuário')
|
throw new Error('Você não pode apagar o host de outro usuário')
|
||||||
|
|
||||||
return prisma.pAHost.delete({ where: { id } })
|
return prisma.pAHost.delete({ where: { id } })
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@ import { ResetToken } from '../../classes/ResetToken'
|
||||||
|
|
||||||
export async function deleteExpiredTokens() {
|
export async function deleteExpiredTokens() {
|
||||||
return `Tokens deletados ${await ResetToken.deleteExpiredTokens()}`
|
return `Tokens deletados ${await ResetToken.deleteExpiredTokens()}`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ import { User } from '../../classes/User'
|
||||||
export async function importUsers() {
|
export async function importUsers() {
|
||||||
User.importAllUsers()
|
User.importAllUsers()
|
||||||
return 'A importação está sendo feita. Isso pode demorar alguns minutos.'
|
return 'A importação está sendo feita. Isso pode demorar alguns minutos.'
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { delPAHost } from './delPAHost'
|
||||||
import { updateAccessPoint } from './updateAccessPoint'
|
import { updateAccessPoint } from './updateAccessPoint'
|
||||||
|
|
||||||
const Mutation = {
|
const Mutation = {
|
||||||
|
|
||||||
login,
|
login,
|
||||||
updatePassword,
|
updatePassword,
|
||||||
replacePassword,
|
replacePassword,
|
||||||
|
|
|
@ -2,4 +2,4 @@ import { User } from '../../classes/User'
|
||||||
|
|
||||||
export async function login(parent, { data }) {
|
export async function login(parent, { data }) {
|
||||||
return User.login(data.username, data.password)
|
return User.login(data.username, data.password)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,4 @@ export async function replacePassword(parent, { data }, { auth }) {
|
||||||
})
|
})
|
||||||
|
|
||||||
return replaceADPassword(data.username, data.newPassword)
|
return replaceADPassword(data.username, data.newPassword)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@ export async function replaceStudentPassword(parent, { data }, { auth }) {
|
||||||
|
|
||||||
if (isServant) throw new Error(`Usuário ${data.username} é um servidor`)
|
if (isServant) throw new Error(`Usuário ${data.username} é um servidor`)
|
||||||
|
|
||||||
if (!isStudent)
|
if (!isStudent) throw new Error(`Usuário ${data.username} não é um estudante`)
|
||||||
throw new Error(`Usuário ${data.username} não é um estudante`)
|
|
||||||
|
|
||||||
logInfo({
|
logInfo({
|
||||||
tags: ['replaceStudentPassword', 'user'],
|
tags: ['replaceStudentPassword', 'user'],
|
||||||
|
@ -24,4 +23,4 @@ export async function replaceStudentPassword(parent, { data }, { auth }) {
|
||||||
})
|
})
|
||||||
|
|
||||||
return replacePassword(data.username, data.newPassword)
|
return replacePassword(data.username, data.newPassword)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,37 @@
|
||||||
|
|
||||||
import prisma from '../../prisma'
|
import prisma from '../../prisma'
|
||||||
import { ACCESS_POINTS_UPDATED, pubsub } from '../../pubsub'
|
import { ACCESS_POINTS_UPDATED, pubsub } from '../../pubsub'
|
||||||
import { logError, logInfo } from '../../lib/logger'
|
import { logError, logInfo } from '../../lib/logger'
|
||||||
import { getSubnetInfo } from '../../utils/subnetInfo'
|
import { getSubnetInfo } from '../../utils/subnetInfo'
|
||||||
|
|
||||||
export async function updateAccessPoint(_, { data: { id, name, local, notes } }, { auth },) {
|
export async function updateAccessPoint(
|
||||||
const accessPoint = await prisma.accessPoint.findUnique({ where: { id: parseInt(id) }, })
|
_,
|
||||||
|
{ data: { id, name, local, notes } },
|
||||||
|
{ auth }
|
||||||
|
) {
|
||||||
|
const accessPoint = await prisma.accessPoint.findUnique({
|
||||||
|
where: { id: parseInt(id) }
|
||||||
|
})
|
||||||
|
|
||||||
if (!accessPoint) throw new Error('Access Point não encontrado')
|
if (!accessPoint) throw new Error('Access Point não encontrado')
|
||||||
|
|
||||||
if (getSubnetInfo(accessPoint.ip).shortName !== auth.campus) {
|
if (getSubnetInfo(accessPoint.ip).shortName !== auth.campus) {
|
||||||
logError({
|
logError({
|
||||||
tags: ['accessPointEdited', 'accessPoints'],
|
tags: ['accessPointEdited', 'accessPoints'],
|
||||||
message: `O usuário ${auth.displayName} (${auth.sAMAccountName}) tentou atualizar as informações do
|
message: `O usuário ${auth.displayName} (${
|
||||||
AP ${accessPoint.name || accessPoint.hostname}, mas não tinha permissão.`
|
auth.sAMAccountName
|
||||||
|
}) tentou atualizar as informações do
|
||||||
|
AP ${
|
||||||
|
accessPoint.name || accessPoint.hostname
|
||||||
|
}, mas não tinha permissão.`
|
||||||
})
|
})
|
||||||
|
|
||||||
throw new Error(`O AP ${accessPoint.name || accessPoint.hostname} não está na rede do campus ${auth.campus}. Você só pode editar APs da rede do seu campus.`)
|
throw new Error(
|
||||||
|
`O AP ${
|
||||||
|
accessPoint.name || accessPoint.hostname
|
||||||
|
} não está na rede do campus ${
|
||||||
|
auth.campus
|
||||||
|
}. Você só pode editar APs da rede do seu campus.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedAccessPoint = await prisma.accessPoint.update({
|
const updatedAccessPoint = await prisma.accessPoint.update({
|
||||||
|
@ -26,7 +41,11 @@ export async function updateAccessPoint(_, { data: { id, name, local, notes } },
|
||||||
|
|
||||||
logInfo({
|
logInfo({
|
||||||
tags: ['accessPointEdited', 'accessPoints'],
|
tags: ['accessPointEdited', 'accessPoints'],
|
||||||
message: `O usuário ${auth.displayName} (${auth.sAMAccountName}) atualizou as informações do AP ${updatedAccessPoint.name || updatedAccessPoint.hostname}`,
|
message: `O usuário ${auth.displayName} (${
|
||||||
|
auth.sAMAccountName
|
||||||
|
}) atualizou as informações do AP ${
|
||||||
|
updatedAccessPoint.name || updatedAccessPoint.hostname
|
||||||
|
}`,
|
||||||
data: updatedAccessPoint
|
data: updatedAccessPoint
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -39,4 +58,4 @@ export async function updateAccessPoint(_, { data: { id, name, local, notes } },
|
||||||
})
|
})
|
||||||
|
|
||||||
return updatedAccessPoint
|
return updatedAccessPoint
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export async function updatePassword(parent, { data }, { auth }) {
|
export async function updatePassword(parent, { data }, { auth }) {
|
||||||
return auth.updatePassword(data.oldPassword, data.newPassword)
|
return auth.updatePassword(data.oldPassword, data.newPassword)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,4 @@ import { ResetToken } from '../../classes/ResetToken'
|
||||||
|
|
||||||
export async function useResetToken(parent, { data }) {
|
export async function useResetToken(parent, { data }) {
|
||||||
return ResetToken.useToken(data.token, data.newPassword)
|
return ResetToken.useToken(data.token, data.newPassword)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@ export async function logs(parent, { search, dateIn, dateOut, limit = 100 }) {
|
||||||
},
|
},
|
||||||
OR: search
|
OR: search
|
||||||
? [
|
? [
|
||||||
{ message: { contains: search, mode: 'insensitive' } },
|
{ message: { contains: search, mode: 'insensitive' } },
|
||||||
{ tags: { contains: search, mode: 'insensitive' } }
|
{ tags: { contains: search, mode: 'insensitive' } }
|
||||||
]
|
]
|
||||||
: undefined
|
: undefined
|
||||||
},
|
},
|
||||||
orderBy: { timestamp: 'desc' },
|
orderBy: { timestamp: 'desc' },
|
||||||
|
|
|
@ -18,7 +18,9 @@ export async function userPresence(_, { search, onlyServants }) {
|
||||||
|
|
||||||
if (onlyServants)
|
if (onlyServants)
|
||||||
usersWithWifiDevices = usersWithWifiDevices.filter(
|
usersWithWifiDevices = usersWithWifiDevices.filter(
|
||||||
({ extensionAttribute2 }) => extensionAttribute2 == 'Técnico-administrativo' || extensionAttribute2 == 'Docente'
|
({ extensionAttribute2 }) =>
|
||||||
|
extensionAttribute2 == 'Técnico-administrativo' ||
|
||||||
|
extensionAttribute2 == 'Docente'
|
||||||
)
|
)
|
||||||
|
|
||||||
let filteredUsers = usersWithWifiDevices
|
let filteredUsers = usersWithWifiDevices
|
||||||
|
@ -28,7 +30,6 @@ export async function userPresence(_, { search, onlyServants }) {
|
||||||
const searchTerms = search.split(' ')
|
const searchTerms = search.split(' ')
|
||||||
|
|
||||||
for (const term of searchTerms) {
|
for (const term of searchTerms) {
|
||||||
|
|
||||||
filteredUsers = filteredUsers.filter(
|
filteredUsers = filteredUsers.filter(
|
||||||
user =>
|
user =>
|
||||||
Object.keys(user).some(
|
Object.keys(user).some(
|
||||||
|
@ -37,14 +38,12 @@ export async function userPresence(_, { search, onlyServants }) {
|
||||||
user.wifiDevices?.some(
|
user.wifiDevices?.some(
|
||||||
device =>
|
device =>
|
||||||
device.status != 'OFFLINE' &&
|
device.status != 'OFFLINE' &&
|
||||||
(
|
(device.ip?.startsWith(term) ||
|
||||||
device.ip?.startsWith(term) ||
|
|
||||||
device.apName?.contains(term) ||
|
device.apName?.contains(term) ||
|
||||||
device.essid?.contains(term) ||
|
device.essid?.contains(term) ||
|
||||||
device.hostname?.contains(term) ||
|
device.hostname?.contains(term) ||
|
||||||
device.accessPoint?.name?.contains(term) ||
|
device.accessPoint?.name?.contains(term) ||
|
||||||
device.accessPoint?.local?.contains(term)
|
device.accessPoint?.local?.contains(term))
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -80,9 +79,13 @@ export async function userPresence(_, { search, onlyServants }) {
|
||||||
thumbnailPhoto: userPresence.thumbnailPhoto,
|
thumbnailPhoto: userPresence.thumbnailPhoto,
|
||||||
lastSeen: userPresence.wifiDevices[0].lastSeen,
|
lastSeen: userPresence.wifiDevices[0].lastSeen,
|
||||||
status: userPresence.wifiDevices[0].status,
|
status: userPresence.wifiDevices[0].status,
|
||||||
apName: userPresence.wifiDevices[0].accessPoint?.name || userPresence.wifiDevices[0].apName || userPresence.wifiDevices[0].accessPoint?.hostname,
|
apName:
|
||||||
|
userPresence.wifiDevices[0].accessPoint?.name ||
|
||||||
|
userPresence.wifiDevices[0].apName ||
|
||||||
|
userPresence.wifiDevices[0].accessPoint?.hostname,
|
||||||
local: userPresence.wifiDevices[0].accessPoint?.local,
|
local: userPresence.wifiDevices[0].accessPoint?.local,
|
||||||
campus: getSubnetInfo(userPresence.wifiDevices[0].accessPoint?.ip).shortName
|
campus: getSubnetInfo(userPresence.wifiDevices[0].accessPoint?.ip)
|
||||||
|
.shortName
|
||||||
}))
|
}))
|
||||||
.slice(0, 200)
|
.slice(0, 200)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import prisma from '../../prisma'
|
import prisma from '../../prisma'
|
||||||
|
|
||||||
export async function wifiDevices(parent, { take = 50, skip = 0, search, sortBy, sortDesc, onlineOnly }) {
|
export async function wifiDevices(
|
||||||
|
parent,
|
||||||
|
{ take = 50, skip = 0, search, sortBy, sortDesc, onlineOnly }
|
||||||
|
) {
|
||||||
const mode = 'insensitive'
|
const mode = 'insensitive'
|
||||||
|
|
||||||
if (!search) search = ''
|
if (!search) search = ''
|
||||||
|
@ -28,9 +31,7 @@ export async function wifiDevices(parent, { take = 50, skip = 0, search, sortBy,
|
||||||
}),
|
}),
|
||||||
data: prisma.wifiDevice.findMany({
|
data: prisma.wifiDevice.findMany({
|
||||||
where,
|
where,
|
||||||
orderBy: [
|
orderBy: [{ [sortBy || 'hostname']: sortDesc ? 'desc' : 'asc' }],
|
||||||
{ [sortBy || 'hostname']: sortDesc ? 'desc' : 'asc' },
|
|
||||||
],
|
|
||||||
include: { user: true, accessPoint: true },
|
include: { user: true, accessPoint: true },
|
||||||
take,
|
take,
|
||||||
skip
|
skip
|
||||||
|
|
|
@ -4,8 +4,7 @@ import prisma from '../../prisma'
|
||||||
export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
||||||
const mode = 'insensitive'
|
const mode = 'insensitive'
|
||||||
|
|
||||||
if (search === null)
|
if (search === null) search = undefined
|
||||||
search = undefined
|
|
||||||
|
|
||||||
const where = {
|
const where = {
|
||||||
AND: [
|
AND: [
|
||||||
|
@ -19,7 +18,7 @@ export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
||||||
accessPoint: {
|
accessPoint: {
|
||||||
OR: [
|
OR: [
|
||||||
{ name: { contains: search, mode } },
|
{ name: { contains: search, mode } },
|
||||||
{ local: { contains: search, mode } },
|
{ local: { contains: search, mode } }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,27 +26,24 @@ export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
||||||
},
|
},
|
||||||
{ wifiDevices: { some: { mac: { contains: search, mode } } } },
|
{ wifiDevices: { some: { mac: { contains: search, mode } } } },
|
||||||
{ wifiDevices: { some: { ip: { contains: search, mode } } } },
|
{ wifiDevices: { some: { ip: { contains: search, mode } } } },
|
||||||
{ displayName: { contains: search, mode } }, ,
|
{ displayName: { contains: search, mode } },
|
||||||
{ sAMAccountName: { contains: search, mode } },
|
,
|
||||||
|
{ sAMAccountName: { contains: search, mode } }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data:
|
data: prisma.user.findMany({
|
||||||
prisma.user.findMany({
|
where,
|
||||||
where,
|
include: {
|
||||||
include: {
|
wifiDevices: true
|
||||||
wifiDevices: true
|
},
|
||||||
},
|
orderBy: [{ wifiDevices: { _count: 'desc' } }, { displayName: 'asc' }],
|
||||||
orderBy: [
|
take,
|
||||||
{ wifiDevices: { _count: 'desc' } },
|
skip
|
||||||
{ displayName: 'asc' }],
|
}),
|
||||||
take,
|
|
||||||
skip
|
|
||||||
}),
|
|
||||||
|
|
||||||
total: prisma.user.count({ where })
|
total: prisma.user.count({ where })
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,15 @@ const User = {
|
||||||
sharedFolders: parent =>
|
sharedFolders: parent =>
|
||||||
parent.groups
|
parent.groups
|
||||||
? parent.groups
|
? parent.groups
|
||||||
.filter(group => group.cn.includes('-Share-'))
|
.filter(group => group.cn.includes('-Share-'))
|
||||||
.map(group => group.cn.split('-')[2])
|
.map(group => group.cn.split('-')[2])
|
||||||
: [],
|
: [],
|
||||||
|
|
||||||
sharedPrinters: parent =>
|
sharedPrinters: parent =>
|
||||||
parent.groups
|
parent.groups
|
||||||
? parent.groups
|
? parent.groups
|
||||||
.filter(group => group.cn.includes('-Printer-'))
|
.filter(group => group.cn.includes('-Printer-'))
|
||||||
.map(group => group.cn.split('-')[2])
|
.map(group => group.cn.split('-')[2])
|
||||||
: [],
|
: [],
|
||||||
|
|
||||||
isSuperAdmin: parent => parent.roles.includes('superAdmin'),
|
isSuperAdmin: parent => parent.roles.includes('superAdmin'),
|
||||||
|
@ -62,24 +62,22 @@ const User = {
|
||||||
return campus || '--'
|
return campus || '--'
|
||||||
},
|
},
|
||||||
|
|
||||||
onlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
onlineWifiDevicesCount: (parent, data, { auth }) =>
|
||||||
where: {
|
prisma.wifiDevice.count({
|
||||||
status: 'ONLINE',
|
where: {
|
||||||
user: { id: parent.id }
|
status: 'ONLINE',
|
||||||
}
|
user: { id: parent.id }
|
||||||
}),
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
offlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
offlineWifiDevicesCount: (parent, data, { auth }) =>
|
||||||
where: {
|
prisma.wifiDevice.count({
|
||||||
OR: [
|
where: {
|
||||||
{ status: 'OFFLINE' },
|
OR: [{ status: 'OFFLINE' }, { status: 'RECENT' }],
|
||||||
{ status: 'RECENT' },
|
|
||||||
],
|
|
||||||
|
|
||||||
user: { id: parent.id }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
user: { id: parent.id }
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { User }
|
export { User }
|
||||||
|
|
|
@ -15,25 +15,22 @@ const WifiDevice = {
|
||||||
})
|
})
|
||||||
).user,
|
).user,
|
||||||
|
|
||||||
usage: parent => parent.usage < 0 ? parent.usage * -1 : parent.usage,
|
usage: parent => parent.usage.toString(),
|
||||||
|
|
||||||
accessPoint: async parent => {
|
accessPoint: async parent => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ap = await prisma.accessPoint.findUnique({ where: { hostname: parent.apName } })
|
const ap = await prisma.accessPoint.findUnique({
|
||||||
if (ap)
|
where: { hostname: parent.apName }
|
||||||
return ap
|
})
|
||||||
else
|
if (ap) return ap
|
||||||
return null
|
else return null
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
logError({
|
logError({
|
||||||
tags: ['wifiDevice', 'accessPoint'],
|
tags: ['wifiDevice', 'accessPoint'],
|
||||||
message: `Could not find access point ${parent.apName}`,
|
message: `Could not find access point ${parent.apName}`,
|
||||||
data: parent
|
data: parent
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class AuthDirective extends SchemaDirectiveVisitor {
|
||||||
|
|
||||||
context.auth = {
|
context.auth = {
|
||||||
...user,
|
...user,
|
||||||
campus: user.extensionAttribute1?.split('-')[0] || '--',
|
campus: user.extensionAttribute1?.split('-')[0] || '--'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.pwdLastSet.toISOString() === pwdLastSet) {
|
if (user.pwdLastSet.toISOString() === pwdLastSet) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { gql } from 'apollo-server'
|
||||||
const typeDefs = gql`
|
const typeDefs = gql`
|
||||||
type Query {
|
type Query {
|
||||||
"Returns only a few fields of a user"
|
"Returns only a few fields of a user"
|
||||||
basicUser(sAMAccountName: String!): User!
|
basicUser(sAMAccountName: String!): User!
|
||||||
|
|
||||||
"The authenticated user"
|
"The authenticated user"
|
||||||
me: User! @auth
|
me: User! @auth
|
||||||
|
@ -15,37 +15,37 @@ const typeDefs = gql`
|
||||||
limit: Int = 15
|
limit: Int = 15
|
||||||
"Should return only students?"
|
"Should return only students?"
|
||||||
onlyStudents: Boolean = false
|
onlyStudents: Boolean = false
|
||||||
): [User!] @auth(roles: ["servant"])
|
): [User!] @auth(roles: ["servant"])
|
||||||
|
|
||||||
"A single user"
|
"A single user"
|
||||||
user(sAMAccountName: String!): User!
|
user(sAMAccountName: String!): User! @auth(roles: ["superAdmin"])
|
||||||
@auth(roles: ["superAdmin"])
|
|
||||||
|
|
||||||
"AD groups"
|
"AD groups"
|
||||||
groups(where: GroupWhereInput!, limit: Int = 10): [Group!]!
|
groups(where: GroupWhereInput!, limit: Int = 10): [Group!]!
|
||||||
@auth(roles: ["servant"])
|
@auth(roles: ["servant"])
|
||||||
|
|
||||||
"Current stats. Differs from the historical statistics."
|
"Current stats. Differs from the historical statistics."
|
||||||
stats: Stats!
|
stats: Stats!
|
||||||
|
|
||||||
"Users who has some device currently connected to Wi-Fi"
|
"Users who has some device currently connected to Wi-Fi"
|
||||||
userPresence(search: String = "", onlyServants: Boolean = false): [UserPresence!] @auth(roles: ["watcher"])
|
userPresence(
|
||||||
|
search: String = ""
|
||||||
|
onlyServants: Boolean = false
|
||||||
|
): [UserPresence!] @auth(roles: ["watcher"])
|
||||||
|
|
||||||
"Devices that uses the Wi-Fi"
|
"Devices that uses the Wi-Fi"
|
||||||
wifiDevices(
|
wifiDevices(
|
||||||
search: String = ""
|
search: String = ""
|
||||||
take: Int
|
take: Int
|
||||||
skip: Int
|
skip: Int
|
||||||
sortBy: WifiDevicesResultSortBy = "signalStrength"
|
sortBy: WifiDevicesResultSortBy = "signalStrength"
|
||||||
sortDesc: Boolean = false,
|
sortDesc: Boolean = false
|
||||||
onlineOnly: Boolean = false
|
onlineOnly: Boolean = false
|
||||||
): WifiDevicesResult! @auth(roles: ["superAdmin"])
|
): WifiDevicesResult! @auth(roles: ["superAdmin"])
|
||||||
|
|
||||||
"Users that uses the Wi-Fi"
|
"Users that uses the Wi-Fi"
|
||||||
wifiUsers(
|
wifiUsers(search: String = "", take: Int, skip: Int): WifiUsersResult!
|
||||||
search: String = ""
|
@auth(roles: ["superAdmin"])
|
||||||
take: Int
|
|
||||||
skip: Int): WifiUsersResult! @auth(roles: ["superAdmin"])
|
|
||||||
|
|
||||||
"Application Logs"
|
"Application Logs"
|
||||||
logs(
|
logs(
|
||||||
|
@ -92,7 +92,7 @@ const typeDefs = gql`
|
||||||
|
|
||||||
"Import all users from Active Directory"
|
"Import all users from Active Directory"
|
||||||
importUsers: String! @auth(roles: ["superAdmin"])
|
importUsers: String! @auth(roles: ["superAdmin"])
|
||||||
|
|
||||||
"Add a PA host"
|
"Add a PA host"
|
||||||
addPAHost(data: AddPAHostInput!): PAHost! @auth(roles: ["superAdmin"])
|
addPAHost(data: AddPAHostInput!): PAHost! @auth(roles: ["superAdmin"])
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ const typeDefs = gql`
|
||||||
lastSeen: String
|
lastSeen: String
|
||||||
essid: String
|
essid: String
|
||||||
ip: String
|
ip: String
|
||||||
uptime: String
|
uptime: Int
|
||||||
apName: String
|
apName: String
|
||||||
status: Status
|
status: Status
|
||||||
accessPoint: AccessPoint
|
accessPoint: AccessPoint
|
||||||
|
@ -247,7 +247,7 @@ const typeDefs = gql`
|
||||||
frequency: String
|
frequency: String
|
||||||
protocol: String
|
protocol: String
|
||||||
speed: Int
|
speed: Int
|
||||||
usage: Int
|
usage: String
|
||||||
}
|
}
|
||||||
|
|
||||||
"A user that is on the Wi-Fi network reach"
|
"A user that is on the Wi-Fi network reach"
|
||||||
|
@ -322,6 +322,7 @@ const typeDefs = gql`
|
||||||
ip: String
|
ip: String
|
||||||
clients: Int
|
clients: Int
|
||||||
subnetInfo: SubnetInfo
|
subnetInfo: SubnetInfo
|
||||||
|
usage: String
|
||||||
|
|
||||||
createdAt: String
|
createdAt: String
|
||||||
updatedAt: String
|
updatedAt: String
|
||||||
|
@ -345,14 +346,14 @@ const typeDefs = gql`
|
||||||
shortName: String!
|
shortName: String!
|
||||||
name: String!
|
name: String!
|
||||||
cidr: String!
|
cidr: String!
|
||||||
networkAddress: String!
|
networkAddress: String!
|
||||||
firstAddress: String!
|
firstAddress: String!
|
||||||
lastAddress: String!
|
lastAddress: String!
|
||||||
broadcastAddress: String!
|
broadcastAddress: String!
|
||||||
subnetMask: String!
|
subnetMask: String!
|
||||||
subnetMaskLength: String!
|
subnetMaskLength: String!
|
||||||
numHosts: String!
|
numHosts: String!
|
||||||
length: String!
|
length: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input LoginInput {
|
input LoginInput {
|
||||||
|
@ -405,7 +406,7 @@ const typeDefs = gql`
|
||||||
notes: String
|
notes: String
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WifiDevicesResultSortBy{
|
enum WifiDevicesResultSortBy {
|
||||||
mac
|
mac
|
||||||
hostname
|
hostname
|
||||||
firstSeen
|
firstSeen
|
||||||
|
@ -420,7 +421,7 @@ const typeDefs = gql`
|
||||||
frequency
|
frequency
|
||||||
protocol
|
protocol
|
||||||
speed
|
speed
|
||||||
usage
|
usage
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
String.prototype.capitalize = function(lower = true) {
|
String.prototype.capitalize = function (lower = true) {
|
||||||
return (lower ? this.toLowerCase() : this).replace(/(?:^|\s)\S/g, a =>
|
return (lower ? this.toLowerCase() : this).replace(/(?:^|\s)\S/g, a =>
|
||||||
a.toUpperCase()
|
a.toUpperCase()
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
retrocycle, set, stringify, test
|
retrocycle, set, stringify, test
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (typeof JSON.decycle !== "function") {
|
if (typeof JSON.decycle !== 'function') {
|
||||||
JSON.decycle = function decycle(object, replacer) {
|
JSON.decycle = function decycle(object, replacer) {
|
||||||
"use strict";
|
'use strict'
|
||||||
|
|
||||||
// Make a deep copy of an object or array, assuring that there is at most
|
// Make a deep copy of an object or array, assuring that there is at most
|
||||||
// one instance of each object or array in the resulting structure. The
|
// one instance of each object or array in the resulting structure. The
|
||||||
|
@ -50,77 +50,73 @@ if (typeof JSON.decycle !== "function") {
|
||||||
// the object or array. [NUMBER] or [STRING] indicates a child element or
|
// the object or array. [NUMBER] or [STRING] indicates a child element or
|
||||||
// property.
|
// property.
|
||||||
|
|
||||||
var objects = new WeakMap(); // object to path mappings
|
var objects = new WeakMap() // object to path mappings
|
||||||
|
|
||||||
return (function derez(value, path) {
|
return (function derez(value, path) {
|
||||||
|
|
||||||
// The derez function recurses through the object, producing the deep copy.
|
// The derez function recurses through the object, producing the deep copy.
|
||||||
|
|
||||||
var old_path; // The path of an earlier occurance of value
|
var old_path // The path of an earlier occurance of value
|
||||||
var nu; // The new object or array
|
var nu // The new object or array
|
||||||
|
|
||||||
// If a replacer function was provided, then call it to get a replacement value.
|
// If a replacer function was provided, then call it to get a replacement value.
|
||||||
|
|
||||||
if (replacer !== undefined) {
|
if (replacer !== undefined) {
|
||||||
value = replacer(value);
|
value = replacer(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeof null === "object", so go on if this value is really an object but not
|
// typeof null === "object", so go on if this value is really an object but not
|
||||||
// one of the weird builtin objects.
|
// one of the weird builtin objects.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof value === "object"
|
typeof value === 'object' &&
|
||||||
&& value !== null
|
value !== null &&
|
||||||
&& !(value instanceof Boolean)
|
!(value instanceof Boolean) &&
|
||||||
&& !(value instanceof Date)
|
!(value instanceof Date) &&
|
||||||
&& !(value instanceof Number)
|
!(value instanceof Number) &&
|
||||||
&& !(value instanceof RegExp)
|
!(value instanceof RegExp) &&
|
||||||
&& !(value instanceof String)
|
!(value instanceof String)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// If the value is an object or array, look to see if we have already
|
// If the value is an object or array, look to see if we have already
|
||||||
// encountered it. If so, return a {"$ref":PATH} object. This uses an
|
// encountered it. If so, return a {"$ref":PATH} object. This uses an
|
||||||
// ES6 WeakMap.
|
// ES6 WeakMap.
|
||||||
|
|
||||||
old_path = objects.get(value);
|
old_path = objects.get(value)
|
||||||
if (old_path !== undefined) {
|
if (old_path !== undefined) {
|
||||||
return { $ref: old_path };
|
return { $ref: old_path }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, accumulate the unique value and its path.
|
// Otherwise, accumulate the unique value and its path.
|
||||||
|
|
||||||
objects.set(value, path);
|
objects.set(value, path)
|
||||||
|
|
||||||
// If it is an array, replicate the array.
|
// If it is an array, replicate the array.
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
nu = [];
|
nu = []
|
||||||
value.forEach(function (element, i) {
|
value.forEach(function (element, i) {
|
||||||
nu[i] = derez(element, path + "[" + i + "]");
|
nu[i] = derez(element, path + '[' + i + ']')
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// If it is an object, replicate the object.
|
// If it is an object, replicate the object.
|
||||||
|
|
||||||
nu = {};
|
nu = {}
|
||||||
Object.keys(value).forEach(function (name) {
|
Object.keys(value).forEach(function (name) {
|
||||||
nu[name] = derez(
|
nu[name] = derez(
|
||||||
value[name],
|
value[name],
|
||||||
path + "[" + JSON.stringify(name) + "]"
|
path + '[' + JSON.stringify(name) + ']'
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
return nu;
|
return nu
|
||||||
}
|
}
|
||||||
return value;
|
return value
|
||||||
}(object, "$"));
|
})(object, '$')
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof JSON.retrocycle !== 'function') {
|
||||||
if (typeof JSON.retrocycle !== "function") {
|
|
||||||
JSON.retrocycle = function retrocycle($) {
|
JSON.retrocycle = function retrocycle($) {
|
||||||
"use strict";
|
'use strict'
|
||||||
|
|
||||||
// Restore an object that was reduced by decycle. Members whose values are
|
// Restore an object that was reduced by decycle. Members whose values are
|
||||||
// objects of the form
|
// objects of the form
|
||||||
|
@ -141,42 +137,42 @@ if (typeof JSON.retrocycle !== "function") {
|
||||||
// return JSON.retrocycle(JSON.parse(s));
|
// return JSON.retrocycle(JSON.parse(s));
|
||||||
// produces an array containing a single element which is the array itself.
|
// produces an array containing a single element which is the array itself.
|
||||||
|
|
||||||
var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
|
var px =
|
||||||
|
/^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/
|
||||||
(function rez(value) {
|
|
||||||
|
|
||||||
|
;(function rez(value) {
|
||||||
// The rez function walks recursively through the object looking for $ref
|
// The rez function walks recursively through the object looking for $ref
|
||||||
// properties. When it finds one that has a value that is a path, then it
|
// properties. When it finds one that has a value that is a path, then it
|
||||||
// replaces the $ref object with a reference to the value that is found by
|
// replaces the $ref object with a reference to the value that is found by
|
||||||
// the path.
|
// the path.
|
||||||
|
|
||||||
if (value && typeof value === "object") {
|
if (value && typeof value === 'object') {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
value.forEach(function (element, i) {
|
value.forEach(function (element, i) {
|
||||||
if (typeof element === "object" && element !== null) {
|
if (typeof element === 'object' && element !== null) {
|
||||||
var path = element.$ref;
|
var path = element.$ref
|
||||||
if (typeof path === "string" && px.test(path)) {
|
if (typeof path === 'string' && px.test(path)) {
|
||||||
value[i] = eval(path);
|
value[i] = eval(path)
|
||||||
} else {
|
} else {
|
||||||
rez(element);
|
rez(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
Object.keys(value).forEach(function (name) {
|
Object.keys(value).forEach(function (name) {
|
||||||
var item = value[name];
|
var item = value[name]
|
||||||
if (typeof item === "object" && item !== null) {
|
if (typeof item === 'object' && item !== null) {
|
||||||
var path = item.$ref;
|
var path = item.$ref
|
||||||
if (typeof path === "string" && px.test(path)) {
|
if (typeof path === 'string' && px.test(path)) {
|
||||||
value[name] = eval(path);
|
value[name] = eval(path)
|
||||||
} else {
|
} else {
|
||||||
rez(item);
|
rez(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}($));
|
})($)
|
||||||
return $;
|
return $
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import fs from 'fs'
|
||||||
function saveJSONToFile(json, fileName = 'output.json') {
|
function saveJSONToFile(json, fileName = 'output.json') {
|
||||||
const jsonContent = JSON.stringify(json)
|
const jsonContent = JSON.stringify(json)
|
||||||
|
|
||||||
fs.writeFile(fileName, jsonContent, 'utf8', function(err) {
|
fs.writeFile(fileName, jsonContent, 'utf8', function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('An error occured while writing JSON Object to File.')
|
console.log('An error occured while writing JSON Object to File.')
|
||||||
return console.log(err)
|
return console.log(err)
|
||||||
|
|
|
@ -5,47 +5,37 @@ const subNetsInfo = [
|
||||||
{
|
{
|
||||||
shortName: 'RT',
|
shortName: 'RT',
|
||||||
name: 'Reitoria',
|
name: 'Reitoria',
|
||||||
cidr: '10.0.0.0/16',
|
cidr: '10.0.0.0/16'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'RT',
|
shortName: 'RT',
|
||||||
name: 'Reitoria',
|
name: 'Reitoria',
|
||||||
cidr: '10.1.0.0/16',
|
cidr: '10.1.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.32.4' }]
|
||||||
{ name: 'RNP', ip: '200.19.32.4' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'AQ',
|
shortName: 'AQ',
|
||||||
name: 'Aquidauana',
|
name: 'Aquidauana',
|
||||||
cidr: '10.2.0.0/16',
|
cidr: '10.2.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.32.253' }]
|
||||||
{ name: 'RNP', ip: '200.19.32.253' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'CG',
|
shortName: 'CG',
|
||||||
name: 'Campo Grande',
|
name: 'Campo Grande',
|
||||||
cidr: '10.3.0.0/16',
|
cidr: '10.3.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.32.120' }]
|
||||||
{ name: 'RNP', ip: '200.19.32.120' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'CB',
|
shortName: 'CB',
|
||||||
name: 'Corumbá',
|
name: 'Corumbá',
|
||||||
cidr: '10.4.0.0/16',
|
cidr: '10.4.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.37.2' }]
|
||||||
{ name: 'RNP', ip: '200.19.37.2' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'CX',
|
shortName: 'CX',
|
||||||
name: 'Coxim',
|
name: 'Coxim',
|
||||||
cidr: '10.5.0.0/16',
|
cidr: '10.5.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.36.16' }]
|
||||||
{ name: 'RNP', ip: '200.19.36.16' }
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'NA',
|
shortName: 'NA',
|
||||||
|
@ -57,17 +47,13 @@ const subNetsInfo = [
|
||||||
shortName: 'PP',
|
shortName: 'PP',
|
||||||
name: 'Ponta Porã',
|
name: 'Ponta Porã',
|
||||||
cidr: '10.7.0.0/16',
|
cidr: '10.7.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.34.254' }]
|
||||||
{ name: 'RNP', ip: '200.19.34.254' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'TL',
|
shortName: 'TL',
|
||||||
name: 'Três Lagoas',
|
name: 'Três Lagoas',
|
||||||
cidr: '10.8.0.0/16',
|
cidr: '10.8.0.0/16',
|
||||||
addresses: [
|
addresses: [{ name: 'RNP', ip: '200.19.35.2' }]
|
||||||
{ name: 'RNP', ip: '200.19.35.2' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'JD',
|
shortName: 'JD',
|
||||||
|
@ -80,13 +66,11 @@ const subNetsInfo = [
|
||||||
name: 'Naviraí',
|
name: 'Naviraí',
|
||||||
cidr: '10.10.0.0/16',
|
cidr: '10.10.0.0/16',
|
||||||
addresses: []
|
addresses: []
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
shortName: 'DR',
|
shortName: 'DR',
|
||||||
name: 'Dourados',
|
name: 'Dourados',
|
||||||
cidr: '10.11.0.0/16'
|
cidr: '10.11.0.0/16',
|
||||||
,
|
|
||||||
addresses: []
|
addresses: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -103,7 +87,6 @@ export function getSubnetInfo(ip) {
|
||||||
name: 'Sem rede'
|
name: 'Sem rede'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const subnet = subNets.find(subnet => subnet.contains(ip))
|
const subnet = subNets.find(subnet => subnet.contains(ip))
|
||||||
|
|
||||||
if (!subnet)
|
if (!subnet)
|
||||||
|
|
|
@ -6,5 +6,10 @@
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"arrowParens": "avoid",
|
"arrowParens": "avoid",
|
||||||
"vueIndentScriptAndStyle": false,
|
"vueIndentScriptAndStyle": false,
|
||||||
"excludeFiles": "dist/**"
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.js, *.vue, *.css, *.scss",
|
||||||
|
"excludeFiles": "**/dist/**, **/node_modules/**"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Portal de TI - Web Client
|
# Portal de TI - Web Client
|
||||||
|
|
||||||
## Desenvolvimento
|
## Desenvolvimento
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install
|
npm install
|
||||||
npm get-schema
|
npm get-schema
|
||||||
|
@ -8,11 +9,13 @@ npm run serve
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compilar para produção
|
### Compilar para produção
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lint
|
### Lint
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
directive @auth(roles: [String!]) on FIELD_DEFINITION
|
directive @auth(roles: [String!]) on FIELD_DEFINITION
|
||||||
|
|
||||||
directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE
|
directive @cacheControl(
|
||||||
|
maxAge: Int
|
||||||
|
scope: CacheControlScope
|
||||||
|
) on FIELD_DEFINITION | OBJECT | INTERFACE
|
||||||
|
|
||||||
type AuthPayload {
|
type AuthPayload {
|
||||||
user: User!
|
user: User!
|
||||||
|
@ -48,14 +51,23 @@ type Mutation {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
"""Returns only a few fields of User"""
|
"""
|
||||||
|
Returns only a few fields of User
|
||||||
|
"""
|
||||||
basicUser(sAMAccountName: String!): User!
|
basicUser(sAMAccountName: String!): User!
|
||||||
me: User!
|
me: User!
|
||||||
users(where: UserWhereInput!, limit: Int = 15, onlyStudents: Boolean = false): [User!]
|
users(
|
||||||
|
where: UserWhereInput!
|
||||||
|
limit: Int = 15
|
||||||
|
onlyStudents: Boolean = false
|
||||||
|
): [User!]
|
||||||
user(sAMAccountName: String!): User!
|
user(sAMAccountName: String!): User!
|
||||||
groups(where: GroupWhereInput!, limit: Int = 10): [Group!]!
|
groups(where: GroupWhereInput!, limit: Int = 10): [Group!]!
|
||||||
stats: Stats!
|
stats: Stats!
|
||||||
wifiDevices(search: String = "", identifiedOnly: Boolean = true): [WifiDevice]!
|
wifiDevices(
|
||||||
|
search: String = ""
|
||||||
|
identifiedOnly: Boolean = true
|
||||||
|
): [WifiDevice]!
|
||||||
userPresence(search: String): [UserPresence!]
|
userPresence(search: String): [UserPresence!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +103,14 @@ input UpdatePasswordInput {
|
||||||
newPassword: String!
|
newPassword: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
"""The `Upload` scalar type represents a file upload."""
|
"""
|
||||||
|
The `Upload` scalar type represents a file upload.
|
||||||
|
"""
|
||||||
scalar Upload
|
scalar Upload
|
||||||
|
|
||||||
"""A mix between the database User and the Active Directory User"""
|
"""
|
||||||
|
A mix between the database User and the Active Directory User
|
||||||
|
"""
|
||||||
type User {
|
type User {
|
||||||
id: ID
|
id: ID
|
||||||
wifiDevices: [WifiDevice!]
|
wifiDevices: [WifiDevice!]
|
||||||
|
@ -175,7 +191,7 @@ type WifiDevice {
|
||||||
lastSeen: String
|
lastSeen: String
|
||||||
essid: String
|
essid: String
|
||||||
ip: String
|
ip: String
|
||||||
uptime: String
|
uptime: Int
|
||||||
apName: String
|
apName: String
|
||||||
status: Status
|
status: Status
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
{
|
{
|
||||||
"name": "App",
|
"name": "App",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-36x36.png",
|
"src": "/android-icon-36x36.png",
|
||||||
"sizes": "36x36",
|
"sizes": "36x36",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "0.75"
|
"density": "0.75"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-48x48.png",
|
"src": "/android-icon-48x48.png",
|
||||||
"sizes": "48x48",
|
"sizes": "48x48",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "1.0"
|
"density": "1.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-72x72.png",
|
"src": "/android-icon-72x72.png",
|
||||||
"sizes": "72x72",
|
"sizes": "72x72",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "1.5"
|
"density": "1.5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-96x96.png",
|
"src": "/android-icon-96x96.png",
|
||||||
"sizes": "96x96",
|
"sizes": "96x96",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "2.0"
|
"density": "2.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-144x144.png",
|
"src": "/android-icon-144x144.png",
|
||||||
"sizes": "144x144",
|
"sizes": "144x144",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "3.0"
|
"density": "3.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "\/android-icon-192x192.png",
|
"src": "/android-icon-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image\/png",
|
"type": "image/png",
|
||||||
"density": "4.0"
|
"density": "4.0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
td {
|
td,
|
||||||
|
td * {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -37,4 +37,9 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style scoped>
|
||||||
|
td,
|
||||||
|
td * {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
:items="items"
|
:items="items"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:search="search"
|
:search="search"
|
||||||
|
sort-by="status"
|
||||||
|
sort-desc
|
||||||
calculate-widths
|
calculate-widths
|
||||||
>
|
>
|
||||||
<template #[`item.status`]="{ item }">
|
<template #[`item.status`]="{ item }">
|
||||||
|
@ -108,7 +110,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
td {
|
td,
|
||||||
|
td * {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #[`item.uptime`]="{ item: { uptime } }">
|
<template #[`item.uptime`]="{ item: { uptime } }">
|
||||||
<small> {{ uptime | durationFromSeconds }}</small>
|
<small class="text-no-wrap"> {{ uptime | durationFromSeconds }}</small>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #[`item.signalStrength`]="{ item: { signalStrength, status } }">
|
<template #[`item.signalStrength`]="{ item: { signalStrength, status } }">
|
||||||
|
@ -131,7 +131,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
td {
|
td,
|
||||||
|
td * {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -55,4 +55,9 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style scoped>
|
||||||
|
td,
|
||||||
|
td * {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<span class="text-no-wrap">
|
||||||
{{ amount }} <small>{{ unit }}</small>
|
{{ amount }} <small class="font-weight-medium">{{ unit }}</small>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import { destructedBytes } from '../../plugins/format-bytes'
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Number,
|
type: String,
|
||||||
default: 0
|
default: '0'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
|
||||||
export function destructedBytes(bytes, kib, maxUnit) {
|
export function destructedBytes(bytes, kib, maxUnit) {
|
||||||
|
if (bytes == 0)
|
||||||
|
return {
|
||||||
|
amount: '0',
|
||||||
|
unit: 'Bytes'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(parseFloat(bytes)) && !isFinite(bytes))
|
||||||
|
return { amount: '', unit: 'Err' }
|
||||||
|
|
||||||
const decimals = 1
|
const decimals = 1
|
||||||
|
|
||||||
kib = kib || false
|
kib = kib || false
|
||||||
|
|
||||||
if (bytes < 0) bytes = bytes * -1
|
|
||||||
|
|
||||||
if (bytes === 0) return '0 Bytes'
|
|
||||||
|
|
||||||
if (isNaN(parseFloat(bytes)) && !isFinite(bytes)) return ''
|
|
||||||
|
|
||||||
const k = kib ? 1024 : 1000
|
const k = kib ? 1024 : 1000
|
||||||
|
|
||||||
const sizes = kib
|
const sizes = kib
|
||||||
|
|
|
@ -144,7 +144,7 @@
|
||||||
<template #[`item.clients`]="{ item }">
|
<template #[`item.clients`]="{ item }">
|
||||||
<div class="align-content-end">
|
<div class="align-content-end">
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="item.uptime === '-1'"
|
:disabled="item.uptime == -1"
|
||||||
block
|
block
|
||||||
small
|
small
|
||||||
rounded
|
rounded
|
||||||
|
@ -183,6 +183,9 @@
|
||||||
<template #[`item.notes`]="{ item }">
|
<template #[`item.notes`]="{ item }">
|
||||||
<small>{{ item.notes }}</small>
|
<small>{{ item.notes }}</small>
|
||||||
</template>
|
</template>
|
||||||
|
<template #[`item.usage`]="{ item }">
|
||||||
|
<small>{{ item.usage | bytes }}</small>
|
||||||
|
</template>
|
||||||
</v-data-table>
|
</v-data-table>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
@ -206,6 +209,7 @@ export default {
|
||||||
'local',
|
'local',
|
||||||
'clients',
|
'clients',
|
||||||
'uptime',
|
'uptime',
|
||||||
|
'usage',
|
||||||
'notes'
|
'notes'
|
||||||
],
|
],
|
||||||
allHeaders: [
|
allHeaders: [
|
||||||
|
@ -214,7 +218,6 @@ export default {
|
||||||
{ text: 'IP', value: 'ip', width: 80 },
|
{ text: 'IP', value: 'ip', width: 80 },
|
||||||
{ text: 'MAC', value: 'mac' },
|
{ text: 'MAC', value: 'mac' },
|
||||||
{ text: 'Campus', value: 'campus', group: true },
|
{ text: 'Campus', value: 'campus', group: true },
|
||||||
|
|
||||||
{ text: 'Localização', value: 'local' },
|
{ text: 'Localização', value: 'local' },
|
||||||
{
|
{
|
||||||
text: 'Clientes',
|
text: 'Clientes',
|
||||||
|
@ -228,6 +231,7 @@ export default {
|
||||||
text: 'Controladora',
|
text: 'Controladora',
|
||||||
value: 'controller'
|
value: 'controller'
|
||||||
},
|
},
|
||||||
|
{ text: 'Uso', value: 'usage' },
|
||||||
{ text: 'Observações', value: 'notes' },
|
{ text: 'Observações', value: 'notes' },
|
||||||
{ text: 'Última atualização', value: 'updatedAt', width: 160 }
|
{ text: 'Última atualização', value: 'updatedAt', width: 160 }
|
||||||
]
|
]
|
||||||
|
@ -306,6 +310,7 @@ export default {
|
||||||
model
|
model
|
||||||
ip
|
ip
|
||||||
clients
|
clients
|
||||||
|
usage
|
||||||
|
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
|
@ -332,6 +337,7 @@ export default {
|
||||||
model
|
model
|
||||||
ip
|
ip
|
||||||
clients
|
clients
|
||||||
|
usage
|
||||||
|
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
|
|
Loading…
Reference in New Issue
Block a user