diff --git a/app/app/components/section/gemini/type-editor.js b/app/app/components/section/gemini/type-editor.js index 14a265b9..dd3babf7 100644 --- a/app/app/components/section/gemini/type-editor.js +++ b/app/app/components/section/gemini/type-editor.js @@ -15,194 +15,212 @@ import TooltipMixin from '../../../mixins/tooltip'; import SectionMixin from '../../../mixins/section'; export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, { - sectionService: Ember.inject.service('section'), - isDirty: false, - waiting: false, - authenticated: false, - user: {}, - workspaces: [], - config: {}, + sectionService: Ember.inject.service('section'), + isDirty: false, + waiting: false, + authenticated: false, + user: {}, + workspaces: [], + config: {}, - 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 = { - APIKey: "", - filter: {}, - itemCount: 0, - url: "", - userId: 0, - username: "", - workspaceId: 0, - workspaceName: "", - }; - } + if (is.empty(config)) { + config = { + APIKey: "", + filter: {}, + itemCount: 0, + url: "", + userId: 0, + username: "", + workspaceId: 0, + workspaceName: "", + }; + } - this.set('config', config); + this.set('config', config); - if (this.get('config.userId') > 0) { - this.send('auth'); - } - }, + let self = this; + self.set('waiting', true); + this.get('sectionService').fetch(this.get('page'), "secrets", this.get('config')) + .then(function (response) { + console.log(response); + self.set('waiting', false); - willDestroyElement() { - this.destroyTooltips(); - }, + self.set('config.APIKey', response.apikey); + self.set('config.url', response.url); + self.set('config.username', response.username); - getWorkspaces() { - let page = this.get('page'); - let self = this; - this.set('waiting', true); + if (response.apikey.length > 0 && response.url.length > 0 && response.username.length > 0) { + self.send('auth'); + } + }, function (reason) { //jshint ignore: line + console.log(reason); + self.set('waiting', false); + if (self.get('config.userId') > 0) { + self.send('auth'); + } + }); + }, - this.get('sectionService').fetch(page, "workspace", this.get('config')) - .then(function(response) { - // console.log(response); - let workspaceId = self.get('config.workspaceId'); + willDestroyElement() { + this.destroyTooltips(); + }, - if (response.length > 0 && workspaceId === 0) { - workspaceId = response[0].Id; - } + getWorkspaces() { + let page = this.get('page'); + let self = this; + this.set('waiting', true); - self.set("config.workspaceId", workspaceId); - self.set('workspaces', response); - self.selectWorkspace(workspaceId); + this.get('sectionService').fetch(page, "workspace", this.get('config')) + .then(function (response) { + // console.log(response); + let workspaceId = self.get('config.workspaceId'); - Ember.run.schedule('afterRender', function() { - window.scrollTo(0, document.body.scrollHeight); + if (response.length > 0 && workspaceId === 0) { + workspaceId = response[0].Id; + } - response.forEach(function(workspace) { - self.addTooltip(document.getElementById("gemini-workspace-" + workspace.Id)); - }); - }); - self.set('waiting', false); - }, function(reason) { //jshint ignore: line - self.set('workspaces', []); - self.set('waiting', false); - }); - }, + self.set("config.workspaceId", workspaceId); + self.set('workspaces', response); + self.selectWorkspace(workspaceId); - getItems() { - let page = this.get('page'); - let self = this; + Ember.run.schedule('afterRender', function () { + window.scrollTo(0, document.body.scrollHeight); - this.set('waiting', true); + response.forEach(function (workspace) { + self.addTooltip(document.getElementById("gemini-workspace-" + workspace.Id)); + }); + }); + self.set('waiting', false); + }, function (reason) { //jshint ignore: line + self.set('workspaces', []); + self.set('waiting', false); + }); + }, - this.get('sectionService').fetch(page, "items", this.get('config')) - .then(function(response) { - // console.log(response); - self.set('items', response); - self.set('config.itemCount', response.length); - self.set('waiting', false); - }, function(reason) { //jshint ignore: line - self.set('items', []); - self.set('waiting', false); - }); - }, + getItems() { + let page = this.get('page'); + let self = this; - selectWorkspace(id) { - let self = this; - let w = this.get('workspaces'); + this.set('waiting', true); - w.forEach(function(w) { - Ember.set(w, 'selected', w.Id === id); + this.get('sectionService').fetch(page, "items", this.get('config')) + .then(function (response) { + // console.log(response); + self.set('items', response); + self.set('config.itemCount', response.length); + self.set('waiting', false); + }, function (reason) { //jshint ignore: line + self.set('items', []); + self.set('waiting', false); + }); + }, - if (w.Id === id) { - self.set("config.filter", w.Filter); - self.set("config.workspaceId", id); - self.set("config.workspaceName", w.Title); - // console.log(self.get('config')); - } - }); + selectWorkspace(id) { + let self = this; + let w = this.get('workspaces'); - this.set('workspaces', w); - this.getItems(); - }, + w.forEach(function (w) { + Ember.set(w, 'selected', w.Id === id); - actions: { - isDirty() { - return this.get('isDirty'); - }, + if (w.Id === id) { + self.set("config.filter", w.Filter); + self.set("config.workspaceId", id); + self.set("config.workspaceName", w.Title); + // console.log(self.get('config')); + } + }); - auth() { - // missing data? - if (is.empty(this.get('config.url'))) { - $("#gemini-url").addClass("error").focus(); - return; - } - if (is.empty(this.get('config.username'))) { - $("#gemini-username").addClass("error").focus(); - return; - } - if (is.empty(this.get('config.APIKey'))) { - $("#gemini-apikey").addClass("error").focus(); - return; - } + this.set('workspaces', w); + this.getItems(); + }, - // knock out spaces - this.set('config.url', this.get('config.url').trim()); - this.set('config.username', this.get('config.username').trim()); - this.set('config.APIKey', this.get('config.APIKey').trim()); + actions: { + isDirty() { + return this.get('isDirty'); + }, - // remove trailing slash in URL - let url = this.get('config.url'); - if (url.indexOf("/", url.length - 1) !== -1) { - this.set('config.url', url.substring(0, url.length - 1)); - } + auth() { + // missing data? + if (is.empty(this.get('config.url'))) { + $("#gemini-url").addClass("error").focus(); + return; + } + if (is.empty(this.get('config.username'))) { + $("#gemini-username").addClass("error").focus(); + return; + } + if (is.empty(this.get('config.APIKey'))) { + $("#gemini-apikey").addClass("error").focus(); + return; + } - let page = this.get('page'); - let self = this; + // knock out spaces + this.set('config.url', this.get('config.url').trim()); + this.set('config.username', this.get('config.username').trim()); + this.set('config.APIKey', this.get('config.APIKey').trim()); - this.set('waiting', true); + // remove trailing slash in URL + let url = this.get('config.url'); + if (url.indexOf("/", url.length - 1) !== -1) { + this.set('config.url', url.substring(0, url.length - 1)); + } - this.get('sectionService').fetch(page, "auth", this.get('config')) - .then(function(response) { - self.set('authenticated', true); - self.set('user', response); - self.set('config.userId', response.BaseEntity.id); - self.set('waiting', false); - self.getWorkspaces(); - }, function(reason) { //jshint ignore: line - self.set('authenticated', false); - self.set('user', null); - self.set('config.userId', 0); - self.set('waiting', false); + let page = this.get('page'); + let self = this; - switch (reason.status) { - case 400: - self.showNotification(`Unable to connect to Gemini URL`); - break; - case 403: - self.showNotification(`Unable to authenticate`); - break; - default: - self.showNotification(`Something went wrong, try again!`); - } - }); - }, + this.set('waiting', true); - onWorkspaceChange(id) { - this.set('isDirty', true); - this.selectWorkspace(id); - }, + this.get('sectionService').fetch(page, "auth", this.get('config')) + .then(function (response) { + self.set('authenticated', true); + self.set('user', response); + self.set('config.userId', response.BaseEntity.id); + self.set('waiting', false); + self.getWorkspaces(); + }, function (reason) { //jshint ignore: line + self.set('authenticated', false); + self.set('user', null); + self.set('config.userId', 0); + self.set('waiting', false); - onCancel() { - this.attrs.onCancel(); - }, + switch (reason.status) { + case 400: + self.showNotification(`Unable to connect to Gemini URL`); + break; + case 403: + self.showNotification(`Unable to authenticate`); + break; + default: + self.showNotification(`Something went wrong, try again!`); + } + }); + }, - onAction(title) { - let page = this.get('page'); - let meta = this.get('meta'); - page.set('title', title); - meta.set('rawBody', JSON.stringify(this.get("items"))); - meta.set('config', JSON.stringify(this.get('config'))); - meta.set('externalSource', true); + onWorkspaceChange(id) { + this.set('isDirty', true); + this.selectWorkspace(id); + }, - this.attrs.onAction(page, meta); - } - } + onCancel() { + this.attrs.onCancel(); + }, + + onAction(title) { + let page = this.get('page'); + let meta = this.get('meta'); + page.set('title', title); + meta.set('rawBody', JSON.stringify(this.get("items"))); + meta.set('config', JSON.stringify(this.get('config'))); + meta.set('externalSource', true); + + this.attrs.onAction(page, meta); + } + } }); \ No newline at end of file diff --git a/app/app/components/section/papertrail/type-editor.js b/app/app/components/section/papertrail/type-editor.js index c3245eb7..127ced77 100644 --- a/app/app/components/section/papertrail/type-editor.js +++ b/app/app/components/section/papertrail/type-editor.js @@ -42,9 +42,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, this.set('config', config); - if (this.get('config.APIToken').length > 0) { - this.send('auth'); - } + this.send('auth'); }, willDestroyElement() { @@ -65,15 +63,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, }, auth() { - // missing data? - this.set('config.APIToken', this.get('config.APIToken').trim()); - - if (is.empty(this.get('config.APIToken'))) { - $("#papertrail-apitoken").addClass("error").focus(); - console.log("auth token empty"); - return; - } - let page = this.get('page'); let config = this.get('config'); let self = this; @@ -93,7 +82,12 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, self.set('waiting', false); let options = self.get('options'); - let group = _.findWhere(options.groups, { id: config.group.id }); + let group = {}; + if (is.not.null(config.group)) { + group = _.findWhere(options.groups, { id: config.group.id }); + } else { + group = options.groups[0]; + } if (is.not.undefined(group)) { Ember.set(config, 'group', group); } diff --git a/app/app/components/section/trello/type-editor.js b/app/app/components/section/trello/type-editor.js index e5aa6b7b..9392f020 100644 --- a/app/app/components/section/trello/type-editor.js +++ b/app/app/components/section/trello/type-editor.js @@ -16,50 +16,50 @@ import TooltipMixin from '../../../mixins/tooltip'; import SectionMixin from '../../../mixins/section'; export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, { - sectionService: Ember.inject.service('section'), - isDirty: false, - busy: false, - authenticated: false, - config: {}, - boards: null, - noBoards: false, + sectionService: Ember.inject.service('section'), + isDirty: false, + busy: false, + authenticated: false, + config: {}, + boards: null, + noBoards: false, appKey: "", - boardStyle: Ember.computed('config.board', function() { - let board = this.get('config.board'); + boardStyle: Ember.computed('config.board', function () { + let board = this.get('config.board'); - if (is.null(board) || is.undefined(board)) { - return "#4c4c4c"; - } + if (is.null(board) || is.undefined(board)) { + return "#4c4c4c"; + } - let color = board.prefs.backgroundColor; - return Ember.String.htmlSafe("background-color: " + color); - }), + let color = board.prefs.backgroundColor; + return Ember.String.htmlSafe("background-color: " + color); + }), - didReceiveAttrs() { - let page = this.get('page'); + didReceiveAttrs() { + let page = this.get('page'); let config = {}; let self = this; try { - config = JSON.parse(this.get('meta.config')); - } - catch (e) {} + config = JSON.parse(this.get('meta.config')); + } catch (e) {} - if (is.empty(config)) { - config = { - token: "", - user: null, - board: null, - lists: [] - }; - } + if (is.empty(config)) { + config = { + token: "", + user: null, + board: null, + lists: [] + }; + } - this.set('config', config); + this.set('config', config); this.get('sectionService').fetch(page, "config", {}) - .then(function(s) { + .then(function (s) { self.set('appKey', s.appKey); + self.set('config.token', s.token); // the user's own token has been stored in the DB // On auth callback capture user token let hashToken = window.location.hash; @@ -70,175 +70,173 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, } } - if (self.get('appKey') !== "" && self.get('config.token') !== "") { - self.send('auth'); - } - else { - Ember.$.getScript("https://api.trello.com/1/client.js?key=" + self.get('appKey'), function() { - Trello.deauthorize(); - }); - } - }, function(error) { //jshint ignore: line - console.log(error); - }); - }, + if (self.get('appKey') !== "" && self.get('config.token') !== "") { + self.send('auth'); + } else { + Ember.$.getScript("https://api.trello.com/1/client.js?key=" + self.get('appKey'), function () { + Trello.deauthorize(); + }); + } + }, function (error) { //jshint ignore: line + console.log(error); + }); + }, - willDestroyElement() { - this.destroyTooltips(); - }, + willDestroyElement() { + this.destroyTooltips(); + }, - getBoardLists() { - this.set('busy', true); + getBoardLists() { + this.set('busy', true); - let self = this; - let boards = this.get('boards'); - let board = this.get('config.board'); - let page = this.get('page'); + let self = this; + let boards = this.get('boards'); + let board = this.get('config.board'); + let page = this.get('page'); - if (is.null(boards) || is.undefined(boards) || boards.length === 0) { - this.set('noBoards', true); - return; - } + if (is.null(boards) || is.undefined(boards) || boards.length === 0) { + this.set('noBoards', true); + return; + } - this.set('noBoards', false); + this.set('noBoards', false); - if (is.null(board) || is.undefined(board)) { - if (boards.length) { - board = boards[0]; - this.set('config.board', board); - } - } - else { - this.set('config.board', boards.findBy('id', board.id)); - } + if (is.null(board) || is.undefined(board)) { + if (boards.length) { + board = boards[0]; + this.set('config.board', board); + } + } else { + this.set('config.board', boards.findBy('id', board.id)); + } - this.get('sectionService').fetch(page, "lists", self.get('config')) - .then(function(lists) { - let savedLists = self.get('config.lists'); - if (savedLists === null) { - savedLists = []; - } + this.get('sectionService').fetch(page, "lists", self.get('config')) + .then(function (lists) { + let savedLists = self.get('config.lists'); + if (savedLists === null) { + savedLists = []; + } - lists.forEach(function(list) { - let saved = savedLists.findBy("id", list.id); - let included = true; - if (is.not.undefined(saved)) { - included = saved.included; - } - list.included = included; - }); + lists.forEach(function (list) { + let saved = savedLists.findBy("id", list.id); + let included = true; + if (is.not.undefined(saved)) { + included = saved.included; + } + list.included = included; + }); - self.set('config.lists', lists); - self.set('busy', false); - }, function(error) { //jshint ignore: line - self.set('busy', false); - self.set('authenticated', false); - self.showNotification("Unable to fetch board lists"); - console.log(error); - }); - }, + self.set('config.lists', lists); + self.set('busy', false); + }, function (error) { //jshint ignore: line + self.set('busy', false); + self.set('authenticated', false); + self.showNotification("Unable to fetch board lists"); + console.log(error); + }); + }, - actions: { - isDirty() { - return this.get('isDirty'); - }, + actions: { + isDirty() { + return this.get('isDirty'); + }, - onListCheckbox(id) { - let lists = this.get('config.lists'); - let list = lists.findBy('id', id); + onListCheckbox(id) { + let lists = this.get('config.lists'); + let list = lists.findBy('id', id); - if (list !== null) { - Ember.set(list, 'included', !list.included); - } - }, + if (list !== null) { + Ember.set(list, 'included', !list.included); + } + }, - auth() { - if (this.get('appKey') === "") { - $("#trello-appkey").addClass('error').focus(); - this.set('authenticated', false); - return; - } + auth() { + if (this.get('appKey') === "") { + $("#trello-appkey").addClass('error').focus(); + this.set('authenticated', false); + return; + } - let self = this; - let page = this.get('page'); + let self = this; + let page = this.get('page'); - self.set('busy', true); + self.set('busy', true); - Ember.$.getScript("https://api.trello.com/1/client.js?key=" + this.get('appKey'), function() { - Trello.authorize({ - type: "redirect", - interactive: true, - name: "Documize", - scope: { - read: true, - write: false - }, - expiration: "never", - persist: true, - success: function() { - self.set('authenticated', true); - self.set('config.token', Trello.token()); - self.set('busy', true); + Ember.$.getScript("https://api.trello.com/1/client.js?key=" + this.get('appKey'), function () { + Trello.authorize({ + type: "redirect", + interactive: true, + name: "Documize", + scope: { + read: true, + write: false + }, + expiration: "never", + persist: true, + success: function () { + self.set('authenticated', true); + self.set('config.token', Trello.token()); + self.set('busy', true); - Trello.members.get("me", function(user) { - self.set('config.user', user); - }, function(error) { - console.log(error); - }); + Trello.members.get("me", function (user) { + self.set('config.user', user); + }, function (error) { + console.log(error); + }); - self.get('sectionService').fetch(page, "boards", self.get('config')) - .then(function(boards) { - self.set('busy', false); - self.set('boards', boards); - self.getBoardLists(); - }, function(error) { //jshint ignore: line - self.set('busy', false); - self.set('authenticated', false); - self.showNotification("Unable to fetch boards"); - console.log(error); - }); - }, - error: function(error) { - self.set('busy', false); - self.set('authenticated', false); - self.showNotification("Unable to authenticate"); - console.log(error); - } - }); - }); - }, + self.get('sectionService').fetch(page, "boards", self.get('config')) + .then(function (boards) { + self.set('busy', false); + self.set('boards', boards); + self.getBoardLists(); + }, function (error) { //jshint ignore: line + self.set('busy', false); + self.set('authenticated', false); + self.showNotification("Unable to fetch boards"); + console.log(error); + }); + }, + error: function (error) { + self.set('busy', false); + self.set('authenticated', false); + self.showNotification("Unable to authenticate"); + console.log(error); + } + }); + }); + }, - onBoardChange(board) { - this.set('isDirty', true); - this.set('config.board', board); - this.set('config.lists', []); - this.getBoardLists(); - }, + onBoardChange(board) { + this.set('isDirty', true); + this.set('config.board', board); + this.set('config.lists', []); + this.getBoardLists(); + }, - onCancel() { - this.attrs.onCancel(); - }, + onCancel() { + this.attrs.onCancel(); + }, - onAction(title) { - this.set('busy', true); + onAction(title) { + this.set('busy', true); - let self = this; - let page = this.get('page'); - let meta = this.get('meta'); - page.set('title', title); - meta.set('rawBody', ''); - meta.set('config', JSON.stringify(this.get('config'))); - meta.set('externalSource', true); + let self = this; + let page = this.get('page'); + let meta = this.get('meta'); + page.set('title', title); + meta.set('rawBody', ''); + meta.set('config', JSON.stringify(this.get('config'))); + meta.set('externalSource', true); - this.get('sectionService').fetch(page, "cards", this.get('config')) - .then(function(response) { - meta.set('rawBody', JSON.stringify(response)); - self.set('busy', false); - self.attrs.onAction(page, meta); - }, function(reason) { //jshint ignore: line - self.set('busy', false); - self.attrs.onAction(page, meta); - }); - } - } -}); + this.get('sectionService').fetch(page, "cards", this.get('config')) + .then(function (response) { + meta.set('rawBody', JSON.stringify(response)); + self.set('busy', false); + self.attrs.onAction(page, meta); + }, function (reason) { //jshint ignore: line + self.set('busy', false); + self.attrs.onAction(page, meta); + }); + } + } +}); \ No newline at end of file diff --git a/documize/section/gemini/gemini.go b/documize/section/gemini/gemini.go index 8dd2a64d..83afc45f 100644 --- a/documize/section/gemini/gemini.go +++ b/documize/section/gemini/gemini.go @@ -74,12 +74,14 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R } switch method { + case "secrets": + secs(ctx, w, r) case "auth": - auth(w, r) + auth(ctx, w, r) case "workspace": - workspace(w, r) + workspace(ctx, w, r) case "items": - items(w, r) + items(ctx, w, r) } } @@ -93,7 +95,7 @@ func (*Provider) Refresh(ctx *provider.Context, config, data string) (newData st return } - c.Clean() + c.Clean(ctx) if len(c.URL) == 0 { log.Info("Gemini.Refresh received empty URL") @@ -150,7 +152,7 @@ func (*Provider) Refresh(ctx *provider.Context, config, data string) (newData st return } -func auth(w http.ResponseWriter, r *http.Request) { +func auth(ctx *provider.Context, w http.ResponseWriter, r *http.Request) { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) @@ -167,7 +169,7 @@ func auth(w http.ResponseWriter, r *http.Request) { return } - config.Clean() + config.Clean(nil) // don't look at the database for the parameters if len(config.URL) == 0 { provider.WriteMessage(w, "gemini", "Missing URL value") @@ -203,6 +205,8 @@ func auth(w http.ResponseWriter, r *http.Request) { return } + config.SaveSecrets(ctx) + defer res.Body.Close() var g = geminiUser{} @@ -218,7 +222,7 @@ func auth(w http.ResponseWriter, r *http.Request) { provider.WriteJSON(w, g) } -func workspace(w http.ResponseWriter, r *http.Request) { +func workspace(ctx *provider.Context, w http.ResponseWriter, r *http.Request) { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) @@ -235,7 +239,7 @@ func workspace(w http.ResponseWriter, r *http.Request) { return } - config.Clean() + config.Clean(ctx) if len(config.URL) == 0 { provider.WriteMessage(w, "gemini", "Missing URL value") @@ -291,7 +295,7 @@ func workspace(w http.ResponseWriter, r *http.Request) { provider.WriteJSON(w, workspace) } -func items(w http.ResponseWriter, r *http.Request) { +func items(ctx *provider.Context, w http.ResponseWriter, r *http.Request) { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) @@ -308,7 +312,7 @@ func items(w http.ResponseWriter, r *http.Request) { return } - config.Clean() + config.Clean(ctx) if len(config.URL) == 0 { provider.WriteMessage(w, "gemini", "Missing URL value") @@ -367,3 +371,9 @@ func items(w http.ResponseWriter, r *http.Request) { provider.WriteJSON(w, items) } + +func secs(ctx *provider.Context, w http.ResponseWriter, r *http.Request) { + sec, err := getSecrets(ctx) + log.IfErr(err) + provider.WriteJSON(w, sec) +} diff --git a/documize/section/gemini/model.go b/documize/section/gemini/model.go index edf68383..84dfc1c1 100644 --- a/documize/section/gemini/model.go +++ b/documize/section/gemini/model.go @@ -11,7 +11,12 @@ package gemini -import "strings" +import ( + "strings" + + "github.com/documize/community/documize/section/provider" + "github.com/documize/community/wordsmith/log" +) // the HTML that is rendered by this section. const renderTemplate = ` @@ -82,8 +87,37 @@ type geminiConfig struct { Filter map[string]interface{} `json:"filter"` } -func (c *geminiConfig) Clean() { +func (c *geminiConfig) Clean(ctx *provider.Context) { + if ctx != nil { + sec, err := getSecrets(ctx) + if err == nil { + if len(sec.APIKey) > 0 && len(sec.Username) > 0 && len(sec.URL) > 0 { + c.APIKey = strings.TrimSpace(sec.APIKey) + c.Username = strings.TrimSpace(sec.Username) + c.URL = strings.TrimSpace(sec.URL) + } + } + } c.APIKey = strings.TrimSpace(c.APIKey) c.Username = strings.TrimSpace(c.Username) c.URL = strings.TrimSpace(c.URL) } + +func (c *geminiConfig) SaveSecrets(ctx *provider.Context) { + var sec secrets + sec.APIKey = strings.TrimSpace(c.APIKey) + sec.Username = strings.TrimSpace(c.Username) + sec.URL = strings.TrimSpace(c.URL) + log.IfErr(ctx.MarshalSecrets(sec)) +} + +type secrets struct { + URL string `json:"url"` + Username string `json:"username"` + APIKey string `json:"apikey"` +} + +func getSecrets(ctx *provider.Context) (sec secrets, err error) { + err = ctx.UnmarshalSecrets(&sec) + return +} diff --git a/documize/section/papertrail/papertrail.go b/documize/section/papertrail/papertrail.go index 28e9ab80..a76a3195 100644 --- a/documize/section/papertrail/papertrail.go +++ b/documize/section/papertrail/papertrail.go @@ -104,7 +104,7 @@ func (p *Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http config.Clean() - if config.APIToken == provider.SecretReplacement { + if config.APIToken == provider.SecretReplacement || config.APIToken == "" { config.APIToken = ctx.GetSecrets("APIToken") } diff --git a/documize/section/provider/provider.go b/documize/section/provider/provider.go index 92e40c72..7964f856 100644 --- a/documize/section/provider/provider.go +++ b/documize/section/provider/provider.go @@ -209,7 +209,21 @@ 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) + m := c.prov.Meta() + return request.UserConfigSetJSON(c.OrgID, c.UserID, m.ContentType, JSONobj) +} + +// MarshalSecrets to the database. +// Parameter the same as for json.Marshal(). +func (c *Context) MarshalSecrets(sec interface{}) error { + if !c.inCommand { + return errors.New("MarshalSecrets() may only be called from within Command()") + } + byts, err := json.Marshal(sec) + if err != nil { + return err + } + return c.SaveSecrets(string(byts)) } // GetSecrets for the current context user/org. @@ -218,7 +232,21 @@ func (c *Context) SaveSecrets(JSONobj string) error { // 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) + m := c.prov.Meta() + return request.UserConfigGetJSON(c.OrgID, c.UserID, m.ContentType, JSONpath) +} + +// ErrNoSecrets is returned if no secret is found in the database. +var ErrNoSecrets = errors.New("no secrets in database") + +// UnmarshalSecrets from the database. +// Parameter the same as for "v" in json.Unmarshal(). +func (c *Context) UnmarshalSecrets(v interface{}) error { + secTxt := c.GetSecrets("") // get all the json of the secrets + if len(secTxt) > 0 { + return json.Unmarshal([]byte(secTxt), v) + } + return ErrNoSecrets } // sort sections in order that that should be presented. diff --git a/documize/section/trello/model.go b/documize/section/trello/model.go index d5f58b23..34f70236 100644 --- a/documize/section/trello/model.go +++ b/documize/section/trello/model.go @@ -35,6 +35,10 @@ const renderTemplate = ` ` +type secrets struct { + Token string `json:"token"` +} + type trelloConfig struct { AppKey string `json:"appKey"` Token string `json:"token"` diff --git a/documize/section/trello/trello.go b/documize/section/trello/trello.go index 32fcb6ad..a28d5756 100644 --- a/documize/section/trello/trello.go +++ b/documize/section/trello/trello.go @@ -25,7 +25,6 @@ import ( ) var meta provider.TypeMeta -var appKey string func init() { meta = provider.TypeMeta{} @@ -49,11 +48,6 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R query := r.URL.Query() method := query.Get("method") - if len(method) == 0 { - provider.WriteMessage(w, "trello", "missing method name") - return - } - defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) @@ -70,19 +64,20 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R return } - if appKey == "" { - appKey = request.ConfigString(meta.ConfigHandle(), "appKey") + config.Clean() + config.AppKey = request.ConfigString(meta.ConfigHandle(), "appKey") + + if len(config.AppKey) == 0 { + log.ErrorString("missing trello App Key") + provider.WriteMessage(w, "trello", "Missing appKey") + return } - config.Clean() - config.AppKey = appKey + if len(config.Token) == 0 { + config.Token = ctx.GetSecrets("token") // get a token, if we have one + } if method != "config" { - if len(config.AppKey) == 0 { - provider.WriteMessage(w, "trello", "Missing appKey") - return - } - if len(config.Token) == 0 { provider.WriteMessage(w, "trello", "Missing token") return @@ -94,8 +89,9 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R render, err := getCards(config) if err != nil { - fmt.Println(err) + log.IfErr(err) provider.WriteError(w, "trello", err) + log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid return } @@ -105,8 +101,9 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R render, err := getBoards(config) if err != nil { - fmt.Println(err) + log.IfErr(err) provider.WriteError(w, "trello", err) + log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid return } @@ -116,24 +113,38 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R render, err := getLists(config) if err != nil { - fmt.Println(err) + log.IfErr(err) provider.WriteError(w, "trello", err) + log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid return } provider.WriteJSON(w, render) case "config": - if method == "config" { - var config struct { - AppKey string `json:"appKey"` - } - - config.AppKey = appKey - provider.WriteJSON(w, config) - return + var ret struct { + AppKey string `json:"appKey"` + Token string `json:"token"` } + ret.AppKey = config.AppKey + if config.Token != "" { + ret.Token = provider.SecretReplacement + } + provider.WriteJSON(w, ret) + return + + default: + log.ErrorString("trello unknown method name: " + method) + provider.WriteMessage(w, "trello", "missing method name") + return } + + // the token has just worked, so save it as our secret + var s secrets + s.Token = config.Token + b, e := json.Marshal(s) + log.IfErr(e) + log.IfErr(ctx.SaveSecrets(string(b))) } // Render just sends back HMTL as-is.