From a297688aa28bed9b8deeccc6f9557ef627347663 Mon Sep 17 00:00:00 2001 From: Harvey Kandola Date: Tue, 28 Jun 2016 17:32:35 -0700 Subject: [PATCH] Papertrail smart section --- .../section/papertrail/type-editor.js | 134 +++++++ .../section/papertrail/type-renderer.js | 14 + app/app/styles/app.scss | 1 + app/app/styles/section/papertrail.scss | 16 + .../components/section/gemini/type-editor.hbs | 6 +- .../section/papertrail/type-editor.hbs | 46 +++ .../section/papertrail/type-renderer.hbs | 1 + app/public/sections/papertrail.png | Bin 0 -> 8119 bytes app/public/sections/papertrail@2x.png | Bin 0 -> 4048 bytes documize/api/endpoint/router.go | 2 +- documize/section/papertrail/model.go | 72 ++++ documize/section/papertrail/papertrail.go | 372 ++++++++++++++++++ documize/section/register.go | 2 + 13 files changed, 662 insertions(+), 4 deletions(-) create mode 100644 app/app/components/section/papertrail/type-editor.js create mode 100644 app/app/components/section/papertrail/type-renderer.js create mode 100644 app/app/styles/section/papertrail.scss create mode 100644 app/app/templates/components/section/papertrail/type-editor.hbs create mode 100644 app/app/templates/components/section/papertrail/type-renderer.hbs create mode 100644 app/public/sections/papertrail.png create mode 100644 app/public/sections/papertrail@2x.png create mode 100644 documize/section/papertrail/model.go create mode 100644 documize/section/papertrail/papertrail.go diff --git a/app/app/components/section/papertrail/type-editor.js b/app/app/components/section/papertrail/type-editor.js new file mode 100644 index 00000000..622f333b --- /dev/null +++ b/app/app/components/section/papertrail/type-editor.js @@ -0,0 +1,134 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +import Ember from 'ember'; +import NotifierMixin from '../../../mixins/notifier'; +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, + config: {}, + items: {}, + + didReceiveAttrs() { + let config = {}; + + try { + config = JSON.parse(this.get('meta.config')); + } catch (e) {} + + if (is.empty(config)) { + config = { + APIToken: "", + query: "", + max: 10, + }; + } + + this.set('config', config); + + if (this.get('config.APIToken').length > 0) { + this.send('auth'); + } + }, + + willDestroyElement() { + this.destroyTooltips(); + }, + + actions: { + isDirty() { + return this.get('isDirty'); + }, + + auth() { + // missing data? + this.set('config.APIToken', this.get('config.APIToken').trim()); + + if (is.empty(this.get('config.APIToken'))) { + $("#papertrail-apitoken").addClass("error").focus(); + return; + } + + let page = this.get('page'); + let self = this; + + this.set('waiting', true); + + this.get('sectionService').fetch(page, "auth", this.get('config')) + .then(function(response) { + self.set('authenticated', true); + self.set('items', response); + self.set('waiting', false); + }, function(reason) { //jshint ignore: line + self.set('authenticated', false); + self.set('waiting', false); + + switch (reason.status) { + case 400: + self.showNotification(`Unable to connect to Papertrail`); + break; + case 403: + self.showNotification(`Unable to authenticate`); + break; + default: + self.showNotification(`Something went wrong, try again!`); + } + }); + }, + + onCancel() { + this.attrs.onCancel(); + }, + + onAction(title) { + let self = this; + 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; + if (is.number(parseInt(config.max))) { + max = parseInt(config.max); + } + + 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'); + + if (items.events.length > max) { + items.events = items.events.slice(0, max); + } + + 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); + console.log(reason); + self.showNotification(`Something went wrong, try again!`); + }); + } + } +}); diff --git a/app/app/components/section/papertrail/type-renderer.js b/app/app/components/section/papertrail/type-renderer.js new file mode 100644 index 00000000..a5417462 --- /dev/null +++ b/app/app/components/section/papertrail/type-renderer.js @@ -0,0 +1,14 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +import Ember from 'ember'; + +export default Ember.Component.extend({}); \ No newline at end of file diff --git a/app/app/styles/app.scss b/app/app/styles/app.scss index 237930c0..b66df98b 100644 --- a/app/app/styles/app.scss +++ b/app/app/styles/app.scss @@ -37,3 +37,4 @@ @import "section/markdown.scss"; @import "section/table.scss"; @import "section/code.scss"; +@import "section/papertrail.scss"; diff --git a/app/app/styles/section/papertrail.scss b/app/app/styles/section/papertrail.scss new file mode 100644 index 00000000..00dd2f68 --- /dev/null +++ b/app/app/styles/section/papertrail.scss @@ -0,0 +1,16 @@ +.section-papertrail-table { + font-size: 12px; + width: 90% important; + + th { + font-size: 1rem; + } + + td:nth-child(2) { + font-variant: small-caps; + } + + a:hover { + text-decoration: underline; + } +} diff --git a/app/app/templates/components/section/gemini/type-editor.hbs b/app/app/templates/components/section/gemini/type-editor.hbs index f7ee622f..3cfb085d 100644 --- a/app/app/templates/components/section/gemini/type-editor.hbs +++ b/app/app/templates/components/section/gemini/type-editor.hbs @@ -1,5 +1,5 @@ {{#section/base-editor document=document folder=folder page=page busy=waiting tip="Gemini enterprise issue and ticketing software (https://www.countersoft.com)" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}} - +
@@ -50,5 +50,5 @@
{{/if}}
- -{{/section/base-editor}} \ No newline at end of file + +{{/section/base-editor}} diff --git a/app/app/templates/components/section/papertrail/type-editor.hbs b/app/app/templates/components/section/papertrail/type-editor.hbs new file mode 100644 index 00000000..70e8656c --- /dev/null +++ b/app/app/templates/components/section/papertrail/type-editor.hbs @@ -0,0 +1,46 @@ +{{#section/base-editor document=document folder=folder page=page busy=waiting tip="Papertrail cloud logging service (https://papertrailapp.com)" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}} + +
+
+ +
+
Papertrail Authentication
+
Provide your Papertrail API token
+
+
+ +
API Token (from your profile)
+ {{focus-input id="papertrail-apitoken" type="password" value=config.APIToken readonly=isReadonly}} +
+
Authenticate
+ +
+
+ + {{#if authenticated}} +
 
+
+
+
+
+
Log Filter
+
Determine which log entries you want to display
+
+
+ +
e.g. bob OR ("some phrase" AND sally)
+ {{input id="papertrail-query" type="text" class="mousetrap" value=config.query}} +
+
+ +
How many log entries do you want?
+ {{input id="papertrail-max" type="number" class="mousetrap" value=config.max}} +
+
+
+
+ {{/if}} + +
+ +{{/section/base-editor}} diff --git a/app/app/templates/components/section/papertrail/type-renderer.hbs b/app/app/templates/components/section/papertrail/type-renderer.hbs new file mode 100644 index 00000000..f2eac9e5 --- /dev/null +++ b/app/app/templates/components/section/papertrail/type-renderer.hbs @@ -0,0 +1 @@ +{{{page.body}}} \ No newline at end of file diff --git a/app/public/sections/papertrail.png b/app/public/sections/papertrail.png new file mode 100644 index 0000000000000000000000000000000000000000..d383ae121e2e9e6e4c184eee93492f481c6a717e GIT binary patch literal 8119 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 DzZN6f literal 0 HcmV?d00001 diff --git a/documize/api/endpoint/router.go b/documize/api/endpoint/router.go index 493979ee..eeff52fb 100644 --- a/documize/api/endpoint/router.go +++ b/documize/api/endpoint/router.go @@ -30,7 +30,7 @@ const ( // AppVersion does what it says // Versioning scheme major.minor where "minor" is optional // e.g. 1, 2, 3, 4.1, 4.2, 5, 6, 7, 7.1, 8, 9, 10, ..... 127, 127.1, 128 - AppVersion = "12.8" + AppVersion = "12.9" ) var port, certFile, keyFile, forcePort2SSL string diff --git a/documize/section/papertrail/model.go b/documize/section/papertrail/model.go new file mode 100644 index 00000000..1311a255 --- /dev/null +++ b/documize/section/papertrail/model.go @@ -0,0 +1,72 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +package papertrail + +import "strings" + +// the HTML that is rendered by this section. +const renderTemplate = ` +{{if .HasData}} +

The Papertrail log for query {{.Config.Query}} contains {{.Count}} entries.

+ + + + + + + + + + {{range $item := .Events}} + + + + + + {{end}} + +
DateSeverityMessage
{{ $item.Dated }}{{ $item.Severity }}{{ $item.Message }}
+{{else}} +

There are no Papertrail log entries to see.

+{{end}} +` + +// Papertrail helpers +type papertrailRender struct { + Config papertrailConfig + Events []papertrailEvent + Count int + Authenticated bool + HasData bool +} + +type papertrailSearch struct { + Events []papertrailEvent `json:"events"` +} + +type papertrailEvent struct { + ID string `json:"id"` + Dated string `json:"display_received_at"` + Message string `json:"message"` + Severity string `json:"severity"` +} + +type papertrailConfig struct { + APIToken string `json:"APIToken"` + Query string `json:"query"` + Max int `json:"max"` +} + +func (c *papertrailConfig) Clean() { + c.APIToken = strings.TrimSpace(c.APIToken) + c.Query = strings.TrimSpace(c.Query) +} diff --git a/documize/section/papertrail/papertrail.go b/documize/section/papertrail/papertrail.go new file mode 100644 index 00000000..852aed22 --- /dev/null +++ b/documize/section/papertrail/papertrail.go @@ -0,0 +1,372 @@ +// Copyright 2016 Documize Inc. . All rights reserved. +// +// This software (Documize Community Edition) is licensed under +// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html +// +// You can operate outside the AGPL restrictions by purchasing +// Documize Enterprise Edition and obtaining a commercial license +// by contacting . +// +// https://documize.com + +package papertrail + +import ( + "bytes" + "encoding/json" + "fmt" + "html/template" + "io/ioutil" + "net/http" + "net/url" + + "github.com/documize/community/documize/section/provider" +) + +const me = "papertrail" + +// Provider represents Gemini +type Provider struct { +} + +// Meta describes us. +func (*Provider) Meta() provider.TypeMeta { + section := provider.TypeMeta{} + section.ID = "db0a3a0a-b5d4-4d00-bfac-ee28abba451d" + section.Title = "Papertrail" + section.Description = "Display log entries" + section.ContentType = "papertrail" + + return section +} + +// Render converts Papertrail data into HTML suitable for browser rendering. +func (*Provider) Render(config, data string) string { + + var search papertrailSearch + var events []papertrailEvent + var payload = papertrailRender{} + var c = papertrailConfig{} + + json.Unmarshal([]byte(data), &search) + json.Unmarshal([]byte(config), &c) + + max := len(search.Events) + if c.Max < max { + max = c.Max + } + + events = search.Events[:max] + payload.Count = len(events) + payload.HasData = payload.Count > 0 + + payload.Events = events + payload.Config = c + payload.Authenticated = c.APIToken != "" + + t := template.New("items") + t, _ = t.Parse(renderTemplate) + + buffer := new(bytes.Buffer) + t.Execute(buffer, payload) + + return buffer.String() +} + +// Command handles authentication, workspace listing and items retrieval. +func (p *Provider) Command(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + method := query.Get("method") + + if len(method) == 0 { + provider.WriteMessage(w, me, "missing method name") + return + } + + switch method { + case "auth": + auth(w, r) + // case "items": + // items(w, r) + } +} + +// Refresh just sends back data as-is. +func (*Provider) Refresh(config, data string) (newData string) { + + return data + // var c = geminiConfig{} + // err := json.Unmarshal([]byte(config), &c) + // + // if err != nil { + // log.Error("Unable to read Gemini config", err) + // return + // } + // + // c.Clean() + // + // if len(c.URL) == 0 { + // log.Info("Gemini.Refresh received empty URL") + // return + // } + // + // if len(c.Username) == 0 { + // log.Info("Gemini.Refresh received empty username") + // return + // } + // + // if len(c.APIKey) == 0 { + // log.Info("Gemini.Refresh received empty API key") + // return + // } + // + // req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/items/card/%d", c.URL, c.WorkspaceID), nil) + // // req.Header.Set("Content-Type", "application/json") + // + // creds := []byte(fmt.Sprintf("%s:%s", c.Username, c.APIKey)) + // req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString(creds)) + // + // client := &http.Client{} + // res, err := client.Do(req) + // + // if err != nil { + // fmt.Println(err) + // return + // } + // + // if res.StatusCode != http.StatusOK { + // return + // } + // + // defer res.Body.Close() + // var items []geminiItem + // + // dec := json.NewDecoder(res.Body) + // err = dec.Decode(&items) + // + // if err != nil { + // fmt.Println(err) + // return + // } + // + // j, err := json.Marshal(items) + // + // if err != nil { + // log.Error("unable to marshall gemini items", err) + // return + // } + // + // newData = string(j) + // return +} + +func auth(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + body, err := ioutil.ReadAll(r.Body) + + if err != nil { + provider.WriteMessage(w, me, "Bad payload") + return + } + + var config = papertrailConfig{} + err = json.Unmarshal(body, &config) + + if err != nil { + provider.WriteMessage(w, me, "Bad config") + return + } + + config.Clean() + + if len(config.APIToken) == 0 { + provider.WriteMessage(w, me, "Missing API token") + return + } + + var search string + if len(config.Query) > 0 { + search = "q=" + url.QueryEscape(config.Query) + } + req, err := http.NewRequest("GET", "https://papertrailapp.com/api/v1/events/search.json?"+search, nil) + req.Header.Set("X-Papertrail-Token", config.APIToken) + + client := &http.Client{} + res, err := client.Do(req) + + if err != nil { + fmt.Println(err) + provider.WriteError(w, me, err) + return + } + + if res.StatusCode != http.StatusOK { + provider.WriteForbidden(w) + return + } + + defer res.Body.Close() + var result interface{} + + dec := json.NewDecoder(res.Body) + err = dec.Decode(&result) + + if err != nil { + fmt.Println(err) + provider.WriteError(w, me, err) + return + } + + provider.WriteJSON(w, result) +} + +// +// func workspace(w http.ResponseWriter, r *http.Request) { +// defer r.Body.Close() +// body, err := ioutil.ReadAll(r.Body) +// +// if err != nil { +// provider.WriteMessage(w, "gemini", "Bad payload") +// return +// } +// +// var config = geminiConfig{} +// err = json.Unmarshal(body, &config) +// +// if err != nil { +// provider.WriteMessage(w, "gemini", "Bad payload") +// return +// } +// +// config.Clean() +// +// if len(config.URL) == 0 { +// provider.WriteMessage(w, "gemini", "Missing URL value") +// return +// } +// +// if len(config.Username) == 0 { +// provider.WriteMessage(w, "gemini", "Missing Username value") +// return +// } +// +// if len(config.APIKey) == 0 { +// provider.WriteMessage(w, "gemini", "Missing APIKey value") +// return +// } +// +// if config.UserID == 0 { +// provider.WriteMessage(w, "gemini", "Missing UserId value") +// return +// } +// +// req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/navigationcards/users/%d", config.URL, config.UserID), nil) +// +// creds := []byte(fmt.Sprintf("%s:%s", config.Username, config.APIKey)) +// req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString(creds)) +// +// client := &http.Client{} +// res, err := client.Do(req) +// +// if err != nil { +// fmt.Println(err) +// provider.WriteError(w, "gemini", err) +// return +// } +// +// if res.StatusCode != http.StatusOK { +// provider.WriteForbidden(w) +// return +// } +// +// defer res.Body.Close() +// var workspace interface{} +// +// dec := json.NewDecoder(res.Body) +// err = dec.Decode(&workspace) +// +// if err != nil { +// fmt.Println(err) +// provider.WriteError(w, "gemini", err) +// return +// } +// +// provider.WriteJSON(w, workspace) +// } +// +// func items(w http.ResponseWriter, r *http.Request) { +// defer r.Body.Close() +// body, err := ioutil.ReadAll(r.Body) +// +// if err != nil { +// provider.WriteMessage(w, "gemini", "Bad payload") +// return +// } +// +// var config = geminiConfig{} +// err = json.Unmarshal(body, &config) +// +// if err != nil { +// provider.WriteMessage(w, "gemini", "Bad payload") +// return +// } +// +// config.Clean() +// +// if len(config.URL) == 0 { +// provider.WriteMessage(w, "gemini", "Missing URL value") +// return +// } +// +// if len(config.Username) == 0 { +// provider.WriteMessage(w, "gemini", "Missing Username value") +// return +// } +// +// if len(config.APIKey) == 0 { +// provider.WriteMessage(w, "gemini", "Missing APIKey value") +// return +// } +// +// creds := []byte(fmt.Sprintf("%s:%s", config.Username, config.APIKey)) +// +// filter, err := json.Marshal(config.Filter) +// if err != nil { +// fmt.Println(err) +// provider.WriteError(w, "gemini", err) +// return +// } +// +// var jsonFilter = []byte(string(filter)) +// req, err := http.NewRequest("POST", fmt.Sprintf("%s/api/items/filtered", config.URL), bytes.NewBuffer(jsonFilter)) +// req.Header.Set("Content-Type", "application/json") +// req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString(creds)) +// +// client := &http.Client{} +// res, err := client.Do(req) +// +// if err != nil { +// fmt.Println(err) +// provider.WriteError(w, "gemini", err) +// return +// } +// +// if res.StatusCode != http.StatusOK { +// provider.WriteForbidden(w) +// return +// } +// +// defer res.Body.Close() +// var items interface{} +// +// dec := json.NewDecoder(res.Body) +// err = dec.Decode(&items) +// +// if err != nil { +// fmt.Println(err) +// provider.WriteError(w, "gemini", err) +// return +// } +// +// provider.WriteJSON(w, items) +// } diff --git a/documize/section/register.go b/documize/section/register.go index 23fc99f7..057e937a 100644 --- a/documize/section/register.go +++ b/documize/section/register.go @@ -22,6 +22,7 @@ import ( "github.com/documize/community/documize/section/intercom" "github.com/documize/community/documize/section/mailchimp" "github.com/documize/community/documize/section/markdown" + "github.com/documize/community/documize/section/papertrail" "github.com/documize/community/documize/section/provider" "github.com/documize/community/documize/section/salesforce" "github.com/documize/community/documize/section/stripe" @@ -43,6 +44,7 @@ func Register() { provider.Register("mailchimp", &mailchimp.Provider{}) provider.Register("markdown", &markdown.Provider{}) provider.Register("salesforce", &salesforce.Provider{}) + provider.Register("papertrail", &papertrail.Provider{}) provider.Register("stripe", &stripe.Provider{}) provider.Register("table", &table.Provider{}) provider.Register("trello", &trello.Provider{})