Entry endpoints

This commit is contained in:
2024-10-11 01:30:52 -03:00
parent 9a245129e7
commit ce6cf91c77
7 changed files with 190 additions and 9 deletions

View File

@@ -21,6 +21,7 @@
"@trpc/client": "^11.0.0-rc.446",
"@trpc/react-query": "^11.0.0-rc.446",
"@trpc/server": "^11.0.0-rc.446",
"cloudinary": "^2.5.1",
"geist": "^1.3.0",
"next": "^14.2.4",
"react": "^18.3.1",

33
pnpm-lock.yaml generated
View File

@@ -26,6 +26,9 @@ importers:
'@trpc/server':
specifier: ^11.0.0-rc.446
version: 11.0.0-rc.566
cloudinary:
specifier: ^2.5.1
version: 2.5.1
geist:
specifier: ^1.3.0
version: 1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
@@ -547,6 +550,10 @@ packages:
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
cloudinary@2.5.1:
resolution: {integrity: sha512-CNg6uU53Hl4FEVynkTGpt5bQEAQWDHi3H+Sm62FzKf5uQHipSN2v7qVqS8GRVqeb0T1WNV+22+75DOJeRXYeSQ==}
engines: {node: '>=9'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -1182,6 +1189,9 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -1485,6 +1495,14 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
q@1.5.1:
resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==}
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
deprecated: |-
You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.
(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
qs@6.13.0:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
engines: {node: '>=0.6'}
@@ -2293,6 +2311,11 @@ snapshots:
client-only@0.0.1: {}
cloudinary@2.5.1:
dependencies:
lodash: 4.17.21
q: 1.5.1
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@@ -2553,7 +2576,7 @@ snapshots:
debug: 4.3.7
enhanced-resolve: 5.17.1
eslint: 8.57.1
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
fast-glob: 3.3.2
get-tsconfig: 4.8.1
is-bun-module: 1.2.1
@@ -2566,7 +2589,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1):
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -2588,7 +2611,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.1(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3
@@ -3094,6 +3117,8 @@ snapshots:
lodash.merge@4.6.2: {}
lodash@4.17.21: {}
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -3328,6 +3353,8 @@ snapshots:
punycode@2.3.1: {}
q@1.5.1: {}
qs@6.13.0:
dependencies:
side-channel: 1.0.6

View File

@@ -19,7 +19,15 @@ model Post {
@@index([name])
}
model KeyValue {
model SpookyImage {
id Int @id @default(autoincrement()) // Auto-incrementing ID
key String @unique // The key must be unique
value String // Value associated with the key
createdAt DateTime @default(now()) // Timestamp for when the entry was created
updatedAt DateTime @updatedAt // Auto-updating timestamp for when the entry was last updated
}
model GeneratedImage {
id Int @id @default(autoincrement()) // Auto-incrementing ID
key String @unique // The key must be unique
value String // Value associated with the key

View File

@@ -36,11 +36,6 @@ export default async function Home({
}
void api.post.getLatest.prefetch();
console.log({
access_token,
refresh_token,
});
return (
<HydrateClient>
<main className="justify-centerbg-gradient-to-r flex min-h-screen flex-col items-center bg-gradient-to-r from-slate-900 to-slate-700 text-slate-200">

View File

@@ -1,5 +1,11 @@
import { postRouter } from "@/server/api/routers/post";
import { createCallerFactory, createTRPCRouter } from "@/server/api/trpc";
import * as cloudinary from "cloudinary";
import { entryRouter } from "./routers/entry";
cloudinary.v2.config({
secure: true,
});
/**
* This is the primary router for your server.
@@ -8,6 +14,7 @@ import { createCallerFactory, createTRPCRouter } from "@/server/api/trpc";
*/
export const appRouter = createTRPCRouter({
post: postRouter,
entry: entryRouter,
});
// export type definition of API

View File

@@ -0,0 +1,106 @@
import { z } from "zod";
import { createTRPCRouter, publicProcedure } from "@/server/api/trpc";
import {
generateEntryUniqueKey,
makeImageSpooky,
uploadImage,
} from "@/server/utils";
export type Entry = {
type: "artist" | "album";
name: string;
image: string;
};
export const entryRouter = createTRPCRouter({
get: publicProcedure
.input(
z.object({
type: z.enum(["artist", "album"]),
name: z.string().min(1),
image: z.string().min(1),
}),
)
.query(async ({ ctx, input }) => {
const key = generateEntryUniqueKey(input);
const existingEntry = await ctx.db.spookyImage.findFirst({
where: {
key,
},
});
return existingEntry;
}),
generate: publicProcedure
.input(
z.object({
entry: z.object({
type: z.enum(["artist", "album"]),
name: z.string().min(1),
image: z.string().min(1),
}),
}),
)
.mutation(async ({ ctx, input }) => {
const key = generateEntryUniqueKey(input.entry);
try {
const uploadedImage = await uploadImage(input.entry.image);
if (!uploadedImage || typeof uploadedImage !== "string") {
throw new Error("Failed to upload image");
}
const spookyImage = makeImageSpooky(uploadedImage);
if (!spookyImage || typeof spookyImage !== "string") {
throw new Error("Failed to make image spooky");
}
await ctx.db.generatedImage.upsert({
where: {
key,
},
update: {},
create: {
key,
value: spookyImage,
},
});
return spookyImage;
} catch (error) {
console.error(error);
return error;
}
}),
save: publicProcedure
.input(
z.object({
entry: z.object({
type: z.enum(["artist", "album"]),
name: z.string().min(1),
image: z.string().min(1),
}),
}),
)
.mutation(async ({ ctx, input }) => {
const key = generateEntryUniqueKey(input.entry);
try {
const generatedImage = await ctx.db.generatedImage.findFirst({
where: {
key,
},
});
if (!generatedImage) {
throw new Error("No generated image found");
}
const entry = await ctx.db.spookyImage.create({
data: {
key,
value: generatedImage.value,
},
});
return entry;
} catch (error) {
console.error(error);
return error;
}
}),
});

37
src/server/utils/index.ts Normal file
View File

@@ -0,0 +1,37 @@
import * as cloudinary from "cloudinary";
import { Entry } from "../api/routers/entry";
export const generateEntryUniqueKey = (entry: Entry): string => {
return `${entry.type}:${entry.name.trim().toLowerCase().replace(/\s/g, "-")}`;
};
export const uploadImage = async (
imagePath: string,
): Promise<string | unknown> => {
const options = {
use_filename: true,
unique_filename: false,
overwrite: true,
};
try {
const result = await cloudinary.v2.uploader.upload(imagePath, options);
console.log(result);
return result.public_id;
} catch (error) {
console.error(error);
return error;
}
};
export const makeImageSpooky = (publicId: string) => {
const options = { effect: "gen_background_replace" };
try {
const result = cloudinary.v2.image(publicId, { ...options });
console.log(result);
return result;
} catch (error) {
console.error(error);
}
};