diff --git a/app/src/components/AuthForm.vue b/app/src/components/AuthForm.vue index 7d05cb6..1f658af 100644 --- a/app/src/components/AuthForm.vue +++ b/app/src/components/AuthForm.vue @@ -83,6 +83,16 @@ const handleChange = () => { errorMessage.value = 'Something went wrong' } } + +const registerGuest = async () => { + try { + await api.post('/auth/register-guest') + router.push({ name: 'map' }) + } catch (err) { + console.error(err) + toast.error('Something went wrong.') + } +} diff --git a/packages/models/src/user.ts b/packages/models/src/user.ts index 8ac5bcd..5e4c63f 100644 --- a/packages/models/src/user.ts +++ b/packages/models/src/user.ts @@ -28,6 +28,7 @@ export interface IUser { socialLogins: Map createdAt: Date updatedAt: Date + isGuest: boolean } export const User = model( @@ -51,6 +52,11 @@ export const User = model( default: {}, required: true, }, + isGuest: { + type: Boolean, + default: false, + required: true, + }, }, { timestamps: true, diff --git a/server/migrations/0001-add-isGuest.ts b/server/migrations/0001-add-isGuest.ts new file mode 100644 index 0000000..20f2266 --- /dev/null +++ b/server/migrations/0001-add-isGuest.ts @@ -0,0 +1,23 @@ +import connectDB, { User } from '@linux-odyssey/models' + +async function migrate() { + await connectDB( + process.env.MONGO_URL || 'mongodb://localhost:27017/odyssey-test' + ) + await User.updateMany( + { + isGuest: { $exists: false }, + }, + { $set: { isGuest: false } } + ) +} + +migrate() + .then(() => { + console.log('Migration completed') + process.exit(0) + }) + .catch((err) => { + console.error(err) + process.exit(1) + }) diff --git a/server/package.json b/server/package.json index 4b9b48a..44b869f 100644 --- a/server/package.json +++ b/server/package.json @@ -9,7 +9,8 @@ "clean": "node dist/cli/clean.js", "build": "tsc -b", "dev": "nodemon", - "build:quests": "node dist/cli/build.js" + "build:quests": "node dist/cli/build.js", + "ts-node": "node --loader ts-node/esm" }, "dependencies": { "@linux-odyssey/constants": "*", @@ -20,6 +21,7 @@ "commander": "^11.0.0", "connect-mongo": "^5.0.0", "cookie-parser": "^1.4.6", + "date-fns": "^3.6.0", "dockerode": "^3.3.5", "dotenv": "^16.4.1", "express": "^4.19.2", diff --git a/server/src/api/controllers/authController.ts b/server/src/api/controllers/authController.ts index 258ba4f..239a6ce 100644 --- a/server/src/api/controllers/authController.ts +++ b/server/src/api/controllers/authController.ts @@ -1,7 +1,7 @@ import type { Request, Response, NextFunction, Express } from 'express' import { matchedData } from 'express-validator' import { genJWT } from '../../utils/auth.js' -import { createUser } from '../../models/userManager.js' +import { createUser, createGuestUser } from '../../models/userManager.js' import { asyncHandler } from '../../middleware/error.js' import logger from '../../utils/logger.js' @@ -39,6 +39,30 @@ export const register = asyncHandler( } ) +export const registerGuest = asyncHandler( + async (req: Request, res: Response) => { + const user = await createGuestUser() + req.login( + { + id: user.id, + username: user.username, + email: user.email, + }, + (err) => { + if (err) { + res.status(500).json({ + message: 'error logging in', + }) + return + } + res.status(201).json({ + message: 'user created', + }) + } + ) + } +) + export function logout(req: Request, res: Response) { req.logout((err) => { if (err) { diff --git a/server/src/api/routes/authRouter.ts b/server/src/api/routes/authRouter.ts index 9fabc58..318af99 100644 --- a/server/src/api/routes/authRouter.ts +++ b/server/src/api/routes/authRouter.ts @@ -9,6 +9,7 @@ import { logout, registerFromSession, socialLoginHandler, + registerGuest, } from '../controllers/authController.js' import { checkUsernameValidators, @@ -32,6 +33,8 @@ router.post( router.post('/register', authenticateRateLimit, registerValidators, register) +router.post('/register-guest', authenticateRateLimit, registerGuest) + router.post('/logout', logout) router.get( diff --git a/server/src/models/userManager.ts b/server/src/models/userManager.ts index 630ac76..06d2a52 100644 --- a/server/src/models/userManager.ts +++ b/server/src/models/userManager.ts @@ -1,4 +1,5 @@ import { Express } from 'express' +import { format } from 'date-fns' import { User, UserProfile } from '@linux-odyssey/models' import { hashPassword } from '../utils/auth.js' @@ -31,6 +32,23 @@ export async function createUser( return user } +export async function createGuestUser() { + const username = `guest_${format(new Date(), 'yyyyMMddHHmmss')}` + const user = new User({ + username, + email: `${username}@example.com`, + isGuest: true, + }) + await user.save() + + const profile = new UserProfile({ + user, + }) + await profile.save() + + return user +} + export function leaderboard() { return UserProfile.aggregate([ { diff --git a/server/swagger.yaml b/server/swagger.yaml index dfadfc2..b2a0605 100644 --- a/server/swagger.yaml +++ b/server/swagger.yaml @@ -1,14 +1,14 @@ openapi: 3.0.0 servers: - url: /api/v1 - - url: https://odyssey.wancat.cc/api/v1 + - url: https://linuxodyssey.xyz/api/v1 - url: http://localhost:3000/api/v1 info: description: Linux Odyssey API version: '1.0.0' title: Session API contact: - email: wancat@wancat.cc + email: contact@linuxodyssey.xyz license: name: Apache 2.0 url: 'http://www.apache.org/licenses/LICENSE-2.0.html' @@ -233,6 +233,22 @@ paths: type: string example: connect.sid=s%3Aq1Z; Path=/; HttpOnly; SameSite=Strict; Secure + /auth/register-guest: + post: + summary: Register a new guest user + responses: + 201: + description: User created + headers: + Set-Cookie: + schema: + type: string + example: connect.sid=s%3Aq1Z; Path=/; HttpOnly; SameSite=Strict; Secure + content: + application/json: + schema: + $ref: '#/components/schemas/User' + /auth/login: post: summary: Log in a user diff --git a/yarn.lock b/yarn.lock index a7887fb..a97122d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3594,6 +3594,11 @@ date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" +date-fns@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" + integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== + dayjs@^1.10.4: version "1.11.10" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"