@edifice.io/client 2.0.1-develop-hotfix.1736778374387 → 2.0.1-develop-hotfix.1736779480274

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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var T = Object.defineProperty;
2
- var F = (n, e, t) => e in n ? T(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
- var u = (n, e, t) => F(n, typeof e != "symbol" ? e + "" : e, t);
2
+ var D = (n, e, t) => e in n ? T(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
3
+ var a = (n, e, t) => D(n, typeof e != "symbol" ? e + "" : e, t);
4
4
  import axios from "axios";
5
5
  import { MimeTypeUtils } from "@edifice.io/utilities";
6
6
  const ReactionTypes = [
@@ -101,125 +101,6 @@ const ReactionTypes = [
101
101
  RGPD_COOKIES: "rgpdCookies"
102
102
  // TODO compléter
103
103
  };
104
- class Subscription {
105
- constructor(e, t) {
106
- u(this, "revoke");
107
- this._channel = e, this.revoke = this.setReceiver(
108
- (s) => t == null ? void 0 : t(s.data)
109
- );
110
- }
111
- setReceiver(e) {
112
- var t;
113
- return (t = this._channel) == null || t.addEventListener("message", e), () => {
114
- this._channel && (this._channel.removeEventListener("message", e), this._channel.close(), delete this._channel);
115
- };
116
- }
117
- }
118
- class Subject {
119
- constructor() {
120
- /* A single BroadcastChannel cannot send AND receive messages, afaik.
121
- * => We maintain here channels for *sending* messages.
122
- * *Receiving* channels will be instantiated while subscribing.
123
- */
124
- u(this, "publishChannels", /* @__PURE__ */ new Map());
125
- }
126
- getChannelName(e) {
127
- return "Subject:" + e;
128
- }
129
- getPublishChannel(e) {
130
- const t = this.getChannelName(e);
131
- let s = this.publishChannels.get(t);
132
- return s || (s = this.newChannel(e), this.publishChannels.set(t, s)), s;
133
- }
134
- newChannel(e) {
135
- const t = this.getChannelName(e), s = new BroadcastChannel(t);
136
- return s.addEventListener("messageerror", (r) => console.log(r.data)), s;
137
- }
138
- publish(e, t) {
139
- typeof e == "string" && this.getPublishChannel(e).postMessage(t);
140
- }
141
- subscribe(e, t) {
142
- if (typeof e == "string") {
143
- const s = this.newChannel(e);
144
- return new Subscription(s, t);
145
- } else
146
- return new Subscription();
147
- }
148
- }
149
- const ASYNC_DATA_NAME = {
150
- SESSION_READY: "sessionReady",
151
- LANG_READY: "langReady",
152
- SKIN_READY: "skinReady",
153
- OVERRIDE_READY: "overrideReady",
154
- APPCONF_READY: "appConfReady"
155
- };
156
- class Promisified {
157
- constructor() {
158
- //-------------------------------------
159
- u(this, "_resolution");
160
- u(this, "_rejection");
161
- u(this, "_promise", new Promise((e, t) => {
162
- this._resolution = e, this._rejection = t;
163
- }));
164
- }
165
- get promise() {
166
- return this._promise;
167
- }
168
- resolve(e) {
169
- this._resolution && this._resolution(e);
170
- }
171
- reject(e) {
172
- this._rejection && this._rejection(e);
173
- }
174
- }
175
- class NotifyFramework {
176
- constructor() {
177
- //-------------------------------------
178
- u(this, "promises", {});
179
- u(this, "subject", new Subject());
180
- }
181
- asyncData(e) {
182
- return typeof this.promises[e] > "u" && (this.promises[e] = new Promisified()), this.promises[e];
183
- }
184
- onSessionReady() {
185
- return this.asyncData(ASYNC_DATA_NAME.SESSION_READY);
186
- }
187
- onLangReady() {
188
- return this.asyncData(ASYNC_DATA_NAME.LANG_READY);
189
- }
190
- onSkinReady() {
191
- return this.asyncData(ASYNC_DATA_NAME.SKIN_READY);
192
- }
193
- onOverridesReady() {
194
- return this.asyncData(ASYNC_DATA_NAME.OVERRIDE_READY);
195
- }
196
- onAppConfReady() {
197
- return this.asyncData(ASYNC_DATA_NAME.APPCONF_READY);
198
- }
199
- promisify() {
200
- return new Promisified();
201
- }
202
- events() {
203
- return this.subject;
204
- }
205
- }
206
- const notify = new NotifyFramework();
207
- class NotifyFrameworkFactory {
208
- static instance() {
209
- return notify;
210
- }
211
- }
212
- const LAYER_NAME = {
213
- WIDGETS: "widgets",
214
- EXPLORER: "explorer",
215
- TRANSPORT: "transport",
216
- WEB_DATA: "webDataPipeline"
217
- }, EVENT_NAME = {
218
- USERPREF_CHANGED: "userprefChanged",
219
- SEARCH_RESULTED: "searchResulted",
220
- ERROR_OCCURED: "error",
221
- DATA_TRACKED: "track"
222
- };
223
104
  class ServiceRegistry extends Map {
224
105
  /** Register a service */
225
106
  register({
@@ -262,7 +143,7 @@ const f = class f {
262
143
  //
263
144
  // PROTECTED HELPERS
264
145
  //
265
- u(this, "checkHttpResponse", (e) => {
146
+ a(this, "checkHttpResponse", (e) => {
266
147
  if (this.http.latestResponse.status >= 300)
267
148
  throw this.http.latestResponse.statusText;
268
149
  return e;
@@ -480,8 +361,8 @@ const f = class f {
480
361
  //
481
362
  // STATIC REGISTRY
482
363
  //
483
- u(f, "registry", new ServiceRegistry()), // Expose some useful functions
484
- u(f, "register", f.registry.register.bind(f.registry)), u(f, "findService", f.registry.findService.bind(f.registry)), u(f, "findMainService", f.registry.findMainService.bind(f.registry)), u(f, "isRegistered", f.registry.isRegistered.bind(f.registry));
364
+ a(f, "registry", new ServiceRegistry()), // Expose some useful functions
365
+ a(f, "register", f.registry.register.bind(f.registry)), a(f, "findService", f.registry.findService.bind(f.registry)), a(f, "findMainService", f.registry.findMainService.bind(f.registry)), a(f, "isRegistered", f.registry.isRegistered.bind(f.registry));
485
366
  let ResourceService = f;
486
367
  const APP$1 = "scrapbook", RESOURCE$1 = "scrapbook";
487
368
  class ScrapbookResourceService extends ResourceService {
@@ -574,70 +455,279 @@ ResourceService.register(
574
455
  { application: RESOURCE, resourceType: RESOURCE },
575
456
  (n) => new HomeworksResourceService(n)
576
457
  );
577
- const globalCache = {}, mutexPromise = {};
578
- class CacheService {
579
- constructor(e) {
580
- this.context = e;
458
+ let ATTag;
459
+ class AnalyticsService {
460
+ constructor(n) {
461
+ this.context = n;
462
+ }
463
+ get conf() {
464
+ return this.context.conf();
581
465
  }
582
466
  get http() {
583
467
  return this.context.http();
584
468
  }
585
- async fromCacheIfPossible(e, t, s) {
586
- if (mutexPromise[e] && await mutexPromise[e], globalCache[e])
587
- return globalCache[e];
588
- try {
589
- const r = t();
590
- mutexPromise[e] = r;
591
- const i = await r;
592
- return s(i) && (globalCache[e] = i), i;
593
- } catch (r) {
594
- throw console.error(`Failed to retrieve value for: ${e}`, r), r;
595
- }
596
- }
597
- clearCache(e) {
598
- if (e)
599
- delete globalCache[e];
600
- else
601
- for (const t in globalCache)
602
- globalCache.hasOwnProperty(t) && delete globalCache[t];
469
+ get session() {
470
+ return this.context.session();
603
471
  }
604
- async httpGet(e, t) {
605
- return this.fromCacheIfPossible(
606
- e,
607
- async () => {
608
- const s = await this.http.get(e, t), r = { ...this.http.latestResponse };
609
- return { value: s, response: r };
472
+ /**
473
+ * Xiti tracker for page loading.
474
+ * @param locationPath
475
+ * @param app
476
+ */
477
+ async trackPageLoad(n, e) {
478
+ const [t] = await Promise.all([
479
+ // get Xiti configuration
480
+ this.getXitiConfig(e.name.toLowerCase()),
481
+ // load Xiti javascript file
482
+ this.loadXitiScript()
483
+ ]);
484
+ if (!t || !ATInternet) return;
485
+ let s = t.LIBELLE_SERVICE.default || null;
486
+ for (const r in t.LIBELLE_SERVICE)
487
+ if (r !== "default" && n.indexOf(r) >= 0) {
488
+ s = t.LIBELLE_SERVICE[r];
489
+ break;
490
+ }
491
+ ATTag = new ATInternet.Tracker.Tag({ site: t.STRUCT_ID }), ATTag.setProps(
492
+ {
493
+ SERVICE: s,
494
+ TYPE: t.TYPE,
495
+ OUTIL: t.OUTIL,
496
+ UAI: t.STRUCT_UAI,
497
+ PROJET: t.PROJET,
498
+ EXPLOITANT: t.EXPLOITANT,
499
+ PLATEFORME: t.PLATFORME,
500
+ PROFIL: t.PROFILE
610
501
  },
611
- ({ response: s }) => !(s.status < 200 || s.status >= 300)
612
- );
502
+ !0
503
+ ), ATTag.identifiedVisitor.set({
504
+ id: t.ID_PERSO,
505
+ category: t.PROFILE
506
+ }), ATTag.page.set({
507
+ name: (e == null ? void 0 : e.prefix) === "userbook" ? "directory" : e == null ? void 0 : e.prefix,
508
+ chapter1: "",
509
+ chapter2: "",
510
+ chapter3: "",
511
+ level2: t.STRUCT_UAI
512
+ }), ATTag.dispatch();
613
513
  }
614
- async httpGetJson(e, t) {
615
- const { response: s, value: r } = await this.httpGet(e, t);
616
- if (s.status < 200 || s.status >= 300)
617
- throw `Bad http status (${s.status}) for url: ${e}`;
618
- return r;
514
+ async getXitiConfig(n) {
515
+ const [e, t] = await Promise.all([
516
+ this.http.get("/analyticsConf"),
517
+ //FIXME change servers config to only keep the "all-in-one" query to /analyticsConf.
518
+ this.http.get("/xiti/config")
519
+ ]);
520
+ if (!(e != null && e.type))
521
+ throw ERROR_CODE.MALFORMED_DATA;
522
+ return t != null && t.active && (e.xiti = await this.getXitiTrackingParams(t, n)), e.xiti;
523
+ }
524
+ async loadXitiScript() {
525
+ if (typeof ATInternet > "u") {
526
+ const scriptPath = "/xiti/public/js/lib/smarttag_ENT.js", response = await this.http.get(scriptPath, {
527
+ headers: { Accept: "application/javascript" }
528
+ });
529
+ if (this.http.latestResponse.status != 200)
530
+ throw "Error while loading XiTi script";
531
+ eval(response);
532
+ }
533
+ }
534
+ async getXitiTrackingParams(n, e) {
535
+ if (!n.structureMap || !e) return;
536
+ const t = await this.session.getUser(), s = await this.session.getUserProfile();
537
+ let r;
538
+ if (!(t != null && t.structures)) return;
539
+ for (const h of t.structures) {
540
+ const l = n.structureMap[h];
541
+ if (l && l.collectiviteId && l.UAI) {
542
+ r = l;
543
+ break;
544
+ }
545
+ }
546
+ if (!r || !r.active) return;
547
+ const i = await this.conf.getPublicConf(e);
548
+ if (!i) return;
549
+ const o = i.xiti;
550
+ if (!o || !o.LIBELLE_SERVICE || !r.UAI) return;
551
+ function u(h) {
552
+ let l = "";
553
+ for (let g = 0; g < h.length; g++)
554
+ l += h.charCodeAt(g);
555
+ return l;
556
+ }
557
+ const c = {
558
+ Student: "ELEVE",
559
+ Teacher: "ENSEIGNANT",
560
+ Relative: "PARENT",
561
+ Personnel: "ADMIN_VIE_SCOL_TECH",
562
+ Guest: "AUTRE"
563
+ };
564
+ return {
565
+ LIBELLE_SERVICE: o.LIBELLE_SERVICE,
566
+ // Which property of LIBELLE_SERVICE to use depends on the frontend.
567
+ TYPE: o.OUTIL ? "TIERS" : "NATIF",
568
+ OUTIL: o.OUTIL ? o.OUTIL : "",
569
+ STRUCT_ID: r.collectiviteId,
570
+ STRUCT_UAI: r.UAI,
571
+ PROJET: r.projetId ? r.projetId : n.ID_PROJET,
572
+ EXPLOITANT: n.ID_EXPLOITANT,
573
+ PLATFORME: r.plateformeId ? r.plateformeId : n.ID_PLATEFORME,
574
+ ID_PERSO: u(t.userId),
575
+ PROFILE: s && s.length > 0 ? c[s[0]] ?? "" : ""
576
+ };
619
577
  }
620
578
  }
621
- class ConfService {
622
- constructor(e) {
623
- u(this, "Platform", {
624
- deploymentTag: "",
625
- cdnDomain: ""
626
- });
627
- this.context = e;
579
+ class ReactionsService {
580
+ constructor(e, t, s) {
581
+ this.context = e, this.module = t, this.resourceType = s;
628
582
  }
629
583
  get http() {
630
584
  return this.context.http();
631
585
  }
632
- get cache() {
633
- return this.context.cache();
586
+ async loadAvailableReactions() {
587
+ try {
588
+ const { "reaction-types": e } = await this.context.conf().getPublicConf("audience");
589
+ return Array.isArray(e) ? e : void 0;
590
+ } catch {
591
+ console.error("Audience configuration not found");
592
+ return;
593
+ }
594
+ }
595
+ async loadReactionSummaries(e) {
596
+ const t = await this.http.get(
597
+ `/audience/reactions/${this.module}/${this.resourceType}?resourceIds=${e.join(",")}`
598
+ );
599
+ return this.http.isResponseError() ? {} : t.reactionsByResource;
600
+ }
601
+ async loadReactionDetails(e, t, s) {
602
+ const r = await this.http.get(
603
+ `/audience/reactions/${this.module}/${this.resourceType}/${e}?page=${t}&size=${s}`
604
+ );
605
+ return this.http.isResponseError() ? void 0 : r;
606
+ }
607
+ async deleteReaction(e) {
608
+ await this.http.delete(
609
+ `/audience/reactions/${this.module}/${this.resourceType}/${e}`
610
+ );
611
+ }
612
+ async updateReaction(e, t) {
613
+ await this.http.putJson(
614
+ `/audience/reactions/${this.module}/${this.resourceType}`,
615
+ {
616
+ resourceId: e,
617
+ reactionType: t
618
+ }
619
+ );
620
+ }
621
+ async createReaction(e, t) {
622
+ await this.http.postJson(
623
+ `/audience/reactions/${this.module}/${this.resourceType}`,
624
+ {
625
+ resourceId: e,
626
+ reactionType: t
627
+ }
628
+ );
629
+ }
630
+ }
631
+ class ViewsService {
632
+ constructor(e, t, s) {
633
+ this.context = e, this.module = t, this.resourceType = s;
634
+ }
635
+ get http() {
636
+ return this.context.http();
637
+ }
638
+ async getCounters(e) {
639
+ const t = await this.http.get(
640
+ `/audience/views/count/${this.module}/${this.resourceType}?resourceIds=${e.join(",")}`
641
+ );
642
+ return this.http.isResponseError() ? {} : t;
643
+ }
644
+ async getDetails(e) {
645
+ const t = await this.http.get(
646
+ `/audience/views/details/${this.module}/${this.resourceType}/${e}`
647
+ );
648
+ return this.http.isResponseError() ? void 0 : t;
649
+ }
650
+ trigger(e) {
651
+ return this.http.post(
652
+ `/audience/views/${this.module}/${this.resourceType}/${e}`
653
+ );
654
+ }
655
+ }
656
+ class AudienceService {
657
+ constructor(e, t, s) {
658
+ this.context = e, this.module = t, this.resourceType = s;
659
+ }
660
+ get views() {
661
+ return new ViewsService(this.context, this.module, this.resourceType);
662
+ }
663
+ get reactions() {
664
+ return new ReactionsService(this.context, this.module, this.resourceType);
665
+ }
666
+ }
667
+ const globalCache = {}, mutexPromise = {};
668
+ class CacheService {
669
+ constructor(e) {
670
+ this.context = e;
671
+ }
672
+ get http() {
673
+ return this.context.http();
674
+ }
675
+ async fromCacheIfPossible(e, t, s) {
676
+ if (mutexPromise[e] && await mutexPromise[e], globalCache[e])
677
+ return globalCache[e];
678
+ try {
679
+ const r = t();
680
+ mutexPromise[e] = r;
681
+ const i = await r;
682
+ return s(i) && (globalCache[e] = i), i;
683
+ } catch (r) {
684
+ throw console.error(`Failed to retrieve value for: ${e}`, r), r;
685
+ }
686
+ }
687
+ clearCache(e) {
688
+ if (e)
689
+ delete globalCache[e];
690
+ else
691
+ for (const t in globalCache)
692
+ globalCache.hasOwnProperty(t) && delete globalCache[t];
693
+ }
694
+ async httpGet(e, t) {
695
+ return this.fromCacheIfPossible(
696
+ e,
697
+ async () => {
698
+ const s = await this.http.get(e, t), r = { ...this.http.latestResponse };
699
+ return { value: s, response: r };
700
+ },
701
+ ({ response: s }) => !(s.status < 200 || s.status >= 300)
702
+ );
703
+ }
704
+ async httpGetJson(e, t) {
705
+ const { response: s, value: r } = await this.httpGet(e, t);
706
+ if (s.status < 200 || s.status >= 300)
707
+ throw `Bad http status (${s.status}) for url: ${e}`;
708
+ return r;
709
+ }
710
+ }
711
+ class ConfService {
712
+ constructor(e) {
713
+ a(this, "Platform", {
714
+ deploymentTag: "",
715
+ cdnDomain: ""
716
+ });
717
+ this.context = e;
718
+ }
719
+ get http() {
720
+ return this.context.http();
721
+ }
722
+ get cache() {
723
+ return this.context.cache();
634
724
  }
635
725
  get cdnDomain() {
636
726
  return this.Platform.cdnDomain;
637
727
  }
638
- get notify() {
728
+ /* private get notify() {
639
729
  return this.context.notify();
640
- }
730
+ } */
641
731
  async getConf(e) {
642
732
  const [t, s] = await Promise.all([
643
733
  this.getThemeConf(),
@@ -645,14 +735,14 @@ class ConfService {
645
735
  ]), [r, i] = await Promise.all([
646
736
  this.getTheme({ conf: t, publicTheme: s === void 0 }),
647
737
  this.getWebAppConf({ app: e, applications: s ?? [] })
648
- ]), o = {
738
+ ]);
739
+ return {
649
740
  app: e,
650
741
  applications: s ?? [],
651
742
  conf: t,
652
743
  currentApp: i,
653
744
  theme: r
654
745
  };
655
- return this.notify.onAppConfReady().resolve(o), o;
656
746
  }
657
747
  async getPublicConf(e) {
658
748
  const { response: t, value: s } = await this.cache.httpGet(
@@ -707,19 +797,19 @@ class ConfService {
707
797
  const { value: r } = await this.cache.httpGet("/theme", {
708
798
  queryParams: { _: e }
709
799
  }), i = s ? null : r, o = t == null ? void 0 : t.overriding.find(
710
- (p) => (
800
+ (d) => (
711
801
  // Public access => simply use the 1st override
712
- i === null || p.child === i.themeName
802
+ i === null || d.child === i.themeName
713
803
  )
714
- ), a = (i == null ? void 0 : i.skinName) || o.skins[0], c = (i == null ? void 0 : i.skin) || `/assets/themes/${o.child}/skins/${a}/`, l = o.skins, h = o.bootstrapVersion.split("-").slice(-1)[0], E = o.parent === "panda";
804
+ ), u = (i == null ? void 0 : i.skinName) || o.skins[0], c = (i == null ? void 0 : i.skin) || `/assets/themes/${o.child}/skins/${u}/`, h = o.skins, l = o.bootstrapVersion.split("-").slice(-1)[0], g = o.parent === "panda";
715
805
  return {
716
806
  basePath: `${this.cdnDomain}${c}../../`,
717
- bootstrapVersion: h,
718
- is1d: E,
807
+ bootstrapVersion: l,
808
+ is1d: g,
719
809
  logoutCallback: (i == null ? void 0 : i.logoutCallback) || "/",
720
810
  skin: o.child,
721
- skinName: a,
722
- skins: l,
811
+ skinName: u,
812
+ skins: h,
723
813
  themeName: o.child,
724
814
  themeUrl: c,
725
815
  npmTheme: o.npmTheme ?? void 0
@@ -767,18 +857,18 @@ class DirectoryService {
767
857
  return {
768
858
  id: s,
769
859
  displayName: r,
770
- groups: t.map(({ name: o, id: a }) => ({
860
+ groups: t.map(({ name: o, id: u }) => ({
771
861
  displayName: o,
772
- id: a
862
+ id: u
773
863
  })),
774
- users: i.map(({ displayName: o, id: a, profile: c }) => ({
864
+ users: i.map(({ displayName: o, id: u, profile: c }) => ({
775
865
  profile: c,
776
866
  displayName: o,
777
867
  // these info are missing from api
778
868
  firstName: "",
779
869
  lastName: "",
780
870
  login: "",
781
- id: a
871
+ id: u
782
872
  }))
783
873
  };
784
874
  }
@@ -788,564 +878,219 @@ class DirectoryService {
788
878
  users: r
789
879
  }) {
790
880
  this.cache.clearCache("/directory/sharebookmark/all");
791
- const i = r.map((p) => typeof p == "string" ? p : p.id), o = s.map((p) => typeof p == "string" ? p : p.id), a = t.map(async (p) => {
792
- if (typeof p == "string") {
793
- const { displayName: d, groups: g, id: A, users: m } = await this.getBookMarkById(p), R = m.map((C) => C.id), v = g.map((C) => C.id);
881
+ const i = r.map((d) => typeof d == "string" ? d : d.id), o = s.map((d) => typeof d == "string" ? d : d.id), u = t.map(async (d) => {
882
+ if (typeof d == "string") {
883
+ const { displayName: p, groups: E, id: A, users: m } = await this.getBookMarkById(d), w = m.map((v) => v.id), C = E.map((v) => v.id);
794
884
  return {
795
- displayName: d,
885
+ displayName: p,
796
886
  id: A,
797
- members: [...v, ...R]
887
+ members: [...C, ...w]
798
888
  };
799
889
  } else
800
- return Promise.resolve(p);
801
- }), l = (await Promise.all(a)).map((p) => p.members).reduce((p, d) => [...p, ...d], []), h = {
890
+ return Promise.resolve(d);
891
+ }), h = (await Promise.all(u)).map((d) => d.members).reduce((d, p) => [...d, ...p], []), l = {
802
892
  name: e,
803
- members: [...i, ...o, ...l]
804
- }, { id: E } = await this.http.postJson(
893
+ members: [...i, ...o, ...h]
894
+ }, { id: g } = await this.http.postJson(
805
895
  "/directory/sharebookmark",
806
- h
896
+ l
807
897
  );
808
898
  return {
809
- id: E,
899
+ id: g,
810
900
  displayName: e,
811
- members: h.members
901
+ members: l.members
812
902
  };
813
903
  }
814
904
  }
815
- const loadedScripts = {};
816
- class HttpService {
905
+ class EmbedderService {
817
906
  constructor(e) {
818
- // Axios automatically manages the XSRF-TOKEN cookie and the X-XSRF-TOKEN HTTP header.
819
- u(this, "axios");
820
- u(this, "baseUrl");
821
- u(this, "headers", {});
822
- u(this, "_latestResponse");
823
- this.context = e, this.axios = axios;
907
+ this.context = e;
824
908
  }
825
- fixBaseUrl(e) {
826
- return e.startsWith("http://") || e.startsWith("https://") ? e : this.baseUrl ? this.baseUrl.endsWith("/") || e.startsWith("/") ? `${this.baseUrl}${e}` : `${this.baseUrl}/${e}` : e;
909
+ get http() {
910
+ return this.context.http();
827
911
  }
828
- useBaseUrl(e) {
829
- return this.baseUrl = e, this;
912
+ /**
913
+ * Returns the default list of video embedder
914
+ * @returns the default list of video embedder
915
+ */
916
+ async getDefault() {
917
+ return this.http.get("/infra/embed/default");
830
918
  }
831
- useHeaders(e) {
832
- return this.headers = e, this;
919
+ /**
920
+ * Returns the custom list of video embedder
921
+ * @returns the custom list of video embedder
922
+ */
923
+ async getCustom() {
924
+ return this.http.get("/infra/embed/custom");
833
925
  }
834
- setCdn(e) {
835
- e && XMLHttpRequest && !XMLHttpRequest.prototype.cdnUrl && (XMLHttpRequest.prototype.cdnUrl = e, XMLHttpRequest.prototype.baseOpen = XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.open = function() {
836
- const t = arguments[1];
837
- return t.startsWith("/infra/public") && (arguments[1] = e + t), /^\/([^\/]*)\/public/.test(t) && (arguments[1] = e + t), t.startsWith("/assets") && (arguments[1] = e + t), t == "/conf/public" && (arguments[1] = t), t.startsWith("http") && (arguments[1] = t), this.baseOpen.apply(this, arguments);
838
- });
926
+ /**
927
+ * The provider matching with the URL
928
+ * @param {Embedder[]} embedderList - The list of video providers to test with
929
+ * @param {String} url - The URL for the video
930
+ * @returns The provider matching with the URL or undefined
931
+ */
932
+ getProviderFromUrl(e, t) {
933
+ for (const s of e)
934
+ if (this.isUrlFromProvider(t, s))
935
+ return s;
839
936
  }
840
- // private toAxiosConfig(params?: IHttpParams): AxiosRequestConfig {
841
- toAxiosConfig(e) {
842
- if (e) {
843
- const t = Object.assign({}, this.axios.defaults);
844
- e.headers && (t.headers = Object.assign({}, this.axios.defaults.headers), Object.assign(t.headers, e.headers)), e.responseType && (t.responseType = e.responseType), e.queryParams && (t.params = Object.assign({}, e.queryParams));
845
- const s = t.headers ?? {};
846
- return t.headers = { ...s, ...this.headers }, t;
847
- } else
848
- return this.axios.defaults;
937
+ urlIsFromPattern(e, t) {
938
+ const s = new RegExp("[^{}]+(?=(?:[^{}]*{[^}]*})*[^}]*$)", "g"), r = new RegExp("{[^}]*}", "g");
939
+ let i = !0;
940
+ const o = t.match(s) || [], u = [];
941
+ return (t.match(r) || []).forEach((h, l) => {
942
+ h.includes("ignore") || u.push(o[l]);
943
+ }), u.forEach((h) => {
944
+ if (!e.includes(h)) {
945
+ i = !1;
946
+ return;
947
+ }
948
+ }), i;
849
949
  }
850
- toCdnUrl(e) {
851
- e = this.fixBaseUrl(e);
852
- const t = this.context.conf().getCdnUrl() || "";
853
- if (t.length > 0 && e !== "/conf/public") {
854
- const s = "" + e;
855
- (s.startsWith("/infra/public") || s.startsWith("/assets") || /^\/([^\/]*)\/public/.test(s)) && (e = t + s);
856
- }
857
- return e;
950
+ /**
951
+ * Check if a given URL correspond to one of the URL pattern of the provider
952
+ * @param {String} url - The URL for the video
953
+ * @param {Embedder} embedder - The video provider to test with
954
+ * @returns boolean depending if a given URL correspond to one of the URL pattern of the provider
955
+ */
956
+ isUrlFromProvider(e, t) {
957
+ typeof t.url == "string" && (t.url = [t.url]);
958
+ for (const s of t.url)
959
+ if (this.urlIsFromPattern(e, s))
960
+ return !0;
961
+ return !1;
858
962
  }
859
- mapAxiosError(e, t) {
860
- e.response ? this._latestResponse = e.response : e.request ? this._latestResponse = {
861
- status: 408,
862
- statusText: ERROR_CODE.TIME_OUT
863
- } : this._latestResponse = {
864
- status: 500,
865
- statusText: ERROR_CODE.UNKNOWN
866
- };
867
- const { status: s, statusText: r, headers: i, data: o } = this._latestResponse;
868
- return t != null && t.disableNotifications || notify.events().publish(LAYER_NAME.TRANSPORT, {
869
- name: EVENT_NAME.ERROR_OCCURED,
870
- data: {
871
- params: t,
872
- response: { status: s, statusText: r, headers: i },
873
- payload: o
963
+ /**
964
+ * Get embed code to display the video for an URL and a provider
965
+ * @param {Embedder} embedder - The video provider for the URL
966
+ * @param {String} url - The URL for the video
967
+ * @returns embed code to display the video for an URL and a provider
968
+ */
969
+ getEmbedCodeForProvider(e, t) {
970
+ for (const s of e.url)
971
+ if (this.urlIsFromPattern(t, s)) {
972
+ const r = new RegExp("{[a-zA-Z0-9_.]+}", "g"), i = s.match(r) || [];
973
+ let o = e.embed;
974
+ for (const u of i) {
975
+ let c = s.split(u)[0];
976
+ const h = c.split("}");
977
+ h.length > 1 && (c = h[h.length - 1]);
978
+ let l = t.split(c)[1];
979
+ if (!l)
980
+ continue;
981
+ const g = s.split(u)[1].split("{")[0];
982
+ g && (l = l.split(g)[0]);
983
+ const d = new RegExp("\\" + u.replace(/}/, "\\}"), "g");
984
+ o = o.replace(d, l);
985
+ }
986
+ return o;
874
987
  }
875
- }), o;
988
+ return "";
876
989
  }
877
- mapAxiosResponse(e, t) {
878
- return this._latestResponse = e, e.data;
990
+ }
991
+ class Subscription {
992
+ constructor(e, t) {
993
+ a(this, "revoke");
994
+ this._channel = e, this.revoke = this.setReceiver(
995
+ (s) => t == null ? void 0 : t(s.data)
996
+ );
879
997
  }
880
- get latestResponse() {
881
- return this._latestResponse;
998
+ setReceiver(e) {
999
+ var t;
1000
+ return (t = this._channel) == null || t.addEventListener("message", e), () => {
1001
+ this._channel && (this._channel.removeEventListener("message", e), this._channel.close(), delete this._channel);
1002
+ };
882
1003
  }
883
- isResponseError() {
884
- return this.latestResponse.status < 200 || this.latestResponse.status >= 300;
1004
+ }
1005
+ class Subject {
1006
+ constructor() {
1007
+ /* A single BroadcastChannel cannot send AND receive messages, afaik.
1008
+ * => We maintain here channels for *sending* messages.
1009
+ * *Receiving* channels will be instantiated while subscribing.
1010
+ */
1011
+ a(this, "publishChannels", /* @__PURE__ */ new Map());
885
1012
  }
886
- async get(e, t) {
887
- try {
888
- const s = await this.axios.get(
889
- this.toCdnUrl(e),
890
- this.toAxiosConfig(t)
891
- );
892
- return this.mapAxiosResponse(s, t);
893
- } catch (s) {
894
- throw this.mapAxiosError(s, t);
895
- }
1013
+ getChannelName(e) {
1014
+ return "Subject:" + e;
896
1015
  }
897
- async post(e, t, s) {
898
- try {
899
- const r = await this.axios.post(
900
- this.fixBaseUrl(e),
901
- t,
902
- this.toAxiosConfig(s)
903
- );
904
- return this.mapAxiosResponse(r, s);
905
- } catch (r) {
906
- throw this.mapAxiosError(r, s);
907
- }
1016
+ getPublishChannel(e) {
1017
+ const t = this.getChannelName(e);
1018
+ let s = this.publishChannels.get(t);
1019
+ return s || (s = this.newChannel(e), this.publishChannels.set(t, s)), s;
908
1020
  }
909
- async postFile(e, t, s) {
910
- const r = this.toAxiosConfig(s);
911
- r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
912
- try {
913
- const i = await this.axios.post(this.fixBaseUrl(e), t, {
914
- ...r,
915
- headers: {
916
- "Content-Type": "multipart/form-data"
917
- }
918
- });
919
- return this.mapAxiosResponse(i, s);
920
- } catch (i) {
921
- throw this.mapAxiosError(i, s);
922
- }
1021
+ newChannel(e) {
1022
+ const t = this.getChannelName(e), s = new BroadcastChannel(t);
1023
+ return s.addEventListener("messageerror", (r) => console.log(r.data)), s;
923
1024
  }
924
- async postJson(e, t, s) {
925
- const r = this.toAxiosConfig();
926
- r.headers && (r.headers["Content-Type"] = "application/json");
927
- try {
928
- const i = await this.axios.post(
929
- this.fixBaseUrl(e),
930
- t,
931
- this.toAxiosConfig(s)
932
- );
933
- return this.mapAxiosResponse(i, s);
934
- } catch (i) {
935
- throw this.mapAxiosError(i, s);
936
- }
1025
+ publish(e, t) {
1026
+ typeof e == "string" && this.getPublishChannel(e).postMessage(t);
937
1027
  }
938
- async put(e, t, s) {
939
- try {
940
- const r = await this.axios.put(
941
- this.fixBaseUrl(e),
942
- t,
943
- this.toAxiosConfig(s)
944
- );
945
- return this.mapAxiosResponse(r, s);
946
- } catch (r) {
947
- throw this.mapAxiosError(r, s);
948
- }
1028
+ subscribe(e, t) {
1029
+ if (typeof e == "string") {
1030
+ const s = this.newChannel(e);
1031
+ return new Subscription(s, t);
1032
+ } else
1033
+ return new Subscription();
949
1034
  }
950
- async putFile(e, t, s) {
951
- try {
952
- const r = this.toAxiosConfig(s);
953
- r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
954
- const i = await this.axios.put(this.fixBaseUrl(e), t, {
955
- ...r,
956
- headers: {
957
- "Content-Type": "multipart/form-data"
958
- }
959
- });
960
- return this.mapAxiosResponse(i, s);
961
- } catch (r) {
962
- throw this.mapAxiosError(r, s);
963
- }
1035
+ }
1036
+ const ASYNC_DATA_NAME = {
1037
+ SESSION_READY: "sessionReady",
1038
+ LANG_READY: "langReady",
1039
+ SKIN_READY: "skinReady",
1040
+ OVERRIDE_READY: "overrideReady",
1041
+ APPCONF_READY: "appConfReady"
1042
+ };
1043
+ class Promisified {
1044
+ constructor() {
1045
+ //-------------------------------------
1046
+ a(this, "_resolution");
1047
+ a(this, "_rejection");
1048
+ a(this, "_promise", new Promise((e, t) => {
1049
+ this._resolution = e, this._rejection = t;
1050
+ }));
964
1051
  }
965
- async putJson(e, t, s) {
966
- const r = this.toAxiosConfig(s);
967
- r.headers && (r.headers["Content-Type"] = "application/json");
968
- try {
969
- const i = await this.axios.put(this.fixBaseUrl(e), t, r);
970
- return this.mapAxiosResponse(i, s);
971
- } catch (i) {
972
- throw this.mapAxiosError(i, s);
973
- }
1052
+ get promise() {
1053
+ return this._promise;
974
1054
  }
975
- async delete(e, t) {
976
- try {
977
- const s = await this.axios.delete(
978
- this.fixBaseUrl(e),
979
- this.toAxiosConfig(t)
980
- );
981
- return this.mapAxiosResponse(s, t);
982
- } catch (s) {
983
- throw this.mapAxiosError(s, t);
984
- }
1055
+ resolve(e) {
1056
+ this._resolution && this._resolution(e);
985
1057
  }
986
- async deleteJson(e, t) {
987
- try {
988
- const s = await this.axios.delete(this.fixBaseUrl(e), {
989
- data: t
990
- });
991
- return this.mapAxiosResponse(s);
992
- } catch (s) {
993
- throw this.mapAxiosError(s);
994
- }
1058
+ reject(e) {
1059
+ this._rejection && this._rejection(e);
995
1060
  }
996
- getScript(e, t, s) {
997
- const r = s ?? "exports", i = this.toAxiosConfig(t);
998
- return i.headers && (i.headers.Accept = "application/javascript"), this.axios.get(this.toCdnUrl(e), i).then((o) => this.mapAxiosResponse(o, t)).then((o) => {
999
- try {
1000
- const a = `"use strict";var ${r.split(".")[0]}={};${o};return ${r};`;
1001
- return Function(a)();
1002
- } catch {
1003
- return o;
1004
- }
1005
- }).catch((o) => {
1006
- throw this.mapAxiosError(o, t), o;
1007
- });
1061
+ }
1062
+ class NotifyFramework {
1063
+ constructor() {
1064
+ //-------------------------------------
1065
+ a(this, "promises", {});
1066
+ a(this, "subject", new Subject());
1008
1067
  }
1009
- loadScript(e, t) {
1010
- return loadedScripts[e] ? Promise.resolve() : this.getScript(e, t).then((s) => {
1011
- loadedScripts[e] = !0;
1012
- });
1068
+ asyncData(e) {
1069
+ return typeof this.promises[e] > "u" && (this.promises[e] = new Promisified()), this.promises[e];
1013
1070
  }
1014
- }
1015
- class RightService {
1016
- constructor(e) {
1017
- this.context = e;
1071
+ onSessionReady() {
1072
+ return this.asyncData(ASYNC_DATA_NAME.SESSION_READY);
1018
1073
  }
1019
- get session() {
1020
- return this.context.session();
1074
+ onLangReady() {
1075
+ return this.asyncData(ASYNC_DATA_NAME.LANG_READY);
1021
1076
  }
1022
- /**
1023
- * Parse right concat as "$TYPE:$ID:$RIGHT"
1024
- * $TYPE = user | group | creator
1025
- * $ID: id of the resource
1026
- * $RIGHT: read | contrib | manage
1027
- *
1028
- * @param right a concat right
1029
- * @returns Right parsed
1030
- */
1031
- parseResourceRight(e) {
1032
- const t = e.split(":");
1033
- if (t.length === 2) {
1034
- if (t[0] === "creator")
1035
- return {
1036
- id: t[1],
1037
- right: "creator",
1038
- type: "creator"
1039
- };
1040
- } else return t.length === 3 ? {
1041
- id: t[1],
1042
- right: t[2],
1043
- type: t[0]
1044
- } : void 0;
1077
+ onSkinReady() {
1078
+ return this.asyncData(ASYNC_DATA_NAME.SKIN_READY);
1045
1079
  }
1046
- /**
1047
- * Parse an array of rights concat as "$TYPE:$ID:$RIGHT"
1048
- * $TYPE = user | group | creator
1049
- * $ID: id of the resource
1050
- * $RIGHT: read | contrib | manage
1051
- *
1052
- * @param rights a list of concat rights
1053
- * @returns Array of Right parsed
1054
- */
1055
- parseResourceRights(e) {
1056
- return e.map((s) => this.parseResourceRight(s)).filter((s) => s !== void 0);
1080
+ onOverridesReady() {
1081
+ return this.asyncData(ASYNC_DATA_NAME.OVERRIDE_READY);
1057
1082
  }
1058
- /**
1059
- * Check wether a user has the expected right for a ressource
1060
- * @param user the userId and groupId concerned by the check
1061
- * @param expect the expected right to check
1062
- * @param rights array of Right for the resource
1063
- * @returns true if has rights
1064
- */
1065
- hasResourceRight({ id: e, groupIds: t }, s, r) {
1066
- const i = r.map((o) => typeof o == "string" ? this.parseResourceRight(o) : o).filter((o) => o !== void 0);
1067
- for (const o of i) {
1068
- if (o.id === e && o.type === "creator")
1069
- return !0;
1070
- if (o.id === e && o.type === "user" && o.right === s)
1071
- return !0;
1072
- if (t.includes(o.id) && o.type === "group" && o.right === s)
1073
- return !0;
1074
- }
1075
- return !1;
1083
+ onAppConfReady() {
1084
+ return this.asyncData(ASYNC_DATA_NAME.APPCONF_READY);
1076
1085
  }
1077
- /**
1078
- * Check wether the current user have resource right
1079
- * @param expect the expected right to check
1080
- * @param rights array of Right for the resource
1081
- * @returns true if has rights
1082
- */
1083
- async sessionHasResourceRight(e, t) {
1084
- try {
1085
- const s = await this.session.getUser();
1086
- return !!s && this.hasResourceRight(
1087
- { groupIds: s.groupsIds, id: s.userId },
1088
- e,
1089
- t
1090
- );
1091
- } catch (s) {
1092
- return console.error(`Unexpected error ${s} in sessionHasResourceRight()`), !1;
1093
- }
1086
+ promisify() {
1087
+ return new Promisified();
1094
1088
  }
1095
- /**
1096
- * Check wether the current user have at least one of resource right expected
1097
- * @param expects array of expected right to check
1098
- * @param rights array of Right for the resource
1099
- * @returns true if has rights
1100
- */
1101
- async sessionHasAtLeastOneResourceRight(e, t) {
1102
- for (const s of e)
1103
- if (await this.sessionHasResourceRight(s, t))
1104
- return !0;
1105
- return !1;
1106
- }
1107
- /**
1108
- * Check wether the current user has resource right for each right list
1109
- * @param expect expected right to check
1110
- * @param rightsArray array of array of Right for multiple resources
1111
- * @returns true if has rights
1112
- */
1113
- async sessionHasResourceRightForEachList(e, t) {
1114
- let s = 0;
1115
- for (const r of t)
1116
- await this.sessionHasResourceRight(e, r) && s++;
1117
- return s === t.length;
1118
- }
1119
- /**
1120
- * Check wether the current user have at least one of resource right for each right list
1121
- * @param expects array of expected right to check
1122
- * @param rightsArray array of array of Right for multiple resources
1123
- * @returns true if has rights
1124
- */
1125
- async sessionHasAtLeastOneResourceRightForEachList(e, t) {
1126
- for (const s of e) {
1127
- let r = 0;
1128
- for (const i of t)
1129
- await this.sessionHasResourceRight(s, i) && r++;
1130
- if (r === t.length)
1131
- return !0;
1132
- }
1133
- return !1;
1134
- }
1135
- hasWorkflowRight(e, t) {
1136
- return t.findIndex((s) => s === e) !== -1;
1137
- }
1138
- /**
1139
- * @param expect a workflow right
1140
- * @returns true if current session has right on it
1141
- */
1142
- async sessionHasWorkflowRight(e) {
1143
- try {
1144
- const t = await this.session.getUser();
1145
- return !!t && this.hasWorkflowRight(
1146
- e,
1147
- t.authorizedActions.map(
1148
- (s) => s.name
1149
- )
1150
- );
1151
- } catch (t) {
1152
- return console.error(`Unexpected error ${t} in sessionHasWorkflowRight()`), !1;
1153
- }
1154
- }
1155
- /**
1156
- * @param expect a workflow right
1157
- * @returns a record with right as key and boolean as value if current session has right on it
1158
- */
1159
- async sessionHasWorkflowRights(e) {
1160
- const t = {};
1161
- try {
1162
- const s = await this.session.getUser();
1163
- for (const r of e)
1164
- t[r] = !!s && this.hasWorkflowRight(
1165
- r,
1166
- s.authorizedActions.map(
1167
- (i) => i.name
1168
- )
1169
- );
1170
- } catch (s) {
1171
- console.error(`Unexpected error ${s} in sessionHasWorkflowRights()`);
1172
- for (const r of e)
1173
- t[r] = !1;
1174
- }
1175
- return t;
1176
- }
1177
- }
1178
- class SessionService {
1179
- constructor(e) {
1180
- this.context = e;
1181
- }
1182
- get http() {
1183
- return this.context.http();
1184
- }
1185
- get cache() {
1186
- return this.context.cache();
1187
- }
1188
- get conf() {
1189
- return this.context.conf();
1190
- }
1191
- /**
1192
- * Callback to call when user logout
1193
- */
1194
- onLogout() {
1195
- this.cache.clearCache();
1196
- }
1197
- /**
1198
- * Callback to call when session change
1199
- */
1200
- onRefreshSession() {
1201
- this.cache.clearCache();
1202
- }
1203
- async getSession() {
1204
- const e = await this.getUser(), [
1205
- t,
1206
- s,
1207
- r,
1208
- i,
1209
- o
1210
- ] = await Promise.all([
1211
- this.getCurrentLanguage(e),
1212
- this.latestQuotaAndUsage(e),
1213
- this.loadDescription(e),
1214
- this.getUserProfile(),
1215
- this.getBookmarks(e)
1216
- ]);
1217
- return {
1218
- user: e,
1219
- quotaAndUsage: s,
1220
- currentLanguage: t,
1221
- userDescription: r,
1222
- userProfile: i,
1223
- bookmarkedApps: o
1224
- };
1225
- }
1226
- login(e, t, s, r) {
1227
- const i = new FormData();
1228
- return i.append("email", e), i.append("password", t), typeof s < "u" && i.append("rememberMe", "" + s), typeof r < "u" && i.append("secureLocation", "" + r), this.http.post("/auth/login", i, {
1229
- headers: { "content-type": "application/x-www-form-urlencoded" }
1230
- }).finally(() => {
1231
- switch (this.http.latestResponse.status) {
1232
- case 200:
1233
- throw ERROR_CODE.MALFORMED_DATA;
1234
- }
1235
- });
1236
- }
1237
- async logout() {
1238
- const e = await this.conf.getLogoutCallback();
1239
- return this.http.get("/auth/logout?callback=" + e).finally(() => {
1240
- });
1241
- }
1242
- async latestQuotaAndUsage(e) {
1243
- const t = { quota: 0, storage: 0 };
1244
- if (!e) return t;
1245
- try {
1246
- return await this.http.get(
1247
- `/workspace/quota/user/${e == null ? void 0 : e.userId}`
1248
- );
1249
- } catch (s) {
1250
- return console.error(s), t;
1251
- }
1252
- }
1253
- async getCurrentLanguage(e) {
1254
- const t = (e == null ? void 0 : e.sessionMetadata) && (e == null ? void 0 : e.sessionMetadata.userId);
1255
- try {
1256
- let s;
1257
- return t ? s = await this.loadUserLanguage() : s = await this.loadDefaultLanguage(), s;
1258
- } catch (s) {
1259
- console.error(s);
1260
- }
1261
- }
1262
- async loadUserLanguage() {
1263
- try {
1264
- const e = await this.http.get(
1265
- "/userbook/preference/language"
1266
- );
1267
- return JSON.parse(e.preference)["default-domain"];
1268
- } catch {
1269
- return await this.loadDefaultLanguage();
1270
- }
1271
- }
1272
- async loadDefaultLanguage() {
1273
- return (await this.cache.httpGetJson(
1274
- "/locale"
1275
- )).locale;
1276
- }
1277
- async getUser() {
1278
- const { response: e, value: t } = await this.cache.httpGet(
1279
- "/auth/oauth2/userinfo"
1280
- );
1281
- if (!(e.status < 200 || e.status >= 300) && typeof t == "object")
1282
- return t;
1283
- throw ERROR_CODE.NOT_LOGGED_IN;
1284
- }
1285
- hasWorkflow({
1286
- workflowName: e,
1287
- user: t
1288
- }) {
1289
- return e === void 0 || (t == null ? void 0 : t.authorizedActions.findIndex((s) => s.name === e)) !== -1;
1290
- }
1291
- async loadDescription(e) {
1292
- if (!e) return {};
1293
- try {
1294
- const [t, s] = await Promise.all([
1295
- // FIXME The full user's description should be obtainable from a single endpoint in the backend.
1296
- this.getUserProfile({
1297
- options: { requestName: "refreshAvatar" }
1298
- }),
1299
- this.http.get("/directory/userbook/" + (e == null ? void 0 : e.userId))
1300
- ]);
1301
- return { ...s, profiles: t };
1302
- } catch (t) {
1303
- return console.error(t), {};
1304
- }
1305
- }
1306
- async getBookmarks(e) {
1307
- if (!e) return [];
1308
- const t = await this.http.get("/userbook/preference/apps");
1309
- t.preference || (t.preference = null);
1310
- const s = JSON.parse(t.preference);
1311
- let r;
1312
- r = s, r || (r = {
1313
- bookmarks: [],
1314
- applications: []
1315
- });
1316
- const i = [];
1317
- return r.bookmarks.forEach((o, a) => {
1318
- const c = ((e == null ? void 0 : e.apps) || []).find(
1319
- (l) => l.name === o
1320
- );
1321
- if (c) {
1322
- const l = Object.assign({}, c);
1323
- i.push(l);
1324
- }
1325
- }), i;
1326
- }
1327
- async getUserProfile(e = {}) {
1328
- var c, l;
1329
- const { options: t = {}, params: s = {} } = e, r = new URLSearchParams(s).toString(), i = `/userbook/api/person${r ? `?${r}` : ""}`, { response: o, value: a } = await this.cache.httpGet(i, t);
1330
- return o.status < 200 || o.status >= 300 || typeof a == "string" ? ["Guest"] : ((l = (c = a == null ? void 0 : a.result) == null ? void 0 : c[0]) == null ? void 0 : l.type) || ["Guest"];
1331
- }
1332
- async isAdml() {
1333
- const e = await this.getUser();
1334
- return (e == null ? void 0 : e.functions.ADMIN_LOCAL) !== void 0;
1335
- }
1336
- /**
1337
- * Get details of an application if the user can access it.
1338
- * @return undefined if no access, or app not found
1339
- */
1340
- async getWebApp(e) {
1341
- const t = await this.getUser();
1342
- return t == null ? void 0 : t.apps.find((s) => {
1343
- var r;
1344
- return s != null && s.prefix ? (s == null ? void 0 : s.prefix.replace("/", "")) === e || !1 : s != null && s.address && ((r = s.address) == null ? void 0 : r.split("/")[1]) === e || !1;
1345
- });
1089
+ events() {
1090
+ return this.subject;
1346
1091
  }
1347
1092
  }
1348
- const bundle = {}, promises = {}, defaultDiacriticsRemovalMap = [
1093
+ const notify = new NotifyFramework(), bundle = {}, promises = {}, defaultDiacriticsRemovalMap = [
1349
1094
  {
1350
1095
  base: "A",
1351
1096
  letters: /[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g
@@ -1592,9 +1337,9 @@ class IdiomService {
1592
1337
  const i = new Promisified();
1593
1338
  promises[t] = i.promise;
1594
1339
  const o = {};
1595
- e && (o["Accept-Language"] = e), this.http.get(t, { headers: o }).then((a) => {
1596
- Object.assign(bundle, a), typeof s == "function" && s(), i.resolve();
1597
- }).catch((a) => {
1340
+ e && (o["Accept-Language"] = e), this.http.get(t, { headers: o }).then((u) => {
1341
+ Object.assign(bundle, u), typeof s == "function" && s(), i.resolve();
1342
+ }).catch((u) => {
1598
1343
  typeof s == "function" && s(), i.reject();
1599
1344
  });
1600
1345
  }
@@ -1627,1409 +1372,1525 @@ class IdiomService {
1627
1372
  return e;
1628
1373
  }
1629
1374
  }
1630
- class StringUtils {
1631
- static removeAccents(e) {
1632
- for (let t = 0; t < defaultDiacriticsRemovalMap.length; t++)
1633
- e = e.replace(
1634
- defaultDiacriticsRemovalMap[t].letters,
1635
- defaultDiacriticsRemovalMap[t].base
1636
- );
1637
- return e;
1638
- }
1639
- }
1640
- class ShareService {
1375
+ class AbstractBehaviourService {
1641
1376
  //
1642
1377
  // IMPLEMENTATION
1643
1378
  //
1644
1379
  constructor(e) {
1645
- this.context = e;
1380
+ //-----------------
1381
+ //--- Utilities ---
1382
+ //-----------------
1383
+ a(this, "_cache");
1384
+ this.context = e, this._cache = new CacheService(this.context);
1646
1385
  }
1647
- get directory() {
1648
- return this.context.directory();
1386
+ getApplication() {
1387
+ return this.APP;
1649
1388
  }
1650
- get http() {
1651
- return this.context.http();
1652
- }
1653
- get cache() {
1654
- return this.context.cache();
1655
- }
1656
- async searchShareSubjects(e, t, s) {
1657
- const r = StringUtils.removeAccents(s).toLowerCase(), i = await this.cache.httpGetJson(
1658
- `/${e}/share/json/${t}?search=${s}`
1659
- ), o = i.users.visibles.filter(({ username: h, firstName: E, lastName: p, login: d }) => {
1660
- const g = StringUtils.removeAccents(
1661
- p || ""
1662
- ).toLowerCase(), A = StringUtils.removeAccents(
1663
- E || ""
1664
- ).toLowerCase(), m = StringUtils.removeAccents(
1665
- h || ""
1666
- ).toLowerCase(), R = StringUtils.removeAccents(d || "").toLowerCase();
1667
- return m.includes(r) || A.includes(r) || g.includes(r) || R.includes(r);
1668
- }).map((h) => ({
1669
- avatarUrl: this.directory.getAvatarUrl(h.id, "user"),
1670
- directoryUrl: this.directory.getDirectoryUrl(h.id, "user"),
1671
- displayName: h.username,
1672
- id: h.id,
1673
- profile: h.profile,
1674
- type: "user"
1675
- })), a = i.groups.visibles.filter(({ name: h }) => StringUtils.removeAccents(h || "").toLowerCase().includes(r)).map((h) => ({
1676
- avatarUrl: this.directory.getAvatarUrl(h.id, "group"),
1677
- directoryUrl: this.directory.getDirectoryUrl(h.id, "group"),
1678
- displayName: h.name,
1679
- id: h.id,
1680
- type: "group",
1681
- structureName: h.structureName
1682
- }));
1683
- return [...(await this.directory.getBookMarks()).filter(({ displayName: h }) => StringUtils.removeAccents(
1684
- h || ""
1685
- ).toLowerCase().includes(r)).map((h) => ({
1686
- avatarUrl: "",
1687
- directoryUrl: "",
1688
- profile: "",
1689
- displayName: h.displayName,
1690
- id: h.id,
1691
- type: "sharebookmark"
1692
- })), ...o, ...a];
1693
- }
1694
- async getShareMapping(e) {
1695
- const t = await this.cache.httpGetJson(
1696
- `/${e}/rights/sharing`
1697
- );
1698
- for (const s of Object.keys(t))
1699
- if (s.includes(".")) {
1700
- const r = s.split(".")[1], i = t[s];
1701
- delete t[s], t[r] = i;
1702
- }
1703
- return t;
1389
+ getResourceType() {
1390
+ return this.RESOURCE;
1704
1391
  }
1705
- getActionsAvailableFor({ id: e, type: t }, s, r) {
1706
- const o = (t === "user" ? s.users.checked[e] : s.groups.checked[e]) || [], a = Object.keys(r), c = [];
1707
- for (const l of a)
1708
- r[l].filter(
1709
- (p) => o.includes(p)
1710
- ).length > 0 && c.push(l);
1711
- return c;
1392
+ httpGet(e, t) {
1393
+ return this._cache.httpGetJson(e, t);
1712
1394
  }
1713
- async getRightsForResource(e, t) {
1714
- const s = await this.directory.getBookMarks(), r = `/${e}/share/json/${t}?search=`, i = await this.cache.httpGetJson(r), o = await this.getShareMapping(e), a = await this.cache.httpGetJson(
1715
- "/infra/public/json/sharing-rights.json"
1716
- ), c = Object.keys(i.users.checked).map((d) => i.users.visibles.find(
1717
- (A) => A.id === d
1718
- )).filter((d) => d !== void 0).map((d) => {
1719
- const g = this.getActionsAvailableFor(
1720
- { id: d.id, type: "user" },
1721
- i,
1722
- o
1723
- );
1724
- return {
1725
- id: d.id,
1726
- type: "user",
1727
- displayName: d.username,
1728
- profile: d.profile,
1729
- avatarUrl: this.directory.getAvatarUrl(d.id, "user"),
1730
- directoryUrl: this.directory.getDirectoryUrl(d.id, "user"),
1731
- actions: g.map((m) => {
1732
- const R = a[m];
1733
- return {
1734
- displayName: m,
1735
- id: m,
1736
- priority: R.priority
1737
- };
1738
- })
1739
- };
1740
- }).sort((d, g) => (d.displayName || "").localeCompare(g.displayName)), l = Object.keys(i.groups.checked).map((d) => i.groups.visibles.find(
1741
- (A) => A.id === d
1742
- )).filter((d) => d !== void 0).map((d) => {
1743
- const g = this.getActionsAvailableFor(
1744
- { id: d.id, type: "group" },
1745
- i,
1746
- o
1747
- );
1748
- return {
1749
- id: d.id,
1750
- type: "group",
1751
- displayName: d.name,
1752
- profile: void 0,
1753
- avatarUrl: this.directory.getAvatarUrl(d.id, "group"),
1754
- directoryUrl: this.directory.getDirectoryUrl(d.id, "group"),
1755
- actions: g.map((m) => {
1756
- const R = a[m];
1757
- return {
1758
- displayName: m,
1759
- id: m,
1760
- priority: R.priority
1761
- };
1762
- })
1763
- };
1764
- }).sort((d, g) => (d.displayName || "").localeCompare(g.displayName)), h = [...c, ...l], E = i.groups.visibles.map(
1765
- ({ groupDisplayName: d, id: g, name: A }) => ({
1766
- displayName: d || A,
1767
- id: g
1768
- })
1769
- ), p = i.users.visibles.map(
1770
- ({ id: d, profile: g, username: A, firstName: m, lastName: R, login: v }) => ({
1771
- displayName: A,
1772
- firstName: m,
1773
- lastName: R,
1774
- login: v,
1775
- profile: g,
1776
- id: d
1777
- })
1778
- );
1395
+ /* Utility to map data between linker model and search model. */
1396
+ dataToResource({
1397
+ modified: e,
1398
+ ...t
1399
+ }) {
1400
+ const s = typeof e == "string" ? e : e != null && e.$date ? "" + e.$date : "";
1779
1401
  return {
1780
- rights: h,
1781
- visibleBookmarks: s,
1782
- visibleGroups: E,
1783
- visibleUsers: p
1402
+ application: this.RESOURCE,
1403
+ name: t.title,
1404
+ creatorId: t.owner,
1405
+ creatorName: t.ownerName,
1406
+ thumbnail: t.icon,
1407
+ assetId: t._id,
1408
+ modifiedAt: s,
1409
+ shared: t.shared,
1410
+ path: t.path
1784
1411
  };
1785
1412
  }
1786
- async saveRights(e, t, s) {
1787
- const r = await this.getShareMapping(e), i = {
1788
- bookmarks: {},
1789
- groups: {},
1790
- users: {}
1791
- };
1792
- for (const c of s) {
1793
- const l = c.actions.map((E) => r[E.id]).reduce((E, p) => Array.isArray(p) ? [...E, ...p] : E, []), h = [...new Set(l)];
1794
- h.length > 0 && (c.type === "user" ? i.users[c.id] = h : c.type === "group" ? i.groups[c.id] = h : i.bookmarks[c.id] = h);
1795
- }
1796
- const o = `/${e}/share/resource/${t}`;
1797
- return this.cache.clearCache(`/${e}/share/json/${t}?search=`), await this.http.putJson(o, i);
1413
+ }
1414
+ class ActualitesBehaviour extends AbstractBehaviourService {
1415
+ constructor() {
1416
+ super(...arguments);
1417
+ a(this, "APP", "actualites");
1418
+ a(this, "RESOURCE", "actualites");
1798
1419
  }
1799
- async getActionsForApp(e) {
1800
- const t = await this.cache.httpGetJson(
1801
- "/infra/public/json/sharing-rights.json"
1802
- ), s = await this.getShareMapping(e);
1803
- return Object.keys(t).map((i) => {
1804
- const o = t[i];
1805
- return {
1806
- displayName: i,
1807
- id: i,
1808
- priority: o.priority,
1809
- requires: o.requires
1810
- };
1811
- }).filter((i) => {
1812
- var o;
1813
- return ((o = s[i.id]) == null ? void 0 : o.length) > 0;
1814
- }).sort((i, o) => i.priority - o.priority);
1420
+ async loadResources() {
1421
+ return (await this.httpGet(
1422
+ "/actualites/linker/infos"
1423
+ )).map((s) => {
1424
+ var r;
1425
+ return s.thread_icon ? r = s.thread_icon + "?thumbnail=48x48" : r = "/img/icons/glyphicons_036_file.png", this.dataToResource({
1426
+ title: s.title + " [" + s.thread_title + "]",
1427
+ ownerName: s.username,
1428
+ owner: s.owner,
1429
+ icon: r,
1430
+ path: "/actualites#/view/thread/" + s.thread_id + "/info/" + s._id,
1431
+ _id: `${s.thread_id}#${s._id}`,
1432
+ shared: !!(s.shared && s.shared.length >= 0),
1433
+ modified: s.modified
1434
+ });
1435
+ });
1815
1436
  }
1816
1437
  }
1817
- const defaultMappers = {
1818
- csv: function({ type: n, extension: e }) {
1819
- return MimeTypeUtils.INSTANCE.isCsvLike(n, e);
1820
- },
1821
- doc: function({ type: n, extension: e }) {
1822
- return MimeTypeUtils.INSTANCE.isWordLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("wordprocessing") !== -1;
1823
- },
1824
- xls: function({ type: n, extension: e }) {
1825
- return MimeTypeUtils.INSTANCE.isExcelLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("spreadsheet") !== -1 || n.indexOf("ms-excel") !== -1;
1826
- },
1827
- img: function({ type: n }) {
1828
- return n.indexOf("image") !== -1;
1829
- },
1830
- pdf: function({ type: n }) {
1831
- return n.indexOf("pdf") !== -1 || n === "application/x-download";
1832
- },
1833
- ppt: function({ type: n, extension: e }) {
1834
- return MimeTypeUtils.INSTANCE.isPowerpointLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("presentation") !== -1 || n.indexOf("powerpoint") !== -1;
1835
- },
1836
- txt: function({ type: n, extension: e }) {
1837
- return MimeTypeUtils.INSTANCE.isTxtLike(n, e);
1838
- },
1839
- md: function({ type: n, extension: e }) {
1840
- return MimeTypeUtils.INSTANCE.isMdLike(n, e);
1841
- },
1842
- video: function({ type: n }) {
1843
- return n.indexOf("video") !== -1;
1844
- },
1845
- audio: function({ type: n }) {
1846
- return n.indexOf("audio") !== -1;
1847
- },
1848
- zip: function({ type: n }) {
1849
- return n.indexOf("zip") !== -1 || n.indexOf("rar") !== -1 || n.indexOf("tar") !== -1 || n.indexOf("7z") !== -1;
1438
+ class BlogBehaviour extends AbstractBehaviourService {
1439
+ constructor() {
1440
+ super(...arguments);
1441
+ a(this, "APP", "blog");
1442
+ a(this, "RESOURCE", "blog");
1850
1443
  }
1851
- }, b = class b {
1852
- /* Similar role notion as in infra-front > workspace > Model.ts */
1853
- static getRole(e) {
1854
- var t, s;
1855
- return b.role(
1856
- (t = e.metadata) == null ? void 0 : t["content-type"],
1857
- !1,
1858
- (s = e.metadata) == null ? void 0 : s.extension
1444
+ loadResources() {
1445
+ return new Promise(async (t, s) => {
1446
+ try {
1447
+ const r = await this.httpGet("/blog/linker"), i = [];
1448
+ r.forEach((o) => {
1449
+ o.thumbnail ? o.thumbnail = o.thumbnail + "?thumbnail=48x48" : o.thumbnail = "/img/illustrations/blog.svg";
1450
+ const u = o.fetchPosts.map((c) => this.dataToResource({
1451
+ owner: o.author.userId,
1452
+ ownerName: o.author.username,
1453
+ title: c.title + " [" + o.title + "]",
1454
+ _id: `${o._id}#${c._id}`,
1455
+ icon: o.thumbnail,
1456
+ path: `/blog/id/${o._id}/post/${c._id}`,
1457
+ shared: !!(o.shared && o.shared.length >= 0),
1458
+ modified: o.modified
1459
+ }));
1460
+ i.push(...u);
1461
+ }), t(i);
1462
+ } catch (r) {
1463
+ s(r);
1464
+ }
1465
+ });
1466
+ }
1467
+ }
1468
+ class CollaborativewallBehaviour extends AbstractBehaviourService {
1469
+ constructor() {
1470
+ super(...arguments);
1471
+ a(this, "APP", "collaborativewall");
1472
+ a(this, "RESOURCE", "collaborativewall");
1473
+ }
1474
+ async loadResources() {
1475
+ return (await this.httpGet(
1476
+ "/collaborativewall/list/all"
1477
+ )).map(
1478
+ (s) => this.dataToResource({
1479
+ title: s.name,
1480
+ ownerName: s.owner.displayName,
1481
+ owner: s.owner.userId,
1482
+ icon: s.icon ? s.icon : "/img/illustrations/collaborative-wall-default.png",
1483
+ path: "/collaborativewall#/view/" + s._id,
1484
+ _id: s._id,
1485
+ shared: !!(s.shared && s.shared.length >= 0),
1486
+ modified: s.modified
1487
+ })
1859
1488
  );
1860
1489
  }
1861
- /* Similar role notion as in infra-front > workspace > Model.ts */
1862
- static role(e, t = !1, s) {
1863
- if (s && (s = s.trim()), !e) return "unknown";
1864
- this.roleMappers || console.warn("[DocumentHelper.role] should not have empty roles", this);
1865
- const r = { type: e, previewRole: t, extension: s };
1866
- for (const i of this.roleMappers) {
1867
- const o = i(r);
1868
- if (o)
1869
- return o;
1870
- }
1871
- return "unknown";
1490
+ }
1491
+ class CommunityBehaviour extends AbstractBehaviourService {
1492
+ constructor() {
1493
+ super(...arguments);
1494
+ a(this, "APP", "community");
1495
+ a(this, "RESOURCE", "community");
1872
1496
  }
1873
- };
1874
- // FIXME add edumedia support
1875
- u(b, "roleMappers", [
1876
- (e) => Object.keys(defaultMappers).find((s) => defaultMappers[s](e))
1877
- ]);
1878
- let DocumentHelper = b;
1879
- class WorkspaceService {
1880
- constructor(e) {
1881
- this.context = e;
1497
+ async loadResources() {
1498
+ return (await this.httpGet(
1499
+ "/community/listallpages"
1500
+ )).map((s) => {
1501
+ var r;
1502
+ return typeof s.thumbnail > "u" || s.thumbnail === "" ? r = "/img/icons/glyphicons_036_file.png" : r = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
1503
+ title: s.name,
1504
+ icon: r,
1505
+ path: "/community#/view/" + s.id,
1506
+ _id: s.id,
1507
+ owner: "",
1508
+ ownerName: "",
1509
+ shared: !!(s.shared && s.shared.length >= 0),
1510
+ modified: s.name
1511
+ // FIXME date ?
1512
+ });
1513
+ });
1882
1514
  }
1883
- get http() {
1884
- return this.context.http();
1515
+ }
1516
+ class ExercizerBehaviour extends AbstractBehaviourService {
1517
+ constructor() {
1518
+ super(...arguments);
1519
+ a(this, "APP", "exercizer");
1520
+ a(this, "RESOURCE", "exercizer");
1885
1521
  }
1886
- extractMetadata(e) {
1887
- const t = e.name || "", s = t.split("."), r = e.type || "application/octet-stream", i = s.length > 1 ? s[s.length - 1] : "", o = {
1888
- "content-type": r,
1889
- filename: t,
1890
- size: e.size,
1891
- extension: i,
1892
- role: DocumentHelper.role(r, !1, i)
1893
- }, a = t.replace("." + o.extension, ""), c = o.extension ? a + "." + o.extension : a;
1894
- return { basename: a, fullname: c, metadata: o };
1522
+ async loadResources() {
1523
+ return (await this.httpGet(
1524
+ "/exercizer/subjects-scheduled"
1525
+ )).map((s) => {
1526
+ const r = s.picture ? s.picture + "?thumbnail=48x48" : "/img/illustrations/exercizer.svg";
1527
+ let i, o = !1, u = JSON.parse(s.scheduled_at);
1528
+ return u.groupList.length > 0 ? (o = !0, i = u.groupList[0].name) : u.userList.length > 0 ? (o = !0, i = u.userList[0].name) : i = "", u.groupList.length + u.userList.length > 1 && (i += "..."), this.dataToResource({
1529
+ title: s.title,
1530
+ owner: s.owner,
1531
+ ownerName: i,
1532
+ icon: r,
1533
+ path: "/exercizer#/linker/" + s.id,
1534
+ _id: "" + s.id,
1535
+ shared: o,
1536
+ modified: s.modified
1537
+ });
1538
+ });
1895
1539
  }
1896
- async saveFile(e, t) {
1897
- const { fullname: s, metadata: r } = this.extractMetadata(e), i = new FormData();
1898
- i.append("file", e, s);
1899
- const o = [];
1900
- ((t == null ? void 0 : t.visibility) === "public" || (t == null ? void 0 : t.visibility) === "protected") && o.push(`${t.visibility}=true`), t != null && t.application && o.push(`application=${t.application}`), r.role === "img" && o.push("quality=1"), t != null && t.parentId && o.push(`parentId=${t.parentId}`);
1901
- const a = await this.http.postFile(
1902
- `/workspace/document?${o.join("&")}`,
1903
- i
1904
- );
1905
- if (this.http.isResponseError())
1906
- throw this.http.latestResponse.statusText;
1907
- return a;
1540
+ }
1541
+ class FormulaireBehaviour extends AbstractBehaviourService {
1542
+ constructor() {
1543
+ super(...arguments);
1544
+ a(this, "APP", "formulaire");
1545
+ a(this, "RESOURCE", "formulaire");
1546
+ }
1547
+ async loadResources() {
1548
+ return (await this.httpGet(
1549
+ "/formulaire/forms/linker"
1550
+ )).map((s) => (s.picture || (s.picture = "/formulaire/public/img/logo.svg"), this.dataToResource({
1551
+ _id: "" + s.id,
1552
+ icon: s.picture,
1553
+ title: s.title,
1554
+ ownerName: s.owner_name,
1555
+ owner: s.owner_id,
1556
+ path: s.is_public ? `${window.location.origin}/formulaire-public#/form/${s.public_key}` : `${window.location.origin}/formulaire#/form/${s.id}/${s.rgpd ? "rgpd" : "new"}`,
1557
+ shared: !!(s.shared && s.shared.length >= 0),
1558
+ modified: "" + s.date_modification
1559
+ })));
1908
1560
  }
1909
- async updateFile(e, t, s) {
1910
- const { fullname: r, metadata: i } = this.extractMetadata(t), o = new FormData();
1911
- o.append("file", t, r);
1912
- const a = [];
1913
- i.role === "img" && a.push("quality=1"), s != null && s.alt && a.push(`alt=${s.alt}`), s != null && s.legend && a.push(`legend=${s.legend}`), s != null && s.name && a.push(`name=${s.name}`);
1914
- const c = await this.http.putFile(
1915
- `/workspace/document/${e}?${a.join("&")}`,
1916
- o
1561
+ }
1562
+ class ForumBehaviour extends AbstractBehaviourService {
1563
+ constructor() {
1564
+ super(...arguments);
1565
+ a(this, "APP", "forum");
1566
+ a(this, "RESOURCE", "forum");
1567
+ }
1568
+ async loadResources() {
1569
+ return (await this.httpGet("/forum/categories")).map(
1570
+ (s) => this.dataToResource({
1571
+ _id: s._id,
1572
+ title: s.name,
1573
+ icon: s.icon || "/img/illustrations/forum.svg",
1574
+ path: "/forum#/view/" + s._id,
1575
+ ownerName: s.owner.displayName,
1576
+ owner: s.owner.userId,
1577
+ shared: !!(s.shared && s.shared.length >= 0),
1578
+ modified: s.modified
1579
+ })
1917
1580
  );
1918
- if (this.http.isResponseError())
1919
- throw this.http.latestResponse.statusText;
1920
- return c;
1921
1581
  }
1922
- async deleteFile(e) {
1923
- const t = e.map((s) => s._id);
1924
- if (t.length == 0)
1925
- Promise.resolve(null);
1926
- else if (await this.http.deleteJson("/workspace/documents", {
1927
- ids: t
1928
- }), this.http.isResponseError())
1929
- throw this.http.latestResponse.statusText;
1582
+ }
1583
+ class HomeworksBehaviour extends AbstractBehaviourService {
1584
+ constructor() {
1585
+ super(...arguments);
1586
+ a(this, "APP", "homeworks");
1587
+ a(this, "RESOURCE", "homeworks");
1930
1588
  }
1931
- async acceptDocuments(e) {
1932
- const t = await this.context.session().getUser();
1933
- return (s) => s.deleted && s.trasher ? (t == null ? void 0 : t.userId) == s.trasher : !0;
1589
+ async loadResources() {
1590
+ return (await this.httpGet("/homeworks/list")).filter((t) => t.owner && t.trashed === 0).map((t) => this.dataToResource({
1591
+ title: t.title,
1592
+ ownerName: t.owner.displayName,
1593
+ owner: t.owner.userId,
1594
+ icon: t.thumbnail || "/img/illustrations/homeworks.svg",
1595
+ path: "/homeworks#/view-homeworks/" + t._id,
1596
+ _id: "" + t._id,
1597
+ shared: typeof t.shared < "u",
1598
+ modified: t.modified
1599
+ }));
1934
1600
  }
1935
- async searchDocuments(e) {
1936
- const t = e.filter !== "external" || e.parentId ? await this.http.get("/workspace/documents", {
1937
- queryParams: { ...e, _: (/* @__PURE__ */ new Date()).getTime() }
1938
- }) : [], s = await this.acceptDocuments(e);
1939
- return t.filter(s);
1601
+ }
1602
+ class MagnetoBehaviour extends AbstractBehaviourService {
1603
+ constructor() {
1604
+ super(...arguments);
1605
+ a(this, "APP", "magneto");
1606
+ a(this, "RESOURCE", "magneto");
1940
1607
  }
1941
- async listDocuments(e, t) {
1942
- return this.searchDocuments({ filter: e, parentId: t, includeall: !0 });
1608
+ async loadResources() {
1609
+ const { all: t } = await this.httpGet(
1610
+ "/magneto/boards/editable"
1611
+ );
1612
+ return t.map((s) => this.dataToResource({
1613
+ _id: s._id,
1614
+ title: s.title,
1615
+ icon: s.imageUrl,
1616
+ owner: s.ownerId,
1617
+ ownerName: s.ownerName,
1618
+ path: `/magneto#/board/${s._id}/view`,
1619
+ shared: !!(s.shared && s.shared.length >= 0),
1620
+ modified: "" + s.modificationDate
1621
+ }));
1943
1622
  }
1944
- /**
1945
- * Duplicate and transfers documents if needed to a different folder with the specified application and visibility.
1946
- * @param documents - The array of documents to transfer.
1947
- * @param application - The application to associate with the transferred documents.
1948
- * @param visibility - The visibility of the transferred documents. Defaults to "protected".
1949
- * @returns A Promise that resolves to an array of transferred WorkspaceElements.
1950
- */
1951
- async transferDocuments(e, t, s = "protected") {
1952
- const r = [];
1953
- if (e.forEach((i) => {
1954
- (s === "public" && !i.public || !i.public && !i.protected) && r.push(i);
1955
- }), r.length > 0) {
1956
- const i = await this.http.post(
1957
- "/workspace/documents/transfer",
1958
- {
1959
- application: t,
1960
- visibility: s,
1961
- ids: r.map((o) => o._id)
1962
- }
1963
- );
1964
- if (this.http.isResponseError())
1965
- throw this.http.latestResponse.statusText;
1966
- return r.forEach((o, a) => {
1967
- const c = e.findIndex(
1968
- (l) => l._id === o._id
1969
- );
1970
- 0 <= c && c < e.length && (e[c] = i[a]);
1971
- }), e.filter((o) => !!o);
1972
- }
1973
- return e;
1623
+ }
1624
+ class MindmapBehaviour extends AbstractBehaviourService {
1625
+ constructor() {
1626
+ super(...arguments);
1627
+ a(this, "APP", "mindmap");
1628
+ a(this, "RESOURCE", "mindmap");
1974
1629
  }
1975
- /**
1976
- * Get the URL of the thumbnail of a workspace element (or its URL),
1977
- * or `null` if none exists or can be created.
1978
- */
1979
- getThumbnailUrl(e, t = 0, s = 0) {
1980
- var i, o;
1981
- const r = t > 0 || s > 0 ? `${t}x${s}` : "120x120";
1982
- if (typeof e == "string")
1983
- return e.includes("data:image") || e.includes("thumbnail") ? e : `${e}${e.includes("?") ? "&" : "?"}thumbnail=${r}`;
1984
- {
1985
- const a = `/workspace/${e.public ? "pub/" : ""}document/${e._id}?thumbnail=`, c = e.thumbnails;
1986
- if ((o = (i = e.metadata) == null ? void 0 : i["content-type"]) != null && o.includes("video")) {
1987
- const l = c && Object.keys(c).length > 0 ? Object.keys(c)[0] : null;
1988
- return l ? a + l : null;
1989
- } else
1990
- return a + r;
1991
- }
1630
+ async loadResources() {
1631
+ return (await this.httpGet("/mindmap/list/all")).map(
1632
+ (s) => this.dataToResource({
1633
+ title: s.name,
1634
+ ownerName: s.owner.displayName,
1635
+ owner: s.owner.userId,
1636
+ icon: s.thumbnail || "/img/illustrations/mindmap-default.png",
1637
+ path: "/mindmap#/view/" + s._id,
1638
+ _id: s._id,
1639
+ shared: !!(s.shared && s.shared.length >= 0),
1640
+ modified: s.modified
1641
+ })
1642
+ );
1992
1643
  }
1993
1644
  }
1994
- let ATTag;
1995
- class AnalyticsService {
1996
- constructor(n) {
1997
- this.context = n;
1998
- }
1999
- get conf() {
2000
- return this.context.conf();
1645
+ class PagesBehaviour extends AbstractBehaviourService {
1646
+ constructor() {
1647
+ super(...arguments);
1648
+ a(this, "APP", "pages");
1649
+ a(this, "RESOURCE", "pages");
2001
1650
  }
2002
- get http() {
2003
- return this.context.http();
1651
+ async loadResources() {
1652
+ const t = await this.httpGet("/pages/list/all"), s = [];
1653
+ return t.forEach((r) => {
1654
+ var o;
1655
+ const i = r.thumbnail ? r.thumbnail + "?thumbnail=48x48" : "/img/illustrations/pages.svg";
1656
+ s.push(
1657
+ this.dataToResource({
1658
+ title: r.title,
1659
+ owner: r.owner.userId,
1660
+ ownerName: r.owner.displayName,
1661
+ icon: i,
1662
+ path: "/pages#/website/" + r._id,
1663
+ _id: r._id,
1664
+ shared: typeof r.shared < "u",
1665
+ modified: r.modified
1666
+ })
1667
+ ), (o = r.pages) == null || o.forEach((u) => {
1668
+ s.push(
1669
+ this.dataToResource({
1670
+ title: u.title,
1671
+ owner: r.owner.userId,
1672
+ ownerName: r.owner.displayName,
1673
+ icon: i,
1674
+ path: "/pages#/website/" + r._id + "/" + u.titleLink,
1675
+ _id: r._id + "/" + u.titleLink,
1676
+ shared: typeof r.shared < "u",
1677
+ modified: r.modified
1678
+ })
1679
+ );
1680
+ });
1681
+ }), s;
2004
1682
  }
2005
- get session() {
2006
- return this.context.session();
1683
+ }
1684
+ class PollBehaviour extends AbstractBehaviourService {
1685
+ constructor() {
1686
+ super(...arguments);
1687
+ a(this, "APP", "poll");
1688
+ a(this, "RESOURCE", "poll");
2007
1689
  }
2008
- /**
2009
- * Xiti tracker for page loading.
2010
- * @param locationPath
2011
- * @param app
2012
- */
2013
- async trackPageLoad(n, e) {
2014
- const [t] = await Promise.all([
2015
- // get Xiti configuration
2016
- this.getXitiConfig(e.name.toLowerCase()),
2017
- // load Xiti javascript file
2018
- this.loadXitiScript()
2019
- ]);
2020
- if (!t || !ATInternet) return;
2021
- let s = t.LIBELLE_SERVICE.default || null;
2022
- for (const r in t.LIBELLE_SERVICE)
2023
- if (r !== "default" && n.indexOf(r) >= 0) {
2024
- s = t.LIBELLE_SERVICE[r];
2025
- break;
2026
- }
2027
- ATTag = new ATInternet.Tracker.Tag({ site: t.STRUCT_ID }), ATTag.setProps(
2028
- {
2029
- SERVICE: s,
2030
- TYPE: t.TYPE,
2031
- OUTIL: t.OUTIL,
2032
- UAI: t.STRUCT_UAI,
2033
- PROJET: t.PROJET,
2034
- EXPLOITANT: t.EXPLOITANT,
2035
- PLATEFORME: t.PLATFORME,
2036
- PROFIL: t.PROFILE
2037
- },
2038
- !0
2039
- ), ATTag.identifiedVisitor.set({
2040
- id: t.ID_PERSO,
2041
- category: t.PROFILE
2042
- }), ATTag.page.set({
2043
- name: (e == null ? void 0 : e.prefix) === "userbook" ? "directory" : e == null ? void 0 : e.prefix,
2044
- chapter1: "",
2045
- chapter2: "",
2046
- chapter3: "",
2047
- level2: t.STRUCT_UAI
2048
- }), ATTag.dispatch();
1690
+ async loadResources() {
1691
+ return (await this.httpGet("/poll/list/all")).map((s) => {
1692
+ const r = s.icon ? s.icon + "?thumbnail=48x48" : "/img/icons/glyphicons_036_file.png";
1693
+ return this.dataToResource({
1694
+ title: s.question,
1695
+ ownerName: s.owner.displayName,
1696
+ icon: r,
1697
+ path: "/poll#/view/" + s._id,
1698
+ _id: s._id,
1699
+ owner: s.owner.userId,
1700
+ shared: !!(s.shared && s.shared.length >= 0),
1701
+ modified: s.modified
1702
+ });
1703
+ });
2049
1704
  }
2050
- async getXitiConfig(n) {
2051
- const [e, t] = await Promise.all([
2052
- this.http.get("/analyticsConf"),
2053
- //FIXME change servers config to only keep the "all-in-one" query to /analyticsConf.
2054
- this.http.get("/xiti/config")
2055
- ]);
2056
- if (!(e != null && e.type))
2057
- throw ERROR_CODE.MALFORMED_DATA;
2058
- return t != null && t.active && (e.xiti = await this.getXitiTrackingParams(t, n)), e.xiti;
1705
+ }
1706
+ class ScrapbookBehaviour extends AbstractBehaviourService {
1707
+ constructor() {
1708
+ super(...arguments);
1709
+ a(this, "APP", "scrapbook");
1710
+ a(this, "RESOURCE", "scrapbook");
2059
1711
  }
2060
- async loadXitiScript() {
2061
- if (typeof ATInternet > "u") {
2062
- const scriptPath = "/xiti/public/js/lib/smarttag_ENT.js", response = await this.http.get(scriptPath, {
2063
- headers: { Accept: "application/javascript" }
1712
+ async loadResources() {
1713
+ return (await this.httpGet(
1714
+ "/scrapbook/list/all"
1715
+ )).map((s) => {
1716
+ const r = s.icon || "/img/illustrations/scrapbook.svg";
1717
+ return this.dataToResource({
1718
+ title: s.name,
1719
+ owner: s.owner.userId,
1720
+ ownerName: s.owner.displayName,
1721
+ icon: r,
1722
+ path: "/scrapbook#/view-scrapbook/" + s._id,
1723
+ _id: s._id,
1724
+ shared: !!(s.shared && s.shared.length >= 0),
1725
+ modified: s.modified
2064
1726
  });
2065
- if (this.http.latestResponse.status != 200)
2066
- throw "Error while loading XiTi script";
2067
- eval(response);
2068
- }
1727
+ });
2069
1728
  }
2070
- async getXitiTrackingParams(n, e) {
2071
- if (!n.structureMap || !e) return;
2072
- const t = await this.session.getUser(), s = await this.session.getUserProfile();
2073
- let r;
2074
- if (!(t != null && t.structures)) return;
2075
- for (const l of t.structures) {
2076
- const h = n.structureMap[l];
2077
- if (h && h.collectiviteId && h.UAI) {
2078
- r = h;
2079
- break;
1729
+ }
1730
+ class TimelinegeneratorBehaviour extends AbstractBehaviourService {
1731
+ constructor() {
1732
+ super(...arguments);
1733
+ a(this, "APP", "timelinegenerator");
1734
+ a(this, "RESOURCE", "timelinegenerator");
1735
+ }
1736
+ loadResources() {
1737
+ return new Promise(async (t, s) => {
1738
+ try {
1739
+ const i = (await this.httpGet(
1740
+ "/timelinegenerator/timelines"
1741
+ )).map((o) => {
1742
+ const u = o.icon || "/img/illustrations/timeline-default.png";
1743
+ return this.dataToResource({
1744
+ title: o.headline,
1745
+ ownerName: o.owner.displayName,
1746
+ owner: o.owner.userId,
1747
+ icon: u,
1748
+ path: "/timelinegenerator#/view/" + o._id,
1749
+ _id: o._id,
1750
+ shared: typeof o.shared < "u",
1751
+ modified: o.modified
1752
+ });
1753
+ });
1754
+ t(i);
1755
+ } catch (r) {
1756
+ s(r);
2080
1757
  }
2081
- }
2082
- if (!r || !r.active) return;
2083
- const i = await this.conf.getPublicConf(e);
2084
- if (!i) return;
2085
- const o = i.xiti;
2086
- if (!o || !o.LIBELLE_SERVICE || !r.UAI) return;
2087
- function a(l) {
2088
- let h = "";
2089
- for (let E = 0; E < l.length; E++)
2090
- h += l.charCodeAt(E);
2091
- return h;
2092
- }
2093
- const c = {
2094
- Student: "ELEVE",
2095
- Teacher: "ENSEIGNANT",
2096
- Relative: "PARENT",
2097
- Personnel: "ADMIN_VIE_SCOL_TECH",
2098
- Guest: "AUTRE"
2099
- };
2100
- return {
2101
- LIBELLE_SERVICE: o.LIBELLE_SERVICE,
2102
- // Which property of LIBELLE_SERVICE to use depends on the frontend.
2103
- TYPE: o.OUTIL ? "TIERS" : "NATIF",
2104
- OUTIL: o.OUTIL ? o.OUTIL : "",
2105
- STRUCT_ID: r.collectiviteId,
2106
- STRUCT_UAI: r.UAI,
2107
- PROJET: r.projetId ? r.projetId : n.ID_PROJET,
2108
- EXPLOITANT: n.ID_EXPLOITANT,
2109
- PLATFORME: r.plateformeId ? r.plateformeId : n.ID_PLATEFORME,
2110
- ID_PERSO: a(t.userId),
2111
- PROFILE: s && s.length > 0 ? c[s[0]] ?? "" : ""
2112
- };
1758
+ });
2113
1759
  }
2114
1760
  }
2115
- const w = class w {
2116
- // in minutes. Applies to recorded videos.
2117
- constructor(e) {
2118
- this.context = e;
1761
+ class WikiBehaviour extends AbstractBehaviourService {
1762
+ constructor() {
1763
+ super(...arguments);
1764
+ a(this, "APP", "wiki");
1765
+ a(this, "RESOURCE", "wiki");
2119
1766
  }
2120
- get http() {
2121
- return this.context.http();
1767
+ async loadResources() {
1768
+ return (await this.httpGet(
1769
+ "/wiki/listallpages?visible=true"
1770
+ )).map((s) => s.pages.map((r) => {
1771
+ let i;
1772
+ return typeof s.thumbnail > "u" || s.thumbnail === "" ? i = "/img/icons/glyphicons_036_file.png" : i = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
1773
+ title: r.title + " [" + s.title + "]",
1774
+ ownerName: s.owner.displayName,
1775
+ owner: s.owner.userId,
1776
+ icon: i,
1777
+ path: "/wiki#/view/" + s._id + "/" + r._id,
1778
+ _id: `${s._id}#${r._id}`,
1779
+ shared: typeof s.shared < "u",
1780
+ modified: r.modified
1781
+ });
1782
+ })).flat();
2122
1783
  }
2123
- get conf() {
2124
- return this.context.conf();
1784
+ }
1785
+ class WorkspaceBehaviour extends AbstractBehaviourService {
1786
+ constructor() {
1787
+ super(...arguments);
1788
+ a(this, "APP", "workspace");
1789
+ a(this, "RESOURCE", "workspace");
2125
1790
  }
2126
- /**
2127
- * Returns the video app public conf (maxWeight, maxDuration and accepted extensions)
2128
- * @returns the Video app public conf
2129
- */
2130
- async getVideoConf() {
2131
- var t;
2132
- const e = await this.conf.getPublicConf(
2133
- APP$2.VIDEO
2134
- );
2135
- return {
2136
- maxWeight: (e == null ? void 0 : e["max-videosize-mbytes"]) ?? w.MAX_WEIGHT,
2137
- maxDuration: (e == null ? void 0 : e["max-videoduration-minutes"]) ?? w.MAX_DURATION,
2138
- acceptVideoUploadExtensions: ((t = e == null ? void 0 : e["accept-videoupload-extensions"]) == null ? void 0 : t.map(
2139
- (s) => s.toUpperCase()
2140
- )) ?? []
2141
- };
1791
+ loadResources({ search: t, asset_id: s }) {
1792
+ return new Promise(async (r, i) => {
1793
+ try {
1794
+ let o = "/workspace/documents?filter=all&hierarchical=true";
1795
+ s && s.length ? o += `&search=${t}` : t && t.length && (o += `&search=${t}`);
1796
+ const c = (await this.httpGet(o)).filter((h) => !h.deleted).map((h) => {
1797
+ const l = h.metadata["content-type"] && h.metadata["content-type"].indexOf("image") !== -1 ? `/workspace/document/${h._id}?thumbnail=120x120` : "/img/icons/unknown-large.png";
1798
+ return this.dataToResource({
1799
+ title: h.name,
1800
+ ownerName: h.ownerName,
1801
+ owner: h.owner,
1802
+ icon: l,
1803
+ path: `/workspace/document/${h._id}`,
1804
+ _id: h._id,
1805
+ shared: !!(h.shared && h.shared.length >= 0),
1806
+ modified: h.modified
1807
+ });
1808
+ });
1809
+ r(c);
1810
+ } catch (o) {
1811
+ i(o);
1812
+ }
1813
+ });
2142
1814
  }
2143
- /**
2144
- * Starts the encoding process and check when video is fully processed.
2145
- * @param params cf VideoUploadParams
2146
- * @returns a VideoCheckResponse
2147
- */
2148
- async upload({
2149
- data: e,
2150
- appCode: t,
2151
- captation: s,
2152
- duration: r
2153
- }) {
2154
- if (!e.file)
2155
- throw new Error("Invalid video file.");
2156
- if (!e.filename)
2157
- throw new Error("Invalid video filename");
2158
- const i = `${e.browser.name} ${e.browser.version}`, o = new FormData();
2159
- o.append("device", e.device || ""), o.append("browser", i), o.append("url", e.url), o.append("app", t), o.append("file", e.file, e.filename), o.append("weight", "" + e.file.size), o.append("captation", "" + s);
2160
- let a = `/video/encode?captation=${s}`;
2161
- r && (a += `&duration=${r}`);
2162
- const c = await this.http.post(
2163
- a,
2164
- o,
2165
- { headers: { "Content-Type": "multipart/form-data" } }
2166
- );
2167
- if (c.state == "running") {
2168
- let l = 0, h = 1;
2169
- do {
2170
- const E = h + l;
2171
- await new Promise(
2172
- (d) => setTimeout(d, E * 1e3)
2173
- ), l = h, h = Math.min(8, E);
2174
- const p = await this.http.get(
2175
- `/video/status/${c.processid}`
2176
- );
2177
- if (p.state == "succeed")
2178
- return p.videoworkspaceid && p.videosize && this.context.data().trackVideoSave(
2179
- p.videoworkspaceid,
2180
- Math.round(r),
2181
- p.videosize,
2182
- s,
2183
- e.url,
2184
- i,
2185
- e.device
2186
- ), p;
2187
- if (p.state == "error")
2188
- break;
2189
- } while (!0);
1815
+ }
1816
+ const y = class y {
1817
+ static async initialize(e, t) {
1818
+ const s = e.http();
1819
+ if (!this.resourceProducingApps.length) {
1820
+ this.resourceProducingApps = [t, "workspace"];
1821
+ try {
1822
+ const [r, i] = await Promise.all([
1823
+ s.get("/resources-applications"),
1824
+ e.session().getUser()
1825
+ ]);
1826
+ i != null && i.apps && (r != null && r.length) && (this.resourceProducingApps = r.filter(
1827
+ (o) => i.apps.some((u) => u.address.includes(o))
1828
+ ));
1829
+ } catch (r) {
1830
+ console.warn("Failed to load resource-producing apps:", r);
1831
+ }
2190
1832
  }
2191
- throw new Error("Video cannot be uploaded.");
1833
+ return this.resourceProducingApps;
1834
+ }
1835
+ static async registerBehaviours(e) {
1836
+ this.resourceProducingApps.forEach((t) => {
1837
+ const s = { application: e, resourceType: t };
1838
+ this.registry.register(
1839
+ s,
1840
+ (r) => this.serviceFor(r, e, t)
1841
+ );
1842
+ });
1843
+ }
1844
+ static serviceFor(e, t, s) {
1845
+ let r;
1846
+ switch (s) {
1847
+ case "timelinegenerator":
1848
+ r = new TimelinegeneratorBehaviour(e);
1849
+ break;
1850
+ case "workspace":
1851
+ r = new WorkspaceBehaviour(e);
1852
+ break;
1853
+ case "blog":
1854
+ r = new BlogBehaviour(e);
1855
+ break;
1856
+ case "actualites":
1857
+ r = new ActualitesBehaviour(e);
1858
+ break;
1859
+ case "wiki":
1860
+ r = new WikiBehaviour(e);
1861
+ break;
1862
+ case "pages":
1863
+ r = new PagesBehaviour(e);
1864
+ break;
1865
+ case "poll":
1866
+ r = new PollBehaviour(e);
1867
+ break;
1868
+ case "community":
1869
+ r = new CommunityBehaviour(e);
1870
+ break;
1871
+ case "mindmap":
1872
+ r = new MindmapBehaviour(e);
1873
+ break;
1874
+ case "forum":
1875
+ r = new ForumBehaviour(e);
1876
+ break;
1877
+ case "homeworks":
1878
+ r = new HomeworksBehaviour(e);
1879
+ break;
1880
+ case "scrapbook":
1881
+ r = new ScrapbookBehaviour(e);
1882
+ break;
1883
+ case "collaborativewall":
1884
+ r = new CollaborativewallBehaviour(e);
1885
+ break;
1886
+ case "exercizer":
1887
+ r = new ExercizerBehaviour(e);
1888
+ break;
1889
+ case "formulaire":
1890
+ r = new FormulaireBehaviour(e);
1891
+ break;
1892
+ case "magneto":
1893
+ r = new MagnetoBehaviour(e);
1894
+ break;
1895
+ default:
1896
+ throw ERROR_CODE.NOT_SUPPORTED;
1897
+ }
1898
+ return r.APP = t, r;
2192
1899
  }
2193
1900
  };
2194
- u(w, "MAX_WEIGHT", 50), // in Mbytes. Applies to uploaded videos.
2195
- u(w, "MAX_DURATION", 3);
2196
- let VideoService = w;
2197
- class EmbedderService {
1901
+ //
1902
+ // STATIC REGISTRY
1903
+ //
1904
+ a(y, "registry", new ServiceRegistry()), // Expose some useful functions
1905
+ a(y, "findBehaviour", y.registry.findService.bind(y.registry)), a(y, "hasBehaviour", y.registry.isRegistered.bind(y.registry)), a(y, "resourceProducingApps", []);
1906
+ let SnipletsService = y;
1907
+ class RightService {
2198
1908
  constructor(e) {
2199
1909
  this.context = e;
2200
1910
  }
2201
- get http() {
2202
- return this.context.http();
1911
+ get session() {
1912
+ return this.context.session();
1913
+ }
1914
+ /**
1915
+ * Parse right concat as "$TYPE:$ID:$RIGHT"
1916
+ * $TYPE = user | group | creator
1917
+ * $ID: id of the resource
1918
+ * $RIGHT: read | contrib | manage
1919
+ *
1920
+ * @param right a concat right
1921
+ * @returns Right parsed
1922
+ */
1923
+ parseResourceRight(e) {
1924
+ const t = e.split(":");
1925
+ if (t.length === 2) {
1926
+ if (t[0] === "creator")
1927
+ return {
1928
+ id: t[1],
1929
+ right: "creator",
1930
+ type: "creator"
1931
+ };
1932
+ } else return t.length === 3 ? {
1933
+ id: t[1],
1934
+ right: t[2],
1935
+ type: t[0]
1936
+ } : void 0;
2203
1937
  }
2204
1938
  /**
2205
- * Returns the default list of video embedder
2206
- * @returns the default list of video embedder
1939
+ * Parse an array of rights concat as "$TYPE:$ID:$RIGHT"
1940
+ * $TYPE = user | group | creator
1941
+ * $ID: id of the resource
1942
+ * $RIGHT: read | contrib | manage
1943
+ *
1944
+ * @param rights a list of concat rights
1945
+ * @returns Array of Right parsed
2207
1946
  */
2208
- async getDefault() {
2209
- return this.http.get("/infra/embed/default");
1947
+ parseResourceRights(e) {
1948
+ return e.map((s) => this.parseResourceRight(s)).filter((s) => s !== void 0);
2210
1949
  }
2211
1950
  /**
2212
- * Returns the custom list of video embedder
2213
- * @returns the custom list of video embedder
1951
+ * Check wether a user has the expected right for a ressource
1952
+ * @param user the userId and groupId concerned by the check
1953
+ * @param expect the expected right to check
1954
+ * @param rights array of Right for the resource
1955
+ * @returns true if has rights
2214
1956
  */
2215
- async getCustom() {
2216
- return this.http.get("/infra/embed/custom");
1957
+ hasResourceRight({ id: e, groupIds: t }, s, r) {
1958
+ const i = r.map((o) => typeof o == "string" ? this.parseResourceRight(o) : o).filter((o) => o !== void 0);
1959
+ for (const o of i) {
1960
+ if (o.id === e && o.type === "creator")
1961
+ return !0;
1962
+ if (o.id === e && o.type === "user" && o.right === s)
1963
+ return !0;
1964
+ if (t.includes(o.id) && o.type === "group" && o.right === s)
1965
+ return !0;
1966
+ }
1967
+ return !1;
2217
1968
  }
2218
1969
  /**
2219
- * The provider matching with the URL
2220
- * @param {Embedder[]} embedderList - The list of video providers to test with
2221
- * @param {String} url - The URL for the video
2222
- * @returns The provider matching with the URL or undefined
1970
+ * Check wether the current user have resource right
1971
+ * @param expect the expected right to check
1972
+ * @param rights array of Right for the resource
1973
+ * @returns true if has rights
2223
1974
  */
2224
- getProviderFromUrl(e, t) {
2225
- for (const s of e)
2226
- if (this.isUrlFromProvider(t, s))
2227
- return s;
2228
- }
2229
- urlIsFromPattern(e, t) {
2230
- const s = new RegExp("[^{}]+(?=(?:[^{}]*{[^}]*})*[^}]*$)", "g"), r = new RegExp("{[^}]*}", "g");
2231
- let i = !0;
2232
- const o = t.match(s) || [], a = [];
2233
- return (t.match(r) || []).forEach((l, h) => {
2234
- l.includes("ignore") || a.push(o[h]);
2235
- }), a.forEach((l) => {
2236
- if (!e.includes(l)) {
2237
- i = !1;
2238
- return;
2239
- }
2240
- }), i;
1975
+ async sessionHasResourceRight(e, t) {
1976
+ try {
1977
+ const s = await this.session.getUser();
1978
+ return !!s && this.hasResourceRight(
1979
+ { groupIds: s.groupsIds, id: s.userId },
1980
+ e,
1981
+ t
1982
+ );
1983
+ } catch (s) {
1984
+ return console.error(`Unexpected error ${s} in sessionHasResourceRight()`), !1;
1985
+ }
2241
1986
  }
2242
1987
  /**
2243
- * Check if a given URL correspond to one of the URL pattern of the provider
2244
- * @param {String} url - The URL for the video
2245
- * @param {Embedder} embedder - The video provider to test with
2246
- * @returns boolean depending if a given URL correspond to one of the URL pattern of the provider
1988
+ * Check wether the current user have at least one of resource right expected
1989
+ * @param expects array of expected right to check
1990
+ * @param rights array of Right for the resource
1991
+ * @returns true if has rights
2247
1992
  */
2248
- isUrlFromProvider(e, t) {
2249
- typeof t.url == "string" && (t.url = [t.url]);
2250
- for (const s of t.url)
2251
- if (this.urlIsFromPattern(e, s))
1993
+ async sessionHasAtLeastOneResourceRight(e, t) {
1994
+ for (const s of e)
1995
+ if (await this.sessionHasResourceRight(s, t))
2252
1996
  return !0;
2253
1997
  return !1;
2254
1998
  }
2255
1999
  /**
2256
- * Get embed code to display the video for an URL and a provider
2257
- * @param {Embedder} embedder - The video provider for the URL
2258
- * @param {String} url - The URL for the video
2259
- * @returns embed code to display the video for an URL and a provider
2000
+ * Check wether the current user has resource right for each right list
2001
+ * @param expect expected right to check
2002
+ * @param rightsArray array of array of Right for multiple resources
2003
+ * @returns true if has rights
2260
2004
  */
2261
- getEmbedCodeForProvider(e, t) {
2262
- for (const s of e.url)
2263
- if (this.urlIsFromPattern(t, s)) {
2264
- const r = new RegExp("{[a-zA-Z0-9_.]+}", "g"), i = s.match(r) || [];
2265
- let o = e.embed;
2266
- for (const a of i) {
2267
- let c = s.split(a)[0];
2268
- const l = c.split("}");
2269
- l.length > 1 && (c = l[l.length - 1]);
2270
- let h = t.split(c)[1];
2271
- if (!h)
2272
- continue;
2273
- const E = s.split(a)[1].split("{")[0];
2274
- E && (h = h.split(E)[0]);
2275
- const p = new RegExp("\\" + a.replace(/}/, "\\}"), "g");
2276
- o = o.replace(p, h);
2277
- }
2278
- return o;
2279
- }
2280
- return "";
2281
- }
2282
- }
2283
- class AbstractBehaviourService {
2284
- //
2285
- // IMPLEMENTATION
2286
- //
2287
- constructor(e) {
2288
- //-----------------
2289
- //--- Utilities ---
2290
- //-----------------
2291
- u(this, "_cache");
2292
- this.context = e, this._cache = new CacheService(this.context);
2005
+ async sessionHasResourceRightForEachList(e, t) {
2006
+ let s = 0;
2007
+ for (const r of t)
2008
+ await this.sessionHasResourceRight(e, r) && s++;
2009
+ return s === t.length;
2293
2010
  }
2294
- getApplication() {
2295
- return this.APP;
2011
+ /**
2012
+ * Check wether the current user have at least one of resource right for each right list
2013
+ * @param expects array of expected right to check
2014
+ * @param rightsArray array of array of Right for multiple resources
2015
+ * @returns true if has rights
2016
+ */
2017
+ async sessionHasAtLeastOneResourceRightForEachList(e, t) {
2018
+ for (const s of e) {
2019
+ let r = 0;
2020
+ for (const i of t)
2021
+ await this.sessionHasResourceRight(s, i) && r++;
2022
+ if (r === t.length)
2023
+ return !0;
2024
+ }
2025
+ return !1;
2296
2026
  }
2297
- getResourceType() {
2298
- return this.RESOURCE;
2027
+ hasWorkflowRight(e, t) {
2028
+ return t.findIndex((s) => s === e) !== -1;
2299
2029
  }
2300
- httpGet(e, t) {
2301
- return this._cache.httpGetJson(e, t);
2030
+ /**
2031
+ * @param expect a workflow right
2032
+ * @returns true if current session has right on it
2033
+ */
2034
+ async sessionHasWorkflowRight(e) {
2035
+ try {
2036
+ const t = await this.session.getUser();
2037
+ return !!t && this.hasWorkflowRight(
2038
+ e,
2039
+ t.authorizedActions.map(
2040
+ (s) => s.name
2041
+ )
2042
+ );
2043
+ } catch (t) {
2044
+ return console.error(`Unexpected error ${t} in sessionHasWorkflowRight()`), !1;
2045
+ }
2302
2046
  }
2303
- /* Utility to map data between linker model and search model. */
2304
- dataToResource({
2305
- modified: e,
2306
- ...t
2307
- }) {
2308
- const s = typeof e == "string" ? e : e != null && e.$date ? "" + e.$date : "";
2309
- return {
2310
- application: this.RESOURCE,
2311
- name: t.title,
2312
- creatorId: t.owner,
2313
- creatorName: t.ownerName,
2314
- thumbnail: t.icon,
2315
- assetId: t._id,
2316
- modifiedAt: s,
2317
- shared: t.shared,
2318
- path: t.path
2319
- };
2047
+ /**
2048
+ * @param expect a workflow right
2049
+ * @returns a record with right as key and boolean as value if current session has right on it
2050
+ */
2051
+ async sessionHasWorkflowRights(e) {
2052
+ const t = {};
2053
+ try {
2054
+ const s = await this.session.getUser();
2055
+ for (const r of e)
2056
+ t[r] = !!s && this.hasWorkflowRight(
2057
+ r,
2058
+ s.authorizedActions.map(
2059
+ (i) => i.name
2060
+ )
2061
+ );
2062
+ } catch (s) {
2063
+ console.error(`Unexpected error ${s} in sessionHasWorkflowRights()`);
2064
+ for (const r of e)
2065
+ t[r] = !1;
2066
+ }
2067
+ return t;
2320
2068
  }
2321
2069
  }
2322
- class ActualitesBehaviour extends AbstractBehaviourService {
2323
- constructor() {
2324
- super(...arguments);
2325
- u(this, "APP", "actualites");
2326
- u(this, "RESOURCE", "actualites");
2070
+ class SessionService {
2071
+ constructor(e) {
2072
+ this.context = e;
2327
2073
  }
2328
- async loadResources() {
2329
- return (await this.httpGet(
2330
- "/actualites/linker/infos"
2331
- )).map((s) => {
2332
- var r;
2333
- return s.thread_icon ? r = s.thread_icon + "?thumbnail=48x48" : r = "/img/icons/glyphicons_036_file.png", this.dataToResource({
2334
- title: s.title + " [" + s.thread_title + "]",
2335
- ownerName: s.username,
2336
- owner: s.owner,
2337
- icon: r,
2338
- path: "/actualites#/view/thread/" + s.thread_id + "/info/" + s._id,
2339
- _id: `${s.thread_id}#${s._id}`,
2340
- shared: !!(s.shared && s.shared.length >= 0),
2341
- modified: s.modified
2342
- });
2343
- });
2074
+ get http() {
2075
+ return this.context.http();
2344
2076
  }
2345
- }
2346
- class BlogBehaviour extends AbstractBehaviourService {
2347
- constructor() {
2348
- super(...arguments);
2349
- u(this, "APP", "blog");
2350
- u(this, "RESOURCE", "blog");
2077
+ get cache() {
2078
+ return this.context.cache();
2351
2079
  }
2352
- loadResources() {
2353
- return new Promise(async (t, s) => {
2354
- try {
2355
- const r = await this.httpGet("/blog/linker"), i = [];
2356
- r.forEach((o) => {
2357
- o.thumbnail ? o.thumbnail = o.thumbnail + "?thumbnail=48x48" : o.thumbnail = "/img/illustrations/blog.svg";
2358
- const a = o.fetchPosts.map((c) => this.dataToResource({
2359
- owner: o.author.userId,
2360
- ownerName: o.author.username,
2361
- title: c.title + " [" + o.title + "]",
2362
- _id: `${o._id}#${c._id}`,
2363
- icon: o.thumbnail,
2364
- path: `/blog/id/${o._id}/post/${c._id}`,
2365
- shared: !!(o.shared && o.shared.length >= 0),
2366
- modified: o.modified
2367
- }));
2368
- i.push(...a);
2369
- }), t(i);
2370
- } catch (r) {
2371
- s(r);
2372
- }
2373
- });
2080
+ get conf() {
2081
+ return this.context.conf();
2374
2082
  }
2375
- }
2376
- class CollaborativewallBehaviour extends AbstractBehaviourService {
2377
- constructor() {
2378
- super(...arguments);
2379
- u(this, "APP", "collaborativewall");
2380
- u(this, "RESOURCE", "collaborativewall");
2083
+ /**
2084
+ * Callback to call when user logout
2085
+ */
2086
+ onLogout() {
2087
+ this.cache.clearCache();
2381
2088
  }
2382
- async loadResources() {
2383
- return (await this.httpGet(
2384
- "/collaborativewall/list/all"
2385
- )).map(
2386
- (s) => this.dataToResource({
2387
- title: s.name,
2388
- ownerName: s.owner.displayName,
2389
- owner: s.owner.userId,
2390
- icon: s.icon ? s.icon : "/img/illustrations/collaborative-wall-default.png",
2391
- path: "/collaborativewall#/view/" + s._id,
2392
- _id: s._id,
2393
- shared: !!(s.shared && s.shared.length >= 0),
2394
- modified: s.modified
2395
- })
2396
- );
2089
+ /**
2090
+ * Callback to call when session change
2091
+ */
2092
+ onRefreshSession() {
2093
+ this.cache.clearCache();
2397
2094
  }
2398
- }
2399
- class CommunityBehaviour extends AbstractBehaviourService {
2400
- constructor() {
2401
- super(...arguments);
2402
- u(this, "APP", "community");
2403
- u(this, "RESOURCE", "community");
2095
+ async getSession() {
2096
+ const e = await this.getUser(), [
2097
+ t,
2098
+ s,
2099
+ r,
2100
+ i,
2101
+ o
2102
+ ] = await Promise.all([
2103
+ this.getCurrentLanguage(e),
2104
+ this.latestQuotaAndUsage(e),
2105
+ this.loadDescription(e),
2106
+ this.getUserProfile(),
2107
+ this.getBookmarks(e)
2108
+ ]);
2109
+ return {
2110
+ user: e,
2111
+ quotaAndUsage: s,
2112
+ currentLanguage: t,
2113
+ userDescription: r,
2114
+ userProfile: i,
2115
+ bookmarkedApps: o
2116
+ };
2404
2117
  }
2405
- async loadResources() {
2406
- return (await this.httpGet(
2407
- "/community/listallpages"
2408
- )).map((s) => {
2409
- var r;
2410
- return typeof s.thumbnail > "u" || s.thumbnail === "" ? r = "/img/icons/glyphicons_036_file.png" : r = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
2411
- title: s.name,
2412
- icon: r,
2413
- path: "/community#/view/" + s.id,
2414
- _id: s.id,
2415
- owner: "",
2416
- ownerName: "",
2417
- shared: !!(s.shared && s.shared.length >= 0),
2418
- modified: s.name
2419
- // FIXME date ?
2420
- });
2118
+ login(e, t, s, r) {
2119
+ const i = new FormData();
2120
+ return i.append("email", e), i.append("password", t), typeof s < "u" && i.append("rememberMe", "" + s), typeof r < "u" && i.append("secureLocation", "" + r), this.http.post("/auth/login", i, {
2121
+ headers: { "content-type": "application/x-www-form-urlencoded" }
2122
+ }).finally(() => {
2123
+ switch (this.http.latestResponse.status) {
2124
+ case 200:
2125
+ throw ERROR_CODE.MALFORMED_DATA;
2126
+ }
2421
2127
  });
2422
2128
  }
2423
- }
2424
- class ExercizerBehaviour extends AbstractBehaviourService {
2425
- constructor() {
2426
- super(...arguments);
2427
- u(this, "APP", "exercizer");
2428
- u(this, "RESOURCE", "exercizer");
2429
- }
2430
- async loadResources() {
2431
- return (await this.httpGet(
2432
- "/exercizer/subjects-scheduled"
2433
- )).map((s) => {
2434
- const r = s.picture ? s.picture + "?thumbnail=48x48" : "/img/illustrations/exercizer.svg";
2435
- let i, o = !1, a = JSON.parse(s.scheduled_at);
2436
- return a.groupList.length > 0 ? (o = !0, i = a.groupList[0].name) : a.userList.length > 0 ? (o = !0, i = a.userList[0].name) : i = "", a.groupList.length + a.userList.length > 1 && (i += "..."), this.dataToResource({
2437
- title: s.title,
2438
- owner: s.owner,
2439
- ownerName: i,
2440
- icon: r,
2441
- path: "/exercizer#/linker/" + s.id,
2442
- _id: "" + s.id,
2443
- shared: o,
2444
- modified: s.modified
2445
- });
2129
+ async logout() {
2130
+ const e = await this.conf.getLogoutCallback();
2131
+ return this.http.get("/auth/logout?callback=" + e).finally(() => {
2446
2132
  });
2447
2133
  }
2448
- }
2449
- class FormulaireBehaviour extends AbstractBehaviourService {
2450
- constructor() {
2451
- super(...arguments);
2452
- u(this, "APP", "formulaire");
2453
- u(this, "RESOURCE", "formulaire");
2134
+ async latestQuotaAndUsage(e) {
2135
+ const t = { quota: 0, storage: 0 };
2136
+ if (!e) return t;
2137
+ try {
2138
+ return await this.http.get(
2139
+ `/workspace/quota/user/${e == null ? void 0 : e.userId}`
2140
+ );
2141
+ } catch (s) {
2142
+ return console.error(s), t;
2143
+ }
2454
2144
  }
2455
- async loadResources() {
2456
- return (await this.httpGet(
2457
- "/formulaire/forms/linker"
2458
- )).map((s) => (s.picture || (s.picture = "/formulaire/public/img/logo.svg"), this.dataToResource({
2459
- _id: "" + s.id,
2460
- icon: s.picture,
2461
- title: s.title,
2462
- ownerName: s.owner_name,
2463
- owner: s.owner_id,
2464
- path: s.is_public ? `${window.location.origin}/formulaire-public#/form/${s.public_key}` : `${window.location.origin}/formulaire#/form/${s.id}/${s.rgpd ? "rgpd" : "new"}`,
2465
- shared: !!(s.shared && s.shared.length >= 0),
2466
- modified: "" + s.date_modification
2467
- })));
2145
+ async getCurrentLanguage(e) {
2146
+ const t = (e == null ? void 0 : e.sessionMetadata) && (e == null ? void 0 : e.sessionMetadata.userId);
2147
+ try {
2148
+ let s;
2149
+ return t ? s = await this.loadUserLanguage() : s = await this.loadDefaultLanguage(), s;
2150
+ } catch (s) {
2151
+ console.error(s);
2152
+ }
2468
2153
  }
2469
- }
2470
- class ForumBehaviour extends AbstractBehaviourService {
2471
- constructor() {
2472
- super(...arguments);
2473
- u(this, "APP", "forum");
2474
- u(this, "RESOURCE", "forum");
2154
+ async loadUserLanguage() {
2155
+ try {
2156
+ const e = await this.http.get(
2157
+ "/userbook/preference/language"
2158
+ );
2159
+ return JSON.parse(e.preference)["default-domain"];
2160
+ } catch {
2161
+ return await this.loadDefaultLanguage();
2162
+ }
2475
2163
  }
2476
- async loadResources() {
2477
- return (await this.httpGet("/forum/categories")).map(
2478
- (s) => this.dataToResource({
2479
- _id: s._id,
2480
- title: s.name,
2481
- icon: s.icon || "/img/illustrations/forum.svg",
2482
- path: "/forum#/view/" + s._id,
2483
- ownerName: s.owner.displayName,
2484
- owner: s.owner.userId,
2485
- shared: !!(s.shared && s.shared.length >= 0),
2486
- modified: s.modified
2487
- })
2164
+ async loadDefaultLanguage() {
2165
+ return (await this.cache.httpGetJson(
2166
+ "/locale"
2167
+ )).locale;
2168
+ }
2169
+ async getUser() {
2170
+ const { response: e, value: t } = await this.cache.httpGet(
2171
+ "/auth/oauth2/userinfo"
2488
2172
  );
2173
+ if (!(e.status < 200 || e.status >= 300) && typeof t == "object")
2174
+ return t;
2175
+ throw ERROR_CODE.NOT_LOGGED_IN;
2489
2176
  }
2490
- }
2491
- class HomeworksBehaviour extends AbstractBehaviourService {
2492
- constructor() {
2493
- super(...arguments);
2494
- u(this, "APP", "homeworks");
2495
- u(this, "RESOURCE", "homeworks");
2177
+ hasWorkflow({
2178
+ workflowName: e,
2179
+ user: t
2180
+ }) {
2181
+ return e === void 0 || (t == null ? void 0 : t.authorizedActions.findIndex((s) => s.name === e)) !== -1;
2496
2182
  }
2497
- async loadResources() {
2498
- return (await this.httpGet("/homeworks/list")).filter((t) => t.owner && t.trashed === 0).map((t) => this.dataToResource({
2499
- title: t.title,
2500
- ownerName: t.owner.displayName,
2501
- owner: t.owner.userId,
2502
- icon: t.thumbnail || "/img/illustrations/homeworks.svg",
2503
- path: "/homeworks#/view-homeworks/" + t._id,
2504
- _id: "" + t._id,
2505
- shared: typeof t.shared < "u",
2506
- modified: t.modified
2507
- }));
2183
+ async loadDescription(e) {
2184
+ if (!e) return {};
2185
+ try {
2186
+ const [t, s] = await Promise.all([
2187
+ // FIXME The full user's description should be obtainable from a single endpoint in the backend.
2188
+ this.getUserProfile({
2189
+ options: { requestName: "refreshAvatar" }
2190
+ }),
2191
+ this.http.get("/directory/userbook/" + (e == null ? void 0 : e.userId))
2192
+ ]);
2193
+ return { ...s, profiles: t };
2194
+ } catch (t) {
2195
+ return console.error(t), {};
2196
+ }
2508
2197
  }
2509
- }
2510
- class MagnetoBehaviour extends AbstractBehaviourService {
2511
- constructor() {
2512
- super(...arguments);
2513
- u(this, "APP", "magneto");
2514
- u(this, "RESOURCE", "magneto");
2198
+ async getBookmarks(e) {
2199
+ if (!e) return [];
2200
+ const t = await this.http.get("/userbook/preference/apps");
2201
+ t.preference || (t.preference = null);
2202
+ const s = JSON.parse(t.preference);
2203
+ let r;
2204
+ r = s, r || (r = {
2205
+ bookmarks: [],
2206
+ applications: []
2207
+ });
2208
+ const i = [];
2209
+ return r.bookmarks.forEach((o, u) => {
2210
+ const c = ((e == null ? void 0 : e.apps) || []).find(
2211
+ (h) => h.name === o
2212
+ );
2213
+ if (c) {
2214
+ const h = Object.assign({}, c);
2215
+ i.push(h);
2216
+ }
2217
+ }), i;
2515
2218
  }
2516
- async loadResources() {
2517
- const { all: t } = await this.httpGet(
2518
- "/magneto/boards/editable"
2519
- );
2520
- return t.map((s) => this.dataToResource({
2521
- _id: s._id,
2522
- title: s.title,
2523
- icon: s.imageUrl,
2524
- owner: s.ownerId,
2525
- ownerName: s.ownerName,
2526
- path: `/magneto#/board/${s._id}/view`,
2527
- shared: !!(s.shared && s.shared.length >= 0),
2528
- modified: "" + s.modificationDate
2529
- }));
2219
+ async getUserProfile(e = {}) {
2220
+ var c, h;
2221
+ const { options: t = {}, params: s = {} } = e, r = new URLSearchParams(s).toString(), i = `/userbook/api/person${r ? `?${r}` : ""}`, { response: o, value: u } = await this.cache.httpGet(i, t);
2222
+ return o.status < 200 || o.status >= 300 || typeof u == "string" ? ["Guest"] : ((h = (c = u == null ? void 0 : u.result) == null ? void 0 : c[0]) == null ? void 0 : h.type) || ["Guest"];
2223
+ }
2224
+ async isAdml() {
2225
+ const e = await this.getUser();
2226
+ return (e == null ? void 0 : e.functions.ADMIN_LOCAL) !== void 0;
2227
+ }
2228
+ /**
2229
+ * Get details of an application if the user can access it.
2230
+ * @return undefined if no access, or app not found
2231
+ */
2232
+ async getWebApp(e) {
2233
+ const t = await this.getUser();
2234
+ return t == null ? void 0 : t.apps.find((s) => {
2235
+ var r;
2236
+ return s != null && s.prefix ? (s == null ? void 0 : s.prefix.replace("/", "")) === e || !1 : s != null && s.address && ((r = s.address) == null ? void 0 : r.split("/")[1]) === e || !1;
2237
+ });
2530
2238
  }
2531
2239
  }
2532
- class MindmapBehaviour extends AbstractBehaviourService {
2533
- constructor() {
2534
- super(...arguments);
2535
- u(this, "APP", "mindmap");
2536
- u(this, "RESOURCE", "mindmap");
2537
- }
2538
- async loadResources() {
2539
- return (await this.httpGet("/mindmap/list/all")).map(
2540
- (s) => this.dataToResource({
2541
- title: s.name,
2542
- ownerName: s.owner.displayName,
2543
- owner: s.owner.userId,
2544
- icon: s.thumbnail || "/img/illustrations/mindmap-default.png",
2545
- path: "/mindmap#/view/" + s._id,
2546
- _id: s._id,
2547
- shared: !!(s.shared && s.shared.length >= 0),
2548
- modified: s.modified
2549
- })
2550
- );
2240
+ class StringUtils {
2241
+ static removeAccents(e) {
2242
+ for (let t = 0; t < defaultDiacriticsRemovalMap.length; t++)
2243
+ e = e.replace(
2244
+ defaultDiacriticsRemovalMap[t].letters,
2245
+ defaultDiacriticsRemovalMap[t].base
2246
+ );
2247
+ return e;
2551
2248
  }
2552
2249
  }
2553
- class PagesBehaviour extends AbstractBehaviourService {
2554
- constructor() {
2555
- super(...arguments);
2556
- u(this, "APP", "pages");
2557
- u(this, "RESOURCE", "pages");
2250
+ class ShareService {
2251
+ //
2252
+ // IMPLEMENTATION
2253
+ //
2254
+ constructor(e) {
2255
+ this.context = e;
2558
2256
  }
2559
- async loadResources() {
2560
- const t = await this.httpGet("/pages/list/all"), s = [];
2561
- return t.forEach((r) => {
2562
- var o;
2563
- const i = r.thumbnail ? r.thumbnail + "?thumbnail=48x48" : "/img/illustrations/pages.svg";
2564
- s.push(
2565
- this.dataToResource({
2566
- title: r.title,
2567
- owner: r.owner.userId,
2568
- ownerName: r.owner.displayName,
2569
- icon: i,
2570
- path: "/pages#/website/" + r._id,
2571
- _id: r._id,
2572
- shared: typeof r.shared < "u",
2573
- modified: r.modified
2574
- })
2575
- ), (o = r.pages) == null || o.forEach((a) => {
2576
- s.push(
2577
- this.dataToResource({
2578
- title: a.title,
2579
- owner: r.owner.userId,
2580
- ownerName: r.owner.displayName,
2581
- icon: i,
2582
- path: "/pages#/website/" + r._id + "/" + a.titleLink,
2583
- _id: r._id + "/" + a.titleLink,
2584
- shared: typeof r.shared < "u",
2585
- modified: r.modified
2586
- })
2587
- );
2588
- });
2589
- }), s;
2257
+ get directory() {
2258
+ return this.context.directory();
2590
2259
  }
2591
- }
2592
- class PollBehaviour extends AbstractBehaviourService {
2593
- constructor() {
2594
- super(...arguments);
2595
- u(this, "APP", "poll");
2596
- u(this, "RESOURCE", "poll");
2260
+ get http() {
2261
+ return this.context.http();
2597
2262
  }
2598
- async loadResources() {
2599
- return (await this.httpGet("/poll/list/all")).map((s) => {
2600
- const r = s.icon ? s.icon + "?thumbnail=48x48" : "/img/icons/glyphicons_036_file.png";
2601
- return this.dataToResource({
2602
- title: s.question,
2603
- ownerName: s.owner.displayName,
2604
- icon: r,
2605
- path: "/poll#/view/" + s._id,
2606
- _id: s._id,
2607
- owner: s.owner.userId,
2608
- shared: !!(s.shared && s.shared.length >= 0),
2609
- modified: s.modified
2610
- });
2611
- });
2263
+ get cache() {
2264
+ return this.context.cache();
2612
2265
  }
2613
- }
2614
- class ScrapbookBehaviour extends AbstractBehaviourService {
2615
- constructor() {
2616
- super(...arguments);
2617
- u(this, "APP", "scrapbook");
2618
- u(this, "RESOURCE", "scrapbook");
2266
+ async searchShareSubjects(e, t, s) {
2267
+ const r = StringUtils.removeAccents(s).toLowerCase(), i = await this.cache.httpGetJson(
2268
+ `/${e}/share/json/${t}?search=${s}`
2269
+ ), o = i.users.visibles.filter(({ username: l, firstName: g, lastName: d, login: p }) => {
2270
+ const E = StringUtils.removeAccents(
2271
+ d || ""
2272
+ ).toLowerCase(), A = StringUtils.removeAccents(
2273
+ g || ""
2274
+ ).toLowerCase(), m = StringUtils.removeAccents(
2275
+ l || ""
2276
+ ).toLowerCase(), w = StringUtils.removeAccents(p || "").toLowerCase();
2277
+ return m.includes(r) || A.includes(r) || E.includes(r) || w.includes(r);
2278
+ }).map((l) => ({
2279
+ avatarUrl: this.directory.getAvatarUrl(l.id, "user"),
2280
+ directoryUrl: this.directory.getDirectoryUrl(l.id, "user"),
2281
+ displayName: l.username,
2282
+ id: l.id,
2283
+ profile: l.profile,
2284
+ type: "user"
2285
+ })), u = i.groups.visibles.filter(({ name: l }) => StringUtils.removeAccents(l || "").toLowerCase().includes(r)).map((l) => ({
2286
+ avatarUrl: this.directory.getAvatarUrl(l.id, "group"),
2287
+ directoryUrl: this.directory.getDirectoryUrl(l.id, "group"),
2288
+ displayName: l.name,
2289
+ id: l.id,
2290
+ type: "group",
2291
+ structureName: l.structureName
2292
+ }));
2293
+ return [...(await this.directory.getBookMarks()).filter(({ displayName: l }) => StringUtils.removeAccents(
2294
+ l || ""
2295
+ ).toLowerCase().includes(r)).map((l) => ({
2296
+ avatarUrl: "",
2297
+ directoryUrl: "",
2298
+ profile: "",
2299
+ displayName: l.displayName,
2300
+ id: l.id,
2301
+ type: "sharebookmark"
2302
+ })), ...o, ...u];
2619
2303
  }
2620
- async loadResources() {
2621
- return (await this.httpGet(
2622
- "/scrapbook/list/all"
2623
- )).map((s) => {
2624
- const r = s.icon || "/img/illustrations/scrapbook.svg";
2625
- return this.dataToResource({
2626
- title: s.name,
2627
- owner: s.owner.userId,
2628
- ownerName: s.owner.displayName,
2629
- icon: r,
2630
- path: "/scrapbook#/view-scrapbook/" + s._id,
2631
- _id: s._id,
2632
- shared: !!(s.shared && s.shared.length >= 0),
2633
- modified: s.modified
2634
- });
2635
- });
2304
+ async getShareMapping(e) {
2305
+ const t = await this.cache.httpGetJson(
2306
+ `/${e}/rights/sharing`
2307
+ );
2308
+ for (const s of Object.keys(t))
2309
+ if (s.includes(".")) {
2310
+ const r = s.split(".")[1], i = t[s];
2311
+ delete t[s], t[r] = i;
2312
+ }
2313
+ return t;
2636
2314
  }
2637
- }
2638
- class TimelinegeneratorBehaviour extends AbstractBehaviourService {
2639
- constructor() {
2640
- super(...arguments);
2641
- u(this, "APP", "timelinegenerator");
2642
- u(this, "RESOURCE", "timelinegenerator");
2315
+ getActionsAvailableFor({ id: e, type: t }, s, r) {
2316
+ const o = (t === "user" ? s.users.checked[e] : s.groups.checked[e]) || [], u = Object.keys(r), c = [];
2317
+ for (const h of u)
2318
+ r[h].filter(
2319
+ (d) => o.includes(d)
2320
+ ).length > 0 && c.push(h);
2321
+ return c;
2643
2322
  }
2644
- loadResources() {
2645
- return new Promise(async (t, s) => {
2646
- try {
2647
- const i = (await this.httpGet(
2648
- "/timelinegenerator/timelines"
2649
- )).map((o) => {
2650
- const a = o.icon || "/img/illustrations/timeline-default.png";
2651
- return this.dataToResource({
2652
- title: o.headline,
2653
- ownerName: o.owner.displayName,
2654
- owner: o.owner.userId,
2655
- icon: a,
2656
- path: "/timelinegenerator#/view/" + o._id,
2657
- _id: o._id,
2658
- shared: typeof o.shared < "u",
2659
- modified: o.modified
2660
- });
2661
- });
2662
- t(i);
2663
- } catch (r) {
2664
- s(r);
2665
- }
2666
- });
2323
+ async getRightsForResource(e, t) {
2324
+ const s = await this.directory.getBookMarks(), r = `/${e}/share/json/${t}?search=`, i = await this.cache.httpGetJson(r), o = await this.getShareMapping(e), u = await this.cache.httpGetJson(
2325
+ "/infra/public/json/sharing-rights.json"
2326
+ ), c = Object.keys(i.users.checked).map((p) => i.users.visibles.find(
2327
+ (A) => A.id === p
2328
+ )).filter((p) => p !== void 0).map((p) => {
2329
+ const E = this.getActionsAvailableFor(
2330
+ { id: p.id, type: "user" },
2331
+ i,
2332
+ o
2333
+ );
2334
+ return {
2335
+ id: p.id,
2336
+ type: "user",
2337
+ displayName: p.username,
2338
+ profile: p.profile,
2339
+ avatarUrl: this.directory.getAvatarUrl(p.id, "user"),
2340
+ directoryUrl: this.directory.getDirectoryUrl(p.id, "user"),
2341
+ actions: E.map((m) => {
2342
+ const w = u[m];
2343
+ return {
2344
+ displayName: m,
2345
+ id: m,
2346
+ priority: w.priority
2347
+ };
2348
+ })
2349
+ };
2350
+ }).sort((p, E) => (p.displayName || "").localeCompare(E.displayName)), h = Object.keys(i.groups.checked).map((p) => i.groups.visibles.find(
2351
+ (A) => A.id === p
2352
+ )).filter((p) => p !== void 0).map((p) => {
2353
+ const E = this.getActionsAvailableFor(
2354
+ { id: p.id, type: "group" },
2355
+ i,
2356
+ o
2357
+ );
2358
+ return {
2359
+ id: p.id,
2360
+ type: "group",
2361
+ displayName: p.name,
2362
+ profile: void 0,
2363
+ avatarUrl: this.directory.getAvatarUrl(p.id, "group"),
2364
+ directoryUrl: this.directory.getDirectoryUrl(p.id, "group"),
2365
+ actions: E.map((m) => {
2366
+ const w = u[m];
2367
+ return {
2368
+ displayName: m,
2369
+ id: m,
2370
+ priority: w.priority
2371
+ };
2372
+ })
2373
+ };
2374
+ }).sort((p, E) => (p.displayName || "").localeCompare(E.displayName)), l = [...c, ...h], g = i.groups.visibles.map(
2375
+ ({ groupDisplayName: p, id: E, name: A }) => ({
2376
+ displayName: p || A,
2377
+ id: E
2378
+ })
2379
+ ), d = i.users.visibles.map(
2380
+ ({ id: p, profile: E, username: A, firstName: m, lastName: w, login: C }) => ({
2381
+ displayName: A,
2382
+ firstName: m,
2383
+ lastName: w,
2384
+ login: C,
2385
+ profile: E,
2386
+ id: p
2387
+ })
2388
+ );
2389
+ return {
2390
+ rights: l,
2391
+ visibleBookmarks: s,
2392
+ visibleGroups: g,
2393
+ visibleUsers: d
2394
+ };
2667
2395
  }
2668
- }
2669
- class WikiBehaviour extends AbstractBehaviourService {
2670
- constructor() {
2671
- super(...arguments);
2672
- u(this, "APP", "wiki");
2673
- u(this, "RESOURCE", "wiki");
2396
+ async saveRights(e, t, s) {
2397
+ const r = await this.getShareMapping(e), i = {
2398
+ bookmarks: {},
2399
+ groups: {},
2400
+ users: {}
2401
+ };
2402
+ for (const c of s) {
2403
+ const h = c.actions.map((g) => r[g.id]).reduce((g, d) => Array.isArray(d) ? [...g, ...d] : g, []), l = [...new Set(h)];
2404
+ l.length > 0 && (c.type === "user" ? i.users[c.id] = l : c.type === "group" ? i.groups[c.id] = l : i.bookmarks[c.id] = l);
2405
+ }
2406
+ const o = `/${e}/share/resource/${t}`;
2407
+ return this.cache.clearCache(`/${e}/share/json/${t}?search=`), await this.http.putJson(o, i);
2674
2408
  }
2675
- async loadResources() {
2676
- return (await this.httpGet(
2677
- "/wiki/listallpages?visible=true"
2678
- )).map((s) => s.pages.map((r) => {
2679
- let i;
2680
- return typeof s.thumbnail > "u" || s.thumbnail === "" ? i = "/img/icons/glyphicons_036_file.png" : i = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
2681
- title: r.title + " [" + s.title + "]",
2682
- ownerName: s.owner.displayName,
2683
- owner: s.owner.userId,
2684
- icon: i,
2685
- path: "/wiki#/view/" + s._id + "/" + r._id,
2686
- _id: `${s._id}#${r._id}`,
2687
- shared: typeof s.shared < "u",
2688
- modified: r.modified
2689
- });
2690
- })).flat();
2409
+ async getActionsForApp(e) {
2410
+ const t = await this.cache.httpGetJson(
2411
+ "/infra/public/json/sharing-rights.json"
2412
+ ), s = await this.getShareMapping(e);
2413
+ return Object.keys(t).map((i) => {
2414
+ const o = t[i];
2415
+ return {
2416
+ displayName: i,
2417
+ id: i,
2418
+ priority: o.priority,
2419
+ requires: o.requires
2420
+ };
2421
+ }).filter((i) => {
2422
+ var o;
2423
+ return ((o = s[i.id]) == null ? void 0 : o.length) > 0;
2424
+ }).sort((i, o) => i.priority - o.priority);
2691
2425
  }
2692
2426
  }
2693
- class WorkspaceBehaviour extends AbstractBehaviourService {
2694
- constructor() {
2695
- super(...arguments);
2696
- u(this, "APP", "workspace");
2697
- u(this, "RESOURCE", "workspace");
2698
- }
2699
- loadResources({ search: t, asset_id: s }) {
2700
- return new Promise(async (r, i) => {
2701
- try {
2702
- let o = "/workspace/documents?filter=all&hierarchical=true";
2703
- s && s.length ? o += `&search=${t}` : t && t.length && (o += `&search=${t}`);
2704
- const c = (await this.httpGet(o)).filter((l) => !l.deleted).map((l) => {
2705
- const h = l.metadata["content-type"] && l.metadata["content-type"].indexOf("image") !== -1 ? `/workspace/document/${l._id}?thumbnail=120x120` : "/img/icons/unknown-large.png";
2706
- return this.dataToResource({
2707
- title: l.name,
2708
- ownerName: l.ownerName,
2709
- owner: l.owner,
2710
- icon: h,
2711
- path: `/workspace/document/${l._id}`,
2712
- _id: l._id,
2713
- shared: !!(l.shared && l.shared.length >= 0),
2714
- modified: l.modified
2715
- });
2716
- });
2717
- r(c);
2718
- } catch (o) {
2719
- i(o);
2720
- }
2721
- });
2427
+ const loadedScripts = {};
2428
+ class HttpService {
2429
+ constructor(e, t) {
2430
+ // Axios automatically manages the XSRF-TOKEN cookie and the X-XSRF-TOKEN HTTP header.
2431
+ a(this, "axios");
2432
+ a(this, "baseUrl");
2433
+ a(this, "headers", {});
2434
+ a(this, "_latestResponse");
2435
+ this.context = e, this.axios = t || axios;
2722
2436
  }
2723
- }
2724
- const y = class y {
2725
- static async initialize(e, t) {
2726
- const s = e.http();
2727
- if (!this.resourceProducingApps.length) {
2728
- this.resourceProducingApps = [t, "workspace"];
2729
- try {
2730
- const [r, i] = await Promise.all([
2731
- s.get("/resources-applications"),
2732
- e.session().getUser()
2733
- ]);
2734
- i != null && i.apps && (r != null && r.length) && (this.resourceProducingApps = r.filter(
2735
- (o) => i.apps.some((a) => a.address.includes(o))
2736
- ));
2737
- } catch (r) {
2738
- console.warn("Failed to load resource-producing apps:", r);
2739
- }
2740
- }
2741
- return this.resourceProducingApps;
2437
+ fixBaseUrl(e) {
2438
+ return e.startsWith("http://") || e.startsWith("https://") ? e : this.baseUrl ? this.baseUrl.endsWith("/") || e.startsWith("/") ? `${this.baseUrl}${e}` : `${this.baseUrl}/${e}` : e;
2742
2439
  }
2743
- static async registerBehaviours(e) {
2744
- this.resourceProducingApps.forEach((t) => {
2745
- const s = { application: e, resourceType: t };
2746
- this.registry.register(
2747
- s,
2748
- (r) => this.serviceFor(r, e, t)
2749
- );
2440
+ useBaseUrl(e) {
2441
+ return this.baseUrl = e, this;
2442
+ }
2443
+ useHeaders(e) {
2444
+ return this.headers = e, this;
2445
+ }
2446
+ setCdn(e) {
2447
+ e && XMLHttpRequest && !XMLHttpRequest.prototype.cdnUrl && (XMLHttpRequest.prototype.cdnUrl = e, XMLHttpRequest.prototype.baseOpen = XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.open = function() {
2448
+ const t = arguments[1];
2449
+ return t.startsWith("/infra/public") && (arguments[1] = e + t), /^\/([^\/]*)\/public/.test(t) && (arguments[1] = e + t), t.startsWith("/assets") && (arguments[1] = e + t), t == "/conf/public" && (arguments[1] = t), t.startsWith("http") && (arguments[1] = t), this.baseOpen.apply(this, arguments);
2750
2450
  });
2751
2451
  }
2752
- static serviceFor(e, t, s) {
2753
- let r;
2754
- switch (s) {
2755
- case "timelinegenerator":
2756
- r = new TimelinegeneratorBehaviour(e);
2757
- break;
2758
- case "workspace":
2759
- r = new WorkspaceBehaviour(e);
2760
- break;
2761
- case "blog":
2762
- r = new BlogBehaviour(e);
2763
- break;
2764
- case "actualites":
2765
- r = new ActualitesBehaviour(e);
2766
- break;
2767
- case "wiki":
2768
- r = new WikiBehaviour(e);
2769
- break;
2770
- case "pages":
2771
- r = new PagesBehaviour(e);
2772
- break;
2773
- case "poll":
2774
- r = new PollBehaviour(e);
2775
- break;
2776
- case "community":
2777
- r = new CommunityBehaviour(e);
2778
- break;
2779
- case "mindmap":
2780
- r = new MindmapBehaviour(e);
2781
- break;
2782
- case "forum":
2783
- r = new ForumBehaviour(e);
2784
- break;
2785
- case "homeworks":
2786
- r = new HomeworksBehaviour(e);
2787
- break;
2788
- case "scrapbook":
2789
- r = new ScrapbookBehaviour(e);
2790
- break;
2791
- case "collaborativewall":
2792
- r = new CollaborativewallBehaviour(e);
2793
- break;
2794
- case "exercizer":
2795
- r = new ExercizerBehaviour(e);
2796
- break;
2797
- case "formulaire":
2798
- r = new FormulaireBehaviour(e);
2799
- break;
2800
- case "magneto":
2801
- r = new MagnetoBehaviour(e);
2802
- break;
2803
- default:
2804
- throw ERROR_CODE.NOT_SUPPORTED;
2452
+ // private toAxiosConfig(params?: IHttpParams): AxiosRequestConfig {
2453
+ toAxiosConfig(e) {
2454
+ if (e) {
2455
+ const t = Object.assign({}, this.axios.defaults);
2456
+ e.headers && (t.headers = Object.assign({}, this.axios.defaults.headers), Object.assign(t.headers, e.headers)), e.responseType && (t.responseType = e.responseType), e.queryParams && (t.params = Object.assign({}, e.queryParams));
2457
+ const s = t.headers ?? {};
2458
+ return t.headers = { ...s, ...this.headers }, t;
2459
+ } else
2460
+ return this.axios.defaults;
2461
+ }
2462
+ toCdnUrl(e) {
2463
+ e = this.fixBaseUrl(e);
2464
+ const t = this.context.conf().getCdnUrl() || "";
2465
+ if (t.length > 0 && e !== "/conf/public") {
2466
+ const s = "" + e;
2467
+ (s.startsWith("/infra/public") || s.startsWith("/assets") || /^\/([^\/]*)\/public/.test(s)) && (e = t + s);
2805
2468
  }
2806
- return r.APP = t, r;
2469
+ return e;
2807
2470
  }
2808
- };
2809
- //
2810
- // STATIC REGISTRY
2811
- //
2812
- u(y, "registry", new ServiceRegistry()), // Expose some useful functions
2813
- u(y, "findBehaviour", y.registry.findService.bind(y.registry)), u(y, "hasBehaviour", y.registry.isRegistered.bind(y.registry)), u(y, "resourceProducingApps", []);
2814
- let SnipletsService = y;
2815
- const SEND_ALL = "*";
2816
- class WebBroker {
2817
- constructor(e) {
2818
- u(this, "subscription");
2819
- this.odeServices = e;
2471
+ mapAxiosError(e, t) {
2472
+ e.response ? this._latestResponse = e.response : e.request ? this._latestResponse = {
2473
+ status: 408,
2474
+ statusText: ERROR_CODE.TIME_OUT
2475
+ } : this._latestResponse = {
2476
+ status: 500,
2477
+ statusText: ERROR_CODE.UNKNOWN
2478
+ };
2479
+ const {
2480
+ /* status, statusText, headers, */
2481
+ data: s
2482
+ } = this._latestResponse;
2483
+ return s;
2820
2484
  }
2821
- get http() {
2822
- return this.odeServices.http();
2485
+ mapAxiosResponse(e, t) {
2486
+ return this._latestResponse = e, e.data;
2823
2487
  }
2824
- get events() {
2825
- return this.odeServices.notify().events();
2488
+ get latestResponse() {
2489
+ return this._latestResponse;
2826
2490
  }
2827
- dispatchEvent(e, t) {
2828
- t.findIndex(
2829
- (r) => SEND_ALL === r || e.data["event-type"] === r
2830
- ) >= 0 && this.http.post("/infra/event/web/store", e.data, {
2831
- disableNotifications: !0
2832
- });
2491
+ isResponseError() {
2492
+ return this.latestResponse.status < 200 || this.latestResponse.status >= 300;
2833
2493
  }
2834
- initialize(e) {
2835
- if (e === void 0 || e.send === void 0 || e.send.length > 0) {
2836
- const t = (e == null ? void 0 : e.send) ?? [SEND_ALL];
2837
- this.subscription = this.events.subscribe(
2838
- LAYER_NAME.WEB_DATA,
2839
- (s) => this.dispatchEvent(s, t)
2494
+ async get(e, t) {
2495
+ try {
2496
+ const s = await this.axios.get(
2497
+ this.toCdnUrl(e),
2498
+ this.toAxiosConfig(t)
2840
2499
  );
2500
+ return this.mapAxiosResponse(s, t);
2501
+ } catch (s) {
2502
+ throw this.mapAxiosError(s, t);
2841
2503
  }
2842
- return this;
2843
2504
  }
2844
- destroy() {
2845
- this.subscription && (this.subscription.revoke(), delete this.subscription);
2505
+ async post(e, t, s) {
2506
+ try {
2507
+ const r = await this.axios.post(
2508
+ this.fixBaseUrl(e),
2509
+ t,
2510
+ this.toAxiosConfig(s)
2511
+ );
2512
+ return this.mapAxiosResponse(r, s);
2513
+ } catch (r) {
2514
+ throw this.mapAxiosError(r, s);
2515
+ }
2846
2516
  }
2847
- }
2848
- class DataService {
2849
- constructor(e) {
2850
- u(this, "_webBroker");
2851
- u(this, "app");
2852
- u(this, "user");
2853
- u(this, "profile");
2854
- this.odeServices = e;
2517
+ async postFile(e, t, s) {
2518
+ const r = this.toAxiosConfig(s);
2519
+ r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
2520
+ try {
2521
+ const i = await this.axios.post(this.fixBaseUrl(e), t, {
2522
+ ...r,
2523
+ headers: {
2524
+ "Content-Type": "multipart/form-data"
2525
+ }
2526
+ });
2527
+ return this.mapAxiosResponse(i, s);
2528
+ } catch (i) {
2529
+ throw this.mapAxiosError(i, s);
2530
+ }
2855
2531
  }
2856
- get conf() {
2857
- return this.odeServices.conf();
2532
+ async postJson(e, t, s) {
2533
+ const r = this.toAxiosConfig();
2534
+ r.headers && (r.headers["Content-Type"] = "application/json");
2535
+ try {
2536
+ const i = await this.axios.post(
2537
+ this.fixBaseUrl(e),
2538
+ t,
2539
+ this.toAxiosConfig(s)
2540
+ );
2541
+ return this.mapAxiosResponse(i, s);
2542
+ } catch (i) {
2543
+ throw this.mapAxiosError(i, s);
2544
+ }
2858
2545
  }
2859
- get notify() {
2860
- return this.odeServices.notify();
2546
+ async put(e, t, s) {
2547
+ try {
2548
+ const r = await this.axios.put(
2549
+ this.fixBaseUrl(e),
2550
+ t,
2551
+ this.toAxiosConfig(s)
2552
+ );
2553
+ return this.mapAxiosResponse(r, s);
2554
+ } catch (r) {
2555
+ throw this.mapAxiosError(r, s);
2556
+ }
2861
2557
  }
2862
- // This method is called once, by the service container.
2863
- async initialize() {
2558
+ async putFile(e, t, s) {
2864
2559
  try {
2865
- const { app: e } = await this.notify.onAppConfReady().promise;
2866
- this.app = e, this.user = await this.odeServices.session().getUser(), this.profile = await this.odeServices.session().getUserProfile();
2867
- const { ["data-service"]: t } = await this.conf.getPublicConf(e);
2868
- this._webBroker = new WebBroker(this.odeServices).initialize(t == null ? void 0 : t.web);
2869
- } catch {
2870
- console.log("DataService not initialized, usage data unavailable.");
2560
+ const r = this.toAxiosConfig(s);
2561
+ r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
2562
+ const i = await this.axios.put(this.fixBaseUrl(e), t, {
2563
+ ...r,
2564
+ headers: {
2565
+ "Content-Type": "multipart/form-data"
2566
+ }
2567
+ });
2568
+ return this.mapAxiosResponse(i, s);
2569
+ } catch (r) {
2570
+ throw this.mapAxiosError(r, s);
2871
2571
  }
2872
2572
  }
2873
- //FIXME When to call that ??
2874
- predestroy() {
2875
- this._webBroker && (this._webBroker.destroy(), delete this._webBroker);
2573
+ async putJson(e, t, s) {
2574
+ const r = this.toAxiosConfig(s);
2575
+ r.headers && (r.headers["Content-Type"] = "application/json");
2576
+ try {
2577
+ const i = await this.axios.put(this.fixBaseUrl(e), t, r);
2578
+ return this.mapAxiosResponse(i, s);
2579
+ } catch (i) {
2580
+ throw this.mapAxiosError(i, s);
2581
+ }
2876
2582
  }
2877
- /** Send a web-user-level event to the data pipeline. */
2878
- trackWebEvent(e) {
2879
- this.notify.events().publish(LAYER_NAME.WEB_DATA, {
2880
- name: EVENT_NAME.DATA_TRACKED,
2881
- data: e
2882
- });
2583
+ async delete(e, t) {
2584
+ try {
2585
+ const s = await this.axios.delete(
2586
+ this.fixBaseUrl(e),
2587
+ this.toAxiosConfig(t)
2588
+ );
2589
+ return this.mapAxiosResponse(s, t);
2590
+ } catch (s) {
2591
+ throw this.mapAxiosError(s, t);
2592
+ }
2883
2593
  }
2884
- addUserInfos(e) {
2885
- return this.user && (e.userId = this.user.userId, e.structure = this.user.structureNames[0]), this.profile && (e.profil = this.profile[0]), e;
2886
- }
2887
- trackVideoSave(e, t, s, r, i, o, a) {
2888
- const c = this.addUserInfos({
2889
- "event-type": "VIDEO_SAVE",
2890
- module: "video",
2891
- video_id: e,
2892
- browser: o,
2893
- duration: Math.round(t),
2894
- weight: s,
2895
- source: r ? "CAPTURED" : "UPLOADED",
2896
- url: i
2897
- });
2898
- this.app && (c["override-module"] = this.app), a && (c.device_type = a), this.trackWebEvent(c);
2899
- }
2900
- trackVideoRead(e, t, s, r, i) {
2901
- const o = this.addUserInfos({
2902
- "event-type": "VIDEO_READ",
2903
- module: "video",
2904
- video_id: e,
2905
- browser: r,
2906
- source: t ? "CAPTURED" : "UPLOADED",
2907
- url: s
2908
- });
2909
- this.app && (o["override-module"] = this.app), i && (o.device_type = i), this.trackWebEvent(o);
2594
+ async deleteJson(e, t) {
2595
+ try {
2596
+ const s = await this.axios.delete(this.fixBaseUrl(e), {
2597
+ data: t
2598
+ });
2599
+ return this.mapAxiosResponse(s);
2600
+ } catch (s) {
2601
+ throw this.mapAxiosError(s);
2602
+ }
2910
2603
  }
2911
- trackSpeechAndText(e) {
2912
- const t = this.addUserInfos({
2913
- "event-type": "SPEECH_AND_TEXT",
2914
- function: e
2604
+ getScript(e, t, s) {
2605
+ const r = s ?? "exports", i = this.toAxiosConfig(t);
2606
+ return i.headers && (i.headers.Accept = "application/javascript"), this.axios.get(this.toCdnUrl(e), i).then((o) => this.mapAxiosResponse(o, t)).then((o) => {
2607
+ try {
2608
+ const u = `"use strict";var ${r.split(".")[0]}={};${o};return ${r};`;
2609
+ return Function(u)();
2610
+ } catch {
2611
+ return o;
2612
+ }
2613
+ }).catch((o) => {
2614
+ throw this.mapAxiosError(o, t), o;
2915
2615
  });
2916
- this.app && (t.module = this.app), this.trackWebEvent(t);
2917
2616
  }
2918
- trackAccessLibraryFromExplorer() {
2919
- const e = this.addUserInfos({
2920
- "event-type": "ACCESS_LIBRARY_FROM_EXPLORER"
2617
+ loadScript(e, t) {
2618
+ return loadedScripts[e] ? Promise.resolve() : this.getScript(e, t).then((s) => {
2619
+ loadedScripts[e] = !0;
2921
2620
  });
2922
- this.app && (e.module = this.app), this.trackWebEvent(e);
2923
2621
  }
2924
- }
2925
- class ReactionsService {
2926
- constructor(e, t, s) {
2927
- this.context = e, this.module = t, this.resourceType = s;
2622
+ }
2623
+ const R = class R {
2624
+ // in minutes. Applies to recorded videos.
2625
+ constructor(e) {
2626
+ this.context = e;
2928
2627
  }
2929
2628
  get http() {
2930
2629
  return this.context.http();
2931
2630
  }
2932
- async loadAvailableReactions() {
2933
- try {
2934
- const { "reaction-types": e } = await this.context.conf().getPublicConf("audience");
2935
- return Array.isArray(e) ? e : void 0;
2936
- } catch {
2937
- console.error("Audience configuration not found");
2938
- return;
2939
- }
2631
+ get conf() {
2632
+ return this.context.conf();
2940
2633
  }
2941
- async loadReactionSummaries(e) {
2942
- const t = await this.http.get(
2943
- `/audience/reactions/${this.module}/${this.resourceType}?resourceIds=${e.join(",")}`
2634
+ /**
2635
+ * Returns the video app public conf (maxWeight, maxDuration and accepted extensions)
2636
+ * @returns the Video app public conf
2637
+ */
2638
+ async getVideoConf() {
2639
+ var t;
2640
+ const e = await this.conf.getPublicConf(
2641
+ APP$2.VIDEO
2944
2642
  );
2945
- return this.http.isResponseError() ? {} : t.reactionsByResource;
2643
+ return {
2644
+ maxWeight: (e == null ? void 0 : e["max-videosize-mbytes"]) ?? R.MAX_WEIGHT,
2645
+ maxDuration: (e == null ? void 0 : e["max-videoduration-minutes"]) ?? R.MAX_DURATION,
2646
+ acceptVideoUploadExtensions: ((t = e == null ? void 0 : e["accept-videoupload-extensions"]) == null ? void 0 : t.map(
2647
+ (s) => s.toUpperCase()
2648
+ )) ?? []
2649
+ };
2946
2650
  }
2947
- async loadReactionDetails(e, t, s) {
2948
- const r = await this.http.get(
2949
- `/audience/reactions/${this.module}/${this.resourceType}/${e}?page=${t}&size=${s}`
2651
+ /**
2652
+ * Starts the encoding process and check when video is fully processed.
2653
+ * @param params cf VideoUploadParams
2654
+ * @returns a VideoCheckResponse
2655
+ */
2656
+ async upload({
2657
+ data: e,
2658
+ appCode: t,
2659
+ captation: s,
2660
+ duration: r
2661
+ }) {
2662
+ if (!e.file)
2663
+ throw new Error("Invalid video file.");
2664
+ if (!e.filename)
2665
+ throw new Error("Invalid video filename");
2666
+ const i = `${e.browser.name} ${e.browser.version}`, o = new FormData();
2667
+ o.append("device", e.device || ""), o.append("browser", i), o.append("url", e.url), o.append("app", t), o.append("file", e.file, e.filename), o.append("weight", "" + e.file.size), o.append("captation", "" + s);
2668
+ let u = `/video/encode?captation=${s}`;
2669
+ r && (u += `&duration=${r}`);
2670
+ const c = await this.http.post(
2671
+ u,
2672
+ o,
2673
+ { headers: { "Content-Type": "multipart/form-data" } }
2950
2674
  );
2951
- return this.http.isResponseError() ? void 0 : r;
2675
+ if (c.state == "running") {
2676
+ let h = 0, l = 1;
2677
+ do {
2678
+ const g = l + h;
2679
+ await new Promise(
2680
+ (p) => setTimeout(p, g * 1e3)
2681
+ ), h = l, l = Math.min(8, g);
2682
+ const d = await this.http.get(
2683
+ `/video/status/${c.processid}`
2684
+ );
2685
+ if (d.state == "succeed")
2686
+ return d;
2687
+ if (d.state == "error")
2688
+ break;
2689
+ } while (!0);
2690
+ }
2691
+ throw new Error("Video cannot be uploaded.");
2952
2692
  }
2953
- async deleteReaction(e) {
2954
- await this.http.delete(
2955
- `/audience/reactions/${this.module}/${this.resourceType}/${e}`
2956
- );
2693
+ };
2694
+ a(R, "MAX_WEIGHT", 50), // in Mbytes. Applies to uploaded videos.
2695
+ a(R, "MAX_DURATION", 3);
2696
+ let VideoService = R;
2697
+ const defaultMappers = {
2698
+ csv: function({ type: n, extension: e }) {
2699
+ return MimeTypeUtils.INSTANCE.isCsvLike(n, e);
2700
+ },
2701
+ doc: function({ type: n, extension: e }) {
2702
+ return MimeTypeUtils.INSTANCE.isWordLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("wordprocessing") !== -1;
2703
+ },
2704
+ xls: function({ type: n, extension: e }) {
2705
+ return MimeTypeUtils.INSTANCE.isExcelLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("spreadsheet") !== -1 || n.indexOf("ms-excel") !== -1;
2706
+ },
2707
+ img: function({ type: n }) {
2708
+ return n.indexOf("image") !== -1;
2709
+ },
2710
+ pdf: function({ type: n }) {
2711
+ return n.indexOf("pdf") !== -1 || n === "application/x-download";
2712
+ },
2713
+ ppt: function({ type: n, extension: e }) {
2714
+ return MimeTypeUtils.INSTANCE.isPowerpointLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("presentation") !== -1 || n.indexOf("powerpoint") !== -1;
2715
+ },
2716
+ txt: function({ type: n, extension: e }) {
2717
+ return MimeTypeUtils.INSTANCE.isTxtLike(n, e);
2718
+ },
2719
+ md: function({ type: n, extension: e }) {
2720
+ return MimeTypeUtils.INSTANCE.isMdLike(n, e);
2721
+ },
2722
+ video: function({ type: n }) {
2723
+ return n.indexOf("video") !== -1;
2724
+ },
2725
+ audio: function({ type: n }) {
2726
+ return n.indexOf("audio") !== -1;
2727
+ },
2728
+ zip: function({ type: n }) {
2729
+ return n.indexOf("zip") !== -1 || n.indexOf("rar") !== -1 || n.indexOf("tar") !== -1 || n.indexOf("7z") !== -1;
2957
2730
  }
2958
- async updateReaction(e, t) {
2959
- await this.http.putJson(
2960
- `/audience/reactions/${this.module}/${this.resourceType}`,
2961
- {
2962
- resourceId: e,
2963
- reactionType: t
2964
- }
2731
+ }, b = class b {
2732
+ /* Similar role notion as in infra-front > workspace > Model.ts */
2733
+ static getRole(e) {
2734
+ var t, s;
2735
+ return b.role(
2736
+ (t = e.metadata) == null ? void 0 : t["content-type"],
2737
+ !1,
2738
+ (s = e.metadata) == null ? void 0 : s.extension
2965
2739
  );
2966
2740
  }
2967
- async createReaction(e, t) {
2968
- await this.http.postJson(
2969
- `/audience/reactions/${this.module}/${this.resourceType}`,
2970
- {
2971
- resourceId: e,
2972
- reactionType: t
2973
- }
2974
- );
2741
+ /* Similar role notion as in infra-front > workspace > Model.ts */
2742
+ static role(e, t = !1, s) {
2743
+ if (s && (s = s.trim()), !e) return "unknown";
2744
+ this.roleMappers || console.warn("[DocumentHelper.role] should not have empty roles", this);
2745
+ const r = { type: e, previewRole: t, extension: s };
2746
+ for (const i of this.roleMappers) {
2747
+ const o = i(r);
2748
+ if (o)
2749
+ return o;
2750
+ }
2751
+ return "unknown";
2975
2752
  }
2976
- }
2977
- class ViewsService {
2978
- constructor(e, t, s) {
2979
- this.context = e, this.module = t, this.resourceType = s;
2753
+ };
2754
+ // FIXME add edumedia support
2755
+ a(b, "roleMappers", [
2756
+ (e) => Object.keys(defaultMappers).find((s) => defaultMappers[s](e))
2757
+ ]);
2758
+ let DocumentHelper = b;
2759
+ class WorkspaceService {
2760
+ constructor(e) {
2761
+ this.context = e;
2980
2762
  }
2981
2763
  get http() {
2982
2764
  return this.context.http();
2983
2765
  }
2984
- async getCounters(e) {
2985
- const t = await this.http.get(
2986
- `/audience/views/count/${this.module}/${this.resourceType}?resourceIds=${e.join(",")}`
2987
- );
2988
- return this.http.isResponseError() ? {} : t;
2766
+ extractMetadata(e) {
2767
+ const t = e.name || "", s = t.split("."), r = e.type || "application/octet-stream", i = s.length > 1 ? s[s.length - 1] : "", o = {
2768
+ "content-type": r,
2769
+ filename: t,
2770
+ size: e.size,
2771
+ extension: i,
2772
+ role: DocumentHelper.role(r, !1, i)
2773
+ }, u = t.replace("." + o.extension, ""), c = o.extension ? u + "." + o.extension : u;
2774
+ return { basename: u, fullname: c, metadata: o };
2989
2775
  }
2990
- async getDetails(e) {
2991
- const t = await this.http.get(
2992
- `/audience/views/details/${this.module}/${this.resourceType}/${e}`
2776
+ async saveFile(e, t) {
2777
+ const { fullname: s, metadata: r } = this.extractMetadata(e), i = new FormData();
2778
+ i.append("file", e, s);
2779
+ const o = [];
2780
+ ((t == null ? void 0 : t.visibility) === "public" || (t == null ? void 0 : t.visibility) === "protected") && o.push(`${t.visibility}=true`), t != null && t.application && o.push(`application=${t.application}`), r.role === "img" && o.push("quality=1"), t != null && t.parentId && o.push(`parentId=${t.parentId}`);
2781
+ const u = await this.http.postFile(
2782
+ `/workspace/document?${o.join("&")}`,
2783
+ i
2993
2784
  );
2994
- return this.http.isResponseError() ? void 0 : t;
2785
+ if (this.http.isResponseError())
2786
+ throw this.http.latestResponse.statusText;
2787
+ return u;
2995
2788
  }
2996
- trigger(e) {
2997
- return this.http.post(
2998
- `/audience/views/${this.module}/${this.resourceType}/${e}`
2789
+ async updateFile(e, t, s) {
2790
+ const { fullname: r, metadata: i } = this.extractMetadata(t), o = new FormData();
2791
+ o.append("file", t, r);
2792
+ const u = [];
2793
+ i.role === "img" && u.push("quality=1"), s != null && s.alt && u.push(`alt=${s.alt}`), s != null && s.legend && u.push(`legend=${s.legend}`), s != null && s.name && u.push(`name=${s.name}`);
2794
+ const c = await this.http.putFile(
2795
+ `/workspace/document/${e}?${u.join("&")}`,
2796
+ o
2999
2797
  );
2798
+ if (this.http.isResponseError())
2799
+ throw this.http.latestResponse.statusText;
2800
+ return c;
3000
2801
  }
3001
- }
3002
- class AudienceService {
3003
- constructor(e, t, s) {
3004
- this.context = e, this.module = t, this.resourceType = s;
2802
+ async deleteFile(e) {
2803
+ const t = e.map((s) => s._id);
2804
+ if (t.length == 0)
2805
+ Promise.resolve(null);
2806
+ else if (await this.http.deleteJson("/workspace/documents", {
2807
+ ids: t
2808
+ }), this.http.isResponseError())
2809
+ throw this.http.latestResponse.statusText;
3005
2810
  }
3006
- get views() {
3007
- return new ViewsService(this.context, this.module, this.resourceType);
2811
+ async acceptDocuments(e) {
2812
+ const t = await this.context.session().getUser();
2813
+ return (s) => s.deleted && s.trasher ? (t == null ? void 0 : t.userId) == s.trasher : !0;
3008
2814
  }
3009
- get reactions() {
3010
- return new ReactionsService(this.context, this.module, this.resourceType);
2815
+ async searchDocuments(e) {
2816
+ const t = e.filter !== "external" || e.parentId ? await this.http.get("/workspace/documents", {
2817
+ queryParams: { ...e, _: (/* @__PURE__ */ new Date()).getTime() }
2818
+ }) : [], s = await this.acceptDocuments(e);
2819
+ return t.filter(s);
2820
+ }
2821
+ async listDocuments(e, t) {
2822
+ return this.searchDocuments({ filter: e, parentId: t, includeall: !0 });
2823
+ }
2824
+ /**
2825
+ * Duplicate and transfers documents if needed to a different folder with the specified application and visibility.
2826
+ * @param documents - The array of documents to transfer.
2827
+ * @param application - The application to associate with the transferred documents.
2828
+ * @param visibility - The visibility of the transferred documents. Defaults to "protected".
2829
+ * @returns A Promise that resolves to an array of transferred WorkspaceElements.
2830
+ */
2831
+ async transferDocuments(e, t, s = "protected") {
2832
+ const r = [];
2833
+ if (e.forEach((i) => {
2834
+ (s === "public" && !i.public || !i.public && !i.protected) && r.push(i);
2835
+ }), r.length > 0) {
2836
+ const i = await this.http.post(
2837
+ "/workspace/documents/transfer",
2838
+ {
2839
+ application: t,
2840
+ visibility: s,
2841
+ ids: r.map((o) => o._id)
2842
+ }
2843
+ );
2844
+ if (this.http.isResponseError())
2845
+ throw this.http.latestResponse.statusText;
2846
+ return r.forEach((o, u) => {
2847
+ const c = e.findIndex(
2848
+ (h) => h._id === o._id
2849
+ );
2850
+ 0 <= c && c < e.length && (e[c] = i[u]);
2851
+ }), e.filter((o) => !!o);
2852
+ }
2853
+ return e;
2854
+ }
2855
+ /**
2856
+ * Get the URL of the thumbnail of a workspace element (or its URL),
2857
+ * or `null` if none exists or can be created.
2858
+ */
2859
+ getThumbnailUrl(e, t = 0, s = 0) {
2860
+ var i, o;
2861
+ const r = t > 0 || s > 0 ? `${t}x${s}` : "120x120";
2862
+ if (typeof e == "string")
2863
+ return e.includes("data:image") || e.includes("thumbnail") ? e : `${e}${e.includes("?") ? "&" : "?"}thumbnail=${r}`;
2864
+ {
2865
+ const u = `/workspace/${e.public ? "pub/" : ""}document/${e._id}?thumbnail=`, c = e.thumbnails;
2866
+ if ((o = (i = e.metadata) == null ? void 0 : i["content-type"]) != null && o.includes("video")) {
2867
+ const h = c && Object.keys(c).length > 0 ? Object.keys(c)[0] : null;
2868
+ return h ? u + h : null;
2869
+ } else
2870
+ return u + r;
2871
+ }
3011
2872
  }
3012
2873
  }
3013
2874
  class OdeServices {
3014
2875
  constructor() {
3015
- u(this, "_analytics");
3016
- u(this, "_cache");
3017
- u(this, "_conf");
3018
- u(this, "_data");
3019
- u(this, "_directory");
3020
- u(this, "_http");
3021
- u(this, "_idiom");
3022
- u(this, "_notify");
3023
- u(this, "_rights");
3024
- u(this, "_session");
3025
- u(this, "_share");
3026
- u(this, "_video");
3027
- u(this, "_workspace");
3028
- u(this, "_embedder");
3029
- this._analytics = new AnalyticsService(this), this._cache = new CacheService(this), this._conf = new ConfService(this), this._data = new DataService(this), this._directory = new DirectoryService(this), this._http = new HttpService(this), this._idiom = new IdiomService(this), this._notify = NotifyFrameworkFactory.instance(), this._rights = new RightService(this), this._session = new SessionService(this), this._share = new ShareService(this), this._video = new VideoService(this), this._workspace = new WorkspaceService(this), this._embedder = new EmbedderService(this);
2876
+ a(this, "_analytics");
2877
+ a(this, "_cache");
2878
+ a(this, "_conf");
2879
+ // private _data: DataService;
2880
+ a(this, "_directory");
2881
+ a(this, "_http");
2882
+ a(this, "_idiom");
2883
+ // private _notify: INotifyFramework;
2884
+ a(this, "_rights");
2885
+ a(this, "_session");
2886
+ a(this, "_share");
2887
+ a(this, "_video");
2888
+ a(this, "_workspace");
2889
+ a(this, "_embedder");
2890
+ this._analytics = new AnalyticsService(this), this._cache = new CacheService(this), this._conf = new ConfService(this), this._directory = new DirectoryService(this), this._http = new HttpService(this), this._idiom = new IdiomService(this), this._rights = new RightService(this), this._session = new SessionService(this), this._share = new ShareService(this), this._video = new VideoService(this), this._workspace = new WorkspaceService(this), this._embedder = new EmbedderService(this);
3030
2891
  }
3031
2892
  initialize() {
3032
- return this._data.initialize(), this;
2893
+ return this;
3033
2894
  }
3034
2895
  analytics() {
3035
2896
  return this._analytics;
@@ -3043,9 +2904,9 @@ class OdeServices {
3043
2904
  conf() {
3044
2905
  return this._conf;
3045
2906
  }
3046
- data() {
2907
+ /* data() {
3047
2908
  return this._data;
3048
- }
2909
+ } */
3049
2910
  directory() {
3050
2911
  return this._directory;
3051
2912
  }
@@ -3055,9 +2916,9 @@ class OdeServices {
3055
2916
  idiom() {
3056
2917
  return this._idiom;
3057
2918
  }
3058
- notify() {
2919
+ /* notify() {
3059
2920
  return this._notify;
3060
- }
2921
+ } */
3061
2922
  resource(e, t) {
3062
2923
  return t ? ResourceService.findService({ application: e, resourceType: t }, this) : ResourceService.findMainService({ application: e }, this);
3063
2924
  }
@@ -3196,11 +3057,8 @@ export {
3196
3057
  BOOLEAN_FILTER,
3197
3058
  DocumentHelper,
3198
3059
  ERROR_CODE,
3199
- EVENT_NAME,
3200
3060
  FOLDER,
3201
- LAYER_NAME,
3202
3061
  LastInfosWidget,
3203
- NotifyFrameworkFactory,
3204
3062
  ReactionTypes,
3205
3063
  ResourceService,
3206
3064
  SORT_BY,