@livepreso/api 6.44.0 → 6.45.0

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.
Files changed (127) hide show
  1. package/.eslintrc.js +3 -0
  2. package/.rush/temp/256021b5963b4c0221d3dec247b697b9691a9b2c.log +10 -0
  3. package/.rush/temp/2a322f00f12cf9d1e64afe81275cc78d01c49050.log +10 -0
  4. package/.rush/temp/30061f1865447dcbb3f20a305061205f3dbe6091.log +10 -0
  5. package/.rush/temp/45522aea0dee8cb2be1a53248ba45bd235743b43.log +10 -0
  6. package/.rush/temp/58fcbb7f15a76326d40e0839ab179755da82a891.log +10 -0
  7. package/.rush/temp/5bc0bba70b733baa4dd976667ba0a1386e516186.log +10 -0
  8. package/.rush/temp/64f1bb696f8d7d7e72907b80df316b127f72e23e.log +10 -0
  9. package/.rush/temp/6f640f951414ea68adb65c17e4ed7527cde54faf.log +10 -0
  10. package/.rush/temp/7c7b958682d4ab5697530be47d0aac62efe1adf1.log +10 -0
  11. package/.rush/temp/82bfb987463fbcfebf04022e6ed00015c73879c8.log +10 -0
  12. package/.rush/temp/844034aa6e542115075e8f3dc5ffc640973e0064.log +10 -0
  13. package/.rush/temp/8b42957a7c15da1f29cb57bee125f13affa70dca.log +10 -0
  14. package/.rush/temp/a769db9d81a23000c0e9b1bf4f1a9a9e721d0d7c.log +10 -0
  15. package/.rush/temp/a87d3a8b4ece87ec66f27c86226a9f205617681f.log +10 -0
  16. package/.rush/temp/bb7a5bdcc4af4ad1507f81f33774b31f5b4e4fb7.log +10 -0
  17. package/.rush/temp/c20e29ccaaa9231b38a28bb24451b4ce7562cdc0.log +10 -0
  18. package/.rush/temp/e21303db8f59b4625fd184c9114377d781fd24f8.log +10 -0
  19. package/.rush/temp/e6d303862765b6a5f41dd483d0f9ae083a1fae10.log +10 -0
  20. package/.rush/temp/eaf69fbc059d2f1258d7569136180d4a1d3c7072.log +10 -0
  21. package/.rush/temp/f85d279e2674966daaec83e1c3986a96f86ef304.log +10 -0
  22. package/.rush/temp/fc0a332c5b34c6b90006850cf2d93a48fb4b9a6e.log +10 -0
  23. package/.rush/temp/package-deps_build.json +170 -0
  24. package/.rush/temp/package-deps_test.json +38 -36
  25. package/.rush/temp/shrinkwrap-deps.json +231 -240
  26. package/CHANGELOG.json +17 -0
  27. package/CHANGELOG.md +8 -1
  28. package/api.build.log +4 -2
  29. package/bin/test.sh +0 -1
  30. package/cjs/auth.js +36 -10
  31. package/cjs/auth.js.map +1 -1
  32. package/cjs/auth.spec.js +12 -6
  33. package/cjs/auth.spec.js.map +1 -1
  34. package/cjs/collections/base.js +10 -2
  35. package/cjs/collections/base.js.map +1 -1
  36. package/cjs/collections/base.spec.js +22 -4
  37. package/cjs/collections/base.spec.js.map +1 -1
  38. package/cjs/collections/deck-version-screenshots.js +62 -0
  39. package/cjs/collections/deck-version-screenshots.js.map +1 -0
  40. package/cjs/collections.js +13 -0
  41. package/cjs/collections.js.map +1 -1
  42. package/cjs/models/activity-item.js +3 -1
  43. package/cjs/models/activity-item.js.map +1 -1
  44. package/cjs/models/appointment.js +11 -1
  45. package/cjs/models/appointment.js.map +1 -1
  46. package/cjs/models/auto-adjunct.js +3 -1
  47. package/cjs/models/auto-adjunct.js.map +1 -1
  48. package/cjs/models/base.js +19 -1
  49. package/cjs/models/base.js.map +1 -1
  50. package/cjs/models/base.spec.js +9 -0
  51. package/cjs/models/base.spec.js.map +1 -1
  52. package/cjs/models/deck-version-screenshot.js +59 -0
  53. package/cjs/models/deck-version-screenshot.js.map +1 -0
  54. package/cjs/models/deck-version.js +28 -5
  55. package/cjs/models/deck-version.js.map +1 -1
  56. package/cjs/models/feed-data.js +5 -0
  57. package/cjs/models/feed-data.js.map +1 -1
  58. package/cjs/models/image.js +34 -0
  59. package/cjs/models/image.js.map +1 -1
  60. package/cjs/models/manifest-json.js +1 -1
  61. package/cjs/models/manifest-json.js.map +1 -1
  62. package/cjs/models/section.js +3 -1
  63. package/cjs/models/section.js.map +1 -1
  64. package/cjs/models/slide.js +3 -1
  65. package/cjs/models/slide.js.map +1 -1
  66. package/cjs/models/template.js +3 -1
  67. package/cjs/models/template.js.map +1 -1
  68. package/cjs/models/token.js +56 -0
  69. package/cjs/models/token.js.map +1 -0
  70. package/cjs/models/user.js +2 -1
  71. package/cjs/models/user.js.map +1 -1
  72. package/cjs/models.js +26 -0
  73. package/cjs/models.js.map +1 -1
  74. package/cjs/presentation/appointment-presentation.js +7 -3
  75. package/cjs/presentation/appointment-presentation.js.map +1 -1
  76. package/cjs/presentation/base-presentation-model.js +111 -2
  77. package/cjs/presentation/base-presentation-model.js.map +1 -1
  78. package/cjs/presentation/base-presentation-model.spec.js +56 -0
  79. package/cjs/presentation/base-presentation-model.spec.js.map +1 -1
  80. package/cjs/presentation/presentation-deck.js +33 -6
  81. package/cjs/presentation/presentation-deck.js.map +1 -1
  82. package/cjs/presentation/presentation-deck.spec.js +53 -0
  83. package/cjs/presentation/presentation-deck.spec.js.map +1 -1
  84. package/cjs/presentation/presentation-section.js +42 -16
  85. package/cjs/presentation/presentation-section.js.map +1 -1
  86. package/cjs/presentation/presentation-section.spec.js +121 -3
  87. package/cjs/presentation/presentation-section.spec.js.map +1 -1
  88. package/cjs/presentation/presentation-slide.js +30 -13
  89. package/cjs/presentation/presentation-slide.js.map +1 -1
  90. package/cjs/presentation/presentation-slide.spec.js +94 -2
  91. package/cjs/presentation/presentation-slide.spec.js.map +1 -1
  92. package/cjs/presentation/presentation.js +112 -8
  93. package/cjs/presentation/presentation.js.map +1 -1
  94. package/jest.config.js +1 -0
  95. package/package.json +4 -4
  96. package/src/auth.js +44 -8
  97. package/src/auth.spec.js +2 -0
  98. package/src/collections/base.js +10 -4
  99. package/src/collections/base.spec.js +17 -3
  100. package/src/collections/deck-version-screenshots.js +48 -0
  101. package/src/collections.js +1 -0
  102. package/src/models/activity-item.js +2 -0
  103. package/src/models/appointment.js +12 -0
  104. package/src/models/auto-adjunct.js +2 -0
  105. package/src/models/base.js +19 -1
  106. package/src/models/base.spec.js +16 -9
  107. package/src/models/deck-version-screenshot.js +48 -0
  108. package/src/models/deck-version.js +30 -4
  109. package/src/models/feed-data.js +2 -0
  110. package/src/models/image.js +32 -0
  111. package/src/models/manifest-json.js +1 -1
  112. package/src/models/section.js +2 -0
  113. package/src/models/slide.js +2 -0
  114. package/src/models/template.js +2 -0
  115. package/src/models/token.js +47 -0
  116. package/src/models/user.js +2 -0
  117. package/src/models.js +2 -0
  118. package/src/presentation/appointment-presentation.js +10 -2
  119. package/src/presentation/base-presentation-model.js +77 -1
  120. package/src/presentation/base-presentation-model.spec.js +77 -0
  121. package/src/presentation/presentation-deck.js +40 -2
  122. package/src/presentation/presentation-deck.spec.js +53 -0
  123. package/src/presentation/presentation-section.js +37 -5
  124. package/src/presentation/presentation-section.spec.js +135 -2
  125. package/src/presentation/presentation-slide.js +25 -5
  126. package/src/presentation/presentation-slide.spec.js +104 -2
  127. package/src/presentation/presentation.js +24 -7
@@ -25,6 +25,7 @@ export const AutoAdjunctModel = BaseModel.extend(
25
25
  * @property {string} after_key
26
26
  * @property {boolean} enabled
27
27
  * @property {number} sequence
28
+ * @property {string[]} cmsvalkey_set
28
29
  */
29
30
  props: {
30
31
  image_128: "string",
@@ -39,6 +40,7 @@ export const AutoAdjunctModel = BaseModel.extend(
39
40
  enabled: "boolean",
40
41
  sequence: "number",
41
42
  tags: "array",
43
+ cmsvalkey_set: "array",
42
44
  },
43
45
 
44
46
  /**
@@ -26,6 +26,10 @@ export const BaseModel = Model.extend(
26
26
  // behaviour from automatically hydrating all children and collections on a fetch.
27
27
  isFetching: false,
28
28
 
29
+ // Useful to figure out whether the model is just a URL (unfetched), or has been
30
+ // fetched from the server (an object).
31
+ _isFetched: true,
32
+
29
33
  // Object of regexes that should be used to match a url in `matchesURL`
30
34
  // For example the URL: /api/foo/{pk}/bar/ might have the following:
31
35
  //
@@ -38,11 +42,13 @@ export const BaseModel = Model.extend(
38
42
  // ```
39
43
  urlMatchKeys: {},
40
44
 
41
- constructor(data = {}, opts = {}) {
45
+ constructor(_data = {}, opts = {}) {
42
46
  const options = _.defaults(opts, {
43
47
  data: {},
44
48
  });
45
49
 
50
+ let data = _data;
51
+
46
52
  this._unsetChildren = {};
47
53
  this._unsetCollections = {};
48
54
  this._expandedValues = {};
@@ -61,6 +67,13 @@ export const BaseModel = Model.extend(
61
67
  // Convert any strings into a url format we can understand
62
68
  if (_.isString(data)) {
63
69
  data = { url: data };
70
+ this._isFetched = false;
71
+ }
72
+
73
+ // Convert model ids into a format we can understand
74
+ if (_.isNumber(data)) {
75
+ data = { id: data };
76
+ this._isFetched = false;
64
77
  }
65
78
 
66
79
  const dataCopy = _.extend({}, data);
@@ -402,6 +415,7 @@ export const BaseModel = Model.extend(
402
415
 
403
416
  this.isFetching = true;
404
417
  return Model.prototype.fetch.apply(this, arguments).tap((response) => {
418
+ this._isFetched = true;
405
419
  this.isFetching = false;
406
420
  this._updateResponse(response);
407
421
  });
@@ -421,6 +435,10 @@ export const BaseModel = Model.extend(
421
435
  });
422
436
  },
423
437
 
438
+ isFetched() {
439
+ return this._isFetched;
440
+ },
441
+
424
442
  getSafeAttrs(key) {
425
443
  if (!_.isUndefined(key)) {
426
444
  return !_.isUndefined(this._expandedValues[key])
@@ -7,7 +7,7 @@ import log from "../log.js";
7
7
  import moment from "moment";
8
8
  import td from "testdouble";
9
9
 
10
- it("should set date types correctly (SP-2698)", function () {
10
+ it("should set date types correctly (SP-2698)", () => {
11
11
  const TestModel = BaseModel.extend({ props: { testDate: "date" } });
12
12
 
13
13
  const model = new TestModel();
@@ -48,7 +48,7 @@ it("should not append a slash to a get query", () => {
48
48
  expect(model.url()).toEqual("/api/tests/?foo=bar");
49
49
  });
50
50
 
51
- it("should replace child model strings with the registered model", function () {
51
+ it("should replace child model strings with the registered model", () => {
52
52
  const TestModel = G(BaseModel, "TestModel");
53
53
  const Model = G(
54
54
  BaseModel.extend({
@@ -59,7 +59,7 @@ it("should replace child model strings with the registered model", function () {
59
59
  expect(model.test).toBeInstanceOf(TestModel);
60
60
  });
61
61
 
62
- it("should allow the model to be passed in", function () {
62
+ it("should allow the model to be passed in", () => {
63
63
  const TestModel = G(BaseModel, "TestModel");
64
64
  const Model = G(
65
65
  BaseModel.extend({
@@ -71,7 +71,7 @@ it("should allow the model to be passed in", function () {
71
71
  expect(model.test).toBeInstanceOf(TestModel);
72
72
  });
73
73
 
74
- it("should reference parent model if foreign key exists", function () {
74
+ it("should reference parent model if foreign key exists", () => {
75
75
  G(BaseModel, "TestModel");
76
76
  const Model = G(
77
77
  BaseModel.extend({
@@ -92,7 +92,7 @@ it("should throw an error if the child model doesn't exist", () => {
92
92
  expect(() => new Model()).toThrow();
93
93
  });
94
94
 
95
- it("should convert a url into a model", function () {
95
+ it("should convert a url into a model", () => {
96
96
  G(BaseModel.extend({ modelName: "tests" }), "TestModel");
97
97
  const Model = G(
98
98
  BaseModel.extend({
@@ -103,7 +103,14 @@ it("should convert a url into a model", function () {
103
103
  expect(model.test.id).toEqual(1);
104
104
  });
105
105
 
106
- it("should convert an object into a model", function () {
106
+ it("should convert an id into a model", () => {
107
+ const TestModel = BaseModel.extend({ modelName: "test" });
108
+ const testModel = new TestModel(1);
109
+ expect(testModel.id).toEqual(1);
110
+ expect(testModel.url()).toEqual("/test/1/");
111
+ });
112
+
113
+ it("should convert an object into a model", () => {
107
114
  G(BaseModel, "TestModel");
108
115
  const Model = G(
109
116
  BaseModel.extend({
@@ -114,7 +121,7 @@ it("should convert an object into a model", function () {
114
121
  expect(model.test.id).toEqual(1);
115
122
  });
116
123
 
117
- it("should replace collection strings with their registered state", function () {
124
+ it("should replace collection strings with their registered state", () => {
118
125
  G(BaseModel, "TestModel");
119
126
  const TestCollection = G(
120
127
  BaseCollection.extend({
@@ -133,7 +140,7 @@ it("should replace collection strings with their registered state", function ()
133
140
  expect(model.tests).toBeInstanceOf(TestCollection);
134
141
  });
135
142
 
136
- it("should allow a list of models to be passed into a collection", function () {
143
+ it("should allow a list of models to be passed into a collection", () => {
137
144
  const TestModel = G(BaseModel, "TestModel");
138
145
  G(
139
146
  BaseCollection.extend({
@@ -211,7 +218,7 @@ it("should convert an array of objects into a collection", () => {
211
218
  expect(model.tests.at(1).id).toEqual(2);
212
219
  });
213
220
 
214
- it("should correctly sanitize strings of multibyte characters (preserving spaces)", function () {
221
+ it("should correctly sanitize strings of multibyte characters (preserving spaces)", () => {
215
222
  const TestModel = BaseModel.extend({
216
223
  props: {
217
224
  normalString: "string",
@@ -0,0 +1,48 @@
1
+ import "./team.js";
2
+
3
+ import { BaseModel } from "./base.js";
4
+ import _ from "lodash";
5
+ import { register } from "../state-register.js";
6
+
7
+ /**
8
+ * @constructor
9
+ * @alias models.DeckVersionScreenshotModel
10
+ * @extends models.BaseModel
11
+ */
12
+ export const DeckVersionScreenshotModel = BaseModel.extend(
13
+ /** @lends models.DeckVersionScreenshotModel# */ {
14
+ modelName: "deckversion-screenshots",
15
+
16
+ urlMatchKeys: {
17
+ "deckversion.id": "number",
18
+ },
19
+
20
+ /**
21
+ * @property {date} created_date
22
+ * @property {date} modified_date
23
+ * @property {string} image_128
24
+ * @property {string} image_256
25
+ * @property {string} image_512
26
+ * @property {string} subject - A url for a screenshotted model (section, slide, etc.)
27
+ */
28
+ props: {
29
+ created_date: "date",
30
+ modified_date: "date",
31
+ image_128: "string",
32
+ image_256: "string",
33
+ image_512: "string",
34
+ subject: "string",
35
+ },
36
+
37
+ children: {
38
+ team: "TeamModel",
39
+ },
40
+
41
+ serialize() {
42
+ const data = BaseModel.prototype.serialize.call(this);
43
+ return _.omit(data, ["url"]);
44
+ },
45
+ }
46
+ );
47
+
48
+ register("DeckVersionScreenshotModel", DeckVersionScreenshotModel);
@@ -7,6 +7,7 @@ import "./asset.js";
7
7
  import "./manifest-json.js";
8
8
 
9
9
  import { BaseModel } from "./base.js";
10
+ import { DeckVersionScreenshotCollection } from "../collections/deck-version-screenshots.js";
10
11
  import Promise from "bluebird";
11
12
  import _ from "lodash";
12
13
  import { register } from "../state-register.js";
@@ -39,6 +40,7 @@ export const DeckVersionModel = BaseModel.extend(
39
40
  * @property {boolean} has_editable_share_support
40
41
  * @property {string} point_in_time_share_policy
41
42
  * @property {string[]} tags
43
+ * @property {string[]} cmsvalkey_set
42
44
  */
43
45
  props: {
44
46
  image_128: "string",
@@ -59,6 +61,7 @@ export const DeckVersionModel = BaseModel.extend(
59
61
  has_editable_share_support: "boolean",
60
62
  point_in_time_share_policy: "string",
61
63
  tags: "array",
64
+ cmsvalkey_set: "array",
62
65
  },
63
66
 
64
67
  /**
@@ -86,10 +89,24 @@ export const DeckVersionModel = BaseModel.extend(
86
89
  },
87
90
 
88
91
  /**
89
- * @todo This should eventually return a hooks interface
90
- * @returns {object}
92
+ * @property {collections.DeckVersionScreenshotCollection} screenshots
91
93
  */
92
- getHooks() {
94
+ derived: {
95
+ screenshots: {
96
+ deps: ["id"],
97
+ fn: function () {
98
+ const screenshots = new DeckVersionScreenshotCollection(
99
+ {},
100
+ {
101
+ deckversion: this,
102
+ }
103
+ );
104
+ return screenshots;
105
+ },
106
+ },
107
+ },
108
+
109
+ getHooksPath() {
93
110
  if (this.isNew()) {
94
111
  throw new Error(
95
112
  "Can only get hooks from a fetched deckversion or at least have an ID"
@@ -117,8 +134,17 @@ export const DeckVersionModel = BaseModel.extend(
117
134
  if (!this.manifest_json.hooks) {
118
135
  throw new Error("Manifest does not contain a hooks entry");
119
136
  }
120
- const hooksPath = `${rootAssetUrl}${this.manifest_json.hooks}`;
137
+ return `${rootAssetUrl}${this.manifest_json.hooks}`;
138
+ });
139
+ },
121
140
 
141
+ /**
142
+ * @todo This should eventually return a hooks interface
143
+ * @returns {object}
144
+ */
145
+ getHooks() {
146
+ return this.getHooksPath()
147
+ .then((hooksPath) => {
122
148
  return SystemJS.import(hooksPath);
123
149
  })
124
150
  .then((hooks) => {
@@ -14,10 +14,12 @@ export const FeedDataModel = BaseModel.extend(
14
14
 
15
15
  /**
16
16
  * @property {object} feed_data
17
+ * @property {object} feed_debug
17
18
  * @property {string} creation_status
18
19
  */
19
20
  props: {
20
21
  feed_data: "object",
22
+ feed_debug: {type: "object", default: () => {}},
21
23
  creation_status: "string",
22
24
  },
23
25
 
@@ -1,6 +1,8 @@
1
1
  import "./user.js";
2
2
 
3
+ import { Auth } from "../auth.js";
3
4
  import { BaseModel } from "./base.js";
5
+ import SuperAgentRequest from "superagent-bluebird-promise";
4
6
  import { register } from "../state-register.js";
5
7
 
6
8
  /**
@@ -37,6 +39,36 @@ export const ImageModel = BaseModel.extend(
37
39
  children: {
38
40
  event: "UserModel",
39
41
  },
42
+ uploadBase64(data) {
43
+ // mime will be in the format "image/png;base64"
44
+ const fileType = data.mime.split(";")[0];
45
+ const fileEnd = fileType.split("/")[1];
46
+
47
+ return fetch(data.value)
48
+ .then((res) => {
49
+ return res.blob();
50
+ })
51
+ .then((blob) => {
52
+ const file = new File([blob], `image.${fileEnd}`, { type: fileType });
53
+ const formData = new FormData();
54
+ formData.append("image_original", file);
55
+
56
+ return this.uploadFile(file);
57
+ });
58
+ },
59
+ uploadFile(file) {
60
+ const formData = new FormData();
61
+ formData.append("image_original", file);
62
+
63
+ return SuperAgentRequest.post(this.url())
64
+ .send(formData)
65
+ .set(Auth.headers)
66
+ .then((response) => {
67
+ Object.keys(response.body).forEach((key) => {
68
+ this.set(key, response.body[key]);
69
+ });
70
+ });
71
+ },
40
72
  }
41
73
  );
42
74
 
@@ -311,7 +311,7 @@ ManifestJSONModel.createFromProject = function (projectFile) {
311
311
  // This means we validate that a fieldset field has a value. Before
312
312
  // this change, it was possible to save with a required field unfilled.
313
313
  // This just keeps backwards compatability.
314
- manifest.app_settings.fieldsets.enforce_required = true;
314
+ manifest.app_settings.fieldsets.enforce_required = false;
315
315
 
316
316
  return manifest;
317
317
  };
@@ -34,6 +34,7 @@ export const SectionModel = BaseModel.extend(
34
34
  * @property {string} title
35
35
  * @property {boolean} uploaded
36
36
  * @property {boolean} visible
37
+ * @property {string[]} cmsvalkey_set
37
38
  */
38
39
  props: {
39
40
  adjunctslide_limit: "number",
@@ -62,6 +63,7 @@ export const SectionModel = BaseModel.extend(
62
63
  type: "array",
63
64
  default: () => [],
64
65
  },
66
+ cmsvalkey_set: "array",
65
67
  },
66
68
 
67
69
  /**
@@ -35,6 +35,7 @@ export const SlideModel = BaseModel.extend(
35
35
  * @property {boolean} uploaded
36
36
  * @property {boolean} visible
37
37
  * @property {array} tags
38
+ * @property {string[]} cmsvalkey_set
38
39
  */
39
40
  props: {
40
41
  adjunctslide_limit: "number",
@@ -63,6 +64,7 @@ export const SlideModel = BaseModel.extend(
63
64
  type: "array",
64
65
  default: () => [],
65
66
  },
67
+ cmsvalkey_set: "array",
66
68
  },
67
69
 
68
70
  /**
@@ -23,6 +23,7 @@ export const TemplateModel = BaseModel.extend(
23
23
  * @property {string} image_128
24
24
  * @property {string} image_256
25
25
  * @property {string} image_512
26
+ * @property {string[]} cmsvalkey_set
26
27
  */
27
28
  props: {
28
29
  created_date: "date",
@@ -33,6 +34,7 @@ export const TemplateModel = BaseModel.extend(
33
34
  image_128: "string",
34
35
  image_256: "string",
35
36
  image_512: "string",
37
+ cmsvalkey_set: "array",
36
38
  },
37
39
 
38
40
  /**
@@ -0,0 +1,47 @@
1
+ import "./user.js";
2
+
3
+ import { BaseModel } from "./base.js";
4
+ import { register } from "../state-register.js";
5
+
6
+ /**
7
+ * @constructor
8
+ * @alias models.TokenModel
9
+ * @extends models.BaseModel
10
+ */
11
+ export const TokenModel = BaseModel.extend(
12
+ /** @lends models.TokenModel# */ {
13
+ modelName: "tokens",
14
+
15
+ /**
16
+ * @property {date} created_date
17
+ * @property {boolean} expired
18
+ * @property {date} expires_at
19
+ * @property {string} key
20
+ * @property {number} seconds_to_expiry
21
+ * @property {string} agent
22
+ * @property {string} agent_version
23
+ */
24
+ props: {
25
+ created_date: "date",
26
+ expired: "boolean",
27
+ expires_at: "date",
28
+ key: "string",
29
+ seconds_to_expiry: "number",
30
+ agent: "string",
31
+ agent_version: "string",
32
+ },
33
+
34
+ /**
35
+ * @property {models.UserModel} user
36
+ */
37
+ children: {
38
+ user: "UserModel",
39
+ },
40
+
41
+ url() {
42
+ return `${this.urlRoot()}${this.key}/`;
43
+ },
44
+ }
45
+ );
46
+
47
+ register("TokenModel", TokenModel);
@@ -157,6 +157,8 @@ export const UserModel = BaseModel.extend(
157
157
  this.actions.indexOf("Allow Teamless Appointments") > -1,
158
158
  canUseClosedCaptions:
159
159
  this.actions.indexOf("Use Closed Captions") > -1,
160
+ canCreateMutedAppointments:
161
+ this.actions.indexOf("Create Muted Appointments") > -1,
160
162
  };
161
163
 
162
164
  const customers = {
package/src/models.js CHANGED
@@ -19,6 +19,7 @@ export * from "./models/customer";
19
19
  export * from "./models/deck";
20
20
  export * from "./models/deck-tags";
21
21
  export * from "./models/deck-version";
22
+ export * from "./models/deck-version-screenshot";
22
23
  export * from "./models/dispatch";
23
24
  export * from "./models/dispatch-preview";
24
25
  export * from "./models/envs.js";
@@ -65,3 +66,4 @@ export * from "./models/team.js";
65
66
  export * from "./models/template.js";
66
67
  export * from "./models/auto-adjunct-key-check.js";
67
68
  export * from "./models/transcribe-socket.js";
69
+ export * from "./models/token.js";
@@ -5,7 +5,8 @@ import "../models/user.js";
5
5
  import "../collections/opportunities.js";
6
6
  import "../collections/contacts.js";
7
7
 
8
- import { AppointmentModel } from "../models.js";
8
+ import { AppointmentModel, TeamModel } from "../models.js";
9
+
9
10
  import { BaseModel } from "../models/base.js";
10
11
  import { PresentationDeck } from "./presentation-deck.js";
11
12
  import { register } from "../state-register.js";
@@ -58,20 +59,27 @@ export const AppointmentPresentation = BaseModel.extend(
58
59
 
59
60
  const createFromAppointment = function (appointment, options) {
60
61
  const appointmentPresentation = new AppointmentPresentation();
62
+ const team = appointment.team ? new TeamModel(appointment.team).id : null;
61
63
 
62
64
  // Note that we're not passing through tags if appointment.tags is empty.
63
65
  // This is because tags currently aren't available in the telepresenter
64
66
  // bundle and we want to fall back on the model tags for now.
65
67
  appointmentPresentation.presentation.decks.add(
66
68
  appointment.deckversion_set.map((model, index) => {
69
+ const screenshots = PresentationDeck.filterScreenshotsByTeam(
70
+ model.screenshots,
71
+ team
72
+ );
73
+
67
74
  return PresentationDeck.createFromDeckVersion(model, {
68
75
  adjunctSections: appointment.adjunctSections,
69
76
  adjunctSlides: appointment.adjunctSlides,
70
77
  adjunctSubSlides: appointment.adjunctSubSlides,
71
78
  sectionSelections: appointment.appointmentssection_set,
72
79
  slideSelections: appointment.appointmentsslide_set,
73
- index,
74
80
  appointmentTags: appointment.tags.length ? appointment.tags : null,
81
+ screenshots,
82
+ index,
75
83
  ...options,
76
84
  });
77
85
  })
@@ -1,4 +1,7 @@
1
1
  import { BaseModel } from "../models/base.js";
2
+ import { DeckVersionScreenshotCollection } from "../collections/deck-version-screenshots.js";
3
+ import { TeamModel } from "../models/team.js";
4
+ import _ from "lodash";
2
5
 
3
6
  /**
4
7
  * @constructor
@@ -13,6 +16,80 @@ export const BasePresentationModel = BaseModel.extend(
13
16
  }
14
17
  );
15
18
 
19
+ /**
20
+ * Logic to pick a thumbnail based on either the model itself or from
21
+ * and overriding screenshot if one exists.
22
+ */
23
+ BasePresentationModel.getThumbnail = function (model, screenshots) {
24
+ const overrideScreenshot =
25
+ screenshots?.filter((screen) => {
26
+ return screen.subject === model.url();
27
+ }) ?? [];
28
+
29
+ if (overrideScreenshot.length) {
30
+ if (overrideScreenshot.length > 1) {
31
+ throw new Error(`
32
+ Found multiple screenshots that could match this subject. If there is a team
33
+ and a global, be sure to remove the screenshot that you don't need.
34
+ `);
35
+ }
36
+
37
+ return overrideScreenshot[0].image_256;
38
+ }
39
+
40
+ return model.image_256;
41
+ };
42
+
43
+ /**
44
+ * Takes a list of screenshots and filters it to only be a list used by a single team
45
+ * (or company wide).
46
+ *
47
+ * The logic should be like this:
48
+ *
49
+ * * If the team is null, we just return all global screenshots (team = null)
50
+ * * If we select a team, we take those global screenshots and replace any that have a
51
+ * team specific version of that screenshot. If none is found, the team will want to
52
+ * see the same global version. Obviously only one team's screenshots should be available.
53
+ */
54
+ BasePresentationModel.filterScreenshotsByTeam = function (
55
+ _screenshots,
56
+ _team = null
57
+ ) {
58
+ const screenshots = new DeckVersionScreenshotCollection(_screenshots);
59
+ const team = _team ? new TeamModel(_team) : null;
60
+
61
+ const globalScreenshots = screenshots
62
+ .filter((screen) => screen.team === null)
63
+ .map((screen) => screen.toJSON());
64
+
65
+ const result = globalScreenshots;
66
+
67
+ if (team) {
68
+ const teamScreenshots = screenshots
69
+ .filter((screen) => screen.team && screen.team.url() === team.url())
70
+ .map((screen) => ({ ...screen.toJSON(), team: screen.team.url() }));
71
+
72
+ for (const teamScreen of teamScreenshots) {
73
+ const existingGlobalIndex = _.findIndex(result, {
74
+ subject: teamScreen.subject,
75
+ });
76
+
77
+ if (existingGlobalIndex === -1) {
78
+ // If there isn't an existing global version, just add the team
79
+ // screenshot to the list
80
+ result.push(teamScreen);
81
+ } else {
82
+ // Otherwise we should use the team version instead of the global version
83
+ result[existingGlobalIndex] = teamScreen;
84
+ }
85
+ }
86
+ }
87
+
88
+ // Try to return it in the same order every time
89
+ const ordered = _.orderBy(result, ["team", "subject"], ["desc", "asc"]);
90
+ return new DeckVersionScreenshotCollection(ordered);
91
+ };
92
+
16
93
  /**
17
94
  * Standard function for retrieving the visibility and sequence of a model
18
95
  * from a choicelist or section & slide selections. If a choicelist is
@@ -20,7 +97,6 @@ export const BasePresentationModel = BaseModel.extend(
20
97
  * Adjuncts are included in choicelists but not in selections so we use the
21
98
  * model's state to determine sequence & vis when selections are used.
22
99
  */
23
-
24
100
  BasePresentationModel.getVisibilityAndSequence = function (
25
101
  model,
26
102
  options = {}
@@ -1,4 +1,5 @@
1
1
  import { BasePresentationModel } from "./base-presentation-model.js";
2
+ import { DeckVersionScreenshotCollection } from "../collections/deck-version-screenshots.js";
2
3
 
3
4
  describe("#getVisibilityAndSequence", () => {
4
5
  it("should return model defaults when no options", () => {
@@ -227,3 +228,79 @@ describe("#getTags", () => {
227
228
  expect(tags).toEqual(["adjunctslide-tags"]);
228
229
  });
229
230
  });
231
+
232
+ describe("#filterScreenshotsByTeam", () => {
233
+ const screenshots = new DeckVersionScreenshotCollection([
234
+ {
235
+ subject: "/api/slides/1/",
236
+ image_256: "global-screenshot-1.png",
237
+ team: null,
238
+ },
239
+ {
240
+ subject: "/api/slides/2/",
241
+ image_256: "global-screenshot-2.png",
242
+ team: null,
243
+ },
244
+ {
245
+ subject: "/api/slides/1/",
246
+ image_256: "team-1-screenshot.png",
247
+ team: "/api/teams/1/",
248
+ },
249
+ {
250
+ subject: "/api/sections/2/",
251
+ image_256: "team-1-screenshot.png",
252
+ team: "/api/teams/1/",
253
+ },
254
+ // Just for testing that the team filters don't get cross-contaminated
255
+ {
256
+ subject: "/api/sections/2/",
257
+ image_256: "team-2-screenshot.png",
258
+ team: "/api/teams/2/",
259
+ },
260
+ ]);
261
+
262
+ it("should just return global screenshots if team is null", () => {
263
+ const filtered = BasePresentationModel.filterScreenshotsByTeam(
264
+ screenshots,
265
+ null
266
+ ).toJSON();
267
+
268
+ expect(filtered).toEqual([
269
+ {
270
+ subject: "/api/slides/1/",
271
+ image_256: "global-screenshot-1.png",
272
+ team: null,
273
+ },
274
+ {
275
+ subject: "/api/slides/2/",
276
+ image_256: "global-screenshot-2.png",
277
+ team: null,
278
+ },
279
+ ]);
280
+ });
281
+
282
+ it("should return globals with team override", () => {
283
+ const filtered = BasePresentationModel.filterScreenshotsByTeam(
284
+ screenshots,
285
+ 1
286
+ ).toJSON();
287
+
288
+ expect(filtered).toEqual([
289
+ {
290
+ image_256: "global-screenshot-2.png",
291
+ subject: "/api/slides/2/",
292
+ team: null,
293
+ },
294
+ {
295
+ image_256: "team-1-screenshot.png",
296
+ subject: "/api/sections/2/",
297
+ team: "/api/teams/1/",
298
+ },
299
+ {
300
+ image_256: "team-1-screenshot.png",
301
+ subject: "/api/slides/1/",
302
+ team: "/api/teams/1/",
303
+ },
304
+ ]);
305
+ });
306
+ });