Skip to content

Commit

Permalink
feat: migrated store server
Browse files Browse the repository at this point in the history
  • Loading branch information
yungblud committed Jan 14, 2024
1 parent 9428a14 commit 19554d0
Show file tree
Hide file tree
Showing 28 changed files with 627 additions and 8 deletions.
7 changes: 7 additions & 0 deletions packages/store-server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL=""
9 changes: 9 additions & 0 deletions packages/store-server/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": [
"coldsurfers", // for nodejs-typescript, or 'coldsurfers/nodejs-typescript'
"coldsurfers/react-typescript" // for react-typescript
],
"rules": {
"camelcase": "off"
}
}
11 changes: 11 additions & 0 deletions packages/store-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
# Keep environment variables out of version control
.env

src/config/config.json

Dockerfile

dist/

docker-compose.yml
6 changes: 6 additions & 0 deletions packages/store-server/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
14 changes: 14 additions & 0 deletions packages/store-server/Dockerfile.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# https://umanking.github.io/2023/08/04/mysql-dockerfile/
# Dockerfile

# MySQL 이미지를 기반으로 이미지 생성
FROM mysql:latest

# MySQL 설정
ENV MYSQL_ROOT_PASSWORD=my-secret-pw
ENV MYSQL_DATABASE=mydb
ENV MYSQL_USER=myuser
ENV MYSQL_PASSWORD=mypassword

# 포트 설정 (기본 MySQL 포트는 3306)
EXPOSE 3306
16 changes: 16 additions & 0 deletions packages/store-server/docker-compose.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# https://wecandev.tistory.com/107

version: '3'
services:
mysql:
image: mysql:8.0
container_name: mysql
ports:
- 3306:3306 # HOST:CONTAINER
environment:
MYSQL_ROOT_PASSWORD: admin
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumes:
- D:/mysql/data:/var/lib/mysql
29 changes: 29 additions & 0 deletions packages/store-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "server",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"dev": "NODE_ENV=development npx ts-node ./src/server.ts",
"start": "NODE_ENV=production node ./dist/server.js",
"build": "tsc && cp -R ./src/config ./dist/config",
"deploy": "yarn pm2 start ./src/config/ecosystem.config.js"
},
"devDependencies": {
"@types/nconf": "^0.10.6",
"@types/node": "^20",
"pm2": "^5.3.0",
"prisma": "^5.7.1",
"typescript": "^5"
},
"dependencies": {
"@fastify/autoload": "^5.8.0",
"@fastify/cors": "^8.4.2",
"@fastify/jwt": "^7.2.4",
"@prisma/client": "^5.7.1",
"fastify": "^4.24.3",
"google-auth-library": "^9.4.1",
"nconf": "^0.12.1",
"uuidv4": "^6.2.13",
"zod": "^3.22.4"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"password" VARCHAR(255),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "AuthToken" (
"id" TEXT NOT NULL,
"auth_token" TEXT NOT NULL,
"refresh_token" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "AuthToken_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

-- CreateIndex
CREATE UNIQUE INDEX "AuthToken_user_id_key" ON "AuthToken"("user_id");

-- AddForeignKey
ALTER TABLE "AuthToken" ADD CONSTRAINT "AuthToken_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
3 changes: 3 additions & 0 deletions packages/store-server/prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
28 changes: 28 additions & 0 deletions packages/store-server/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id String @id @default(uuid())
email String @unique
password String? @db.VarChar(255)
created_at DateTime @default(now())
auth_token AuthToken?
}

model AuthToken {
id String @id @default(uuid())
auth_token String @db.Text
refresh_token String @db.Text
user User @relation(fields: [user_id], references: [id])
user_id String @unique
created_at DateTime @default(now())
}
64 changes: 64 additions & 0 deletions packages/store-server/src/api/controllers/authController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { RouteHandler } from 'fastify'
import { OAuth2Client } from 'google-auth-library'
import User from '../models/User'
import AuthToken from '../models/AuthToken'

const client = new OAuth2Client()

export const socialSignInCtrl: RouteHandler<{
Body: {
social_token: string
provider: 'google'
}
}> = async (req, res) => {
const { social_token: socialToken, provider } = req.body
try {
if (provider === 'google') {
const tokenInfo = await client.getTokenInfo(socialToken)
const { email: gmail } = tokenInfo
if (!gmail) {
throw Error('cannot get gmail')
}
let user = await User.findByEmail(gmail)
if (!user) {
user = await new User({
email: gmail,
}).create()
}
const authToken = new AuthToken({
auth_token: await res.jwtSign(
{
provider,
email: user.email,
id: user.id,
},
{
expiresIn: '7d',
}
),
refresh_token: await res.jwtSign(
{
provider,
email: user.email,
id: user.id,
},
{
expiresIn: '30d',
}
),
user_id: user.id,
})
const { refresh_token, auth_token } = await authToken.create()

return res.status(200).send({
refresh_token,
auth_token,
user,
})
}
return res.status(404).send()
} catch (e) {
console.error(e)
return res.send(e)
}
}
14 changes: 14 additions & 0 deletions packages/store-server/src/api/controllers/meController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FastifyError, RouteHandler } from 'fastify'
// import { JWTDecoded } from '../../types/jwt'

export const getMeCtrl: RouteHandler<{}> = async (req, rep) => {
try {
await req.jwtVerify()
// const decoded = (await req.jwtDecode()) as JWTDecoded
// todo find user by auth token
return rep.status(501)
} catch (e) {
const error = e as FastifyError
return rep.status(error.statusCode ?? 500).send(error)
}
}
10 changes: 10 additions & 0 deletions packages/store-server/src/api/controllers/userController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { RouteHandler } from 'fastify'

export const getUserCtrl: RouteHandler<{
Params: {
userId: string
}
}> = (req, res) =>
res.status(200).send({
status: 'okay',
})
3 changes: 3 additions & 0 deletions packages/store-server/src/api/database/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { PrismaClient } from '@prisma/client'

export const prisma = new PrismaClient()
77 changes: 77 additions & 0 deletions packages/store-server/src/api/models/AuthToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { prisma } from '../database/prisma'

export type AuthTokenSerialized = {
id: string
auth_token: string
refresh_token: string
user_id: string
created_at: string
}

export default class AuthToken {
public id?: string

public auth_token!: string

public refresh_token!: string

public user_id!: string

public created_at?: Date

constructor(params: {
id?: string
auth_token: string
refresh_token: string
user_id: string
created_at?: Date
}) {
this.id = params.id
this.auth_token = params.auth_token
this.refresh_token = params.refresh_token
this.user_id = params.user_id
this.created_at = params.created_at
}

public static async getByUserId(userId: string) {
// eslint-disable-next-line no-return-await
return await prisma.authToken.findUnique({
where: {
user_id: userId,
},
})
}

public static async deleteById(id: string) {
await prisma.authToken.delete({
where: {
id,
},
})
}

public async create() {
const existing = await AuthToken.getByUserId(this.user_id)
if (existing) {
await AuthToken.deleteById(existing.id)
}
// eslint-disable-next-line no-return-await
return await prisma.authToken.create({
data: {
auth_token: this.auth_token,
refresh_token: this.refresh_token,
user_id: this.user_id,
},
})
}

public serialize(): AuthTokenSerialized {
return {
id: this.id ?? '',
auth_token: this.auth_token,
refresh_token: this.refresh_token,
user_id: this.user_id,
created_at: this.created_at?.toISOString() ?? '',
}
}
}
49 changes: 49 additions & 0 deletions packages/store-server/src/api/models/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable class-methods-use-this */
import { prisma } from '../database/prisma'

export type UserSerialized = {
id: string
email: string
created_at: string
}

export default class User {
public id?: string

public email!: string

public created_at?: Date

constructor(params: { id?: string; email: string; created_at?: Date }) {
this.id = params.id
this.email = params.email
this.created_at = params.created_at
}

public static async findByEmail(email: string) {
const user = await prisma.user.findUnique({
where: {
email,
},
})

return user
}

public async create() {
const user = await prisma.user.create({
data: {
email: this.email,
},
})
return user
}

public serialize(): UserSerialized {
return {
id: this.id ?? '',
email: this.email,
created_at: this.created_at?.toISOString() ?? '',
}
}
}
Loading

0 comments on commit 19554d0

Please sign in to comment.