diff --git a/app/app/components/section/papertrail/type-editor.js b/app/app/components/section/papertrail/type-editor.js index 622f333b..f46452b8 100644 --- a/app/app/components/section/papertrail/type-editor.js +++ b/app/app/components/section/papertrail/type-editor.js @@ -13,6 +13,7 @@ import Ember from 'ember'; import NotifierMixin from '../../../mixins/notifier'; import TooltipMixin from '../../../mixins/tooltip'; import SectionMixin from '../../../mixins/section'; +import netUtil from '../../../utils/net'; export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, { sectionService: Ember.inject.service('section'), @@ -34,6 +35,8 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, APIToken: "", query: "", max: 10, + group: null, + system: null }; } @@ -48,6 +51,14 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, this.destroyTooltips(); }, + displayError(reason) { + if (netUtil.isAjaxAccessError(reason)) { + this.showNotification(`Unable to authenticate`); + } else { + this.showNotification(`Something went wrong, try again!`); + } + }, + actions: { isDirty() { return this.get('isDirty'); @@ -63,32 +74,73 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, } let page = this.get('page'); + let config = this.get('config'); let self = this; this.set('waiting', true); - this.get('sectionService').fetch(page, "auth", this.get('config')) + this.get('sectionService').fetch(page, "auth", config) .then(function(response) { self.set('authenticated', true); self.set('items', response); - self.set('waiting', false); - }, function(reason) { //jshint ignore: line + + 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); + self.displayError(reason); + }); + }, 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!`); - } + self.displayError(reason); }); }, + 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.get('sectionService').fetch(page, "auth", config) + .then(function(response) { + 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('config.system', system); + this.set('waiting', true); + + this.get('sectionService').fetch(page, "auth", config) + .then(function(response) { + self.set('waiting', false); + self.set('items', response); + }, function(reason) { //jshint ignore: line + self.set('waiting', false); + self.displayError(reason); + }); + }, + onCancel() { this.attrs.onCancel(); }, @@ -126,7 +178,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, }, 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/templates/components/section/papertrail/type-editor.hbs b/app/app/templates/components/section/papertrail/type-editor.hbs index 70e8656c..2d50af1d 100644 --- a/app/app/templates/components/section/papertrail/type-editor.hbs +++ b/app/app/templates/components/section/papertrail/type-editor.hbs @@ -36,6 +36,11 @@
How many log entries do you want?
{{input id="papertrail-max" type="number" class="mousetrap" value=config.max}} +
+ +
Optional Papertrail group
+ {{ui-select id="group-dropdown" prompt="" content=options.groups action=(action 'onGroupsChange') optionValuePath="id" optionLabelPath="name" selection=config.group}} +
diff --git a/documize/section/papertrail/model.go b/documize/section/papertrail/model.go index 1311a255..01dede45 100644 --- a/documize/section/papertrail/model.go +++ b/documize/section/papertrail/model.go @@ -61,12 +61,24 @@ type papertrailEvent struct { } type papertrailConfig struct { - APIToken string `json:"APIToken"` - Query string `json:"query"` - Max int `json:"max"` + APIToken string `json:"APIToken"` + Query string `json:"query"` + Max int `json:"max"` + Group papertrailOption `json:"group"` + System papertrailOption `json:"system"` } func (c *papertrailConfig) Clean() { c.APIToken = strings.TrimSpace(c.APIToken) c.Query = strings.TrimSpace(c.Query) } + +type papertrailOption struct { + ID int `json:"id"` + Name string `json:"name"` +} + +type papertrailOptions struct { + Groups []papertrailOption `json:"groups"` + Systems []papertrailOption `json:"systems"` +} diff --git a/documize/section/papertrail/papertrail.go b/documize/section/papertrail/papertrail.go index 852aed22..98339bd2 100644 --- a/documize/section/papertrail/papertrail.go +++ b/documize/section/papertrail/papertrail.go @@ -21,6 +21,7 @@ import ( "net/url" "github.com/documize/community/documize/section/provider" + "github.com/documize/community/wordsmith/log" ) const me = "papertrail" @@ -42,7 +43,6 @@ func (*Provider) Meta() provider.TypeMeta { // 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{} @@ -83,84 +83,6 @@ func (p *Provider) Command(w http.ResponseWriter, r *http.Request) { 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) @@ -184,11 +106,68 @@ func auth(w http.ResponseWriter, r *http.Request) { return } - var search string - if len(config.Query) > 0 { - search = "q=" + url.QueryEscape(config.Query) + switch method { + case "auth": + auth(config, w, r) + case "options": + options(config, w, r) } - req, err := http.NewRequest("GET", "https://papertrailapp.com/api/v1/events/search.json?"+search, nil) +} + +// Refresh just sends back data as-is. +func (*Provider) Refresh(config, data string) (newData string) { + var c = papertrailConfig{} + err := json.Unmarshal([]byte(config), &c) + + if err != nil { + log.Error("unable to read Papertrail config", err) + return + } + + c.Clean() + + if len(c.APIToken) == 0 { + log.Error("missing API token", err) + return + } + + result, err := fetchEvents(c) + + if err != nil { + log.Error("Papertrail fetchEvents failed", err) + return + } + + j, err := json.Marshal(result) + + if err != nil { + log.Error("unable to marshal Papaertrail events", err) + return + } + + newData = string(j) + return +} + +func auth(config papertrailConfig, w http.ResponseWriter, r *http.Request) { + result, err := fetchEvents(config) + + if err != nil { + if err.Error() == "forbidden" { + provider.WriteForbidden(w) + } else { + provider.WriteError(w, me, err) + } + + return + } + + provider.WriteJSON(w, result) +} + +func options(config papertrailConfig, w http.ResponseWriter, r *http.Request) { + // get systems + req, err := http.NewRequest("GET", "https://papertrailapp.com/api/v1/systems.json", nil) req.Header.Set("X-Papertrail-Token", config.APIToken) client := &http.Client{} @@ -206,10 +185,10 @@ func auth(w http.ResponseWriter, r *http.Request) { } defer res.Body.Close() - var result interface{} + var systems []papertrailOption dec := json.NewDecoder(res.Body) - err = dec.Decode(&result) + err = dec.Decode(&systems) if err != nil { fmt.Println(err) @@ -217,156 +196,80 @@ func auth(w http.ResponseWriter, r *http.Request) { return } - provider.WriteJSON(w, result) + // get groups + req, err = http.NewRequest("GET", "https://papertrailapp.com/api/v1/groups.json", 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 groups []papertrailOption + + dec = json.NewDecoder(res.Body) + err = dec.Decode(&groups) + + if err != nil { + fmt.Println(err) + provider.WriteError(w, me, err) + return + } + + var options = papertrailOptions{} + options.Groups = groups + options.Systems = systems + + provider.WriteJSON(w, options) } -// -// 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) -// } +func fetchEvents(config papertrailConfig) (result interface{}, err error) { + var filter string + if len(config.Query) > 0 { + filter = fmt.Sprintf("q=%s", url.QueryEscape(config.Query)) + } + if config.Group.ID > 0 { + prefix := "" + if len(filter) > 0 { + prefix = "&" + } + filter = fmt.Sprintf("%s%sgroup_id=%d", filter, prefix, config.Group.ID) + } + + req, err := http.NewRequest("GET", "https://papertrailapp.com/api/v1/events/search.json?"+filter, nil) + req.Header.Set("X-Papertrail-Token", config.APIToken) + + client := &http.Client{} + res, err := client.Do(req) + + if err != nil { + log.Error("message", err) + return + } + + if res.StatusCode != http.StatusOK { + log.Error("forbidden", err) + return + } + + defer res.Body.Close() + + dec := json.NewDecoder(res.Body) + err = dec.Decode(&result) + + if err != nil { + log.Error("unable to read result", err) + } + + return +}