1
0
mirror of https://github.com/barthuijgen/factorio-sites.git synced 2025-01-09 14:45:40 +02:00

Added user for blueprint_page and user filter query for main page (#4)

* Added user for blueprint_page and user filter query for main page

* Added sql error catch, comments related fixes

* Comments related fixes #2
This commit is contained in:
Alexander Horbunov 2021-03-10 23:18:40 +02:00 committed by GitHub
parent 21aaf8519d
commit 843b7e715f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 84 additions and 44 deletions

View File

@ -0,0 +1,2 @@
-- AddForeignKey
ALTER TABLE "blueprint_page" ADD FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@ -60,6 +60,7 @@ model blueprint_page {
blueprint_book blueprint_book? @relation(fields: [blueprint_book_id], references: [id]) blueprint_book blueprint_book? @relation(fields: [blueprint_book_id], references: [id])
blueprint blueprint? @relation(fields: [blueprint_id], references: [id]) blueprint blueprint? @relation(fields: [blueprint_id], references: [id])
user_favorites user_favorites[] user_favorites user_favorites[]
user user? @relation(fields: [user_id], references: [id])
} }
model session { model session {
@ -92,6 +93,7 @@ model user {
updated_at DateTime @updatedAt updated_at DateTime @updatedAt
session session[] session session[]
user_favorites user_favorites[] user_favorites user_favorites[]
blueprint_pages blueprint_page[]
} }
model user_favorites { model user_favorites {

View File

@ -1,11 +1,12 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import Link from "next/link";
import BBCode from "bbcode-to-react"; import BBCode from "bbcode-to-react";
import { Button, Grid, Image } from "@chakra-ui/react"; import { Button, Grid, Image } from "@chakra-ui/react";
import { import {
getBlueprintBookById, getBlueprintBookById,
getBlueprintById, getBlueprintById,
getBlueprintPageById, getBlueprintPageWithUserById,
isBlueprintPageUserFavorite, isBlueprintPageUserFavorite,
} from "@factorio-sites/database"; } from "@factorio-sites/database";
import { import {
@ -92,7 +93,7 @@ export const Index: NextPage<IndexProps> = ({
.then((res) => res.text()) .then((res) => res.text())
.then((string) => { .then((string) => {
const data = parseBlueprintStringClient(string); const data = parseBlueprintStringClient(string);
console.log("data", data); // console.log("data", data);
if (data && blueprint_book) { if (data && blueprint_book) {
setBookChildTreeData( setBookChildTreeData(
mergeBlueprintDataAndChildTree(data, { mergeBlueprintDataAndChildTree(data, {
@ -185,7 +186,15 @@ export const Index: NextPage<IndexProps> = ({
<tbody> <tbody>
<tr> <tr>
<td>User</td> <td>User</td>
<td>-</td> <td>
{blueprint_page.user ? (
<Link href={`/?user=${blueprint_page.user?.id}`}>
<a>{blueprint_page.user?.username}</a>
</Link>
) : (
"-"
)}
</td>
</tr> </tr>
<tr> <tr>
<td>Tags</td> <td>Tags</td>
@ -362,8 +371,8 @@ export const getServerSideProps = pageHandler(async (context, { session }) => {
if (!blueprintId) return throwError("Blueprint ID not found"); if (!blueprintId) return throwError("Blueprint ID not found");
const blueprint_page = await getBlueprintPageById(blueprintId); const blueprint_page = await getBlueprintPageWithUserById(blueprintId);
tl("getBlueprintPageById"); tl("getBlueprintPageWithUserById");
if (!blueprint_page) return throwError("Blueprint page not found"); if (!blueprint_page) return throwError("Blueprint page not found");

View File

@ -156,6 +156,7 @@ export async function getServerSideProps({ query }: NextPageContext) {
const entities = query.entities ? String(query.entities).split(",") : undefined; const entities = query.entities ? String(query.entities).split(",") : undefined;
const items = query.items ? String(query.items).split(",") : undefined; const items = query.items ? String(query.items).split(",") : undefined;
const recipes = query.recipes ? String(query.recipes).split(",") : undefined; const recipes = query.recipes ? String(query.recipes).split(",") : undefined;
const user = query.user ? String(query.user) : undefined;
const { count, rows } = await searchBlueprintPages({ const { count, rows } = await searchBlueprintPages({
page, page,
@ -166,6 +167,7 @@ export async function getServerSideProps({ query }: NextPageContext) {
entities, entities,
items, items,
recipes, recipes,
user,
}); });
return { return {

View File

@ -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 { join, raw, sqltag } from "@prisma/client/runtime";
import { getBlueprintImageRequestTopic } from "../gcp-pubsub"; import { getBlueprintImageRequestTopic } from "../gcp-pubsub";
import { prisma } from "../postgres/database"; import { prisma } from "../postgres/database";
import { BlueprintPage, ChildTree } from "@factorio-sites/types"; import { BlueprintPage, ChildTree } from "@factorio-sites/types";
import { getBlueprintBookById } from "./blueprint_book"; // import { getBlueprintBookById } from "./blueprint_book";
import { import {
getAllBlueprintsFromChildTree, getAllBlueprintsFromChildTree,
getFirstBlueprintFromChildTree, getFirstBlueprintFromChildTree,
} from "@factorio-sites/node-utils"; } 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, id: entity.id,
blueprint_id: entity.blueprint_id ?? null, blueprint_id: entity.blueprint_id ?? null,
blueprint_book_id: entity.blueprint_book_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, updated_at: entity.updated_at && entity.updated_at.getTime() / 1000,
factorioprints_id: entity.factorioprints_id ?? null, factorioprints_id: entity.factorioprints_id ?? null,
favorite_count: (entity as any).favorite_count || null, favorite_count: (entity as any).favorite_count || null,
user: user || null,
}); });
export async function getBlueprintPageById(id: string): Promise<BlueprintPage | null> { export async function getBlueprintPageById(id: string): Promise<BlueprintPage | null> {
@ -33,6 +37,13 @@ export async function getBlueprintPageByUserId(user_id: string): Promise<Bluepri
return results ? results.map((result) => mapBlueprintPageEntityToObject(result)) : null; return results ? results.map((result) => 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( export async function getBlueprintPageByFactorioprintsId(
id: string id: string
): Promise<BlueprintPage | null> { ): Promise<BlueprintPage | null> {
@ -49,6 +60,7 @@ export async function searchBlueprintPages({
entities, entities,
items, items,
recipes, recipes,
user,
}: { }: {
page: number; page: number;
perPage: number; perPage: number;
@ -58,6 +70,7 @@ export async function searchBlueprintPages({
entities?: string[]; entities?: string[];
items?: string[]; items?: string[];
recipes?: string[]; recipes?: string[];
user?: string;
}): Promise<{ count: number; rows: BlueprintPage[] }> { }): Promise<{ count: number; rows: BlueprintPage[] }> {
const orderMap: Record<string, string> = { const orderMap: Record<string, string> = {
date: "blueprint_page.updated_at", date: "blueprint_page.updated_at",
@ -80,39 +93,50 @@ export async function searchBlueprintPages({
const tagsFragment = tags const tagsFragment = tags
? sqltag`AND blueprint_page.tags @> array[${join(tags)}::varchar]` ? sqltag`AND blueprint_page.tags @> array[${join(tags)}::varchar]`
: sqltag``; : sqltag``;
const userFragment = user ? sqltag`AND blueprint_page.user_id = ${user}` : sqltag``;
const result = ( try {
await prisma.$queryRaw<(blueprint_page & { favorite_count: number })[]>` const result = (
SELECT DISTINCT blueprint_page.*, (SELECT COUNT(*) FROM user_favorites where user_favorites.blueprint_page_id = blueprint_page.id) AS favorite_count await prisma.$queryRaw<(blueprint_page & { favorite_count: number })[]>`
FROM public.blueprint_page SELECT DISTINCT blueprint_page.*, (SELECT COUNT(*) FROM user_favorites where user_favorites.blueprint_page_id = blueprint_page.id) AS favorite_count
${blueprintDataSearch} FROM public.blueprint_page
WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} ${blueprintDataSearch}
${entitiesFragment} WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"}
${itemsFragment} ${entitiesFragment}
${recipesFragment} ${itemsFragment}
${tagsFragment} ${recipesFragment}
ORDER BY ${raw(orderMap[order] || orderMap.date)} DESC ${tagsFragment}
LIMIT ${perPage} OFFSET ${(page - 1) * perPage}` ${userFragment}
).map((blueprintPage) => ({ ORDER BY ${raw(orderMap[order] || orderMap.date)} DESC
...blueprintPage, LIMIT ${perPage} OFFSET ${(page - 1) * perPage}`
created_at: new Date(blueprintPage.created_at), ).map((blueprintPage) => ({
updated_at: new Date(blueprintPage.updated_at), ...blueprintPage,
})); created_at: new Date(blueprintPage.created_at),
updated_at: new Date(blueprintPage.updated_at),
}));
const countResult = await prisma.$queryRaw<{ count: number }[]>` const countResult = await prisma.$queryRaw<{ count: number }[]>`
SELECT COUNT(DISTINCT blueprint_page.id) SELECT COUNT(DISTINCT blueprint_page.id)
FROM public.blueprint_page FROM public.blueprint_page
${blueprintDataSearch} ${blueprintDataSearch}
WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"} WHERE blueprint_page.title ILIKE ${query ? `%${query}%` : "%"}
${entitiesFragment} ${entitiesFragment}
${itemsFragment} ${itemsFragment}
${recipesFragment} ${recipesFragment}
${tagsFragment}`; ${tagsFragment}
${userFragment}`;
return { return {
count: countResult[0].count, count: countResult[0].count,
rows: result.map(mapBlueprintPageEntityToObject), rows: result.map(mapBlueprintPageEntityToObject),
}; };
} catch (err) {
console.error(err);
return {
count: 0,
rows: [],
};
}
} }
export async function createBlueprintPage( export async function createBlueprintPage(
@ -120,7 +144,7 @@ export async function createBlueprintPage(
targetId: string, targetId: string,
data: { data: {
title: string; title: string;
user_id: string | null; user_id?: string;
description_markdown: string; description_markdown: string;
tags?: string[]; tags?: string[];
image_hash: string; image_hash: string;
@ -132,7 +156,7 @@ export async function createBlueprintPage(
) { ) {
const page = await prisma.blueprint_page.create({ const page = await prisma.blueprint_page.create({
data: { data: {
user_id: data.user_id, user_id: data.user_id || null,
title: data.title, title: data.title,
description_markdown: data.description_markdown, description_markdown: data.description_markdown,
factorioprints_id: data.factorioprints_id, factorioprints_id: data.factorioprints_id,
@ -170,7 +194,7 @@ export async function editBlueprintPage(
targetId: string, targetId: string,
extraInfo: { extraInfo: {
title: string; title: string;
user_id: string | null; user_id?: string;
description_markdown: string; description_markdown: string;
tags?: string[]; tags?: string[];
created_at?: number; created_at?: number;
@ -181,7 +205,7 @@ export async function editBlueprintPage(
const page = await prisma.blueprint_page.update({ const page = await prisma.blueprint_page.update({
where: { id: blueprintPageId }, where: { id: blueprintPageId },
data: { data: {
user_id: extraInfo.user_id, user_id: extraInfo.user_id || null,
title: extraInfo.title, title: extraInfo.title,
description_markdown: extraInfo.description_markdown, description_markdown: extraInfo.description_markdown,
factorioprints_id: extraInfo.factorioprints_id, factorioprints_id: extraInfo.factorioprints_id,

View File

@ -10,6 +10,7 @@ interface BlueprintDataFromFactorioprints {
created_at?: number; created_at?: number;
tags: string[]; tags: string[];
factorioprints_id: string; factorioprints_id: string;
user_id: string;
} }
export async function saveBlueprintFromFactorioprints( export async function saveBlueprintFromFactorioprints(
factorioprintData: BlueprintDataFromFactorioprints, factorioprintData: BlueprintDataFromFactorioprints,
@ -28,7 +29,7 @@ export async function saveBlueprintFromFactorioprints(
}; };
const extraInfoPage = { const extraInfoPage = {
user_id: null, user_id: factorioprintData.user_id,
title: factorioprintData.title, title: factorioprintData.title,
description_markdown: factorioprintData.description_markdown, description_markdown: factorioprintData.description_markdown,
created_at: factorioprintData.created_at, created_at: factorioprintData.created_at,

View File

@ -1,5 +1,4 @@
import { Signal } from "./blueprint-string"; import { Signal } from "./blueprint-string";
export interface ChildTreeBlueprint { export interface ChildTreeBlueprint {
type: "blueprint"; type: "blueprint";
id: string; id: string;
@ -54,6 +53,7 @@ export interface BlueprintPage {
updated_at: number; updated_at: number;
factorioprints_id: string | null; factorioprints_id: string | null;
favorite_count?: number; favorite_count?: number;
user: { id: string; username: string } | null;
// BlueprintPageEntry->BlueprintEntry 1:m // BlueprintPageEntry->BlueprintEntry 1:m
// BlueprintPageEntry->BlueprintBook 1:m // BlueprintPageEntry->BlueprintBook 1:m
} }