Remove MongoDB; add PM2 scripts, CI, tests; fix PlayerTab hooks; add pm2 smoke-test
This commit is contained in:
23
.github/workflows/ci.yml
vendored
Normal file
23
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run tests
|
||||
run: npm test -- --runInBand
|
||||
- name: Build production bundle
|
||||
run: npm run build
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,5 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
mongodb.log
|
||||
Deathwatch-Core-Rulebook.pdf
|
||||
data/journal/*
|
||||
|
||||
@@ -8,7 +8,6 @@ Deathwatch Roller is a React-based application designed to assist players and Ga
|
||||
- Player management
|
||||
- Requisition shop for items
|
||||
- Session tracking
|
||||
- Integration with MongoDB for data persistence
|
||||
|
||||
## Setup Instructions
|
||||
1. Clone the repository:
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
WiredTiger
|
||||
WiredTiger 10.0.2: (December 21, 2021)
|
||||
@@ -1 +0,0 @@
|
||||
WiredTiger lock file
|
||||
@@ -1,6 +0,0 @@
|
||||
WiredTiger version string
|
||||
WiredTiger 10.0.2: (December 21, 2021)
|
||||
WiredTiger version
|
||||
major=10,minor=0,patch=2
|
||||
file:WiredTiger.wt
|
||||
access_pattern_hint=none,allocation_size=4KB,app_metadata=,assert=(commit_timestamp=none,durable_timestamp=none,read_timestamp=none,write_timestamp=off),block_allocation=best,block_compressor=,cache_resident=false,checksum=on,collator=,columns=,dictionary=0,encryption=(keyid=,name=),format=btree,huffman_key=,huffman_value=,id=0,ignore_in_memory_cache_size=false,internal_item_max=0,internal_key_max=0,internal_key_truncate=true,internal_page_max=4KB,key_format=S,key_gap=10,leaf_item_max=0,leaf_key_max=0,leaf_page_max=32KB,leaf_value_max=0,log=(enabled=true),memory_page_image_max=0,memory_page_max=5MB,os_cache_dirty_max=0,os_cache_max=0,prefix_compression=false,prefix_compression_min=4,readonly=false,split_deepen_min_child=0,split_deepen_per_child=0,split_pct=90,tiered_object=false,tiered_storage=(auth_token=,bucket=,bucket_prefix=,cache_directory=,local_retention=300,name=,object_target_size=0),value_format=S,verbose=[],version=(major=1,minor=1),write_timestamp_usage=none,checkpoint=(WiredTigerCheckpoint.11=(addr="018581e4dc06b8b98681e4928c41608781e41f76d752808080e29fc0e22fc0",order=11,time=1755206972,size=24576,newest_start_durable_ts=0,oldest_start_ts=0,newest_txn=4,newest_stop_durable_ts=0,newest_stop_ts=-1,newest_stop_txn=-11,prepare=0,write_gen=29,run_write_gen=25)),checkpoint_backup_info=,checkpoint_lsn=(4,4864)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6663,3 +6663,308 @@ Connected to MongoDB
|
||||
[2025-08-16T10:21:06.519Z] API: Deleted player testplayer
|
||||
[2025-08-16T10:21:08.256Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:21:08.258Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:33:58.033Z] DB: getSession - start 78e9a6aeec141cc6e5b5c7fc769bcdf001b2cd8bdc5ef7cab93ef2ceb5e76256
|
||||
[2025-08-16T10:33:58.033Z] DB: getSession - ok 78e9a6aeec141cc6e5b5c7fc769bcdf001b2cd8bdc5ef7cab93ef2ceb5e76256
|
||||
[2025-08-16T10:33:58.034Z] SESSION: Validate success 78e9a6aeec141cc6e5b5c7fc769bcdf001b2cd8bdc5ef7cab93ef2ceb5e76256 andreas
|
||||
[2025-08-16T10:40:12.152Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:40:12.152Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:40:12.152Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:40:12.152Z] DB: deletePlayer - changes 0 gmtest
|
||||
[2025-08-16T10:40:12.186Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:40:12.186Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.186Z] DB: getPlayerByName - not found gmtest
|
||||
[2025-08-16T10:40:12.268Z] DB: createPlayer - start gmtest
|
||||
[2025-08-16T10:40:12.269Z] DB: createPlayer - done gmtest rowid 85
|
||||
[2025-08-16T10:40:12.269Z] API: Created player gmtest
|
||||
[2025-08-16T10:40:12.288Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:40:12.288Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:40:12.288Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.289Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:40:12.289Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:40:12.289Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:40:12.289Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.289Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:40:12.290Z] API: Updated player gmtest
|
||||
[2025-08-16T10:40:12.307Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:40:12.307Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:40:12.307Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.307Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:40:12.388Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:40:12.388Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:40:12.388Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.388Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:40:12.388Z] API: Updated player gmtest
|
||||
[2025-08-16T10:40:12.405Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:40:12.406Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:40:12.489Z] DB: createSession - start 95266200028019a2301ce82b6fa7f5cd47f9d409ab6abebb7342caaa7eb70675 expiresAt 2025-08-17T10:40:12.489Z
|
||||
[2025-08-16T10:40:12.490Z] DB: createSession - done 95266200028019a2301ce82b6fa7f5cd47f9d409ab6abebb7342caaa7eb70675
|
||||
[2025-08-16T10:40:12.490Z] API: Player login gmtest 95266200028019a2301ce82b6fa7f5cd47f9d409ab6abebb7342caaa7eb70675
|
||||
[2025-08-16T10:40:12.507Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:40:12.507Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:40:12.507Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:40:12.508Z] DB: deletePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:40:12.508Z] API: Deleted player gmtest
|
||||
[2025-08-16T10:40:12.523Z] SESSION: GM bypass accepted GET /api/players
|
||||
[2025-08-16T10:40:12.523Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:40:12.525Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:40:12.525Z] API: Fetch all players (public) Found 7 players
|
||||
[2025-08-16T10:40:14.429Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:40:14.429Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:40:14.429Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:40:14.429Z] DB: deletePlayer - changes 0 testplayer
|
||||
[2025-08-16T10:40:14.445Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:40:14.446Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.446Z] DB: getPlayerByName - not found testplayer
|
||||
[2025-08-16T10:40:14.525Z] DB: createPlayer - start testplayer
|
||||
[2025-08-16T10:40:14.525Z] DB: createPlayer - done testplayer rowid 86
|
||||
[2025-08-16T10:40:14.525Z] API: Created player testplayer
|
||||
[2025-08-16T10:40:14.546Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.546Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:40:14.627Z] DB: createSession - start f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3 expiresAt 2025-08-17T10:40:14.627Z
|
||||
[2025-08-16T10:40:14.627Z] DB: createSession - done f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.627Z] API: Player login testplayer f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.642Z] DB: getSession - start f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.643Z] DB: getSession - ok f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.643Z] SESSION: Valid f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: getSession - start f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.643Z] DB: getSession - ok f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.643Z] SESSION: Valid f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.643Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:40:14.643Z] API: Updated player testplayer
|
||||
[2025-08-16T10:40:14.670Z] DB: getSession - start f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.670Z] DB: getSession - ok f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.670Z] SESSION: Valid f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:40:14.670Z] DB: getSession - start f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.670Z] DB: getSession - ok f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3
|
||||
[2025-08-16T10:40:14.670Z] SESSION: Valid f8abbc1404903c0cf118c734972228a0a7ff2f9766da758aa0d88c7f617e84b3 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:40:14.670Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.670Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:40:14.671Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:40:14.671Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:40:14.671Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:40:14.671Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:40:14.671Z] API: Updated player testplayer
|
||||
[2025-08-16T10:40:14.688Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:40:14.689Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:40:14.689Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:40:14.689Z] DB: deletePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:40:14.689Z] API: Deleted player testplayer
|
||||
[2025-08-16T10:40:15.178Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:40:15.184Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:53:33.754Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:53:33.755Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:53:33.756Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:53:33.756Z] DB: deletePlayer - changes 0 gmtest
|
||||
[2025-08-16T10:53:33.793Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:53:33.794Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:33.794Z] DB: getPlayerByName - not found gmtest
|
||||
[2025-08-16T10:53:33.986Z] DB: createPlayer - start gmtest
|
||||
[2025-08-16T10:53:33.986Z] DB: createPlayer - done gmtest rowid 87
|
||||
[2025-08-16T10:53:33.987Z] API: Created player gmtest
|
||||
[2025-08-16T10:53:34.007Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:53:34.008Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:53:34.008Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:34.008Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:53:34.009Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:53:34.010Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:53:34.010Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:34.010Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:53:34.010Z] API: Updated player gmtest
|
||||
[2025-08-16T10:53:34.027Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:53:34.027Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:53:34.027Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:34.027Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:53:34.109Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:53:34.109Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:53:34.109Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:34.110Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:53:34.110Z] API: Updated player gmtest
|
||||
[2025-08-16T10:53:34.127Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:53:34.127Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:53:34.207Z] DB: createSession - start b95410e923efaa4bcef57b8b3633c84ab618013d2bd6bbeb1afd99a60b96caf9 expiresAt 2025-08-17T10:53:34.207Z
|
||||
[2025-08-16T10:53:34.208Z] DB: createSession - done b95410e923efaa4bcef57b8b3633c84ab618013d2bd6bbeb1afd99a60b96caf9
|
||||
[2025-08-16T10:53:34.208Z] API: Player login gmtest b95410e923efaa4bcef57b8b3633c84ab618013d2bd6bbeb1afd99a60b96caf9
|
||||
[2025-08-16T10:53:34.224Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:53:34.225Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:53:34.225Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:53:34.225Z] DB: deletePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:53:34.225Z] API: Deleted player gmtest
|
||||
[2025-08-16T10:53:34.250Z] SESSION: GM bypass accepted GET /api/players
|
||||
[2025-08-16T10:53:34.251Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:53:34.253Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:53:34.253Z] API: Fetch all players (public) Found 7 players
|
||||
[2025-08-16T10:53:34.683Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:53:34.684Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:53:34.684Z] DB: deletePlayer - start shoptestplayer
|
||||
[2025-08-16T10:53:34.684Z] DB: deletePlayer - changes 0 shoptestplayer
|
||||
[2025-08-16T10:53:34.697Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:53:34.697Z] DB: getPlayerByName - start shoptestplayer
|
||||
[2025-08-16T10:53:34.698Z] DB: getPlayerByName - not found shoptestplayer
|
||||
[2025-08-16T10:53:34.777Z] DB: createPlayer - start shoptestplayer
|
||||
[2025-08-16T10:53:34.778Z] DB: createPlayer - done shoptestplayer rowid 88
|
||||
[2025-08-16T10:53:34.778Z] API: Created player shoptestplayer
|
||||
[2025-08-16T10:53:34.791Z] SESSION: Missing sessionId GET /api/shop/inventory/shoptestplayer
|
||||
[2025-08-16T10:53:34.803Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:53:34.804Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:53:34.804Z] DB: deletePlayer - start shoptestplayer
|
||||
[2025-08-16T10:53:34.804Z] DB: deletePlayer - changes 1 shoptestplayer
|
||||
[2025-08-16T10:53:34.804Z] API: Deleted player shoptestplayer
|
||||
[2025-08-16T10:53:35.117Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:53:35.117Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:53:35.117Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:53:35.118Z] DB: deletePlayer - changes 0 testplayer
|
||||
[2025-08-16T10:53:35.133Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:53:35.134Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.134Z] DB: getPlayerByName - not found testplayer
|
||||
[2025-08-16T10:53:35.216Z] DB: createPlayer - start testplayer
|
||||
[2025-08-16T10:53:35.216Z] DB: createPlayer - done testplayer rowid 89
|
||||
[2025-08-16T10:53:35.216Z] API: Created player testplayer
|
||||
[2025-08-16T10:53:35.234Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.234Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:53:35.315Z] DB: createSession - start 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c expiresAt 2025-08-17T10:53:35.315Z
|
||||
[2025-08-16T10:53:35.316Z] DB: createSession - done 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.316Z] API: Player login testplayer 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.332Z] DB: getSession - start 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.332Z] DB: getSession - ok 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.332Z] SESSION: Valid 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:53:35.332Z] DB: getSession - start 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.333Z] DB: getSession - ok 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.333Z] SESSION: Valid 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.333Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:53:35.333Z] API: Updated player testplayer
|
||||
[2025-08-16T10:53:35.349Z] DB: getSession - start 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.350Z] DB: getSession - ok 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.350Z] SESSION: Valid 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: getSession - start 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.350Z] DB: getSession - ok 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c
|
||||
[2025-08-16T10:53:35.350Z] SESSION: Valid 195d0b602edb504111434414528c19901ecd060718a4d2db08c261cc66c69f7c testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:53:35.350Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:53:35.351Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:53:35.351Z] API: Updated player testplayer
|
||||
[2025-08-16T10:53:35.366Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:53:35.366Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:53:35.366Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:53:35.367Z] DB: deletePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:53:35.367Z] API: Deleted player testplayer
|
||||
[2025-08-16T10:53:35.902Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:53:35.905Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:59:25.321Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:59:25.322Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:59:25.322Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:59:25.322Z] DB: deletePlayer - changes 0 gmtest
|
||||
[2025-08-16T10:59:25.338Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:59:25.339Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.339Z] DB: getPlayerByName - not found gmtest
|
||||
[2025-08-16T10:59:25.418Z] DB: createPlayer - start gmtest
|
||||
[2025-08-16T10:59:25.418Z] DB: createPlayer - done gmtest rowid 90
|
||||
[2025-08-16T10:59:25.419Z] API: Created player gmtest
|
||||
[2025-08-16T10:59:25.435Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:59:25.435Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.436Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:59:25.436Z] API: Updated player gmtest
|
||||
[2025-08-16T10:59:25.451Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:59:25.451Z] SESSION: GM bypass accepted PUT /api/players/gmtest
|
||||
[2025-08-16T10:59:25.452Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.452Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:59:25.533Z] DB: updatePlayer - start gmtest
|
||||
[2025-08-16T10:59:25.533Z] DB: updatePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:59:25.533Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.533Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:59:25.533Z] API: Updated player gmtest
|
||||
[2025-08-16T10:59:25.549Z] DB: getPlayerByName - start gmtest
|
||||
[2025-08-16T10:59:25.549Z] DB: getPlayerByName - found gmtest
|
||||
[2025-08-16T10:59:25.629Z] DB: createSession - start 2936785aeb120a3bc01ceb240e7b0042612208e33770e19edaddcc0e0cb5ee2f expiresAt 2025-08-17T10:59:25.629Z
|
||||
[2025-08-16T10:59:25.629Z] DB: createSession - done 2936785aeb120a3bc01ceb240e7b0042612208e33770e19edaddcc0e0cb5ee2f
|
||||
[2025-08-16T10:59:25.629Z] API: Player login gmtest 2936785aeb120a3bc01ceb240e7b0042612208e33770e19edaddcc0e0cb5ee2f
|
||||
[2025-08-16T10:59:25.644Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:59:25.645Z] SESSION: GM bypass accepted DELETE /api/players/gmtest
|
||||
[2025-08-16T10:59:25.645Z] DB: deletePlayer - start gmtest
|
||||
[2025-08-16T10:59:25.646Z] DB: deletePlayer - changes 1 gmtest
|
||||
[2025-08-16T10:59:25.646Z] API: Deleted player gmtest
|
||||
[2025-08-16T10:59:25.661Z] SESSION: GM bypass accepted GET /api/players
|
||||
[2025-08-16T10:59:25.661Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:59:25.662Z] DB: getAllPlayers - resultCount 7
|
||||
[2025-08-16T10:59:25.662Z] API: Fetch all players (public) Found 7 players
|
||||
[2025-08-16T10:59:26.476Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:59:26.476Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:59:26.476Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:59:26.477Z] DB: deletePlayer - changes 0 testplayer
|
||||
[2025-08-16T10:59:26.494Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:59:26.494Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.494Z] DB: getPlayerByName - not found testplayer
|
||||
[2025-08-16T10:59:26.576Z] DB: createPlayer - start testplayer
|
||||
[2025-08-16T10:59:26.576Z] DB: createPlayer - done testplayer rowid 91
|
||||
[2025-08-16T10:59:26.576Z] API: Created player testplayer
|
||||
[2025-08-16T10:59:26.594Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.594Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:59:26.674Z] DB: createSession - start 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9 expiresAt 2025-08-17T10:59:26.674Z
|
||||
[2025-08-16T10:59:26.674Z] DB: createSession - done 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.674Z] API: Player login testplayer 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.690Z] DB: getSession - start 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.690Z] DB: getSession - ok 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.690Z] SESSION: Valid 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: getSession - start 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.691Z] DB: getSession - ok 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.691Z] SESSION: Valid 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.691Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:59:26.692Z] API: Updated player testplayer
|
||||
[2025-08-16T10:59:26.707Z] DB: getSession - start 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.707Z] DB: getSession - ok 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.707Z] SESSION: Valid 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:59:26.707Z] DB: getSession - start 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.707Z] DB: getSession - ok 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9
|
||||
[2025-08-16T10:59:26.707Z] SESSION: Valid 31676e2f35d8d1e8f1d0723c323e93afd39286a7320483214f6d07ca909066b9 testplayer PUT /api/players/testplayer
|
||||
[2025-08-16T10:59:26.707Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.708Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:59:26.708Z] DB: updatePlayer - start testplayer
|
||||
[2025-08-16T10:59:26.708Z] DB: updatePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:59:26.708Z] DB: getPlayerByName - start testplayer
|
||||
[2025-08-16T10:59:26.708Z] DB: getPlayerByName - found testplayer
|
||||
[2025-08-16T10:59:26.708Z] API: Updated player testplayer
|
||||
[2025-08-16T10:59:26.724Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:59:26.724Z] SESSION: GM bypass accepted DELETE /api/players/testplayer
|
||||
[2025-08-16T10:59:26.724Z] DB: deletePlayer - start testplayer
|
||||
[2025-08-16T10:59:26.725Z] DB: deletePlayer - changes 1 testplayer
|
||||
[2025-08-16T10:59:26.725Z] API: Deleted player testplayer
|
||||
[2025-08-16T10:59:27.107Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:59:27.107Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:59:27.107Z] DB: deletePlayer - start shoptestplayer
|
||||
[2025-08-16T10:59:27.107Z] DB: deletePlayer - changes 0 shoptestplayer
|
||||
[2025-08-16T10:59:27.121Z] SESSION: GM bypass accepted POST /api/players
|
||||
[2025-08-16T10:59:27.121Z] DB: getPlayerByName - start shoptestplayer
|
||||
[2025-08-16T10:59:27.121Z] DB: getPlayerByName - not found shoptestplayer
|
||||
[2025-08-16T10:59:27.201Z] DB: createPlayer - start shoptestplayer
|
||||
[2025-08-16T10:59:27.201Z] DB: createPlayer - done shoptestplayer rowid 92
|
||||
[2025-08-16T10:59:27.201Z] API: Created player shoptestplayer
|
||||
[2025-08-16T10:59:27.214Z] SESSION: Missing sessionId GET /api/shop/inventory/shoptestplayer
|
||||
[2025-08-16T10:59:27.227Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:59:27.227Z] SESSION: GM bypass accepted DELETE /api/players/shoptestplayer
|
||||
[2025-08-16T10:59:27.227Z] DB: deletePlayer - start shoptestplayer
|
||||
[2025-08-16T10:59:27.227Z] DB: deletePlayer - changes 1 shoptestplayer
|
||||
[2025-08-16T10:59:27.227Z] API: Deleted player shoptestplayer
|
||||
[2025-08-16T10:59:27.726Z] DB: getAllPlayers - start
|
||||
[2025-08-16T10:59:27.728Z] DB: getAllPlayers - resultCount 7
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// One-time script to fix player passwords at the top level
|
||||
const mongoose = require('mongoose');
|
||||
const Player = require('./playerModel');
|
||||
|
||||
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/deathwatch';
|
||||
|
||||
async function fixPasswords() {
|
||||
await mongoose.connect(MONGO_URI);
|
||||
const players = await Player.find();
|
||||
for (const player of players) {
|
||||
let pw = player.pw;
|
||||
let pwHash = player.pwHash;
|
||||
// Try to extract from tabInfo if not set at top level
|
||||
if ((!pw || pw === '') && player.tabInfo && player.tabInfo.pw) pw = player.tabInfo.pw;
|
||||
if ((!pwHash || pwHash === '') && player.tabInfo && player.tabInfo.pwHash) pwHash = player.tabInfo.pwHash;
|
||||
// Try to extract from tabInfo.tabInfo (legacy nesting)
|
||||
if ((!pw || pw === '') && player.tabInfo && player.tabInfo.tabInfo && player.tabInfo.tabInfo.pw) pw = player.tabInfo.tabInfo.pw;
|
||||
if ((!pwHash || pwHash === '') && player.tabInfo && player.tabInfo.tabInfo && player.tabInfo.tabInfo.pwHash) pwHash = player.tabInfo.tabInfo.pwHash;
|
||||
// Only update if needed
|
||||
if (pw && pwHash && (player.pw !== pw || player.pwHash !== pwHash)) {
|
||||
player.pw = pw;
|
||||
player.pwHash = pwHash;
|
||||
await player.save();
|
||||
console.log(`Updated ${player.name}: pw=${pw}, pwHash=${pwHash}`);
|
||||
}
|
||||
}
|
||||
await mongoose.disconnect();
|
||||
console.log('Done.');
|
||||
}
|
||||
|
||||
fixPasswords().catch(e => { console.error(e); process.exit(1); });
|
||||
@@ -1,19 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const gmSessionSchema = new mongoose.Schema({
|
||||
sessionId: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('GMSession', gmSessionSchema);
|
||||
@@ -1,166 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Player = require('./playerModel');
|
||||
const { playerHelpers, sessionHelpers } = require('./sqlite-db');
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/deathwatch';
|
||||
|
||||
async function migratePlayers() {
|
||||
try {
|
||||
// Connect to MongoDB
|
||||
console.log('Connecting to MongoDB...');
|
||||
await mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
|
||||
console.log('Connected to MongoDB');
|
||||
|
||||
// Fetch all players from MongoDB
|
||||
console.log('Fetching players from MongoDB...');
|
||||
const mongoPlayers = await Player.find();
|
||||
console.log(`Found ${mongoPlayers.length} players in MongoDB`);
|
||||
|
||||
// Migrate each player to SQLite
|
||||
let migratedCount = 0;
|
||||
let skippedCount = 0;
|
||||
|
||||
for (const mongoPlayer of mongoPlayers) {
|
||||
try {
|
||||
// Check if player already exists in SQLite
|
||||
const existingPlayer = playerHelpers.getByName(mongoPlayer.name);
|
||||
|
||||
if (existingPlayer) {
|
||||
console.log(`Player ${mongoPlayer.name} already exists in SQLite, updating...`);
|
||||
const updated = playerHelpers.update(mongoPlayer.name, {
|
||||
rollerInfo: mongoPlayer.rollerInfo || {},
|
||||
shopInfo: mongoPlayer.shopInfo || {},
|
||||
tabInfo: mongoPlayer.tabInfo || {},
|
||||
pw: mongoPlayer.pw || '',
|
||||
pwHash: mongoPlayer.pwHash || ''
|
||||
});
|
||||
|
||||
if (updated) {
|
||||
console.log(`✓ Updated player: ${mongoPlayer.name}`);
|
||||
migratedCount++;
|
||||
} else {
|
||||
console.log(`⚠ Failed to update player: ${mongoPlayer.name}`);
|
||||
skippedCount++;
|
||||
}
|
||||
} else {
|
||||
// Create new player in SQLite
|
||||
const newPlayer = playerHelpers.create({
|
||||
name: mongoPlayer.name,
|
||||
rollerInfo: mongoPlayer.rollerInfo || {},
|
||||
shopInfo: mongoPlayer.shopInfo || {},
|
||||
tabInfo: mongoPlayer.tabInfo || {},
|
||||
pw: mongoPlayer.pw || '',
|
||||
pwHash: mongoPlayer.pwHash || ''
|
||||
});
|
||||
|
||||
console.log(`✓ Migrated player: ${mongoPlayer.name}`);
|
||||
migratedCount++;
|
||||
}
|
||||
|
||||
// Log the data being migrated
|
||||
console.log(` - Roller info: ${Object.keys(mongoPlayer.rollerInfo || {}).length} keys`);
|
||||
console.log(` - Shop info: ${Object.keys(mongoPlayer.shopInfo || {}).length} keys`);
|
||||
console.log(` - Tab info: ${Object.keys(mongoPlayer.tabInfo || {}).length} keys`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error migrating player ${mongoPlayer.name}:`, error);
|
||||
skippedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n=== Migration Summary ===');
|
||||
console.log(`Total players in MongoDB: ${mongoPlayers.length}`);
|
||||
console.log(`Successfully migrated/updated: ${migratedCount}`);
|
||||
console.log(`Skipped/failed: ${skippedCount}`);
|
||||
|
||||
// Verify the migration
|
||||
console.log('\n=== Verification ===');
|
||||
const sqlitePlayers = playerHelpers.getAll();
|
||||
console.log(`Total players in SQLite: ${sqlitePlayers.length}`);
|
||||
|
||||
// Show sample data
|
||||
if (sqlitePlayers.length > 0) {
|
||||
console.log('\nSample migrated player:');
|
||||
const sample = sqlitePlayers[0];
|
||||
console.log(`Name: ${sample.name}`);
|
||||
console.log(`Roller info keys: ${Object.keys(sample.rollerInfo).length}`);
|
||||
console.log(`Shop info keys: ${Object.keys(sample.shopInfo).length}`);
|
||||
console.log(`Tab info keys: ${Object.keys(sample.tabInfo).length}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Migration failed:', error);
|
||||
} finally {
|
||||
// Close connections
|
||||
await mongoose.disconnect();
|
||||
console.log('Disconnected from MongoDB');
|
||||
}
|
||||
}
|
||||
|
||||
// Export player data to JSON for backup
|
||||
async function exportToJson() {
|
||||
try {
|
||||
console.log('Exporting MongoDB data to JSON backup...');
|
||||
|
||||
// Connect to MongoDB
|
||||
await mongoose.connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
|
||||
|
||||
// Fetch all players
|
||||
const players = await Player.find();
|
||||
|
||||
// Create backup object
|
||||
const backup = {
|
||||
exportDate: new Date().toISOString(),
|
||||
playerCount: players.length,
|
||||
players: players.map(player => ({
|
||||
name: player.name,
|
||||
rollerInfo: player.rollerInfo || {},
|
||||
shopInfo: player.shopInfo || {},
|
||||
tabInfo: player.tabInfo || {},
|
||||
pw: player.pw || '',
|
||||
pwHash: player.pwHash || '',
|
||||
mongoId: player._id.toString()
|
||||
}))
|
||||
};
|
||||
|
||||
// Write to file
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const backupPath = path.join(__dirname, 'mongo-backup.json');
|
||||
|
||||
fs.writeFileSync(backupPath, JSON.stringify(backup, null, 2));
|
||||
console.log(`✓ Backup saved to: ${backupPath}`);
|
||||
console.log(`✓ Exported ${players.length} players`);
|
||||
|
||||
await mongoose.disconnect();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Export failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Main function
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.includes('--export-only')) {
|
||||
await exportToJson();
|
||||
} else if (args.includes('--migrate-only')) {
|
||||
await migratePlayers();
|
||||
} else {
|
||||
// Do both
|
||||
await exportToJson();
|
||||
await migratePlayers();
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { migratePlayers, exportToJson };
|
||||
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"exportDate": "2025-08-15T07:12:29.894Z",
|
||||
"playerCount": 3,
|
||||
"players": [
|
||||
{
|
||||
"name": "christoffer",
|
||||
"rollerInfo": {},
|
||||
"shopInfo": {},
|
||||
"tabInfo": {
|
||||
"rp": 10,
|
||||
"inventory": [],
|
||||
"renown": "None"
|
||||
},
|
||||
"pw": "1234",
|
||||
"pwHash": "1234",
|
||||
"mongoId": "689e8ba7f8623eb2e1049cea"
|
||||
},
|
||||
{
|
||||
"name": "claes",
|
||||
"rollerInfo": {},
|
||||
"shopInfo": {},
|
||||
"tabInfo": {
|
||||
"rp": 10,
|
||||
"inventory": [],
|
||||
"renown": "None"
|
||||
},
|
||||
"pw": "1234",
|
||||
"pwHash": "1234",
|
||||
"mongoId": "689e8ba8f8623eb2e1049cec"
|
||||
},
|
||||
{
|
||||
"name": "phillip",
|
||||
"rollerInfo": {},
|
||||
"shopInfo": {},
|
||||
"tabInfo": {
|
||||
"rp": 10,
|
||||
"inventory": [],
|
||||
"renown": "None"
|
||||
},
|
||||
"pw": "1234",
|
||||
"pwHash": "1234",
|
||||
"mongoId": "689e8ba9f8623eb2e1049cee"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const playerSchema = new mongoose.Schema({
|
||||
name: { type: String, required: true },
|
||||
rollerInfo: { type: Object, default: {} },
|
||||
shopInfo: { type: Object, default: {} },
|
||||
tabInfo: { type: Object, default: {} },
|
||||
pw: { type: String, default: '' },
|
||||
pwHash: { type: String, default: '' },
|
||||
});
|
||||
|
||||
const Player = mongoose.model('Player', playerSchema);
|
||||
|
||||
module.exports = Player;
|
||||
28
database/scripts/pm2_smoke_test.sh
Normal file
28
database/scripts/pm2_smoke_test.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# Start pm2 using the repo pm2.config.js, wait until server is responsive, then stop pm2.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
# start pm2 using npm script (if available) or call pm2 directly
|
||||
if command -v npm >/dev/null 2>&1; then
|
||||
npm run pm2:start || true
|
||||
else
|
||||
pm2 start pm2.config.js --env production --update-env || true
|
||||
fi
|
||||
# wait for server
|
||||
for i in {1..15}; do
|
||||
if curl -sSf http://localhost:5000/ >/dev/null 2>&1; then
|
||||
echo "server up"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# basic health endpoints
|
||||
curl -sSf http://localhost:5000/api/players || true
|
||||
curl -sSf http://localhost:5000/api/shop/items || true
|
||||
# stop pm2 process
|
||||
if command -v npm >/dev/null 2>&1; then
|
||||
npm run pm2:stop || true
|
||||
else
|
||||
pm2 stop deathwatch-server || true
|
||||
fi
|
||||
exit 0
|
||||
@@ -1,75 +0,0 @@
|
||||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
const playerRoutes = require('./routes/playerRoutes-sqlite');
|
||||
const sessionRoutes = require('./routes/sessionRoutes-sqlite');
|
||||
const shopRoutes = require('./routes/shopRoutes');
|
||||
const rulesRoutes = require('./routes/rulesRoutes');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 5000;
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
|
||||
// Serve static files from the React app build directory
|
||||
app.use(express.static(path.join(__dirname, '../build')));
|
||||
|
||||
// Initialize SQLite database
|
||||
const { db } = require('./sqlite-db');
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', () => {
|
||||
console.log('Closing SQLite database...');
|
||||
db.close();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('Closing SQLite database...');
|
||||
db.close();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Root route for friendly message
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Deathwatch Roller API is running with SQLite. Use /api/players for player data.');
|
||||
});
|
||||
|
||||
// Health endpoint checks DB connectivity and players
|
||||
app.get('/api/health', (req, res) => {
|
||||
try {
|
||||
const { playerHelpers } = require('./sqlite-db');
|
||||
const players = playerHelpers.getAll();
|
||||
res.json({ ok: true, players: players.length, sample: players.slice(0,5).map(p=>p.name) });
|
||||
} catch (err) {
|
||||
console.error('Healthcheck error', err);
|
||||
res.status(500).json({ ok: false, error: err && err.message ? err.message : String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
// Use routes
|
||||
app.use('/api/players', playerRoutes);
|
||||
app.use('/api/sessions', sessionRoutes);
|
||||
app.use('/api/shop', shopRoutes);
|
||||
app.use('/api/rules', rulesRoutes);
|
||||
|
||||
// Catch all handler: send back React's index.html file for any non-API routes
|
||||
app.get(/^(?!\/api).*/, (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../build/index.html'));
|
||||
});
|
||||
|
||||
// Start Server
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`Server running on http://0.0.0.0:${PORT}`);
|
||||
console.log('Using SQLite database');
|
||||
});
|
||||
|
||||
// Keep the process alive reliably under systemd (avoid accidental exit)
|
||||
if (process.stdin && typeof process.stdin.resume === 'function') {
|
||||
process.stdin.resume();
|
||||
}
|
||||
|
||||
module.exports = app;
|
||||
Binary file not shown.
Binary file not shown.
182
package-lock.json
generated
182
package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"better-sqlite3": "^12.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0",
|
||||
"mongoose": "^8.17.1",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdfjs-dist": "^4.8.69",
|
||||
"react": "^18.2.0",
|
||||
@@ -4149,14 +4148,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@mongodb-js/saslprep": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz",
|
||||
"integrity": "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ==",
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/canvas": {
|
||||
"version": "0.1.77",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.77.tgz",
|
||||
@@ -5485,19 +5476,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
@@ -7245,14 +7223,6 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "6.10.4",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
|
||||
"integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
@@ -15935,14 +15905,6 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kareem": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@@ -16408,11 +16370,6 @@
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||
@@ -16800,131 +16757,6 @@
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
},
|
||||
"node_modules/mongodb": {
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz",
|
||||
"integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==",
|
||||
"dependencies": {
|
||||
"@mongodb-js/saslprep": "^1.1.9",
|
||||
"bson": "^6.10.4",
|
||||
"mongodb-connection-string-url": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.188.0",
|
||||
"@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
|
||||
"gcp-metadata": "^5.2.0",
|
||||
"kerberos": "^2.0.1",
|
||||
"mongodb-client-encryption": ">=6.0.0 <7",
|
||||
"snappy": "^7.2.2",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/credential-providers": {
|
||||
"optional": true
|
||||
},
|
||||
"@mongodb-js/zstd": {
|
||||
"optional": true
|
||||
},
|
||||
"gcp-metadata": {
|
||||
"optional": true
|
||||
},
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
},
|
||||
"socks": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
|
||||
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^14.1.0 || ^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url/node_modules/tr46": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url/node_modules/whatwg-url": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||
"dependencies": {
|
||||
"tr46": "^5.1.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.17.1.tgz",
|
||||
"integrity": "sha512-aodS4cacux5caoxB5ErEwRmrafIUsVRJxHnvP7URnSUnTenr32j1qBVV+KjYxryyLSisQkxglAFF69TNLeZTLg==",
|
||||
"dependencies": {
|
||||
"bson": "^6.10.4",
|
||||
"kareem": "2.6.3",
|
||||
"mongodb": "~6.18.0",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "5.0.0",
|
||||
"ms": "2.1.3",
|
||||
"sift": "17.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mongoose"
|
||||
}
|
||||
},
|
||||
"node_modules/mpath": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mquery": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||
"dependencies": {
|
||||
"debug": "4.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -19986,6 +19818,7 @@
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -21935,11 +21768,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sift": {
|
||||
"version": "17.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
|
||||
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
@@ -22133,14 +21961,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sparse-bitfield": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/spdy": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
|
||||
|
||||
13
package.json
13
package.json
@@ -10,7 +10,6 @@
|
||||
"better-sqlite3": "^12.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0",
|
||||
"mongoose": "^8.17.1",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdfjs-dist": "^4.8.69",
|
||||
"react": "^18.2.0",
|
||||
@@ -28,11 +27,12 @@
|
||||
"extract:armoury": "node scripts/extract-armoury.js \"$PWD/Deathwatch-Core-Rulebook.pdf\" public/deathwatch-armoury.json",
|
||||
"server": "npm test && cd database && node server.js",
|
||||
"server:notest": "cd database && node server.js",
|
||||
"db:migrate": "cd database && node migrate-to-sqlite.js",
|
||||
"db:export": "cd database && node migrate-to-sqlite.js --export-only",
|
||||
"db:sqlite": "cd database && ./switch-db.sh sqlite",
|
||||
"prestart": "",
|
||||
"preserver": ""
|
||||
"pm2:start": "cd database && pm2 start pm2.config.js --env production --update-env",
|
||||
"pm2:stop": "pm2 stop deathwatch-server || true",
|
||||
"pm2:reload": "cd database && pm2 reload pm2.config.js --env production --update-env",
|
||||
"prestart": "",
|
||||
"preserver": ""
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
@@ -66,6 +66,7 @@
|
||||
"prettier-eslint": "^16.4.2",
|
||||
"react-scripts": "^5.0.1",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"webpack-dev-server": "^5.2.2"
|
||||
"webpack-dev-server": "^5.2.2",
|
||||
"pm2": "^5.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Player = require('../database/playerModel');
|
||||
const GMSession = require('../database/gmSessionModel');
|
||||
|
||||
async function setupDatabase() {
|
||||
try {
|
||||
console.log('Connecting to MongoDB...');
|
||||
await mongoose.connect('mongodb://localhost:27017/deathwatch', {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
});
|
||||
console.log('Connected to MongoDB.');
|
||||
|
||||
console.log('Initializing collections...');
|
||||
|
||||
// Initialize Players collection
|
||||
const samplePlayers = [
|
||||
{ name: 'Player1', rollerInfo: {}, shopInfo: {}, tabInfo: {} },
|
||||
{ name: 'Player2', rollerInfo: {}, shopInfo: {}, tabInfo: {} },
|
||||
];
|
||||
await Player.insertMany(samplePlayers);
|
||||
console.log('Players collection initialized.');
|
||||
|
||||
// Initialize GM Sessions collection
|
||||
const sampleSessions = [
|
||||
{ sessionId: 'session1', isActive: true },
|
||||
{ sessionId: 'session2', isActive: false },
|
||||
];
|
||||
await GMSession.insertMany(sampleSessions);
|
||||
console.log('GM Sessions collection initialized.');
|
||||
|
||||
console.log('Database setup completed successfully.');
|
||||
} catch (error) {
|
||||
console.error('Error during database setup:', error.message);
|
||||
} finally {
|
||||
mongoose.connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
setupDatabase();
|
||||
@@ -1,26 +0,0 @@
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
function installMongoDB() {
|
||||
try {
|
||||
console.log('Installing gnupg and curl...');
|
||||
execSync('sudo apt-get install -y gnupg curl', { stdio: 'inherit' });
|
||||
|
||||
console.log('Importing MongoDB public GPG key...');
|
||||
execSync('curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor', { stdio: 'inherit' });
|
||||
|
||||
console.log('Creating MongoDB list file...');
|
||||
execSync('echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list', { stdio: 'inherit' });
|
||||
|
||||
console.log('Reloading package database...');
|
||||
execSync('sudo apt-get update', { stdio: 'inherit' });
|
||||
|
||||
console.log('Installing MongoDB Community Server...');
|
||||
execSync('sudo apt-get install -y mongodb-org', { stdio: 'inherit' });
|
||||
|
||||
console.log('MongoDB installation completed successfully.');
|
||||
} catch (error) {
|
||||
console.error('Error during MongoDB installation:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
installMongoDB();
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useState, useEffect, useMemo, useCallback } from 'react';
|
||||
import axios from 'axios';
|
||||
import logger, { debug, info, warn, logApiCall, logApiError, logUserAction } from '../utils/logger';
|
||||
|
||||
@@ -432,13 +432,9 @@ function PlayerTab({
|
||||
// Define shopAuthed for use in the component
|
||||
const shopAuthed = getShopAuthed();
|
||||
|
||||
function isGMOrShopAuthed() {
|
||||
return isGMLoggedIn() || authedPlayer;
|
||||
}
|
||||
|
||||
function isGMLoggedIn() {
|
||||
return authedPlayer === 'gm';
|
||||
}
|
||||
// Stable callbacks so hooks depending on them don't change each render
|
||||
const isGMLoggedIn = useCallback(() => authedPlayer === 'gm', [authedPlayer]);
|
||||
const isGMOrShopAuthed = useCallback(() => isGMLoggedIn() || !!authedPlayer, [isGMLoggedIn, authedPlayer]);
|
||||
|
||||
// GM session is now managed in App.js
|
||||
|
||||
|
||||
43
tests/rules.test.js
Normal file
43
tests/rules.test.js
Normal file
@@ -0,0 +1,43 @@
|
||||
jest.setTimeout(20000);
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
describe('Rules endpoints', () => {
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
const command = `curl -s -X ${method} ${headers} -H "Content-Type: application/json" ${data ? `-d '${JSON.stringify(data)}'` : ''} ${url}`;
|
||||
try {
|
||||
const result = execSync(command, { encoding: 'utf-8' });
|
||||
return JSON.parse(result || '{}');
|
||||
} catch (error) {
|
||||
if (error.stdout) {
|
||||
try { return JSON.parse(error.stdout); } catch (e) { /* ignore */ }
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
test('categories, search, random and stats endpoints respond', () => {
|
||||
const cats = curl('GET', `${baseURL}/api/rules/categories`);
|
||||
expect(Array.isArray(cats)).toBe(true);
|
||||
|
||||
const search = curl('GET', `${baseURL}/api/rules/search?q=test`);
|
||||
expect(Array.isArray(search)).toBe(true);
|
||||
|
||||
const randomRes = curl('GET', `${baseURL}/api/rules/random`);
|
||||
expect(Array.isArray(randomRes)).toBe(true);
|
||||
|
||||
const stats = curl('GET', `${baseURL}/api/rules/stats`);
|
||||
expect(stats && typeof stats.totalRules === 'number').toBe(true);
|
||||
|
||||
// Try reload without proper GM secret should fail
|
||||
const reloadFail = curl('POST', `${baseURL}/api/rules/reload`);
|
||||
expect(reloadFail && reloadFail.error).toBeTruthy();
|
||||
|
||||
// Reload with GM secret
|
||||
const reloadOk = curl('POST', `${baseURL}/api/rules/reload`, null, gmHeaders);
|
||||
expect(reloadOk && typeof reloadOk.success === 'boolean').toBe(true);
|
||||
});
|
||||
});
|
||||
42
tests/shop.test.js
Normal file
42
tests/shop.test.js
Normal file
@@ -0,0 +1,42 @@
|
||||
jest.setTimeout(20000);
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
describe('Shop endpoints (public and protected)', () => {
|
||||
const baseURL = process.env.API_BASE || 'http://localhost:5000';
|
||||
const gmHeaders = `-H "x-gm-secret: ${process.env.GM_PASSWORD || 'bongo'}"`;
|
||||
const mockPlayer = 'shoptestplayer';
|
||||
|
||||
const curl = (method, url, data = null, headers = '') => {
|
||||
const command = `curl -s -X ${method} ${headers} -H "Content-Type: application/json" ${data ? `-d '${JSON.stringify(data)}'` : ''} ${url}`;
|
||||
try {
|
||||
const result = execSync(command, { encoding: 'utf-8' });
|
||||
return JSON.parse(result || '{}');
|
||||
} catch (error) {
|
||||
if (error.stdout) {
|
||||
try { return JSON.parse(error.stdout); } catch (e) { /* ignore */ }
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
test('public items endpoints work and protected inventory requires auth', () => {
|
||||
const items = curl('GET', `${baseURL}/api/shop/items`);
|
||||
expect(Array.isArray(items)).toBe(true);
|
||||
|
||||
const category = curl('GET', `${baseURL}/api/shop/items/category/Gear`);
|
||||
expect(Array.isArray(category)).toBe(true);
|
||||
|
||||
// create player to ensure inventory exists
|
||||
try { curl('DELETE', `${baseURL}/api/players/${mockPlayer}`, null, gmHeaders); } catch (e) {}
|
||||
const created = curl('POST', `${baseURL}/api/players`, { name: mockPlayer, rp: 20, pw: 'pw' }, gmHeaders);
|
||||
expect(created.name).toBe(mockPlayer);
|
||||
|
||||
// Inventory without session should be protected (requireSession returns 403 or similar)
|
||||
const invNoAuth = curl('GET', `${baseURL}/api/shop/inventory/${mockPlayer}`);
|
||||
// invNoAuth should be an error object or not an array
|
||||
expect(Array.isArray(invNoAuth)).toBe(false);
|
||||
|
||||
// cleanup
|
||||
curl('DELETE', `${baseURL}/api/players/${mockPlayer}`, null, gmHeaders);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user