@flumens/models 0.0.1

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # @flumens/models
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("mobx");function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=t(require("@flumens/utils/dist/uuid"));const s={async reset(){for(;this.length;){const e=this.pop();if(!e)return;await e.destroy()}},async _fromStore(){if(!this._store||!this.Model)return!1;const e=(await this._store.findAll()).map((e=>new this.Model(e)));return this.push(...e),!0}};exports.default=function({models:t=[],id:o="",cid:i="",store:n,Model:u}){const d=e.observable([...t]);return Object.assign(d,s,{_store:n,Model:u}),d.id=o,d.cid=i||o||r.default(),d.ready=d._fromStore(),d};
@@ -0,0 +1,70 @@
1
+ import { AnySchema } from 'yup';
2
+ import Model, { Attrs as GenericModelAttrs, Options as GenericModelOptions } from './Model';
3
+ export type BackendConfig = {
4
+ /**
5
+ * Site URL without a trailing slash.
6
+ */
7
+ url: string;
8
+ /**
9
+ * Consumer ID.
10
+ */
11
+ clientId: string;
12
+ /**
13
+ * Consumer secret.
14
+ */
15
+ clientPass?: string;
16
+ /**
17
+ * User scopes (roles to fetch).
18
+ */
19
+ scopes?: string[];
20
+ };
21
+ export interface Attrs extends GenericModelAttrs {
22
+ email?: string;
23
+ verified?: boolean;
24
+ indiciaUserId?: number;
25
+ iss?: string;
26
+ roles?: string[];
27
+ tokens?: {
28
+ access_token: string;
29
+ refresh_token: string;
30
+ expires_in: number;
31
+ token_type: string;
32
+ };
33
+ }
34
+ export interface Options extends GenericModelOptions {
35
+ /**
36
+ * Drupal site config.
37
+ */
38
+ config: BackendConfig;
39
+ }
40
+ export default class DrupalUserModel extends Model {
41
+ config: BackendConfig;
42
+ attrs: Attrs;
43
+ loginSchema: AnySchema;
44
+ loginSchemaBackend: AnySchema;
45
+ resetSchema: AnySchema;
46
+ registerSchema: AnySchema;
47
+ registerSchemaBackend: AnySchema;
48
+ private _refreshingProfilePromise?;
49
+ private _refreshingTokenPromise?;
50
+ constructor({ config, ...options }: Options);
51
+ logIn(email: string, password: string): Promise<void>;
52
+ register(email: string, password: string, otherFields: any): Promise<void>;
53
+ reset(email: string): Promise<void>;
54
+ delete(): Promise<void>;
55
+ /**
56
+ * Gets full user profile inc. fresh new tokens.
57
+ */
58
+ refreshProfile(): Promise<void>;
59
+ /**
60
+ * @deprecated The method should not be used. Use isLoggedIn instead.
61
+ */
62
+ hasLogIn(): boolean;
63
+ isLoggedIn(): boolean;
64
+ logOut(): Promise<void>;
65
+ resetDefaults(defaultsToSet?: any): Promise<void>;
66
+ getAccessToken(forceRefresh?: boolean): Promise<string | undefined>;
67
+ protected _sendVerificationEmail(email?: string): Promise<import("axios").AxiosResponse<any, any>>;
68
+ private _exchangePasswordToTokens;
69
+ private _refreshAccessToken;
70
+ }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("axios"),r=require("jwt-decode"),s=require("yup"),i=require("@flumens/utils/dist/errors"),n=require("./Model.js");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=a(t);function c(e,t){Object.keys(t).forEach((function(r){if(r.match(/^field_/)){var s=r.replace("field_","").replace(/_([a-z])/g,(function(e){return e[1].toUpperCase()}));if(!t[r])return;if(Array.isArray(t[r])&&t[r].length)return void(e[s]=t[r][0].value);e[s]=t[r]}}))}var u=function(e){var t;if(e.response&&e.response.data&&e.response.data.message){if(e.response.data.message.includes("is already taken"))throw new i.HandledError("This email is already taken.");if("The user credentials were incorrect."===e.response.data.message)throw new i.HandledError("Incorrect password or email");if("Unrecognized username or email address."===e.response.data.message)throw new i.HandledError("Unrecognized email address.");if("This account is already activated"===e.response.data.message)throw new i.HandledError("This account is already activated.");if(e.response.data.message.includes("not been activated"))throw new i.HandledError("The user has not been activated or is blocked.");throw new Error(e.response.data.message)}if(null===(t=e.message)||void 0===t?void 0:t.includes("timeout"))throw new i.HandledError("Timeout");throw e},h=6e4;var d={email:"",tokens:void 0,verified:!1,iss:void 0,indiciaUserId:void 0},l=function(t){function i(r){var i=this,a=r.config,o=e.__rest(r,["config"]);return(i=t.call(this,o)||this).attrs=n.default.extendAttrs(i.attrs,d),i.loginSchema=s.object().shape({email:s.string().email().required(),password:s.string().required()}),i.loginSchemaBackend=s.object().shape({id:s.number().required(),email:s.string().email().required()}),i.resetSchema=s.object().shape({email:s.string().email().required()}),i.registerSchema=s.object().shape({email:s.string().email().required(),password:s.string().required()}),i.registerSchemaBackend=s.object().shape({uid:s.array().of(s.object().shape({value:s.number().required()}))}),i.config=a,i}return e.__extends(i,t),i.prototype.logIn=function(t,r){return e.__awaiter(this,void 0,void 0,(function(){var s;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this._exchangePasswordToTokens(t,r)];case 1:return s=e.sent(),this.attrs.tokens=s,[4,this.refreshProfile()];case 2:return e.sent(),[2,this.save()]}}))}))},i.prototype.register=function(t,r,s){return e.__awaiter(this,void 0,void 0,(function(){var i,n,a,d;return e.__generator(this,(function(l){switch(l.label){case 0:return i=JSON.stringify(e.__assign({name:[{value:t}],pass:[{value:r}],mail:[{value:t}]},s)),n={method:"post",url:"".concat(this.config.url,"/user/register-with-password?_format=json"),headers:{"content-type":"application/json"},data:i,timeout:h},[4,o.default(n).catch(u)];case 1:return a=l.sent().data,[4,this.registerSchemaBackend.isValid(a)];case 2:if(!l.sent())throw new Error("Invalid backend response.");return[4,this._exchangePasswordToTokens(t,r)];case 3:return d=l.sent(),this.attrs.tokens=d,this.id=a.uid[0].value,this.attrs.email=t,c(this.attrs,a),[2,this.save()]}}))}))},i.prototype.reset=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,s,i;return e.__generator(this,(function(e){switch(e.label){case 0:r=JSON.stringify({mail:t}),s={method:"post",url:"".concat(this.config.url,"/user/password?_format=json"),headers:{"content-type":"application/json"},data:r},e.label=1;case 1:return e.trys.push([1,3,,6]),[4,o.default(s).catch(u)];case 2:return e.sent(),[3,6];case 3:return"The user has not been activated or is blocked."!==(i=e.sent()).message?[3,5]:[4,this._sendVerificationEmail(t)];case 4:return e.sent(),[2];case 5:return u(i),[3,6];case 6:return[2]}}))}))},i.prototype.delete=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.getAccessToken(!0)];case 1:return t=e.sent(),r={method:"delete",url:"".concat(this.config.url,"/user/").concat(this.id,"?_format=json"),headers:{Authorization:"Bearer ".concat(t)}},[4,o.default(r).catch(u)];case 2:return e.sent(),this.logOut(),[2]}}))}))},i.prototype.refreshProfile=function(){return e.__awaiter(this,void 0,void 0,(function(){var t=this;return e.__generator(this,(function(r){return this._refreshingProfilePromise||(this._refreshingProfilePromise=Promise.resolve().then((function(){return e.__awaiter(t,void 0,void 0,(function(){var t,r,s;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.getAccessToken(!0)];case 1:return t=e.sent(),this.attrs.verified?(r={url:"".concat(this.config.url,"/user/").concat(this.id,"?_format=json"),headers:{Authorization:"Bearer ".concat(t)},timeout:h},[4,o.default(r).catch(u)]):[3,3];case 2:s=e.sent().data,this.attrs.email=s.mail[0].value,c(this.attrs,s),e.label=3;case 3:return[4,this.save()];case 4:return e.sent(),delete this._refreshingProfilePromise,[2]}}))}))})).catch((function(e){throw delete t._refreshingProfilePromise,e}))),[2,this._refreshingProfilePromise]}))}))},i.prototype.hasLogIn=function(){return console.warn("hasLogIn is deprecated, please use isLoggedIn instead."),this.isLoggedIn()},i.prototype.isLoggedIn=function(){return this.attrs.email,!!this.id},i.prototype.logOut=function(){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){return[2,this.resetDefaults()]}))}))},i.prototype.resetDefaults=function(r){return t.prototype.resetDefaults.call(this,e.__assign(e.__assign({},d),r))},i.prototype.getAccessToken=function(t){var s;return e.__awaiter(this,void 0,void 0,(function(){var i,n,a,o,c;return e.__generator(this,(function(e){switch(e.label){case 0:if(!t&&!this.isLoggedIn())throw new Error("User is not logged in.");if(i=(this.attrs.tokens||{}).access_token,n=function(e){if(!e)return!0;var t=1e3*r.jwtDecode(e).exp;return Date.now()+12e4>t}(i),!(!i||n||t))return[3,6];e.label=1;case 1:return e.trys.push([1,3,,6]),[4,this._refreshAccessToken()];case 2:return e.sent(),[3,6];case 3:return a=e.sent(),console.error(a),o="The refresh token is invalid."===a.message,c="Token has no user email."===a.message,o||c?[4,this.logOut()]:[3,5];case 4:throw e.sent(),new Error("User re-login is required.");case 5:throw a;case 6:return[2,null===(s=this.attrs.tokens)||void 0===s?void 0:s.access_token]}}))}))},i.prototype._sendVerificationEmail=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,s;return e.__generator(this,(function(e){return r=JSON.stringify({mail:[{value:t||this.attrs.email}]}),s={method:"post",url:"".concat(this.config.url,"/user/register-with-password?_format=json&resendVerificationEmail=true"),headers:{"content-type":"application/json"},data:r,timeout:h},[2,o.default(s).catch(u)]}))}))},i.prototype._exchangePasswordToTokens=function(t,r){var s;return e.__awaiter(this,void 0,void 0,(function(){var i,n;return e.__generator(this,(function(e){switch(e.label){case 0:return(i=new FormData).append("grant_type","password"),i.append("username",t),i.append("password",r),i.append("client_id",this.config.clientId),this.config.clientPass&&i.append("client_secret",this.config.clientPass),(null===(s=this.config.scopes)||void 0===s?void 0:s.length)&&i.append("scope",this.config.scopes.join(" ")),n={method:"post",url:"".concat(this.config.url,"/oauth/token"),data:i},[4,o.default(n).catch(u)];case 1:return[2,e.sent().data]}}))}))},i.prototype._refreshAccessToken=function(){return e.__awaiter(this,void 0,void 0,(function(){var t=this;return e.__generator(this,(function(s){return this._refreshingTokenPromise||(this._refreshingTokenPromise=Promise.resolve().then((function(){return e.__awaiter(t,void 0,void 0,(function(){var t,s,i,n,a,d;return e.__generator(this,(function(l){switch(l.label){case 0:if(!(t=(this.attrs.tokens||{}).refresh_token))throw new Error("No user session refresh token was found");return(s=new FormData).append("grant_type","refresh_token"),s.append("refresh_token",t),s.append("client_id",this.config.clientId),this.config.clientPass&&s.append("client_secret",this.config.clientPass),i={method:"post",url:"".concat(this.config.url,"/oauth/token"),data:s,timeout:h},[4,o.default(i).catch(u)];case 1:if(n=l.sent().data,this.attrs.tokens=e.__assign(e.__assign({},this.attrs.tokens),n),a=r.jwtDecode(null===(d=this.attrs.tokens)||void 0===d?void 0:d.access_token),this.id=a.sub,this.attrs.email=a.email,!this.attrs.email)throw new Error("Token has no user email.");return this.attrs.verified=a.email_verified,this.attrs.iss=a.iss,this.attrs.indiciaUserId=a["http://indicia.org.uk/user:id"],a.scopes&&(this.attrs.roles=a.scopes),c(this.attrs,a),[4,this.save()];case 2:return l.sent(),delete this._refreshingTokenPromise,[2]}}))}))})).catch((function(e){throw delete t._refreshingTokenPromise,e}))),[2,this._refreshingTokenPromise]}))}))},i}(n.default);exports.default=l;
@@ -0,0 +1,138 @@
1
+ interface Attribute {
2
+ value: any;
3
+ id: string;
4
+ }
5
+ export interface Media {
6
+ type: string;
7
+ path: string;
8
+ }
9
+ interface Event {
10
+ date_start: string;
11
+ source_system_key: string;
12
+ parent_attributes: Attribute[];
13
+ week: string;
14
+ date_end: string;
15
+ ukbms_week: string;
16
+ month: string;
17
+ sampling_protocol: string;
18
+ event_id: string;
19
+ year: string;
20
+ date_type: string;
21
+ day_of_year: string;
22
+ event_remarks?: string;
23
+ recorded_by: string;
24
+ parent_event_id: string;
25
+ attributes?: Attribute[];
26
+ media?: Media[];
27
+ }
28
+ interface Square {
29
+ centre: string;
30
+ }
31
+ interface GridSquare {
32
+ '1km': Square;
33
+ srid: string;
34
+ '10km': Square;
35
+ '2km': Square;
36
+ }
37
+ interface HigherGeography {
38
+ name: string;
39
+ id: string;
40
+ type: string;
41
+ code: string;
42
+ }
43
+ interface Location {
44
+ input_sref: string;
45
+ output_sref: string;
46
+ verbatim_locality: string;
47
+ geom: string;
48
+ grid_square: GridSquare;
49
+ point: string;
50
+ output_sref_system: string;
51
+ coordinate_uncertainty_in_meters: string;
52
+ input_sref_system: string;
53
+ higher_geography: HigherGeography[];
54
+ }
55
+ interface Survey {
56
+ title: string;
57
+ id: string;
58
+ }
59
+ interface Website {
60
+ title: string;
61
+ id: string;
62
+ }
63
+ interface Metadata {
64
+ private: string;
65
+ trial: string;
66
+ sensitive: string;
67
+ survey: Survey;
68
+ tracking: string;
69
+ import_guid: string;
70
+ confidential: string;
71
+ created_by_id: string;
72
+ updated_on: string;
73
+ website: Website;
74
+ created_on: string;
75
+ release_status: string;
76
+ }
77
+ interface AutoChecks {
78
+ result: string;
79
+ enabled: string;
80
+ output: any[];
81
+ }
82
+ interface Verifier {
83
+ id: string;
84
+ name: string;
85
+ }
86
+ export type VerifiedStates = 'C' | 'V' | 'R';
87
+ interface Identification {
88
+ verification_status: VerifiedStates;
89
+ auto_checks: AutoChecks;
90
+ verification_substatus: string;
91
+ verified_on: string;
92
+ verifier: Verifier;
93
+ }
94
+ interface TaxonList {
95
+ title: string;
96
+ id: string;
97
+ }
98
+ interface Taxon {
99
+ taxa_taxon_list_id: string;
100
+ taxon_meaning_id: string;
101
+ group_id: string;
102
+ taxon_list: TaxonList;
103
+ accepted_name: string;
104
+ vernacular_name?: string;
105
+ species?: string;
106
+ group: string;
107
+ /**
108
+ * What user has selected.
109
+ */
110
+ taxon_name: string;
111
+ taxon_rank_sort_order: string;
112
+ taxon_rank: string;
113
+ input_group: string;
114
+ input_group_id: string;
115
+ }
116
+ export interface Occurrence {
117
+ zero_abundance: string;
118
+ source_system_key: string;
119
+ attributes?: Attribute[];
120
+ media?: Media[];
121
+ occurrence_remarks?: string;
122
+ individual_count?: string;
123
+ life_stage?: string;
124
+ }
125
+ export default interface Source {
126
+ event: Event;
127
+ date: string;
128
+ '@version': string;
129
+ '@timestamp': Date;
130
+ identification: Identification;
131
+ taxon: Taxon;
132
+ occurrence: Occurrence;
133
+ location: Location;
134
+ metadata: Metadata;
135
+ warehouse: string;
136
+ id: string;
137
+ }
138
+ export {};
@@ -0,0 +1,99 @@
1
+ interface Attribute {
2
+ value: any;
3
+ id: string;
4
+ }
5
+ export interface Media {
6
+ type: string;
7
+ path: string;
8
+ }
9
+ interface Event {
10
+ date_start: string;
11
+ source_system_key: string;
12
+ week: string;
13
+ date_end: string;
14
+ ukbms_week: string;
15
+ month: string;
16
+ sampling_protocol: string;
17
+ event_id: string;
18
+ parent_event_id?: string;
19
+ year: string;
20
+ date_type: string;
21
+ day_of_year: string;
22
+ recorded_by: string;
23
+ event_remarks?: string;
24
+ attributes: Attribute[];
25
+ media?: Media[];
26
+ }
27
+ interface Square {
28
+ centre: string;
29
+ }
30
+ interface GridSquare {
31
+ '1km': Square;
32
+ srid: string;
33
+ '10km': Square;
34
+ '2km': Square;
35
+ }
36
+ export interface HigherGeography {
37
+ name: string;
38
+ id: string;
39
+ type: string;
40
+ code: string;
41
+ }
42
+ interface Location {
43
+ code?: string;
44
+ name?: string;
45
+ input_sref: string;
46
+ output_sref: string;
47
+ verbatim_locality: string;
48
+ geom: string;
49
+ grid_square: GridSquare;
50
+ point: string;
51
+ output_sref_system: string;
52
+ coordinate_uncertainty_in_meters: string;
53
+ input_sref_system: string;
54
+ higher_geography: HigherGeography[];
55
+ }
56
+ interface Survey {
57
+ title: string;
58
+ id: string;
59
+ }
60
+ interface Website {
61
+ title: string;
62
+ id: string;
63
+ }
64
+ export interface Group {
65
+ title: string;
66
+ id: string;
67
+ }
68
+ interface Metadata {
69
+ private: string;
70
+ trial: string;
71
+ verification_status: string;
72
+ sensitive: string;
73
+ survey: Survey;
74
+ tracking: string;
75
+ confidential: string;
76
+ created_by_id: string;
77
+ updated_on: string;
78
+ website: Website;
79
+ created_on: string;
80
+ release_status: string;
81
+ input_form?: string;
82
+ group?: Group;
83
+ }
84
+ interface Stats {
85
+ count_taxa: string;
86
+ count_taxon_groups: string;
87
+ count_occurrences: string;
88
+ sum_individual_count: string;
89
+ }
90
+ export default interface Source {
91
+ event: Event;
92
+ location: Location;
93
+ metadata: Metadata;
94
+ '@version': string;
95
+ stats: Stats;
96
+ '@timestamp': Date;
97
+ id: string;
98
+ }
99
+ export {};
@@ -0,0 +1,88 @@
1
+ import Model, { Attrs as AttrsOriginal, Options as OptionsOriginal } from '../Model';
2
+ import Occurrence from './Occurrence';
3
+ import Sample from './Sample';
4
+ export interface Metadata {
5
+ }
6
+ export type DataURI = string;
7
+ export type URL = string;
8
+ export interface Options<T = any, S = any> extends OptionsOriginal<T> {
9
+ metadata?: S;
10
+ }
11
+ export interface Attrs extends AttrsOriginal {
12
+ type?: string;
13
+ data?: any;
14
+ thumbnail?: DataURI;
15
+ queued?: string | null;
16
+ path?: string | null;
17
+ width?: string | number;
18
+ height?: string | number;
19
+ caption?: string;
20
+ }
21
+ export interface Remote {
22
+ synchronising?: boolean;
23
+ url?: string | null;
24
+ headers?: any;
25
+ timeout?: number;
26
+ }
27
+ declare class Media<T extends Attrs = Attrs, S extends Metadata = Metadata> extends Model {
28
+ static fromJSON(json: any): Media<Attrs, Metadata>;
29
+ /**
30
+ * Transforms and resizes an image file into a string.
31
+ * Can accept file image path and a file input file.
32
+ *
33
+ * @param onError
34
+ * @param file
35
+ * @param onSaveSuccess
36
+ * @returns {number}
37
+ */
38
+ static getDataURI(file: any, options?: any): Promise<[
39
+ dataURI: DataURI,
40
+ fileType: string,
41
+ width: number,
42
+ height: number
43
+ ]>;
44
+ /**
45
+ * http://stackoverflow.com/questions/2516117/how-to-scale-an-image-in-data-uri-format-in-javascript-real-scaling-not-usin
46
+ */
47
+ static resize(data: URL | DataURI, fileType: string, MAX_WIDTH?: number, MAX_HEIGHT?: number): Promise<unknown>;
48
+ /**
49
+ * Create new image model with a photo
50
+ * @param ImageModel Class representing the model.
51
+ * @param imageURL
52
+ * @param dataDirPath
53
+ * @returns
54
+ */
55
+ static getImageModel(imageURL: URL, dataDirPath: string, skipThumbnail?: boolean): Promise<Media>;
56
+ attrs: T;
57
+ metadata: S;
58
+ remote: Remote;
59
+ debouncedValue: number;
60
+ constructor({ metadata, ...options }?: Options);
61
+ parent?: Sample | Occurrence;
62
+ toJSON(): any;
63
+ setupdatedAtTimestamp(newUpdatedAt: number): void;
64
+ getSubmission(warehouseMediaNames?: any): any;
65
+ sync(): Promise<void>;
66
+ uploadFile(): Promise<void>;
67
+ getFormData(): Promise<unknown[]>;
68
+ getRemoteURL(): string;
69
+ /**
70
+ * Returns image's absolute URL or dataURI.
71
+ */
72
+ getURL(): any;
73
+ /**
74
+ * Resizes itself.
75
+ */
76
+ resize(MAX_WIDTH: number, MAX_HEIGHT: number): Promise<unknown>;
77
+ /**
78
+ * Adds a thumbnail to image model.
79
+ * @param options
80
+ */
81
+ addThumbnail(options?: {
82
+ width?: number;
83
+ height?: number;
84
+ }): Promise<void>;
85
+ isUploaded(): boolean;
86
+ isDisabled(): boolean;
87
+ }
88
+ export default Media;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t,e=require("tslib"),r=require("mobx"),i=require("@flumens/utils/dist/image"),a=require("../Model.js"),n=require("./helpers.js"),o=!!window.cordova||!!(null===(t=null===window||void 0===window?void 0:window.Capacitor)||void 0===t?void 0:t.isNative),s=function(t){function a(i){var a=this;void 0===i&&(i={});var n=i.metadata,o=void 0===n?{}:n,s=e.__rest(i,["metadata"]);return(a=t.call(this,s)||this).remote={synchronising:!1,url:null,headers:{},timeout:12e4},a.debouncedValue=300,a.parent=a.parent,a.metadata=r.observable(o),a}return e.__extends(a,t),a.fromJSON=function(t){var r,i,a;return new this(e.__assign(e.__assign({},t),{createdAt:t.createdAt||(null===(r=t.metadata)||void 0===r?void 0:r.createdOn),updatedAt:t.updatedAt||(null===(i=t.metadata)||void 0===i?void 0:i.updatedOn),syncedAt:t.syncedAt||(null===(a=t.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(t,r,a){return e.__awaiter(this,void 0,void 0,(function(){var n,s,d,u,h,c,l;return e.__generator(this,(function(e){switch(e.label){case 0:if(n=this,!t)throw new Error("File not found while creating image model.");return o?[4,i.createImage(t)]:[3,2];case 1:return h=e.sent(),s=h.width,d=h.height,u=t.split("/").pop(),[3,4];case 2:return[4,n.getDataURI(t,{width:2e3,height:2e3})];case 3:l=e.sent(),u=l[0],s=l[2],d=l[3],e.label=4;case 4:return c=new n({attrs:{data:u,type:"jpeg",width:s,height:d,path:r}}),a?[3,6]:[4,c.addThumbnail()];case 5:e.sent(),e.label=6;case 6:return[2,c]}}))}))},a.prototype.toJSON=function(){var i=t.prototype.toJSON.call(this);return JSON.parse(JSON.stringify(e.__assign(e.__assign({},i),{metadata:r.toJS(this.metadata)||{}})))},a.prototype.setupdatedAtTimestamp=function(e){var r;t.prototype.setUpdatedAtTimestamp.call(this,e),null===(r=this.parent)||void 0===r||r.setUpdatedAtTimestamp(e)},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 e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){return[2,this.parent?this.parent.sync():t.prototype.sync.call(this)]}))}))},a.prototype.uploadFile=function(){var t;return e.__awaiter(this,void 0,void 0,(function(){var r,i,a,o,s,d;return e.__generator(this,(function(e){switch(e.label){case 0:if(this.id)throw new Error("A file of a media on the remote cannot be uploaded again.");return[4,this.getFormData()];case 1:return r=e.sent(),i=new FormData,(d=i).append.apply(d,r),"function"!=typeof this.remote.headers?[3,3]:[4,this.remote.headers()];case 2:return a=e.sent(),[3,4];case 3:a=this.remote.headers,e.label=4;case 4:return o={method:"POST",headers:a,body:i},[4,n.makeRequest("".concat(this.remote.url,"/media-queue"),o)];case 5:if(s=e.sent(),!(null===(t=s[this.cid])||void 0===t?void 0:t.name))throw new Error("New remote media name was not be found.");return this.attrs.queued=s[this.cid].name,this.syncedAt=(new Date).getTime(),[2]}}))}))},a.prototype.getFormData=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r,i,a,o,s,d;return e.__generator(this,(function(e){switch(e.label){case 0:return t=this.attrs.type,r=t,i=t,(null==t?void 0:t.match(/image.*/))?(d=t.split("/"),r=d[1]):i="image/".concat(i),a=this.getURL(),[4,n.getBlobFromURL(a,i)];case 1:return o=e.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=s;
@@ -0,0 +1,127 @@
1
+ import { IObservableArray } from 'mobx';
2
+ import Model, { Attrs as AttrsOriginal, Options as OptionsOriginal } from '../Model';
3
+ import Media from './Media';
4
+ import Sample from './Sample';
5
+ import { RemoteConfig, Keys } from './helpers';
6
+ export { RemoteConfig };
7
+ export interface Metadata {
8
+ }
9
+ export interface Options<T = any, S = any> extends OptionsOriginal<T> {
10
+ metadata?: S;
11
+ media?: any[];
12
+ }
13
+ export interface Attrs extends AttrsOriginal {
14
+ training?: boolean;
15
+ /**
16
+ * R - released record (default).
17
+ * U - unreleased record.
18
+ * P - record pending a "peer review" check.
19
+ */
20
+ releaseStatus?: 'R' | 'U' | 'P';
21
+ /**
22
+ * V - Accepted.
23
+ * V1 - Accepted as correct.
24
+ * V2 - Accepted as considered correct.
25
+ * C - Pending review.
26
+ * C3 - Plausible.
27
+ * R - Not accepted.
28
+ * R4 - Not accepted as unable to verify.
29
+ * R5 - Not accepted as incorrect.
30
+ * D - Dubious.
31
+ * T - Test.
32
+ * I - Incomplete.
33
+ */
34
+ recordStatus?: 'V' | 'V1' | 'V2' | 'C' | 'C3' | 'R' | 'R4' | 'R5' | 'D' | 'T' | 'I';
35
+ /**
36
+ * Confidential records are normally completely blocked from public reports.
37
+ */
38
+ confidential?: boolean;
39
+ zeroAbundance?: boolean;
40
+ /**
41
+ * Sensitive records are visible to the public but only at a lower precision.
42
+ * "" - not sensitive
43
+ * 100 - >100m
44
+ * 1000 - >1km
45
+ * 2000 - >2km
46
+ * 10000 - >10km
47
+ * 100000 - >100km
48
+ */
49
+ sensitivityPrecision?: '' | 100 | 1000 | 2000 | 10000 | 100000;
50
+ comment?: string;
51
+ taxon?: any;
52
+ }
53
+ export default class Occurrence<T extends Attrs = Attrs, S extends Metadata = Metadata> extends Model {
54
+ static fromJSON(json: any, MediaClass?: any): Occurrence<Attrs, Metadata>;
55
+ /**
56
+ * Warehouse attributes and their values.
57
+ */
58
+ static keys: {
59
+ taxon: {
60
+ id: string;
61
+ };
62
+ comment: {
63
+ id: string;
64
+ };
65
+ releaseStatus: {
66
+ id: string;
67
+ };
68
+ recordStatus: {
69
+ id: string;
70
+ };
71
+ sensitivityPrecision: {
72
+ id: string;
73
+ };
74
+ training: {
75
+ id: string;
76
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
77
+ };
78
+ deleted: {
79
+ id: string;
80
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
81
+ };
82
+ confidential: {
83
+ id: string;
84
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
85
+ };
86
+ zeroAbundance: {
87
+ id: string;
88
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
89
+ };
90
+ };
91
+ metadata: S;
92
+ attrs: T;
93
+ parent?: Sample;
94
+ media: IObservableArray<Media>;
95
+ debouncedValue: number;
96
+ constructor({ metadata, media, ...options }?: Options);
97
+ setUpdatedAtTimestamp(newUpdatedAt: number): void;
98
+ /**
99
+ * Save the model to the offline store.
100
+ */
101
+ save(): Promise<void>;
102
+ /**
103
+ * Destroy the model and remove from the offline store.
104
+ */
105
+ destroy(silent?: boolean): Promise<void>;
106
+ sync(): Promise<void>;
107
+ /**
108
+ * Returns a clean (no observables) JSON representation of the model.
109
+ */
110
+ toJSON(): any;
111
+ keys: Keys;
112
+ getSurvey(): {
113
+ attrs?: {
114
+ [key: string]: {
115
+ remote?: RemoteConfig | undefined;
116
+ };
117
+ } | undefined;
118
+ modifySubmission?: ((submission: any, model: any) => any) | undefined;
119
+ };
120
+ isUploaded(): boolean;
121
+ isDisabled(): boolean;
122
+ /**
123
+ * Returns an object with attributes and their values
124
+ * mapped for warehouse submission.
125
+ */
126
+ getSubmission(warehouseMediaNames?: {}): any;
127
+ }
@@ -0,0 +1 @@
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"},comment:{id:"comment"},releaseStatus:{id:"release_status"},recordStatus:{id:"record_status"},sensitivityPrecision:{id:"sensitivity_precision"},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;
@@ -0,0 +1,163 @@
1
+ import { IObservableArray } from 'mobx';
2
+ import Model, { Attrs as AttrsOriginal, Options as OptionsOriginal } from '../Model';
3
+ import Media from './Media';
4
+ import Occurrence from './Occurrence';
5
+ import { RemoteConfig, Keys } from './helpers';
6
+ export interface Metadata {
7
+ }
8
+ export { RemoteConfig };
9
+ type ModelWithSubmodels = {
10
+ occurrences?: Occurrence[];
11
+ samples?: Sample[];
12
+ media?: Media[];
13
+ };
14
+ export declare const _getMediaFormData: (model: ModelWithSubmodels) => Promise<any[]>;
15
+ export interface Options<T = any, S = any> extends OptionsOriginal<T> {
16
+ metadata?: S;
17
+ occurrences?: any[];
18
+ samples?: any[];
19
+ media?: any[];
20
+ }
21
+ export interface Attrs extends AttrsOriginal {
22
+ surveyId?: string | number | null;
23
+ /**
24
+ * Remote website survey edit page path.
25
+ */
26
+ inputForm?: string | null;
27
+ date?: any;
28
+ location_type?: any;
29
+ /**
30
+ * Allows record precision to be blurred for public viewing for privacy
31
+ * (as opposed to sensitivity) reasons. An example might be to obscure
32
+ * the garden location of a minor.
33
+ */
34
+ privacyPrecision?: number;
35
+ training?: boolean;
36
+ comment?: string;
37
+ }
38
+ export interface Remote {
39
+ synchronising?: boolean;
40
+ url?: string | null;
41
+ headers?: any;
42
+ timeout?: number;
43
+ /**
44
+ * @deprecated
45
+ */
46
+ host_url?: any;
47
+ /**
48
+ * @deprecated
49
+ */
50
+ api_key?: any;
51
+ }
52
+ type BaseSurvey = {
53
+ attrs?: {
54
+ [key: string]: {
55
+ remote?: RemoteConfig;
56
+ };
57
+ };
58
+ modifySubmission?: (submission: any, model: any) => any;
59
+ };
60
+ export interface Survey extends BaseSurvey {
61
+ smp?: Survey;
62
+ occ?: BaseSurvey;
63
+ }
64
+ declare class Sample<T extends Attrs = Attrs, S extends Metadata = Metadata> extends Model {
65
+ static fromJSON(json: any, OccurrenceClass?: any, Sample?: any, // eslint-disable-line
66
+ MediaClass?: any): Sample<Attrs, Metadata>;
67
+ /**
68
+ * Warehouse attributes and their values.
69
+ */
70
+ static keys: {
71
+ surveyId: {
72
+ id: string;
73
+ };
74
+ date: {
75
+ id: string;
76
+ };
77
+ sample_method_id: {
78
+ id: string;
79
+ };
80
+ location: {
81
+ id: string;
82
+ };
83
+ location_type: {
84
+ id: string;
85
+ values: {
86
+ british: string;
87
+ irish: string;
88
+ channel: string;
89
+ latlon: number;
90
+ };
91
+ };
92
+ inputForm: {
93
+ id: string;
94
+ };
95
+ group: {
96
+ id: string;
97
+ };
98
+ comment: {
99
+ id: string;
100
+ };
101
+ training: {
102
+ id: string;
103
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
104
+ };
105
+ deleted: {
106
+ id: string;
107
+ values: (val?: boolean | "t" | "f" | null | undefined) => "t" | "f";
108
+ };
109
+ privacyPrecision: {
110
+ id: string;
111
+ };
112
+ recordStatus: {
113
+ id: string;
114
+ };
115
+ };
116
+ /**
117
+ * Model persistent observable metadata.
118
+ */
119
+ metadata: Metadata;
120
+ /**
121
+ * Model's persistent observable attributes.
122
+ */
123
+ attrs: T;
124
+ remote: Remote;
125
+ validateRemote: any;
126
+ error: {
127
+ message: string;
128
+ };
129
+ collection?: any;
130
+ samples: IObservableArray<Sample<T, S>>;
131
+ occurrences: IObservableArray<Occurrence>;
132
+ media: IObservableArray<Media>;
133
+ parent?: Sample<T, S>;
134
+ survey?: Survey;
135
+ debouncedValue: number;
136
+ constructor({ metadata, samples, occurrences, media, attrs, ...options }?: Options);
137
+ setupdatedAtTimestamp(newUpdatedAt: number): void;
138
+ /**
139
+ * Returns a clean (no observables) JSON representation of the model.
140
+ */
141
+ toJSON(): any;
142
+ keys: Keys;
143
+ getSurvey(): Survey;
144
+ /**
145
+ * Save the model to the offline store.
146
+ */
147
+ save(): Promise<void>;
148
+ /**
149
+ * Destroy the model and remove from the offline store.
150
+ */
151
+ destroy(silent?: boolean): Promise<void>;
152
+ sync(): Promise<void>;
153
+ requiresRemoteSync: () => boolean;
154
+ saveRemote(): Promise<void>;
155
+ updateRemote(): Promise<void>;
156
+ private _createRemote;
157
+ private _updateRemote;
158
+ private _uploadMedia;
159
+ getSubmission(warehouseMediaNames?: {}): any;
160
+ isUploaded(): boolean;
161
+ isDisabled(): boolean;
162
+ }
163
+ export default Sample;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("mobx"),r=require("lodash"),s=require("@flumens/utils/dist/errors"),n=require("../Model.js"),i=require("./Media.js"),a=require("./Occurrence.js"),o=require("./helpers.js");function u(e,t){var r,s,n;t&&t.values?(e.id=t.values.id,e.samples&&t.samples&&(null===(r=e.samples)||void 0===r||r.forEach((function(e,r){return u(e,t.samples[r])}))),e.occurrences&&t.occurrences&&(null===(s=e.occurrences)||void 0===s||s.forEach((function(e,r){return u(e,t.occurrences[r])}))),e.media&&t.media&&(null===(n=e.media)||void 0===n||n.forEach((function(e,r){return u(e,t.media[r])})))):console.warn("Model didn't receive an id from the server")}var c=function(t){return e.__awaiter(void 0,void 0,void 0,(function(){var r,s,n;return e.__generator(this,(function(e){switch(e.label){case 0:return r=[],t.media?(s=function(e){return e.getFormData()},[4,Promise.all(t.media.map(s))]):[3,2];case 1:n=e.sent(),r.push.apply(r,n),e.label=2;case 2:return t.occurrences?[4,Promise.all(t.occurrences.map(c))]:[3,4];case 3:n=e.sent(),r.push.apply(r,n.flat()),e.label=4;case 4:return t.samples?[4,Promise.all(t.samples.map(c))]:[3,6];case 5:n=e.sent(),r.push.apply(r,n.flat()),e.label=6;case 6:return[2,r]}}))}))};function d(e,t){var r={values:{id:t||-1}};return e.occurrences&&(r.occurrences=e.occurrences.map((function(e){return d(e)}))),e.samples&&(r.samples=e.samples.map((function(e){return d(e)}))),e.media&&(r.media=e.media.map((function(e){return d(e)}))),r}function l(e){try{console.warn(JSON.stringify(e).substring(0,1e5))}catch(e){}}var h=function(n){function h(r){var s=this;void 0===r&&(r={});var i=r.metadata,a=void 0===i?{}:i,u=r.samples,c=void 0===u?[]:u,d=r.occurrences,l=void 0===d?[]:d,m=r.media,p=void 0===m?[]:m,f=r.attrs,v=void 0===f?{}:f,_=e.__rest(r,["metadata","samples","occurrences","media","attrs"]);(s=n.call(this,e.__assign(e.__assign({},_),{attrs:e.__assign({date:(new Date).toISOString(),location_type:"latlon"},v)}))||this).remote=t.observable({synchronising:!1,url:null,headers:{},timeout:12e4}),s.validateRemote=o.validateRemoteModel,s.error=t.observable({message:""}),s.debouncedValue=300,s.keys=function(){return e.__assign(e.__assign({},h.keys),function(t){return Object.keys(t).reduce((function(r,s){var n;return e.__assign(e.__assign({},r),((n={})[s]=t[s].remote||t[s],n))}),{})}(s.getSurvey().attrs||{}))},s.requiresRemoteSync=function(){return!s.syncedAt||s.updatedAt>s.syncedAt},s.metadata=t.observable(a),s.samples=t.observable(c),s.occurrences=t.observable(l),s.media=t.observable(p);var y=function(e){return e.parent=s};s.samples.forEach(y),s.occurrences.forEach(y),s.media.forEach(y);var g=function(e){var t;return(null===(t=e.added)||void 0===t?void 0:t.length)?(e.added.forEach(y),s.setupdatedAtTimestamp(Date.now())):e.removedCount&&s.setupdatedAtTimestamp(Date.now()),e};return t.intercept(s.samples,g),t.intercept(s.occurrences,g),t.intercept(s.media,g),s}return e.__extends(h,n),h.fromJSON=function(t,r,s,n){var o,u,c,d,l,h;return void 0===r&&(r=a.default),void 0===s&&(s=this),void 0===n&&(n=i.default),new this(e.__assign(e.__assign({},t),{createdAt:t.createdAt||(null===(o=t.metadata)||void 0===o?void 0:o.createdOn),updatedAt:t.updatedAt||(null===(u=t.metadata)||void 0===u?void 0:u.updatedOn),syncedAt:t.syncedAt||(null===(c=t.metadata)||void 0===c?void 0:c.syncedOn),samples:null===(d=t.samples)||void 0===d?void 0:d.map((function(e){return s.fromJSON(e,r,s,n)})),occurrences:null===(l=t.occurrences)||void 0===l?void 0:l.map((function(e){return r.fromJSON(e,n)})),media:null===(h=t.media)||void 0===h?void 0:h.map((function(e){return n.fromJSON(e)}))}))},h.prototype.setupdatedAtTimestamp=function(e){var t;n.prototype.setUpdatedAtTimestamp.call(this,e),null===(t=this.parent)||void 0===t||t.setupdatedAtTimestamp(e)},h.prototype.toJSON=function(){var r,s,i=n.prototype.toJSON.call(this);return JSON.parse(JSON.stringify(e.__assign(e.__assign({},i),{occurrences:this.occurrences.map((function(e){return e.toJSON()}))||[],samples:(null===(r=this.samples)||void 0===r?void 0:r.map((function(e){return e.toJSON()})))||[],media:(null===(s=this.media)||void 0===s?void 0:s.map((function(e){return e.toJSON()})))||[],metadata:t.toJS(this.metadata)||{}})))},h.prototype.getSurvey=function(){return this.survey?this.parent?this.parent.getSurvey().smp||{}:this.survey:{}},h.prototype.save=function(){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){switch(e.label){case 0:if(this.attrs.deleted)return[2];if(this.parent)return this.parent.save(),[2];if(!this._store)throw new Error("Trying to sync locally without a store");return[4,this._store.save(this.toJSON())];case 1:return e.sent(),[2]}}))}))},h.prototype.destroy=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,s=this;return e.__generator(this,(function(e){switch(e.label){case 0:return r=function(){return Promise.all([Promise.all(s.media.map((function(e){return e.destroy(!0)}))),Promise.all(s.occurrences.map((function(e){return e.destroy(!0)})))])},this.parent?(this.parent.samples.remove(this),[4,r()]):[3,2];case 1:return e.sent(),t?[2]:(this.parent.save(),[2]);case 2:if(!this._store)throw new Error("Trying to sync locally without a store");return[4,this._store.destroy(this.cid)];case 3:return e.sent(),this.collection&&this.collection.remove(this),[4,r()];case 4:return e.sent(),this.attrs.deleted=!0,[2]}}))}))},h.prototype.sync=function(){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){return[2,this.parent?this.parent.sync():n.prototype.sync.call(this)]}))}))},h.prototype.saveRemote=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r,s,n,i,a;return e.__generator(this,(function(e){switch(e.label){case 0:if(e.trys.push([0,6,,7]),!this.remote.url)throw new Error('A "remote" property is not configured.');t=void 0,e.label=1;case 1:return e.trys.push([1,4,,5]),this.remote.synchronising=!0,[4,this._uploadMedia()];case 2:return r=e.sent(),t=this.getSubmission(r),[4,this._createRemote(t)];case 3:return s=e.sent(),this.remote.synchronising=!1,u(this,s),n=(new Date).getTime(),this.updatedAt=n,this.syncedAt=n,this.save(),[3,5];case 4:throw i=e.sent(),this.remote.synchronising=!1,i.payload=t,i;case 5:return[3,7];case 6:throw 400===(a=e.sent()).status&&a.payload&&l(a.payload),a;case 7:return[2]}}))}))},h.prototype.updateRemote=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r,s,n,i,a;return e.__generator(this,(function(e){switch(e.label){case 0:if(e.trys.push([0,5,,6]),!this.remote.url)throw new Error('A "remote" property is not configured.');t=void 0,e.label=1;case 1:return e.trys.push([1,3,,4]),this.remote.synchronising=!0,r={},t=this.getSubmission(r),[4,this._updateRemote(this.id,t)];case 2:return s=e.sent(),this.remote.synchronising=!1,u(this,s),n=(new Date).getTime(),this.updatedAt=n,this.syncedAt=n,this.save(),[3,4];case 3:throw i=e.sent(),this.remote.synchronising=!1,i.payload=t,i;case 4:return[3,6];case 5:throw 400===(a=e.sent()).status&&a.payload&&l(a.payload),a;case 6:return[2]}}))}))},h.prototype._createRemote=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,n,i,a;return e.__generator(this,(function(e){switch(e.label){case 0:return r=this.remote.url,"function"!=typeof this.remote.headers?[3,2]:[4,this.remote.headers()];case 1:return n=e.sent(),[3,3];case 2:n=this.remote.headers,e.label=3;case 3:i={method:"POST",headers:n,body:JSON.stringify(t)},e.label=4;case 4:return e.trys.push([4,6,,7]),[4,o.makeRequest("".concat(r,"/samples"),i)];case 5:return[2,e.sent()];case 6:if(409===(a=e.sent()).status&&a.res&&a.res.duplicate_of)return[2,d(this,a.res.duplicate_of.id)];if("timeout"===a.message)throw new s.HandledError("Request aborted because of a network issue (timeout or similar).");throw a;case 7:return[2]}}))}))},h.prototype._updateRemote=function(t,r){return e.__awaiter(this,void 0,void 0,(function(){var n,i,a,u;return e.__generator(this,(function(e){switch(e.label){case 0:return n=this.remote.url,"function"!=typeof this.remote.headers?[3,2]:[4,this.remote.headers()];case 1:return i=e.sent(),[3,3];case 2:i=this.remote.headers,e.label=3;case 3:a={method:"PUT",headers:i,body:JSON.stringify(r)},e.label=4;case 4:return e.trys.push([4,6,,7]),[4,o.makeRequest("".concat(n,"/samples/").concat(t),a)];case 5:return[2,e.sent()];case 6:if(409===(u=e.sent()).status&&u.res&&u.res.duplicate_of)return[2,d(this,u.res.duplicate_of.id)];if("timeout"===u.message)throw new s.HandledError("Request aborted because of a network issue (timeout or similar).");throw u;case 7:return[2]}}))}))},h.prototype._uploadMedia=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r,n,i,a,u,d=this;return e.__generator(this,(function(l){switch(l.label){case 0:return t={},[4,c(this)];case 1:if(r=l.sent(),!r.length)return[2,t];n=function(t){return e.__awaiter(d,void 0,void 0,(function(){var r,n,i;return e.__generator(this,(function(e){switch(e.label){case 0:return r=this.remote.url,"function"!=typeof this.remote.headers?[3,2]:[4,this.remote.headers()];case 1:return n=e.sent(),[3,3];case 2:n=this.remote.headers,e.label=3;case 3:i={method:"POST",headers:n,body:t};try{return[2,o.makeRequest("".concat(r,"/media-queue"),i)]}catch(e){if("timeout"===e.message)throw new s.HandledError("Request aborted because of a network issue (timeout or similar).");throw e}return[2]}}))}))},i=5,a=function(s){var a,o,u;return e.__generator(this,(function(c){switch(c.label){case 0:return a=r.slice(s,s+i),o=new FormData,a.forEach((function(e){return o.append.apply(o,e)})),[4,n(o)];case 1:return u=c.sent(),t=e.__assign(e.__assign({},t),u),[2]}}))},u=0,l.label=2;case 2:return u<r.length?[5,a(u)]:[3,5];case 3:l.sent(),l.label=4;case 4:return u+=i,[3,2];case 5:return[2,t]}}))}))},h.prototype.getSubmission=function(t){var s=this;void 0===t&&(t={});var n="function"==typeof this.keys?this.keys():this.keys,i=e.__assign(e.__assign({},h.keys),n),a={values:{external_key:this.cid},media:[],samples:[],occurrences:[]};this.id&&(a.values.id=this.id);var o=function(e,t){var r=i[e].values;if(!r)return t;if("function"==typeof r)return r(t,a,s);if(t instanceof Array)return t.map((function(t){return o(e,t)}));if(r instanceof Array){var n=r.find((function(e){return e.value===t}));if(!n||!n.id)throw new Error('A "'.concat(e,'" attribute "').concat(t,'" value could not be mapped to a remote database field.'));return n.id}return r[t]};Object.keys(this.attrs).forEach((function(e){var t=s.attrs[e],n=function(e){return null==e};if(!n(t)){if(!i[e])return e=e.includes("smpAttr:")?e:r.snakeCase(e),void(a.values[e]=t);if(!n(t=o(e,t))){var u=i[e].id||e,c=Number.isNaN(Number(u))?u:"smpAttr:".concat(u);c=c.includes("smpAttr:")?c:r.snakeCase(c),a.values[c]=t}}})),this.samples.forEach((function(e){s.attrs.training&&(e.attrs.training=s.attrs.training);var r=e.getSubmission(t);r&&a.samples.push(r)})),this.occurrences.forEach((function(e){s.attrs.training&&(e.attrs.training=s.attrs.training);var r=e.getSubmission(t);r&&a.occurrences.push(r)})),this.media.forEach((function(e){var r=e.getSubmission(t);r&&a.media.push(r)}));var u=this.getSurvey();return u.modifySubmission?u.modifySubmission(a,this):a},h.prototype.isUploaded=function(){return this.parent?this.parent.isUploaded():!!this.syncedAt},h.prototype.isDisabled=function(){return this.isUploaded()},h.keys={surveyId:{id:"survey_id"},date:{id:"date"},sample_method_id:{id:"sample_method_id"},location:{id:"entered_sref"},location_type:{id:"entered_sref_system",values:{british:"OSGB",irish:"OSIE",channel:"utm30ed50",latlon:4326}},inputForm:{id:"input_form"},group:{id:"group_id"},comment:{id:"comment"},training:{id:"training",values:o.boolToWarehouseValue},deleted:{id:"deleted",values:o.boolToWarehouseValue},privacyPrecision:{id:"privacy_precision"},recordStatus:{id:"record_status"}},h}(n.default);exports._getMediaFormData=c,exports.default=h;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ export declare class SyncError extends Error {
2
+ status?: number;
3
+ res?: any;
4
+ payload?: any;
5
+ }
6
+ export declare function makeRequest(url: string, options: RequestInit, timeout?: number): Promise<any>;
7
+ /**
8
+ * Converts DataURI object to a Blob.
9
+ *
10
+ * @param {type} dataURI
11
+ * @param {type} fileType
12
+ * @returns {undefined}
13
+ */
14
+ export declare function dataURItoBlob(dataURI: string, fileType: string): Blob;
15
+ export declare function isDataURL(string: string): boolean;
16
+ export declare function getBlobFromURL(url: string, mediaType: string): Promise<unknown>;
17
+ export interface RemoteConfig {
18
+ id?: number | string;
19
+ values?: {
20
+ id?: number | string;
21
+ value?: string | number | null;
22
+ }[] | {
23
+ [key: string]: string | number | null;
24
+ } | ((value: any, submission: any, model: any) => any);
25
+ }
26
+ export declare const boolToWarehouseValue: (val?: boolean | 't' | 'f' | null) => "t" | "f";
27
+ export type Keys = (() => {
28
+ [key: string]: RemoteConfig;
29
+ }) | {
30
+ [key: string]: RemoteConfig;
31
+ };
32
+ export declare function validateRemoteModel(): {
33
+ attributes: any;
34
+ model: any;
35
+ models: any;
36
+ } | null;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=function(t){function r(){return null!==t&&t.apply(this,arguments)||this}return e.__extends(r,t),r}(Error);function r(e,t){for(var r=atob(e.split(",")[1]),s=[],n=0;n<r.length;n++)s.push(r.charCodeAt(n));return new Blob([new Uint8Array(s)],{type:t})}function s(e){if(!e)return!1;return!!e.toString().match(/^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i)}exports.SyncError=t,exports.boolToWarehouseValue=function(e){return!0===e||"t"===e?"t":"f"},exports.dataURItoBlob=r,exports.getBlobFromURL=function(e,t){if(s(e)){var n=r(e,t);return Promise.resolve(n)}return new Promise((function(t){var r=new XMLHttpRequest;r.open("GET",e,!0),r.responseType="blob",r.onload=function(){var e=r.response;t(e)},r.send()}))},exports.isDataURL=s,exports.makeRequest=function(r,s,n){return void 0===n&&(n=12e4),e.__awaiter(this,void 0,void 0,(function(){var o,i,a,u,c,l;return e.__generator(this,(function(e){switch(e.label){case 0:return o=new Promise((function(e,t){setTimeout((function(){return t(new Error("timeout"))}),n)})),[4,Promise.race([fetch(r,s),o])];case 1:i=e.sent(),a={},e.label=2;case 2:return e.trys.push([2,4,,5]),[4,i.text()];case 3:return a=e.sent(),a=JSON.parse(a),[3,5];case 4:if(u=e.sent(),201!==i.status||!a.includes("Document Moved"))throw u;return a=JSON.parse(a.slice(a.indexOf('{"values'))),[3,5];case 5:if(!i.ok)throw c=i.statusText,"object"==typeof a.message&&(d=a.message,c=Object.entries(d).reduce((function(e,t){return"".concat(e).concat(t[0]," ").concat(t[1],"\n")}),"")),(l=new t(c)).status=i.status,l.res=a,l;return[2,a]}var d}))}))},exports.validateRemoteModel=function(){var t=this.getSurvey(),r=t.verify&&t.verify(this.attrs,this),s={};if(r){var n=r&&"issues"in r;!("ValidationError"===(null==r?void 0:r.name)||"ValidationError"===(null==r?void 0:r.type))&&!n?s.errors=[r.message]:n?s.errors=r.issues.map((function(e){return e.message})):s=e.__assign({},r)}var o=function(e,t){var r=t.validateRemote();return r&&(e[t.cid]=r,e[t.cid].model=t),e},i=(this.samples||[]).reduce(o,{}),a=(this.occurrences||[]).reduce(o,{}),u=(this.media||[]).reduce(o,{});return Object.keys(s).length||Object.keys(i).length||Object.keys(a).length||Object.keys(u).length?{attributes:s,model:this,models:e.__assign(e.__assign(e.__assign({},i),a),u)}:null};
@@ -0,0 +1,75 @@
1
+ import Store, { ModelDTO } from './Stores/Store';
2
+ export interface Options<T = any> {
3
+ id?: string;
4
+ cid?: string;
5
+ createdAt?: number;
6
+ updatedAt?: number;
7
+ syncedAt?: number;
8
+ attrs?: T;
9
+ store?: Store;
10
+ }
11
+ export interface Attrs {
12
+ /**
13
+ * Flag whether the model was deleted. Global and persistent models might not need this.
14
+ */
15
+ deleted?: boolean;
16
+ }
17
+ export default class Model {
18
+ /**
19
+ * Extends observable attributes.
20
+ */
21
+ static extendAttrs: (obj1: any, obj2: any) => any;
22
+ /**
23
+ * Remote server document ID.
24
+ */
25
+ id: string;
26
+ /**
27
+ * Key name of the model used to save and fetch the model from.
28
+ */
29
+ cid: string;
30
+ /**
31
+ * Model create time.
32
+ */
33
+ createdAt: number;
34
+ /**
35
+ * Locally updated time.
36
+ */
37
+ updatedAt: number;
38
+ /**
39
+ * Remote updated time.
40
+ */
41
+ syncedAt?: number;
42
+ /**
43
+ * Model's persistent observable attributes.
44
+ */
45
+ attrs: Attrs;
46
+ /**
47
+ * The offline store used to save and fetch the model from.
48
+ */
49
+ protected _store?: Store;
50
+ /**
51
+ * A promise to flag if the model was initialised from the store.
52
+ */
53
+ ready?: Promise<boolean>;
54
+ protected debouncedValue: number;
55
+ constructor({ id, cid, createdAt, updatedAt, syncedAt, attrs, store, }: Options);
56
+ setUpdatedAtTimestamp(newUpdatedAt: number): void;
57
+ /**
58
+ * Initialize the model from store.
59
+ */
60
+ private _fromStore;
61
+ /**
62
+ * Save the model to the offline store.
63
+ */
64
+ save(): Promise<void>;
65
+ /**
66
+ * Destroy the model and remove from the offline store.
67
+ */
68
+ destroy(): Promise<void>;
69
+ sync(..._: any): Promise<void>;
70
+ /**
71
+ * Returns a clean (no observables) JSON representation of the model.
72
+ */
73
+ toJSON(): ModelDTO;
74
+ resetDefaults(defaultsToSet?: any): Promise<void>;
75
+ }
package/dist/Model.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("tslib"),e=require("mobx"),r=require("mobx-utils");function s(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var i=s(require("@flumens/utils/dist/uuid")),n={deleted:!1},o=function(){function s(s){var o=this,a=s.id,u=void 0===a?"":a,d=s.cid,c=void 0===d?"":d,h=s.createdAt,f=s.updatedAt,_=s.syncedAt,l=s.attrs,p=void 0===l?{}:l,v=s.store;this.debouncedValue=3e3,this.id=u,this.cid=c||u||i.default();var y,A,b=Date.now();this.createdAt=h||b,this.updatedAt=f||b,this.syncedAt=_,this.attrs=e.observable((y=t.__assign(t.__assign({},n),p),JSON.parse(JSON.stringify(y)))),this._store=v,this.ready=this._fromStore();var w=function(){o.updatedAt=Date.now(),function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];clearTimeout(A),A=setTimeout((function(){return o.sync.apply(o,t)}),o.debouncedValue)}()};this.ready.then((function(){return r.deepObserve(o.attrs,w)}))}return s.prototype.setUpdatedAtTimestamp=function(t){this.updatedAt=t},s.prototype._fromStore=function(){return t.__awaiter(this,void 0,void 0,(function(){var r;return t.__generator(this,(function(t){switch(t.label){case 0:return this._store?[4,this._store.find(this.cid)]:[2,!1];case 1:return(r=t.sent())?[3,3]:[4,this.save()];case 2:return t.sent(),[2,!0];case 3:return r.id&&(this.id=r.id),r.cid&&(this.cid=r.cid),this.createdAt=r.createdAt,this.updatedAt=r.updatedAt,this.syncedAt=r.syncedAt,e.set(this.attrs,r.attrs),[2,!0]}}))}))},s.prototype.save=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){switch(t.label){case 0:if(!this._store)throw new Error("Trying to save locally without a store");return[4,this._store.save(this.toJSON())];case 1:return t.sent(),[2]}}))}))},s.prototype.destroy=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){switch(t.label){case 0:if(!this._store)throw new Error("Trying to delete locally without a store");return[4,this._store.destroy(this.cid)];case 1:return t.sent(),[2]}}))}))},s.prototype.sync=function(){return t.__awaiter(this,void 0,void 0,(function(){return t.__generator(this,(function(t){switch(t.label){case 0:return this._store?[4,this.save()]:[3,2];case 1:t.sent(),t.label=2;case 2:return[2]}}))}))},s.prototype.toJSON=function(){return{id:this.id,cid:this.cid,createdAt:this.createdAt,updatedAt:this.updatedAt,syncedAt:this.syncedAt,attrs:e.toJS(this.attrs)}},s.prototype.resetDefaults=function(r){var s=this;this.id="";var i=JSON.parse(JSON.stringify(t.__assign(t.__assign({},n),r)));e.set(this.attrs,i);var o=Object.keys(i);return Object.keys(this.attrs).forEach((function(t){o.includes(t)||(s.attrs[t]=null,delete s.attrs[t])})),this.save()},s.extendAttrs=function(r,s){return e.set(r,t.__assign(t.__assign({},s),r)),r},s}();exports.default=o;
@@ -0,0 +1,22 @@
1
+ import Store, { ModelDTO } from './Store';
2
+ export default class LocalForageStore implements Store {
3
+ debugging: any;
4
+ localForage: any;
5
+ ready: any;
6
+ constructor(options: any);
7
+ static _getDriverOrder(driverOrder: any): any;
8
+ save(val: ModelDTO): Promise<any>;
9
+ find(key: any): Promise<any>;
10
+ findAll(): Promise<any>;
11
+ destroy(key: any): Promise<any>;
12
+ destroyAll(): Promise<void>;
13
+ /**
14
+ * Exports all objects from the store.
15
+ */
16
+ export(): Promise<any>;
17
+ /**
18
+ * Imports objects to store.
19
+ */
20
+ import(obj: any): Promise<void>;
21
+ _printDiff(key: any, val: any): Promise<void>;
22
+ }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),r=require("deep-diff"),t=require("localforage"),n=require("localforage-cordovasqlitedriver"),i=require("lodash"),o=require("@ionic/react");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=a(t),c=a(n),u=["indexeddb","websql","localstorage"];if(o.isPlatform("hybrid")){if(!window.sqlitePlugin)throw new Error("cordova-sql-storage plugin is missing. Please install it.");u=e.__spreadArray([c.default],u,!0)}var l={driverOrder:u},d=function(){function t(r){var n=this,i=e.__assign(e.__assign({},l),r);this.debugging=i.debugging,this.localForage=null,this.ready=new Promise((function(e,r){var o=new Promise((function(e){i.driverOrder&&"object"==typeof i.driverOrder[0]?s.default.defineDriver(i.driverOrder[0]).then(e):e(void 0)}));if(!i.storeName)throw new Error("storeName prop is missing");o.then((function(){var o={name:i.name||"indicia",storeName:i.storeName};i.version&&(o.version=i.version);var a=t._getDriverOrder(i.driverOrder),c=i.LocalForage||s.default;n.localForage=c.createInstance(o),n.localForage.setDriver(a).then(e).catch(r)}))}))}return t._getDriverOrder=function(e){return e.map((function(e){switch(e){case"indexeddb":return s.default.INDEXEDDB;case"websql":return s.default.WEBSQL;case"localstorage":return s.default.LOCALSTORAGE;default:return"object"==typeof e&&e._driver?e._driver:console.error("No such db driver!")}}))},t.prototype.save=function(r){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:if(e.sent(),!r.cid)throw new Error("Invalid key passed to store");return this.debugging&&this._printDiff(r.cid,r),[2,this.localForage.setItem(r.cid,r)]}}))}))},t.prototype.find=function(r){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:if(e.sent(),!r)throw new Error("Invalid key passed to store");return[2,this.localForage.getItem(r)]}}))}))},t.prototype.findAll=function(){return e.__awaiter(this,void 0,void 0,(function(){var r;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:return e.sent(),r=[],[4,this.localForage.iterate((function(e){r.push(e)}))];case 2:return e.sent(),[2,r]}}))}))},t.prototype.destroy=function(r){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:if(e.sent(),!r)throw new Error("Invalid key passed to store");return[2,this.localForage.removeItem(r)]}}))}))},t.prototype.destroyAll=function(){return e.__awaiter(this,void 0,void 0,(function(){var r,t=this;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:return e.sent(),[4,this.findAll()];case 2:return r=e.sent(),[4,Promise.all(r.map((function(e){return t.destroy(e)})))];case 3:return e.sent(),[2]}}))}))},t.prototype.export=function(){return e.__awaiter(this,void 0,void 0,(function(){var r;return e.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:return t.sent(),r=function(r,t){var n;return e.__assign(e.__assign({},r),((n={})[t.cid]=t,n))},[4,this.findAll()];case 2:return[2,t.sent().reduce(r,{})]}}))}))},t.prototype.import=function(r){return e.__awaiter(this,void 0,void 0,(function(){var t,n=this;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.ready];case 1:return e.sent(),[4,this.destroyAll()];case 2:if(e.sent(),"object"!=typeof r)throw new Error("Invalid obj passed to store");return t=Object.entries(r).map((function(e){var r=e[1];return n.save(r)})),[4,Promise.all(t)];case 3:return e.sent(),[2]}}))}))},t.prototype._printDiff=function(t,n){return e.__awaiter(this,void 0,void 0,(function(){var o,a,s,c,u,l,d;return e.__generator(this,(function(e){switch(e.label){case 0:return o=this.localForage._config.storeName,[4,this.localForage.getItem(t)];case 1:return a=e.sent(),(s=r.diff(a,n))?(c={},u=0,l="",s.forEach((function(e){var r,n,a=((r={})[o]=((n={})[t]={},n),r);if(!e.path)return a[o][t]=e.rhs,console.groupCollapsed("Δ + ".concat(t)),console.log(a),void console.groupEnd();e.path.reduce((function(r,t,n){if(e.path.length-1>n)return r[t]={},r[t];var i=JSON.stringify(e.lhs,null,2),o=JSON.stringify(e.rhs,null,2);if(i===o)return r[t];u++,r[t]="".concat(i," -> ").concat(o),l="".concat(t,": ").concat(i," -> ").concat(o)}),a[o][t]),c=i.merge(c,a)})),u&&(d="Δ ".concat(t),1===u&&(d+=" ".concat(l)),console.groupCollapsed(d),console.log(c),console.groupEnd()),[2]):[2]}}))}))},t}();exports.default=d;
@@ -0,0 +1,10 @@
1
+ export default class SQLiteDatabase {
2
+ private sqliteConnection;
3
+ private connection?;
4
+ private get db();
5
+ protected name: string;
6
+ protected debugging: boolean;
7
+ constructor(databaseName?: string, debugging?: boolean);
8
+ init(): Promise<void>;
9
+ query(query: string, values?: any[]): Promise<import("@capacitor-community/sqlite").DBSQLiteValues | undefined>;
10
+ }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("@capacitor-community/sqlite"),n=require("@ionic/core"),i=function(){function i(e,n){this.sqliteConnection=new t.SQLiteConnection(t.CapacitorSQLite),this.name="main",this.debugging=!1,this.name=e||this.name,this.debugging=n||this.debugging}return Object.defineProperty(i.prototype,"db",{get:function(){return this.connection},enumerable:!1,configurable:!0}),i.prototype.init=function(){return e.__awaiter(this,void 0,void 0,(function(){var t;return e.__generator(this,(function(e){switch(e.label){case 0:return n.isPlatform("hybrid")?[3,3]:[4,customElements.whenDefined("jeep-sqlite")];case 1:return e.sent(),[4,this.sqliteConnection.initWebStore()];case 2:e.sent(),e.label=3;case 3:return t=this,[4,this.sqliteConnection.createConnection("".concat(this.name,"."),!1,"no-encryption",1,!1)];case 4:return t.connection=e.sent(),[4,this.connection.open()];case 5:return e.sent(),[2]}}))}))},i.prototype.query=function(t,n){var i,o;return e.__awaiter(this,void 0,void 0,(function(){var r;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,null===(i=this.db)||void 0===i?void 0:i.query(t,n)];case 1:return r=e.sent(),this.debugging?(console.groupCollapsed("💾 SQL: ".concat(t.trimStart().replaceAll(/\n/g," ").replaceAll(/\s+/g," ").substring(0,30),"...")),console.debug(t),console.groupEnd(),[4,null===(o=this.sqliteConnection)||void 0===o?void 0:o.saveToStore("".concat(this.name,"."))]):[3,3];case 2:e.sent(),e.label=3;case 3:return[2,r]}}))}))},i}();exports.default=i;
@@ -0,0 +1,25 @@
1
+ import Store, { ModelDTO } from './Store';
2
+ export default class SQLiteStore implements Store {
3
+ debugging: any;
4
+ ready: any;
5
+ dbName?: string;
6
+ storeName?: string;
7
+ localForage: any;
8
+ db: any;
9
+ constructor({ debugging, name, storeName }: any);
10
+ init(): Promise<void>;
11
+ save(val: ModelDTO): Promise<any>;
12
+ find(cid: string | number): Promise<ModelDTO>;
13
+ findAll(): Promise<any>;
14
+ destroy(cid: any): Promise<void>;
15
+ destroyAll(): Promise<void>;
16
+ /**
17
+ * Exports all objects from the store.
18
+ */
19
+ export(): Promise<any>;
20
+ /**
21
+ * Imports objects to store.
22
+ */
23
+ import(obj: any): Promise<void>;
24
+ _printDiff(cid: any, val: any): Promise<void>;
25
+ }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("tslib"),e=require("deep-diff"),r=require("jeep-sqlite/loader"),n=require("lodash"),i=require("@ionic/react"),a=require("./SQLiteDatabase.js");if(!i.isPlatform("hybrid")){r.defineCustomElements(window);var s=document.createElement("jeep-sqlite");s.setAttribute("autoSave","true"),document.body.appendChild(s)}var o=function(t){var e=t.id,r=t.cid,n=t.data;return{id:e,cid:r,createdAt:t.created_at,updatedAt:t.updated_at,syncedAt:t.synced_at,attrs:n}},d=function(){function r(t){var e=t.debugging,r=t.name,n=t.storeName;this.debugging=e,this.dbName=r,this.storeName=n,this.db=new a.default(r,e),this.ready=this.init(),window.db=this.db}return r.prototype.init=function(){return t.__awaiter(this,void 0,void 0,(function(){var e;return t.__generator(this,(function(t){switch(t.label){case 0:return i.isPlatform("hybrid")?[3,2]:[4,customElements.whenDefined("jeep-sqlite")];case 1:t.sent(),t.label=2;case 2:if(!this.storeName)throw new Error("storeName prop is missing");return[4,this.db.init()];case 3:return t.sent(),e="\n CREATE TABLE IF NOT EXISTS ".concat(this.storeName,"\n (\n id VARCHAR(36),\n cid VARCHAR(36) PRIMARY KEY NOT NULL DEFAULT id,\n data JSONB NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n synced_at INTEGER\n );\n "),[4,this.db.query(e)];case 4:return t.sent(),[2]}}))}))},r.prototype.save=function(e){return t.__awaiter(this,void 0,void 0,(function(){var r,n,i,a,s,o,d;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:if(t.sent(),!e.cid)throw new Error("Invalid cid passed to store");return r=e.cid,n=e.id,i=e.createdAt,a=e.updatedAt,s=e.syncedAt,o=e.attrs,this.debugging?[4,this._printDiff(r,e)]:[3,3];case 2:t.sent(),t.label=3;case 3:return d="\n INSERT INTO ".concat(this.storeName,"(id, cid, data, created_at, updated_at, synced_at)\n VALUES (?, ?, jsonb(?), ?, ?, ?)\n ON CONFLICT(cid) DO UPDATE SET data = excluded.data;\n "),[2,this.db.query(d,[n,r,JSON.stringify(o),new Date(i).getTime(),new Date(a).getTime(),s?new Date(s).getTime():null])]}}))}))},r.prototype.find=function(e){var r,n;return t.__awaiter(this,void 0,void 0,(function(){var i,a,s;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:if(t.sent(),!e)throw new Error("Invalid cid passed to store");return i="\n SELECT id, cid, json(data) as data, created_at, updated_at, synced_at,\n FROM ".concat(this.storeName,"\n WHERE cid = ?;\n "),[4,this.db.query(i,[e])];case 2:return a=t.sent(),s=(null===(n=null===(r=a.values)||void 0===r?void 0:r[0])||void 0===n?void 0:n["json(data)"])||null,[2,o(JSON.parse(s))]}}))}))},r.prototype.findAll=function(){var e;return t.__awaiter(this,void 0,void 0,(function(){var r,n;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:return t.sent(),r="\n SELECT id, cid, json(data) as data, created_at, updated_at, synced_at,\n FROM ".concat(this.storeName,";\n "),[4,this.db.query(r)];case 2:return n=t.sent(),[2,(null===(e=n.values)||void 0===e?void 0:e.map((function(t){return o(JSON.parse(null==t?void 0:t["json(data)"])||null)})))||[]]}}))}))},r.prototype.destroy=function(e){return t.__awaiter(this,void 0,void 0,(function(){var r;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:if(t.sent(),!e)throw new Error("Invalid cid passed to store");return r="DELETE from ".concat(this.storeName,' where cid = "').concat(e,'"'),[4,this.db.query(r)];case 2:return t.sent(),[2]}}))}))},r.prototype.destroyAll=function(){return t.__awaiter(this,void 0,void 0,(function(){var e;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:return t.sent(),e="DELETE from ".concat(this.storeName),[4,this.db.query(e)];case 2:return t.sent(),[2]}}))}))},r.prototype.export=function(){return t.__awaiter(this,void 0,void 0,(function(){var e;return t.__generator(this,(function(r){switch(r.label){case 0:return[4,this.ready];case 1:return r.sent(),e=function(e,r){var n;return t.__assign(t.__assign({},e),((n={})[r.cid]=r,n))},[4,this.findAll()];case 2:return[2,r.sent().reduce(e,{})]}}))}))},r.prototype.import=function(e){return t.__awaiter(this,void 0,void 0,(function(){var r,n=this;return t.__generator(this,(function(t){switch(t.label){case 0:return[4,this.ready];case 1:return t.sent(),[4,this.destroyAll()];case 2:if(t.sent(),"object"!=typeof e)throw new Error("Invalid obj passed to store");return r=Object.entries(e).map((function(t){var e=t[1];return n.save(e)})),Promise.all(r),[2]}}))}))},r.prototype._printDiff=function(r,i){return t.__awaiter(this,void 0,void 0,(function(){var a,s,o,d,c,u,l;return t.__generator(this,(function(t){switch(t.label){case 0:return a=this.storeName||"",[4,this.find(r)];case 1:return s=t.sent(),(o=e.diff(s,i))?(d={},c=0,u="",o.forEach((function(t){var e,i,s=((e={})[a]=((i={})[r]={},i),e);if(!t.path)return s[a][r]=t.rhs,console.groupCollapsed("Δ + ".concat(r)),console.log(s),void console.groupEnd();t.path.reduce((function(e,r,n){if(t.path.length-1>n)return e[r]={},e[r];var i=JSON.stringify(t.lhs,null,2),a=JSON.stringify(t.rhs,null,2);if(i===a)return e[r];c++,e[r]="".concat(i," -> ").concat(a),u="".concat(r,": ").concat(i," -> ").concat(a)}),s[a][r]),d=n.merge(d,s)})),c&&(l="Δ ".concat(r),1===c&&(l+=" ".concat(u)),console.groupCollapsed(l),console.log(d),console.groupEnd()),[2]):[2]}}))}))},r}();exports.default=d;
@@ -0,0 +1,17 @@
1
+ export type ModelDTO = {
2
+ id: string;
3
+ cid: string;
4
+ createdAt: number;
5
+ updatedAt: number;
6
+ syncedAt?: number;
7
+ attrs: any;
8
+ };
9
+ export default interface Store {
10
+ save(val: ModelDTO): Promise<void>;
11
+ find(cid: any): Promise<ModelDTO>;
12
+ findAll(): Promise<ModelDTO[]>;
13
+ destroy(cid: any): Promise<void>;
14
+ destroyAll(): Promise<void>;
15
+ export(): Promise<any>;
16
+ import(obj: any): Promise<void>;
17
+ }
@@ -0,0 +1,3 @@
1
+ export { default as LocalForageStore } from './LocalForageStore';
2
+ export { default as SQLiteStore } from './SQLiteStore';
3
+ export { default as IStore } from './Store';
@@ -0,0 +1,10 @@
1
+ export { default as DrupalUserModel } from './DrupalUserModel';
2
+ export { default as initStoredSamples } from './initStoredSamples';
3
+ export * from './Stores';
4
+ export { default as Model } from './Model';
5
+ export { default as Collection } from './Collection';
6
+ export { default as IndiciaMedia } from './Indicia/Media';
7
+ export { default as ElasticIndiciaOccurrence } from './Indicia/ElasticOccurrence';
8
+ export { default as ElasticIndiciaSample } from './Indicia/ElasticSample';
9
+ export { default as IndiciaOccurrence } from './Indicia/Occurrence';
10
+ export { default as IndiciaSample } from './Indicia/Sample';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./DrupalUserModel.js"),r=require("./initStoredSamples.js"),t=require("./Stores/LocalForageStore.js"),i=require("./Stores/SQLiteStore.js"),o=require("./Model.js"),a=require("./Collection/index.js"),s=require("./Indicia/Media.js"),l=require("./Indicia/Occurrence.js"),d=require("./Indicia/Sample.js");exports.DrupalUserModel=e.default,exports.initStoredSamples=r.default,exports.LocalForageStore=t.default,exports.SQLiteStore=i.default,exports.Model=o.default,exports.Collection=a.default,exports.IndiciaMedia=s.default,exports.IndiciaOccurrence=l.default,exports.IndiciaSample=d.default;
@@ -0,0 +1 @@
1
+ export default function initStoredSamples(store: any, Sample: any): any;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("mobx");exports.default=function(r,t){var n=e.observable([]);e.observe(n,(function(e){e.addedCount&&(e.added[0].collection=n)}));var o=function(e){var r=t.fromJSON(e);n.push(r)};return n.ready=r.findAll().then((function(e){return e.forEach(o)})),n._init=n.ready,n.removeAllSynced=function(){var e=[];return n.forEach((function(r){r.syncedAt&&e.push(r.destroy())})),Promise.all(e)},n.comparator=function(e){return-new Date(e.createdAt).getTime()},n.resetDefaults=function(){var e=n.map((function(e){return e.destroy()}));return Promise.all(e)},n};
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@flumens/models",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.js",
5
+ "types": "dist/src/index.d.ts",
6
+ "scripts": {
7
+ "build": "rollup -c",
8
+ "build:watch": "rollup -c -w",
9
+ "prepare": "npm run build",
10
+ "test:eslint": "eslint src --quiet --ext .jsx --ext .ts --ext .tsx --ext .js && echo '\\033[37;42;1m PASS \\033[00m'",
11
+ "postpublish": "TAG_NAME=models-v\"$npm_package_version\" && git tag $TAG_NAME && git push origin \"$TAG_NAME\"",
12
+ "test": "jest --passWithNoTests",
13
+ "test:watch": "jest --watchAll"
14
+ },
15
+ "author": "Flumens",
16
+ "license": "GNU GPL v3",
17
+ "devDependencies": {
18
+ "@rollup/plugin-json": "6.0.0",
19
+ "@rollup/plugin-node-resolve": "13.3.0",
20
+ "@rollup/plugin-typescript": "8.3.2",
21
+ "@trivago/prettier-plugin-sort-imports": "4.3.0",
22
+ "@types/react": "18.2.38",
23
+ "@types/react-dom": "18.2.17",
24
+ "prettier": "3.2.5",
25
+ "react": "^18.2.0",
26
+ "react-dom": "^18.2.0",
27
+ "rollup-plugin-clear": "2.0.7",
28
+ "rollup-plugin-terser": "7.0.2",
29
+ "tslib": "2.6.2",
30
+ "typescript": "4.9.4"
31
+ },
32
+ "peerDependencies": {},
33
+ "optionalDependencies": {
34
+ "localforage": "^1",
35
+ "jwt-decode": "^4",
36
+ "deep-diff": "^1",
37
+ "@capacitor-community/sqlite": "^6.0.2",
38
+ "localforage-cordovasqlitedriver": "^1",
39
+ "mobx-utils": "^6",
40
+ "jeep-sqlite": "^2.8.0",
41
+ "yup": "^1"
42
+ },
43
+ "jest": {
44
+ "testEnvironment": "jsdom",
45
+ "preset": "ts-jest",
46
+ "moduleNameMapper": {
47
+ "^.+.(css|style|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": "jest-transform-stub"
48
+ },
49
+ "testPathIgnorePatterns": [
50
+ "node_modules",
51
+ "dist"
52
+ ]
53
+ },
54
+ "dependencies": {}
55
+ }