@flumens/models 0.5.2 → 0.6.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.
@@ -1 +1,369 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("tslib"),e=require("mobx"),r=require("axios"),i=require("@flumens/utils/dist/image"),a=require("../Model.js"),n=require("./helpers.js");function o(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var s,d=o(r),u=!!window.cordova||!!(null===(s=null===window||void 0===window?void 0:window.Capacitor)||void 0===s?void 0:s.isNative),h=function(r){function a(i){var a=this;void 0===i&&(i={});var n=i.metadata,o=void 0===n?{}:n,s=t.__rest(i,["metadata"]);return(a=r.call(this,s)||this).remote={synchronising:!1,url:null,headers:{},timeout:12e4},a.debouncedValue=300,a.parent=a.parent,a.metadata=e.observable(o),a}return t.__extends(a,r),a.fromJSON=function(e){var r,i,a;return new this(t.__assign(t.__assign({},e),{createdAt:e.createdAt||(null===(r=e.metadata)||void 0===r?void 0:r.createdOn),updatedAt:e.updatedAt||(null===(i=e.metadata)||void 0===i?void 0:i.updatedOn),syncedAt:e.syncedAt||(null===(a=e.metadata)||void 0===a?void 0:a.syncedOn)}))},a.getDataURI=function(t,e){void 0===e&&(e={});var r=new Promise((function(r,i){if("string"==typeof t){var n=t.replace(/.*\.([a-z]+)$/i,"$1");return"jpg"===n&&(n="jpeg"),void a.resize(t,n,e.width,e.height).then((function(t){var e=t[0],i=t[1];r([i,n,e.width,e.height])}))}if(window.FileReader){var o=new FileReader;o.onload=function(i){var n,o;if(e.width||e.height)a.resize(null===(n=i.target)||void 0===n?void 0:n.result,t.type,e.width,e.height).then((function(e){var i=e[0],a=e[1];r([a,t.type,i.width,i.height])}));else{var s=new window.Image;s.onload=function(){var e,a=t.type.replace(/.*\/([a-z]+)$/i,"$1");r([null===(e=i.target)||void 0===e?void 0:e.result,a,s.width,s.height])},s.src=null===(o=i.target)||void 0===o?void 0:o.result}},o.readAsDataURL(t)}else i(new Error("No File Reader"))}));return r},a.resize=function(t,e,r,i){var a=new Promise((function(a){var n=new window.Image;n.onload=function(){var t,o=n.width,s=n.height,d=null;o/=d=o>s?o/(!r||r>o?o:r):s/(!i||i>s?s:i),s/=d;var u=document.createElement("canvas");u.width=o,u.height=s,null===(t=u.getContext("2d"))||void 0===t||t.drawImage(n,0,0,o,s),a([n,u.toDataURL(e)])},n.src=t}));return a},a.getImageModel=function(e,r,a){return t.__awaiter(this,void 0,void 0,(function(){var n,o,s,d,h,c,l;return t.__generator(this,(function(t){switch(t.label){case 0:if(n=this,!e)throw new Error("File not found while creating image model.");return u?[4,i.createImage(e)]:[3,2];case 1:return h=t.sent(),o=h.width,s=h.height,d=e.split("/").pop(),[3,4];case 2:return[4,n.getDataURI(e,{width:2e3,height:2e3})];case 3:l=t.sent(),d=l[0],o=l[2],s=l[3],t.label=4;case 4:return c=new n({attrs:{data:d,type:"jpeg",width:o,height:s,path:r}}),a?[3,6]:[4,c.addThumbnail()];case 5:t.sent(),t.label=6;case 6:return[2,c]}}))}))},a.prototype.toJSON=function(){var i=r.prototype.toJSON.call(this);return JSON.parse(JSON.stringify(t.__assign(t.__assign({},i),{metadata:e.toJS(this.metadata)||{}})))},a.prototype.setupdatedAtTimestamp=function(t){var e;r.prototype.setUpdatedAtTimestamp.call(this,t),null===(e=this.parent)||void 0===e||e.setUpdatedAtTimestamp(t)},a.prototype.getSubmission=function(t){void 0===t&&(t={});var e=t[this.cid];if(!this.id&&!e)throw new Error("Image ID or queued ID is missing.");var r={values:{caption:this.attrs.caption}};return this.id?r.values.id=this.id:r.values.queued=e.name,r},a.prototype.sync=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){return[2,this.parent?this.parent.sync():r.prototype.sync.call(this)]}))}))},a.prototype.uploadFile=function(e){var r;return void 0===e&&(e=!1),t.__awaiter(this,void 0,void 0,(function(){var i,a,n,o,s,u,h,c;return t.__generator(this,(function(t){switch(t.label){case 0:if(this.id)throw new Error("A file of a media on the remote cannot be uploaded again.");return i=Date.now()-432e5,a=this.syncedAt>i&&this.attrs.queued,!e&&a?[2]:[4,this.getFormData()];case 1:return n=t.sent(),o=new FormData,(c=o).append.apply(c,n),"function"!=typeof this.remote.headers?[3,3]:[4,this.remote.headers()];case 2:return u=t.sent(),[3,4];case 3:u=this.remote.headers,t.label=4;case 4:return s=u,[4,d.default.post("".concat(this.remote.url,"/media-queue"),o,{headers:s,timeout:12e4})];case 5:if(h=t.sent(),!(null===(r=h.data[this.cid])||void 0===r?void 0:r.name))throw new Error("New remote media name was not be found.");return this.attrs.queued=h.data[this.cid].name,this.syncedAt=(new Date).getTime(),[2]}}))}))},a.prototype.getFormData=function(){return t.__awaiter(this,void 0,void 0,(function(){var e,r,i,a,o,s,d;return t.__generator(this,(function(t){switch(t.label){case 0:return e=this.attrs.type,r=e,i=e,(null==e?void 0:e.match(/image.*/))?(d=e.split("/"),r=d[1]):i="image/".concat(i),a=this.getURL(),[4,n.getBlobFromURL(a,i)];case 1:return o=t.sent(),[2,[s=this.cid,o,"".concat(s,".").concat(r)]]}}))}))},a.prototype.getRemoteURL=function(){if(!this.remote.url)throw new Error("No remote url was set.");if(!this.attrs.queued&&!this.attrs.path)throw new Error("No media queued or path attribute.");var t=this.remote.url.replace("/index.php/services/rest","");return this.attrs.queued?"".concat(t,"/upload-queue/").concat(this.attrs.queued):"".concat(t,"/upload/").concat(this.attrs.path)},a.prototype.getURL=function(){return this.attrs.data},a.prototype.resize=function(t,e){var r=this,i=this,n=new Promise((function(n,o){a.resize(r.getURL(),r.attrs.type,t,e).then((function(t){var e=t[0],r=t[1];i.attrs.data=r,n([e,r])})).catch(o)}));return n},a.prototype.addThumbnail=function(t){var e=this,r=this;return new Promise((function(t,i){/^data:/i.test(e.getURL())?a.resize(e.getURL(),e.attrs.type,100,100).then((function(e){var i=e[1];r.attrs.thumbnail=i,t()})).catch(i):a.getDataURI(e.getURL(),{width:100,height:100}).then((function(e){r.attrs.thumbnail=e[0],t()})).catch(i)}))},a.prototype.isUploaded=function(){if(!this.parent)throw new Error("No media parent to return disabled status.");return this.parent.isUploaded()},a.prototype.isDisabled=function(){return this.isUploaded()},a}(a.default);exports.default=h;
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var mobx = require('mobx');
7
+ var axios = require('axios');
8
+ var utils = require('@flumens/utils');
9
+ var Model = require('../Model.js');
10
+ var helpers = require('./helpers.js');
11
+
12
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
+
14
+ var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
15
+
16
+ var THUMBNAIL_WIDTH = 100; // px
17
+ var THUMBNAIL_HEIGHT = 100; // px
18
+ var isHybrid = utils.isPlatform('hybrid');
19
+ var Media = /** @class */ (function (_super) {
20
+ tslib.__extends(Media, _super);
21
+ function Media(_a) {
22
+ if (_a === void 0) { _a = {}; }
23
+ var _this = this;
24
+ var _b = _a.metadata, metadata = _b === void 0 ? {} : _b, options = tslib.__rest(_a, ["metadata"]);
25
+ _this = _super.call(this, options) || this;
26
+ _this.remote = {
27
+ synchronising: false,
28
+ url: null, // must be set up for remote sync
29
+ headers: {}, // auth and other headers
30
+ timeout: 120000, // 120s
31
+ };
32
+ _this.debouncedValue = 300;
33
+ _this.parent = _this.parent;
34
+ _this.metadata = mobx.observable(metadata);
35
+ return _this;
36
+ }
37
+ Media.fromJSON = function (json) {
38
+ var _a, _b, _c;
39
+ return new this(tslib.__assign(tslib.__assign({}, json), { createdAt: json.createdAt || ((_a = json.metadata) === null || _a === void 0 ? void 0 : _a.createdOn), updatedAt: json.updatedAt || ((_b = json.metadata) === null || _b === void 0 ? void 0 : _b.updatedOn), syncedAt: json.syncedAt || ((_c = json.metadata) === null || _c === void 0 ? void 0 : _c.syncedOn) }));
40
+ };
41
+ /**
42
+ * Transforms and resizes an image file into a string.
43
+ * Can accept file image path and a file input file.
44
+ *
45
+ * @param onError
46
+ * @param file
47
+ * @param onSaveSuccess
48
+ * @returns {number}
49
+ */
50
+ Media.getDataURI = function (file, options) {
51
+ if (options === void 0) { options = {}; }
52
+ var promise = new Promise(function (fulfill, reject) {
53
+ // file paths
54
+ if (typeof file === 'string') {
55
+ // get extension
56
+ var fileType_1 = file.replace(/.*\.([a-z]+)$/i, '$1');
57
+ if (fileType_1 === 'jpg')
58
+ fileType_1 = 'jpeg'; // to match media types image/jpeg
59
+ Media.resize(file, fileType_1, options.width, options.height).then(function (args) {
60
+ var image = args[0], dataURI = args[1];
61
+ fulfill([dataURI, fileType_1, image.width, image.height]);
62
+ });
63
+ return;
64
+ }
65
+ // file inputs
66
+ if (!window.FileReader) {
67
+ reject(new Error('No File Reader'));
68
+ return;
69
+ }
70
+ var reader = new FileReader();
71
+ reader.onload = function (event) {
72
+ var _a, _b;
73
+ if (options.width || options.height) {
74
+ // resize
75
+ Media.resize((_a = event.target) === null || _a === void 0 ? void 0 : _a.result, file.type, options.width, options.height).then(function (args) {
76
+ var image = args[0], dataURI = args[1];
77
+ fulfill([dataURI, file.type, image.width, image.height]);
78
+ });
79
+ }
80
+ else {
81
+ var image_1 = new window.Image(); // native one
82
+ image_1.onload = function () {
83
+ var _a;
84
+ var type = file.type.replace(/.*\/([a-z]+)$/i, '$1');
85
+ fulfill([(_a = event.target) === null || _a === void 0 ? void 0 : _a.result, type, image_1.width, image_1.height]);
86
+ };
87
+ image_1.src = (_b = event.target) === null || _b === void 0 ? void 0 : _b.result;
88
+ }
89
+ };
90
+ reader.readAsDataURL(file);
91
+ });
92
+ return promise;
93
+ };
94
+ /**
95
+ * http://stackoverflow.com/questions/2516117/how-to-scale-an-image-in-data-uri-format-in-javascript-real-scaling-not-usin
96
+ */
97
+ Media.resize = function (data, fileType, MAX_WIDTH, MAX_HEIGHT) {
98
+ var promise = new Promise(function (fulfill) {
99
+ var image = new window.Image(); // native one
100
+ image.onload = function () {
101
+ var _a;
102
+ var width = image.width;
103
+ var height = image.height;
104
+ var maxWidth = !MAX_WIDTH || MAX_WIDTH > width ? width : MAX_WIDTH;
105
+ var maxHeight = !MAX_HEIGHT || MAX_HEIGHT > height ? height : MAX_HEIGHT;
106
+ var res = null;
107
+ // resizing
108
+ if (width > height) {
109
+ res = width / maxWidth;
110
+ }
111
+ else {
112
+ res = height / maxHeight;
113
+ }
114
+ width /= res;
115
+ height /= res;
116
+ // Create a canvas with the desired dimensions
117
+ var canvas = document.createElement('canvas');
118
+ canvas.width = width;
119
+ canvas.height = height;
120
+ // Scale and draw the source image to the canvas
121
+ (_a = canvas.getContext('2d')) === null || _a === void 0 ? void 0 : _a.drawImage(image, 0, 0, width, height);
122
+ // Convert the canvas to a data URL in some format
123
+ fulfill([image, canvas.toDataURL(fileType)]);
124
+ };
125
+ image.src = data;
126
+ });
127
+ return promise;
128
+ };
129
+ /**
130
+ * Create new image model with a photo
131
+ * @param ImageModel Class representing the model.
132
+ * @param imageURL
133
+ * @param dataDirPath
134
+ * @returns
135
+ */
136
+ Media.getImageModel = function (imageURL, dataDirPath, skipThumbnail) {
137
+ return tslib.__awaiter(this, void 0, void 0, function () {
138
+ var MediaClass, width, height, data, image, imageModel;
139
+ var _a;
140
+ return tslib.__generator(this, function (_b) {
141
+ switch (_b.label) {
142
+ case 0:
143
+ MediaClass = this;
144
+ if (!imageURL) {
145
+ throw new Error('File not found while creating image model.');
146
+ }
147
+ if (!isHybrid) return [3 /*break*/, 2];
148
+ return [4 /*yield*/, utils.createImage(imageURL)];
149
+ case 1:
150
+ image = _b.sent();
151
+ width = image.width;
152
+ height = image.height;
153
+ data = imageURL.split('/').pop();
154
+ return [3 /*break*/, 4];
155
+ case 2: return [4 /*yield*/, MediaClass.getDataURI(imageURL, {
156
+ width: 2000,
157
+ height: 2000,
158
+ })];
159
+ case 3:
160
+ _a = _b.sent(), data = _a[0], width = _a[2], height = _a[3];
161
+ _b.label = 4;
162
+ case 4:
163
+ imageModel = new MediaClass({
164
+ attrs: {
165
+ data: data,
166
+ type: 'jpeg',
167
+ width: width,
168
+ height: height,
169
+ path: dataDirPath,
170
+ },
171
+ });
172
+ if (!!skipThumbnail) return [3 /*break*/, 6];
173
+ return [4 /*yield*/, imageModel.addThumbnail()];
174
+ case 5:
175
+ _b.sent();
176
+ _b.label = 6;
177
+ case 6: return [2 /*return*/, imageModel];
178
+ }
179
+ });
180
+ });
181
+ };
182
+ Media.prototype.toJSON = function () {
183
+ var data = _super.prototype.toJSON.call(this);
184
+ return JSON.parse(JSON.stringify(tslib.__assign(tslib.__assign({}, data), { metadata: mobx.toJS(this.metadata) || {} })));
185
+ };
186
+ Media.prototype.setupdatedAtTimestamp = function (newUpdatedAt) {
187
+ var _a;
188
+ _super.prototype.setUpdatedAtTimestamp.call(this, newUpdatedAt);
189
+ (_a = this.parent) === null || _a === void 0 ? void 0 : _a.setUpdatedAtTimestamp(newUpdatedAt);
190
+ };
191
+ Media.prototype.getSubmission = function (warehouseMediaNames) {
192
+ if (warehouseMediaNames === void 0) { warehouseMediaNames = {}; }
193
+ var queued = warehouseMediaNames[this.cid];
194
+ if (!this.id && !queued) {
195
+ throw new Error('Image ID or queued ID is missing.');
196
+ }
197
+ var submission = {
198
+ values: {
199
+ caption: this.attrs.caption,
200
+ },
201
+ };
202
+ if (this.id) {
203
+ submission.values.id = this.id;
204
+ }
205
+ else {
206
+ submission.values.queued = queued.name;
207
+ }
208
+ return submission;
209
+ };
210
+ Media.prototype.sync = function () {
211
+ return tslib.__awaiter(this, void 0, void 0, function () {
212
+ return tslib.__generator(this, function (_a) {
213
+ return [2 /*return*/, this.parent ? this.parent.sync() : _super.prototype.sync.call(this)];
214
+ });
215
+ });
216
+ };
217
+ Media.prototype.uploadFile = function () {
218
+ return tslib.__awaiter(this, arguments, void 0, function (force) {
219
+ var twelveHrsAgo, alreadySynced, formData, data, headers, _a, res;
220
+ var _b;
221
+ var _c;
222
+ if (force === void 0) { force = false; }
223
+ return tslib.__generator(this, function (_d) {
224
+ switch (_d.label) {
225
+ case 0:
226
+ if (this.id) {
227
+ throw new Error('A file of a media on the remote cannot be uploaded again.');
228
+ }
229
+ twelveHrsAgo = Date.now() - 1000 * 60 * 60 * 12;
230
+ alreadySynced = this.syncedAt > twelveHrsAgo && this.attrs.queued;
231
+ if (!force && alreadySynced)
232
+ return [2 /*return*/];
233
+ return [4 /*yield*/, this.getFormData()];
234
+ case 1:
235
+ formData = _d.sent();
236
+ data = new FormData();
237
+ (_b = data).append.apply(_b, formData);
238
+ if (!(typeof this.remote.headers === 'function')) return [3 /*break*/, 3];
239
+ return [4 /*yield*/, this.remote.headers()];
240
+ case 2:
241
+ _a = _d.sent();
242
+ return [3 /*break*/, 4];
243
+ case 3:
244
+ _a = this.remote.headers;
245
+ _d.label = 4;
246
+ case 4:
247
+ headers = _a;
248
+ return [4 /*yield*/, axios__default["default"].post("".concat(this.remote.url, "/media-queue"), data, {
249
+ headers: headers,
250
+ timeout: 120000,
251
+ })];
252
+ case 5:
253
+ res = _d.sent();
254
+ if (!((_c = res.data[this.cid]) === null || _c === void 0 ? void 0 : _c.name))
255
+ throw new Error('New remote media name was not be found.');
256
+ this.attrs.queued = res.data[this.cid].name;
257
+ this.syncedAt = new Date().getTime();
258
+ return [2 /*return*/];
259
+ }
260
+ });
261
+ });
262
+ };
263
+ Media.prototype.getFormData = function () {
264
+ return tslib.__awaiter(this, void 0, void 0, function () {
265
+ var type, extension, mediaType, url, blob, name;
266
+ var _a;
267
+ return tslib.__generator(this, function (_b) {
268
+ switch (_b.label) {
269
+ case 0:
270
+ type = this.attrs.type;
271
+ extension = type;
272
+ mediaType = type;
273
+ if (type === null || type === void 0 ? void 0 : type.match(/image.*/)) {
274
+ _a = type.split('/'), extension = _a[1];
275
+ }
276
+ else {
277
+ mediaType = "image/".concat(mediaType);
278
+ }
279
+ url = this.getURL();
280
+ return [4 /*yield*/, helpers.getBlobFromURL(url, mediaType)];
281
+ case 1:
282
+ blob = _b.sent();
283
+ name = this.cid;
284
+ return [2 /*return*/, [name, blob, "".concat(name, ".").concat(extension)]];
285
+ }
286
+ });
287
+ });
288
+ };
289
+ Media.prototype.getRemoteURL = function () {
290
+ if (!this.remote.url) {
291
+ throw new Error('No remote url was set.');
292
+ }
293
+ if (!this.attrs.queued && !this.attrs.path) {
294
+ throw new Error('No media queued or path attribute.');
295
+ }
296
+ var baseRemoteURL = this.remote.url.replace('/index.php/services/rest', '');
297
+ if (this.attrs.queued) {
298
+ return "".concat(baseRemoteURL, "/upload-queue/").concat(this.attrs.queued);
299
+ }
300
+ return "".concat(baseRemoteURL, "/upload/").concat(this.attrs.path);
301
+ };
302
+ /**
303
+ * Returns image's absolute URL or dataURI.
304
+ */
305
+ Media.prototype.getURL = function () {
306
+ return this.attrs.data;
307
+ };
308
+ /**
309
+ * Resizes itself.
310
+ */
311
+ Media.prototype.resize = function (MAX_WIDTH, MAX_HEIGHT) {
312
+ var _this = this;
313
+ var that = this;
314
+ var promise = new Promise(function (fulfill, reject) {
315
+ Media.resize(_this.getURL(), _this.attrs.type, MAX_WIDTH, MAX_HEIGHT)
316
+ .then(function (args) {
317
+ var image = args[0], data = args[1];
318
+ that.attrs.data = data;
319
+ fulfill([image, data]);
320
+ })
321
+ .catch(reject);
322
+ });
323
+ return promise;
324
+ };
325
+ /**
326
+ * Adds a thumbnail to image model.
327
+ * @param options
328
+ */
329
+ Media.prototype.addThumbnail = function (options) {
330
+ var _this = this;
331
+ var that = this;
332
+ var promise = new Promise(function (fulfill, reject) {
333
+ // check if data source is dataURI
334
+ var re = /^data:/i;
335
+ if (re.test(_this.getURL())) {
336
+ Media.resize(_this.getURL(), _this.attrs.type, THUMBNAIL_WIDTH , THUMBNAIL_WIDTH )
337
+ .then(function (args) {
338
+ var data = args[1];
339
+ that.attrs.thumbnail = data;
340
+ fulfill();
341
+ })
342
+ .catch(reject);
343
+ return;
344
+ }
345
+ Media.getDataURI(_this.getURL(), {
346
+ width: THUMBNAIL_WIDTH ,
347
+ height: THUMBNAIL_HEIGHT ,
348
+ })
349
+ .then(function (data) {
350
+ that.attrs.thumbnail = data[0];
351
+ fulfill();
352
+ })
353
+ .catch(reject);
354
+ });
355
+ return promise;
356
+ };
357
+ Media.prototype.isUploaded = function () {
358
+ if (!this.parent) {
359
+ throw new Error('No media parent to return disabled status.');
360
+ }
361
+ return this.parent.isUploaded();
362
+ };
363
+ Media.prototype.isDisabled = function () {
364
+ return this.isUploaded();
365
+ };
366
+ return Media;
367
+ }(Model["default"]));
368
+
369
+ exports["default"] = Media;
@@ -61,19 +61,19 @@ export default class Occurrence<T extends Attrs = Attrs, S extends Metadata = Me
61
61
  };
62
62
  training: {
63
63
  id: string;
64
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
64
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
65
65
  };
66
66
  deleted: {
67
67
  id: string;
68
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
68
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
69
69
  };
70
70
  confidential: {
71
71
  id: string;
72
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
72
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
73
73
  };
74
74
  zeroAbundance: {
75
75
  id: string;
76
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
76
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
77
77
  };
78
78
  };
79
79
  metadata: S;
@@ -100,10 +100,10 @@ export default class Occurrence<T extends Attrs = Attrs, S extends Metadata = Me
100
100
  getSurvey(): {
101
101
  attrs?: {
102
102
  [key: string]: {
103
- remote?: RemoteConfig | undefined;
103
+ remote?: RemoteConfig;
104
104
  };
105
- } | undefined;
106
- modifySubmission?: ((submission: any, model: any) => any) | undefined;
105
+ };
106
+ modifySubmission?: (submission: any, model: any) => any;
107
107
  };
108
108
  isUploaded(): boolean;
109
109
  isDisabled(): boolean;
@@ -1 +1,220 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("tslib"),e=require("mobx"),r=require("lodash"),i=require("../Model.js"),a=require("./Media.js"),n=require("./helpers.js"),o=function(i){function o(r){var a=this;void 0===r&&(r={});var n=r.metadata,s=void 0===n?{}:n,u=r.media,d=void 0===u?[]:u,c=t.__rest(r,["metadata","media"]);(a=i.call(this,c)||this).debouncedValue=300,a.keys=function(){var e;return t.__assign(t.__assign({},o.keys),(e=a.getSurvey().attrs||{},Object.keys(e).reduce((function(r,i){var a;return t.__assign(t.__assign({},r),((a={})[i]=e[i].remote||e[i],a))}),{})))},a.metadata=e.observable(s),a.media=e.observable(d);var l=function(t){return t.parent=a};a.media.forEach(l);return e.intercept(a.media,(function(t){var e;return(null===(e=t.added)||void 0===e?void 0:e.length)?(t.added.forEach(l),a.setUpdatedAtTimestamp(Date.now())):t.removedCount&&a.setUpdatedAtTimestamp(Date.now()),t})),a}return t.__extends(o,i),o.fromJSON=function(e,r){var i,n,o,s;return void 0===r&&(r=a.default),new this(t.__assign(t.__assign({},e),{createdAt:e.createdAt||(null===(i=e.metadata)||void 0===i?void 0:i.createdOn),updatedAt:e.updatedAt||(null===(n=e.metadata)||void 0===n?void 0:n.updatedOn),syncedAt:e.syncedAt||(null===(o=e.metadata)||void 0===o?void 0:o.syncedOn),media:null===(s=e.media)||void 0===s?void 0:s.map((function(t){return r.fromJSON(t)}))}))},o.prototype.setUpdatedAtTimestamp=function(t){var e;i.prototype.setUpdatedAtTimestamp.call(this,t),null===(e=this.parent)||void 0===e||e.setUpdatedAtTimestamp(t)},o.prototype.save=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){if(!this.parent)throw new Error("Trying to save locally without a parent");return this.parent.save(),[2]}))}))},o.prototype.destroy=function(e){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){switch(t.label){case 0:if(!this.parent)throw new Error("Trying to destroy locally without a parent");return this.parent.occurrences.remove(this),[4,Promise.all(this.media.map((function(t){return t.destroy(!0)})))];case 1:return t.sent(),e?[2]:[4,this.parent.save()];case 2:return t.sent(),[2]}}))}))},o.prototype.sync=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){return[2,this.parent?this.parent.sync():i.prototype.sync.call(this)]}))}))},o.prototype.toJSON=function(){var r,a=i.prototype.toJSON.call(this);return JSON.parse(JSON.stringify(t.__assign(t.__assign({},a),{media:(null===(r=this.media)||void 0===r?void 0:r.map((function(t){return t.toJSON()})))||[],metadata:e.toJS(this.metadata)||{}})))},o.prototype.getSurvey=function(){return this.parent&&this.parent.getSurvey().occ||{}},o.prototype.isUploaded=function(){if(!this.parent)throw new Error("No occurrence parent to return disabled status.");return this.parent.isUploaded()},o.prototype.isDisabled=function(){return this.isUploaded()},o.prototype.getSubmission=function(e){var i=this;void 0===e&&(e={});var a="function"==typeof this.keys?this.keys():this.keys,n=t.__assign(t.__assign({},o.keys),a),s={values:{external_key:this.cid},media:[]};this.id&&(s.values.id=this.id);Object.keys(this.attrs).forEach((function(t){var e=i.attrs[t],a=function(t){return null==t};if(!a(e)){if(!n[t])return t=t.includes("occAttr:")?t:r.snakeCase(t),void(s.values[t]=e);var o=n[t].id||t;if(e=function(t,e){var r=n[t].values;if(!r)return e;if("function"==typeof r)return r(e,s,i);if(r instanceof Array){var a=r.find((function(t){return t.value===e}));if(!a||!a.id)throw new Error('A "'.concat(t,'" attribute "').concat(e,'" value could not be mapped to a remote database field.'));return a.id}return e instanceof Array?e.map((function(t){return r[t]})):r[e]}(t,e),!a(e)){var u=Number.isNaN(Number(o))?o:"occAttr:".concat(o);u=u.includes("occAttr:")?u:r.snakeCase(u),s.values[u]=e}}})),this.media.forEach((function(t){var r=t.getSubmission(e);r&&s.media.push(r)}));var u=this.getSurvey();return u.modifySubmission?u.modifySubmission(s,this):s},o.keys={taxon:{id:"taxa_taxon_list_id"},training:{id:"training",values:n.boolToWarehouseValue},deleted:{id:"deleted",values:n.boolToWarehouseValue},confidential:{id:"confidential",values:n.boolToWarehouseValue},zeroAbundance:{id:"zero_abundance",values:n.boolToWarehouseValue}},o}(i.default);exports.default=o;
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var mobx = require('mobx');
7
+ var lodash = require('lodash');
8
+ var Model = require('../Model.js');
9
+ var Media = require('./Media.js');
10
+ var helpers = require('./helpers.js');
11
+
12
+ var Occurrence = /** @class */ (function (_super) {
13
+ tslib.__extends(Occurrence, _super);
14
+ function Occurrence(_a) {
15
+ if (_a === void 0) { _a = {}; }
16
+ var _this = this;
17
+ var _b = _a.metadata, metadata = _b === void 0 ? {} : _b, _c = _a.media, media = _c === void 0 ? [] : _c, options = tslib.__rest(_a, ["metadata", "media"]);
18
+ _this = _super.call(this, options) || this;
19
+ _this.debouncedValue = 300;
20
+ _this.keys = function () {
21
+ var getRemoteProps = function (attrs) {
22
+ var extractRemoteIfExists = function (agg, key) {
23
+ var _a;
24
+ return (tslib.__assign(tslib.__assign({}, agg), (_a = {}, _a[key] = attrs[key].remote || attrs[key], _a)));
25
+ };
26
+ return Object.keys(attrs).reduce(extractRemoteIfExists, {});
27
+ };
28
+ return tslib.__assign(tslib.__assign({}, Occurrence.keys), getRemoteProps(_this.getSurvey().attrs || {}));
29
+ };
30
+ _this.metadata = mobx.observable(metadata);
31
+ _this.media = mobx.observable(media);
32
+ // eslint-disable-next-line no-param-reassign, no-return-assign
33
+ var attachParent = function (model) { return (model.parent = _this); };
34
+ _this.media.forEach(attachParent);
35
+ var onAddedSetParentAndUpdateTime = function (change) {
36
+ var _a;
37
+ if ((_a = change.added) === null || _a === void 0 ? void 0 : _a.length) {
38
+ change.added.forEach(attachParent);
39
+ _this.setUpdatedAtTimestamp(Date.now());
40
+ }
41
+ else if (change.removedCount) {
42
+ _this.setUpdatedAtTimestamp(Date.now());
43
+ }
44
+ return change;
45
+ };
46
+ mobx.intercept(_this.media, onAddedSetParentAndUpdateTime);
47
+ return _this;
48
+ }
49
+ Occurrence.fromJSON = function (json, MediaClass) {
50
+ var _a, _b, _c, _d;
51
+ if (MediaClass === void 0) { MediaClass = Media["default"]; }
52
+ var occurrence = new this(tslib.__assign(tslib.__assign({}, json), { createdAt: json.createdAt || ((_a = json.metadata) === null || _a === void 0 ? void 0 : _a.createdOn), updatedAt: json.updatedAt || ((_b = json.metadata) === null || _b === void 0 ? void 0 : _b.updatedOn), syncedAt: json.syncedAt || ((_c = json.metadata) === null || _c === void 0 ? void 0 : _c.syncedOn), media: (_d = json.media) === null || _d === void 0 ? void 0 : _d.map(function (mJson) { return MediaClass.fromJSON(mJson); }) }));
53
+ return occurrence;
54
+ };
55
+ Occurrence.prototype.setUpdatedAtTimestamp = function (newUpdatedAt) {
56
+ var _a;
57
+ _super.prototype.setUpdatedAtTimestamp.call(this, newUpdatedAt);
58
+ (_a = this.parent) === null || _a === void 0 ? void 0 : _a.setUpdatedAtTimestamp(newUpdatedAt);
59
+ };
60
+ /**
61
+ * Save the model to the offline store.
62
+ */
63
+ Occurrence.prototype.save = function () {
64
+ return tslib.__awaiter(this, void 0, void 0, function () {
65
+ return tslib.__generator(this, function (_a) {
66
+ if (!this.parent) {
67
+ throw new Error('Trying to save locally without a parent');
68
+ }
69
+ this.parent.save();
70
+ return [2 /*return*/];
71
+ });
72
+ });
73
+ };
74
+ /**
75
+ * Destroy the model and remove from the offline store.
76
+ */
77
+ Occurrence.prototype.destroy = function (silent) {
78
+ return tslib.__awaiter(this, void 0, void 0, function () {
79
+ return tslib.__generator(this, function (_a) {
80
+ switch (_a.label) {
81
+ case 0:
82
+ if (!this.parent) {
83
+ throw new Error('Trying to destroy locally without a parent');
84
+ }
85
+ this.parent.occurrences.remove(this);
86
+ return [4 /*yield*/, Promise.all(this.media.map(function (media) { return media.destroy(true); }))];
87
+ case 1:
88
+ _a.sent();
89
+ if (silent)
90
+ return [2 /*return*/];
91
+ return [4 /*yield*/, this.parent.save()];
92
+ case 2:
93
+ _a.sent();
94
+ return [2 /*return*/];
95
+ }
96
+ });
97
+ });
98
+ };
99
+ Occurrence.prototype.sync = function () {
100
+ return tslib.__awaiter(this, void 0, void 0, function () {
101
+ return tslib.__generator(this, function (_a) {
102
+ return [2 /*return*/, this.parent ? this.parent.sync() : _super.prototype.sync.call(this)];
103
+ });
104
+ });
105
+ };
106
+ /**
107
+ * Returns a clean (no observables) JSON representation of the model.
108
+ */
109
+ Occurrence.prototype.toJSON = function () {
110
+ var _a;
111
+ var data = _super.prototype.toJSON.call(this);
112
+ return JSON.parse(JSON.stringify(tslib.__assign(tslib.__assign({}, data), { media: ((_a = this.media) === null || _a === void 0 ? void 0 : _a.map(function (model) { return model.toJSON(); })) || [], metadata: mobx.toJS(this.metadata) || {} })));
113
+ };
114
+ Occurrence.prototype.getSurvey = function () {
115
+ if (!this.parent)
116
+ return {};
117
+ var survey = this.parent.getSurvey();
118
+ return survey.occ || {};
119
+ };
120
+ Occurrence.prototype.isUploaded = function () {
121
+ if (!this.parent) {
122
+ throw new Error('No occurrence parent to return disabled status.');
123
+ }
124
+ return this.parent.isUploaded();
125
+ };
126
+ Occurrence.prototype.isDisabled = function () {
127
+ return this.isUploaded();
128
+ };
129
+ /**
130
+ * Returns an object with attributes and their values
131
+ * mapped for warehouse submission.
132
+ */
133
+ Occurrence.prototype.getSubmission = function (warehouseMediaNames) {
134
+ var _this = this;
135
+ if (warehouseMediaNames === void 0) { warehouseMediaNames = {}; }
136
+ var occKeys = typeof this.keys === 'function' ? this.keys() : this.keys;
137
+ var keys = tslib.__assign(tslib.__assign({}, Occurrence.keys), occKeys); // warehouse keys/values to transform
138
+ var submission = {
139
+ values: {
140
+ external_key: this.cid,
141
+ },
142
+ media: [],
143
+ };
144
+ if (this.id) {
145
+ submission.values.id = this.id;
146
+ }
147
+ var mapValue = function (attr, value) {
148
+ var valuesMapping = keys[attr].values;
149
+ if (!valuesMapping) {
150
+ return value;
151
+ }
152
+ if (typeof valuesMapping === 'function') {
153
+ return valuesMapping(value, submission, _this);
154
+ }
155
+ if (valuesMapping instanceof Array) {
156
+ var mapping = valuesMapping.find(function (_a) {
157
+ var val = _a.value;
158
+ return val === value;
159
+ });
160
+ if (!mapping || !mapping.id) {
161
+ throw new Error("A \"".concat(attr, "\" attribute \"").concat(value, "\" value could not be mapped to a remote database field."));
162
+ }
163
+ return mapping.id;
164
+ }
165
+ if (value instanceof Array) {
166
+ return value.map(function (v) { return valuesMapping[v]; });
167
+ }
168
+ return valuesMapping[value];
169
+ };
170
+ var getValue = function (attr) {
171
+ // no need to send attributes with no values
172
+ var value = _this.attrs[attr];
173
+ var isEmpty = function (val) { return val === null || val === undefined; };
174
+ if (isEmpty(value)) {
175
+ return;
176
+ }
177
+ if (!keys[attr]) {
178
+ attr = attr.includes('occAttr:') ? attr : lodash.snakeCase(attr);
179
+ submission.values[attr] = value;
180
+ return;
181
+ }
182
+ var warehouseAttr = keys[attr].id || attr;
183
+ value = mapValue(attr, value);
184
+ if (isEmpty(value)) {
185
+ return;
186
+ }
187
+ var attrKey = !Number.isNaN(Number(warehouseAttr))
188
+ ? "occAttr:".concat(warehouseAttr)
189
+ : warehouseAttr;
190
+ attrKey = attrKey.includes('occAttr:') ? attrKey : lodash.snakeCase(attrKey);
191
+ submission.values[attrKey] = value;
192
+ };
193
+ Object.keys(this.attrs).forEach(getValue);
194
+ this.media.forEach(function (model) {
195
+ var modelSubmission = model.getSubmission(warehouseMediaNames);
196
+ if (!modelSubmission) {
197
+ return;
198
+ }
199
+ submission.media.push(modelSubmission);
200
+ });
201
+ var survey = this.getSurvey();
202
+ if (survey.modifySubmission) {
203
+ return survey.modifySubmission(submission, this);
204
+ }
205
+ return submission;
206
+ };
207
+ /**
208
+ * Warehouse attributes and their values.
209
+ */
210
+ Occurrence.keys = {
211
+ taxon: { id: 'taxa_taxon_list_id' },
212
+ training: { id: 'training', values: helpers.boolToWarehouseValue },
213
+ deleted: { id: 'deleted', values: helpers.boolToWarehouseValue },
214
+ confidential: { id: 'confidential', values: helpers.boolToWarehouseValue },
215
+ zeroAbundance: { id: 'zero_abundance', values: helpers.boolToWarehouseValue },
216
+ };
217
+ return Occurrence;
218
+ }(Model["default"]));
219
+
220
+ exports["default"] = Occurrence;
@@ -86,11 +86,11 @@ declare class Sample<T extends Attrs = Attrs, S extends Metadata = Metadata> ext
86
86
  };
87
87
  training: {
88
88
  id: string;
89
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
89
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
90
90
  };
91
91
  deleted: {
92
92
  id: string;
93
- values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
93
+ values: (val?: boolean | "t" | "f" | null) => "t" | "f";
94
94
  };
95
95
  };
96
96
  /**