mirror of
https://github.com/barthuijgen/factorio-sites.git
synced 2024-11-21 18:16:33 +02:00
update fbe-editor, migrate from sequelize to prisma
This commit is contained in:
parent
fe51aa2376
commit
a42927f336
4
.gitignore
vendored
4
.gitignore
vendored
@ -43,5 +43,5 @@ Thumbs.db
|
||||
/credentials
|
||||
.env.local
|
||||
.local.env
|
||||
/.yalc
|
||||
local.readme.md
|
||||
local.readme.md
|
||||
.yalc
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -1,4 +1,7 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[prisma]": {
|
||||
"editor.defaultFormatter": "Prisma.prisma"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The migration will add a unique constraint covering the columns `[blueprint_hash]` on the table `blueprint_book`. If there are existing duplicate values, the migration will fail.
|
||||
- The migration will add a unique constraint covering the columns `[factorioprints_id]` on the table `blueprint_page`. If there are existing duplicate values, the migration will fail.
|
||||
- The migration will add a unique constraint covering the columns `[session_token]` on the table `session`. If there are existing duplicate values, the migration will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "blueprint" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "blueprint_book" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "blueprint_page" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "session" ALTER COLUMN "last_used" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user" ALTER COLUMN "password_reset_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "last_password_change" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "last_login_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user_favorites" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER COLUMN "created_at" SET DATA TYPE TIMESTAMP(3),
|
||||
ALTER COLUMN "updated_at" SET DATA TYPE TIMESTAMP(3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "blueprint_book.blueprint_hash_unique" ON "blueprint_book"("blueprint_hash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "blueprint_page.factorioprints_id_unique" ON "blueprint_page"("factorioprints_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "session.session_token_unique" ON "session"("session_token");
|
3
apps/blueprints/prisma/migrations/migration_lock.toml
Normal file
3
apps/blueprints/prisma/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"
|
113
apps/blueprints/prisma/schema.prisma
Normal file
113
apps/blueprints/prisma/schema.prisma
Normal file
@ -0,0 +1,113 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum enum_user_role {
|
||||
user
|
||||
moderator
|
||||
admin
|
||||
}
|
||||
|
||||
model blueprint {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
label String? @db.VarChar(255)
|
||||
description String?
|
||||
game_version String? @db.VarChar(255)
|
||||
blueprint_hash String @unique @db.VarChar(40)
|
||||
image_hash String @db.VarChar(40)
|
||||
image_version Int @default(1)
|
||||
tags String[] @db.VarChar(255)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
blueprint_page blueprint_page?
|
||||
}
|
||||
|
||||
model blueprint_book {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
label String? @db.VarChar(255)
|
||||
description String?
|
||||
child_tree Json @db.Json
|
||||
blueprint_hash String @unique @db.VarChar(40)
|
||||
is_modded Boolean
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
blueprint_page blueprint_page?
|
||||
}
|
||||
|
||||
model blueprint_book_blueprints {
|
||||
blueprint_book_id String @db.Uuid
|
||||
blueprint_id String @db.Uuid
|
||||
|
||||
@@id([blueprint_book_id, blueprint_id])
|
||||
}
|
||||
|
||||
model blueprint_book_books {
|
||||
blueprint_book_1_id String @db.Uuid
|
||||
blueprint_book_2_id String @db.Uuid
|
||||
|
||||
@@id([blueprint_book_1_id, blueprint_book_2_id])
|
||||
}
|
||||
|
||||
model blueprint_page {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
user_id String? @db.Uuid
|
||||
blueprint_id String? @unique @db.Uuid
|
||||
blueprint_book_id String? @unique @db.Uuid
|
||||
title String @db.VarChar(255)
|
||||
description_markdown String?
|
||||
tags String[] @db.VarChar(255)
|
||||
factorioprints_id String? @unique @db.VarChar(255)
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
blueprint_book blueprint_book? @relation(fields: [blueprint_book_id], references: [id])
|
||||
blueprint blueprint? @relation(fields: [blueprint_id], references: [id])
|
||||
user_favorites user_favorites[]
|
||||
}
|
||||
|
||||
model session {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
user_id String @db.Uuid
|
||||
session_token String @unique @db.VarChar(255)
|
||||
useragent String @db.VarChar(255)
|
||||
ip String @db.VarChar(255)
|
||||
last_used DateTime
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
user user @relation(fields: [user_id], references: [id])
|
||||
}
|
||||
|
||||
model user {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
email String? @unique @db.VarChar(255)
|
||||
username String @unique @db.VarChar(255)
|
||||
role enum_user_role? @default(user)
|
||||
steam_id String? @unique @db.VarChar(255)
|
||||
password String? @db.VarChar(255)
|
||||
password_reset_token String? @db.Uuid
|
||||
password_reset_at DateTime?
|
||||
last_password_change DateTime?
|
||||
last_login_at DateTime?
|
||||
last_login_ip String @db.VarChar(255)
|
||||
email_validated Boolean @default(false)
|
||||
email_validate_token String? @db.Uuid
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
session session[]
|
||||
user_favorites user_favorites[]
|
||||
}
|
||||
|
||||
model user_favorites {
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
user_id String @db.Uuid
|
||||
blueprint_page_id String @db.Uuid
|
||||
blueprint_page blueprint_page @relation(fields: [blueprint_page_id], references: [id])
|
||||
user user @relation(fields: [user_id], references: [id])
|
||||
|
||||
@@id([user_id, blueprint_page_id])
|
||||
}
|
51
apps/blueprints/src/components/BlueprintLink.tsx
Normal file
51
apps/blueprints/src/components/BlueprintLink.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import Link from "next/link";
|
||||
import { css } from "@emotion/react";
|
||||
import { BlueprintPage } from "@factorio-sites/database";
|
||||
import { Box, Text } from "@chakra-ui/react";
|
||||
import { MdFavorite } from "react-icons/md";
|
||||
|
||||
const linkStyles = css`
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
a {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: #ccc;
|
||||
}
|
||||
`;
|
||||
|
||||
const formatDate = (datenum: number) => {
|
||||
const date = new Date(datenum * 1000);
|
||||
return date.toLocaleString();
|
||||
};
|
||||
|
||||
interface BlueprintLinkProps {
|
||||
blueprint: BlueprintPage;
|
||||
editLink?: boolean;
|
||||
}
|
||||
|
||||
export const BlueprintLink: React.FC<BlueprintLinkProps> = ({ blueprint, editLink }) => (
|
||||
<div css={linkStyles}>
|
||||
<Link
|
||||
href={editLink ? `/user/blueprint/${blueprint.id}` : `/blueprint/${blueprint.id}`}
|
||||
passHref
|
||||
>
|
||||
<a>
|
||||
<Box css={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Text>{blueprint.title}</Text>
|
||||
<Box css={{ display: "flex" }}>
|
||||
<Text css={{ display: "flex", alignItems: "center", marginRight: "2rem" }}>
|
||||
<MdFavorite css={{ marginRight: "0.5rem" }} />
|
||||
{blueprint.favorite_count}
|
||||
</Text>
|
||||
<Text>{formatDate(blueprint.updated_at)}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
@ -5,10 +5,10 @@ const handler = apiHandler(async (_, res, { session }) => {
|
||||
if (session) {
|
||||
return res.status(200).json({
|
||||
auth: {
|
||||
user_id: session.user.get("id"),
|
||||
username: session.user.get("username"),
|
||||
email: session.user.get("email"),
|
||||
steam_id: session.user.get("steam_id"),
|
||||
user_id: session.user.id,
|
||||
username: session.user.username,
|
||||
email: session.user.email,
|
||||
steam_id: session.user.steam_id,
|
||||
} as AuthContextProps,
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { isBlueprintPageUserFavorite, createUserFavorite } from "@factorio-sites/database";
|
||||
import { isBlueprintPageUserFavorite, createUserFavorite, prisma } from "@factorio-sites/database";
|
||||
import { apiHandler } from "../../../utils/api-handler";
|
||||
|
||||
const handler = apiHandler(async (req, res, { session }) => {
|
||||
@ -12,7 +12,14 @@ const handler = apiHandler(async (req, res, { session }) => {
|
||||
const existing = await isBlueprintPageUserFavorite(user.id, blueprint_page_id);
|
||||
|
||||
if (existing) {
|
||||
await existing.destroy();
|
||||
await prisma().user_favorites.delete({
|
||||
where: {
|
||||
user_id_blueprint_page_id: {
|
||||
user_id: existing.user_id,
|
||||
blueprint_page_id: existing.blueprint_page_id,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await createUserFavorite(user.id, blueprint_page_id);
|
||||
}
|
||||
|
@ -1,52 +1,12 @@
|
||||
import React from "react";
|
||||
import { NextPage, NextPageContext } from "next";
|
||||
import Link from "next/link";
|
||||
import { css } from "@emotion/react";
|
||||
import { BlueprintPage, getMostRecentBlueprintPages, init } from "@factorio-sites/database";
|
||||
import { SimpleGrid, Box, RadioGroup, Stack, Radio, Text } from "@chakra-ui/react";
|
||||
import { SimpleGrid, Box, RadioGroup, Stack, Radio } from "@chakra-ui/react";
|
||||
import { Panel } from "../components/Panel";
|
||||
import { Pagination } from "../components/Pagination";
|
||||
import { useRouterQueryToHref } from "../hooks/query.hook";
|
||||
import { useRouter } from "next/router";
|
||||
import { MdFavorite } from "react-icons/md";
|
||||
|
||||
const linkStyles = css`
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
a {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: #ccc;
|
||||
}
|
||||
`;
|
||||
|
||||
const formatDate = (datenum: number) => {
|
||||
const date = new Date(datenum * 1000);
|
||||
return date.toLocaleString();
|
||||
};
|
||||
|
||||
const BlueprintComponent: React.FC<{ blueprint: BlueprintPage }> = ({ blueprint }) => (
|
||||
<div css={linkStyles}>
|
||||
<Link href={`/blueprint/${blueprint.id}`} passHref>
|
||||
<a>
|
||||
<Box css={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Text>{blueprint.title}</Text>
|
||||
<Box css={{ display: "flex" }}>
|
||||
<Text css={{ display: "flex", alignItems: "center", marginRight: "2rem" }}>
|
||||
<MdFavorite css={{ marginRight: "0.5rem" }} />
|
||||
{blueprint.favorite_count}
|
||||
</Text>
|
||||
<Text>{formatDate(blueprint.updated_at)}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
import { BlueprintLink } from "../components/BlueprintLink";
|
||||
|
||||
interface IndexProps {
|
||||
totalItems: number;
|
||||
@ -88,7 +48,7 @@ export const Index: NextPage<IndexProps> = ({
|
||||
</Box>
|
||||
<Box>
|
||||
{blueprints.map((bp) => (
|
||||
<BlueprintComponent key={bp.id} blueprint={bp} />
|
||||
<BlueprintLink key={bp.id} blueprint={bp} />
|
||||
))}
|
||||
<Pagination page={currentPage} totalPages={totalPages} totalItems={totalItems} />
|
||||
</Box>
|
||||
|
229
apps/blueprints/src/pages/user/blueprint/[blueprintId].tsx
Normal file
229
apps/blueprints/src/pages/user/blueprint/[blueprintId].tsx
Normal file
@ -0,0 +1,229 @@
|
||||
import React from "react";
|
||||
import { NextPage } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { Formik, Field } from "formik";
|
||||
import { css } from "@emotion/react";
|
||||
import {
|
||||
FormControl,
|
||||
FormLabel,
|
||||
FormErrorMessage,
|
||||
Input,
|
||||
SimpleGrid,
|
||||
Button,
|
||||
Box,
|
||||
Text,
|
||||
Textarea,
|
||||
} from "@chakra-ui/react";
|
||||
import MultiSelect from "react-multi-select-component";
|
||||
import { chakraResponsive } from "@factorio-sites/web-utils";
|
||||
import {
|
||||
Blueprint,
|
||||
BlueprintBook,
|
||||
BlueprintPage,
|
||||
getBlueprintBookById,
|
||||
getBlueprintById,
|
||||
getBlueprintPageById,
|
||||
getBlueprintStringByHash,
|
||||
} from "@factorio-sites/database";
|
||||
import { pageHandler } from "../../../utils/page-handler";
|
||||
import { Panel } from "../../../components/Panel";
|
||||
import { validateCreateBlueprintForm } from "../../../utils/validate";
|
||||
import { useAuth } from "../../../providers/auth";
|
||||
import { ImageEditor } from "../../../components/ImageEditor";
|
||||
|
||||
const FieldStyle = css`
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
|
||||
const TAGS = [
|
||||
{ value: "foo", label: "foo" },
|
||||
{ value: "bar", label: "bar" },
|
||||
{ value: "x", label: "x" },
|
||||
{ value: "y", label: "y" },
|
||||
];
|
||||
|
||||
type Selected =
|
||||
| { type: "blueprint"; data: Pick<Blueprint, "id" | "blueprint_hash">; string: string }
|
||||
| { type: "blueprint_book"; data: Pick<BlueprintBook, "id" | "blueprint_hash">; string: string };
|
||||
|
||||
interface UserBlueprintProps {
|
||||
blueprintPage: BlueprintPage;
|
||||
selected: Selected;
|
||||
}
|
||||
export const UserBlueprint: NextPage<UserBlueprintProps> = ({ blueprintPage, selected }) => {
|
||||
const auth = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
if (!auth) {
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
if (!blueprintPage) return null;
|
||||
|
||||
return (
|
||||
<div css={{ margin: "0.7rem" }}>
|
||||
<Formik
|
||||
initialValues={{
|
||||
title: blueprintPage.title,
|
||||
description: blueprintPage.description_markdown,
|
||||
string: selected.string,
|
||||
tags: [],
|
||||
}}
|
||||
validate={validateCreateBlueprintForm}
|
||||
onSubmit={async (values, { setSubmitting, setErrors, setStatus }) => {
|
||||
setStatus("");
|
||||
|
||||
const result = await fetch("/api/blueprint/create", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(values),
|
||||
}).then((res) => res.json());
|
||||
|
||||
if (result.status) {
|
||||
setSubmitting(false);
|
||||
setStatus(result.status);
|
||||
} else if (result.errors) {
|
||||
setSubmitting(false);
|
||||
setErrors(result.errors);
|
||||
} else if (result.success) {
|
||||
router.push(`/blueprint/${result.id}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting, handleSubmit, status, values, errors, setFieldValue }) => (
|
||||
<SimpleGrid
|
||||
columns={2}
|
||||
gap={6}
|
||||
templateColumns={chakraResponsive({ mobile: "1fr", desktop: "1fr 1fr" })}
|
||||
>
|
||||
<Panel title="Create new blueprint">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Field name="title">
|
||||
{({ field, meta }: any) => (
|
||||
<FormControl
|
||||
id="title"
|
||||
isRequired
|
||||
isInvalid={meta.touched && meta.error}
|
||||
css={FieldStyle}
|
||||
>
|
||||
<FormLabel>Title</FormLabel>
|
||||
<Input type="text" {...field} />
|
||||
<FormErrorMessage>{meta.error}</FormErrorMessage>
|
||||
</FormControl>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field name="description">
|
||||
{({ field, meta }: any) => (
|
||||
<FormControl
|
||||
id="description"
|
||||
isRequired
|
||||
isInvalid={meta.touched && meta.error}
|
||||
css={FieldStyle}
|
||||
>
|
||||
<FormLabel>Description</FormLabel>
|
||||
<Textarea {...field} />
|
||||
<FormErrorMessage>{meta.error}</FormErrorMessage>
|
||||
</FormControl>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field name="tags">
|
||||
{({ field, meta }: any) => (
|
||||
<FormControl id="tags" isInvalid={meta.touched && meta.error} css={FieldStyle}>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
<MultiSelect
|
||||
css={{ color: "black" }}
|
||||
options={TAGS}
|
||||
value={field.value}
|
||||
onChange={(value: any) => setFieldValue("tags", value)}
|
||||
labelledBy="Select"
|
||||
hasSelectAll={false}
|
||||
/>
|
||||
<FormErrorMessage>{meta.error}</FormErrorMessage>
|
||||
</FormControl>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field name="string">
|
||||
{({ field, meta }: any) => (
|
||||
<FormControl
|
||||
id="string"
|
||||
isRequired
|
||||
isInvalid={meta.touched && meta.error}
|
||||
css={FieldStyle}
|
||||
>
|
||||
<FormLabel>Blueprint string</FormLabel>
|
||||
<Input type="text" {...field} />
|
||||
<FormErrorMessage>{meta.error}</FormErrorMessage>
|
||||
</FormControl>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Box css={{ display: "flex", alignItems: "center" }}>
|
||||
<Button type="submit" colorScheme="green" disabled={isSubmitting}>
|
||||
Submit
|
||||
</Button>
|
||||
{status && <Text css={{ marginLeft: "1rem", color: "red" }}>{status}</Text>}
|
||||
</Box>
|
||||
</form>
|
||||
</Panel>
|
||||
<Panel title="Preview">
|
||||
<Box>
|
||||
{values.string && !errors.string && (
|
||||
<ImageEditor string={values.string}></ImageEditor>
|
||||
)}
|
||||
</Box>
|
||||
</Panel>
|
||||
</SimpleGrid>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps = pageHandler(async (context, { session }) => {
|
||||
const blueprintId = context.query.blueprintId ? (context.query.blueprintId as string) : null;
|
||||
|
||||
if (!session || !blueprintId) {
|
||||
return { props: {} };
|
||||
}
|
||||
|
||||
const blueprintPage = await getBlueprintPageById(blueprintId);
|
||||
let selected!: UserBlueprintProps["selected"];
|
||||
|
||||
if (blueprintPage?.blueprint_id) {
|
||||
const blueprint = await getBlueprintById(blueprintPage.blueprint_id);
|
||||
if (!blueprint) return;
|
||||
|
||||
selected = {
|
||||
type: "blueprint",
|
||||
data: {
|
||||
id: blueprintPage.blueprint_id,
|
||||
blueprint_hash: blueprint.blueprint_hash,
|
||||
},
|
||||
string: (await getBlueprintStringByHash(blueprint.blueprint_hash)) as string,
|
||||
};
|
||||
} else if (blueprintPage?.blueprint_book_id) {
|
||||
const blueprintBook = await getBlueprintBookById(blueprintPage.blueprint_book_id);
|
||||
if (!blueprintBook) return;
|
||||
|
||||
selected = {
|
||||
type: "blueprint_book",
|
||||
data: {
|
||||
id: blueprintPage.blueprint_book_id,
|
||||
blueprint_hash: blueprintBook.blueprint_hash,
|
||||
},
|
||||
string: (await getBlueprintStringByHash(blueprintBook.blueprint_hash)) as string,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
blueprintPage: blueprintPage,
|
||||
selected,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default UserBlueprint;
|
@ -3,22 +3,55 @@ import { NextPage } from "next";
|
||||
import { Button, SimpleGrid, Box } from "@chakra-ui/react";
|
||||
import { Panel } from "../../components/Panel";
|
||||
import Link from "next/link";
|
||||
import { pageHandler } from "../../utils/page-handler";
|
||||
import { BlueprintPage, getBlueprintPageByUserId } from "@factorio-sites/database";
|
||||
import { BlueprintLink } from "../../components/BlueprintLink";
|
||||
|
||||
export const UserBlueprints: NextPage = () => {
|
||||
interface UserBlueprintsProps {
|
||||
blueprints: BlueprintPage[];
|
||||
}
|
||||
|
||||
export const UserBlueprints: NextPage<UserBlueprintsProps> = ({ blueprints }) => {
|
||||
return (
|
||||
<div css={{ margin: "0.7rem" }}>
|
||||
<SimpleGrid columns={1} margin="0 auto" maxWidth="800px">
|
||||
<Panel title="Blueprints">
|
||||
<Box>user blueprints</Box>
|
||||
<Link href="/user/blueprint-create">
|
||||
<a>
|
||||
<Button colorScheme="green">create blueprint</Button>
|
||||
</a>
|
||||
</Link>
|
||||
<Box
|
||||
css={{
|
||||
display: "flex",
|
||||
borderBottom: "1px solid #b7b7b7",
|
||||
paddingBottom: "0.3rem",
|
||||
}}
|
||||
>
|
||||
<Link href="/user/blueprint-create">
|
||||
<a>
|
||||
<Button colorScheme="green">create blueprint</Button>
|
||||
</a>
|
||||
</Link>
|
||||
</Box>
|
||||
<Box>
|
||||
{blueprints.map((bp) => (
|
||||
<BlueprintLink key={bp.id} blueprint={bp} editLink />
|
||||
))}
|
||||
</Box>
|
||||
</Panel>
|
||||
</SimpleGrid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps = pageHandler(async (context, { session }) => {
|
||||
if (!session) {
|
||||
return { props: {} };
|
||||
}
|
||||
|
||||
const blueprints = await getBlueprintPageByUserId(session.user.id);
|
||||
|
||||
return {
|
||||
props: {
|
||||
blueprints,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default UserBlueprints;
|
||||
|
Binary file not shown.
@ -1,14 +1,13 @@
|
||||
import { BlueprintData, getBlueprintContentForImageHash } from "@factorio-sites/common-utils";
|
||||
import { encodeBlueprint, hashString } from "@factorio-sites/node-utils";
|
||||
// import { getBlueprintImageRequestTopic } from "../gcp-pubsub";
|
||||
import { blueprint as BlueprintModel } from "@prisma/client";
|
||||
import { saveBlueprintString } from "../gcp-storage";
|
||||
import { BlueprintModel } from "../postgres/database";
|
||||
import { BlueprintInstance } from "../postgres/models/Blueprint";
|
||||
import { prisma } from "../postgres/database";
|
||||
import { Blueprint } from "../types";
|
||||
|
||||
// const blueprintImageRequestTopic = getBlueprintImageRequestTopic();
|
||||
|
||||
const mapBlueprintInstanceToEntry = (entity: BlueprintInstance): Blueprint => ({
|
||||
const mapBlueprintInstanceToEntry = (entity: BlueprintModel): Blueprint => ({
|
||||
id: entity.id,
|
||||
blueprint_hash: entity.blueprint_hash,
|
||||
image_hash: entity.image_hash,
|
||||
@ -21,18 +20,12 @@ const mapBlueprintInstanceToEntry = (entity: BlueprintInstance): Blueprint => ({
|
||||
});
|
||||
|
||||
export async function getBlueprintById(id: string): Promise<Blueprint | null> {
|
||||
const result = await BlueprintModel()
|
||||
.findByPk(id)
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint.findUnique({ where: { id } });
|
||||
return result ? mapBlueprintInstanceToEntry(result) : null;
|
||||
}
|
||||
|
||||
export async function getBlueprintByHash(hash: string): Promise<Blueprint | null> {
|
||||
const result = await BlueprintModel()
|
||||
.findOne({
|
||||
where: { blueprint_hash: hash },
|
||||
})
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint.findUnique({ where: { blueprint_hash: hash } });
|
||||
return result ? mapBlueprintInstanceToEntry(result) : null;
|
||||
}
|
||||
|
||||
@ -57,16 +50,19 @@ export async function createBlueprint(
|
||||
await saveBlueprintString(blueprint_hash, string);
|
||||
|
||||
// Write blueprint details to datastore
|
||||
const result = await BlueprintModel().create({
|
||||
label: blueprint.label,
|
||||
description: blueprint.description,
|
||||
blueprint_hash: blueprint_hash,
|
||||
image_hash: image_hash,
|
||||
tags: extraInfo.tags,
|
||||
game_version: `${blueprint.version}`,
|
||||
image_version: 1,
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : undefined,
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : undefined,
|
||||
|
||||
const result = await prisma().blueprint.create({
|
||||
data: {
|
||||
label: blueprint.label,
|
||||
description: blueprint.description,
|
||||
blueprint_hash: blueprint_hash,
|
||||
image_hash: image_hash,
|
||||
tags: extraInfo.tags,
|
||||
game_version: `${blueprint.version}`,
|
||||
image_version: 1,
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : new Date(),
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Created Blueprint ${result.id}`);
|
||||
|
@ -1,35 +1,29 @@
|
||||
import { BlueprintBookData } from "@factorio-sites/common-utils";
|
||||
import { encodeBlueprint, hashString } from "@factorio-sites/node-utils";
|
||||
import { blueprint_book } from "@prisma/client";
|
||||
import { saveBlueprintString } from "../gcp-storage";
|
||||
import { BlueprintBookModel } from "../postgres/database";
|
||||
import { BlueprintBookInstance } from "../postgres/models/BlueprintBook";
|
||||
import { prisma } from "../postgres/database";
|
||||
import { BlueprintBook, ChildTree } from "../types";
|
||||
import { createBlueprint } from "./blueprint";
|
||||
|
||||
const mapBlueprintBookEntityToObject = (entity: BlueprintBookInstance): BlueprintBook => ({
|
||||
const mapBlueprintBookEntityToObject = (entity: blueprint_book): BlueprintBook => ({
|
||||
id: entity.id,
|
||||
child_tree: entity.child_tree ? entity.child_tree : [],
|
||||
child_tree: entity.child_tree ? (entity.child_tree as any) : [],
|
||||
blueprint_hash: entity.blueprint_hash,
|
||||
label: entity.label,
|
||||
description: entity.description,
|
||||
label: entity.label || "",
|
||||
description: entity.description || "",
|
||||
created_at: entity.created_at && entity.created_at.getTime() / 1000,
|
||||
updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
|
||||
is_modded: entity.is_modded || false,
|
||||
});
|
||||
|
||||
export async function getBlueprintBookById(id: string): Promise<BlueprintBook | null> {
|
||||
const result = await BlueprintBookModel()
|
||||
.findByPk(id)
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint_book.findUnique({ where: { id } });
|
||||
return result ? mapBlueprintBookEntityToObject(result) : null;
|
||||
}
|
||||
|
||||
export async function getBlueprintBookByHash(hash: string): Promise<BlueprintBook | null> {
|
||||
const result = await BlueprintBookModel()
|
||||
.findOne({
|
||||
where: { blueprint_hash: hash },
|
||||
})
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint_book.findUnique({ where: { blueprint_hash: hash } });
|
||||
return result ? mapBlueprintBookEntityToObject(result) : null;
|
||||
}
|
||||
|
||||
@ -81,14 +75,16 @@ export async function createBlueprintBook(
|
||||
}
|
||||
}
|
||||
|
||||
const result = await BlueprintBookModel().create({
|
||||
label: blueprintBook.label,
|
||||
description: blueprintBook.description,
|
||||
blueprint_hash: blueprint_hash,
|
||||
is_modded: false,
|
||||
child_tree,
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : undefined,
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : undefined,
|
||||
const result = await prisma().blueprint_book.create({
|
||||
data: {
|
||||
label: blueprintBook.label,
|
||||
description: blueprintBook.description,
|
||||
blueprint_hash: blueprint_hash,
|
||||
is_modded: false,
|
||||
child_tree: child_tree as any,
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : new Date(),
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Created Blueprint book ${result.id}`);
|
||||
|
@ -1,15 +1,13 @@
|
||||
import { Sequelize } from "sequelize";
|
||||
import { Op } from "sequelize";
|
||||
import { BlueprintPageModel } from "../postgres/database";
|
||||
import { BlueprintPageInstance } from "../postgres/models/BlueprintPage";
|
||||
import { blueprint_page } from "@prisma/client";
|
||||
import { prisma } from "../postgres/database";
|
||||
import { BlueprintPage } from "../types";
|
||||
|
||||
const mapBlueprintPageEntityToObject = (entity: BlueprintPageInstance): BlueprintPage => ({
|
||||
const mapBlueprintPageEntityToObject = (entity: blueprint_page): BlueprintPage => ({
|
||||
id: entity.id,
|
||||
blueprint_id: entity.blueprint_id ?? null,
|
||||
blueprint_book_id: entity.blueprint_book_id ?? null,
|
||||
title: entity.title,
|
||||
description_markdown: entity.description_markdown,
|
||||
description_markdown: entity.description_markdown || "",
|
||||
created_at: entity.created_at && entity.created_at.getTime() / 1000,
|
||||
updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
|
||||
factorioprints_id: entity.factorioprints_id ?? null,
|
||||
@ -17,20 +15,19 @@ const mapBlueprintPageEntityToObject = (entity: BlueprintPageInstance): Blueprin
|
||||
});
|
||||
|
||||
export async function getBlueprintPageById(id: string): Promise<BlueprintPage | null> {
|
||||
const result = await BlueprintPageModel()
|
||||
.findByPk(id)
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint_page.findUnique({ where: { id } });
|
||||
return result ? mapBlueprintPageEntityToObject(result) : null;
|
||||
}
|
||||
|
||||
export async function getBlueprintPageByUserId(user_id: string): Promise<BlueprintPage[] | null> {
|
||||
const results = await prisma().blueprint_page.findMany({ where: { user_id } });
|
||||
return results ? results.map((result) => mapBlueprintPageEntityToObject(result)) : null;
|
||||
}
|
||||
|
||||
export async function getBlueprintPageByFactorioprintsId(
|
||||
id: string
|
||||
): Promise<BlueprintPage | null> {
|
||||
const result = await BlueprintPageModel()
|
||||
.findOne({
|
||||
where: { factorioprints_id: id },
|
||||
})
|
||||
.catch(() => null);
|
||||
const result = await prisma().blueprint_page.findFirst({ where: { factorioprints_id: id } });
|
||||
return result ? mapBlueprintPageEntityToObject(result) : null;
|
||||
}
|
||||
|
||||
@ -45,37 +42,30 @@ export async function getMostRecentBlueprintPages({
|
||||
query?: string;
|
||||
order: "date" | "favorites" | string;
|
||||
}): Promise<{ count: number; rows: BlueprintPage[] }> {
|
||||
const orderMap: any = {
|
||||
date: {
|
||||
order: [["updated_at", "DESC"]],
|
||||
},
|
||||
favorites: {
|
||||
order: [[Sequelize.literal(`"favorite_count"`), "DESC"]],
|
||||
},
|
||||
const orderMap: Record<string, string> = {
|
||||
date: "updated_at",
|
||||
favorites: "favorite_count",
|
||||
};
|
||||
const orderArgs = orderMap[order] || orderMap.date;
|
||||
const result = await BlueprintPageModel()
|
||||
.findAndCountAll({
|
||||
where: query ? { title: { [Op.iLike]: `%${query}%` } } : undefined,
|
||||
limit: perPage,
|
||||
offset: (page - 1) * perPage,
|
||||
raw: true,
|
||||
attributes: [
|
||||
"blueprint_page.*",
|
||||
[
|
||||
Sequelize.literal(
|
||||
"(SELECT COUNT(*) FROM user_favorites WHERE user_favorites.blueprint_page_id = blueprint_page.id)"
|
||||
),
|
||||
"favorite_count",
|
||||
],
|
||||
],
|
||||
...orderArgs,
|
||||
})
|
||||
.catch(() => null);
|
||||
const result = (
|
||||
await prisma().$queryRaw<(blueprint_page & { favorite_count: number })[]>(
|
||||
`SELECT *, (SELECT COUNT(*) FROM user_favorites where user_favorites.blueprint_page_id = blueprint_page.id) AS favorite_count
|
||||
FROM public.blueprint_page
|
||||
WHERE blueprint_page.title ILIKE $1
|
||||
ORDER BY ${orderMap[order] || orderMap.date} DESC
|
||||
LIMIT $2 OFFSET $3`,
|
||||
query ? `%${query}%` : "%",
|
||||
perPage,
|
||||
(page - 1) * perPage
|
||||
)
|
||||
).map((blueprintPage) => ({
|
||||
...blueprintPage,
|
||||
created_at: new Date(blueprintPage.created_at),
|
||||
updated_at: new Date(blueprintPage.updated_at),
|
||||
}));
|
||||
|
||||
return {
|
||||
count: result?.count ?? 0,
|
||||
rows: result?.rows.map(mapBlueprintPageEntityToObject) ?? [],
|
||||
count: result.length,
|
||||
rows: result.map(mapBlueprintPageEntityToObject),
|
||||
};
|
||||
}
|
||||
|
||||
@ -92,16 +82,18 @@ export async function createBlueprintPage(
|
||||
factorioprints_id?: string;
|
||||
}
|
||||
) {
|
||||
const page = await BlueprintPageModel().create({
|
||||
user_id: extraInfo.user_id,
|
||||
title: extraInfo.title,
|
||||
description_markdown: extraInfo.description_markdown,
|
||||
factorioprints_id: extraInfo.factorioprints_id,
|
||||
blueprint_id: type === "blueprint" ? targetId : undefined,
|
||||
blueprint_book_id: type === "blueprint_book" ? targetId : undefined,
|
||||
tags: extraInfo.tags ? extraInfo.tags : [],
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : undefined,
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : undefined,
|
||||
const page = await prisma().blueprint_page.create({
|
||||
data: {
|
||||
user_id: extraInfo.user_id,
|
||||
title: extraInfo.title,
|
||||
description_markdown: extraInfo.description_markdown,
|
||||
factorioprints_id: extraInfo.factorioprints_id,
|
||||
blueprint_id: type === "blueprint" ? targetId : undefined,
|
||||
blueprint_book_id: type === "blueprint_book" ? targetId : undefined,
|
||||
tags: extraInfo.tags ? extraInfo.tags : [],
|
||||
updated_at: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : new Date(),
|
||||
created_at: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Created Blueprint Page`);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as bcrypt from "bcrypt";
|
||||
import { sequelize, SessionModel, UserModel } from "../postgres/database";
|
||||
import { prisma } from "../postgres/database";
|
||||
import { SessionInstance } from "../postgres/models/Session";
|
||||
import { UserInstance } from "../postgres/models/User";
|
||||
|
||||
export const getUserById = async (id: string) => {
|
||||
const user = await UserModel().findByPk(id, { raw: true });
|
||||
const user = await prisma().user.findUnique({ where: { id } });
|
||||
return user ? user : null;
|
||||
};
|
||||
|
||||
@ -15,20 +15,24 @@ export const createUserWithEmail = async (
|
||||
ip: string
|
||||
) => {
|
||||
const hash = await bcrypt.hash(password, 10);
|
||||
return UserModel().create({
|
||||
email,
|
||||
username,
|
||||
password: hash,
|
||||
last_login_ip: ip,
|
||||
last_password_change: new Date(),
|
||||
return prisma().user.create({
|
||||
data: {
|
||||
email,
|
||||
username,
|
||||
password: hash,
|
||||
last_login_ip: ip,
|
||||
last_password_change: new Date(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const createUserWithSteam = async (steam_id: string, username: string, ip: string) => {
|
||||
return UserModel().create({
|
||||
steam_id,
|
||||
username,
|
||||
last_login_ip: ip,
|
||||
return prisma().user.create({
|
||||
data: {
|
||||
steam_id,
|
||||
username,
|
||||
last_login_ip: ip,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -43,7 +47,7 @@ export const loginUserWithEmail = async ({
|
||||
useragent: string;
|
||||
ip: string;
|
||||
}): Promise<(UserInstance & { session: SessionInstance }) | null> => {
|
||||
const user = await UserModel().findOne({ where: { email } });
|
||||
const user = await prisma().user.findUnique({ where: { email } });
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
@ -61,45 +65,50 @@ export const loginUserWithEmail = async ({
|
||||
};
|
||||
|
||||
export const loginUserWithSteam = async (steam_id: string, ip: string) => {
|
||||
const user = await UserModel().findOne({ where: { steam_id } });
|
||||
const user = await prisma().user.findUnique({ where: { steam_id } });
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
await user.update({
|
||||
last_login_ip: ip,
|
||||
last_login_at: new Date(),
|
||||
await prisma().user.update({
|
||||
where: { steam_id },
|
||||
data: {
|
||||
last_login_ip: ip,
|
||||
last_login_at: new Date(),
|
||||
},
|
||||
});
|
||||
return user;
|
||||
};
|
||||
|
||||
export const createSession = async (user: UserInstance, useragent: string, ip: string) => {
|
||||
return SessionModel().create({
|
||||
user_id: user.id,
|
||||
useragent,
|
||||
ip,
|
||||
return prisma().session.create({
|
||||
datta: {
|
||||
user_id: user.id,
|
||||
useragent,
|
||||
ip,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getSessionByToken = async (
|
||||
token: string
|
||||
): Promise<(SessionInstance & { user: UserInstance }) | null> => {
|
||||
return SessionModel().findOne<any>({
|
||||
export const getSessionByToken = async (token: string) => {
|
||||
return await prisma().session.findUnique({
|
||||
where: { session_token: token },
|
||||
include: [UserModel()],
|
||||
include: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const isBlueprintPageUserFavorite = async (user_id: string, blueprint_page_id: string) => {
|
||||
const UserFavorites = sequelize().models.user_favorites;
|
||||
return UserFavorites.findOne({
|
||||
where: { user_id, blueprint_page_id },
|
||||
});
|
||||
const { user_favorites } = prisma();
|
||||
return user_favorites.findFirst({ where: { user_id, blueprint_page_id } });
|
||||
};
|
||||
|
||||
export const createUserFavorite = async (user_id: string, blueprint_page_id: string) => {
|
||||
const UserFavorites = sequelize().models.user_favorites;
|
||||
return UserFavorites.create({
|
||||
user_id,
|
||||
blueprint_page_id,
|
||||
const { user_favorites } = prisma();
|
||||
return user_favorites.create({
|
||||
data: {
|
||||
user_id,
|
||||
blueprint_page_id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -1,438 +0,0 @@
|
||||
// import { Datastore } from "@google-cloud/datastore";
|
||||
// import { encodeBlueprint, hashString, parseBlueprintString } from "@factorio-sites/node-utils";
|
||||
// import {
|
||||
// BlueprintStringData,
|
||||
// BlueprintBookData,
|
||||
// getBlueprintContentForImageHash,
|
||||
// } from "@factorio-sites/common-utils";
|
||||
// import { getBlueprintImageRequestTopic } from "./gcp-pubsub";
|
||||
// import { saveBlueprintString } from "./gcp-storage";
|
||||
// import { BlueprintBook, Blueprint, BlueprintPage } from "./types";
|
||||
|
||||
// const datastore = new Datastore();
|
||||
// const BlueprintEntity = "Blueprint";
|
||||
// const BlueprintBookEntity = "BlueprintBook";
|
||||
// const BlueprintPageEntity = "BlueprintPage";
|
||||
// const BlueprintStringEntity = "BlueprintString";
|
||||
// const blueprintImageRequestTopic = getBlueprintImageRequestTopic();
|
||||
|
||||
// class DatastoreExistsError extends Error {
|
||||
// constructor(public existingId: string, message: string) {
|
||||
// super(message);
|
||||
// this.name = this.constructor.name;
|
||||
// Error.captureStackTrace(this, this.constructor);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * BlueprintBook
|
||||
// */
|
||||
|
||||
// const mapBlueprintBookEntityToObject = (entity: any): BlueprintBook => ({
|
||||
// id: entity[datastore.KEY].id,
|
||||
// // blueprint_ids: entity.blueprint_ids.map((key: any) => key.id),
|
||||
// // blueprint_book_ids: entity.blueprint_book_ids.map((key: any) => key.id),
|
||||
// child_tree: entity.child_tree ? entity.child_tree : [],
|
||||
// blueprint_hash: entity.blueprint_hash,
|
||||
// label: entity.label,
|
||||
// description: entity.description,
|
||||
// created_at: entity.created_at && entity.created_at.getTime() / 1000,
|
||||
// updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
|
||||
// is_modded: entity.is_modded || false,
|
||||
// factorioprints_id: entity.factorioprints_id || null,
|
||||
// });
|
||||
|
||||
// export async function getBlueprintBookById(id: string): Promise<BlueprintBook | null> {
|
||||
// const result = await datastore.get(datastore.key([BlueprintBookEntity, Number(id)]));
|
||||
// return result[0] ? mapBlueprintBookEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function getBlueprintBookByHash(hash: string): Promise<BlueprintBook | null> {
|
||||
// const query = datastore
|
||||
// .createQuery(BlueprintBookEntity)
|
||||
// .filter("blueprint_hash", "=", hash)
|
||||
// .limit(1);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result[0] ? mapBlueprintBookEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function createBlueprintBook(
|
||||
// blueprintBook: BlueprintBookData,
|
||||
// extraInfo: { tags: string[]; created_at: number; updated_at: number; factorioprints_id: string }
|
||||
// ): Promise<{ insertedId: string; child_tree: BlueprintBook["child_tree"] }> {
|
||||
// const string = await encodeBlueprint({ blueprint_book: blueprintBook });
|
||||
// const blueprint_hash = hashString(string);
|
||||
|
||||
// const exists = await getBlueprintBookByHash(blueprint_hash);
|
||||
// if (exists) {
|
||||
// const book = await getBlueprintBookById(exists.id);
|
||||
// if (!book) throw Error("this is impossible, just pleasing typescript");
|
||||
// return { insertedId: exists.id, child_tree: book.child_tree };
|
||||
// }
|
||||
|
||||
// // Write string to google storage
|
||||
// await saveBlueprintString(blueprint_hash, string);
|
||||
|
||||
// const blueprint_ids = [];
|
||||
// const blueprint_book_ids = [];
|
||||
// const child_tree: BlueprintBook["child_tree"] = [];
|
||||
|
||||
// // Create the book's child objects
|
||||
// for (let i = 0; i < blueprintBook.blueprints.length; i++) {
|
||||
// const blueprint = blueprintBook.blueprints[i];
|
||||
// if (blueprint.blueprint) {
|
||||
// const result = await createBlueprint(blueprint.blueprint, extraInfo);
|
||||
// child_tree.push({
|
||||
// type: "blueprint",
|
||||
// id: result.insertedId,
|
||||
// name: blueprint.blueprint.label,
|
||||
// });
|
||||
// blueprint_ids.push(result.insertedId);
|
||||
// } else if (blueprint.blueprint_book) {
|
||||
// const result = await createBlueprintBook(blueprint.blueprint_book, extraInfo);
|
||||
// child_tree.push({
|
||||
// type: "blueprint_book",
|
||||
// id: result.insertedId,
|
||||
// name: blueprint.blueprint_book.label,
|
||||
// children: result.child_tree,
|
||||
// });
|
||||
// blueprint_book_ids.push(result.insertedId);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Write blueprint details to datastore
|
||||
// const [result] = await datastore.insert({
|
||||
// key: datastore.key([BlueprintBookEntity]),
|
||||
// data: [
|
||||
// {
|
||||
// name: "blueprint_ids",
|
||||
// value: blueprint_ids.map((id) => datastore.key([BlueprintEntity, datastore.int(id)])),
|
||||
// },
|
||||
// {
|
||||
// name: "blueprint_book_ids",
|
||||
// value: blueprint_book_ids.map((id) =>
|
||||
// datastore.key([BlueprintBookEntity, datastore.int(id)])
|
||||
// ),
|
||||
// },
|
||||
// { name: "child_tree", value: child_tree, excludeFromIndexes: true },
|
||||
// { name: "label", value: blueprintBook.label },
|
||||
// {
|
||||
// name: "description",
|
||||
// value: blueprintBook.description || null,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "blueprint_hash", value: blueprint_hash },
|
||||
// {
|
||||
// name: "created_at",
|
||||
// value: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : null,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// {
|
||||
// name: "updated_at",
|
||||
// value: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : null,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "factorioprints_id", value: extraInfo.factorioprints_id || null },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// const insertedId = String(result.mutationResults?.[0]?.key?.path?.[0]?.id) as string;
|
||||
// if (!insertedId) throw Error("Something went wrong inserting entity");
|
||||
|
||||
// console.log(`Created Blueprint book ${insertedId}`);
|
||||
|
||||
// return { insertedId, child_tree };
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * Blueprint
|
||||
// */
|
||||
|
||||
// const mapBlueprintEntityToObject = (entity: any): Blueprint => ({
|
||||
// id: entity[datastore.KEY].id,
|
||||
// blueprint_hash: entity.blueprint_hash,
|
||||
// image_hash: entity.image_hash,
|
||||
// label: entity.label,
|
||||
// description: entity.description,
|
||||
// tags: entity.tags,
|
||||
// created_at: entity.created_at && entity.created_at.getTime() / 1000,
|
||||
// updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
|
||||
// factorioprints_id: entity.factorioprints_id || null,
|
||||
// game_version: entity.game_version,
|
||||
// });
|
||||
|
||||
// const mapBlueprintObjectToEntity = (object: Omit<Blueprint, "id"> & { id?: string }): any => ({
|
||||
// key: datastore.key(object.id ? [BlueprintEntity, datastore.int(object.id)] : [BlueprintEntity]),
|
||||
// data: [
|
||||
// { name: "label", value: object.label },
|
||||
// {
|
||||
// name: "description",
|
||||
// value: object.description || null,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "blueprint_hash", value: object.blueprint_hash },
|
||||
// { name: "image_hash", value: object.image_hash },
|
||||
// { name: "tags", value: object.tags || [] },
|
||||
// {
|
||||
// name: "created_at",
|
||||
// value: object.created_at ? new Date(object.created_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// {
|
||||
// name: "updated_at",
|
||||
// value: object.updated_at ? new Date(object.updated_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "game_version", value: object.game_version, excludeFromIndexes: true },
|
||||
// { name: "factorioprints_id", value: object.factorioprints_id || null },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// export async function getBlueprintById(id: string): Promise<Blueprint | null> {
|
||||
// const result = await datastore.get(datastore.key([BlueprintEntity, datastore.int(id)]));
|
||||
// return result[0] ? mapBlueprintEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function getBlueprintByHash(hash: string): Promise<Blueprint | null> {
|
||||
// const query = datastore.createQuery(BlueprintEntity).filter("blueprint_hash", "=", hash).limit(1);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result[0] ? mapBlueprintEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function getBlueprintByImageHash(hash: string): Promise<Blueprint | null> {
|
||||
// const query = datastore.createQuery(BlueprintEntity).filter("image_hash", "=", hash).limit(1);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result[0] ? mapBlueprintEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function createBlueprint(
|
||||
// blueprint: BlueprintStringData,
|
||||
// extraInfo: { tags: string[]; created_at: number; updated_at: number; factorioprints_id: string }
|
||||
// ) {
|
||||
// const string = await encodeBlueprint({ blueprint });
|
||||
// const blueprint_hash = hashString(string);
|
||||
// const image_hash = hashString(getBlueprintContentForImageHash(blueprint));
|
||||
|
||||
// const exists = await getBlueprintByHash(blueprint_hash);
|
||||
// if (exists) {
|
||||
// return { insertedId: exists.id };
|
||||
// }
|
||||
|
||||
// // Write string to google storage
|
||||
// await saveBlueprintString(blueprint_hash, string);
|
||||
|
||||
// // Write blueprint details to datastore
|
||||
// const [result] = await datastore.insert({
|
||||
// key: datastore.key([BlueprintEntity]),
|
||||
// data: [
|
||||
// { name: "label", value: blueprint.label },
|
||||
// {
|
||||
// name: "description",
|
||||
// value: blueprint.description || null,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "blueprint_hash", value: blueprint_hash },
|
||||
// { name: "image_hash", value: image_hash },
|
||||
// { name: "tags", value: extraInfo.tags ? extraInfo.tags : [] },
|
||||
// {
|
||||
// name: "created_at",
|
||||
// value: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// {
|
||||
// name: "updated_at",
|
||||
// value: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// { name: "game_version", value: blueprint.version, excludeFromIndexes: true },
|
||||
// { name: "factorioprints_id", value: extraInfo.factorioprints_id || null },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// const insertedId = String(result.mutationResults?.[0]?.key?.path?.[0]?.id);
|
||||
// if (!insertedId) throw Error("Something went wrong inserting entity");
|
||||
|
||||
// console.log(`Created Blueprint ${insertedId}`);
|
||||
|
||||
// blueprintImageRequestTopic.publishJSON({
|
||||
// blueprintId: insertedId,
|
||||
// });
|
||||
|
||||
// await datastore.insert({
|
||||
// key: datastore.key([BlueprintEntity, datastore.int(insertedId), BlueprintStringEntity]),
|
||||
// data: [
|
||||
// { name: "blueprint_hash", value: blueprint_hash },
|
||||
// { name: "image_hash", value: image_hash },
|
||||
// { name: "version", value: 1 },
|
||||
// { name: "changes_markdown", value: null },
|
||||
// {
|
||||
// name: "created_at",
|
||||
// value: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// return { insertedId };
|
||||
// }
|
||||
|
||||
// export async function updateBlueprint(blueprint: Blueprint) {
|
||||
// datastore.save(mapBlueprintObjectToEntity(blueprint));
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * BlueprintPage
|
||||
// */
|
||||
// const mapBlueprintPageEntityToObject = (entity: any): BlueprintPage => ({
|
||||
// id: entity[datastore.KEY].id,
|
||||
// blueprint_id: entity.blueprint_id ? entity.blueprint_id.id : null,
|
||||
// blueprint_book_id: entity.blueprint_book_id ? entity.blueprint_book_id.id : null,
|
||||
// title: entity.title,
|
||||
// description_markdown: entity.description_markdown,
|
||||
// created_at: entity.created_at && entity.created_at.getTime() / 1000,
|
||||
// updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
|
||||
// factorioprints_id: entity.factorioprints_id || null,
|
||||
// });
|
||||
|
||||
// export async function getBlueprintPageById(id: string): Promise<BlueprintPage | null> {
|
||||
// const result = await datastore.get(datastore.key([BlueprintPageEntity, datastore.int(id)]));
|
||||
// return result[0] ? mapBlueprintPageEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// export async function getBlueprintPageByFactorioprintsId(
|
||||
// id: string
|
||||
// ): Promise<BlueprintPage | null> {
|
||||
// const query = datastore
|
||||
// .createQuery(BlueprintPageEntity)
|
||||
// .filter("factorioprints_id", "=", id)
|
||||
// .limit(1);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result[0] ? mapBlueprintPageEntityToObject(result[0]) : null;
|
||||
// }
|
||||
|
||||
// async function createBlueprintPage(
|
||||
// type: "blueprint" | "blueprint_book",
|
||||
// targetId: string,
|
||||
// extraInfo: {
|
||||
// title: string;
|
||||
// description_markdown: string;
|
||||
// created_at: number;
|
||||
// updated_at: number;
|
||||
// factorioprints_id?: string;
|
||||
// }
|
||||
// ) {
|
||||
// const insertData: any = [
|
||||
// { name: "title", value: extraInfo.title },
|
||||
// {
|
||||
// name: "description_markdown",
|
||||
// value: extraInfo.description_markdown,
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// {
|
||||
// name: "created_at",
|
||||
// value: extraInfo.created_at ? new Date(extraInfo.created_at * 1000) : new Date(),
|
||||
// excludeFromIndexes: true,
|
||||
// },
|
||||
// {
|
||||
// name: "updated_at",
|
||||
// value: extraInfo.updated_at ? new Date(extraInfo.updated_at * 1000) : new Date(),
|
||||
// },
|
||||
// { name: "factorioprints_id", value: extraInfo.factorioprints_id || null },
|
||||
// ];
|
||||
|
||||
// if (type === "blueprint") {
|
||||
// insertData.push({
|
||||
// name: "blueprint_id",
|
||||
// value: datastore.key([BlueprintEntity, datastore.int(targetId)]),
|
||||
// });
|
||||
// } else if (type === "blueprint_book") {
|
||||
// insertData.push({
|
||||
// name: "blueprint_book_id",
|
||||
// value: datastore.key([BlueprintBookEntity, datastore.int(targetId)]),
|
||||
// });
|
||||
// } else {
|
||||
// throw Error("Invalid type given");
|
||||
// }
|
||||
|
||||
// await datastore.insert({
|
||||
// key: datastore.key([BlueprintPageEntity]),
|
||||
// data: insertData,
|
||||
// });
|
||||
|
||||
// console.log(`Created Blueprint Page`);
|
||||
// }
|
||||
|
||||
// /*
|
||||
// * Other
|
||||
// */
|
||||
|
||||
// interface BlueprintDataFromFactorioprints {
|
||||
// description_markdown: string;
|
||||
// title: string;
|
||||
// updated_at: number;
|
||||
// created_at: number;
|
||||
// tags: string[];
|
||||
// factorioprints_id: string;
|
||||
// }
|
||||
// export async function saveBlueprintFromFactorioprints(
|
||||
// factorioprintData: BlueprintDataFromFactorioprints,
|
||||
// blueprintString: string
|
||||
// ) {
|
||||
// const parsed = await parseBlueprintString(blueprintString);
|
||||
|
||||
// // not needed for inserting, just printing
|
||||
// // const { blueprints, books } = flattenBlueprintData(parsed.data);
|
||||
// // console.log(`string has ${books.length} books with ${blueprints.length} blueprints`);
|
||||
|
||||
// const extraInfo = {
|
||||
// created_at: factorioprintData.created_at,
|
||||
// updated_at: factorioprintData.updated_at,
|
||||
// tags: factorioprintData.tags,
|
||||
// factorioprints_id: factorioprintData.factorioprints_id,
|
||||
// };
|
||||
|
||||
// const extraInfoPage = {
|
||||
// title: factorioprintData.title,
|
||||
// description_markdown: factorioprintData.description_markdown,
|
||||
// created_at: factorioprintData.created_at,
|
||||
// updated_at: factorioprintData.updated_at,
|
||||
// factorioprints_id: factorioprintData.factorioprints_id,
|
||||
// };
|
||||
|
||||
// if (parsed.data.blueprint) {
|
||||
// console.log("string has one blueprint...");
|
||||
// const { insertedId } = await createBlueprint(parsed.data.blueprint, extraInfo).catch(
|
||||
// (error) => {
|
||||
// if (error instanceof DatastoreExistsError) {
|
||||
// console.log(`Blueprint already exists with id ${error.existingId}`);
|
||||
// return { insertedId: error.existingId };
|
||||
// } else throw error;
|
||||
// }
|
||||
// );
|
||||
// await createBlueprintPage("blueprint", insertedId, extraInfoPage);
|
||||
// } else if (parsed.data.blueprint_book) {
|
||||
// console.log("string has a blueprint book...");
|
||||
// const { insertedId } = await createBlueprintBook(parsed.data.blueprint_book, extraInfo);
|
||||
// await createBlueprintPage("blueprint_book", insertedId, extraInfoPage);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// export async function getMostRecentBlueprintPages(page = 1): Promise<BlueprintPage[]> {
|
||||
// const perPage = 10;
|
||||
// const query = datastore
|
||||
// .createQuery(BlueprintPageEntity)
|
||||
// .limit(perPage)
|
||||
// .offset((page - 1) * perPage);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result.map(mapBlueprintPageEntityToObject);
|
||||
// }
|
||||
|
||||
// export async function getPaginatedBlueprints(page = 1, perPage = 10): Promise<Blueprint[]> {
|
||||
// const query = datastore
|
||||
// .createQuery(BlueprintEntity)
|
||||
// .limit(perPage)
|
||||
// .offset((page - 1) * perPage);
|
||||
// const [result] = await datastore.runQuery(query);
|
||||
// return result.map(mapBlueprintEntityToObject);
|
||||
// }
|
@ -1,123 +1,40 @@
|
||||
import { Sequelize } from "sequelize";
|
||||
import { getBlueprintModel } from "./models/Blueprint";
|
||||
import { getBlueprintBookModel } from "./models/BlueprintBook";
|
||||
import { getBlueprintPageModel } from "./models/BlueprintPage";
|
||||
import { getUsertModel } from "./models/User";
|
||||
import { getSessionModel } from "./models/Session";
|
||||
import { getEnv, getEnvOrThrow, getSecretOrThrow } from "../env.util";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { getEnvOrThrow, getSecretOrThrow } from "../env.util";
|
||||
|
||||
const _init = async () => {
|
||||
if (_prisma) return _prisma;
|
||||
|
||||
const databasePassword = getEnvOrThrow("POSTGRES_PASSWORD");
|
||||
|
||||
const sequelize = new Sequelize({
|
||||
dialect: "postgres",
|
||||
host: getEnvOrThrow("POSTGRES_HOST"),
|
||||
port: 5432,
|
||||
database: getEnvOrThrow("POSTGRES_DB"),
|
||||
username: getEnvOrThrow("POSTGRES_USER"),
|
||||
password: databasePassword.startsWith("projects/")
|
||||
? await getSecretOrThrow(databasePassword)
|
||||
: databasePassword,
|
||||
define: {
|
||||
underscored: true,
|
||||
freezeTableName: true,
|
||||
updatedAt: "updated_at",
|
||||
createdAt: "created_at",
|
||||
const prisma = new PrismaClient({
|
||||
log: ["query", "info", "warn", "error"],
|
||||
datasources: {
|
||||
db: {
|
||||
url: `postgresql://${getEnvOrThrow("POSTGRES_USER")}:${await getSecretOrThrow(
|
||||
databasePassword
|
||||
)}@${getEnvOrThrow("POSTGRES_HOST")}:5432/${getEnvOrThrow("POSTGRES_DB")}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const UserModel = getUsertModel(sequelize);
|
||||
const SessionModel = getSessionModel(sequelize);
|
||||
const BlueprintModel = getBlueprintModel(sequelize);
|
||||
const BlueprintBookModel = getBlueprintBookModel(sequelize);
|
||||
const BlueprintPageModel = getBlueprintPageModel(sequelize);
|
||||
await prisma.$connect();
|
||||
|
||||
UserModel.hasMany(SessionModel, { foreignKey: "user_id" });
|
||||
|
||||
SessionModel.belongsTo(UserModel, { foreignKey: "user_id" });
|
||||
|
||||
BlueprintModel.hasMany(BlueprintPageModel, { foreignKey: "blueprint_id" });
|
||||
|
||||
BlueprintPageModel.belongsTo(BlueprintModel, { foreignKey: "blueprint_id" });
|
||||
BlueprintPageModel.belongsTo(BlueprintBookModel, { foreignKey: "blueprint_book_id" });
|
||||
|
||||
BlueprintBookModel.hasMany(BlueprintPageModel, { foreignKey: "blueprint_book_id" });
|
||||
BlueprintBookModel.belongsToMany(BlueprintBookModel, {
|
||||
through: "blueprint_book_books",
|
||||
as: "blueprint_books",
|
||||
foreignKey: "blueprint_book_1_id",
|
||||
otherKey: "blueprint_book_2_id",
|
||||
timestamps: false,
|
||||
});
|
||||
BlueprintBookModel.belongsToMany(BlueprintModel, {
|
||||
through: "blueprint_book_blueprints",
|
||||
as: "blueprints",
|
||||
foreignKey: "blueprint_book_id",
|
||||
otherKey: "blueprint_id",
|
||||
timestamps: false,
|
||||
});
|
||||
UserModel.belongsToMany(BlueprintPageModel, {
|
||||
through: "user_favorites",
|
||||
as: "favorites",
|
||||
foreignKey: "user_id",
|
||||
otherKey: "blueprint_page_id",
|
||||
});
|
||||
|
||||
// Test database connection, if it fails the method will throw
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log(`[DB] connecting to database ${sequelize.config.database}`);
|
||||
await sequelize.authenticate();
|
||||
}
|
||||
|
||||
if (getEnv("SYNCHRONIZE_DB")) {
|
||||
const sync_tables = getEnv("SYNCHRONIZE_DB")?.split(",") || [];
|
||||
console.log(`[SYNCHRONIZE_DB] syncing database`, { sync_tables });
|
||||
|
||||
for (const key in sequelize.models) {
|
||||
if (sync_tables.includes(key) || sync_tables.includes("*")) {
|
||||
await sequelize.models[key].sync({ force: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
sequelize,
|
||||
UserModel,
|
||||
SessionModel,
|
||||
BlueprintModel,
|
||||
BlueprintBookModel,
|
||||
BlueprintPageModel,
|
||||
};
|
||||
return prisma;
|
||||
};
|
||||
|
||||
const promise = _init()
|
||||
.then((result) => {
|
||||
_sequelize = result.sequelize;
|
||||
_UserModel = result.UserModel;
|
||||
_SessionModel = result.SessionModel;
|
||||
_BlueprintModel = result.BlueprintModel;
|
||||
_BlueprintBookModel = result.BlueprintBookModel;
|
||||
_BlueprintPageModel = result.BlueprintPageModel;
|
||||
_prisma = result;
|
||||
return result;
|
||||
})
|
||||
.catch((reason) => {
|
||||
console.log("Database failed to init!", reason);
|
||||
});
|
||||
|
||||
let _sequelize: Sequelize;
|
||||
let _UserModel: ReturnType<typeof getUsertModel>;
|
||||
let _SessionModel: ReturnType<typeof getSessionModel>;
|
||||
let _BlueprintModel: ReturnType<typeof getBlueprintModel>;
|
||||
let _BlueprintBookModel: ReturnType<typeof getBlueprintBookModel>;
|
||||
let _BlueprintPageModel: ReturnType<typeof getBlueprintPageModel>;
|
||||
let _prisma: PrismaClient;
|
||||
|
||||
export const init = async () => {
|
||||
return promise;
|
||||
};
|
||||
|
||||
export const sequelize = () => _sequelize;
|
||||
export const UserModel = () => _UserModel;
|
||||
export const SessionModel = () => _SessionModel;
|
||||
export const BlueprintModel = () => _BlueprintModel;
|
||||
export const BlueprintBookModel = () => _BlueprintBookModel;
|
||||
export const BlueprintPageModel = () => _BlueprintPageModel;
|
||||
export const prisma = () => _prisma;
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { QueryInterface, Sequelize } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
||||
queryInterface.createTable("user", {});
|
||||
},
|
||||
async down(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
||||
//
|
||||
},
|
||||
};
|
86
package.json
86
package.json
@ -24,76 +24,79 @@
|
||||
"update": "nx migrate latest",
|
||||
"workspace-schematic": "nx workspace-schematic",
|
||||
"dep-graph": "nx dep-graph",
|
||||
"help": "nx help"
|
||||
"help": "nx help",
|
||||
"db-gen": "npx prisma generate --schema=./apps/blueprints/prisma/schema.prisma",
|
||||
"preinstall": "npx yalc add @fbe/editor"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chakra-ui/react": "1.1.2",
|
||||
"@emotion/react": "11.1.4",
|
||||
"@chakra-ui/react": "1.3.3",
|
||||
"@emotion/react": "11.1.5",
|
||||
"@emotion/server": "11.0.0",
|
||||
"@emotion/styled": "11.0.0",
|
||||
"@fbe/editor": "./fbe-editor-v1.0.0.tgz",
|
||||
"@emotion/styled": "11.1.5",
|
||||
"@fbe/editor": "file:.yalc/@fbe/editor",
|
||||
"@google-cloud/datastore": "6.3.1",
|
||||
"@google-cloud/pubsub": "2.7.0",
|
||||
"@google-cloud/secret-manager": "3.2.3",
|
||||
"@google-cloud/storage": "5.7.0",
|
||||
"@hookstate/core": "3.0.3",
|
||||
"@google-cloud/pubsub": "2.9.0",
|
||||
"@google-cloud/secret-manager": "3.4.0",
|
||||
"@google-cloud/storage": "5.7.4",
|
||||
"@hookstate/core": "3.0.5",
|
||||
"@prisma/client": "2.18.0",
|
||||
"bbcode-to-react": "0.2.9",
|
||||
"bcrypt": "5.0.0",
|
||||
"cookie": "0.4.1",
|
||||
"document-register-element": "1.14.10",
|
||||
"formik": "2.2.6",
|
||||
"framer-motion": "3.1.4",
|
||||
"next": "10.0.5",
|
||||
"framer-motion": "3.3.0",
|
||||
"next": "10.0.7",
|
||||
"nprogress": "0.2.0",
|
||||
"openid": "2.0.7",
|
||||
"pako": "1.0.11",
|
||||
"pg": "8.5.1",
|
||||
"phin": "3.5.1",
|
||||
"puppeteer": "5.5.0",
|
||||
"puppeteer": "7.1.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react-icons": "4.1.0",
|
||||
"react-icons": "4.2.0",
|
||||
"react-map-interaction": "2.0.0",
|
||||
"react-markdown": "5.0.3",
|
||||
"sequelize": "6.3.5",
|
||||
"sharp": "0.27.0",
|
||||
"ws": "7.4.2"
|
||||
"react-multi-select-component": "3.1.3",
|
||||
"sharp": "0.27.1",
|
||||
"ws": "7.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.12.10",
|
||||
"@babel/preset-env": "7.12.11",
|
||||
"@babel/preset-react": "7.12.10",
|
||||
"@babel/preset-typescript": "7.12.7",
|
||||
"@nrwl/cli": "11.0.20",
|
||||
"@nrwl/cypress": "11.0.20",
|
||||
"@nrwl/eslint-plugin-nx": "11.0.20",
|
||||
"@nrwl/jest": "11.0.20",
|
||||
"@nrwl/next": "11.0.20",
|
||||
"@nrwl/node": "11.0.20",
|
||||
"@nrwl/react": "11.0.20",
|
||||
"@nrwl/web": "11.0.20",
|
||||
"@nrwl/workspace": "11.0.20",
|
||||
"@testing-library/react": "11.2.2",
|
||||
"@babel/core": "7.12.16",
|
||||
"@babel/preset-env": "7.12.16",
|
||||
"@babel/preset-react": "7.12.13",
|
||||
"@babel/preset-typescript": "7.12.16",
|
||||
"@nrwl/cli": "11.2.12",
|
||||
"@nrwl/cypress": "11.2.12",
|
||||
"@nrwl/eslint-plugin-nx": "11.2.12",
|
||||
"@nrwl/jest": "11.2.12",
|
||||
"@nrwl/next": "11.2.12",
|
||||
"@nrwl/node": "11.2.12",
|
||||
"@nrwl/react": "11.2.12",
|
||||
"@nrwl/web": "11.2.12",
|
||||
"@nrwl/workspace": "11.2.12",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@types/bbcode-to-react": "0.2.0",
|
||||
"@types/bcrypt": "3.0.0",
|
||||
"@types/cookie": "0.4.0",
|
||||
"@types/jest": "26.0.20",
|
||||
"@types/node": "14.14.14",
|
||||
"@types/node": "14.14.28",
|
||||
"@types/nprogress": "0.2.0",
|
||||
"@types/openid": "2.0.1",
|
||||
"@types/pako": "1.0.1",
|
||||
"@types/puppeteer": "5.4.2",
|
||||
"@types/react": "17.0.0",
|
||||
"@types/react-dom": "17.0.0",
|
||||
"@types/puppeteer": "5.4.3",
|
||||
"@types/react": "17.0.2",
|
||||
"@types/react-dom": "17.0.1",
|
||||
"@types/sharp": "0.27.1",
|
||||
"@types/ws": "7.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.12.0",
|
||||
"@typescript-eslint/parser": "4.12.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.15.1",
|
||||
"@typescript-eslint/parser": "4.15.1",
|
||||
"babel-jest": "26.6.3",
|
||||
"cypress": "6.2.1",
|
||||
"cypress": "6.4.0",
|
||||
"dotenv": "8.2.0",
|
||||
"eslint": "7.17.0",
|
||||
"eslint-config-prettier": "7.1.0",
|
||||
"eslint": "7.20.0",
|
||||
"eslint-config-prettier": "7.2.0",
|
||||
"eslint-plugin-cypress": "2.11.2",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||
@ -101,10 +104,11 @@
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"prisma": "2.18.0",
|
||||
"ts-jest": "26.5.1",
|
||||
"ts-node": "9.1.1",
|
||||
"tslint": "6.1.3",
|
||||
"typescript": "4.1.3",
|
||||
"typescript": "4.1.5",
|
||||
"wasm-loader": "1.3.0"
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,9 @@
|
||||
"version": "v1",
|
||||
"packages": {
|
||||
"@fbe/editor": {
|
||||
"signature": "fcd9eadabd31e2c2000a5ea3e4b000f8",
|
||||
"file": true
|
||||
"signature": "4394b199f59f3db8ce4aa6b1c9801472",
|
||||
"file": true,
|
||||
"replaced": "./fbe-editor-v1.0.0.tgz"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user