feat: add classroomio's server to the monorepo (#168)
* add classroomio server to apps * ReadME upadte * Update README.md * rename project to backend * fix lock file --------- Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
co-authored by
Rotimi Best
parent
d040f9f12e
commit
3a22a73380
@@ -0,0 +1,35 @@
|
||||
const express = require('express');
|
||||
const zod = require('zod');
|
||||
const { generateCertificate } = require('../utils/certificate');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate
|
||||
const mySchema = zod.object({
|
||||
theme: zod.string(),
|
||||
studentName: zod.string(),
|
||||
courseName: zod.string(),
|
||||
courseDescription: zod.string(),
|
||||
orgLogoUrl: zod.string(),
|
||||
orgName: zod.string(),
|
||||
});
|
||||
console.log('req.body', req.body);
|
||||
|
||||
mySchema.parse(req.body);
|
||||
|
||||
const pdfBuffer = await generateCertificate(req.body);
|
||||
|
||||
res.contentType('application/pdf');
|
||||
res.send(pdfBuffer);
|
||||
} catch (error) {
|
||||
console.error('Error', error);
|
||||
res.json({
|
||||
success: false,
|
||||
error,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,42 @@
|
||||
const express = require('express');
|
||||
const zod = require('zod');
|
||||
const { generateCoursePdf } = require('../utils/course.js');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// localhost:3002/downloadCourse
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate
|
||||
const mySchema = zod.object({
|
||||
courseTitle: zod.string(),
|
||||
orgName: zod.string(),
|
||||
orgTheme: zod.string(),
|
||||
lessons: zod.array(
|
||||
zod.object({
|
||||
lessonTitle: zod.string(),
|
||||
lessonNumber: zod.string(),
|
||||
lessonNote: zod.string(),
|
||||
slideUrl: zod.string().optional(),
|
||||
video: zod.string().array().optional(),
|
||||
})
|
||||
),
|
||||
});
|
||||
console.log('req.body', req.body);
|
||||
|
||||
mySchema.parse(req.body);
|
||||
|
||||
const pdfBuffer = await generateCoursePdf(req.body);
|
||||
|
||||
res.contentType('application/pdf');
|
||||
res.send(pdfBuffer);
|
||||
} catch (error) {
|
||||
console.error('Error', error);
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,47 @@
|
||||
const express = require('express');
|
||||
const zod = require('zod');
|
||||
const { generateLessonPdf } = require('../utils/lesson');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
const lesson = {
|
||||
title: '',
|
||||
number: '01',
|
||||
orgName: '',
|
||||
note: '',
|
||||
slideUrl: '',
|
||||
video: [],
|
||||
courseTitle: '',
|
||||
};
|
||||
|
||||
// localhost:3002/downloadLesson
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate
|
||||
const mySchema = zod.object({
|
||||
title: zod.string(),
|
||||
number: zod.string(),
|
||||
orgName: zod.string(),
|
||||
note: zod.string(),
|
||||
slideUrl: zod.string().optional(),
|
||||
video: zod.string().array().optional(),
|
||||
courseTitle: zod.string(),
|
||||
});
|
||||
console.log('req.body', req.body);
|
||||
|
||||
mySchema.parse(req.body);
|
||||
|
||||
const pdfBuffer = await generateLessonPdf(req.body);
|
||||
|
||||
res.contentType('application/pdf');
|
||||
res.send(pdfBuffer);
|
||||
} catch (error) {
|
||||
console.error('Error', error);
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,251 @@
|
||||
const express = require('express');
|
||||
const FormData = require('form-data');
|
||||
const axios = require('axios');
|
||||
// const Queue = require('bull');
|
||||
const { promisify } = require('util');
|
||||
const fs = require('fs');
|
||||
|
||||
const unlinkAsync = promisify(fs.unlink);
|
||||
|
||||
const {
|
||||
S3Client,
|
||||
PutObjectCommand,
|
||||
// GetObjectCommand,
|
||||
} = require('@aws-sdk/client-s3');
|
||||
|
||||
// const { getSupabase } = require('../utils/supabase');
|
||||
const genUniqueId = require('../utils/genUniqueId');
|
||||
const upload = require('../utils/upload');
|
||||
|
||||
const {
|
||||
CLOUDFLARE_ACCESS_KEY,
|
||||
CLOUDFLARE_SECRET_ACCESS_KEY,
|
||||
CLOUDFLARE_ACCOUNT_ID,
|
||||
CLOUDFLARE_PUBLIC_ACCOUNT_ID,
|
||||
MUSE_API_KEY,
|
||||
} = process.env;
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
const S3 = new S3Client({
|
||||
region: 'auto',
|
||||
endpoint: `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
||||
credentials: {
|
||||
accessKeyId: CLOUDFLARE_ACCESS_KEY,
|
||||
secretAccessKey: CLOUDFLARE_SECRET_ACCESS_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
// const supabase = getSupabase();
|
||||
|
||||
// const museUploadQueue = new Queue('video', process.env.REDIS_API_KEY, {
|
||||
// redis: { tls: { rejectUnauthorized: false } },
|
||||
// });
|
||||
|
||||
router.post('/', upload.single('videoFile'), async (req, res) => {
|
||||
const {
|
||||
file,
|
||||
query: { lessonId },
|
||||
} = req;
|
||||
console.log('lessonId', lessonId);
|
||||
console.log('file', file);
|
||||
|
||||
if (!file?.fieldname || !file?.fieldname) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'You must provide a file to upload',
|
||||
});
|
||||
}
|
||||
|
||||
if (file?.size > 30 * 1024 * 1024) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
type: 'FILE_TOO_LARGE',
|
||||
message: 'File is too large',
|
||||
});
|
||||
}
|
||||
const fileData = fs.readFileSync(file.path);
|
||||
|
||||
const fileName = `${genUniqueId()}-${file.originalname}`;
|
||||
const params = {
|
||||
Bucket: 'videos',
|
||||
Key: fileName,
|
||||
Body: fileData,
|
||||
};
|
||||
|
||||
const fileUrl = `https://pub-${CLOUDFLARE_PUBLIC_ACCOUNT_ID}.r2.dev/${fileName}`;
|
||||
let metadata = {};
|
||||
|
||||
try {
|
||||
const s3Upload = S3.send(new PutObjectCommand(params));
|
||||
const museUpload = uploadToMuseNow(fileData, file.originalname);
|
||||
|
||||
Promise.all([s3Upload, museUpload]).then((values) => {
|
||||
const [s3UploadRes, museUploadRes] = values;
|
||||
|
||||
// Delete file saved by mutler in file
|
||||
unlinkAsync(file.path);
|
||||
|
||||
console.log('s3UploadRes', s3UploadRes);
|
||||
console.log('museUploadRes', museUploadRes);
|
||||
|
||||
if (museUploadRes.metadata) {
|
||||
metadata = museUploadRes.metadata;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
url: fileUrl,
|
||||
metadata,
|
||||
message: 'Uploaded successfully',
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
// error handling.
|
||||
const { requestId, cfId, extendedRequestId } = error.$$metadata || {};
|
||||
|
||||
console.error('Error uploading file', error);
|
||||
console.log({ requestId, cfId, extendedRequestId });
|
||||
|
||||
res.json({
|
||||
success: false,
|
||||
message: 'Uploaded failed: ' + error,
|
||||
});
|
||||
} finally {
|
||||
// finally.
|
||||
console.log('File upload complete');
|
||||
|
||||
// console.log('Add muse queue');
|
||||
// museUploadQueue.add({
|
||||
// fileName,
|
||||
// originalFileName: file.originalname,
|
||||
// lessonId,
|
||||
// fileUrl,
|
||||
// unlinkPath: file.path,
|
||||
// });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.send('Get upload video');
|
||||
});
|
||||
|
||||
async function uploadToMuseNow(fileData, fileName) {
|
||||
try {
|
||||
// Add file data to form
|
||||
const form = new FormData();
|
||||
form.append('file', fileData, fileName);
|
||||
|
||||
// Send to muse through axios - fetch is a pain in the ass
|
||||
const response = await axios({
|
||||
method: 'POST',
|
||||
url: 'https://api.muse.ai/api/files/upload',
|
||||
data: form,
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
Key: MUSE_API_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
metadata: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log('Upload to Muse failed', error?.response?.data);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Uploads video to muse.ai and store response in DB
|
||||
// *
|
||||
// * @param {Blod} s3Data AWS s3 data
|
||||
// * @param {string} fileName Name of the file
|
||||
// * @param {string} lessonId Associated lesson this video was uploaded to
|
||||
// * @param {string} fileUrl URL to the video in s3
|
||||
// * @param {string} unlinkPath Path to mutler file to delete
|
||||
// */
|
||||
// async function uploadToMuse(s3Key, fileName, lessonId, fileUrl, unlinkPath) {
|
||||
// try {
|
||||
// await unlinkAsync(unlinkPath);
|
||||
|
||||
// const s3Data = await S3.send(
|
||||
// new GetObjectCommand({
|
||||
// Bucket: 'videos',
|
||||
// Key: s3Key,
|
||||
// })
|
||||
// );
|
||||
// // Add file data to form
|
||||
// const form = new FormData();
|
||||
// form.append('file', s3Data.Body, fileName);
|
||||
|
||||
// // Send to muse through axios - fetch is a pain in the ass
|
||||
// const response = await axios({
|
||||
// method: 'POST',
|
||||
// url: 'https://api.muse.ai/api/files/upload',
|
||||
// data: form,
|
||||
// maxContentLength: Infinity,
|
||||
// maxBodyLength: Infinity,
|
||||
// headers: {
|
||||
// Key: MUSE_API_KEY,
|
||||
// },
|
||||
// });
|
||||
|
||||
// console.log('Upload to muse complete', response.data);
|
||||
// const { data: lesson } = await supabase
|
||||
// .from('lesson')
|
||||
// .select(`*`)
|
||||
// .eq('id', lessonId)
|
||||
// .single();
|
||||
|
||||
// if (lesson) {
|
||||
// console.log('Found lesson');
|
||||
// // Add Muse response to metadata
|
||||
// const videos = lesson.videos.map((v) => {
|
||||
// if (v.link === fileUrl) {
|
||||
// console.log('matches');
|
||||
// v.metadata = JSON.parse(JSON.stringify(response.data));
|
||||
// }
|
||||
// return v;
|
||||
// });
|
||||
|
||||
// // Save uploaded data to DB
|
||||
// const { error } = await supabase
|
||||
// .from('lesson')
|
||||
// .update({ videos })
|
||||
// .eq('id', lessonId)
|
||||
// .select();
|
||||
// if (error) {
|
||||
// console.log('Error updating lesson', error);
|
||||
// } else {
|
||||
// console.log('Update DB complete');
|
||||
// }
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.log('Upload to Muse failed', error?.response?.data);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Queue to Upload to muse.ai
|
||||
// museUploadQueue.process(async function (job, done) {
|
||||
// console.log('Initilizing Muse Request\n\n', job.data);
|
||||
// const { fileName, originalFileName, lessonId, fileUrl, unlinkPath } =
|
||||
// job.data;
|
||||
|
||||
// await uploadToMuse(fileName, originalFileName, lessonId, fileUrl, unlinkPath);
|
||||
|
||||
// done();
|
||||
// });
|
||||
|
||||
// museUploadQueue.on('completed', function (job) {
|
||||
// // Job completed with output result!
|
||||
// console.log('Completed all jobs in uploading to muse', job.data);
|
||||
// });
|
||||
|
||||
// museUploadQueue.on('error', function (error) {
|
||||
// // Job completed with output result!
|
||||
// console.log('error on queue', error);
|
||||
// });
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user