@learnpack/learnpack 5.0.156 → 5.0.160

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import { flags } from "@oclif/command"
2
+ // import multer from "multer"
2
3
  // import * as ytdl from "ytdl-core"
3
4
  import { YoutubeTranscript } from "youtube-transcript"
4
5
  import * as express from "express"
@@ -24,6 +25,7 @@ import {
24
25
  readmeCreator,
25
26
  makeReadmeReadable,
26
27
  generateImage,
28
+ isPackageAuthor,
27
29
  } from "../utils/rigoActions"
28
30
  import * as dotenv from "dotenv"
29
31
  import {
@@ -34,10 +36,11 @@ import {
34
36
  import axios from "axios"
35
37
  import * as FormData from "form-data"
36
38
  import { RIGOBOT_HOST } from "../utils/api"
37
- import { minutesToISO8601Duration } from "../utils/misc"
39
+ import { createUploadMiddleware, minutesToISO8601Duration } from "../utils/misc"
38
40
  import { buildConfig, ConfigResponse } from "../utils/configBuilder"
39
41
  import { checkReadability, slugify } from "../utils/creatorUtilities"
40
42
  import { checkAndFixSidebarPure } from "../utils/sidebarGenerator"
43
+ import { handleAssetCreation } from "./publish"
41
44
  const frontMatter = require("front-matter")
42
45
 
43
46
  dotenv.config()
@@ -415,7 +418,7 @@ export default class ServeCommand extends SessionCommand {
415
418
 
416
419
  app.post(
417
420
  "/upload-image",
418
- express.json({ limit: 20_000_000 }),
421
+ express.json({ limit: "10mb" }),
419
422
  async (req, res) => {
420
423
  const { image_url, destination } = req.body
421
424
  if (!image_url || !destination) {
@@ -451,6 +454,99 @@ export default class ServeCommand extends SessionCommand {
451
454
  }
452
455
  )
453
456
 
457
+ const upload = createUploadMiddleware()
458
+
459
+ app.post("/upload-image-file", upload.single("file"), async (req, res) => {
460
+ console.log("UPLOADING IMAGE FILE")
461
+
462
+ const destination = (req.body as { destination?: string }).destination
463
+
464
+ // eslint-disable-next-line
465
+ // @ts-ignore
466
+ if (!req.file || !destination) {
467
+ return res
468
+ .status(400)
469
+ .json({ error: "File and destination are required" })
470
+ }
471
+
472
+ try {
473
+ // eslint-disable-next-line
474
+ // @ts-ignore
475
+ const fileData = req.file.buffer
476
+
477
+ const file = bucket.file(destination)
478
+ await file.save(fileData, {
479
+ resumable: false,
480
+ // eslint-disable-next-line
481
+ // @ts-ignore
482
+ contentType: req.file.mimetype,
483
+ })
484
+
485
+ console.log(`✅ Image uploaded to ${file.name}`)
486
+ res.json({ message: "Image uploaded successfully", path: file.name })
487
+ } catch (error) {
488
+ console.error("❌ upload-image-file error:", error)
489
+ res.status(500).json({ error: (error as Error).message })
490
+ }
491
+ })
492
+
493
+ app.put(
494
+ "/upload/preview-image/:slug",
495
+ createUploadMiddleware().single("file"),
496
+ async (req, res) => {
497
+ const { slug } = req.params
498
+ const rigoToken = req.header("x-rigo-token")
499
+
500
+ if (!rigoToken) {
501
+ return res.status(400).json({
502
+ error: "Rigo token is required. x-rigo-token header is missing",
503
+ })
504
+ }
505
+
506
+ const { isAuthor } = await isPackageAuthor(rigoToken, slug)
507
+
508
+ if (!isAuthor) {
509
+ return res.status(403).json({
510
+ error: "You are not authorized to upload a preview image",
511
+ })
512
+ }
513
+
514
+ // eslint-disable-next-line
515
+ // @ts-ignore
516
+ if (!slug || !req.file) {
517
+ return res.status(400).json({ error: "Slug and file are required" })
518
+ }
519
+
520
+ try {
521
+ const filePath = `courses/${slug}/preview.png`
522
+ const file = bucket.file(filePath)
523
+
524
+ // eslint-disable-next-line
525
+ // @ts-ignore
526
+ await file.save(req.file.buffer, {
527
+ resumable: false,
528
+
529
+ // eslint-disable-next-line
530
+ // @ts-ignore
531
+ contentType: req.file.mimetype,
532
+ })
533
+
534
+ console.log(`✅ Preview image uploaded to ${filePath}`)
535
+ return res.json({ message: "Preview uploaded", path: filePath })
536
+ } catch (error) {
537
+ console.error("❌ Error uploading preview image:", error)
538
+ return res.status(500).json({ error: (error as Error).message })
539
+ }
540
+ }
541
+ )
542
+
543
+ app.get("/check-preview-image/:slug", async (req, res) => {
544
+ const { slug } = req.params
545
+ const file = bucket.file(`courses/${slug}/preview.png`)
546
+ const [exists] = await file.exists()
547
+ res.json({ exists, file: file.name })
548
+ })
549
+
454
550
  app.get("/create", (req, res) => {
455
551
  console.log("GET /create")
456
552
  res.redirect("/creator/")
@@ -992,14 +1088,11 @@ export default class ServeCommand extends SessionCommand {
992
1088
  }
993
1089
  )
994
1090
 
995
- // 11) Crear/actualizar asset en Breathecode
996
- // await handleAssetCreation(
997
- // { token: bcToken, rigobot: { key: rigoToken }, id: 0 },
998
- // { id: academyId } as any,
999
- // config,
1000
- // rigoRes.data.url,
1001
- // categoryId
1002
- // )
1091
+ await handleAssetCreation(
1092
+ { token: bcToken, rigobotToken: rigoToken },
1093
+ config,
1094
+ rigoRes.data.url
1095
+ )
1003
1096
 
1004
1097
  rimraf.sync(tmpRoot)
1005
1098
  console.log("RIGO RES", rigoRes.data)
@@ -20,7 +20,6 @@ import { ContentIndex } from "./ContentIndex"
20
20
  import { Sidebar } from "./Sidebar"
21
21
  import Login from "../Login"
22
22
  import { useNavigate } from "react-router"
23
- import PreviewGenerator from "../PreviewGenerator"
24
23
  import { ParamsChecker } from "../ParamsChecker"
25
24
  import { slugify } from "../../utils/creatorUtils"
26
25
  import { RIGO_FLOAT_GIT } from "../../utils/constants"
@@ -177,7 +176,6 @@ const SyllabusEditor: React.FC = () => {
177
176
  text="Learnpack is setting up your tutorial.
178
177
  It may take a moment..."
179
178
  />
180
- <PreviewGenerator />
181
179
  </>
182
180
  ) : (
183
181
  <div className="flex w-full bg-white rounded-md shadow-md overflow-hidden h-screen ">
@@ -5,7 +5,6 @@ import "./index.css"
5
5
  import App from "./App.tsx"
6
6
  import SyllabusEditor from "./components/syllabus/SyllabusEditor.tsx"
7
7
  import { Toaster } from "react-hot-toast"
8
- import PreviewGenerator from "./components/PreviewGenerator.tsx"
9
8
  createRoot(document.getElementById("root")!).render(
10
9
  <StrictMode>
11
10
  <Toaster />
@@ -13,7 +12,6 @@ createRoot(document.getElementById("root")!).render(
13
12
  <Routes>
14
13
  <Route path="/creator" element={<App />} />
15
14
  <Route path="/creator/syllabus" element={<SyllabusEditor />} />
16
- <Route path="/creator/image" element={<PreviewGenerator />} />
17
15
  </Routes>
18
16
  </BrowserRouter>
19
17
  </StrictMode>