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