mirror of
https://github.com/fergalmoran/mixyboos.git
synced 2025-12-22 01:34:22 +00:00
Api tests added
This commit is contained in:
27
.env.testing
Normal file
27
.env.testing
Normal file
@@ -0,0 +1,27 @@
|
||||
#DATABASE_URL='mysql://79vu28u4opkh0ztv2qot:pscale_pw_LYNVUN5KF8RpUwQsIJnqCsMW2BeO9hTEfvpxZdq8289@aws.connect.psdb.cloud/mixyboos?sslaccept=strict'
|
||||
DATABASE_URL='postgresql://postgres:hackme@localhost/mixyboosv2'
|
||||
LIVE_HOST=https://live-mixyboos.dev.fergl.ie:9091
|
||||
STREAM_HOST=rtmp://live-mixyboos.dev.fergl.ie:1935/live/
|
||||
|
||||
JWT_SECRET=W2XM83uLCMcxNnNaL0EQQ+rt+9Su+yAZ1DDQGlXwCL0=
|
||||
GOOGLE_CLIENT_ID="760846434166-kpql57gbldqbbb0n7bp4lf62rtcok5bj.apps.googleusercontent.com"
|
||||
GOOGLE_CLIENT_SECRET="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"
|
||||
NEXTAUTH_SECRET="a/XTFzkdmVTfN8A9tOdHgFjUkZLxD/ju85E0Do2obCM="
|
||||
_NEXTAUTH_URL="https://mixyboos.dev.fergl.ie:3000"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
|
||||
AZURE_ACCOUNT_NAME=mixyboos
|
||||
AZURE_ACCOUNT_URL="https://mixyboos.blob.core.windows.net"
|
||||
AZURE_ACCOUNT_KEY=Q65RK6QxP4nJuUt358RKbdPrMiz1QBT4wMz3/VfHFFvpZaK6d9ifJtzgcVEmY1qTVD8gdRQBF1i6+ASt9pkcJQ==
|
||||
|
||||
PUSHER_APPID="1600127"
|
||||
PUSHER_KEY="5de20a9065b26377af84"
|
||||
PUSHER_SECRET="7b2d304f71134aa358fe"
|
||||
|
||||
NEXT_PUBLIC_PUSHER_KEY=$PUSHER_KEY
|
||||
NEXT_PUBLIC_LIVE_HOST=$LIVE_HOST
|
||||
|
||||
QUIRREL_BASE_URL=https://mixyboos.dev.fergl.ie:3000/
|
||||
|
||||
UPLOADTHING_SECRET=sk_live_ae93756f60a4ddbfe72d9425d610bf435f1ee0fda2472d294a39a9f856f0d83b
|
||||
UPLOADTHING_APP_ID=n1karmceay
|
||||
11
jest.setup.js
Normal file
11
jest.setup.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import {loadEnvConfig} from '@next/env'
|
||||
import next from 'next'
|
||||
|
||||
next({})
|
||||
export default async () => {
|
||||
const projectDir = process.cwd()
|
||||
loadEnvConfig(projectDir)
|
||||
|
||||
import next from 'next'
|
||||
next({})
|
||||
}
|
||||
18
package.json
18
package.json
@@ -10,12 +10,13 @@
|
||||
"quirrel": "quirrel",
|
||||
"postinstall": "prisma generate",
|
||||
"lint": "next lint",
|
||||
"start": "next start"
|
||||
"start": "next start",
|
||||
"test": "export $(xargs < .env) && jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.7.15",
|
||||
"@next-auth/prisma-adapter": "^1.0.7",
|
||||
"@prisma/client": "^4.16.1",
|
||||
"@prisma/client": "^4.16.2",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-progress": "^1.0.3",
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
@@ -30,6 +31,7 @@
|
||||
"axios": "^1.4.0",
|
||||
"classnames": "^2.3.2",
|
||||
"http-status-codes": "^2.2.0",
|
||||
"import-local": "^3.1.0",
|
||||
"install": "^0.13.0",
|
||||
"next": "13.4.7",
|
||||
"next-auth": "^4.22.1",
|
||||
@@ -48,6 +50,7 @@
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.0.2",
|
||||
"@next/env": "^13.4.7",
|
||||
"@radix-ui/react-avatar": "^1.0.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
@@ -55,6 +58,8 @@
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@types/eslint": "^8.40.2",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"@types/node": "^20.3.2",
|
||||
"@types/prettier": "^2.7.3",
|
||||
"@types/react": "^18.2.14",
|
||||
@@ -71,12 +76,14 @@
|
||||
"eslint": "^8.43.0",
|
||||
"eslint-config-next": "^13.4.7",
|
||||
"hls.js": "^1.4.6",
|
||||
"jest": "^29.5.0",
|
||||
"lucide-react": "^0.252.0",
|
||||
"next-themes": "^0.2.1",
|
||||
"node-mocks-http": "^1.12.2",
|
||||
"postcss": "^8.4.24",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"prisma": "4.16.1",
|
||||
"prisma": "^4.16.2",
|
||||
"pusher": "^5.1.3",
|
||||
"pusher-js": "^8.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
@@ -88,8 +95,11 @@
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.3",
|
||||
"uuid": "^9.0.0"
|
||||
"uuid": "^9.0.0",
|
||||
"vitest": "^0.32.2"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.12.2"
|
||||
|
||||
7130
pnpm-lock.yaml
generated
7130
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
3
src/__tests__/package.json
Normal file
3
src/__tests__/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import ImageUpload from "@/components/widgets/image-upload";
|
||||
import { notice } from "@/lib/components/notifications/toast";
|
||||
import { type UserModel } from "@/lib/models";
|
||||
import { uploadFile } from "@/lib/services/azure/upload";
|
||||
import { getFileExtension } from "@/lib/services/utils/fileUtils";
|
||||
import { getFileExtension } from "@/lib/utils/fileUtils";
|
||||
import { api } from "@/lib/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
@@ -2,8 +2,7 @@ import { spawn } from "child_process";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { generateSasToken } from "@/lib/services/azure/sas-token";
|
||||
import { uploadFile, uploadFolder } from "@/lib/services/azure/upload";
|
||||
import { uploadFolder } from "@/lib/services/azure/serverUploader";
|
||||
import { Queue } from "quirrel/next-app";
|
||||
|
||||
export const processMixQueue = Queue(
|
||||
@@ -39,13 +38,13 @@ export const processMixQueue = Queue(
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
generateSasToken("mixyboos", "audio")
|
||||
.then((token) => {
|
||||
console.log("upload/mix/route", "SAS TOKEN", token);
|
||||
uploadFolder(outputDir, "audio", mixId, token);
|
||||
|
||||
uploadFolder(outputDir, "audio", path.join("mixes", mixId))
|
||||
.then((r) => {
|
||||
//probably need to tag the mix in some way here?
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("route", "Error uploading folder", err);
|
||||
console.log("route", "error uploading output folder", err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { writeFile } from "fs/promises";
|
||||
import { getFileExtension } from "@/lib/services/utils/fileUtils";
|
||||
import { getFileExtension } from "@/lib/utils/fileUtils";
|
||||
import { NextResponse, type NextRequest } from "next/server";
|
||||
import { processMixQueue } from "../queues/upload/mix/route";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const data = await req.formData();
|
||||
@@ -17,5 +18,6 @@ export async function POST(req: NextRequest) {
|
||||
const path = `/tmp/${id}.${getFileExtension(file.name)}`;
|
||||
await writeFile(path, buffer);
|
||||
console.log(`open ${path} to see the uploaded file`);
|
||||
await processMixQueue.enqueue({ filePath: path, mixId: id }, { delay: 1 });
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getFileNameFromInput } from "@/lib/services/utils/fileUtils";
|
||||
import { getFilename } from "@/lib/utils/fileUtils";
|
||||
import axios, { type AxiosProgressEvent, type AxiosRequestConfig } from "axios";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
import React from "react";
|
||||
@@ -33,7 +33,7 @@ const FileUpload = ({
|
||||
onUploadProgress(progressEvent.total ?? 0, progressEvent.loaded);
|
||||
},
|
||||
};
|
||||
onUploadStart(getFileNameFromInput(event.currentTarget.files[0].name));
|
||||
onUploadStart(getFilename(event.currentTarget.files[0].name));
|
||||
const result = await axios.post("/api/upload", formData, options);
|
||||
|
||||
if (result.status === StatusCodes.OK) {
|
||||
|
||||
@@ -1,35 +1,55 @@
|
||||
import { env } from "@/env.mjs";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
import {
|
||||
BlockBlobClient,
|
||||
BlobServiceClient,
|
||||
StorageSharedKeyCredential,
|
||||
} from "@azure/storage-blob";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const uploadFile = (container: string) => {
|
||||
const client = new BlockBlobClient(
|
||||
`${env.AZURE_ACCOUNT_URL}/${container}`,
|
||||
const uploadFile = async (
|
||||
file: string,
|
||||
container: string,
|
||||
destination: string
|
||||
): Promise<boolean> => {
|
||||
const client = new BlobServiceClient(
|
||||
`${process.env.AZURE_ACCOUNT_URL as string}`,
|
||||
new StorageSharedKeyCredential(
|
||||
env.AZURE_ACCOUNT_NAME,
|
||||
env.AZURE_ACCOUNT_KEY
|
||||
process.env.AZURE_ACCOUNT_NAME as string,
|
||||
process.env.AZURE_ACCOUNT_KEY as string
|
||||
)
|
||||
);
|
||||
const containerClient = client.getContainerClient(container);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(destination);
|
||||
|
||||
const response = await blockBlobClient.uploadFile(file);
|
||||
return response._response.status === StatusCodes.OK;
|
||||
};
|
||||
|
||||
// const uploadFolder = (dir: string, container: string, subFolder: string) => {
|
||||
// fs.readdir(dir, (err, files) => {
|
||||
// console.log("upload", "uploadFolder", err, files);
|
||||
const uploadFolder = async (
|
||||
dir: string,
|
||||
container: string,
|
||||
subFolder: string
|
||||
) => {
|
||||
const files = await fs.readdir(dir);
|
||||
console.log("upload", "uploadFolder", files);
|
||||
for (const file of files) {
|
||||
try {
|
||||
const destinationFile = path.join(subFolder, file);
|
||||
const r = await uploadFile(
|
||||
path.join(dir, file),
|
||||
container,
|
||||
destinationFile
|
||||
);
|
||||
console.log("upload", "File uploaded", r);
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log("upload", "Error uploading", err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// files.forEach((file) => {
|
||||
// const f = new File(file);
|
||||
// uploadFile(f, containerName, `${subFolder}/${f.name}`)
|
||||
// .then((r) => {
|
||||
// console.log("upload", "File uploaded", r);
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.log("upload", "Error uploading", err);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
export { uploadFolder };
|
||||
export { uploadFolder, uploadFile };
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
const getFileExtension = (fileName: string): string =>
|
||||
fileName.split(".").pop() as string;
|
||||
|
||||
const getFileNameFromInput = (fullPath: string): string => {
|
||||
const startIndex =
|
||||
fullPath.indexOf("\\") >= 0
|
||||
? fullPath.lastIndexOf("\\")
|
||||
: fullPath.lastIndexOf("/");
|
||||
let filename = fullPath.substring(startIndex);
|
||||
if (filename.indexOf("\\") === 0 || filename.indexOf("/") === 0) {
|
||||
filename = filename.substring(1);
|
||||
}
|
||||
return filename.replace(/\.[^/.]+$/, "");
|
||||
};
|
||||
export { getFileExtension, getFileNameFromInput };
|
||||
@@ -1,7 +1,24 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import * as crypto from "crypto";
|
||||
|
||||
const generateSecretKey = (): string | undefined =>
|
||||
crypto.createHmac("sha256", uuidv4()).digest("hex");
|
||||
|
||||
export { generateSecretKey };
|
||||
const generateRandomBytes = async (size: number) => {
|
||||
const buffer: crypto.BinaryLike = await new Promise((resolve, reject) => {
|
||||
crypto.randomBytes(size, function (ex, buffer) {
|
||||
if (ex) {
|
||||
reject("error generating token");
|
||||
}
|
||||
resolve(buffer);
|
||||
});
|
||||
});
|
||||
const token = crypto
|
||||
.createHash("sha1")
|
||||
.update(buffer)
|
||||
.digest("hex");
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
export {generateSecretKey, generateRandomBytes};
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { createTRPCRouter, publicProcedure } from "@/server/api/trpc";
|
||||
import {
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from "@/server/api/trpc";
|
||||
import * as z from "zod";
|
||||
|
||||
export const mixRouter = createTRPCRouter({
|
||||
getAll: publicProcedure.query(({ ctx }) => {
|
||||
@@ -8,4 +13,13 @@ export const mixRouter = createTRPCRouter({
|
||||
});
|
||||
return mixes;
|
||||
}),
|
||||
createMix: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { title, description, tags }, ctx }) => {}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user