diff --git a/app/app/components/section/github/type-editor.js b/app/app/components/section/github/type-editor.js
index 9da06254..19c5c053 100644
--- a/app/app/components/section/github/type-editor.js
+++ b/app/app/components/section/github/type-editor.js
@@ -39,7 +39,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
config = {
clientId: cfg.clientID,
callbackUrl: cfg.authorizationCallbackURL,
- token: "",
owner: null,
owner_name: "",
repo: null,
@@ -52,6 +51,8 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
branchLines: "30",
state: null,
issues: "",
+ userId: "",
+ pageId: page.get('id'),
};
try {
@@ -64,18 +65,19 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
config.branchLines = metaConfig.branchLines;
config.state = metaConfig.state;
config.issues = metaConfig.issues;
- config.token = metaConfig.token;
+ config.userId = metaConfig.userId;
+ config.pageId = metaConfig.pageId;
} catch (e) {}
self.set('config', config);
+ self.set('config.pageId', page.get('id'));
// On auth callback capture code
let code = window.location.search;
if (is.not.undefined(code) && is.not.null(code) && is.not.empty(code) && code !== "") {
let tok = code.replace("?code=", "");
- self.set('config.token', tok);
- self.get('sectionService').fetch(page, "set_token", self.get('config'))
+ self.get('sectionService').fetch(page, "saveSecret", { "token": tok })
.then(function () {
console.log("github auth code saved to db");
self.send('authStage2');
@@ -84,14 +86,17 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
self.send('auth');
});
} else {
- self.get('sectionService').fetch(page, "check_token", self.get('config'))
- .then(function (cfg) {
- self.set('config.token', cfg.token);
+ if (config.userId !== self.session.user.id) {
+ console.log("github auth wrong user ID, switching");
+ self.set('config.userId', self.session.user.id);
+ }
+ self.get('sectionService').fetch(page, "checkAuth", self.get('config'))
+ .then(function () {
console.log("github auth code valid");
self.send('authStage2');
}, function (error) { //jshint ignore: line
console.log(error);
- self.send('auth'); // only require auth if the db does not already know the token
+ self.send('auth'); // require auth if the db token is invalid
});
}
}, function (error) { //jshint ignore: line
@@ -166,11 +171,11 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
getReportLists() {
let reports = [];
reports[0] = {
- id: "commits_data", // used as method for fetching Go data
+ id: "commitsData", // used as method for fetching Go data
name: "Commits on a branch"
};
reports[1] = {
- id: "issues_data", // used as method for fetching Go data
+ id: "issuesData", // used as method for fetching Go data
name: "Issues"
};
@@ -207,11 +212,11 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
this.set('showCommits', false);
this.set('showLabels', false);
switch (thisReport.id) {
- case 'commits_data':
+ case 'commitsData':
this.set('showCommits', true);
this.getBranchLists();
break;
- case "issues_data":
+ case 'issuesData':
this.set('showLabels', true);
this.getLabelLists();
break;
@@ -356,6 +361,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
authStage2() {
let self = this;
+ self.set('config.userId', this.session.user.id);
self.set('authenticated', true);
self.set('busy', true);
let page = this.get('page');
@@ -375,7 +381,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
},
auth() {
-
let self = this;
self.set('busy', true);
self.set('authenticated', false);
diff --git a/app/app/components/section/papertrail/type-editor.js b/app/app/components/section/papertrail/type-editor.js
index f46452b8..31009ff9 100644
--- a/app/app/components/section/papertrail/type-editor.js
+++ b/app/app/components/section/papertrail/type-editor.js
@@ -16,40 +16,40 @@ import SectionMixin from '../../../mixins/section';
import netUtil from '../../../utils/net';
export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, {
- sectionService: Ember.inject.service('section'),
- isDirty: false,
- waiting: false,
- authenticated: false,
- config: {},
+ sectionService: Ember.inject.service('section'),
+ isDirty: false,
+ waiting: false,
+ authenticated: false,
+ config: {},
items: {},
- didReceiveAttrs() {
- let config = {};
+ didReceiveAttrs() {
+ let config = {};
- try {
- config = JSON.parse(this.get('meta.config'));
- } catch (e) {}
+ try {
+ config = JSON.parse(this.get('meta.config'));
+ } catch (e) {}
- if (is.empty(config)) {
- config = {
- APIToken: "",
- query: "",
+ if (is.empty(config)) {
+ config = {
+ APIToken: "",
+ query: "",
max: 10,
group: null,
system: null
- };
- }
+ };
+ }
- this.set('config', config);
+ this.set('config', config);
- if (this.get('config.APIToken').length > 0) {
- this.send('auth');
- }
- },
+ if (this.get('config.APIToken').length > 0) {
+ this.send('auth');
+ }
+ },
- willDestroyElement() {
- this.destroyTooltips();
- },
+ willDestroyElement() {
+ this.destroyTooltips();
+ },
displayError(reason) {
if (netUtil.isAjaxAccessError(reason)) {
@@ -59,98 +59,102 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
}
},
- actions: {
- isDirty() {
- return this.get('isDirty');
- },
+ actions: {
+ isDirty() {
+ return this.get('isDirty');
+ },
- auth() {
+ auth() {
+ console.log(this.get('config'));
// missing data?
- this.set('config.APIToken', this.get('config.APIToken').trim());
+ this.set('config.APIToken', this.get('config.APIToken').trim());
- if (is.empty(this.get('config.APIToken'))) {
- $("#papertrail-apitoken").addClass("error").focus();
- return;
- }
+ if (is.empty(this.get('config.APIToken'))) {
+ $("#papertrail-apitoken").addClass("error").focus();
+ return;
+ }
- let page = this.get('page');
+ let page = this.get('page');
let config = this.get('config');
- let self = this;
+ let self = this;
- this.set('waiting', true);
+ this.set('waiting', true);
- this.get('sectionService').fetch(page, "auth", config)
- .then(function(response) {
- self.set('authenticated', true);
- self.set('items', response);
+ this.get('sectionService').fetch(page, "auth", config)
+ .then(function (response) {
+ self.set('authenticated', true);
+ self.set('items', response);
+ self.set('config.APIToken', '********'); // reset the api token once it has been sent to the host
- self.get('sectionService').fetch(page, "options", config)
- .then(function(response) {
- self.set('options', response);
- self.set('waiting', false);
+ self.get('sectionService').fetch(page, "options", config)
+ .then(function (response) {
+ self.set('options', response);
+ self.set('waiting', false);
- let options = self.get('options');
- let group = _.findWhere(options.groups, {id: config.group.id});
- if (is.not.undefined(group)) {
- Ember.set(config, 'group', group);
- }
- }, function(reason) { //jshint ignore: line
- self.set('waiting', false);
+ let options = self.get('options');
+ let group = _.findWhere(options.groups, { id: config.group.id });
+ if (is.not.undefined(group)) {
+ Ember.set(config, 'group', group);
+ }
+ }, function (reason) { //jshint ignore: line
+ self.set('waiting', false);
+ self.displayError(reason);
+ });
+ }, function (reason) { //jshint ignore: line
+ self.set('authenticated', false);
+ self.set('waiting', false);
+ self.set('config.APIToken', ''); // clear the api token
self.displayError(reason);
- });
- }, function(reason) { //jshint ignore: line
- self.set('authenticated', false);
- self.set('waiting', false);
- self.displayError(reason);
- });
- },
+ $("#papertrail-apitoken").addClass("error").focus();
+ });
+ },
onGroupsChange(group) {
let config = this.get('config');
let page = this.get('page');
let self = this;
- this.set('isDirty', true);
- this.set('config.group', group);
- this.set('waiting', true);
+ this.set('isDirty', true);
+ this.set('config.group', group);
+ this.set('waiting', true);
this.get('sectionService').fetch(page, "auth", config)
- .then(function(response) {
+ .then(function (response) {
+ self.set('waiting', false);
+ self.set('items', response);
+ }, function (reason) { //jshint ignore: line
self.set('waiting', false);
- self.set('items', response);
- }, function(reason) { //jshint ignore: line
- self.set('waiting', false);
self.displayError(reason);
- });
- },
+ });
+ },
onSystemsChange(system) {
let config = this.get('config');
let page = this.get('page');
let self = this;
- this.set('isDirty', true);
+ this.set('isDirty', true);
this.set('config.system', system);
- this.set('waiting', true);
+ this.set('waiting', true);
this.get('sectionService').fetch(page, "auth", config)
- .then(function(response) {
+ .then(function (response) {
+ self.set('waiting', false);
+ self.set('items', response);
+ }, function (reason) { //jshint ignore: line
self.set('waiting', false);
- self.set('items', response);
- }, function(reason) { //jshint ignore: line
- self.set('waiting', false);
self.displayError(reason);
- });
- },
+ });
+ },
- onCancel() {
- this.attrs.onCancel();
- },
+ onCancel() {
+ this.attrs.onCancel();
+ },
- onAction(title) {
+ onAction(title) {
let self = this;
- let page = this.get('page');
- let meta = this.get('meta');
- page.set('title', title);
- meta.set('externalSource', true);
+ let page = this.get('page');
+ let meta = this.get('meta');
+ page.set('title', title);
+ meta.set('externalSource', true);
let config = this.get('config');
let max = 10;
@@ -161,25 +165,25 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin,
Ember.set(config, 'max', max);
this.set('waiting', true);
- this.get('sectionService').fetch(page, "auth", this.get('config'))
- .then(function(response) {
- self.set('items', response);
- let items = self.get('items');
+ this.get('sectionService').fetch(page, "auth", this.get('config'))
+ .then(function (response) {
+ self.set('items', response);
+ let items = self.get('items');
- if (items.events.length > max) {
- items.events = items.events.slice(0, max);
- }
+ if (items.events.length > max) {
+ items.events = items.events.slice(0, max);
+ }
- meta.set('config', JSON.stringify(config));
- meta.set('rawBody', JSON.stringify(items));
+ meta.set('config', JSON.stringify(config));
+ meta.set('rawBody', JSON.stringify(items));
- self.set('waiting', false);
- self.attrs.onAction(page, meta);
- }, function(reason) { //jshint ignore: line
- self.set('authenticated', false);
- self.set('waiting', false);
- self.showNotification(`Something went wrong, try again!`);
- });
- }
- }
-});
+ self.set('waiting', false);
+ self.attrs.onAction(page, meta);
+ }, function (reason) { //jshint ignore: line
+ self.set('authenticated', false);
+ self.set('waiting', false);
+ self.showNotification(`Something went wrong, try again!`);
+ });
+ }
+ }
+});
\ No newline at end of file
diff --git a/app/app/services/audit.js b/app/app/services/audit.js
index 95c15754..d3e143f7 100644
--- a/app/app/services/audit.js
+++ b/app/app/services/audit.js
@@ -14,61 +14,65 @@ import netUtil from '../utils/net';
import config from '../config/environment';
export default Ember.Service.extend({
- sessionService: Ember.inject.service('session'),
- ready: false,
- enabled: config.APP.auditEnabled,
+ sessionService: Ember.inject.service('session'),
+ ready: false,
+ enabled: config.APP.auditEnabled,
appId: config.APP.intercomKey,
- init() {
- this.start();
- },
+ init() {
+ this.start();
+ },
- record(id) {
- if (!this.get('enabled') || is.empty(this.get('appId'))) {
- return;
- }
+ record(id) {
+ if (!this.get('enabled') || this.get('appId').length === 0) {
+ return;
+ }
- if (!this.get('ready')) {
- this.start();
- }
+ if (!this.get('ready')) {
+ this.start();
+ }
- Intercom('trackEvent', id); //jshint ignore: line
- Intercom('update'); //jshint ignore: line
- },
+ Intercom('trackEvent', id); //jshint ignore: line
+ Intercom('update'); //jshint ignore: line
+ },
- stop() {
- Intercom('shutdown'); //jshint ignore: line
- },
+ stop() {
+ if (!this.get('enabled') || this.get('appId').length === 0) {
+ return;
+ }
- start() {
- let session = this.get('sessionService');
+ Intercom('shutdown'); //jshint ignore: line
+ },
- if (this.get('appId') === "" || !this.get('enabled') || !session.authenticated || this.get('ready')) {
- return;
- }
+ start() {
+ let session = this.get('sessionService');
- this.set('ready', true);
+ if (this.get('appId') === "" || !this.get('enabled') || !session.authenticated || this.get('ready')) {
+ return;
+ }
- window.intercomSettings = {
- app_id: this.get('appId'),
- name: session.user.firstname + " " + session.user.lastname,
- email: session.user.email,
- user_id: session.user.id,
- "administrator": session.user.admin,
- company: {
- id: session.get('appMeta.orgId'),
- name: session.get('appMeta.title').string,
- "domain": netUtil.getSubdomain(),
- "version": session.get('appMeta.version')
- }
- };
+ this.set('ready', true);
- if (!session.get('isMobile')) {
- window.intercomSettings.widget = {
- activator: "#IntercomDefaultWidget"
- };
- }
+ window.intercomSettings = {
+ app_id: this.get('appId'),
+ name: session.user.firstname + " " + session.user.lastname,
+ email: session.user.email,
+ user_id: session.user.id,
+ "administrator": session.user.admin,
+ company: {
+ id: session.get('appMeta.orgId'),
+ name: session.get('appMeta.title').string,
+ "domain": netUtil.getSubdomain(),
+ "version": session.get('appMeta.version')
+ }
+ };
- window.Intercom('boot', window.intercomSettings);
- },
-});
+ if (!session.get('isMobile')) {
+ window.intercomSettings.widget = {
+ activator: "#IntercomDefaultWidget"
+ };
+ }
+
+ window.Intercom('boot', window.intercomSettings);
+ },
+});
\ No newline at end of file
diff --git a/app/app/templates/components/section/papertrail/type-editor.hbs b/app/app/templates/components/section/papertrail/type-editor.hbs
index 2d50af1d..a4759032 100644
--- a/app/app/templates/components/section/papertrail/type-editor.hbs
+++ b/app/app/templates/components/section/papertrail/type-editor.hbs
@@ -4,7 +4,11 @@
diff --git a/app/app/utils/net.js b/app/app/utils/net.js
index 2ba35f64..3a9900ae 100644
--- a/app/app/utils/net.js
+++ b/app/app/utils/net.js
@@ -10,37 +10,37 @@
// https://documize.com
function getSubdomain() {
- if (is.ipv4(window.location.host)) {
- return "";
- }
+ if (is.ipv4(window.location.host)) {
+ return "";
+ }
- let domain = "";
- let parts = window.location.host.split(".");
+ let domain = "";
+ let parts = window.location.host.split(".");
- if (parts.length > 1) {
- domain = parts[0].toLowerCase();
- }
+ if (parts.length > 1) {
+ domain = parts[0].toLowerCase();
+ }
- return domain;
+ return domain;
}
function getAppUrl(domain) {
- let parts = window.location.host.split(".");
- parts.removeAt(0);
+ let parts = window.location.host.split(".");
+ parts.removeAt(0);
- let leftOvers = parts.join(".");
+ let leftOvers = parts.join(".");
- if (is.empty(domain)) {
- domain = "";
- } else {
- domain = domain + ".";
- }
+ if (is.empty(domain)) {
+ domain = "";
+ } else {
+ domain = domain + ".";
+ }
- return window.location.protocol + "//" + domain + leftOvers;
+ return window.location.protocol + "//" + domain + leftOvers;
}
function isAjaxAccessError(reason) {
- if (typeof reason === "undefined") {
+ if (typeof reason === "undefined" || typeof reason.errors === "undefined") {
return false;
}
@@ -52,7 +52,7 @@ function isAjaxAccessError(reason) {
}
export default {
- getSubdomain,
- getAppUrl,
+ getSubdomain,
+ getAppUrl,
isAjaxAccessError,
-};
+};
\ No newline at end of file
diff --git a/documize/api/endpoint/page_endpoint.go b/documize/api/endpoint/page_endpoint.go
index 70f1ac4c..015bc7fa 100644
--- a/documize/api/endpoint/page_endpoint.go
+++ b/documize/api/endpoint/page_endpoint.go
@@ -79,6 +79,8 @@ func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
model.Meta.PageID = pageID
model.Page.SetDefaults()
model.Meta.SetDefaults()
+ model.Meta.OrgID = p.Context.OrgID
+ model.Meta.UserID = p.Context.UserID
// page.Title = template.HTMLEscapeString(page.Title)
tx, err := request.Db.Beginx()
@@ -90,7 +92,8 @@ func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
p.Context.Transaction = tx
- output, ok := provider.Render(model.Page.ContentType, model.Meta.Config, model.Meta.RawBody)
+ output, ok := provider.Render(model.Page.ContentType,
+ provider.NewContext(model.Meta.OrgID, model.Meta.UserID), model.Meta.Config, model.Meta.RawBody)
if !ok {
log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
}
@@ -374,7 +377,7 @@ func DeleteDocumentPages(w http.ResponseWriter, r *http.Request) {
writeSuccessEmptyJSON(w)
}
-// UpdateDocumentPage will persiste changed page and note the fact
+// UpdateDocumentPage will persist changed page and note the fact
// that this is a new revision. If the page is the first in a document
// then the corresponding document title will also be changed.
func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) {
@@ -432,7 +435,15 @@ func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) {
model.Page.SetDefaults()
model.Meta.SetDefaults()
- output, ok := provider.Render(model.Page.ContentType, model.Meta.Config, model.Meta.RawBody)
+ oldPageMeta, err := p.GetPageMeta(pageID)
+
+ if err != nil {
+ log.Error("unable to fetch old pagemeta record", err)
+ writeBadRequestError(w, method, err.Error())
+ return
+ }
+
+ output, ok := provider.Render(model.Page.ContentType, provider.NewContext(model.Meta.OrgID, oldPageMeta.UserID), model.Meta.Config, model.Meta.RawBody)
if !ok {
log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
}
@@ -452,7 +463,7 @@ func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) {
return
}
- err = p.UpdatePageMeta(model.Meta)
+ err = p.UpdatePageMeta(model.Meta, true) // change the UserID to the current one
log.IfErr(tx.Commit())
diff --git a/documize/api/endpoint/sections_endpoint.go b/documize/api/endpoint/sections_endpoint.go
index bdd163f5..27d5c3e2 100644
--- a/documize/api/endpoint/sections_endpoint.go
+++ b/documize/api/endpoint/sections_endpoint.go
@@ -70,7 +70,7 @@ func RunSectionCommand(w http.ResponseWriter, r *http.Request) {
return
}
- if !provider.Command(sectionName, w, r) {
+ if !provider.Command(sectionName, provider.NewContext(p.Context.OrgID, p.Context.UserID), w, r) {
log.ErrorString("Unable to run provider.Command() for: " + sectionName)
writeNotFoundError(w, "RunSectionCommand", sectionName)
}
@@ -125,14 +125,16 @@ func RefreshSections(w http.ResponseWriter, r *http.Request) {
return
}
+ pcontext := provider.NewContext(pm.OrgID, pm.UserID)
+
// Ask for data refresh
- data, ok := provider.Refresh(page.ContentType, pm.Config, pm.RawBody)
+ data, ok := provider.Refresh(page.ContentType, pcontext, pm.Config, pm.RawBody)
if !ok {
log.ErrorString("provider.Refresh could not find: " + page.ContentType)
}
// Render again
- body, ok := provider.Render(page.ContentType, pm.Config, data)
+ body, ok := provider.Render(page.ContentType, pcontext, pm.Config, data)
if !ok {
log.ErrorString("provider.Render could not find: " + page.ContentType)
}
@@ -153,7 +155,7 @@ func RefreshSections(w http.ResponseWriter, r *http.Request) {
return
}
- err = p.UpdatePageMeta(pm)
+ err = p.UpdatePageMeta(pm, false) // do not change the UserID on this PageMeta
if err != nil {
writeGeneralSQLError(w, method, err)
diff --git a/documize/api/entity/objects.go b/documize/api/entity/objects.go
index cececabb..fd9dc9c7 100644
--- a/documize/api/entity/objects.go
+++ b/documize/api/entity/objects.go
@@ -204,6 +204,7 @@ type PageMeta struct {
Created time.Time `json:"created"`
Revised time.Time `json:"revised"`
OrgID string `json:"orgId"`
+ UserID string `json:"userId"`
DocumentID string `json:"documentId"`
PageID string `json:"pageId"`
RawBody string `json:"rawBody"` // a blob of data
diff --git a/documize/api/request/config.go b/documize/api/request/config.go
index b88c424e..59063f9d 100644
--- a/documize/api/request/config.go
+++ b/documize/api/request/config.go
@@ -67,9 +67,9 @@ func ConfigString(area, path string) (ret string) {
return ret
}
-// UserConfigString fetches a configuration JSON element from the userconfig table.
+// UserConfigGetJSON fetches a configuration JSON element from the userconfig table for a given orgid/userid combination.
// Errors return the empty string. A blank path returns the whole JSON object, as JSON.
-func (p *Persister) UserConfigString(area, path string) (ret string) {
+func UserConfigGetJSON(orgid, userid, area, path string) (ret string) {
if Db == nil {
return ""
}
@@ -77,7 +77,7 @@ func (p *Persister) UserConfigString(area, path string) (ret string) {
path = "." + path
}
sql := "SELECT JSON_EXTRACT(`config`,'$" + path + "') FROM `userconfig` WHERE `key` = '" + area +
- "' AND `userid` = '" + p.Context.UserID + "';"
+ "' AND `orgid` = '" + orgid + "' AND `userid` = '" + userid + "';"
stmt, err := Db.Preparex(sql)
if err != nil {
@@ -105,15 +105,16 @@ func (p *Persister) UserConfigString(area, path string) (ret string) {
}
-// UserConfigSetJSON writes a configuration JSON element to the userconfig table.
-func (p *Persister) UserConfigSetJSON(area, json string) error {
+// UserConfigSetJSON writes a configuration JSON element to the userconfig table for the current user.
+func UserConfigSetJSON(orgid, userid, area, json string) error {
if Db == nil {
return errors.New("no database")
}
if area == "" {
return errors.New("no area")
}
- sql := "INSERT INTO `userconfig` (`userid`,`key`,`config`) VALUES ('" + p.Context.UserID + "','" + area + "','" + json +
+ sql := "INSERT INTO `userconfig` (`orgid`,`userid`,`key`,`config`) " +
+ "VALUES ('" + orgid + "','" + userid + "','" + area + "','" + json +
"') ON DUPLICATE KEY UPDATE `config`='" + json + "';"
stmt, err := Db.Preparex(sql)
diff --git a/documize/api/request/page.go b/documize/api/request/page.go
index 3ac3e1d3..7e220d58 100644
--- a/documize/api/request/page.go
+++ b/documize/api/request/page.go
@@ -34,6 +34,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
model.Page.SetDefaults()
model.Meta.OrgID = p.Context.OrgID
+ model.Meta.UserID = p.Context.UserID
model.Meta.DocumentID = model.Page.DocumentID
model.Meta.Created = time.Now().UTC()
model.Meta.Revised = time.Now().UTC()
@@ -65,7 +66,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
err = searches.Add(&databaseRequest{OrgID: p.Context.OrgID}, model.Page, model.Page.RefID)
- stmt2, err := p.Context.Transaction.Preparex("INSERT INTO pagemeta (pageid, orgid, documentid, rawbody, config, externalsource, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
+ stmt2, err := p.Context.Transaction.Preparex("INSERT INTO pagemeta (pageid, orgid, userid, documentid, rawbody, config, externalsource, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
defer utility.Close(stmt2)
if err != nil {
@@ -73,7 +74,7 @@ func (p *Persister) AddPage(model models.PageModel) (err error) {
return
}
- _, err = stmt2.Exec(model.Meta.PageID, model.Meta.OrgID, model.Meta.DocumentID, model.Meta.RawBody, model.Meta.Config, model.Meta.ExternalSource, model.Meta.Created, model.Meta.Revised)
+ _, err = stmt2.Exec(model.Meta.PageID, model.Meta.OrgID, model.Meta.UserID, model.Meta.DocumentID, model.Meta.RawBody, model.Meta.Config, model.Meta.ExternalSource, model.Meta.Created, model.Meta.Revised)
if err != nil {
log.Error("Unable to execute insert for page meta", err)
@@ -291,12 +292,15 @@ func (p *Persister) UpdatePage(page entity.Page, refID, userID string, skipRevis
}
// UpdatePageMeta persists meta information associated with a document page.
-func (p *Persister) UpdatePageMeta(meta entity.PageMeta) (err error) {
+func (p *Persister) UpdatePageMeta(meta entity.PageMeta,updateUserID bool) (err error) {
err = nil
meta.Revised = time.Now().UTC()
+ if updateUserID {
+ meta.UserID=p.Context.UserID
+ }
var stmt *sqlx.NamedStmt
- stmt, err = p.Context.Transaction.PrepareNamed("UPDATE pagemeta SET documentid=:documentid, rawbody=:rawbody, config=:config, externalsource=:externalsource, revised=:revised WHERE orgid=:orgid AND pageid=:pageid")
+ stmt, err = p.Context.Transaction.PrepareNamed("UPDATE pagemeta SET userid=:userid, documentid=:documentid, rawbody=:rawbody, config=:config, externalsource=:externalsource, revised=:revised WHERE orgid=:orgid AND pageid=:pageid")
defer utility.Close(stmt)
if err != nil {
@@ -383,7 +387,7 @@ func (p *Persister) DeletePage(documentID, pageID string) (rows int64, err error
func (p *Persister) GetPageMeta(pageID string) (meta entity.PageMeta, err error) {
err = nil
- stmt, err := Db.Preparex("SELECT id, pageid, orgid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND pageid=?")
+ stmt, err := Db.Preparex("SELECT id, pageid, orgid, userid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND pageid=?")
defer utility.Close(stmt)
if err != nil {
@@ -409,7 +413,7 @@ func (p *Persister) GetDocumentPageMeta(documentID string, externalSourceOnly bo
filter = " AND externalsource=1"
}
- err = Db.Select(&meta, "SELECT id, pageid, orgid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND documentid=?"+filter, p.Context.OrgID, documentID)
+ err = Db.Select(&meta, "SELECT id, pageid, orgid, userid, documentid, rawbody, coalesce(config,JSON_UNQUOTE('{}')) as config, externalsource, created, revised FROM pagemeta WHERE orgid=? AND documentid=?"+filter, p.Context.OrgID, documentID)
if err != nil {
log.Error(fmt.Sprintf("Unable to execute select document page meta for org %s and document %s", p.Context.OrgID, documentID), err)
diff --git a/documize/database/scripts/autobuild/db_00000.sql b/documize/database/scripts/autobuild/db_00000.sql
index 481c8cbe..710a3ecd 100644
--- a/documize/database/scripts/autobuild/db_00000.sql
+++ b/documize/database/scripts/autobuild/db_00000.sql
@@ -168,6 +168,7 @@ CREATE TABLE IF NOT EXISTS `pagemeta` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`pageid` CHAR(16) NOT NULL COLLATE utf8_bin,
`orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
+ `userid` CHAR(16) NOT NULL COLLATE utf8_bin,
`documentid` CHAR(16) NOT NULL COLLATE utf8_bin,
`rawbody` LONGBLOB,
`config` JSON,
@@ -270,8 +271,12 @@ INSERT INTO `config` VALUES ('SECTION-TRELLO','{\"appKey\": \"\"}');
DROP TABLE IF EXISTS `userconfig`;
CREATE TABLE IF NOT EXISTS `userconfig` (
+ `orgid` CHAR(16) NOT NULL COLLATE utf8_bin,
`userid` CHAR(16) NOT NULL COLLATE utf8_bin,
`key` CHAR(225) NOT NULL,
`config` JSON,
- UNIQUE INDEX `idx_userconfig_userkey` (`userid`, `key` ASC) )
-DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
\ No newline at end of file
+ UNIQUE INDEX `idx_userconfig_orguserkey` (`orgid`, `userid`, `key` ASC) )
+ DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+-- TODO insert userid into pagemeta table
+-- ALTER TABLE `pagemeta` ADD `userid` CHAR(16) NOT NULL COLLATE utf8_bin AFTER `orgid`;
diff --git a/documize/section/asana/asana.go b/documize/section/asana/asana.go
index 19a0b212..47c64711 100644
--- a/documize/section/asana/asana.go
+++ b/documize/section/asana/asana.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/code/code.go b/documize/section/code/code.go
index fa28c118..8d8370e3 100644
--- a/documize/section/code/code.go
+++ b/documize/section/code/code.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/docusign/docusign.go b/documize/section/docusign/docusign.go
index fa02d8d4..03ce4a22 100644
--- a/documize/section/docusign/docusign.go
+++ b/documize/section/docusign/docusign.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/gemini/gemini.go b/documize/section/gemini/gemini.go
index 4478c286..8dd2a64d 100644
--- a/documize/section/gemini/gemini.go
+++ b/documize/section/gemini/gemini.go
@@ -40,7 +40,7 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Render converts Gemini data into HTML suitable for browser rendering.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
var items []geminiItem
var payload = geminiRender{}
var c = geminiConfig{}
@@ -64,7 +64,7 @@ func (*Provider) Render(config, data string) string {
}
// Command handles authentication, workspace listing and items retrieval.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
method := query.Get("method")
@@ -84,7 +84,7 @@ func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) (newData string) {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) (newData string) {
var c = geminiConfig{}
err := json.Unmarshal([]byte(config), &c)
diff --git a/documize/section/github/github.go b/documize/section/github/github.go
index 8b046228..d872db84 100644
--- a/documize/section/github/github.go
+++ b/documize/section/github/github.go
@@ -65,9 +65,22 @@ func authorizationCallbackURL() string {
// NOTE: URL value must have the path and query "/api/public/validate?section=github"
return request.ConfigString(meta.ConfigHandle(), "authorizationCallbackURL")
}
+func validateToken(ptoken string) error {
+ // Github authorization check
+ authClient := gogithub.NewClient((&gogithub.BasicAuthTransport{
+ Username: clientID(),
+ Password: clientSecret(),
+ }).Client())
+ _, _, err := authClient.Authorizations.Check(clientID(), ptoken)
+ return err
+}
+
+func secretsJSON(token string) string {
+ return `{"token":"` + strings.TrimSpace(token) + `"}`
+}
// Command to run the various functions required...
-func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (p *Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
method := query.Get("method")
@@ -100,6 +113,25 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
return
}
+ // get the secret token in the database
+ ptoken := ctx.GetSecrets("token")
+
+ switch method {
+
+ case "saveSecret": // secret Token update code
+
+ // write the new one, direct from JS
+ if err = ctx.SaveSecrets(string(body)); err != nil {
+ log.Error("github settoken configuration", err)
+ provider.WriteError(w, "github", err)
+ return
+ }
+ provider.WriteEmpty(w)
+ return
+
+ }
+
+ // load the config from the client-side
config := githubConfig{}
err = json.Unmarshal(body, &config)
@@ -110,64 +142,30 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
}
config.Clean()
+ // always use DB version of the token
+ config.Token = ptoken
- persist := request.GetPersister(r)
+ client := p.githubClient(config)
- ptoken := persist.UserConfigString(meta.ContentType, "token")
+ switch method { // the main data handling switch
- switch method { // the token handling switch
- case "set_token":
- // write the new one
- if err = persist.UserConfigSetJSON(meta.ContentType, `{"token":"`+config.Token+`"}`); err != nil {
- log.Error("github settoken configuration", err)
+ case "checkAuth":
+
+ if len(ptoken) == 0 {
+ err = errors.New("empty github token")
+ } else {
+ err = validateToken(ptoken)
+ }
+ if err != nil {
+ // token now invalid, so wipe it
+ ctx.SaveSecrets("") // ignore error, already in an error state
+ log.Error("github check token validation", err)
provider.WriteError(w, "github", err)
return
}
provider.WriteEmpty(w)
return
- case "check_token":
- if config.Token != ptoken {
- // user github token does not match that in the database, so use DB version as the section version may be out-of-date
- config.Token = ptoken
- }
- if err = config.TokenCheck(); err != nil {
- log.Error("github checktoken validation", err)
- provider.WriteError(w, "github", err)
- return
- }
- provider.WriteJSON(w, config)
- return
-
- default:
- if config.Token != ptoken {
- if len(config.Token) == 0 {
- if len(ptoken) == 0 {
- err = errors.New("missing github token")
- } else {
- config.Token = ptoken // use database one
- }
- } else {
- // this is important when switching user
- // tokens are different...
- if len(ptoken) == 0 {
- err = errors.New("no user github token")
- } else {
- config.Token = ptoken // use database one
- }
- }
- }
- if err != nil {
- log.Error("github clean token configuration", err)
- provider.WriteError(w, "github", err)
- return
- }
- }
-
- client := p.githubClient(config)
-
- switch method { // the main data handling switch
-
case tagCommitsData:
render, err := p.getCommits(client, config)
@@ -255,7 +253,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
provider.WriteError(w, "github", err)
return
}
- for kr, vr := range repos {
+ for _, vr := range repos {
private := ""
if *vr.Private {
private = " (private)"
@@ -263,7 +261,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
render = append(render,
githubRepo{
Name: config.Owner + "/" + *vr.Name + private,
- ID: fmt.Sprintf("%s:%s:%d", config.Owner, *vr.Name, kr),
+ ID: fmt.Sprintf("%s:%s", config.Owner, *vr.Name),
Owner: config.Owner,
Repo: *vr.Name,
Private: *vr.Private,
@@ -276,6 +274,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
provider.WriteJSON(w, render)
case "branches":
+
if config.Owner == "" || config.Repo == "" {
provider.WriteJSON(w, []githubBranch{}) // we have nothing to return
return
@@ -291,7 +290,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
for kc, vb := range branches {
render[kc] = githubBranch{
Name: *vb.Name,
- ID: fmt.Sprintf("%s:%s:%s:%d", config.Owner, config.Repo, *vb.Name, kc),
+ ID: fmt.Sprintf("%s:%s:%s", config.Owner, config.Repo, *vb.Name),
Included: false,
URL: "https://github.com/" + config.Owner + "/" + config.Repo + "/tree/" + *vb.Name,
}
@@ -300,6 +299,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
provider.WriteJSON(w, render)
case "labels":
+
if config.Owner == "" || config.Repo == "" {
provider.WriteJSON(w, []githubBranch{}) // we have nothing to return
return
@@ -324,6 +324,7 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
provider.WriteJSON(w, render)
default:
+
log.ErrorString("Github connector unknown method: " + method)
provider.WriteEmpty(w)
}
@@ -620,7 +621,7 @@ func (*Provider) getCommits(client *gogithub.Client, config githubConfig) ([]git
}
// Refresh ... gets the latest version
-func (p *Provider) Refresh(configJSON, data string) string {
+func (p *Provider) Refresh(ctx *provider.Context, configJSON, data string) string {
var c = githubConfig{}
err := json.Unmarshal([]byte(configJSON), &c)
@@ -631,6 +632,7 @@ func (p *Provider) Refresh(configJSON, data string) string {
}
c.Clean()
+ c.Token = ctx.GetSecrets("token")
switch c.ReportInfo.ID {
/*case "issuenum_data":
@@ -681,7 +683,7 @@ func (p *Provider) Refresh(configJSON, data string) string {
}
// Render ... just returns the data given, suitably formatted
-func (p *Provider) Render(config, data string) string {
+func (p *Provider) Render(ctx *provider.Context, config, data string) string {
var err error
payload := githubRender{}
@@ -695,6 +697,8 @@ func (p *Provider) Render(config, data string) string {
}
c.Clean()
+ c.Token = ctx.GetSecrets("token")
+
payload.Config = c
payload.Repo = c.RepoInfo
payload.Limit = c.BranchLines
diff --git a/documize/section/github/model.go b/documize/section/github/model.go
index 7e822262..6cf52894 100644
--- a/documize/section/github/model.go
+++ b/documize/section/github/model.go
@@ -13,15 +13,13 @@ package github
import (
"html/template"
- "strings"
"time"
"github.com/documize/community/wordsmith/log"
- gogithub "github.com/google/go-github/github"
)
-const tagIssuesData = "issues_data"
-const tagCommitsData = "commits_data"
+const tagIssuesData = "issuesData"
+const tagCommitsData = "commitsData"
type githubRender struct {
Config githubConfig
@@ -219,8 +217,9 @@ type githubIssueActivity struct {
*/
type githubConfig struct {
- AppKey string `json:"appKey"` // TODO keep?
- Token string `json:"token"`
+ Token string `json:"-"` // NOTE very important that the secret Token is not leaked to the client side, so "-"
+ UserID string `json:"userId"`
+ PageID string `json:"pageId"`
Owner string `json:"owner_name"`
Repo string `json:"repo_name"`
Branch string `json:"branch"`
@@ -240,8 +239,6 @@ type githubConfig struct {
}
func (c *githubConfig) Clean() {
- c.AppKey = strings.TrimSpace(c.AppKey) // TODO keep?
- c.Token = strings.TrimSpace(c.Token)
c.Owner = c.OwnerInfo.Name
c.Repo = c.RepoInfo.Repo
for _, l := range c.Lists {
@@ -264,18 +261,6 @@ func (c *githubConfig) Clean() {
c.SincePtr = &since
}
}
-
-}
-
-func (c *githubConfig) TokenCheck() error {
- // Github authorization check
- authClient := gogithub.NewClient((&gogithub.BasicAuthTransport{
- Username: clientID(),
- Password: clientSecret(),
- }).Client())
-
- _, _, err := authClient.Authorizations.Check(clientID(), c.Token)
- return err
}
type githubCallbackT struct {
diff --git a/documize/section/intercom/intercom.go b/documize/section/intercom/intercom.go
index b3ea5e8c..5abe1c66 100644
--- a/documize/section/intercom/intercom.go
+++ b/documize/section/intercom/intercom.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/mailchimp/mailchimp.go b/documize/section/mailchimp/mailchimp.go
index 9a09fd50..cff56cd0 100644
--- a/documize/section/mailchimp/mailchimp.go
+++ b/documize/section/mailchimp/mailchimp.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/markdown/markdown.go b/documize/section/markdown/markdown.go
index 924abf7e..5e739c3c 100644
--- a/documize/section/markdown/markdown.go
+++ b/documize/section/markdown/markdown.go
@@ -36,18 +36,18 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render converts markdown data into HTML suitable for browser rendering.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
result := blackfriday.MarkdownCommon([]byte(data))
return string(result)
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/papertrail/model.go b/documize/section/papertrail/model.go
index 01dede45..914ce855 100644
--- a/documize/section/papertrail/model.go
+++ b/documize/section/papertrail/model.go
@@ -61,7 +61,7 @@ type papertrailEvent struct {
}
type papertrailConfig struct {
- APIToken string `json:"APIToken"`
+ APIToken string `json:"APIToken"` // only contains the correct token just after it is typed in
Query string `json:"query"`
Max int `json:"max"`
Group papertrailOption `json:"group"`
diff --git a/documize/section/papertrail/papertrail.go b/documize/section/papertrail/papertrail.go
index 98339bd2..6e12f874 100644
--- a/documize/section/papertrail/papertrail.go
+++ b/documize/section/papertrail/papertrail.go
@@ -42,7 +42,7 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Render converts Papertrail data into HTML suitable for browser rendering.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
var search papertrailSearch
var events []papertrailEvent
var payload = papertrailRender{}
@@ -51,6 +51,8 @@ func (*Provider) Render(config, data string) string {
json.Unmarshal([]byte(data), &search)
json.Unmarshal([]byte(config), &c)
+ c.APIToken = ctx.GetSecrets("APIToken")
+
max := len(search.Events)
if c.Max < max {
max = c.Max
@@ -74,7 +76,7 @@ func (*Provider) Render(config, data string) string {
}
// Command handles authentication, workspace listing and items retrieval.
-func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (p *Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
method := query.Get("method")
@@ -101,6 +103,10 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
config.Clean()
+ if config.APIToken == provider.SecretReplacement {
+ config.APIToken = ctx.GetSecrets("APIToken")
+ }
+
if len(config.APIToken) == 0 {
provider.WriteMessage(w, me, "Missing API token")
return
@@ -108,14 +114,14 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) {
switch method {
case "auth":
- auth(config, w, r)
+ auth(ctx, config, w, r)
case "options":
options(config, w, r)
}
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) (newData string) {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) (newData string) {
var c = papertrailConfig{}
err := json.Unmarshal([]byte(config), &c)
@@ -126,6 +132,8 @@ func (*Provider) Refresh(config, data string) (newData string) {
c.Clean()
+ c.APIToken = ctx.GetSecrets("APIToken")
+
if len(c.APIToken) == 0 {
log.Error("missing API token", err)
return
@@ -149,7 +157,7 @@ func (*Provider) Refresh(config, data string) (newData string) {
return
}
-func auth(config papertrailConfig, w http.ResponseWriter, r *http.Request) {
+func auth(ctx *provider.Context, config papertrailConfig, w http.ResponseWriter, r *http.Request) {
result, err := fetchEvents(config)
if err != nil {
@@ -162,6 +170,8 @@ func auth(config papertrailConfig, w http.ResponseWriter, r *http.Request) {
return
}
+ log.IfErr(ctx.SaveSecrets(`{"APIToken":"` + config.APIToken + `"}`))
+
provider.WriteJSON(w, result)
}
diff --git a/documize/section/provider/provider.go b/documize/section/provider/provider.go
index cffd3cc3..92e40c72 100644
--- a/documize/section/provider/provider.go
+++ b/documize/section/provider/provider.go
@@ -19,9 +19,14 @@ import (
"sort"
"strings"
+ "github.com/documize/community/documize/api/request"
"github.com/documize/community/wordsmith/log"
)
+// SecretReplacement is a constant used to replace secrets in data-structures when required.
+// 8 stars.
+const SecretReplacement = "********"
+
// sectionsMap is where individual sections register themselves.
var sectionsMap = make(map[string]Provider)
@@ -43,10 +48,26 @@ func (t *TypeMeta) ConfigHandle() string {
// Provider represents a 'page' in a document.
type Provider interface {
- Meta() TypeMeta // Meta returns section details
- Command(w http.ResponseWriter, r *http.Request) // Command is general-purpose method that can return data to UI
- Render(config, data string) string // Render converts section data into presentable HTML
- Refresh(config, data string) string // Refresh returns latest data
+ Meta() TypeMeta // Meta returns section details
+ Command(ctx *Context, w http.ResponseWriter, r *http.Request) // Command is general-purpose method that can return data to UI
+ Render(ctx *Context, config, data string) string // Render converts section data into presentable HTML
+ Refresh(ctx *Context, config, data string) string // Refresh returns latest data
+}
+
+// Context describes the environment the section code runs in
+type Context struct {
+ OrgID string
+ UserID string
+ prov Provider
+ inCommand bool
+}
+
+// NewContext is a convenience function.
+func NewContext(orgid, userid string) *Context {
+ if orgid == "" || userid == "" {
+ log.Error("NewContext incorrect orgid:"+orgid+" userid:"+userid, errors.New("bad section context"))
+ }
+ return &Context{OrgID: orgid, UserID: userid}
}
// Register makes document section type available
@@ -71,10 +92,12 @@ func GetSectionMeta() []TypeMeta {
}
// Command passes parameters to the given section id, the returned bool indicates success.
-func Command(section string, w http.ResponseWriter, r *http.Request) bool {
+func Command(section string, ctx *Context, w http.ResponseWriter, r *http.Request) bool {
s, ok := sectionsMap[section]
if ok {
- s.Command(w, r)
+ ctx.prov = s
+ ctx.inCommand = true
+ s.Command(ctx, w, r)
}
return ok
}
@@ -91,19 +114,21 @@ func Callback(section string, w http.ResponseWriter, r *http.Request) error {
}
// Render runs that operation for the given section id, the returned bool indicates success.
-func Render(section, config, data string) (string, bool) {
+func Render(section string, ctx *Context, config, data string) (string, bool) {
s, ok := sectionsMap[section]
if ok {
- return s.Render(config, data), true
+ ctx.prov = s
+ return s.Render(ctx, config, data), true
}
return "", false
}
// Refresh returns the latest data for a section.
-func Refresh(section, config, data string) (string, bool) {
+func Refresh(section string, ctx *Context, config, data string) (string, bool) {
s, ok := sectionsMap[section]
if ok {
- return s.Refresh(config, data), true
+ ctx.prov = s
+ return s.Refresh(ctx, config, data), true
}
return "", false
}
@@ -174,6 +199,28 @@ func WriteForbidden(w http.ResponseWriter) {
log.IfErr(err)
}
+// Secrets handling
+
+// SaveSecrets for the current user/org combination.
+// The secrets must be in the form of a JSON format string, for example `{"mysecret":"lover"}`.
+// An empty string signifies no valid secrets for this user/org combination.
+// Note that this function can only be called within the Command method of a section.
+func (c *Context) SaveSecrets(JSONobj string) error {
+ if !c.inCommand {
+ return errors.New("SaveSecrets() may only be called from within Command()")
+ }
+ return request.UserConfigSetJSON(c.OrgID, c.UserID, c.prov.Meta().ContentType, JSONobj)
+}
+
+// GetSecrets for the current context user/org.
+// For example (see SaveSecrets example): thisContext.GetSecrets("mysecret")
+// JSONpath format is defined at https://dev.mysql.com/doc/refman/5.7/en/json-path-syntax.html .
+// An empty JSONpath returns the whole JSON object, as JSON.
+// Errors return the empty string.
+func (c *Context) GetSecrets(JSONpath string) string {
+ return request.UserConfigGetJSON(c.OrgID, c.UserID, c.prov.Meta().ContentType, JSONpath)
+}
+
// sort sections in order that that should be presented.
type sectionsToSort []TypeMeta
diff --git a/documize/section/register.go b/documize/section/register.go
index 057e937a..f75134f9 100644
--- a/documize/section/register.go
+++ b/documize/section/register.go
@@ -50,7 +50,6 @@ func Register() {
provider.Register("trello", &trello.Provider{})
provider.Register("wysiwyg", &wysiwyg.Provider{})
provider.Register("zendesk", &zendesk.Provider{})
-
p := provider.List()
log.Info(fmt.Sprintf("Documize registered %d smart sections", len(p)))
}
diff --git a/documize/section/salesforce/salesforce.go b/documize/section/salesforce/salesforce.go
index e5a165f7..9970d485 100644
--- a/documize/section/salesforce/salesforce.go
+++ b/documize/section/salesforce/salesforce.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/stripe/stripe.go b/documize/section/stripe/stripe.go
index cd76fedd..c646cf14 100644
--- a/documize/section/stripe/stripe.go
+++ b/documize/section/stripe/stripe.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/table/table.go b/documize/section/table/table.go
index 9eed6556..22cc0add 100644
--- a/documize/section/table/table.go
+++ b/documize/section/table/table.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render sends back data as-is (HTML).
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/trello/trello.go b/documize/section/trello/trello.go
index 72fa6f3e..32fcb6ad 100644
--- a/documize/section/trello/trello.go
+++ b/documize/section/trello/trello.go
@@ -45,7 +45,7 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
method := query.Get("method")
@@ -137,7 +137,7 @@ func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
raw := []trelloListCards{}
payload := trelloRender{}
var c = trelloConfig{}
@@ -163,7 +163,7 @@ func (*Provider) Render(config, data string) string {
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
var c = trelloConfig{}
json.Unmarshal([]byte(config), &c)
diff --git a/documize/section/wysiwyg/wysiwyg.go b/documize/section/wysiwyg/wysiwyg.go
index 7e801aa9..1f9ea62f 100644
--- a/documize/section/wysiwyg/wysiwyg.go
+++ b/documize/section/wysiwyg/wysiwyg.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render returns data as-is (HTML).
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}
diff --git a/documize/section/zendesk/zendesk.go b/documize/section/zendesk/zendesk.go
index bbfb0829..8b2d1ba5 100644
--- a/documize/section/zendesk/zendesk.go
+++ b/documize/section/zendesk/zendesk.go
@@ -35,16 +35,16 @@ func (*Provider) Meta() provider.TypeMeta {
}
// Command stub.
-func (*Provider) Command(w http.ResponseWriter, r *http.Request) {
+func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
provider.WriteEmpty(w)
}
// Render just sends back HMTL as-is.
-func (*Provider) Render(config, data string) string {
+func (*Provider) Render(ctx *provider.Context, config, data string) string {
return data
}
// Refresh just sends back data as-is.
-func (*Provider) Refresh(config, data string) string {
+func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
return data
}