Added wifiUsers query

This commit is contained in:
Douglas Barone 2020-11-27 15:01:55 -04:00
parent f8da81a895
commit 94773e52bf
5 changed files with 186 additions and 24 deletions

View File

@ -94,7 +94,7 @@ const Query = {
wifiDevices: async (_, { identifiedOnly, nonIdentifiedOnly }) => { wifiDevices: async (_, { identifiedOnly, nonIdentifiedOnly }) => {
if (identifiedOnly && nonIdentifiedOnly) if (identifiedOnly && nonIdentifiedOnly)
throw new Error('Invalid combination of filters') throw new Error('Invalid combination of filters')
updateDBWithOnlineDevices() updateDBWithOnlineDevices()
return prisma.wifiDevice.findMany({ return prisma.wifiDevice.findMany({
@ -108,6 +108,14 @@ const Query = {
}) })
}, },
wifiUsers: () => {
return prisma.user.findMany({
orderBy: { displayName: 'asc' },
where: { wifiDevices: { some: { NOT: { lastSeen: null } } } },
include: { wifiDevices: true }
})
},
userPresence: async (_, { search }) => { userPresence: async (_, { search }) => {
if (!search) search = '' if (!search) search = ''

View File

@ -23,13 +23,15 @@ const typeDefs = gql`
stats: Stats! stats: Stats!
userPresence(search: String = ""): [UserPresence!] @auth(roles: ["watcher"])
wifiDevices( wifiDevices(
search: String = "" search: String = ""
identifiedOnly: Boolean = false identifiedOnly: Boolean = false
nonIdentifiedOnly: Boolean = false nonIdentifiedOnly: Boolean = false
): [WifiDevice]! ): [WifiDevice]! @auth(roles: ["superAdmin"])
userPresence(search: String = ""): [UserPresence!] @auth(roles: ["watcher"]) wifiUsers: [User]! @auth(roles: ["superAdmin"])
} }
type Mutation { type Mutation {

View File

@ -160,12 +160,23 @@ const routes = [
name: 'wifi-devices', name: 'wifi-devices',
meta: { meta: {
title: 'Dispositivos WiFi', title: 'Dispositivos WiFi',
watcher: true superAdmin: true
}, },
component: () => component: () =>
import(/* webpackChunkName: "wifi-devices" */ '../views/WifiDevices.vue') import(/* webpackChunkName: "wifi-devices" */ '../views/WifiDevices.vue')
}, },
{
path: '/wifi-users',
name: 'wifi-users',
meta: {
title: 'Usuários WiFi',
superAdmin: true
},
component: () =>
import(/* webpackChunkName: "wifi-users" */ '../views/WifiUsers.vue')
},
{ {
path: '/system-administration', path: '/system-administration',
name: 'system-administration', name: 'system-administration',

View File

@ -29,25 +29,47 @@
</v-toolbar> </v-toolbar>
</template> </template>
<template #default="{ items }"> <template #default="{ items }">
<v-expansion-panels popout multiple> <v-expansion-panels multiple>
<v-expansion-panel v-for="item in items" :key="item.mac"> <v-expansion-panel v-for="device in items" :key="device.mac">
<v-expansion-panel-header> <v-expansion-panel-header>
<div> <v-row dense align-content="center" no-gutters>
<v-icon left :color="item.isOnline ? 'green darken-1' : ''"> <v-col class="shrink" align-self="center">
mdi-cellphone-wireless <v-badge
</v-icon> :color="device.isOnline ? 'green' : 'grey'"
{{ item.hostname }} - {{ item.ip }} left
</div> offset-y="16"
dot
>
<ap-icon class="mr-4" :controller="device.controller" />
</v-badge>
</v-col>
<v-col align-self="center" cols="3">
{{ device.hostname }}
</v-col>
<v-col
v-if="$vuetify.breakpoint.mdAndUp"
cols="2"
class="grow"
>{{ device.ip }}</v-col
>
<v-col v-if="$vuetify.breakpoint.mdAndUp" class="grow">
<div>
<avatar left size="24px" :src="device.thumbnailPhoto" />{{
device.displayName
}}
</div>
</v-col>
</v-row>
</v-expansion-panel-header> </v-expansion-panel-header>
<v-expansion-panel-content> <v-expansion-panel-content>
<v-list dense> <v-list dense>
<v-list-item v-if="item.status === 'ONLINE'"> <v-list-item v-if="device.isOnline">
<v-list-item-action> <v-list-item-action>
<v-icon color="green darken-1">mdi-wifi</v-icon> <v-icon color="green darken-1">mdi-wifi</v-icon>
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.essid }} (próximo ao AP {{ item.apName }}) {{ device.essid }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> SSID </v-list-item-subtitle> <v-list-item-subtitle> SSID </v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
@ -59,7 +81,7 @@
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.essid }} (próximo ao AP {{ item.apName }}) {{ device.essid }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
Dispositivo off-line Dispositivo off-line
@ -67,13 +89,27 @@
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
<v-list-item>
<v-list-item-action>
<v-icon>mdi-access-point</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
{{ device.apName }}
</v-list-item-title>
<v-list-item-subtitle>
Access Point ({{ device.controller }})
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item> <v-list-item>
<v-list-item-action> <v-list-item-action>
<v-icon>mdi-ip-network</v-icon> <v-icon>mdi-ip-network</v-icon>
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.ip }} {{ device.ip }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
Último endereço IP conhecido Último endereço IP conhecido
@ -86,10 +122,10 @@
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.mac }} {{ device.mac }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
{{ item.oui }} {{ device.oui }}
</v-list-item-subtitle> </v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
@ -99,7 +135,7 @@
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.lastSeen | dateAndTime }} {{ device.lastSeen | dateAndTime }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
Visto pela última vez Visto pela última vez
@ -112,7 +148,7 @@
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.firstSeen | dateAndTime }} {{ device.firstSeen | dateAndTime }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
Visto pela primeira vez Visto pela primeira vez
@ -121,14 +157,14 @@
</v-list-item> </v-list-item>
<v-list-item> <v-list-item>
<v-list-item-action> <v-list-item-action>
<Avatar :src="item.thumbnailPhoto" size="24px" /> <Avatar :src="device.thumbnailPhoto" size="24px" />
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
<v-list-item-title> <v-list-item-title>
{{ item.displayName }} {{ device.displayName }}
</v-list-item-title> </v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>
{{ item.sAMAccountName }} {{ device.sAMAccountName }}
</v-list-item-subtitle> </v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
</v-list-item> </v-list-item>
@ -144,10 +180,11 @@
<script> <script>
import gql from 'graphql-tag' import gql from 'graphql-tag'
import Avatar from '../components/Avatar.vue' import Avatar from '../components/Avatar.vue'
import ApIcon from '../components/ApIcon.vue'
export default { export default {
name: 'WifiDevices', name: 'WifiDevices',
components: { Avatar }, components: { Avatar, ApIcon },
data: () => ({ data: () => ({
search: '', search: '',
itemsPerPage: 15, itemsPerPage: 15,

104
web/src/views/WifiUsers.vue Normal file
View File

@ -0,0 +1,104 @@
<template>
<v-container fluid>
<v-data-iterator
:items="computedWifiUsers"
:loading="$apollo.queries.wifiUsers.loading"
:search="search"
>
<template #header>
<v-toolbar flat class="mb-2">
<v-text-field
v-model="search"
rounded
outlined
label="Buscar"
hint="Nome, conta"
dense
/>
<v-btn
class="ml-2 mb-6"
:loading="$apollo.queries.wifiUsers.loading"
color="primary"
text
@click="$apollo.queries.wifiUsers.refresh()"
>
<v-icon left>mdi-refresh</v-icon> Atualizar
</v-btn>
</v-toolbar>
</template>
<template #default="{ items }">
<v-expansion-panels>
<v-expansion-panel v-for="user in items" :key="user.sAMAccountName">
<v-expansion-panel-header>
<div style="width: 50px">
<avatar size="24" left :src="user.thumbnailPhoto" />
{{ user.displayName }}
</div>
<template #actions>
{{ user.wifiDevices.length }}
{{ user.wifiDevices.length > 1 ? 'dispositivos' : 'disposivo' }}
</template>
</v-expansion-panel-header>
<v-expansion-panel-content>
<v-expansion-panels flat>
<v-expansion-panel
v-for="device in user.wifiDevices"
:key="device.mac"
>
<v-expansion-panel-header>
{{ device.hostname || device.mac }} {{ device.oui }}
</v-expansion-panel-header>
<v-expansion-panel-content>{{
device
}}</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</template>
</v-data-iterator>
</v-container>
</template>
<script>
import gql from 'graphql-tag'
import Avatar from '../components/Avatar.vue'
export default {
components: { Avatar },
data: () => ({
search: ''
}),
computed: {
computedWifiUsers() {
return this.wifiUsers?.sort(
(a, b) => b.wifiDevices.length - a.wifiDevices.length
)
}
},
apollo: {
wifiUsers: {
fetchPolicy: 'cache-and-network',
query: gql`
query {
wifiUsers {
displayName
sAMAccountName
thumbnailPhoto
wifiDevices {
mac
oui
controller
hostname
firstSeen
lastSeen
}
}
}
`
}
}
}
</script>