@learnpack/learnpack 5.0.344 → 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
@@ -353,20 +353,15 @@ export interface TAcademy {
353
353
  timezone: string;
354
354
  }
355
355
 
356
- const neededPermissions = [
357
- "add_asset",
358
- "change_asset",
359
- "view_asset",
360
- "delete_asset",
361
- ]
356
+ const CRUD_ASSET_CAPABILITY_URL = `${HOST}/v1/auth/user/me/capability/crud_asset`
362
357
 
363
358
  export const listUserAcademies = async (
364
359
  breathecodeToken: string
365
360
  ): Promise<TAcademy[]> => {
366
- const url = "https://breathecode.herokuapp.com/v1/auth/user/me"
361
+ const meUrl = `${HOST}/v1/auth/user/me`
367
362
 
368
363
  try {
369
- const response = await axios.get(url, {
364
+ const response = await axios.get(meUrl, {
370
365
  headers: {
371
366
  Authorization: `Token ${breathecodeToken}`,
372
367
  },
@@ -376,27 +371,47 @@ export const listUserAcademies = async (
376
371
 
377
372
  const academiesMap = new Map<number, TAcademy>()
378
373
 
374
+ if (!Array.isArray(data.roles)) {
375
+ return []
376
+ }
377
+
379
378
  for (const role of data.roles) {
380
379
  const academy = role.academy
380
+ if (!academy) continue
381
381
  if (!academiesMap.has(academy.id)) {
382
382
  academiesMap.set(academy.id, academy)
383
383
  }
384
384
  }
385
385
 
386
- const permissions = new Set(data.permissions.map((p: any) => p.codename))
386
+ const academies = [...academiesMap.values()]
387
387
 
388
- // Validate if the user has ALL the needed permissions
389
- const hasAllPermissions = neededPermissions.every(permission =>
390
- permissions.has(permission)
391
- )
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
+ })
392
397
 
393
- if (!hasAllPermissions) {
394
- // The user does not have all the needed permissions
398
+ if (capResponse.status === 200) {
399
+ return academy
400
+ }
395
401
 
396
- return []
397
- }
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
+ )
398
411
 
399
- 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
400
415
  } catch (error) {
401
416
  console.error("Failed to fetch user academies:", error)
402
417
  return []
@@ -476,6 +491,15 @@ export const createAsset = async (token: string, asset: TAssetMissing) => {
476
491
  headers.Academy = String(asset.academy_id)
477
492
  }
478
493
 
494
+ console.log(
495
+ "[BC] POST",
496
+ url,
497
+ "| academy_id:",
498
+ asset.academy_id ?? "none",
499
+ "| slug:",
500
+ asset.slug
501
+ )
502
+
479
503
  try {
480
504
  const response = await axios.post(url, body, { headers })
481
505
  return response.data
@@ -518,6 +542,9 @@ const updateAsset = async (
518
542
  const headers = {
519
543
  Authorization: `Token ${token}`,
520
544
  }
545
+
546
+ console.log("[BC] PUT", url, "| academy_id:", asset.academy_id ?? "none")
547
+
521
548
  try {
522
549
  const response = await axios.put(url, asset, { headers })
523
550
  return response.data
@@ -593,7 +620,11 @@ type TTechnology = {
593
620
 
594
621
  let technologiesCache: TTechnology[] = []
595
622
 
596
- /** 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
+ */
597
628
  function sanitizeToken(token: string | undefined): string {
598
629
  if (!token) return ""
599
630
  const trimmed = token.trim()