migrate to blitzjs
This commit is contained in:
37
db/_encryption.ts
Normal file
37
db/_encryption.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import crypto from "crypto"
|
||||
import { getConfig } from "blitz"
|
||||
|
||||
const { serverRuntimeConfig } = getConfig()
|
||||
|
||||
const IV_LENGTH = 16
|
||||
const ALGORITHM = "aes-256-cbc"
|
||||
|
||||
export function encrypt(text: string, encryptionKey: Buffer | string) {
|
||||
const encryptionKeyAsBuffer = Buffer.isBuffer(encryptionKey)
|
||||
? encryptionKey
|
||||
: Buffer.from(encryptionKey, "hex")
|
||||
const iv = crypto.randomBytes(IV_LENGTH)
|
||||
const cipher = crypto.createCipheriv(ALGORITHM, encryptionKeyAsBuffer, iv)
|
||||
const encrypted = cipher.update(text)
|
||||
const encryptedBuffer = Buffer.concat([encrypted, cipher.final()])
|
||||
|
||||
return `${iv.toString("hex")}:${encryptedBuffer.toString("hex")}`
|
||||
}
|
||||
|
||||
export function decrypt(encryptedHexText: string, encryptionKey: Buffer | string) {
|
||||
const encryptionKeyAsBuffer = Buffer.isBuffer(encryptionKey)
|
||||
? encryptionKey
|
||||
: Buffer.from(encryptionKey, "hex")
|
||||
const [hexIv, hexText] = encryptedHexText.split(":")
|
||||
const iv = Buffer.from(hexIv!, "hex")
|
||||
const encryptedText = Buffer.from(hexText!, "hex")
|
||||
const decipher = crypto.createDecipheriv(ALGORITHM, encryptionKeyAsBuffer, iv)
|
||||
const decrypted = decipher.update(encryptedText)
|
||||
const decryptedBuffer = Buffer.concat([decrypted, decipher.final()])
|
||||
|
||||
return decryptedBuffer.toString()
|
||||
}
|
||||
|
||||
export function computeEncryptionKey(userIdentifier: string) {
|
||||
return crypto.scryptSync(userIdentifier, serverRuntimeConfig.masterEncryptionKey, 32)
|
||||
}
|
7
db/index.ts
Normal file
7
db/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { enhancePrisma } from "blitz"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const EnhancedPrisma = enhancePrisma(PrismaClient)
|
||||
|
||||
export * from "@prisma/client"
|
||||
export default new EnhancedPrisma()
|
57
db/migrations/20210726100838_init/migration.sql
Normal file
57
db/migrations/20210726100838_init/migration.sql
Normal file
@ -0,0 +1,57 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"name" TEXT,
|
||||
"email" TEXT NOT NULL,
|
||||
"hashedPassword" TEXT,
|
||||
"role" TEXT NOT NULL DEFAULT E'USER',
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
"handle" TEXT NOT NULL,
|
||||
"hashedSessionToken" TEXT,
|
||||
"antiCSRFToken" TEXT,
|
||||
"publicData" TEXT,
|
||||
"privateData" TEXT,
|
||||
"userId" INTEGER,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Token" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"hashedToken" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"sentTo" TEXT NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session.handle_unique" ON "Session"("handle");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Token.hashedToken_type_unique" ON "Token"("hashedToken", "type");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Token" ADD FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
137
db/migrations/20210727115631_import_models/migration.sql
Normal file
137
db/migrations/20210727115631_import_models/migration.sql
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The primary key for the `Session` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `Token` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The primary key for the `User` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- A unique constraint covering the columns `[hashedToken,type]` on the table `Token` will be added. If there are existing duplicate values, this will fail.
|
||||
- Changed the type of `type` on the `Token` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TokenType" AS ENUM ('RESET_PASSWORD');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Direction" AS ENUM ('Inbound', 'Outbound');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "MessageStatus" AS ENUM ('Queued', 'Sending', 'Sent', 'Failed', 'Delivered', 'Undelivered', 'Receiving', 'Received', 'Accepted', 'Scheduled', 'Read', 'PartiallyDelivered', 'Canceled');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CallStatus" AS ENUM ('Queued', 'Ringing', 'InProgress', 'Completed', 'Busy', 'Failed', 'NoAnswer', 'Canceled');
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Session" DROP CONSTRAINT "Session_userId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Token" DROP CONSTRAINT "Token_userId_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Session" DROP CONSTRAINT "Session_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ALTER COLUMN "createdAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "updatedAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "expiresAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "userId" SET DATA TYPE TEXT,
|
||||
ADD PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "Session_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Token" DROP CONSTRAINT "Token_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ALTER COLUMN "createdAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "updatedAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
DROP COLUMN "type",
|
||||
ADD COLUMN "type" "TokenType" NOT NULL,
|
||||
ALTER COLUMN "expiresAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "userId" SET DATA TYPE TEXT,
|
||||
ADD PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "Token_id_seq";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" DROP CONSTRAINT "User_pkey",
|
||||
ALTER COLUMN "id" DROP DEFAULT,
|
||||
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||
ALTER COLUMN "createdAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ALTER COLUMN "updatedAt" SET DATA TYPE TIMESTAMPTZ,
|
||||
ADD PRIMARY KEY ("id");
|
||||
DROP SEQUENCE "User_id_seq";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Customer" (
|
||||
"id" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMPTZ NOT NULL,
|
||||
"encryptionKey" TEXT NOT NULL,
|
||||
"accountSid" TEXT,
|
||||
"authToken" TEXT,
|
||||
"twimlAppSid" TEXT,
|
||||
"paddleCustomerId" TEXT,
|
||||
"paddleSubscriptionId" TEXT,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Message" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sentAt" TIMESTAMPTZ NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"from" TEXT NOT NULL,
|
||||
"to" TEXT NOT NULL,
|
||||
"direction" "Direction" NOT NULL,
|
||||
"status" "MessageStatus" NOT NULL,
|
||||
"twilioSid" TEXT,
|
||||
"customerId" TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PhoneCall" (
|
||||
"id" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL,
|
||||
"twilioSid" TEXT NOT NULL,
|
||||
"from" TEXT NOT NULL,
|
||||
"to" TEXT NOT NULL,
|
||||
"status" "CallStatus" NOT NULL,
|
||||
"direction" "Direction" NOT NULL,
|
||||
"duration" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PhoneNumber" (
|
||||
"id" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ NOT NULL,
|
||||
"phoneNumberSid" TEXT NOT NULL,
|
||||
"phoneNumber" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Token.hashedToken_type_unique" ON "Token"("hashedToken", "type");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Token" ADD FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Customer" ADD FOREIGN KEY ("id") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Message" ADD FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PhoneCall" ADD FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PhoneNumber" ADD FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
12
db/migrations/20210727125716_user_role_enum/migration.sql
Normal file
12
db/migrations/20210727125716_user_role_enum/migration.sql
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The `role` column on the `User` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Role" AS ENUM ('USER', 'ADMIN');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" DROP COLUMN "role",
|
||||
ADD COLUMN "role" "Role" NOT NULL DEFAULT E'USER';
|
@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "PhoneCall" ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "PhoneNumber" ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP;
|
3
db/migrations/migration_lock.toml
Normal file
3
db/migrations/migration_lock.toml
Normal file
@ -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"
|
154
db/schema.prisma
Normal file
154
db/schema.prisma
Normal file
@ -0,0 +1,154 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
datasource db {
|
||||
provider = "postgres"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||
name String?
|
||||
email String @unique
|
||||
hashedPassword String?
|
||||
role Role @default(USER)
|
||||
|
||||
tokens Token[]
|
||||
sessions Session[]
|
||||
customer Customer[]
|
||||
}
|
||||
|
||||
enum Role {
|
||||
USER
|
||||
ADMIN
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||
expiresAt DateTime? @db.Timestamptz
|
||||
handle String @unique
|
||||
hashedSessionToken String?
|
||||
antiCSRFToken String?
|
||||
publicData String?
|
||||
privateData String?
|
||||
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId String?
|
||||
}
|
||||
|
||||
model Token {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||
hashedToken String
|
||||
type TokenType
|
||||
expiresAt DateTime @db.Timestamptz
|
||||
sentTo String
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId String
|
||||
|
||||
@@unique([hashedToken, type])
|
||||
}
|
||||
|
||||
enum TokenType {
|
||||
RESET_PASSWORD
|
||||
}
|
||||
|
||||
model Customer {
|
||||
id String @id
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||
encryptionKey String
|
||||
accountSid String?
|
||||
authToken String?
|
||||
// TODO: encrypt it with encryptionKey
|
||||
twimlAppSid String?
|
||||
paddleCustomerId String?
|
||||
paddleSubscriptionId String?
|
||||
|
||||
user User @relation(fields: [id], references: [id])
|
||||
messages Message[]
|
||||
phoneCalls PhoneCall[]
|
||||
phoneNumbers PhoneNumber[]
|
||||
}
|
||||
|
||||
model Message {
|
||||
id String @id @default(uuid())
|
||||
sentAt DateTime @db.Timestamptz
|
||||
content String
|
||||
from String
|
||||
to String
|
||||
direction Direction
|
||||
status MessageStatus
|
||||
twilioSid String?
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id])
|
||||
customerId String
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
Inbound
|
||||
Outbound
|
||||
}
|
||||
|
||||
enum MessageStatus {
|
||||
Queued
|
||||
Sending
|
||||
Sent
|
||||
Failed
|
||||
Delivered
|
||||
Undelivered
|
||||
Receiving
|
||||
Received
|
||||
Accepted
|
||||
Scheduled
|
||||
Read
|
||||
PartiallyDelivered
|
||||
Canceled
|
||||
}
|
||||
|
||||
model PhoneCall {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
twilioSid String
|
||||
from String
|
||||
to String
|
||||
status CallStatus
|
||||
direction Direction
|
||||
duration String
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id])
|
||||
customerId String
|
||||
}
|
||||
|
||||
enum CallStatus {
|
||||
Queued
|
||||
Ringing
|
||||
InProgress
|
||||
Completed
|
||||
Busy
|
||||
Failed
|
||||
NoAnswer
|
||||
Canceled
|
||||
}
|
||||
|
||||
model PhoneNumber {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now()) @db.Timestamptz
|
||||
phoneNumberSid String
|
||||
phoneNumber String
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id])
|
||||
customerId String
|
||||
}
|
16
db/seeds.ts
Normal file
16
db/seeds.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// import db from "./index"
|
||||
|
||||
/*
|
||||
* This seed function is executed when you run `blitz db seed`.
|
||||
*
|
||||
* Probably you want to use a library like https://chancejs.com
|
||||
* or https://github.com/Marak/Faker.js to easily generate
|
||||
* realistic data.
|
||||
*/
|
||||
const seed = async () => {
|
||||
// for (let i = 0; i < 5; i++) {
|
||||
// await db.project.create({ data: { name: "Project " + i } })
|
||||
// }
|
||||
}
|
||||
|
||||
export default seed
|
Reference in New Issue
Block a user