This commit is contained in:
iamBadgers
2024-08-10 22:16:02 -07:00
15 changed files with 157 additions and 25 deletions

View File

@@ -6,6 +6,7 @@ import { OrderByParser, FilterParser } from './tokenizer'
import { addGameApis } from './gameservice'
import { addCharacterApis } from './characterservice'
import { addRushStatsApis } from './rushstatsservice'
import { addDmApis } from './dmservice'
const app = express()
const jsonParser = json()
@@ -14,7 +15,7 @@ const port = 3001
addGameApis(app, jsonParser)
addCharacterApis(app, jsonParser)
addRushStatsApis(app, jsonParser)
addDmApis(app, jsonParser)
app.use(express.static(__dirname + '/frontend'))
app.use('/', (req, res) => {

View File

@@ -5,7 +5,7 @@ export function addCharacterApis(app, jsonParser) {
app.get('/api/character/:characterId', async (req, res) => {
try {
const character = await Character.findOne({
attributes: ["id", "characterName", "playerName", "role", "creationDate", "status"],
attributes: ['id', 'characterName', 'playerName', 'role', 'creationDate', 'status'],
where: { id: req.params['characterId'] }
})
if (character) {
@@ -35,11 +35,9 @@ export function addCharacterApis(app, jsonParser) {
where: filter
})
const totalCount = await Character.count({
where: filter
})
const pageCount = Math.ceil(
totalCount / count
)
where: filter
})
const pageCount = Math.ceil(totalCount / count)
res.setHeader('Content-Type', 'application/json')
res.send({ characterData, pageCount, totalCount })

58
backend/src/dmservice.ts Normal file
View File

@@ -0,0 +1,58 @@
import { database, Character, Game, Pick, App } from './db'
import { OrderByParser, FilterParser, ParsingError } from './tokenizer'
import { fn, col } from 'sequelize'
export function addDmApis(app, jsonParser) {
app.get('/api/dm/:dmName', async (req, res) => {
const dmName = req.params.dmName
let games = await Game.findAll({
where: { gamemaster: dmName }
})
res.send(games)
})
app.post('/api/dm', jsonParser, async (req, res) => {
try {
const fp = new FilterParser()
const obp = new OrderByParser()
const page = req.body.page || 0
const orderBy = req.body.orderBy ? obp.parse(req.body.orderBy) : ['id']
const count = req.body.count || 10
const filter = req.body.filter ? fp.parse(req.body.filter) : {}
const dms = await Game.findAll({
offset: page * count,
limit: count,
attributes: ['gamemaster', [fn('count', col('id')), 'gamecount']],
group: ['gamemaster'],
order: orderBy,
where: filter
})
const totalCount = (
await Game.count({
group: ['gamemaster'],
where: filter
})
).length
const pageCount = Math.ceil(totalCount / count)
res.setHeader('Content-Type', 'application/json')
res.send({
dms,
pageCount,
totalCount
})
} catch (e) {
if (e instanceof ParsingError) {
res.status(400).send('Could not parse filter.')
} else {
res.status(500).send(e)
}
}
})
}

View File

@@ -33,11 +33,9 @@ export function addGameApis(app, jsonParser) {
where: filter
})
const totalCount = await Game.count({
where: filter
})
const pageCount = Math.ceil(
totalCount / count
)
where: filter
})
const pageCount = Math.ceil(totalCount / count)
res.setHeader('Content-Type', 'application/json')
res.send({ gameData, pageCount, totalCount })

View File

@@ -98,7 +98,6 @@ export class FilterParser {
ctx.accept('value', m[3])
})
this.lexer.rule(spacerRegex, (ctx, m) => {
ctx.ignore()
})

View File

@@ -5,6 +5,7 @@
<v-btn to="/serverstats">Server Stats</v-btn>
<v-btn to="/games">Games</v-btn>
<v-btn to="/characters">Characters</v-btn>
<!-- <v-btn to="/gamemasters">Gamemasters</v-btn> -->
</v-app-bar>
<router-view />
</v-main>

View File

@@ -5,6 +5,7 @@ import GameDetails from '../vues/GameDetails.vue'
import CharacterList from '../vues/CharacterList.vue'
import CharacterDetails from '../vues/CharacterDetails.vue'
import ServerStats from '../vues/ServerStats.vue'
import DmList from '../vues/DmList.vue'
const root = {
path: '/',
@@ -36,13 +37,19 @@ const serverStatsRoute = {
component: ServerStats
}
const gameMasterListRoute = {
path: '/gamemasters',
component: DmList
}
const routes = [
root,
gameListRoute,
gameDetailsRoute,
characterListRoute,
characterDetailsRoute,
serverStatsRoute
serverStatsRoute,
gameMasterListRoute
]
export default createRouter({

View File

@@ -21,6 +21,13 @@ export interface Character {
creationDate: number
}
export interface DmStats {
name: string
gameCount: string
lastGame: number
games: Game
}
export interface GameStats {
Complete: number
Postponed: number

View File

@@ -0,0 +1,17 @@
<template>Hello World</template>
<style></style>
<script setup lang="ts">
import { DmStats } from '../types'
import { onMounted, ref, watch } from 'vue'
import { VDataTable } from 'vuetify/components'
type ReadonlyHeaders = VDataTable['$props']['headers']
const headers: ReadonlyHeaders = [
{ title: 'Game Master', align: 'start', sortable: true, key: 'id' },
{ title: 'Game Count', align: 'start', sortable: true, key: 'characterName' },
{ title: 'Last Game', align: 'start', sortable: true, key: 'role' }
]
</script>

View File

@@ -33,9 +33,7 @@
<thead>
<tr>
<th class="text-left">Role</th>
<th class="text-left">
Characters
</th>
<th class="text-left">Characters</th>
<th class="text-left">App Count</th>
<th class="text-left">Games Played</th>
<th class="text-left">Pick Rate %</th>

View File

@@ -2,11 +2,30 @@
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
echo ""
echo "---"
echo "Creating user rushstats"
echo "---"
if [id rushstats >/dev/null 2>&1]; then
echo "rushstats user already exists, skipping."
else
useradd -s /sbin/nologin rushstats
echo "User rushstats created with /sbin/nologin"
fi
echo ""
echo "---"
echo "Moving the distributable folder into /srv/gamestats"
echo "---"
cp -rf "$parent_path"/dist /srv/gamestats
if [ -d /srv/gamestats ]; then
echo "/srv/gamestats already exists; removing"
rm -r /srv/rushstats
fi
mkdir /srv/gamestats
cp -r "$parent_path"/dist/* /srv/gamestats
cp -r "$parent_path"/loader/* /srv/gamestats
chown -R rushstats:rushstats /srv/gamestats
echo ""
echo "---"
@@ -32,14 +51,18 @@ echo "[Install]" >> $SYSTEMD_SERVICE_FILE
echo "WantedBy=multi-user.target" >> $SYSTEMD_SERVICE_FILE
echo "" >> $SYSTEMD_SERVICE_FILE
echo ""
echo "---"
echo "Creating the cron job to refresh the database."
echo "---"
echo "Created new service."
echo cat $SYSTEMD_SERVICE_FILE
echo ""
echo "---"
echo "Reloading daemons and starting service"
echo "---"
systemctl daeomon-reload
systemctl start rushstats.service
systemctl daemon-reload
systemctl enable rushstats.service
systemctl start rushstats.service
echo ""
echo "---"
echo "Creating the cron job to refresh the database."
echo "---"

15
loader/chron-script.sh Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
PYTHON_VEN="$parent_path"/venv/bin/python
if [ ! -f $PYTHON_VEN ]; then
echo "Setting up new VENV"
python3 -m venv venv
echo "Installing requirements."
source ./venv/bin/activate
pip install -r requirements.txt
deactivate
fi
echo "Start DB Creation"
$parent_path/venv/bin/python createrushdatabase.py

View File

@@ -12,6 +12,10 @@ Game = namedtuple('Game',
Link = namedtuple('Link', ['gameId', 'gameTitle', 'characterId', 'characterName'])
SET_WAL_PRAGMA = """
PRAGMA journal_mode=WAL;
"""
APPS_TABLE_CREATE = """
CREATE TABLE IF NOT EXISTS "Apps" (
"gameId" INTEGER,
@@ -170,6 +174,7 @@ def loadAppsAndPicks(characterNameToId, gameTitleToId, gameFileName):
def createTables(dbName):
with sqlite3.connect(dbName) as connection:
cursor = connection.cursor()
cursor.execute(SET_WAL_PRAGMA)
cursor.execute(CHARACTER_TABLE_CREATE)
cursor.execute(GAMES_TABLE_CREATE)
cursor.execute(APPS_TABLE_CREATE)

5
loader/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
certifi==2024.6.2
charset-normalizer==3.3.2
idna==3.7
requests==2.32.3
urllib3==2.2.1

View File

@@ -22,7 +22,7 @@ cp -f ./backend/dist/* ./dist
cd "$parent_path"/loader
python3 createrushdatabase.py
cd ../
cp -r ./loader/testdb.db ./dist/testdb.db
cp -r ./loader/* ./dist
# Move the package into the dist folder and install the needed modules
cd "$parent_path"