mirror of
https://github.com/kaythomas0/noisedash.git
synced 2025-11-14 12:18:01 +00:00
Add initial admin page with update feature
This commit is contained in:
@@ -7,7 +7,8 @@ module.exports = function () {
|
|||||||
username TEXT UNIQUE,
|
username TEXT UNIQUE,
|
||||||
hashed_password BLOB,
|
hashed_password BLOB,
|
||||||
salt BLOB,
|
salt BLOB,
|
||||||
name TEXT)`
|
name TEXT,
|
||||||
|
is_admin INTEGER)`
|
||||||
)
|
)
|
||||||
|
|
||||||
db.run(`CREATE TABLE IF NOT EXISTS profiles (
|
db.run(`CREATE TABLE IF NOT EXISTS profiles (
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ router.get('/profiles/:profileId', function (req, res, next) {
|
|||||||
return res.sendStatus(401)
|
return res.sendStatus(401)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: I'm guessing there's a better way to marshal this data
|
||||||
const profile = {
|
const profile = {
|
||||||
name: null,
|
name: null,
|
||||||
isTimerEnabled: null,
|
isTimerEnabled: null,
|
||||||
|
|||||||
@@ -3,6 +3,39 @@ const crypto = require('crypto')
|
|||||||
const db = require('../db')
|
const db = require('../db')
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get('/users', function (req, res, next) {
|
||||||
|
if (!req.user) {
|
||||||
|
return res.sendStatus(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: I'm guessing there's a better way to marshal this data
|
||||||
|
const users = []
|
||||||
|
|
||||||
|
db.all('SELECT username, name, is_admin as isAdmin FROM users', (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
console.log('Error getting profiles')
|
||||||
|
console.log(err)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.forEach((row) => {
|
||||||
|
const user = {
|
||||||
|
username: null,
|
||||||
|
name: null,
|
||||||
|
isAdmin: null
|
||||||
|
}
|
||||||
|
|
||||||
|
user.username = row.username
|
||||||
|
user.name = row.name
|
||||||
|
user.isAdmin = row.isAdmin === 1
|
||||||
|
|
||||||
|
users.push(user)
|
||||||
|
})
|
||||||
|
|
||||||
|
res.json({ users: users })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
router.post('/users', function (req, res, next) {
|
router.post('/users', function (req, res, next) {
|
||||||
const salt = crypto.randomBytes(16)
|
const salt = crypto.randomBytes(16)
|
||||||
crypto.pbkdf2(req.body.password, salt, 10000, 32, 'sha256', function (err, hashedPassword) {
|
crypto.pbkdf2(req.body.password, salt, 10000, 32, 'sha256', function (err, hashedPassword) {
|
||||||
@@ -11,11 +44,12 @@ router.post('/users', function (req, res, next) {
|
|||||||
res.sendStatus(500)
|
res.sendStatus(500)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.run('INSERT INTO users (username, hashed_password, salt, name) VALUES (?, ?, ?, ?)', [
|
db.run('INSERT INTO users (username, hashed_password, salt, name, is_admin) VALUES (?, ?, ?, ?, ?)', [
|
||||||
req.body.username,
|
req.body.username,
|
||||||
hashedPassword,
|
hashedPassword,
|
||||||
salt,
|
salt,
|
||||||
req.body.name
|
req.body.name,
|
||||||
|
req.body.isAdmin
|
||||||
], function (err) {
|
], function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
@@ -38,4 +72,22 @@ router.post('/users', function (req, res, next) {
|
|||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.put('/users', function (req, res, next) {
|
||||||
|
if (!req.user) {
|
||||||
|
return res.sendStatus(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.run('UPDATE users SET is_admin = ? WHERE username = ?', [req.body.isAdmin, req.body.username], (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.log('Error getting profiles')
|
||||||
|
console.log(err)
|
||||||
|
return res.sendStatus(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Row(s) updated: ${this.changes}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
res.sendStatus(200)
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|||||||
109
src/components/Admin.vue
Normal file
109
src/components/Admin.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<v-container>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-col class="mb-4">
|
||||||
|
<h1 class="display-2 font-weight-bold mb-3">
|
||||||
|
Admin Dashboard
|
||||||
|
</h1>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-simple-table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-left">
|
||||||
|
Username
|
||||||
|
</th>
|
||||||
|
<th class="text-left">
|
||||||
|
Is Admin
|
||||||
|
</th>
|
||||||
|
<th class="text-left">
|
||||||
|
Delete User
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="user in users"
|
||||||
|
:key="user.username"
|
||||||
|
>
|
||||||
|
<td>{{ user.username }}</td>
|
||||||
|
<td>
|
||||||
|
<v-switch
|
||||||
|
v-model="user.isAdmin"
|
||||||
|
:label="`${user.isAdmin ? 'True' : 'False'}`"
|
||||||
|
@change="updateUser(user.username, user.isAdmin); snackbar = true"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<v-btn
|
||||||
|
@click="updateUser(user.username)"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</v-btn>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</v-simple-table>
|
||||||
|
<v-snackbar
|
||||||
|
v-model="snackbar"
|
||||||
|
timeout="3000"
|
||||||
|
>
|
||||||
|
{{ updateText }}
|
||||||
|
|
||||||
|
<template v-slot:action="{ attrs }">
|
||||||
|
<v-btn
|
||||||
|
text
|
||||||
|
v-bind="attrs"
|
||||||
|
@click="snackbar = false"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-snackbar>
|
||||||
|
</v-col>
|
||||||
|
</v-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Admin',
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
users: [],
|
||||||
|
snackbar: false,
|
||||||
|
updateText: ''
|
||||||
|
}),
|
||||||
|
created () {
|
||||||
|
this.getUsers()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUsers () {
|
||||||
|
this.$http.get('https://localhost:3000/users')
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.users = response.data.users
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.error(error.response)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateUser (username, isAdmin) {
|
||||||
|
this.$http.put('https://localhost:3000/users', {
|
||||||
|
username: username,
|
||||||
|
isAdmin: isAdmin ? 1 : 0
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log('User updated')
|
||||||
|
this.updateText = 'User updated'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.error(error.response)
|
||||||
|
this.updateText = 'Error updating user'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -21,7 +21,9 @@
|
|||||||
<v-list-item-group
|
<v-list-item-group
|
||||||
v-model="group"
|
v-model="group"
|
||||||
>
|
>
|
||||||
<v-list-item>
|
<v-list-item
|
||||||
|
@click="home"
|
||||||
|
>
|
||||||
<v-list-item-icon>
|
<v-list-item-icon>
|
||||||
<v-icon>mdi-home</v-icon>
|
<v-icon>mdi-home</v-icon>
|
||||||
</v-list-item-icon>
|
</v-list-item-icon>
|
||||||
@@ -42,7 +44,6 @@
|
|||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="$vuetify.theme.dark"
|
v-model="$vuetify.theme.dark"
|
||||||
inset
|
|
||||||
label="Dark Mode"
|
label="Dark Mode"
|
||||||
/>
|
/>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@@ -61,6 +62,12 @@ export default {
|
|||||||
group: null
|
group: null
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
|
home () {
|
||||||
|
this.$router.push('/')
|
||||||
|
},
|
||||||
|
admin () {
|
||||||
|
this.$router.push('/admin')
|
||||||
|
},
|
||||||
logout () {
|
logout () {
|
||||||
this.$http.get('https://localhost:3000/logout')
|
this.$http.get('https://localhost:3000/logout')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ export default {
|
|||||||
this.$http.post('https://localhost:3000/users', {
|
this.$http.post('https://localhost:3000/users', {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password
|
password: this.password,
|
||||||
|
isAdmin: 1
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ const routes = [
|
|||||||
// this generates a separate chunk (about.[hash].js) for this route
|
// this generates a separate chunk (about.[hash].js) for this route
|
||||||
// which is lazy-loaded when the route is visited.
|
// which is lazy-loaded when the route is visited.
|
||||||
component: () => import(/* webpackChunkName: "about" */ '../views/Signup.vue')
|
component: () => import(/* webpackChunkName: "about" */ '../views/Signup.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin',
|
||||||
|
name: 'Admin',
|
||||||
|
component: () => import(/* webpackChunkName: "about" */ '../views/AdminPage.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
15
src/views/AdminPage.vue
Normal file
15
src/views/AdminPage.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<Admin />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Admin from '../components/Admin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AdminPage',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Admin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user