Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ build
dist
storybook-static
.yarn
apps/ligretto-core-backend-v2/global.d.ts
apps/ligretto-core-backend-v2/types
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ yarn-error.log*
*.log

.idea
.vscode

# vk-redirect-page
.cache
Expand All @@ -56,3 +57,9 @@ tsconfig.tsbuildinfo

# contentlayer
.contentlayer

# ctags
tags

# clinicjs
.clinic/
13 changes: 12 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,16 @@
"gitlens.advanced.blame.customArguments": [],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
},
"sqltools.connections": [
{
"previewLimit": 50,
"server": "localhost",
"port": 5433,
"driver": "PostgreSQL",
"name": "ligretto",
"database": "ligretto-core",
"username": "ligretto-core-user"
}
]
}
11 changes: 11 additions & 0 deletions apps/ligretto-core-backend-v2/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PLT_SERVER_HOSTNAME=127.0.0.1
PORT=4200
PLT_SERVER_LOGGER_LEVEL=debug
DATABASE_URL=postgres://ligretto-core-user:ligretto_pg_password@127.0.0.1:5433/ligretto-core
PLT_CAS_PARTNER_ID=5ff335e1845b30001086b643
PLT_CAS_PUBLIC_KEY_PATH=../../key.pem
PLT_CAS_URI=https://cas.mems.fun/api

# Set to false to disable automatic typescript compilation.
# Changing this setting is needed for production
PLT_TYPESCRIPT=true
8 changes: 8 additions & 0 deletions apps/ligretto-core-backend-v2/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
PLT_SERVER_HOSTNAME=127.0.0.1
PORT=4200
PLT_SERVER_LOGGER_LEVEL=info
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres

# Set to false to disable automatic typescript compilation.
# Changing this setting is needed for production
PLT_TYPESCRIPT=true
38 changes: 38 additions & 0 deletions apps/ligretto-core-backend-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Platformatic DB API

This is a generated [Platformatic DB](https://docs.platformatic.dev/docs/reference/db/introduction) application.

## Requirements

Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0

## Setup

1. Install dependencies:

```bash
npm install
```

2. Apply migrations:

```bash
npm run migrate
```


## Usage

Run the API with:

```bash
npm start
```

### Explore
- ⚡ The Platformatic DB server is running at http://localhost:3042/
- 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
- 🔍 Try out the GraphiQL web UI at http://localhost:3042/graphiql


41 changes: 41 additions & 0 deletions apps/ligretto-core-backend-v2/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { PlatformaticApp, PlatformaticDBMixin, PlatformaticDBConfig, Entity, Entities, EntityHooks } from '@platformatic/db'
import { EntityTypes, AdonisSchema,Game,Round,RoundUser,User } from './types'

declare module 'fastify' {
interface FastifyInstance {
getSchema<T extends 'AdonisSchema' | 'Game' | 'Round' | 'RoundUser' | 'User'>(schemaId: T): {
'$id': string,
title: string,
description: string,
type: string,
properties: {
[x in keyof EntityTypes[T]]: { type: string, nullable?: boolean }
},
required: string[]
};
}
}

interface AppEntities extends Entities {
adonisSchema: Entity<AdonisSchema>,
game: Entity<Game>,
round: Entity<Round>,
roundUser: Entity<RoundUser>,
user: Entity<User>,
}

interface AppEntityHooks {
addEntityHooks(entityName: 'adonisSchema', hooks: EntityHooks<AdonisSchema>): any
addEntityHooks(entityName: 'game', hooks: EntityHooks<Game>): any
addEntityHooks(entityName: 'round', hooks: EntityHooks<Round>): any
addEntityHooks(entityName: 'roundUser', hooks: EntityHooks<RoundUser>): any
addEntityHooks(entityName: 'user', hooks: EntityHooks<User>): any
}

declare module 'fastify' {
interface FastifyInstance {
platformatic: PlatformaticApp<PlatformaticDBConfig> &
PlatformaticDBMixin<AppEntities> &
AppEntityHooks
}
}
46 changes: 46 additions & 0 deletions apps/ligretto-core-backend-v2/migrations/001.do.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
CREATE TABLE IF NOT EXISTS games (
id uuid NOT NULL PRIMARY KEY,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone
);

CREATE TABLE IF NOT EXISTS round_users (
id integer NOT NULL PRIMARY KEY,
"roundId" uuid,
"userId" character varying(255),
score integer,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone
);


CREATE TABLE IF NOT EXISTS rounds (
id uuid NOT NULL PRIMARY KEY,
"gameId" uuid,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone
);

CREATE TABLE IF NOT EXISTS users (
created_at timestamp with time zone,
updated_at timestamp with time zone,
"casId" character varying(255) NOT NULL PRIMARY KEY,
"isTemporary" boolean
);

ALTER TABLE ONLY round_users
DROP CONSTRAINT round_users_roundid_userid_unique,
ADD CONSTRAINT round_users_roundid_userid_unique UNIQUE ("roundId", "userId");

ALTER TABLE ONLY round_users
DROP CONSTRAINT round_users_roundid_foreign,
ADD CONSTRAINT round_users_roundid_foreign FOREIGN KEY ("roundId") REFERENCES rounds(id);

ALTER TABLE ONLY round_users
DROP CONSTRAINT round_users_userid_foreign,
ADD CONSTRAINT round_users_userid_foreign FOREIGN KEY ("userId") REFERENCES users("casId");

ALTER TABLE ONLY rounds
DROP CONSTRAINT rounds_gameid_foreign,
ADD CONSTRAINT rounds_gameid_foreign FOREIGN KEY ("gameId") REFERENCES games(id) ON DELETE CASCADE;

4 changes: 4 additions & 0 deletions apps/ligretto-core-backend-v2/migrations/001.undo.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DROP TABLE round_users;
DROP TABLE rounds;
DROP TABLE users;
DROP TABLE games;
29 changes: 29 additions & 0 deletions apps/ligretto-core-backend-v2/migrations/002.do.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

ALTER TABLE ONLY games
ALTER COLUMN id SET DEFAULT uuid_generate_v4(),
ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP,
ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP;

ALTER TABLE ONLY rounds
ALTER COLUMN id SET DEFAULT uuid_generate_v4(),
ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP,
ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP;

CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW."updatedAt" := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER rounds_update_updated_at_trigger
BEFORE UPDATE ON rounds
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();

CREATE TRIGGER games_update_updated_at_trigger
BEFORE UPDATE ON games
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
21 changes: 21 additions & 0 deletions apps/ligretto-core-backend-v2/migrations/002.undo.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Drop triggers
DROP TRIGGER IF EXISTS rounds_update_updated_at_trigger ON rounds;
DROP TRIGGER IF EXISTS games_update_updated_at_trigger ON games;

-- Drop trigger function
DROP FUNCTION IF EXISTS update_updated_at() CASCADE;

-- Alter rounds table
ALTER TABLE ONLY rounds
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN "createdAt" DROP DEFAULT,
ALTER COLUMN "updatedAt" DROP DEFAULT;

-- Alter games table
ALTER TABLE ONLY games
ALTER COLUMN id DROP DEFAULT,
ALTER COLUMN "createdAt" DROP DEFAULT,
ALTER COLUMN "updatedAt" DROP DEFAULT;

-- Drop uuid-ossp extension
DROP EXTENSION IF EXISTS "uuid-ossp";
23 changes: 23 additions & 0 deletions apps/ligretto-core-backend-v2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"scripts": {
"start": "platformatic start",
"clean": "rm -fr ./dist",
"build": "platformatic compile",
"migrate": "platformatic db migrations apply",
"test": "tsc && node --test dist/test/*/*.test.js"
},
"devDependencies": {
"fastify": "^4.23.2",
"typescript": "^5.0.4"
},
"dependencies": {
"@fastify/type-provider-typebox": "^3.5.0",
"@memebattle/cas-services": "^3.6.5",
"@platformatic/db": "^1.0.0",
"@sinclair/typebox": "^0.31.17",
"platformatic": "^1.0.0"
},
"engines": {
"node": "^18.8.0 || >=20.6.0"
}
}
52 changes: 52 additions & 0 deletions apps/ligretto-core-backend-v2/platformatic.db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"$schema": "https://platformatic.dev/schemas/v1.0.0/db",
"server": {
"hostname": "{PLT_SERVER_HOSTNAME}",
"port": "{PORT}",
"logger": {
"level": "{PLT_SERVER_LOGGER_LEVEL}"
},
"healthCheck": {
"exposeStatusRoute": {
"url": "/health"
}
}
},
"db": {
"connectionString": "{DATABASE_URL}",
"graphql": true,
"openapi": {
"prefix": "/api"
},
"schemalock": true
},
"watch": {
"ignore": [
"*.sqlite",
"*.sqlite-journal"
]
},
"plugins": {
"paths": [
{
"path": "./plugins",
"options": {
"partnerId": "{PLT_CAS_PARTNER_ID}",
"casURI": "{PLT_CAS_URI}",
"publicKeyPath": "{PLT_CAS_PUBLIC_KEY_PATH}"
},
"encapsulate": false
},
{
"path": "./routes"
}
],
"typescript": "{PLT_TYPESCRIPT}"
},
"migrations": {
"dir": "migrations"
},
"types": {
"autogenerate": true
}
}
69 changes: 69 additions & 0 deletions apps/ligretto-core-backend-v2/plugins/cas-services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference path="../global.d.ts" />
import type { FastifyInstance } from 'fastify'
import fs from 'fs/promises'
import { createCasServices } from '@memebattle/cas-services'

interface CasServices {
login: ReturnType<typeof createCasServices>['loginService']
signUp: ReturnType<typeof createCasServices>['signUpService']
verifyToken: ReturnType<typeof createCasServices>['verifyToken']
getMe: ReturnType<typeof createCasServices>['getMeService']
getUsers: ReturnType<typeof createCasServices>['getUsersService']
createTemporaryToken: ReturnType<typeof createCasServices>['createTemporaryTokenService']
}

declare module 'fastify' {
interface FastifyInstance {
casServices: CasServices
}
}

interface CasServicesOptions {
partnerId: string
casURI: string
publicKeyPath: string
}

export default async function (fastify: FastifyInstance, opts: CasServicesOptions) {
fastify.log.info('Registering CAS services')

const withLogger = (services: CasServices) => {
const result = {} as CasServices

for (const [key, value] of Object.entries(services)) {
result[key] = async (...args: unknown[]) => {
const start = Date.now()
const result = await value(...args)
const end = Date.now()
fastify.log.debug({ service: key, time: end - start, result })
return result
}
}

return result
}

const { partnerId, casURI, publicKeyPath } = opts
const publicKey = await fs.readFile(publicKeyPath).toString()
const services = createCasServices({ partnerId, casURI, publicKey })

const login = services.loginService
const signUp = services.signUpService
const verifyToken = services.verifyToken
const getMe = services.getMeService
const getUsers = services.getUsersService
const createTemporaryToken = services.createTemporaryTokenService

fastify.decorate(
'casServices',
withLogger({
login,
signUp,
verifyToken,
getMe,
getUsers,
createTemporaryToken,
}),
)
}
Loading