@edifice.io/client 2.0.1-develop-hotfix.1736764109512 → 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,567 +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 {
817
- constructor(e, t) {
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.create({
824
- ...t,
825
- adapter: "http"
826
- });
905
+ class EmbedderService {
906
+ constructor(e) {
907
+ this.context = e;
827
908
  }
828
- fixBaseUrl(e) {
829
- 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();
830
911
  }
831
- useBaseUrl(e) {
832
- 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");
833
918
  }
834
- useHeaders(e) {
835
- 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");
836
925
  }
837
- setCdn(e) {
838
- e && XMLHttpRequest && !XMLHttpRequest.prototype.cdnUrl && (XMLHttpRequest.prototype.cdnUrl = e, XMLHttpRequest.prototype.baseOpen = XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.open = function() {
839
- const t = arguments[1];
840
- 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);
841
- });
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;
842
936
  }
843
- // private toAxiosConfig(params?: IHttpParams): AxiosRequestConfig {
844
- toAxiosConfig(e) {
845
- if (e) {
846
- const t = Object.assign({}, this.axios.defaults);
847
- 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));
848
- const s = t.headers ?? {};
849
- return t.headers = { ...s, ...this.headers }, t;
850
- } else
851
- 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;
852
949
  }
853
- toCdnUrl(e) {
854
- e = this.fixBaseUrl(e);
855
- const t = this.context.conf().getCdnUrl() || "";
856
- if (t.length > 0 && e !== "/conf/public") {
857
- const s = "" + e;
858
- (s.startsWith("/infra/public") || s.startsWith("/assets") || /^\/([^\/]*)\/public/.test(s)) && (e = t + s);
859
- }
860
- 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;
861
962
  }
862
- mapAxiosError(e, t) {
863
- e.response ? this._latestResponse = e.response : e.request ? this._latestResponse = {
864
- status: 408,
865
- statusText: ERROR_CODE.TIME_OUT
866
- } : this._latestResponse = {
867
- status: 500,
868
- statusText: ERROR_CODE.UNKNOWN
869
- };
870
- const { status: s, statusText: r, headers: i, data: o } = this._latestResponse;
871
- return t != null && t.disableNotifications || notify.events().publish(LAYER_NAME.TRANSPORT, {
872
- name: EVENT_NAME.ERROR_OCCURED,
873
- data: {
874
- params: t,
875
- response: { status: s, statusText: r, headers: i },
876
- 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;
877
987
  }
878
- }), o;
879
- }
880
- mapAxiosResponse(e, t) {
881
- return this._latestResponse = e, e.data;
988
+ return "";
882
989
  }
883
- get latestResponse() {
884
- return this._latestResponse;
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
+ );
885
997
  }
886
- isResponseError() {
887
- return this.latestResponse.status < 200 || this.latestResponse.status >= 300;
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
+ };
888
1003
  }
889
- async get(e, t) {
890
- try {
891
- const s = await this.axios.get(
892
- this.toCdnUrl(e),
893
- this.toAxiosConfig(t)
894
- );
895
- return this.mapAxiosResponse(s, t);
896
- } catch (s) {
897
- throw this.mapAxiosError(s, t);
898
- }
899
- }
900
- async post(e, t, s) {
901
- try {
902
- const r = await this.axios.post(
903
- this.fixBaseUrl(e),
904
- t,
905
- this.toAxiosConfig(s)
906
- );
907
- return this.mapAxiosResponse(r, s);
908
- } catch (r) {
909
- throw this.mapAxiosError(r, s);
910
- }
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());
911
1012
  }
912
- async postFile(e, t, s) {
913
- const r = this.toAxiosConfig(s);
914
- r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
915
- try {
916
- const i = await this.axios.post(this.fixBaseUrl(e), t, {
917
- ...r,
918
- headers: {
919
- "Content-Type": "multipart/form-data"
920
- }
921
- });
922
- return this.mapAxiosResponse(i, s);
923
- } catch (i) {
924
- throw this.mapAxiosError(i, s);
925
- }
1013
+ getChannelName(e) {
1014
+ return "Subject:" + e;
926
1015
  }
927
- async postJson(e, t, s) {
928
- const r = this.toAxiosConfig();
929
- r.headers && (r.headers["Content-Type"] = "application/json");
930
- try {
931
- const i = await this.axios.post(
932
- this.fixBaseUrl(e),
933
- t,
934
- this.toAxiosConfig(s)
935
- );
936
- return this.mapAxiosResponse(i, s);
937
- } catch (i) {
938
- throw this.mapAxiosError(i, s);
939
- }
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;
940
1020
  }
941
- async put(e, t, s) {
942
- try {
943
- const r = await this.axios.put(
944
- this.fixBaseUrl(e),
945
- t,
946
- this.toAxiosConfig(s)
947
- );
948
- return this.mapAxiosResponse(r, s);
949
- } catch (r) {
950
- throw this.mapAxiosError(r, s);
951
- }
1021
+ newChannel(e) {
1022
+ const t = this.getChannelName(e), s = new BroadcastChannel(t);
1023
+ return s.addEventListener("messageerror", (r) => console.log(r.data)), s;
952
1024
  }
953
- async putFile(e, t, s) {
954
- try {
955
- const r = this.toAxiosConfig(s);
956
- r.headers && r.headers["Content-Type"] && delete r.headers["Content-Type"];
957
- const i = await this.axios.put(this.fixBaseUrl(e), t, {
958
- ...r,
959
- headers: {
960
- "Content-Type": "multipart/form-data"
961
- }
962
- });
963
- return this.mapAxiosResponse(i, s);
964
- } catch (r) {
965
- throw this.mapAxiosError(r, s);
966
- }
1025
+ publish(e, t) {
1026
+ typeof e == "string" && this.getPublishChannel(e).postMessage(t);
967
1027
  }
968
- async putJson(e, t, s) {
969
- const r = this.toAxiosConfig(s);
970
- r.headers && (r.headers["Content-Type"] = "application/json");
971
- try {
972
- const i = await this.axios.put(this.fixBaseUrl(e), t, r);
973
- return this.mapAxiosResponse(i, s);
974
- } catch (i) {
975
- throw this.mapAxiosError(i, s);
976
- }
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();
977
1034
  }
978
- async delete(e, t) {
979
- try {
980
- const s = await this.axios.delete(
981
- this.fixBaseUrl(e),
982
- this.toAxiosConfig(t)
983
- );
984
- return this.mapAxiosResponse(s, t);
985
- } catch (s) {
986
- throw this.mapAxiosError(s, t);
987
- }
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
+ }));
988
1051
  }
989
- async deleteJson(e, t) {
990
- try {
991
- const s = await this.axios.delete(this.fixBaseUrl(e), {
992
- data: t
993
- });
994
- return this.mapAxiosResponse(s);
995
- } catch (s) {
996
- throw this.mapAxiosError(s);
997
- }
1052
+ get promise() {
1053
+ return this._promise;
998
1054
  }
999
- getScript(e, t, s) {
1000
- const r = s ?? "exports", i = this.toAxiosConfig(t);
1001
- return i.headers && (i.headers.Accept = "application/javascript"), this.axios.get(this.toCdnUrl(e), i).then((o) => this.mapAxiosResponse(o, t)).then((o) => {
1002
- try {
1003
- const a = `"use strict";var ${r.split(".")[0]}={};${o};return ${r};`;
1004
- return Function(a)();
1005
- } catch {
1006
- return o;
1007
- }
1008
- }).catch((o) => {
1009
- throw this.mapAxiosError(o, t), o;
1010
- });
1055
+ resolve(e) {
1056
+ this._resolution && this._resolution(e);
1011
1057
  }
1012
- loadScript(e, t) {
1013
- return loadedScripts[e] ? Promise.resolve() : this.getScript(e, t).then((s) => {
1014
- loadedScripts[e] = !0;
1015
- });
1058
+ reject(e) {
1059
+ this._rejection && this._rejection(e);
1016
1060
  }
1017
1061
  }
1018
- class RightService {
1019
- constructor(e) {
1020
- this.context = e;
1062
+ class NotifyFramework {
1063
+ constructor() {
1064
+ //-------------------------------------
1065
+ a(this, "promises", {});
1066
+ a(this, "subject", new Subject());
1021
1067
  }
1022
- get session() {
1023
- return this.context.session();
1068
+ asyncData(e) {
1069
+ return typeof this.promises[e] > "u" && (this.promises[e] = new Promisified()), this.promises[e];
1024
1070
  }
1025
- /**
1026
- * Parse right concat as "$TYPE:$ID:$RIGHT"
1027
- * $TYPE = user | group | creator
1028
- * $ID: id of the resource
1029
- * $RIGHT: read | contrib | manage
1030
- *
1031
- * @param right a concat right
1032
- * @returns Right parsed
1033
- */
1034
- parseResourceRight(e) {
1035
- const t = e.split(":");
1036
- if (t.length === 2) {
1037
- if (t[0] === "creator")
1038
- return {
1039
- id: t[1],
1040
- right: "creator",
1041
- type: "creator"
1042
- };
1043
- } else return t.length === 3 ? {
1044
- id: t[1],
1045
- right: t[2],
1046
- type: t[0]
1047
- } : void 0;
1071
+ onSessionReady() {
1072
+ return this.asyncData(ASYNC_DATA_NAME.SESSION_READY);
1048
1073
  }
1049
- /**
1050
- * Parse an array of rights concat as "$TYPE:$ID:$RIGHT"
1051
- * $TYPE = user | group | creator
1052
- * $ID: id of the resource
1053
- * $RIGHT: read | contrib | manage
1054
- *
1055
- * @param rights a list of concat rights
1056
- * @returns Array of Right parsed
1057
- */
1058
- parseResourceRights(e) {
1059
- return e.map((s) => this.parseResourceRight(s)).filter((s) => s !== void 0);
1074
+ onLangReady() {
1075
+ return this.asyncData(ASYNC_DATA_NAME.LANG_READY);
1060
1076
  }
1061
- /**
1062
- * Check wether a user has the expected right for a ressource
1063
- * @param user the userId and groupId concerned by the check
1064
- * @param expect the expected right to check
1065
- * @param rights array of Right for the resource
1066
- * @returns true if has rights
1067
- */
1068
- hasResourceRight({ id: e, groupIds: t }, s, r) {
1069
- const i = r.map((o) => typeof o == "string" ? this.parseResourceRight(o) : o).filter((o) => o !== void 0);
1070
- for (const o of i) {
1071
- if (o.id === e && o.type === "creator")
1072
- return !0;
1073
- if (o.id === e && o.type === "user" && o.right === s)
1074
- return !0;
1075
- if (t.includes(o.id) && o.type === "group" && o.right === s)
1076
- return !0;
1077
- }
1078
- return !1;
1077
+ onSkinReady() {
1078
+ return this.asyncData(ASYNC_DATA_NAME.SKIN_READY);
1079
1079
  }
1080
- /**
1081
- * Check wether the current user have resource right
1082
- * @param expect the expected right to check
1083
- * @param rights array of Right for the resource
1084
- * @returns true if has rights
1085
- */
1086
- async sessionHasResourceRight(e, t) {
1087
- try {
1088
- const s = await this.session.getUser();
1089
- return !!s && this.hasResourceRight(
1090
- { groupIds: s.groupsIds, id: s.userId },
1091
- e,
1092
- t
1093
- );
1094
- } catch (s) {
1095
- return console.error(`Unexpected error ${s} in sessionHasResourceRight()`), !1;
1096
- }
1080
+ onOverridesReady() {
1081
+ return this.asyncData(ASYNC_DATA_NAME.OVERRIDE_READY);
1097
1082
  }
1098
- /**
1099
- * Check wether the current user have at least one of resource right expected
1100
- * @param expects array of expected right to check
1101
- * @param rights array of Right for the resource
1102
- * @returns true if has rights
1103
- */
1104
- async sessionHasAtLeastOneResourceRight(e, t) {
1105
- for (const s of e)
1106
- if (await this.sessionHasResourceRight(s, t))
1107
- return !0;
1108
- return !1;
1083
+ onAppConfReady() {
1084
+ return this.asyncData(ASYNC_DATA_NAME.APPCONF_READY);
1109
1085
  }
1110
- /**
1111
- * Check wether the current user has resource right for each right list
1112
- * @param expect expected right to check
1113
- * @param rightsArray array of array of Right for multiple resources
1114
- * @returns true if has rights
1115
- */
1116
- async sessionHasResourceRightForEachList(e, t) {
1117
- let s = 0;
1118
- for (const r of t)
1119
- await this.sessionHasResourceRight(e, r) && s++;
1120
- return s === t.length;
1121
- }
1122
- /**
1123
- * Check wether the current user have at least one of resource right for each right list
1124
- * @param expects array of expected right to check
1125
- * @param rightsArray array of array of Right for multiple resources
1126
- * @returns true if has rights
1127
- */
1128
- async sessionHasAtLeastOneResourceRightForEachList(e, t) {
1129
- for (const s of e) {
1130
- let r = 0;
1131
- for (const i of t)
1132
- await this.sessionHasResourceRight(s, i) && r++;
1133
- if (r === t.length)
1134
- return !0;
1135
- }
1136
- return !1;
1137
- }
1138
- hasWorkflowRight(e, t) {
1139
- return t.findIndex((s) => s === e) !== -1;
1140
- }
1141
- /**
1142
- * @param expect a workflow right
1143
- * @returns true if current session has right on it
1144
- */
1145
- async sessionHasWorkflowRight(e) {
1146
- try {
1147
- const t = await this.session.getUser();
1148
- return !!t && this.hasWorkflowRight(
1149
- e,
1150
- t.authorizedActions.map(
1151
- (s) => s.name
1152
- )
1153
- );
1154
- } catch (t) {
1155
- return console.error(`Unexpected error ${t} in sessionHasWorkflowRight()`), !1;
1156
- }
1157
- }
1158
- /**
1159
- * @param expect a workflow right
1160
- * @returns a record with right as key and boolean as value if current session has right on it
1161
- */
1162
- async sessionHasWorkflowRights(e) {
1163
- const t = {};
1164
- try {
1165
- const s = await this.session.getUser();
1166
- for (const r of e)
1167
- t[r] = !!s && this.hasWorkflowRight(
1168
- r,
1169
- s.authorizedActions.map(
1170
- (i) => i.name
1171
- )
1172
- );
1173
- } catch (s) {
1174
- console.error(`Unexpected error ${s} in sessionHasWorkflowRights()`);
1175
- for (const r of e)
1176
- t[r] = !1;
1177
- }
1178
- return t;
1179
- }
1180
- }
1181
- class SessionService {
1182
- constructor(e) {
1183
- this.context = e;
1184
- }
1185
- get http() {
1186
- return this.context.http();
1187
- }
1188
- get cache() {
1189
- return this.context.cache();
1190
- }
1191
- get conf() {
1192
- return this.context.conf();
1193
- }
1194
- /**
1195
- * Callback to call when user logout
1196
- */
1197
- onLogout() {
1198
- this.cache.clearCache();
1199
- }
1200
- /**
1201
- * Callback to call when session change
1202
- */
1203
- onRefreshSession() {
1204
- this.cache.clearCache();
1205
- }
1206
- async getSession() {
1207
- const e = await this.getUser(), [
1208
- t,
1209
- s,
1210
- r,
1211
- i,
1212
- o
1213
- ] = await Promise.all([
1214
- this.getCurrentLanguage(e),
1215
- this.latestQuotaAndUsage(e),
1216
- this.loadDescription(e),
1217
- this.getUserProfile(),
1218
- this.getBookmarks(e)
1219
- ]);
1220
- return {
1221
- user: e,
1222
- quotaAndUsage: s,
1223
- currentLanguage: t,
1224
- userDescription: r,
1225
- userProfile: i,
1226
- bookmarkedApps: o
1227
- };
1228
- }
1229
- login(e, t, s, r) {
1230
- const i = new FormData();
1231
- 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, {
1232
- headers: { "content-type": "application/x-www-form-urlencoded" }
1233
- }).finally(() => {
1234
- switch (this.http.latestResponse.status) {
1235
- case 200:
1236
- throw ERROR_CODE.MALFORMED_DATA;
1237
- }
1238
- });
1239
- }
1240
- async logout() {
1241
- const e = await this.conf.getLogoutCallback();
1242
- return this.http.get("/auth/logout?callback=" + e).finally(() => {
1243
- });
1244
- }
1245
- async latestQuotaAndUsage(e) {
1246
- const t = { quota: 0, storage: 0 };
1247
- if (!e) return t;
1248
- try {
1249
- return await this.http.get(
1250
- `/workspace/quota/user/${e == null ? void 0 : e.userId}`
1251
- );
1252
- } catch (s) {
1253
- return console.error(s), t;
1254
- }
1255
- }
1256
- async getCurrentLanguage(e) {
1257
- const t = (e == null ? void 0 : e.sessionMetadata) && (e == null ? void 0 : e.sessionMetadata.userId);
1258
- try {
1259
- let s;
1260
- return t ? s = await this.loadUserLanguage() : s = await this.loadDefaultLanguage(), s;
1261
- } catch (s) {
1262
- console.error(s);
1263
- }
1264
- }
1265
- async loadUserLanguage() {
1266
- try {
1267
- const e = await this.http.get(
1268
- "/userbook/preference/language"
1269
- );
1270
- return JSON.parse(e.preference)["default-domain"];
1271
- } catch {
1272
- return await this.loadDefaultLanguage();
1273
- }
1274
- }
1275
- async loadDefaultLanguage() {
1276
- return (await this.cache.httpGetJson(
1277
- "/locale"
1278
- )).locale;
1279
- }
1280
- async getUser() {
1281
- const { response: e, value: t } = await this.cache.httpGet(
1282
- "/auth/oauth2/userinfo"
1283
- );
1284
- if (!(e.status < 200 || e.status >= 300) && typeof t == "object")
1285
- return t;
1286
- throw ERROR_CODE.NOT_LOGGED_IN;
1287
- }
1288
- hasWorkflow({
1289
- workflowName: e,
1290
- user: t
1291
- }) {
1292
- return e === void 0 || (t == null ? void 0 : t.authorizedActions.findIndex((s) => s.name === e)) !== -1;
1293
- }
1294
- async loadDescription(e) {
1295
- if (!e) return {};
1296
- try {
1297
- const [t, s] = await Promise.all([
1298
- // FIXME The full user's description should be obtainable from a single endpoint in the backend.
1299
- this.getUserProfile({
1300
- options: { requestName: "refreshAvatar" }
1301
- }),
1302
- this.http.get("/directory/userbook/" + (e == null ? void 0 : e.userId))
1303
- ]);
1304
- return { ...s, profiles: t };
1305
- } catch (t) {
1306
- return console.error(t), {};
1307
- }
1308
- }
1309
- async getBookmarks(e) {
1310
- if (!e) return [];
1311
- const t = await this.http.get("/userbook/preference/apps");
1312
- t.preference || (t.preference = null);
1313
- const s = JSON.parse(t.preference);
1314
- let r;
1315
- r = s, r || (r = {
1316
- bookmarks: [],
1317
- applications: []
1318
- });
1319
- const i = [];
1320
- return r.bookmarks.forEach((o, a) => {
1321
- const c = ((e == null ? void 0 : e.apps) || []).find(
1322
- (l) => l.name === o
1323
- );
1324
- if (c) {
1325
- const l = Object.assign({}, c);
1326
- i.push(l);
1327
- }
1328
- }), i;
1329
- }
1330
- async getUserProfile(e = {}) {
1331
- var c, l;
1332
- 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);
1333
- 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"];
1334
- }
1335
- async isAdml() {
1336
- const e = await this.getUser();
1337
- return (e == null ? void 0 : e.functions.ADMIN_LOCAL) !== void 0;
1086
+ promisify() {
1087
+ return new Promisified();
1338
1088
  }
1339
- /**
1340
- * Get details of an application if the user can access it.
1341
- * @return undefined if no access, or app not found
1342
- */
1343
- async getWebApp(e) {
1344
- const t = await this.getUser();
1345
- return t == null ? void 0 : t.apps.find((s) => {
1346
- var r;
1347
- 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;
1348
- });
1089
+ events() {
1090
+ return this.subject;
1349
1091
  }
1350
1092
  }
1351
- const bundle = {}, promises = {}, defaultDiacriticsRemovalMap = [
1093
+ const notify = new NotifyFramework(), bundle = {}, promises = {}, defaultDiacriticsRemovalMap = [
1352
1094
  {
1353
1095
  base: "A",
1354
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
@@ -1595,9 +1337,9 @@ class IdiomService {
1595
1337
  const i = new Promisified();
1596
1338
  promises[t] = i.promise;
1597
1339
  const o = {};
1598
- e && (o["Accept-Language"] = e), this.http.get(t, { headers: o }).then((a) => {
1599
- Object.assign(bundle, a), typeof s == "function" && s(), i.resolve();
1600
- }).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) => {
1601
1343
  typeof s == "function" && s(), i.reject();
1602
1344
  });
1603
1345
  }
@@ -1630,1409 +1372,1525 @@ class IdiomService {
1630
1372
  return e;
1631
1373
  }
1632
1374
  }
1633
- class StringUtils {
1634
- static removeAccents(e) {
1635
- for (let t = 0; t < defaultDiacriticsRemovalMap.length; t++)
1636
- e = e.replace(
1637
- defaultDiacriticsRemovalMap[t].letters,
1638
- defaultDiacriticsRemovalMap[t].base
1639
- );
1640
- return e;
1641
- }
1642
- }
1643
- class ShareService {
1375
+ class AbstractBehaviourService {
1644
1376
  //
1645
1377
  // IMPLEMENTATION
1646
1378
  //
1647
1379
  constructor(e) {
1648
- this.context = e;
1380
+ //-----------------
1381
+ //--- Utilities ---
1382
+ //-----------------
1383
+ a(this, "_cache");
1384
+ this.context = e, this._cache = new CacheService(this.context);
1649
1385
  }
1650
- get directory() {
1651
- return this.context.directory();
1386
+ getApplication() {
1387
+ return this.APP;
1652
1388
  }
1653
- get http() {
1654
- return this.context.http();
1655
- }
1656
- get cache() {
1657
- return this.context.cache();
1658
- }
1659
- async searchShareSubjects(e, t, s) {
1660
- const r = StringUtils.removeAccents(s).toLowerCase(), i = await this.cache.httpGetJson(
1661
- `/${e}/share/json/${t}?search=${s}`
1662
- ), o = i.users.visibles.filter(({ username: h, firstName: E, lastName: p, login: d }) => {
1663
- const g = StringUtils.removeAccents(
1664
- p || ""
1665
- ).toLowerCase(), A = StringUtils.removeAccents(
1666
- E || ""
1667
- ).toLowerCase(), m = StringUtils.removeAccents(
1668
- h || ""
1669
- ).toLowerCase(), R = StringUtils.removeAccents(d || "").toLowerCase();
1670
- return m.includes(r) || A.includes(r) || g.includes(r) || R.includes(r);
1671
- }).map((h) => ({
1672
- avatarUrl: this.directory.getAvatarUrl(h.id, "user"),
1673
- directoryUrl: this.directory.getDirectoryUrl(h.id, "user"),
1674
- displayName: h.username,
1675
- id: h.id,
1676
- profile: h.profile,
1677
- type: "user"
1678
- })), a = i.groups.visibles.filter(({ name: h }) => StringUtils.removeAccents(h || "").toLowerCase().includes(r)).map((h) => ({
1679
- avatarUrl: this.directory.getAvatarUrl(h.id, "group"),
1680
- directoryUrl: this.directory.getDirectoryUrl(h.id, "group"),
1681
- displayName: h.name,
1682
- id: h.id,
1683
- type: "group",
1684
- structureName: h.structureName
1685
- }));
1686
- return [...(await this.directory.getBookMarks()).filter(({ displayName: h }) => StringUtils.removeAccents(
1687
- h || ""
1688
- ).toLowerCase().includes(r)).map((h) => ({
1689
- avatarUrl: "",
1690
- directoryUrl: "",
1691
- profile: "",
1692
- displayName: h.displayName,
1693
- id: h.id,
1694
- type: "sharebookmark"
1695
- })), ...o, ...a];
1696
- }
1697
- async getShareMapping(e) {
1698
- const t = await this.cache.httpGetJson(
1699
- `/${e}/rights/sharing`
1700
- );
1701
- for (const s of Object.keys(t))
1702
- if (s.includes(".")) {
1703
- const r = s.split(".")[1], i = t[s];
1704
- delete t[s], t[r] = i;
1705
- }
1706
- return t;
1389
+ getResourceType() {
1390
+ return this.RESOURCE;
1707
1391
  }
1708
- getActionsAvailableFor({ id: e, type: t }, s, r) {
1709
- const o = (t === "user" ? s.users.checked[e] : s.groups.checked[e]) || [], a = Object.keys(r), c = [];
1710
- for (const l of a)
1711
- r[l].filter(
1712
- (p) => o.includes(p)
1713
- ).length > 0 && c.push(l);
1714
- return c;
1392
+ httpGet(e, t) {
1393
+ return this._cache.httpGetJson(e, t);
1715
1394
  }
1716
- async getRightsForResource(e, t) {
1717
- 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(
1718
- "/infra/public/json/sharing-rights.json"
1719
- ), c = Object.keys(i.users.checked).map((d) => i.users.visibles.find(
1720
- (A) => A.id === d
1721
- )).filter((d) => d !== void 0).map((d) => {
1722
- const g = this.getActionsAvailableFor(
1723
- { id: d.id, type: "user" },
1724
- i,
1725
- o
1726
- );
1727
- return {
1728
- id: d.id,
1729
- type: "user",
1730
- displayName: d.username,
1731
- profile: d.profile,
1732
- avatarUrl: this.directory.getAvatarUrl(d.id, "user"),
1733
- directoryUrl: this.directory.getDirectoryUrl(d.id, "user"),
1734
- actions: g.map((m) => {
1735
- const R = a[m];
1736
- return {
1737
- displayName: m,
1738
- id: m,
1739
- priority: R.priority
1740
- };
1741
- })
1742
- };
1743
- }).sort((d, g) => (d.displayName || "").localeCompare(g.displayName)), l = Object.keys(i.groups.checked).map((d) => i.groups.visibles.find(
1744
- (A) => A.id === d
1745
- )).filter((d) => d !== void 0).map((d) => {
1746
- const g = this.getActionsAvailableFor(
1747
- { id: d.id, type: "group" },
1748
- i,
1749
- o
1750
- );
1751
- return {
1752
- id: d.id,
1753
- type: "group",
1754
- displayName: d.name,
1755
- profile: void 0,
1756
- avatarUrl: this.directory.getAvatarUrl(d.id, "group"),
1757
- directoryUrl: this.directory.getDirectoryUrl(d.id, "group"),
1758
- actions: g.map((m) => {
1759
- const R = a[m];
1760
- return {
1761
- displayName: m,
1762
- id: m,
1763
- priority: R.priority
1764
- };
1765
- })
1766
- };
1767
- }).sort((d, g) => (d.displayName || "").localeCompare(g.displayName)), h = [...c, ...l], E = i.groups.visibles.map(
1768
- ({ groupDisplayName: d, id: g, name: A }) => ({
1769
- displayName: d || A,
1770
- id: g
1771
- })
1772
- ), p = i.users.visibles.map(
1773
- ({ id: d, profile: g, username: A, firstName: m, lastName: R, login: v }) => ({
1774
- displayName: A,
1775
- firstName: m,
1776
- lastName: R,
1777
- login: v,
1778
- profile: g,
1779
- id: d
1780
- })
1781
- );
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 : "";
1782
1401
  return {
1783
- rights: h,
1784
- visibleBookmarks: s,
1785
- visibleGroups: E,
1786
- 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
1787
1411
  };
1788
1412
  }
1789
- async saveRights(e, t, s) {
1790
- const r = await this.getShareMapping(e), i = {
1791
- bookmarks: {},
1792
- groups: {},
1793
- users: {}
1794
- };
1795
- for (const c of s) {
1796
- const l = c.actions.map((E) => r[E.id]).reduce((E, p) => Array.isArray(p) ? [...E, ...p] : E, []), h = [...new Set(l)];
1797
- h.length > 0 && (c.type === "user" ? i.users[c.id] = h : c.type === "group" ? i.groups[c.id] = h : i.bookmarks[c.id] = h);
1798
- }
1799
- const o = `/${e}/share/resource/${t}`;
1800
- 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");
1801
1419
  }
1802
- async getActionsForApp(e) {
1803
- const t = await this.cache.httpGetJson(
1804
- "/infra/public/json/sharing-rights.json"
1805
- ), s = await this.getShareMapping(e);
1806
- return Object.keys(t).map((i) => {
1807
- const o = t[i];
1808
- return {
1809
- displayName: i,
1810
- id: i,
1811
- priority: o.priority,
1812
- requires: o.requires
1813
- };
1814
- }).filter((i) => {
1815
- var o;
1816
- return ((o = s[i.id]) == null ? void 0 : o.length) > 0;
1817
- }).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
+ });
1818
1436
  }
1819
1437
  }
1820
- const defaultMappers = {
1821
- csv: function({ type: n, extension: e }) {
1822
- return MimeTypeUtils.INSTANCE.isCsvLike(n, e);
1823
- },
1824
- doc: function({ type: n, extension: e }) {
1825
- return MimeTypeUtils.INSTANCE.isWordLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("wordprocessing") !== -1;
1826
- },
1827
- xls: function({ type: n, extension: e }) {
1828
- return MimeTypeUtils.INSTANCE.isExcelLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("spreadsheet") !== -1 || n.indexOf("ms-excel") !== -1;
1829
- },
1830
- img: function({ type: n }) {
1831
- return n.indexOf("image") !== -1;
1832
- },
1833
- pdf: function({ type: n }) {
1834
- return n.indexOf("pdf") !== -1 || n === "application/x-download";
1835
- },
1836
- ppt: function({ type: n, extension: e }) {
1837
- return MimeTypeUtils.INSTANCE.isPowerpointLike(n, e) ? !0 : n.indexOf("document") !== -1 && n.indexOf("presentation") !== -1 || n.indexOf("powerpoint") !== -1;
1838
- },
1839
- txt: function({ type: n, extension: e }) {
1840
- return MimeTypeUtils.INSTANCE.isTxtLike(n, e);
1841
- },
1842
- md: function({ type: n, extension: e }) {
1843
- return MimeTypeUtils.INSTANCE.isMdLike(n, e);
1844
- },
1845
- video: function({ type: n }) {
1846
- return n.indexOf("video") !== -1;
1847
- },
1848
- audio: function({ type: n }) {
1849
- return n.indexOf("audio") !== -1;
1850
- },
1851
- zip: function({ type: n }) {
1852
- 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");
1853
1443
  }
1854
- }, b = class b {
1855
- /* Similar role notion as in infra-front > workspace > Model.ts */
1856
- static getRole(e) {
1857
- var t, s;
1858
- return b.role(
1859
- (t = e.metadata) == null ? void 0 : t["content-type"],
1860
- !1,
1861
- (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
+ })
1862
1488
  );
1863
1489
  }
1864
- /* Similar role notion as in infra-front > workspace > Model.ts */
1865
- static role(e, t = !1, s) {
1866
- if (s && (s = s.trim()), !e) return "unknown";
1867
- this.roleMappers || console.warn("[DocumentHelper.role] should not have empty roles", this);
1868
- const r = { type: e, previewRole: t, extension: s };
1869
- for (const i of this.roleMappers) {
1870
- const o = i(r);
1871
- if (o)
1872
- return o;
1873
- }
1874
- return "unknown";
1490
+ }
1491
+ class CommunityBehaviour extends AbstractBehaviourService {
1492
+ constructor() {
1493
+ super(...arguments);
1494
+ a(this, "APP", "community");
1495
+ a(this, "RESOURCE", "community");
1875
1496
  }
1876
- };
1877
- // FIXME add edumedia support
1878
- u(b, "roleMappers", [
1879
- (e) => Object.keys(defaultMappers).find((s) => defaultMappers[s](e))
1880
- ]);
1881
- let DocumentHelper = b;
1882
- class WorkspaceService {
1883
- constructor(e) {
1884
- 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
+ });
1885
1514
  }
1886
- get http() {
1887
- 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");
1888
1521
  }
1889
- extractMetadata(e) {
1890
- const t = e.name || "", s = t.split("."), r = e.type || "application/octet-stream", i = s.length > 1 ? s[s.length - 1] : "", o = {
1891
- "content-type": r,
1892
- filename: t,
1893
- size: e.size,
1894
- extension: i,
1895
- role: DocumentHelper.role(r, !1, i)
1896
- }, a = t.replace("." + o.extension, ""), c = o.extension ? a + "." + o.extension : a;
1897
- 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
+ });
1898
1539
  }
1899
- async saveFile(e, t) {
1900
- const { fullname: s, metadata: r } = this.extractMetadata(e), i = new FormData();
1901
- i.append("file", e, s);
1902
- const o = [];
1903
- ((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}`);
1904
- const a = await this.http.postFile(
1905
- `/workspace/document?${o.join("&")}`,
1906
- i
1907
- );
1908
- if (this.http.isResponseError())
1909
- throw this.http.latestResponse.statusText;
1910
- 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
+ })));
1911
1560
  }
1912
- async updateFile(e, t, s) {
1913
- const { fullname: r, metadata: i } = this.extractMetadata(t), o = new FormData();
1914
- o.append("file", t, r);
1915
- const a = [];
1916
- 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}`);
1917
- const c = await this.http.putFile(
1918
- `/workspace/document/${e}?${a.join("&")}`,
1919
- 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
+ })
1920
1580
  );
1921
- if (this.http.isResponseError())
1922
- throw this.http.latestResponse.statusText;
1923
- return c;
1924
1581
  }
1925
- async deleteFile(e) {
1926
- const t = e.map((s) => s._id);
1927
- if (t.length == 0)
1928
- Promise.resolve(null);
1929
- else if (await this.http.deleteJson("/workspace/documents", {
1930
- ids: t
1931
- }), this.http.isResponseError())
1932
- 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");
1933
1588
  }
1934
- async acceptDocuments(e) {
1935
- const t = await this.context.session().getUser();
1936
- 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
+ }));
1937
1600
  }
1938
- async searchDocuments(e) {
1939
- const t = e.filter !== "external" || e.parentId ? await this.http.get("/workspace/documents", {
1940
- queryParams: { ...e, _: (/* @__PURE__ */ new Date()).getTime() }
1941
- }) : [], s = await this.acceptDocuments(e);
1942
- 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");
1943
1607
  }
1944
- async listDocuments(e, t) {
1945
- 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
+ }));
1946
1622
  }
1947
- /**
1948
- * Duplicate and transfers documents if needed to a different folder with the specified application and visibility.
1949
- * @param documents - The array of documents to transfer.
1950
- * @param application - The application to associate with the transferred documents.
1951
- * @param visibility - The visibility of the transferred documents. Defaults to "protected".
1952
- * @returns A Promise that resolves to an array of transferred WorkspaceElements.
1953
- */
1954
- async transferDocuments(e, t, s = "protected") {
1955
- const r = [];
1956
- if (e.forEach((i) => {
1957
- (s === "public" && !i.public || !i.public && !i.protected) && r.push(i);
1958
- }), r.length > 0) {
1959
- const i = await this.http.post(
1960
- "/workspace/documents/transfer",
1961
- {
1962
- application: t,
1963
- visibility: s,
1964
- ids: r.map((o) => o._id)
1965
- }
1966
- );
1967
- if (this.http.isResponseError())
1968
- throw this.http.latestResponse.statusText;
1969
- return r.forEach((o, a) => {
1970
- const c = e.findIndex(
1971
- (l) => l._id === o._id
1972
- );
1973
- 0 <= c && c < e.length && (e[c] = i[a]);
1974
- }), e.filter((o) => !!o);
1975
- }
1976
- return e;
1623
+ }
1624
+ class MindmapBehaviour extends AbstractBehaviourService {
1625
+ constructor() {
1626
+ super(...arguments);
1627
+ a(this, "APP", "mindmap");
1628
+ a(this, "RESOURCE", "mindmap");
1977
1629
  }
1978
- /**
1979
- * Get the URL of the thumbnail of a workspace element (or its URL),
1980
- * or `null` if none exists or can be created.
1981
- */
1982
- getThumbnailUrl(e, t = 0, s = 0) {
1983
- var i, o;
1984
- const r = t > 0 || s > 0 ? `${t}x${s}` : "120x120";
1985
- if (typeof e == "string")
1986
- return e.includes("data:image") || e.includes("thumbnail") ? e : `${e}${e.includes("?") ? "&" : "?"}thumbnail=${r}`;
1987
- {
1988
- const a = `/workspace/${e.public ? "pub/" : ""}document/${e._id}?thumbnail=`, c = e.thumbnails;
1989
- if ((o = (i = e.metadata) == null ? void 0 : i["content-type"]) != null && o.includes("video")) {
1990
- const l = c && Object.keys(c).length > 0 ? Object.keys(c)[0] : null;
1991
- return l ? a + l : null;
1992
- } else
1993
- return a + r;
1994
- }
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
+ );
1995
1643
  }
1996
1644
  }
1997
- let ATTag;
1998
- class AnalyticsService {
1999
- constructor(n) {
2000
- this.context = n;
2001
- }
2002
- get conf() {
2003
- return this.context.conf();
1645
+ class PagesBehaviour extends AbstractBehaviourService {
1646
+ constructor() {
1647
+ super(...arguments);
1648
+ a(this, "APP", "pages");
1649
+ a(this, "RESOURCE", "pages");
2004
1650
  }
2005
- get http() {
2006
- 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;
2007
1682
  }
2008
- get session() {
2009
- 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");
2010
1689
  }
2011
- /**
2012
- * Xiti tracker for page loading.
2013
- * @param locationPath
2014
- * @param app
2015
- */
2016
- async trackPageLoad(n, e) {
2017
- const [t] = await Promise.all([
2018
- // get Xiti configuration
2019
- this.getXitiConfig(e.name.toLowerCase()),
2020
- // load Xiti javascript file
2021
- this.loadXitiScript()
2022
- ]);
2023
- if (!t || !ATInternet) return;
2024
- let s = t.LIBELLE_SERVICE.default || null;
2025
- for (const r in t.LIBELLE_SERVICE)
2026
- if (r !== "default" && n.indexOf(r) >= 0) {
2027
- s = t.LIBELLE_SERVICE[r];
2028
- break;
2029
- }
2030
- ATTag = new ATInternet.Tracker.Tag({ site: t.STRUCT_ID }), ATTag.setProps(
2031
- {
2032
- SERVICE: s,
2033
- TYPE: t.TYPE,
2034
- OUTIL: t.OUTIL,
2035
- UAI: t.STRUCT_UAI,
2036
- PROJET: t.PROJET,
2037
- EXPLOITANT: t.EXPLOITANT,
2038
- PLATEFORME: t.PLATFORME,
2039
- PROFIL: t.PROFILE
2040
- },
2041
- !0
2042
- ), ATTag.identifiedVisitor.set({
2043
- id: t.ID_PERSO,
2044
- category: t.PROFILE
2045
- }), ATTag.page.set({
2046
- name: (e == null ? void 0 : e.prefix) === "userbook" ? "directory" : e == null ? void 0 : e.prefix,
2047
- chapter1: "",
2048
- chapter2: "",
2049
- chapter3: "",
2050
- level2: t.STRUCT_UAI
2051
- }), 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
+ });
2052
1704
  }
2053
- async getXitiConfig(n) {
2054
- const [e, t] = await Promise.all([
2055
- this.http.get("/analyticsConf"),
2056
- //FIXME change servers config to only keep the "all-in-one" query to /analyticsConf.
2057
- this.http.get("/xiti/config")
2058
- ]);
2059
- if (!(e != null && e.type))
2060
- throw ERROR_CODE.MALFORMED_DATA;
2061
- 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");
2062
1711
  }
2063
- async loadXitiScript() {
2064
- if (typeof ATInternet > "u") {
2065
- const scriptPath = "/xiti/public/js/lib/smarttag_ENT.js", response = await this.http.get(scriptPath, {
2066
- 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
2067
1726
  });
2068
- if (this.http.latestResponse.status != 200)
2069
- throw "Error while loading XiTi script";
2070
- eval(response);
2071
- }
1727
+ });
2072
1728
  }
2073
- async getXitiTrackingParams(n, e) {
2074
- if (!n.structureMap || !e) return;
2075
- const t = await this.session.getUser(), s = await this.session.getUserProfile();
2076
- let r;
2077
- if (!(t != null && t.structures)) return;
2078
- for (const l of t.structures) {
2079
- const h = n.structureMap[l];
2080
- if (h && h.collectiviteId && h.UAI) {
2081
- r = h;
2082
- 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);
2083
1757
  }
2084
- }
2085
- if (!r || !r.active) return;
2086
- const i = await this.conf.getPublicConf(e);
2087
- if (!i) return;
2088
- const o = i.xiti;
2089
- if (!o || !o.LIBELLE_SERVICE || !r.UAI) return;
2090
- function a(l) {
2091
- let h = "";
2092
- for (let E = 0; E < l.length; E++)
2093
- h += l.charCodeAt(E);
2094
- return h;
2095
- }
2096
- const c = {
2097
- Student: "ELEVE",
2098
- Teacher: "ENSEIGNANT",
2099
- Relative: "PARENT",
2100
- Personnel: "ADMIN_VIE_SCOL_TECH",
2101
- Guest: "AUTRE"
2102
- };
2103
- return {
2104
- LIBELLE_SERVICE: o.LIBELLE_SERVICE,
2105
- // Which property of LIBELLE_SERVICE to use depends on the frontend.
2106
- TYPE: o.OUTIL ? "TIERS" : "NATIF",
2107
- OUTIL: o.OUTIL ? o.OUTIL : "",
2108
- STRUCT_ID: r.collectiviteId,
2109
- STRUCT_UAI: r.UAI,
2110
- PROJET: r.projetId ? r.projetId : n.ID_PROJET,
2111
- EXPLOITANT: n.ID_EXPLOITANT,
2112
- PLATFORME: r.plateformeId ? r.plateformeId : n.ID_PLATEFORME,
2113
- ID_PERSO: a(t.userId),
2114
- PROFILE: s && s.length > 0 ? c[s[0]] ?? "" : ""
2115
- };
1758
+ });
2116
1759
  }
2117
1760
  }
2118
- const w = class w {
2119
- // in minutes. Applies to recorded videos.
2120
- constructor(e) {
2121
- this.context = e;
1761
+ class WikiBehaviour extends AbstractBehaviourService {
1762
+ constructor() {
1763
+ super(...arguments);
1764
+ a(this, "APP", "wiki");
1765
+ a(this, "RESOURCE", "wiki");
2122
1766
  }
2123
- get http() {
2124
- 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();
2125
1783
  }
2126
- get conf() {
2127
- 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");
2128
1790
  }
2129
- /**
2130
- * Returns the video app public conf (maxWeight, maxDuration and accepted extensions)
2131
- * @returns the Video app public conf
2132
- */
2133
- async getVideoConf() {
2134
- var t;
2135
- const e = await this.conf.getPublicConf(
2136
- APP$2.VIDEO
2137
- );
2138
- return {
2139
- maxWeight: (e == null ? void 0 : e["max-videosize-mbytes"]) ?? w.MAX_WEIGHT,
2140
- maxDuration: (e == null ? void 0 : e["max-videoduration-minutes"]) ?? w.MAX_DURATION,
2141
- acceptVideoUploadExtensions: ((t = e == null ? void 0 : e["accept-videoupload-extensions"]) == null ? void 0 : t.map(
2142
- (s) => s.toUpperCase()
2143
- )) ?? []
2144
- };
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
+ });
2145
1814
  }
2146
- /**
2147
- * Starts the encoding process and check when video is fully processed.
2148
- * @param params cf VideoUploadParams
2149
- * @returns a VideoCheckResponse
2150
- */
2151
- async upload({
2152
- data: e,
2153
- appCode: t,
2154
- captation: s,
2155
- duration: r
2156
- }) {
2157
- if (!e.file)
2158
- throw new Error("Invalid video file.");
2159
- if (!e.filename)
2160
- throw new Error("Invalid video filename");
2161
- const i = `${e.browser.name} ${e.browser.version}`, o = new FormData();
2162
- 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);
2163
- let a = `/video/encode?captation=${s}`;
2164
- r && (a += `&duration=${r}`);
2165
- const c = await this.http.post(
2166
- a,
2167
- o,
2168
- { headers: { "Content-Type": "multipart/form-data" } }
2169
- );
2170
- if (c.state == "running") {
2171
- let l = 0, h = 1;
2172
- do {
2173
- const E = h + l;
2174
- await new Promise(
2175
- (d) => setTimeout(d, E * 1e3)
2176
- ), l = h, h = Math.min(8, E);
2177
- const p = await this.http.get(
2178
- `/video/status/${c.processid}`
2179
- );
2180
- if (p.state == "succeed")
2181
- return p.videoworkspaceid && p.videosize && this.context.data().trackVideoSave(
2182
- p.videoworkspaceid,
2183
- Math.round(r),
2184
- p.videosize,
2185
- s,
2186
- e.url,
2187
- i,
2188
- e.device
2189
- ), p;
2190
- if (p.state == "error")
2191
- break;
2192
- } 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
+ }
2193
1832
  }
2194
- 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;
2195
1899
  }
2196
1900
  };
2197
- u(w, "MAX_WEIGHT", 50), // in Mbytes. Applies to uploaded videos.
2198
- u(w, "MAX_DURATION", 3);
2199
- let VideoService = w;
2200
- 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 {
2201
1908
  constructor(e) {
2202
1909
  this.context = e;
2203
1910
  }
2204
- get http() {
2205
- 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;
2206
1937
  }
2207
1938
  /**
2208
- * Returns the default list of video embedder
2209
- * @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
2210
1946
  */
2211
- async getDefault() {
2212
- return this.http.get("/infra/embed/default");
1947
+ parseResourceRights(e) {
1948
+ return e.map((s) => this.parseResourceRight(s)).filter((s) => s !== void 0);
2213
1949
  }
2214
1950
  /**
2215
- * Returns the custom list of video embedder
2216
- * @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
2217
1956
  */
2218
- async getCustom() {
2219
- 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;
2220
1968
  }
2221
1969
  /**
2222
- * The provider matching with the URL
2223
- * @param {Embedder[]} embedderList - The list of video providers to test with
2224
- * @param {String} url - The URL for the video
2225
- * @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
2226
1974
  */
2227
- getProviderFromUrl(e, t) {
2228
- for (const s of e)
2229
- if (this.isUrlFromProvider(t, s))
2230
- return s;
2231
- }
2232
- urlIsFromPattern(e, t) {
2233
- const s = new RegExp("[^{}]+(?=(?:[^{}]*{[^}]*})*[^}]*$)", "g"), r = new RegExp("{[^}]*}", "g");
2234
- let i = !0;
2235
- const o = t.match(s) || [], a = [];
2236
- return (t.match(r) || []).forEach((l, h) => {
2237
- l.includes("ignore") || a.push(o[h]);
2238
- }), a.forEach((l) => {
2239
- if (!e.includes(l)) {
2240
- i = !1;
2241
- return;
2242
- }
2243
- }), 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
+ }
2244
1986
  }
2245
1987
  /**
2246
- * Check if a given URL correspond to one of the URL pattern of the provider
2247
- * @param {String} url - The URL for the video
2248
- * @param {Embedder} embedder - The video provider to test with
2249
- * @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
2250
1992
  */
2251
- isUrlFromProvider(e, t) {
2252
- typeof t.url == "string" && (t.url = [t.url]);
2253
- for (const s of t.url)
2254
- if (this.urlIsFromPattern(e, s))
1993
+ async sessionHasAtLeastOneResourceRight(e, t) {
1994
+ for (const s of e)
1995
+ if (await this.sessionHasResourceRight(s, t))
2255
1996
  return !0;
2256
1997
  return !1;
2257
1998
  }
2258
1999
  /**
2259
- * Get embed code to display the video for an URL and a provider
2260
- * @param {Embedder} embedder - The video provider for the URL
2261
- * @param {String} url - The URL for the video
2262
- * @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
2263
2004
  */
2264
- getEmbedCodeForProvider(e, t) {
2265
- for (const s of e.url)
2266
- if (this.urlIsFromPattern(t, s)) {
2267
- const r = new RegExp("{[a-zA-Z0-9_.]+}", "g"), i = s.match(r) || [];
2268
- let o = e.embed;
2269
- for (const a of i) {
2270
- let c = s.split(a)[0];
2271
- const l = c.split("}");
2272
- l.length > 1 && (c = l[l.length - 1]);
2273
- let h = t.split(c)[1];
2274
- if (!h)
2275
- continue;
2276
- const E = s.split(a)[1].split("{")[0];
2277
- E && (h = h.split(E)[0]);
2278
- const p = new RegExp("\\" + a.replace(/}/, "\\}"), "g");
2279
- o = o.replace(p, h);
2280
- }
2281
- return o;
2282
- }
2283
- return "";
2284
- }
2285
- }
2286
- class AbstractBehaviourService {
2287
- //
2288
- // IMPLEMENTATION
2289
- //
2290
- constructor(e) {
2291
- //-----------------
2292
- //--- Utilities ---
2293
- //-----------------
2294
- u(this, "_cache");
2295
- 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;
2296
2010
  }
2297
- getApplication() {
2298
- 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;
2299
2026
  }
2300
- getResourceType() {
2301
- return this.RESOURCE;
2027
+ hasWorkflowRight(e, t) {
2028
+ return t.findIndex((s) => s === e) !== -1;
2302
2029
  }
2303
- httpGet(e, t) {
2304
- 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
+ }
2305
2046
  }
2306
- /* Utility to map data between linker model and search model. */
2307
- dataToResource({
2308
- modified: e,
2309
- ...t
2310
- }) {
2311
- const s = typeof e == "string" ? e : e != null && e.$date ? "" + e.$date : "";
2312
- return {
2313
- application: this.RESOURCE,
2314
- name: t.title,
2315
- creatorId: t.owner,
2316
- creatorName: t.ownerName,
2317
- thumbnail: t.icon,
2318
- assetId: t._id,
2319
- modifiedAt: s,
2320
- shared: t.shared,
2321
- path: t.path
2322
- };
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;
2323
2068
  }
2324
2069
  }
2325
- class ActualitesBehaviour extends AbstractBehaviourService {
2326
- constructor() {
2327
- super(...arguments);
2328
- u(this, "APP", "actualites");
2329
- u(this, "RESOURCE", "actualites");
2070
+ class SessionService {
2071
+ constructor(e) {
2072
+ this.context = e;
2330
2073
  }
2331
- async loadResources() {
2332
- return (await this.httpGet(
2333
- "/actualites/linker/infos"
2334
- )).map((s) => {
2335
- var r;
2336
- return s.thread_icon ? r = s.thread_icon + "?thumbnail=48x48" : r = "/img/icons/glyphicons_036_file.png", this.dataToResource({
2337
- title: s.title + " [" + s.thread_title + "]",
2338
- ownerName: s.username,
2339
- owner: s.owner,
2340
- icon: r,
2341
- path: "/actualites#/view/thread/" + s.thread_id + "/info/" + s._id,
2342
- _id: `${s.thread_id}#${s._id}`,
2343
- shared: !!(s.shared && s.shared.length >= 0),
2344
- modified: s.modified
2345
- });
2346
- });
2074
+ get http() {
2075
+ return this.context.http();
2347
2076
  }
2348
- }
2349
- class BlogBehaviour extends AbstractBehaviourService {
2350
- constructor() {
2351
- super(...arguments);
2352
- u(this, "APP", "blog");
2353
- u(this, "RESOURCE", "blog");
2077
+ get cache() {
2078
+ return this.context.cache();
2354
2079
  }
2355
- loadResources() {
2356
- return new Promise(async (t, s) => {
2357
- try {
2358
- const r = await this.httpGet("/blog/linker"), i = [];
2359
- r.forEach((o) => {
2360
- o.thumbnail ? o.thumbnail = o.thumbnail + "?thumbnail=48x48" : o.thumbnail = "/img/illustrations/blog.svg";
2361
- const a = o.fetchPosts.map((c) => this.dataToResource({
2362
- owner: o.author.userId,
2363
- ownerName: o.author.username,
2364
- title: c.title + " [" + o.title + "]",
2365
- _id: `${o._id}#${c._id}`,
2366
- icon: o.thumbnail,
2367
- path: `/blog/id/${o._id}/post/${c._id}`,
2368
- shared: !!(o.shared && o.shared.length >= 0),
2369
- modified: o.modified
2370
- }));
2371
- i.push(...a);
2372
- }), t(i);
2373
- } catch (r) {
2374
- s(r);
2375
- }
2376
- });
2080
+ get conf() {
2081
+ return this.context.conf();
2377
2082
  }
2378
- }
2379
- class CollaborativewallBehaviour extends AbstractBehaviourService {
2380
- constructor() {
2381
- super(...arguments);
2382
- u(this, "APP", "collaborativewall");
2383
- u(this, "RESOURCE", "collaborativewall");
2083
+ /**
2084
+ * Callback to call when user logout
2085
+ */
2086
+ onLogout() {
2087
+ this.cache.clearCache();
2384
2088
  }
2385
- async loadResources() {
2386
- return (await this.httpGet(
2387
- "/collaborativewall/list/all"
2388
- )).map(
2389
- (s) => this.dataToResource({
2390
- title: s.name,
2391
- ownerName: s.owner.displayName,
2392
- owner: s.owner.userId,
2393
- icon: s.icon ? s.icon : "/img/illustrations/collaborative-wall-default.png",
2394
- path: "/collaborativewall#/view/" + s._id,
2395
- _id: s._id,
2396
- shared: !!(s.shared && s.shared.length >= 0),
2397
- modified: s.modified
2398
- })
2399
- );
2089
+ /**
2090
+ * Callback to call when session change
2091
+ */
2092
+ onRefreshSession() {
2093
+ this.cache.clearCache();
2400
2094
  }
2401
- }
2402
- class CommunityBehaviour extends AbstractBehaviourService {
2403
- constructor() {
2404
- super(...arguments);
2405
- u(this, "APP", "community");
2406
- 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
+ };
2407
2117
  }
2408
- async loadResources() {
2409
- return (await this.httpGet(
2410
- "/community/listallpages"
2411
- )).map((s) => {
2412
- var r;
2413
- return typeof s.thumbnail > "u" || s.thumbnail === "" ? r = "/img/icons/glyphicons_036_file.png" : r = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
2414
- title: s.name,
2415
- icon: r,
2416
- path: "/community#/view/" + s.id,
2417
- _id: s.id,
2418
- owner: "",
2419
- ownerName: "",
2420
- shared: !!(s.shared && s.shared.length >= 0),
2421
- modified: s.name
2422
- // FIXME date ?
2423
- });
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
+ }
2424
2127
  });
2425
2128
  }
2426
- }
2427
- class ExercizerBehaviour extends AbstractBehaviourService {
2428
- constructor() {
2429
- super(...arguments);
2430
- u(this, "APP", "exercizer");
2431
- u(this, "RESOURCE", "exercizer");
2432
- }
2433
- async loadResources() {
2434
- return (await this.httpGet(
2435
- "/exercizer/subjects-scheduled"
2436
- )).map((s) => {
2437
- const r = s.picture ? s.picture + "?thumbnail=48x48" : "/img/illustrations/exercizer.svg";
2438
- let i, o = !1, a = JSON.parse(s.scheduled_at);
2439
- 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({
2440
- title: s.title,
2441
- owner: s.owner,
2442
- ownerName: i,
2443
- icon: r,
2444
- path: "/exercizer#/linker/" + s.id,
2445
- _id: "" + s.id,
2446
- shared: o,
2447
- modified: s.modified
2448
- });
2129
+ async logout() {
2130
+ const e = await this.conf.getLogoutCallback();
2131
+ return this.http.get("/auth/logout?callback=" + e).finally(() => {
2449
2132
  });
2450
2133
  }
2451
- }
2452
- class FormulaireBehaviour extends AbstractBehaviourService {
2453
- constructor() {
2454
- super(...arguments);
2455
- u(this, "APP", "formulaire");
2456
- 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
+ }
2457
2144
  }
2458
- async loadResources() {
2459
- return (await this.httpGet(
2460
- "/formulaire/forms/linker"
2461
- )).map((s) => (s.picture || (s.picture = "/formulaire/public/img/logo.svg"), this.dataToResource({
2462
- _id: "" + s.id,
2463
- icon: s.picture,
2464
- title: s.title,
2465
- ownerName: s.owner_name,
2466
- owner: s.owner_id,
2467
- path: s.is_public ? `${window.location.origin}/formulaire-public#/form/${s.public_key}` : `${window.location.origin}/formulaire#/form/${s.id}/${s.rgpd ? "rgpd" : "new"}`,
2468
- shared: !!(s.shared && s.shared.length >= 0),
2469
- modified: "" + s.date_modification
2470
- })));
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
+ }
2471
2153
  }
2472
- }
2473
- class ForumBehaviour extends AbstractBehaviourService {
2474
- constructor() {
2475
- super(...arguments);
2476
- u(this, "APP", "forum");
2477
- 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
+ }
2478
2163
  }
2479
- async loadResources() {
2480
- return (await this.httpGet("/forum/categories")).map(
2481
- (s) => this.dataToResource({
2482
- _id: s._id,
2483
- title: s.name,
2484
- icon: s.icon || "/img/illustrations/forum.svg",
2485
- path: "/forum#/view/" + s._id,
2486
- ownerName: s.owner.displayName,
2487
- owner: s.owner.userId,
2488
- shared: !!(s.shared && s.shared.length >= 0),
2489
- modified: s.modified
2490
- })
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"
2491
2172
  );
2173
+ if (!(e.status < 200 || e.status >= 300) && typeof t == "object")
2174
+ return t;
2175
+ throw ERROR_CODE.NOT_LOGGED_IN;
2492
2176
  }
2493
- }
2494
- class HomeworksBehaviour extends AbstractBehaviourService {
2495
- constructor() {
2496
- super(...arguments);
2497
- u(this, "APP", "homeworks");
2498
- 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;
2499
2182
  }
2500
- async loadResources() {
2501
- return (await this.httpGet("/homeworks/list")).filter((t) => t.owner && t.trashed === 0).map((t) => this.dataToResource({
2502
- title: t.title,
2503
- ownerName: t.owner.displayName,
2504
- owner: t.owner.userId,
2505
- icon: t.thumbnail || "/img/illustrations/homeworks.svg",
2506
- path: "/homeworks#/view-homeworks/" + t._id,
2507
- _id: "" + t._id,
2508
- shared: typeof t.shared < "u",
2509
- modified: t.modified
2510
- }));
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
+ }
2511
2197
  }
2512
- }
2513
- class MagnetoBehaviour extends AbstractBehaviourService {
2514
- constructor() {
2515
- super(...arguments);
2516
- u(this, "APP", "magneto");
2517
- 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;
2518
2218
  }
2519
- async loadResources() {
2520
- const { all: t } = await this.httpGet(
2521
- "/magneto/boards/editable"
2522
- );
2523
- return t.map((s) => this.dataToResource({
2524
- _id: s._id,
2525
- title: s.title,
2526
- icon: s.imageUrl,
2527
- owner: s.ownerId,
2528
- ownerName: s.ownerName,
2529
- path: `/magneto#/board/${s._id}/view`,
2530
- shared: !!(s.shared && s.shared.length >= 0),
2531
- modified: "" + s.modificationDate
2532
- }));
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
+ });
2533
2238
  }
2534
2239
  }
2535
- class MindmapBehaviour extends AbstractBehaviourService {
2536
- constructor() {
2537
- super(...arguments);
2538
- u(this, "APP", "mindmap");
2539
- u(this, "RESOURCE", "mindmap");
2540
- }
2541
- async loadResources() {
2542
- return (await this.httpGet("/mindmap/list/all")).map(
2543
- (s) => this.dataToResource({
2544
- title: s.name,
2545
- ownerName: s.owner.displayName,
2546
- owner: s.owner.userId,
2547
- icon: s.thumbnail || "/img/illustrations/mindmap-default.png",
2548
- path: "/mindmap#/view/" + s._id,
2549
- _id: s._id,
2550
- shared: !!(s.shared && s.shared.length >= 0),
2551
- modified: s.modified
2552
- })
2553
- );
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;
2554
2248
  }
2555
2249
  }
2556
- class PagesBehaviour extends AbstractBehaviourService {
2557
- constructor() {
2558
- super(...arguments);
2559
- u(this, "APP", "pages");
2560
- u(this, "RESOURCE", "pages");
2250
+ class ShareService {
2251
+ //
2252
+ // IMPLEMENTATION
2253
+ //
2254
+ constructor(e) {
2255
+ this.context = e;
2561
2256
  }
2562
- async loadResources() {
2563
- const t = await this.httpGet("/pages/list/all"), s = [];
2564
- return t.forEach((r) => {
2565
- var o;
2566
- const i = r.thumbnail ? r.thumbnail + "?thumbnail=48x48" : "/img/illustrations/pages.svg";
2567
- s.push(
2568
- this.dataToResource({
2569
- title: r.title,
2570
- owner: r.owner.userId,
2571
- ownerName: r.owner.displayName,
2572
- icon: i,
2573
- path: "/pages#/website/" + r._id,
2574
- _id: r._id,
2575
- shared: typeof r.shared < "u",
2576
- modified: r.modified
2577
- })
2578
- ), (o = r.pages) == null || o.forEach((a) => {
2579
- s.push(
2580
- this.dataToResource({
2581
- title: a.title,
2582
- owner: r.owner.userId,
2583
- ownerName: r.owner.displayName,
2584
- icon: i,
2585
- path: "/pages#/website/" + r._id + "/" + a.titleLink,
2586
- _id: r._id + "/" + a.titleLink,
2587
- shared: typeof r.shared < "u",
2588
- modified: r.modified
2589
- })
2590
- );
2591
- });
2592
- }), s;
2257
+ get directory() {
2258
+ return this.context.directory();
2593
2259
  }
2594
- }
2595
- class PollBehaviour extends AbstractBehaviourService {
2596
- constructor() {
2597
- super(...arguments);
2598
- u(this, "APP", "poll");
2599
- u(this, "RESOURCE", "poll");
2260
+ get http() {
2261
+ return this.context.http();
2600
2262
  }
2601
- async loadResources() {
2602
- return (await this.httpGet("/poll/list/all")).map((s) => {
2603
- const r = s.icon ? s.icon + "?thumbnail=48x48" : "/img/icons/glyphicons_036_file.png";
2604
- return this.dataToResource({
2605
- title: s.question,
2606
- ownerName: s.owner.displayName,
2607
- icon: r,
2608
- path: "/poll#/view/" + s._id,
2609
- _id: s._id,
2610
- owner: s.owner.userId,
2611
- shared: !!(s.shared && s.shared.length >= 0),
2612
- modified: s.modified
2613
- });
2614
- });
2263
+ get cache() {
2264
+ return this.context.cache();
2615
2265
  }
2616
- }
2617
- class ScrapbookBehaviour extends AbstractBehaviourService {
2618
- constructor() {
2619
- super(...arguments);
2620
- u(this, "APP", "scrapbook");
2621
- 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];
2622
2303
  }
2623
- async loadResources() {
2624
- return (await this.httpGet(
2625
- "/scrapbook/list/all"
2626
- )).map((s) => {
2627
- const r = s.icon || "/img/illustrations/scrapbook.svg";
2628
- return this.dataToResource({
2629
- title: s.name,
2630
- owner: s.owner.userId,
2631
- ownerName: s.owner.displayName,
2632
- icon: r,
2633
- path: "/scrapbook#/view-scrapbook/" + s._id,
2634
- _id: s._id,
2635
- shared: !!(s.shared && s.shared.length >= 0),
2636
- modified: s.modified
2637
- });
2638
- });
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;
2639
2314
  }
2640
- }
2641
- class TimelinegeneratorBehaviour extends AbstractBehaviourService {
2642
- constructor() {
2643
- super(...arguments);
2644
- u(this, "APP", "timelinegenerator");
2645
- 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;
2646
2322
  }
2647
- loadResources() {
2648
- return new Promise(async (t, s) => {
2649
- try {
2650
- const i = (await this.httpGet(
2651
- "/timelinegenerator/timelines"
2652
- )).map((o) => {
2653
- const a = o.icon || "/img/illustrations/timeline-default.png";
2654
- return this.dataToResource({
2655
- title: o.headline,
2656
- ownerName: o.owner.displayName,
2657
- owner: o.owner.userId,
2658
- icon: a,
2659
- path: "/timelinegenerator#/view/" + o._id,
2660
- _id: o._id,
2661
- shared: typeof o.shared < "u",
2662
- modified: o.modified
2663
- });
2664
- });
2665
- t(i);
2666
- } catch (r) {
2667
- s(r);
2668
- }
2669
- });
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
+ };
2670
2395
  }
2671
- }
2672
- class WikiBehaviour extends AbstractBehaviourService {
2673
- constructor() {
2674
- super(...arguments);
2675
- u(this, "APP", "wiki");
2676
- 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);
2677
2408
  }
2678
- async loadResources() {
2679
- return (await this.httpGet(
2680
- "/wiki/listallpages?visible=true"
2681
- )).map((s) => s.pages.map((r) => {
2682
- let i;
2683
- return typeof s.thumbnail > "u" || s.thumbnail === "" ? i = "/img/icons/glyphicons_036_file.png" : i = s.thumbnail + "?thumbnail=48x48", this.dataToResource({
2684
- title: r.title + " [" + s.title + "]",
2685
- ownerName: s.owner.displayName,
2686
- owner: s.owner.userId,
2687
- icon: i,
2688
- path: "/wiki#/view/" + s._id + "/" + r._id,
2689
- _id: `${s._id}#${r._id}`,
2690
- shared: typeof s.shared < "u",
2691
- modified: r.modified
2692
- });
2693
- })).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);
2694
2425
  }
2695
2426
  }
2696
- class WorkspaceBehaviour extends AbstractBehaviourService {
2697
- constructor() {
2698
- super(...arguments);
2699
- u(this, "APP", "workspace");
2700
- u(this, "RESOURCE", "workspace");
2701
- }
2702
- loadResources({ search: t, asset_id: s }) {
2703
- return new Promise(async (r, i) => {
2704
- try {
2705
- let o = "/workspace/documents?filter=all&hierarchical=true";
2706
- s && s.length ? o += `&search=${t}` : t && t.length && (o += `&search=${t}`);
2707
- const c = (await this.httpGet(o)).filter((l) => !l.deleted).map((l) => {
2708
- const h = l.metadata["content-type"] && l.metadata["content-type"].indexOf("image") !== -1 ? `/workspace/document/${l._id}?thumbnail=120x120` : "/img/icons/unknown-large.png";
2709
- return this.dataToResource({
2710
- title: l.name,
2711
- ownerName: l.ownerName,
2712
- owner: l.owner,
2713
- icon: h,
2714
- path: `/workspace/document/${l._id}`,
2715
- _id: l._id,
2716
- shared: !!(l.shared && l.shared.length >= 0),
2717
- modified: l.modified
2718
- });
2719
- });
2720
- r(c);
2721
- } catch (o) {
2722
- i(o);
2723
- }
2724
- });
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;
2725
2436
  }
2726
- }
2727
- const y = class y {
2728
- static async initialize(e, t) {
2729
- const s = e.http();
2730
- if (!this.resourceProducingApps.length) {
2731
- this.resourceProducingApps = [t, "workspace"];
2732
- try {
2733
- const [r, i] = await Promise.all([
2734
- s.get("/resources-applications"),
2735
- e.session().getUser()
2736
- ]);
2737
- i != null && i.apps && (r != null && r.length) && (this.resourceProducingApps = r.filter(
2738
- (o) => i.apps.some((a) => a.address.includes(o))
2739
- ));
2740
- } catch (r) {
2741
- console.warn("Failed to load resource-producing apps:", r);
2742
- }
2743
- }
2744
- 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;
2745
2439
  }
2746
- static async registerBehaviours(e) {
2747
- this.resourceProducingApps.forEach((t) => {
2748
- const s = { application: e, resourceType: t };
2749
- this.registry.register(
2750
- s,
2751
- (r) => this.serviceFor(r, e, t)
2752
- );
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);
2753
2450
  });
2754
2451
  }
2755
- static serviceFor(e, t, s) {
2756
- let r;
2757
- switch (s) {
2758
- case "timelinegenerator":
2759
- r = new TimelinegeneratorBehaviour(e);
2760
- break;
2761
- case "workspace":
2762
- r = new WorkspaceBehaviour(e);
2763
- break;
2764
- case "blog":
2765
- r = new BlogBehaviour(e);
2766
- break;
2767
- case "actualites":
2768
- r = new ActualitesBehaviour(e);
2769
- break;
2770
- case "wiki":
2771
- r = new WikiBehaviour(e);
2772
- break;
2773
- case "pages":
2774
- r = new PagesBehaviour(e);
2775
- break;
2776
- case "poll":
2777
- r = new PollBehaviour(e);
2778
- break;
2779
- case "community":
2780
- r = new CommunityBehaviour(e);
2781
- break;
2782
- case "mindmap":
2783
- r = new MindmapBehaviour(e);
2784
- break;
2785
- case "forum":
2786
- r = new ForumBehaviour(e);
2787
- break;
2788
- case "homeworks":
2789
- r = new HomeworksBehaviour(e);
2790
- break;
2791
- case "scrapbook":
2792
- r = new ScrapbookBehaviour(e);
2793
- break;
2794
- case "collaborativewall":
2795
- r = new CollaborativewallBehaviour(e);
2796
- break;
2797
- case "exercizer":
2798
- r = new ExercizerBehaviour(e);
2799
- break;
2800
- case "formulaire":
2801
- r = new FormulaireBehaviour(e);
2802
- break;
2803
- case "magneto":
2804
- r = new MagnetoBehaviour(e);
2805
- break;
2806
- default:
2807
- 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);
2808
2468
  }
2809
- return r.APP = t, r;
2469
+ return e;
2810
2470
  }
2811
- };
2812
- //
2813
- // STATIC REGISTRY
2814
- //
2815
- u(y, "registry", new ServiceRegistry()), // Expose some useful functions
2816
- u(y, "findBehaviour", y.registry.findService.bind(y.registry)), u(y, "hasBehaviour", y.registry.isRegistered.bind(y.registry)), u(y, "resourceProducingApps", []);
2817
- let SnipletsService = y;
2818
- const SEND_ALL = "*";
2819
- class WebBroker {
2820
- constructor(e) {
2821
- u(this, "subscription");
2822
- 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;
2823
2484
  }
2824
- get http() {
2825
- return this.odeServices.http();
2485
+ mapAxiosResponse(e, t) {
2486
+ return this._latestResponse = e, e.data;
2826
2487
  }
2827
- get events() {
2828
- return this.odeServices.notify().events();
2488
+ get latestResponse() {
2489
+ return this._latestResponse;
2829
2490
  }
2830
- dispatchEvent(e, t) {
2831
- t.findIndex(
2832
- (r) => SEND_ALL === r || e.data["event-type"] === r
2833
- ) >= 0 && this.http.post("/infra/event/web/store", e.data, {
2834
- disableNotifications: !0
2835
- });
2491
+ isResponseError() {
2492
+ return this.latestResponse.status < 200 || this.latestResponse.status >= 300;
2836
2493
  }
2837
- initialize(e) {
2838
- if (e === void 0 || e.send === void 0 || e.send.length > 0) {
2839
- const t = (e == null ? void 0 : e.send) ?? [SEND_ALL];
2840
- this.subscription = this.events.subscribe(
2841
- LAYER_NAME.WEB_DATA,
2842
- (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)
2843
2499
  );
2500
+ return this.mapAxiosResponse(s, t);
2501
+ } catch (s) {
2502
+ throw this.mapAxiosError(s, t);
2844
2503
  }
2845
- return this;
2846
2504
  }
2847
- destroy() {
2848
- 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
+ }
2849
2516
  }
2850
- }
2851
- class DataService {
2852
- constructor(e) {
2853
- u(this, "_webBroker");
2854
- u(this, "app");
2855
- u(this, "user");
2856
- u(this, "profile");
2857
- 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
+ }
2858
2531
  }
2859
- get conf() {
2860
- 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
+ }
2861
2545
  }
2862
- get notify() {
2863
- 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
+ }
2864
2557
  }
2865
- // This method is called once, by the service container.
2866
- async initialize() {
2558
+ async putFile(e, t, s) {
2867
2559
  try {
2868
- const { app: e } = await this.notify.onAppConfReady().promise;
2869
- this.app = e, this.user = await this.odeServices.session().getUser(), this.profile = await this.odeServices.session().getUserProfile();
2870
- const { ["data-service"]: t } = await this.conf.getPublicConf(e);
2871
- this._webBroker = new WebBroker(this.odeServices).initialize(t == null ? void 0 : t.web);
2872
- } catch {
2873
- 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);
2874
2571
  }
2875
2572
  }
2876
- //FIXME When to call that ??
2877
- predestroy() {
2878
- 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
+ }
2879
2582
  }
2880
- /** Send a web-user-level event to the data pipeline. */
2881
- trackWebEvent(e) {
2882
- this.notify.events().publish(LAYER_NAME.WEB_DATA, {
2883
- name: EVENT_NAME.DATA_TRACKED,
2884
- data: e
2885
- });
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
+ }
2886
2593
  }
2887
- addUserInfos(e) {
2888
- return this.user && (e.userId = this.user.userId, e.structure = this.user.structureNames[0]), this.profile && (e.profil = this.profile[0]), e;
2889
- }
2890
- trackVideoSave(e, t, s, r, i, o, a) {
2891
- const c = this.addUserInfos({
2892
- "event-type": "VIDEO_SAVE",
2893
- module: "video",
2894
- video_id: e,
2895
- browser: o,
2896
- duration: Math.round(t),
2897
- weight: s,
2898
- source: r ? "CAPTURED" : "UPLOADED",
2899
- url: i
2900
- });
2901
- this.app && (c["override-module"] = this.app), a && (c.device_type = a), this.trackWebEvent(c);
2902
- }
2903
- trackVideoRead(e, t, s, r, i) {
2904
- const o = this.addUserInfos({
2905
- "event-type": "VIDEO_READ",
2906
- module: "video",
2907
- video_id: e,
2908
- browser: r,
2909
- source: t ? "CAPTURED" : "UPLOADED",
2910
- url: s
2911
- });
2912
- 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
+ }
2913
2603
  }
2914
- trackSpeechAndText(e) {
2915
- const t = this.addUserInfos({
2916
- "event-type": "SPEECH_AND_TEXT",
2917
- 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;
2918
2615
  });
2919
- this.app && (t.module = this.app), this.trackWebEvent(t);
2920
2616
  }
2921
- trackAccessLibraryFromExplorer() {
2922
- const e = this.addUserInfos({
2923
- "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;
2924
2620
  });
2925
- this.app && (e.module = this.app), this.trackWebEvent(e);
2926
2621
  }
2927
- }
2928
- class ReactionsService {
2929
- constructor(e, t, s) {
2930
- 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;
2931
2627
  }
2932
2628
  get http() {
2933
2629
  return this.context.http();
2934
2630
  }
2935
- async loadAvailableReactions() {
2936
- try {
2937
- const { "reaction-types": e } = await this.context.conf().getPublicConf("audience");
2938
- return Array.isArray(e) ? e : void 0;
2939
- } catch {
2940
- console.error("Audience configuration not found");
2941
- return;
2942
- }
2631
+ get conf() {
2632
+ return this.context.conf();
2943
2633
  }
2944
- async loadReactionSummaries(e) {
2945
- const t = await this.http.get(
2946
- `/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
2947
2642
  );
2948
- 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
+ };
2949
2650
  }
2950
- async loadReactionDetails(e, t, s) {
2951
- const r = await this.http.get(
2952
- `/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" } }
2953
2674
  );
2954
- 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.");
2955
2692
  }
2956
- async deleteReaction(e) {
2957
- await this.http.delete(
2958
- `/audience/reactions/${this.module}/${this.resourceType}/${e}`
2959
- );
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;
2960
2730
  }
2961
- async updateReaction(e, t) {
2962
- await this.http.putJson(
2963
- `/audience/reactions/${this.module}/${this.resourceType}`,
2964
- {
2965
- resourceId: e,
2966
- reactionType: t
2967
- }
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
2968
2739
  );
2969
2740
  }
2970
- async createReaction(e, t) {
2971
- await this.http.postJson(
2972
- `/audience/reactions/${this.module}/${this.resourceType}`,
2973
- {
2974
- resourceId: e,
2975
- reactionType: t
2976
- }
2977
- );
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";
2978
2752
  }
2979
- }
2980
- class ViewsService {
2981
- constructor(e, t, s) {
2982
- 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;
2983
2762
  }
2984
2763
  get http() {
2985
2764
  return this.context.http();
2986
2765
  }
2987
- async getCounters(e) {
2988
- const t = await this.http.get(
2989
- `/audience/views/count/${this.module}/${this.resourceType}?resourceIds=${e.join(",")}`
2990
- );
2991
- 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 };
2992
2775
  }
2993
- async getDetails(e) {
2994
- const t = await this.http.get(
2995
- `/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
2996
2784
  );
2997
- return this.http.isResponseError() ? void 0 : t;
2785
+ if (this.http.isResponseError())
2786
+ throw this.http.latestResponse.statusText;
2787
+ return u;
2998
2788
  }
2999
- trigger(e) {
3000
- return this.http.post(
3001
- `/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
3002
2797
  );
2798
+ if (this.http.isResponseError())
2799
+ throw this.http.latestResponse.statusText;
2800
+ return c;
3003
2801
  }
3004
- }
3005
- class AudienceService {
3006
- constructor(e, t, s) {
3007
- 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;
3008
2810
  }
3009
- get views() {
3010
- 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;
3011
2814
  }
3012
- get reactions() {
3013
- 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
+ }
3014
2872
  }
3015
2873
  }
3016
2874
  class OdeServices {
3017
2875
  constructor() {
3018
- u(this, "_analytics");
3019
- u(this, "_cache");
3020
- u(this, "_conf");
3021
- u(this, "_data");
3022
- u(this, "_directory");
3023
- u(this, "_http");
3024
- u(this, "_idiom");
3025
- u(this, "_notify");
3026
- u(this, "_rights");
3027
- u(this, "_session");
3028
- u(this, "_share");
3029
- u(this, "_video");
3030
- u(this, "_workspace");
3031
- u(this, "_embedder");
3032
- 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);
3033
2891
  }
3034
2892
  initialize() {
3035
- return this._data.initialize(), this;
2893
+ return this;
3036
2894
  }
3037
2895
  analytics() {
3038
2896
  return this._analytics;
@@ -3046,9 +2904,9 @@ class OdeServices {
3046
2904
  conf() {
3047
2905
  return this._conf;
3048
2906
  }
3049
- data() {
2907
+ /* data() {
3050
2908
  return this._data;
3051
- }
2909
+ } */
3052
2910
  directory() {
3053
2911
  return this._directory;
3054
2912
  }
@@ -3058,9 +2916,9 @@ class OdeServices {
3058
2916
  idiom() {
3059
2917
  return this._idiom;
3060
2918
  }
3061
- notify() {
2919
+ /* notify() {
3062
2920
  return this._notify;
3063
- }
2921
+ } */
3064
2922
  resource(e, t) {
3065
2923
  return t ? ResourceService.findService({ application: e, resourceType: t }, this) : ResourceService.findMainService({ application: e }, this);
3066
2924
  }
@@ -3199,11 +3057,8 @@ export {
3199
3057
  BOOLEAN_FILTER,
3200
3058
  DocumentHelper,
3201
3059
  ERROR_CODE,
3202
- EVENT_NAME,
3203
3060
  FOLDER,
3204
- LAYER_NAME,
3205
3061
  LastInfosWidget,
3206
- NotifyFrameworkFactory,
3207
3062
  ReactionTypes,
3208
3063
  ResourceService,
3209
3064
  SORT_BY,