github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/section/trello/trello.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 trello
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/json"
    17  	"fmt"
    18  	"html/template"
    19  	"io/ioutil"
    20  	"net/http"
    21  
    22  	"github.com/documize/community/documize/api/request"
    23  	"github.com/documize/community/documize/section/provider"
    24  	"github.com/documize/community/wordsmith/log"
    25  )
    26  
    27  var meta provider.TypeMeta
    28  
    29  func init() {
    30  	meta = provider.TypeMeta{}
    31  	meta.ID = "c455a552-202e-441c-ad79-397a8152920b"
    32  	meta.Title = "Trello"
    33  	meta.Description = "Embed cards from boards and lists"
    34  	meta.ContentType = "trello"
    35  }
    36  
    37  // Provider represents Trello
    38  type Provider struct {
    39  }
    40  
    41  // Meta describes us
    42  func (*Provider) Meta() provider.TypeMeta {
    43  	return meta
    44  }
    45  
    46  // Command stub.
    47  func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) {
    48  	query := r.URL.Query()
    49  	method := query.Get("method")
    50  
    51  	defer r.Body.Close()
    52  	body, err := ioutil.ReadAll(r.Body)
    53  
    54  	if err != nil {
    55  		provider.WriteMessage(w, "trello", "Bad body")
    56  		return
    57  	}
    58  
    59  	var config = trelloConfig{}
    60  	err = json.Unmarshal(body, &config)
    61  
    62  	if err != nil {
    63  		provider.WriteError(w, "trello", err)
    64  		return
    65  	}
    66  
    67  	config.Clean()
    68  	config.AppKey = request.ConfigString(meta.ConfigHandle(), "appKey")
    69  
    70  	if len(config.AppKey) == 0 {
    71  		log.ErrorString("missing trello App Key")
    72  		provider.WriteMessage(w, "trello", "Missing appKey")
    73  		return
    74  	}
    75  
    76  	if len(config.Token) == 0 {
    77  		config.Token = ctx.GetSecrets("token") // get a token, if we have one
    78  	}
    79  
    80  	if method != "config" {
    81  		if len(config.Token) == 0 {
    82  			provider.WriteMessage(w, "trello", "Missing token")
    83  			return
    84  		}
    85  	}
    86  
    87  	switch method {
    88  	case "cards":
    89  		render, err := getCards(config)
    90  
    91  		if err != nil {
    92  			log.IfErr(err)
    93  			provider.WriteError(w, "trello", err)
    94  			log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid
    95  			return
    96  		}
    97  
    98  		provider.WriteJSON(w, render)
    99  
   100  	case "boards":
   101  		render, err := getBoards(config)
   102  
   103  		if err != nil {
   104  			log.IfErr(err)
   105  			provider.WriteError(w, "trello", err)
   106  			log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid
   107  			return
   108  		}
   109  
   110  		provider.WriteJSON(w, render)
   111  
   112  	case "lists":
   113  		render, err := getLists(config)
   114  
   115  		if err != nil {
   116  			log.IfErr(err)
   117  			provider.WriteError(w, "trello", err)
   118  			log.IfErr(ctx.SaveSecrets("")) // failure means our secrets are invalid
   119  			return
   120  		}
   121  
   122  		provider.WriteJSON(w, render)
   123  
   124  	case "config":
   125  		var ret struct {
   126  			AppKey string `json:"appKey"`
   127  			Token  string `json:"token"`
   128  		}
   129  		ret.AppKey = config.AppKey
   130  		if config.Token != "" {
   131  			ret.Token = provider.SecretReplacement
   132  		}
   133  		provider.WriteJSON(w, ret)
   134  		return
   135  
   136  	default:
   137  		log.ErrorString("trello unknown method name: " + method)
   138  		provider.WriteMessage(w, "trello", "missing method name")
   139  		return
   140  	}
   141  
   142  	// the token has just worked, so save it as our secret
   143  	var s secrets
   144  	s.Token = config.Token
   145  	b, e := json.Marshal(s)
   146  	log.IfErr(e)
   147  	log.IfErr(ctx.SaveSecrets(string(b)))
   148  }
   149  
   150  // Render just sends back HMTL as-is.
   151  func (*Provider) Render(ctx *provider.Context, config, data string) string {
   152  	raw := []trelloListCards{}
   153  	payload := trelloRender{}
   154  	var c = trelloConfig{}
   155  
   156  	json.Unmarshal([]byte(data), &raw)
   157  	json.Unmarshal([]byte(config), &c)
   158  
   159  	payload.Board = c.Board
   160  	payload.Data = raw
   161  	payload.ListCount = len(raw)
   162  
   163  	for _, list := range raw {
   164  		payload.CardCount += len(list.Cards)
   165  	}
   166  
   167  	t := template.New("trello")
   168  	t, _ = t.Parse(renderTemplate)
   169  
   170  	buffer := new(bytes.Buffer)
   171  	t.Execute(buffer, payload)
   172  
   173  	return buffer.String()
   174  }
   175  
   176  // Refresh just sends back data as-is.
   177  func (*Provider) Refresh(ctx *provider.Context, config, data string) string {
   178  	var c = trelloConfig{}
   179  	json.Unmarshal([]byte(config), &c)
   180  
   181  	refreshed, err := getCards(c)
   182  
   183  	if err != nil {
   184  		return data
   185  	}
   186  
   187  	j, err := json.Marshal(refreshed)
   188  
   189  	if err != nil {
   190  		log.Error("unable to marshall trello cards", err)
   191  		return data
   192  	}
   193  
   194  	return string(j)
   195  }
   196  
   197  // Helpers
   198  func getBoards(config trelloConfig) (boards []trelloBoard, err error) {
   199  	req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/members/me/boards?fields=id,name,url,closed,prefs,idOrganization&key=%s&token=%s", config.AppKey, config.Token), nil)
   200  	client := &http.Client{}
   201  	res, err := client.Do(req)
   202  
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	if res.StatusCode != http.StatusOK {
   208  		return nil, fmt.Errorf("error: HTTP status code %d", res.StatusCode)
   209  	}
   210  
   211  	b := []trelloBoard{}
   212  
   213  	defer res.Body.Close()
   214  	dec := json.NewDecoder(res.Body)
   215  	err = dec.Decode(&b)
   216  
   217  	// we only show open, team boards (not personal)
   218  	for _, b := range b {
   219  		if !b.Closed && len(b.OrganizationID) > 0 {
   220  			boards = append(boards, b)
   221  		}
   222  	}
   223  
   224  	if err != nil {
   225  		fmt.Println(err)
   226  		return nil, err
   227  	}
   228  
   229  	return boards, nil
   230  }
   231  
   232  func getLists(config trelloConfig) (lists []trelloList, err error) {
   233  	req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/boards/%s/lists/open?key=%s&token=%s", config.Board.ID, config.AppKey, config.Token), nil)
   234  	client := &http.Client{}
   235  	res, err := client.Do(req)
   236  
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  
   241  	if res.StatusCode != http.StatusOK {
   242  		return nil, fmt.Errorf("error: HTTP status code %d", res.StatusCode)
   243  	}
   244  
   245  	defer res.Body.Close()
   246  
   247  	dec := json.NewDecoder(res.Body)
   248  	err = dec.Decode(&lists)
   249  
   250  	if err != nil {
   251  		fmt.Println(err)
   252  		return nil, err
   253  	}
   254  
   255  	return lists, nil
   256  }
   257  
   258  func getCards(config trelloConfig) (listCards []trelloListCards, err error) {
   259  	for _, list := range config.Lists {
   260  
   261  		// don't process lists that user excluded from rendering
   262  		if !list.Included {
   263  			continue
   264  		}
   265  
   266  		req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/lists/%s/cards?key=%s&token=%s", list.ID, config.AppKey, config.Token), nil)
   267  		client := &http.Client{}
   268  		res, err := client.Do(req)
   269  
   270  		if err != nil {
   271  			return nil, err
   272  		}
   273  
   274  		if res.StatusCode != http.StatusOK {
   275  			return nil, fmt.Errorf("error: HTTP status code %d", res.StatusCode)
   276  		}
   277  
   278  		defer res.Body.Close()
   279  		var cards []trelloCard
   280  
   281  		dec := json.NewDecoder(res.Body)
   282  		err = dec.Decode(&cards)
   283  
   284  		if err != nil {
   285  			return nil, err
   286  		}
   287  
   288  		data := trelloListCards{}
   289  		data.Cards = cards
   290  		data.List = list
   291  
   292  		listCards = append(listCards, data)
   293  	}
   294  
   295  	return listCards, nil
   296  }