('/sessions/active', {
+ params: { questId },
+ })
+ return res.data
+}
diff --git a/app/src/utils/terminal.ts b/app/src/utils/terminal.ts
index 337047a..969c000 100644
--- a/app/src/utils/terminal.ts
+++ b/app/src/utils/terminal.ts
@@ -46,7 +46,6 @@ class SocketTerminal {
mount(reference: HTMLElement): void {
this.term.open(reference)
- this.term.focus()
this.resizeScreen()
}
diff --git a/app/src/views/GamePage.vue b/app/src/views/GamePage.vue
index 7325737..fae13bf 100644
--- a/app/src/views/GamePage.vue
+++ b/app/src/views/GamePage.vue
@@ -1,20 +1,20 @@
@@ -56,7 +44,7 @@ onMounted(async () => {
@@ -72,6 +60,7 @@ onMounted(async () => {
+
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
deleted file mode 100644
index b35aba1..0000000
--- a/docker-compose.dev.yml
+++ /dev/null
@@ -1,95 +0,0 @@
-version: '3'
-services:
- app:
- depends_on:
- - backend
- build:
- context: .
- dockerfile: app/Dockerfile
- target: dev
- ports:
- - 5173:5173
- networks:
- - internal
- volumes:
- - ./app:/app/app
- - ./packages:/app/packages
-
- backend:
- depends_on:
- - db
- build:
- context: .
- dockerfile: server/Dockerfile
- target: dev
- networks:
- - internal
- - players
- ports:
- - '3000:3000'
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- - ./server/src:/app/server/src
- - ./server/dist:/app/server/dist
- - ./server/swagger.yaml:/app/server/swagger.yaml
- - ./packages:/app/packages
- - ./quests:/app/quests
- - ./logs:/app/logs
- environment:
- - BASE_URL=http://localhost:5173
- - MONGO_URL=mongodb://db:27017/odyssey-test
- - DOCKER_NETWORK=linux-odyssey-players
- - SECRET_KEY=b1d2e917-17b9-4fce-9055-082dee6ec5d6 # Only for testing
- - TRUSTED_PROXIES=${TRUSTED_PROXIES}
- - SURVEY_URL=${SURVEY_URL}
- - BUG_REPORT_URL=${BUG_REPORT_URL}
- - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
- - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
- - TESTING=true
- - TESTING_USERNAME=alex
- - TESTING_PASSWORD=Alex1234
- - HOST_PWD=${PWD}
- - MOUNT_QUEST=${MOUNT_QUEST}
-
- analytics:
- build:
- context: .
- dockerfile: packages/analytics/Dockerfile
- target: dev
- depends_on:
- - db
- networks:
- - internal
- ports:
- - '3001:3001'
- environment:
- - MONGO_URL=mongodb://db:27017/odyssey-test
- - ADMIN_USERNAME=alex
- - ADMIN_PASSWORD=Alex1234
- volumes:
- - ./packages/analytics:/app/packages/analytics
- - ./packages/models:/app/packages/models
-
- db:
- image: mongo
- restart: always
- networks:
- - internal
- ports:
- - '27017:27017'
- volumes:
- - ./data:/data/db
-
- base:
- image: linuxodyssey/quest-base
- build:
- context: .
- dockerfile: ./quests/Dockerfile
-
-networks:
- internal:
- players:
- name: linux-odyssey-players
- internal: true
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..f7065bd
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,23 @@
+version: '3'
+services:
+ db:
+ image: mongo
+ restart: always
+ networks:
+ - internal
+ ports:
+ - '27017:27017'
+ volumes:
+ - ./data:/data/db
+
+ base:
+ image: linuxodyssey/quest-base
+ build:
+ context: .
+ dockerfile: ./quests/Dockerfile
+
+networks:
+ internal:
+ players:
+ name: linux-odyssey-players
+ internal: true
diff --git a/packages/constants/index.ts b/packages/constants/index.ts
index 0ff060b..c555e8e 100644
--- a/packages/constants/index.ts
+++ b/packages/constants/index.ts
@@ -1,3 +1,5 @@
+import { z } from 'zod'
+
export const passwordPolicy = {
minLength: 8,
minNumbers: 1,
@@ -6,6 +8,11 @@ export const passwordPolicy = {
minSymbols: 0,
}
-export default {
- passwordPolicy,
-}
+export const getSessionsRequestSchema = z.object({
+ questId: z.string().optional(),
+ status: z.enum(['active', 'inactive', 'finished']).optional(),
+ limit: z.coerce.number().optional(),
+ order: z.enum(['asc', 'desc']).optional(),
+})
+
+export type GetSessionsRequest = z.infer
diff --git a/packages/constants/package.json b/packages/constants/package.json
index 39f0201..ec494fd 100644
--- a/packages/constants/package.json
+++ b/packages/constants/package.json
@@ -10,5 +10,8 @@
"scripts": {
"build": "tsc",
"dev": "tsc -w"
+ },
+ "dependencies": {
+ "zod": "^3.23.8"
}
}
diff --git a/server/src/api/controllers/sessionController.ts b/server/src/api/controllers/sessionController.ts
index 6c4f348..9829a3e 100644
--- a/server/src/api/controllers/sessionController.ts
+++ b/server/src/api/controllers/sessionController.ts
@@ -3,7 +3,6 @@ import type { Express, Request, Response } from 'express'
import { User, Session, ISession } from '@linux-odyssey/models'
import {
createNewSession,
- getOrCreateActiveSession,
isQuestUnlocked,
} from '../../models/sessionManager.js'
import { asyncHandler } from '../../middleware/error.js'
@@ -56,7 +55,6 @@ export const createSession = asyncHandler(
export const getSessionById = asyncHandler(
async (req: Request, res: Response) => {
const { sessionId } = matchedData(req)
- console.log(sessionId)
const session = await Session.findOne({
_id: sessionId,
user: (req.user as Express.ExistingUser).id,
@@ -71,7 +69,7 @@ export const getSessionById = asyncHandler(
}
)
-export const getOrCreateSession = asyncHandler(
+export const getActiveSessionHandler = asyncHandler(
async (req: Request, res: Response) => {
const { questId } = matchedData(req)
const user = await User.findById((req.user as Express.ExistingUser).id)
@@ -79,8 +77,12 @@ export const getOrCreateSession = asyncHandler(
user &&
((await isQuestUnlocked(user, questId)) || config.testing.enabled)
) {
- const session = await getOrCreateActiveSession(user, questId)
- res.json(sessionDetail(session))
+ const session = await Session.findOne({
+ user: user.id,
+ quest: questId,
+ status: 'active',
+ })
+ res.json(session ? sessionDetail(session) : null)
} else {
res.status(403).json({ message: 'Quest is locked.' })
}
diff --git a/server/src/api/routes/sessionRouter.ts b/server/src/api/routes/sessionRouter.ts
index 52e4e0c..5e24fd2 100644
--- a/server/src/api/routes/sessionRouter.ts
+++ b/server/src/api/routes/sessionRouter.ts
@@ -17,10 +17,10 @@ router.post(
sessionRateLimit,
sessionController.createSession
)
-router.post(
+router.get(
'/active',
activeSessionValidator,
- sessionController.getOrCreateSession
+ sessionController.getActiveSessionHandler
)
router.get(
'/:sessionId',
diff --git a/server/src/api/socket.ts b/server/src/api/socket.ts
index 6ff4464..5395370 100644
--- a/server/src/api/socket.ts
+++ b/server/src/api/socket.ts
@@ -8,7 +8,6 @@ import SessionMiddleware from '../middleware/session.js'
import { genJWT } from '../utils/auth.js'
import logger from '../utils/logger.js'
-// eslint-disable-next-line no-unused-vars
type SocketCallback = (event: string, ...args: any[]) => void
const sessions = new Map()
@@ -44,7 +43,6 @@ async function connectContainer(socket: Socket, next: (err?: Error) => void) {
next(new Error('User not found.'))
return
}
- // console.log(socket.handshake)
const { sessionId } = socket.handshake.query
if (
!sessionId ||
@@ -79,7 +77,7 @@ async function connectContainer(socket: Socket, next: (err?: Error) => void) {
stream,
}
next()
- } catch (err) {
+ } catch {
next(new Error('Failed to start container.'))
}
}
diff --git a/server/src/containers/docker.ts b/server/src/containers/docker.ts
index a29fd85..fdf42f5 100644
--- a/server/src/containers/docker.ts
+++ b/server/src/containers/docker.ts
@@ -82,7 +82,7 @@ export async function deleteContainer(id: string) {
}
try {
await container.stop()
- } catch (error) {
+ } catch {
logger.warn('Failed to stop container', id)
}
await container.remove()
diff --git a/server/src/game/commandHandler.ts b/server/src/game/commandHandler.ts
index 00ba2cd..e7b3dc0 100644
--- a/server/src/game/commandHandler.ts
+++ b/server/src/game/commandHandler.ts
@@ -112,7 +112,7 @@ export default class CommandHandler extends SessionHandler {
)
)
return checks.every((c) => c === true)
- } catch (e) {
+ } catch {
return false
}
}
diff --git a/server/src/models/sessionManager.ts b/server/src/models/sessionManager.ts
index d6bfa2f..798732c 100644
--- a/server/src/models/sessionManager.ts
+++ b/server/src/models/sessionManager.ts
@@ -79,21 +79,6 @@ export async function createNewSession(
return session
}
-export async function getOrCreateActiveSession(
- user: HydratedDocument,
- questId: string
-): Promise {
- const session = await Session.findOne({
- user,
- quest: questId,
- status: 'active',
- })
- if (session) {
- return session
- }
- return createNewSession(user, questId)
-}
-
export async function finishSession(
session: HydratedDocument
): Promise {
diff --git a/server/swagger.yaml b/server/swagger.yaml
index b2a0605..c5e854b 100644
--- a/server/swagger.yaml
+++ b/server/swagger.yaml
@@ -37,6 +37,19 @@ paths:
schema:
type: string
enum: [active, finished, inactive]
+ - in: query
+ name: limit
+ description: limit the number of sessions to return
+ schema:
+ type: number
+ example: 10
+ - in: query
+ name: order
+ description: order the sessions by createdAt
+ schema:
+ type: string
+ enum: [asc, desc]
+ example: desc
responses:
'200':
description: list of existing session
diff --git a/yarn.lock b/yarn.lock
index a97122d..643f242 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2479,6 +2479,11 @@
"@vue/compiler-dom" "3.4.19"
"@vue/shared" "3.4.19"
+"@vue/devtools-api@^6.5.0":
+ version "6.6.3"
+ resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.3.tgz#b23a588154cba8986bba82b6e1d0248bde3fd1a0"
+ integrity sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==
+
"@vue/devtools-api@^6.5.1":
version "6.6.1"
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.1.tgz#7c14346383751d9f6ad4bea0963245b30220ef83"
@@ -6773,6 +6778,14 @@ pify@^2.2.0, pify@^2.3.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+pinia@^2.1.7:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.1.7.tgz#4cf5420d9324ca00b7b4984d3fbf693222115bbc"
+ integrity sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==
+ dependencies:
+ "@vue/devtools-api" "^6.5.0"
+ vue-demi ">=0.14.5"
+
pirates@^4.0.1, pirates@^4.0.4:
version "4.0.6"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
@@ -8160,6 +8173,11 @@ vite@^4.5.3:
optionalDependencies:
fsevents "~2.3.2"
+vue-demi@>=0.14.5:
+ version "0.14.8"
+ resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.8.tgz#00335e9317b45e4a68d3528aaf58e0cec3d5640a"
+ integrity sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==
+
vue-eslint-parser@^9.4.2:
version "9.4.2"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz#02ffcce82042b082292f2d1672514615f0d95b6d"
@@ -8457,6 +8475,11 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+zod@^3.23.8:
+ version "3.23.8"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
+ integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==
+
zrender@5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.5.0.tgz#54d0d6c4eda81a96d9f60a9cd74dc48ea026bc1e"