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 }