github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/section/papertrail/papertrail.go (about)

     1  // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
     2  //
     3  // This software (Documize Community Edition) is licensed under
     4  // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
     5  //
     6  // You can operate outside the AGPL restrictions by purchasing
     7  // Documize Enterprise Edition and obtaining a commercial license
     8  // by contacting <sales@documize.com>.
     9  //
    10  // https://documize.com
    11  
    12  package papertrail
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/json"
    17  	"errors"
    18  	"fmt"
    19  	"html/template"
    20  	"io/ioutil"
    21  	"net/http"
    22  	"net/url"
    23  
    24  	"github.com/documize/community/documize/section/provider"
    25  	"github.com/documize/community/wordsmith/log"
    26  )
    27  
    28  const me = "papertrail"
    29  
    30  // Provider represents Gemini
    31  type Provider struct {
    32  }
    33  
    34  // Meta describes us.
    35  func (*Provider) Meta() provider.TypeMeta {
    36  	section := provider.TypeMeta{}
    37  	section.ID = "db0a3a0a-b5d4-4d00-bfac-ee28abba451d"
    38  	section.Title = "Papertrail"
    39  	section.Description = "Display log entries"
    40  	section.ContentType = "papertrail"
    41  
    42  	return section
    43  }
    44  
    45  // Render converts Papertrail data into HTML suitable for browser rendering.
    46  func (*Provider) Render(ctx *provider.Context, config, data string) string {
    47  	var search papertrailSearch
    48  	var events []papertrailEvent
    49  	var payload = papertrailRender{}
    50  	var c = papertrailConfig{}
    51  
    52  	json.Unmarshal([]byte(data), &search)
    53  	json.Unmarshal([]byte(config), &c)
    54  
    55  	c.APIToken = ctx.GetSecrets("APIToken")
    56  
    57  	max := len(search.Events)
    58  	if c.Max < max {
    59  		max = c.Max
    60  	}
    61  
    62  	events = search.Events[:max]
    63  	payload.Count = len(events)
    64  	payload.HasData = payload.Count > 0
    65  
    66  	payload.Events = events
    67  	payload.Config = c
    68  	payload.Authenticated = c.APIToken != ""
    69  
    70  	t := template.New("items")
    71  	t, _ = t.Parse(renderTemplate)
    72  
    73  	buffer := new(bytes.Buffer)
    74  	t.Execute(buffer, payload)
    75  
    76  	return buffer.String()
    77  }
    78  
    79  // Command handles authentication, workspace listing and items retrieval.
    80  func (p *Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
    81  	query := r.URL.Query()
    82  	method := query.Get("method")
    83  
    84  	if len(method) == 0 {
    85  		provider.WriteMessage(w, me, "missing method name")
    86  		return
    87  	}
    88  
    89  	defer r.Body.Close()
    90  	body, err := ioutil.ReadAll(r.Body)
    91  
    92  	if err != nil {
    93  		provider.WriteMessage(w, me, "Bad payload")
    94  		return
    95  	}
    96  
    97  	var config = papertrailConfig{}
    98  	err = json.Unmarshal(body, &config)
    99  
   100  	if err != nil {
   101  		provider.WriteMessage(w, me, "Bad config")
   102  		return
   103  	}
   104  
   105  	config.Clean()
   106  
   107  	if config.APIToken == provider.SecretReplacement || config.APIToken == "" {
   108  		config.APIToken = ctx.GetSecrets("APIToken")
   109  	}
   110  
   111  	if len(config.APIToken) == 0 {
   112  		provider.WriteMessage(w, me, "Missing API token")
   113  		return
   114  	}
   115  
   116  	switch method {
   117  	case "auth":
   118  		auth(ctx, config, w, r)
   119  	case "options":
   120  		options(config, w, r)
   121  	}
   122  }
   123  
   124  // Refresh just sends back data as-is.
   125  func (*Provider) Refresh(ctx *provider.Context, config, data string) (newData string) {
   126  	var c = papertrailConfig{}
   127  	err := json.Unmarshal([]byte(config), &c)
   128  
   129  	if err != nil {
   130  		log.Error("unable to read Papertrail config", err)
   131  		return
   132  	}
   133  
   134  	c.Clean()
   135  
   136  	c.APIToken = ctx.GetSecrets("APIToken")
   137  
   138  	if len(c.APIToken) == 0 {
   139  		log.Error("missing API token", err)
   140  		return
   141  	}
   142  
   143  	result, err := fetchEvents(c)
   144  
   145  	if err != nil {
   146  		log.Error("Papertrail fetchEvents failed", err)
   147  		return
   148  	}
   149  
   150  	j, err := json.Marshal(result)
   151  
   152  	if err != nil {
   153  		log.Error("unable to marshal Papaertrail events", err)
   154  		return
   155  	}
   156  
   157  	newData = string(j)
   158  	return
   159  }
   160  
   161  func auth(ctx *provider.Context, config papertrailConfig, w http.ResponseWriter, r *http.Request) {
   162  	result, err := fetchEvents(config)
   163  
   164  	if result == nil {
   165  		err = errors.New("nil result of papertrail query")
   166  	}
   167  
   168  	if err != nil {
   169  
   170  		log.IfErr(ctx.SaveSecrets(`{"APIToken":""}`)) // invalid token, so reset it
   171  
   172  		if err.Error() == "forbidden" {
   173  			provider.WriteForbidden(w)
   174  		} else {
   175  			provider.WriteError(w, me, err)
   176  		}
   177  
   178  		return
   179  	}
   180  
   181  	log.IfErr(ctx.SaveSecrets(`{"APIToken":"` + config.APIToken + `"}`))
   182  
   183  	provider.WriteJSON(w, result)
   184  }
   185  
   186  func options(config papertrailConfig, w http.ResponseWriter, r *http.Request) {
   187  	// get systems
   188  	req, err := http.NewRequest("GET", "https://papertrailapp.com/api/v1/systems.json", nil)
   189  	req.Header.Set("X-Papertrail-Token", config.APIToken)
   190  
   191  	client := &http.Client{}
   192  	res, err := client.Do(req)
   193  
   194  	if err != nil {
   195  		fmt.Println(err)
   196  		provider.WriteError(w, me, err)
   197  		return
   198  	}
   199  
   200  	if res.StatusCode != http.StatusOK {
   201  		provider.WriteForbidden(w)
   202  		return
   203  	}
   204  
   205  	defer res.Body.Close()
   206  	var systems []papertrailOption
   207  
   208  	dec := json.NewDecoder(res.Body)
   209  	err = dec.Decode(&systems)
   210  
   211  	if err != nil {
   212  		fmt.Println(err)
   213  		provider.WriteError(w, me, err)
   214  		return
   215  	}
   216  
   217  	// get groups
   218  	req, err = http.NewRequest("GET", "https://papertrailapp.com/api/v1/groups.json", nil)
   219  	req.Header.Set("X-Papertrail-Token", config.APIToken)
   220  
   221  	client = &http.Client{}
   222  	res, err = client.Do(req)
   223  
   224  	if err != nil {
   225  		fmt.Println(err)
   226  		provider.WriteError(w, me, err)
   227  		return
   228  	}
   229  
   230  	if res.StatusCode != http.StatusOK {
   231  		provider.WriteForbidden(w)
   232  		return
   233  	}
   234  
   235  	defer res.Body.Close()
   236  	var groups []papertrailOption
   237  
   238  	dec = json.NewDecoder(res.Body)
   239  	err = dec.Decode(&groups)
   240  
   241  	if err != nil {
   242  		fmt.Println(err)
   243  		provider.WriteError(w, me, err)
   244  		return
   245  	}
   246  
   247  	var options = papertrailOptions{}
   248  	options.Groups = groups
   249  	options.Systems = systems
   250  
   251  	provider.WriteJSON(w, options)
   252  }
   253  
   254  func fetchEvents(config papertrailConfig) (result interface{}, err error) {
   255  	var filter string
   256  	if len(config.Query) > 0 {
   257  		filter = fmt.Sprintf("q=%s", url.QueryEscape(config.Query))
   258  	}
   259  	if config.Group.ID > 0 {
   260  		prefix := ""
   261  		if len(filter) > 0 {
   262  			prefix = "&"
   263  		}
   264  		filter = fmt.Sprintf("%s%sgroup_id=%d", filter, prefix, config.Group.ID)
   265  	}
   266  
   267  	var req *http.Request
   268  	req, err = http.NewRequest("GET", "https://papertrailapp.com/api/v1/events/search.json?"+filter, nil)
   269  	if err != nil {
   270  		log.Error("new request", err)
   271  		return
   272  	}
   273  	req.Header.Set("X-Papertrail-Token", config.APIToken)
   274  
   275  	client := &http.Client{}
   276  	var res *http.Response
   277  	res, err = client.Do(req)
   278  
   279  	if err != nil {
   280  		log.Error("message", err)
   281  		return
   282  	}
   283  
   284  	if res.StatusCode != http.StatusOK {
   285  		log.Error("forbidden", err)
   286  		return
   287  	}
   288  
   289  	defer res.Body.Close()
   290  
   291  	dec := json.NewDecoder(res.Body)
   292  	err = dec.Decode(&result)
   293  
   294  	if err != nil {
   295  		log.Error("unable to read result", err)
   296  	}
   297  
   298  	return
   299  }