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