2018-07-14 16:12:22 +00:00
|
|
|
const Observable = require('./utils/observable');
|
2018-02-16 13:13:46 +00:00
|
|
|
|
2018-01-12 12:25:07 +00:00
|
|
|
module.exports = {
|
|
|
|
async init() {
|
|
|
|
if (this._initialized) return;
|
2018-02-08 12:28:51 +00:00
|
|
|
this.initConfig();
|
|
|
|
this.initGlobals();
|
2018-07-14 16:12:22 +00:00
|
|
|
this.docs = new Observable();
|
2018-01-12 12:25:07 +00:00
|
|
|
this._initialized = true;
|
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
initConfig() {
|
2018-01-12 12:25:07 +00:00
|
|
|
this.config = {
|
2018-04-30 14:27:41 +00:00
|
|
|
serverURL: '',
|
2018-01-12 12:25:07 +00:00
|
|
|
backend: 'sqlite',
|
|
|
|
port: 8000
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
initGlobals() {
|
2018-02-14 12:50:56 +00:00
|
|
|
this.metaCache = {};
|
2018-02-16 13:13:46 +00:00
|
|
|
this.models = {};
|
|
|
|
this.forms = {};
|
|
|
|
this.views = {};
|
2018-02-22 11:21:42 +00:00
|
|
|
this.flags = {};
|
2018-03-26 12:56:21 +00:00
|
|
|
this.methods = {};
|
2018-03-26 08:53:46 +00:00
|
|
|
// temp params while calling routes
|
|
|
|
this.params = {};
|
2018-01-15 11:55:31 +00:00
|
|
|
},
|
|
|
|
|
2018-02-16 13:13:46 +00:00
|
|
|
registerLibs(common) {
|
|
|
|
// add standard libs and utils to frappe
|
|
|
|
common.initLibs(this);
|
|
|
|
},
|
|
|
|
|
2018-03-05 16:45:21 +00:00
|
|
|
registerModels(models, type) {
|
|
|
|
// register models from app/models/index.js
|
|
|
|
const toAdd = Object.assign({}, models.models);
|
|
|
|
|
|
|
|
// post process based on type
|
|
|
|
if (models[type]) {
|
|
|
|
models[type](toAdd);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object.assign(this.models, toAdd);
|
2018-02-16 13:13:46 +00:00
|
|
|
},
|
|
|
|
|
2018-03-05 16:45:21 +00:00
|
|
|
registerView(view, name, module) {
|
2018-02-16 13:13:46 +00:00
|
|
|
if (!this.views[view]) this.views[view] = {};
|
2018-03-05 16:45:21 +00:00
|
|
|
this.views[view][name] = module;
|
2018-02-16 13:13:46 +00:00
|
|
|
},
|
|
|
|
|
2018-03-26 13:02:35 +00:00
|
|
|
registerMethod({method, handler}) {
|
2018-03-26 12:56:21 +00:00
|
|
|
this.methods[method] = handler;
|
|
|
|
if (this.app) {
|
|
|
|
// add to router if client-server
|
2018-03-26 13:02:35 +00:00
|
|
|
this.app.post(`/api/method/${method}`, this.asyncHandler(async function(request, response) {
|
|
|
|
const data = await handler(request.body);
|
2018-03-26 12:56:21 +00:00
|
|
|
response.json(data);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-30 14:27:41 +00:00
|
|
|
async call({method, args}) {
|
|
|
|
if (this.isServer) {
|
|
|
|
if (this.methods[method]) {
|
|
|
|
return await this.methods[method](args);
|
|
|
|
} else {
|
|
|
|
throw `${method} not found`;
|
|
|
|
}
|
2018-03-26 12:56:21 +00:00
|
|
|
}
|
2018-04-30 14:27:41 +00:00
|
|
|
|
|
|
|
let url = `/api/method/${method}`;
|
|
|
|
let response = await fetch(url, {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Accept': 'application/json',
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify(args || {})
|
|
|
|
});
|
|
|
|
return await response.json();
|
2018-03-26 12:56:21 +00:00
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
addToCache(doc) {
|
2018-02-22 11:21:42 +00:00
|
|
|
if (!this.docs) return;
|
2018-01-15 11:55:31 +00:00
|
|
|
|
|
|
|
// add to `docs` cache
|
|
|
|
if (doc.doctype && doc.name) {
|
|
|
|
if (!this.docs[doc.doctype]) {
|
|
|
|
this.docs[doc.doctype] = {};
|
|
|
|
}
|
|
|
|
this.docs[doc.doctype][doc.name] = doc;
|
2018-02-21 09:38:56 +00:00
|
|
|
|
|
|
|
// singles available as first level objects too
|
|
|
|
if (doc.doctype === doc.name) {
|
|
|
|
this[doc.name] = doc;
|
|
|
|
}
|
2018-02-22 11:21:42 +00:00
|
|
|
|
|
|
|
// propogate change to `docs`
|
|
|
|
doc.on('change', params => {
|
|
|
|
this.docs.trigger('change', params);
|
|
|
|
});
|
2018-01-15 11:55:31 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-02-22 11:21:42 +00:00
|
|
|
isDirty(doctype, name) {
|
|
|
|
return (this.docs && this.docs[doctype] && this.docs[doctype][name]
|
|
|
|
&& this.docs[doctype][name]._dirty) || false;
|
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
getDocFromCache(doctype, name) {
|
2018-02-22 11:21:42 +00:00
|
|
|
if (this.docs && this.docs[doctype] && this.docs[doctype][name]) {
|
2018-01-15 11:55:31 +00:00
|
|
|
return this.docs[doctype][name];
|
|
|
|
}
|
2018-01-12 12:25:07 +00:00
|
|
|
},
|
|
|
|
|
2018-02-08 06:46:38 +00:00
|
|
|
getMeta(doctype) {
|
2018-02-14 12:50:56 +00:00
|
|
|
if (!this.metaCache[doctype]) {
|
2018-02-16 13:13:46 +00:00
|
|
|
let model = this.models[doctype];
|
|
|
|
if (!model) {
|
|
|
|
throw `${doctype} is not a registered doctype`;
|
|
|
|
}
|
|
|
|
let metaClass = model.metaClass || this.BaseMeta;
|
|
|
|
this.metaCache[doctype] = new metaClass(model);
|
2018-01-12 12:25:07 +00:00
|
|
|
}
|
|
|
|
|
2018-02-16 13:13:46 +00:00
|
|
|
return this.metaCache[doctype];
|
2018-01-12 12:25:07 +00:00
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
async getDoc(doctype, name) {
|
|
|
|
let doc = this.getDocFromCache(doctype, name);
|
2018-02-01 11:07:36 +00:00
|
|
|
if (!doc) {
|
2018-02-16 13:13:46 +00:00
|
|
|
doc = new (this.getDocumentClass(doctype))({doctype:doctype, name: name});
|
2018-02-01 11:07:36 +00:00
|
|
|
await doc.load();
|
2018-02-08 12:28:51 +00:00
|
|
|
this.addToCache(doc);
|
2018-01-12 12:25:07 +00:00
|
|
|
}
|
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
|
2018-02-16 13:13:46 +00:00
|
|
|
getDocumentClass(doctype) {
|
|
|
|
const meta = this.getMeta(doctype);
|
|
|
|
return meta.documentClass || this.BaseDocument;
|
|
|
|
},
|
|
|
|
|
2018-02-12 12:01:31 +00:00
|
|
|
async getSingle(doctype) {
|
|
|
|
return await this.getDoc(doctype, doctype);
|
|
|
|
},
|
|
|
|
|
2018-02-14 12:50:56 +00:00
|
|
|
async getDuplicate(doc) {
|
|
|
|
const newDoc = await this.getNewDoc(doc.doctype);
|
|
|
|
for (let field of this.getMeta(doc.doctype).getValidFields()) {
|
2018-02-27 16:29:14 +00:00
|
|
|
if (['name', 'submitted'].includes(field.fieldname)) continue;
|
2018-02-14 12:50:56 +00:00
|
|
|
if (field.fieldtype === 'Table') {
|
2018-02-19 16:41:10 +00:00
|
|
|
newDoc[field.fieldname] = (doc[field.fieldname] || []).map(d => {
|
|
|
|
let newd = Object.assign({}, d);
|
|
|
|
newd.name = '';
|
|
|
|
return newd;
|
|
|
|
});
|
2018-02-14 12:50:56 +00:00
|
|
|
} else {
|
|
|
|
newDoc[field.fieldname] = doc[field.fieldname];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newDoc;
|
|
|
|
},
|
|
|
|
|
2018-02-08 12:28:51 +00:00
|
|
|
async getNewDoc(doctype) {
|
|
|
|
let doc = this.newDoc({doctype: doctype});
|
2018-02-09 12:55:55 +00:00
|
|
|
doc._notInserted = true;
|
2018-03-05 16:45:21 +00:00
|
|
|
doc.name = this.getRandomString();
|
2018-02-08 12:28:51 +00:00
|
|
|
this.addToCache(doc);
|
2018-01-15 11:55:31 +00:00
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
|
2018-02-20 14:11:44 +00:00
|
|
|
newDoc(data) {
|
|
|
|
let doc = new (this.getDocumentClass(data.doctype))(data);
|
|
|
|
doc.setDefaults();
|
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
|
2018-01-12 12:25:07 +00:00
|
|
|
async insert(data) {
|
2018-02-08 12:28:51 +00:00
|
|
|
return await (this.newDoc(data)).insert();
|
2018-01-12 12:25:07 +00:00
|
|
|
},
|
|
|
|
|
2018-02-20 14:11:44 +00:00
|
|
|
async syncDoc(data) {
|
|
|
|
let doc;
|
|
|
|
if (await this.db.exists(data.doctype, data.name)) {
|
|
|
|
doc = await this.getDoc(data.doctype, data.name);
|
|
|
|
Object.assign(doc, data);
|
|
|
|
await doc.update();
|
|
|
|
} else {
|
|
|
|
doc = this.newDoc(data);
|
|
|
|
await doc.insert();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-30 14:27:41 +00:00
|
|
|
// only for client side
|
|
|
|
async login(email, password) {
|
|
|
|
if (email === 'Administrator') {
|
|
|
|
this.session = {
|
|
|
|
user: 'Administrator'
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let response = await fetch(this.getServerURL() + '/api/login', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Accept': 'application/json',
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email, password })
|
|
|
|
});
|
|
|
|
|
|
|
|
if (response.status === 200) {
|
|
|
|
const res = await response.json();
|
|
|
|
|
|
|
|
this.session = {
|
|
|
|
user: email,
|
|
|
|
token: res.token
|
|
|
|
}
|
|
|
|
|
2018-05-07 04:23:20 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return response;
|
|
|
|
},
|
|
|
|
|
|
|
|
async signup(email, fullName, password) {
|
|
|
|
let response = await fetch(this.getServerURL() + '/api/signup', {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Accept': 'application/json',
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({ email, fullName, password })
|
|
|
|
});
|
|
|
|
|
|
|
|
if (response.status === 200) {
|
|
|
|
return await response.json();
|
2018-04-30 14:27:41 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 04:23:20 +00:00
|
|
|
return response;
|
2018-04-30 14:27:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getServerURL() {
|
|
|
|
return this.config.serverURL || '';
|
2018-01-12 12:25:07 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
close() {
|
|
|
|
this.db.close();
|
|
|
|
|
|
|
|
if (this.server) {
|
|
|
|
this.server.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|