@learnpack/learnpack 5.0.343 → 5.0.346

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.
package/src/ui/app.tar.gz CHANGED
Binary file
package/src/utils/api.ts CHANGED
@@ -7,7 +7,8 @@ import * as dotenv from "dotenv"
7
7
  dotenv.config()
8
8
 
9
9
  const HOST = "https://breathecode.herokuapp.com"
10
- export const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
10
+ export const RIGOBOT_HOST =
11
+ process.env.RIGOBOT_HOST || "https://rigobot.herokuapp.com"
11
12
  export const RIGOBOT_REALTIME_HOST = "https://ai.4geeks.com"
12
13
  // export const RIGOBOT_REALTIME_HOST = "http://127.0.0.1:8003"
13
14
  // export const RIGOBOT_HOST = "https://rigobot-test-cca7d841c9d8.herokuapp.com"
@@ -352,20 +353,15 @@ export interface TAcademy {
352
353
  timezone: string;
353
354
  }
354
355
 
355
- const neededPermissions = [
356
- "add_asset",
357
- "change_asset",
358
- "view_asset",
359
- "delete_asset",
360
- ]
356
+ const CRUD_ASSET_CAPABILITY_URL = `${HOST}/v1/auth/user/me/capability/crud_asset`
361
357
 
362
358
  export const listUserAcademies = async (
363
359
  breathecodeToken: string
364
360
  ): Promise<TAcademy[]> => {
365
- const url = "https://breathecode.herokuapp.com/v1/auth/user/me"
361
+ const meUrl = `${HOST}/v1/auth/user/me`
366
362
 
367
363
  try {
368
- const response = await axios.get(url, {
364
+ const response = await axios.get(meUrl, {
369
365
  headers: {
370
366
  Authorization: `Token ${breathecodeToken}`,
371
367
  },
@@ -375,27 +371,47 @@ export const listUserAcademies = async (
375
371
 
376
372
  const academiesMap = new Map<number, TAcademy>()
377
373
 
374
+ if (!Array.isArray(data.roles)) {
375
+ return []
376
+ }
377
+
378
378
  for (const role of data.roles) {
379
379
  const academy = role.academy
380
+ if (!academy) continue
380
381
  if (!academiesMap.has(academy.id)) {
381
382
  academiesMap.set(academy.id, academy)
382
383
  }
383
384
  }
384
385
 
385
- const permissions = new Set(data.permissions.map((p: any) => p.codename))
386
+ const academies = [...academiesMap.values()]
386
387
 
387
- // Validate if the user has ALL the needed permissions
388
- const hasAllPermissions = neededPermissions.every(permission =>
389
- permissions.has(permission)
390
- )
388
+ const allowed = await Promise.all(
389
+ academies.map(async academy => {
390
+ const capResponse = await axios.get(CRUD_ASSET_CAPABILITY_URL, {
391
+ headers: {
392
+ Authorization: `Token ${breathecodeToken}`,
393
+ Academy: academy.id,
394
+ },
395
+ validateStatus: () => true,
396
+ })
391
397
 
392
- if (!hasAllPermissions) {
393
- // The user does not have all the needed permissions
398
+ if (capResponse.status === 200) {
399
+ return academy
400
+ }
394
401
 
395
- return []
396
- }
402
+ if (capResponse.status !== 403) {
403
+ console.warn(
404
+ `listUserAcademies: unexpected status ${capResponse.status} for academy ${academy.id}`
405
+ )
406
+ }
407
+
408
+ return null
409
+ })
410
+ )
397
411
 
398
- return [...academiesMap.values()]
412
+ const filtered = allowed.filter((a): a is TAcademy => a !== null)
413
+ filtered.sort((a, b) => a.name.localeCompare(b.name))
414
+ return filtered
399
415
  } catch (error) {
400
416
  console.error("Failed to fetch user academies:", error)
401
417
  return []
@@ -475,6 +491,15 @@ export const createAsset = async (token: string, asset: TAssetMissing) => {
475
491
  headers.Academy = String(asset.academy_id)
476
492
  }
477
493
 
494
+ console.log(
495
+ "[BC] POST",
496
+ url,
497
+ "| academy_id:",
498
+ asset.academy_id ?? "none",
499
+ "| slug:",
500
+ asset.slug
501
+ )
502
+
478
503
  try {
479
504
  const response = await axios.post(url, body, { headers })
480
505
  return response.data
@@ -517,6 +542,9 @@ const updateAsset = async (
517
542
  const headers = {
518
543
  Authorization: `Token ${token}`,
519
544
  }
545
+
546
+ console.log("[BC] PUT", url, "| academy_id:", asset.academy_id ?? "none")
547
+
520
548
  try {
521
549
  const response = await axios.put(url, asset, { headers })
522
550
  return response.data
@@ -592,7 +620,11 @@ type TTechnology = {
592
620
 
593
621
  let technologiesCache: TTechnology[] = []
594
622
 
595
- /** Strip .env comments (e.g. "token # comment") so the token is sent without spaces. */
623
+ /**
624
+ * Strip .env comments (e.g. "token # comment") so the token is sent without spaces.
625
+ * @param token - Raw token value from env, possibly with trailing comment.
626
+ * @returns Trimmed token with inline `#` comments removed, or empty string if missing.
627
+ */
596
628
  function sanitizeToken(token: string | undefined): string {
597
629
  if (!token) return ""
598
630
  const trimmed = token.trim()