diff --git a/backend/src/app.ts b/backend/src/app.ts
index 5f50c87..13ebca8 100644
--- a/backend/src/app.ts
+++ b/backend/src/app.ts
@@ -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) => {
diff --git a/backend/src/characterservice.ts b/backend/src/characterservice.ts
index 7cce42c..1750d46 100644
--- a/backend/src/characterservice.ts
+++ b/backend/src/characterservice.ts
@@ -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 })
diff --git a/backend/src/dmservice.ts b/backend/src/dmservice.ts
new file mode 100644
index 0000000..3bb3dad
--- /dev/null
+++ b/backend/src/dmservice.ts
@@ -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)
+ }
+ }
+ })
+}
diff --git a/backend/src/gameservice.ts b/backend/src/gameservice.ts
index 96140f7..24d6738 100644
--- a/backend/src/gameservice.ts
+++ b/backend/src/gameservice.ts
@@ -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 })
diff --git a/backend/src/tokenizer.ts b/backend/src/tokenizer.ts
index 5a4fe83..fde9ee2 100644
--- a/backend/src/tokenizer.ts
+++ b/backend/src/tokenizer.ts
@@ -98,7 +98,6 @@ export class FilterParser {
ctx.accept('value', m[3])
})
-
this.lexer.rule(spacerRegex, (ctx, m) => {
ctx.ignore()
})
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 1daed69..8a9be1c 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -5,6 +5,7 @@
Server Stats
Games
Characters
+
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index f5d159d..a41d190 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -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({
diff --git a/frontend/src/types.ts b/frontend/src/types.ts
index 814c40f..c13d050 100644
--- a/frontend/src/types.ts
+++ b/frontend/src/types.ts
@@ -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
diff --git a/frontend/src/vues/DmList.vue b/frontend/src/vues/DmList.vue
new file mode 100644
index 0000000..6a92ea0
--- /dev/null
+++ b/frontend/src/vues/DmList.vue
@@ -0,0 +1,17 @@
+Hello World
+
+
+
+
diff --git a/frontend/src/vues/ServerStats.vue b/frontend/src/vues/ServerStats.vue
index 3d46b68..cc4d007 100644
--- a/frontend/src/vues/ServerStats.vue
+++ b/frontend/src/vues/ServerStats.vue
@@ -33,9 +33,7 @@
| Role |
-
- Characters
- |
+ Characters |
App Count |
Games Played |
Pick Rate % |
diff --git a/install.sh b/install.sh
index 39013bb..c7d21ed 100755
--- a/install.sh
+++ b/install.sh
@@ -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
\ No newline at end of file
+systemctl daemon-reload
+systemctl enable rushstats.service
+systemctl start rushstats.service
+
+echo ""
+echo "---"
+echo "Creating the cron job to refresh the database."
+echo "---"
diff --git a/loader/chron-script.sh b/loader/chron-script.sh
new file mode 100644
index 0000000..f0c7e2a
--- /dev/null
+++ b/loader/chron-script.sh
@@ -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
diff --git a/loader/databasesync.py b/loader/databasesync.py
index 41cb9a6..f5f2f61 100644
--- a/loader/databasesync.py
+++ b/loader/databasesync.py
@@ -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)
diff --git a/loader/requirements.txt b/loader/requirements.txt
new file mode 100644
index 0000000..fd8654b
--- /dev/null
+++ b/loader/requirements.txt
@@ -0,0 +1,5 @@
+certifi==2024.6.2
+charset-normalizer==3.3.2
+idna==3.7
+requests==2.32.3
+urllib3==2.2.1
diff --git a/setup.sh b/setup.sh
index 1eaf546..c8ca604 100755
--- a/setup.sh
+++ b/setup.sh
@@ -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"