diff --git a/apps/blueprints/prisma/migrations/20210310204136_blueprint_page_user/migration.sql b/apps/blueprints/prisma/migrations/20210310204136_blueprint_page_user/migration.sql new file mode 100644 index 0000000..4ddc433 --- /dev/null +++ b/apps/blueprints/prisma/migrations/20210310204136_blueprint_page_user/migration.sql @@ -0,0 +1,2 @@ +-- AddForeignKey +ALTER TABLE "blueprint_page" ADD FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/blueprints/prisma/schema.prisma b/apps/blueprints/prisma/schema.prisma index d5e803f..60ff524 100644 --- a/apps/blueprints/prisma/schema.prisma +++ b/apps/blueprints/prisma/schema.prisma @@ -60,6 +60,7 @@ model blueprint_page { blueprint_book blueprint_book? @relation(fields: [blueprint_book_id], references: [id]) blueprint blueprint? @relation(fields: [blueprint_id], references: [id]) user_favorites user_favorites[] + user user? @relation(fields: [user_id], references: [id]) } model session { @@ -92,6 +93,7 @@ model user { updated_at DateTime @updatedAt session session[] user_favorites user_favorites[] + blueprint_pages blueprint_page[] } model user_favorites { diff --git a/apps/blueprints/src/pages/blueprint/[blueprintId].tsx b/apps/blueprints/src/pages/blueprint/[blueprintId].tsx index c6f0a9a..26e7089 100644 --- a/apps/blueprints/src/pages/blueprint/[blueprintId].tsx +++ b/apps/blueprints/src/pages/blueprint/[blueprintId].tsx @@ -1,11 +1,12 @@ import React, { useEffect, useState } from "react"; import { NextPage } from "next"; +import Link from "next/link"; import BBCode from "bbcode-to-react"; import { Button, Grid, Image } from "@chakra-ui/react"; import { getBlueprintBookById, getBlueprintById, - getBlueprintPageById, + getBlueprintPageWithUserById, isBlueprintPageUserFavorite, } from "@factorio-sites/database"; import { @@ -92,7 +93,7 @@ export const Index: NextPage = ({ .then((res) => res.text()) .then((string) => { const data = parseBlueprintStringClient(string); - console.log("data", data); + // console.log("data", data); if (data && blueprint_book) { setBookChildTreeData( mergeBlueprintDataAndChildTree(data, { @@ -185,7 +186,15 @@ export const Index: NextPage = ({ User - - + + {blueprint_page.user ? ( + + {blueprint_page.user?.username} + + ) : ( + "-" + )} + Tags @@ -362,8 +371,8 @@ export const getServerSideProps = pageHandler(async (context, { session }) => { if (!blueprintId) return throwError("Blueprint ID not found"); - const blueprint_page = await getBlueprintPageById(blueprintId); - tl("getBlueprintPageById"); + const blueprint_page = await getBlueprintPageWithUserById(blueprintId); + tl("getBlueprintPageWithUserById"); if (!blueprint_page) return throwError("Blueprint page not found"); diff --git a/apps/blueprints/src/pages/index.tsx b/apps/blueprints/src/pages/index.tsx index 277e26c..6e97917 100644 --- a/apps/blueprints/src/pages/index.tsx +++ b/apps/blueprints/src/pages/index.tsx @@ -156,6 +156,7 @@ export async function getServerSideProps({ query }: NextPageContext) { const entities = query.entities ? String(query.entities).split(",") : undefined; const items = query.items ? String(query.items).split(",") : undefined; const recipes = query.recipes ? String(query.recipes).split(",") : undefined; + const user = query.user ? String(query.user) : undefined; const { count, rows } = await searchBlueprintPages({ page, @@ -166,6 +167,7 @@ export async function getServerSideProps({ query }: NextPageContext) { entities, items, recipes, + user, }); return { diff --git a/libs/database/src/lib/data/blueprint_page.ts b/libs/database/src/lib/data/blueprint_page.ts index 029eea4..db4ad71 100644 --- a/libs/database/src/lib/data/blueprint_page.ts +++ b/libs/database/src/lib/data/blueprint_page.ts @@ -1,15 +1,18 @@ -import { blueprint_page } from "@prisma/client"; +import { blueprint_page, user } from "@prisma/client"; import { join, raw, sqltag } from "@prisma/client/runtime"; import { getBlueprintImageRequestTopic } from "../gcp-pubsub"; import { prisma } from "../postgres/database"; import { BlueprintPage, ChildTree } from "@factorio-sites/types"; -import { getBlueprintBookById } from "./blueprint_book"; +// import { getBlueprintBookById } from "./blueprint_book"; import { getAllBlueprintsFromChildTree, getFirstBlueprintFromChildTree, } from "@factorio-sites/node-utils"; -const mapBlueprintPageEntityToObject = (entity: blueprint_page): BlueprintPage => ({ +const mapBlueprintPageEntityToObject = ( + entity: blueprint_page, + user?: { id: string; username: string } +): BlueprintPage => ({ id: entity.id, blueprint_id: entity.blueprint_id ?? null, blueprint_book_id: entity.blueprint_book_id ?? null, @@ -21,6 +24,7 @@ const mapBlueprintPageEntityToObject = (entity: blueprint_page): BlueprintPage = updated_at: entity.updated_at && entity.updated_at.getTime() / 1000, factorioprints_id: entity.factorioprints_id ?? null, favorite_count: (entity as any).favorite_count || null, + user: user || null, }); export async function getBlueprintPageById(id: string): Promise { @@ -33,6 +37,13 @@ export async function getBlueprintPageByUserId(user_id: string): Promise mapBlueprintPageEntityToObject(result)) : null; } +export async function getBlueprintPageWithUserById( + id: string +): Promise<(BlueprintPage & { user: { id: string; username: string } | null }) | null> { + const result = await prisma.blueprint_page.findUnique({ where: { id }, include: { user: true } }); + return result ? mapBlueprintPageEntityToObject(result, result.user) : null; +} + export async function getBlueprintPageByFactorioprintsId( id: string ): Promise { @@ -49,6 +60,7 @@ export async function searchBlueprintPages({ entities, items, recipes, + user, }: { page: number; perPage: number; @@ -58,6 +70,7 @@ export async function searchBlueprintPages({ entities?: string[]; items?: string[]; recipes?: string[]; + user?: string; }): Promise<{ count: number; rows: BlueprintPage[] }> { const orderMap: Record = { date: "blueprint_page.updated_at", @@ -80,39 +93,50 @@ export async function searchBlueprintPages({ const tagsFragment = tags ? sqltag`AND blueprint_page.tags @> array[${join(tags)}::varchar]` : sqltag``; + const userFragment = user ? sqltag`AND blueprint_page.user_id = ${user}` : sqltag``; - const result = ( - await prisma.$queryRaw<(blueprint_page & { favorite_count: number })[]>` - SELECT DISTINCT blueprint_page.*, (SELECT COUNT(*) FROM user_favorites where user_favorites.blueprint_page_id = blueprint_page.id) AS favorite_count - FROM public.blueprint_page - ${blueprintDataSearch} - WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} - ${entitiesFragment} - ${itemsFragment} - ${recipesFragment} - ${tagsFragment} - ORDER BY ${raw(orderMap[order] || orderMap.date)} DESC - LIMIT ${perPage} OFFSET ${(page - 1) * perPage}` - ).map((blueprintPage) => ({ - ...blueprintPage, - created_at: new Date(blueprintPage.created_at), - updated_at: new Date(blueprintPage.updated_at), - })); + try { + const result = ( + await prisma.$queryRaw<(blueprint_page & { favorite_count: number })[]>` + SELECT DISTINCT blueprint_page.*, (SELECT COUNT(*) FROM user_favorites where user_favorites.blueprint_page_id = blueprint_page.id) AS favorite_count + FROM public.blueprint_page + ${blueprintDataSearch} + WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} + ${entitiesFragment} + ${itemsFragment} + ${recipesFragment} + ${tagsFragment} + ${userFragment} + ORDER BY ${raw(orderMap[order] || orderMap.date)} DESC + LIMIT ${perPage} OFFSET ${(page - 1) * perPage}` + ).map((blueprintPage) => ({ + ...blueprintPage, + created_at: new Date(blueprintPage.created_at), + updated_at: new Date(blueprintPage.updated_at), + })); - const countResult = await prisma.$queryRaw<{ count: number }[]>` - SELECT COUNT(DISTINCT blueprint_page.id) - FROM public.blueprint_page - ${blueprintDataSearch} - WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} - ${entitiesFragment} - ${itemsFragment} - ${recipesFragment} - ${tagsFragment}`; + const countResult = await prisma.$queryRaw<{ count: number }[]>` + SELECT COUNT(DISTINCT blueprint_page.id) + FROM public.blueprint_page + ${blueprintDataSearch} + WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} + ${entitiesFragment} + ${itemsFragment} + ${recipesFragment} + ${tagsFragment} + ${userFragment}`; - return { - count: countResult[0].count, - rows: result.map(mapBlueprintPageEntityToObject), - }; + return { + count: countResult[0].count, + rows: result.map(mapBlueprintPageEntityToObject), + }; + } catch (err) { + console.error(err); + return { + count: 0, + rows: [], + }; + } } export async function createBlueprintPage( @@ -120,7 +144,7 @@ export async function createBlueprintPage( targetId: string, data: { title: string; - user_id: string | null; + user_id?: string; description_markdown: string; tags?: string[]; image_hash: string; @@ -132,7 +156,7 @@ export async function createBlueprintPage( ) { const page = await prisma.blueprint_page.create({ data: { - user_id: data.user_id, + user_id: data.user_id || null, title: data.title, description_markdown: data.description_markdown, factorioprints_id: data.factorioprints_id, @@ -170,7 +194,7 @@ export async function editBlueprintPage( targetId: string, extraInfo: { title: string; - user_id: string | null; + user_id?: string; description_markdown: string; tags?: string[]; created_at?: number; @@ -181,7 +205,7 @@ export async function editBlueprintPage( const page = await prisma.blueprint_page.update({ where: { id: blueprintPageId }, data: { - user_id: extraInfo.user_id, + user_id: extraInfo.user_id || null, title: extraInfo.title, description_markdown: extraInfo.description_markdown, factorioprints_id: extraInfo.factorioprints_id, diff --git a/libs/database/src/lib/data/factorioprints.ts b/libs/database/src/lib/data/factorioprints.ts index b72c284..7cac877 100644 --- a/libs/database/src/lib/data/factorioprints.ts +++ b/libs/database/src/lib/data/factorioprints.ts @@ -10,6 +10,7 @@ interface BlueprintDataFromFactorioprints { created_at?: number; tags: string[]; factorioprints_id: string; + user_id: string; } export async function saveBlueprintFromFactorioprints( factorioprintData: BlueprintDataFromFactorioprints, @@ -28,7 +29,7 @@ export async function saveBlueprintFromFactorioprints( }; const extraInfoPage = { - user_id: null, + user_id: factorioprintData.user_id, title: factorioprintData.title, description_markdown: factorioprintData.description_markdown, created_at: factorioprintData.created_at, diff --git a/libs/types/src/lib/data-models.ts b/libs/types/src/lib/data-models.ts index 019fcfa..f2010ae 100644 --- a/libs/types/src/lib/data-models.ts +++ b/libs/types/src/lib/data-models.ts @@ -1,5 +1,4 @@ import { Signal } from "./blueprint-string"; - export interface ChildTreeBlueprint { type: "blueprint"; id: string; @@ -54,6 +53,7 @@ export interface BlueprintPage { updated_at: number; factorioprints_id: string | null; favorite_count?: number; + user: { id: string; username: string } | null; // BlueprintPageEntry->BlueprintEntry 1:m // BlueprintPageEntry->BlueprintBook 1:m }