From d697e7926b8f716a4b88e10e9ad83700cddded8e Mon Sep 17 00:00:00 2001 From: Harvey Kandola Date: Mon, 16 May 2016 22:10:28 -0700 Subject: [PATCH] Trello board rendering --- app/app/components/section/trello/code.go | 40 --- .../components/section/trello/type-editor.js | 30 +- .../components/section/trello/type-editor.hbs | 26 +- .../section/trello/type-renderer.hbs | 19 +- documize/section/gemini.go | 53 ++-- documize/section/trello.go | 282 +++++++++++++++++- 6 files changed, 346 insertions(+), 104 deletions(-) delete mode 100644 app/app/components/section/trello/code.go diff --git a/app/app/components/section/trello/code.go b/app/app/components/section/trello/code.go deleted file mode 100644 index 77b8a20f..00000000 --- a/app/app/components/section/trello/code.go +++ /dev/null @@ -1,40 +0,0 @@ -package section - -import ( - "net/http" -) - -type code struct { -} - -func init() { - sectionsMap["code"] = &code{} -} - -func (*code) Meta() TypeMeta { - section := TypeMeta{} - - section.ID = "4f6f2b02-8397-483d-9bb9-eea1fef13304" - section.Title = "Code" - section.Description = "Code snippets supporting 50+ languages" - section.ContentType = "code" - section.IconFontLigature = "code" - section.Order = 9997 - - return section -} - -// Command stub. -func (*code) Command(w http.ResponseWriter, r *http.Request) { - writeEmpty(w) -} - -// Render just sends back HMTL as-is. -func (*code) Render(config, data string) string { - return data -} - -// Refresh just sends back data as-is. -func (*code) Refresh(config, data string) string { - return data -} diff --git a/app/app/components/section/trello/type-editor.js b/app/app/components/section/trello/type-editor.js index b8b40af1..b8480295 100644 --- a/app/app/components/section/trello/type-editor.js +++ b/app/app/components/section/trello/type-editor.js @@ -10,7 +10,6 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { authenticated: false, config: {}, boards: null, - lists: null, didReceiveAttrs() { let config = {}; @@ -24,8 +23,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { appKey: "", token: "", board: null, - list: null, - cards: null + lists: [] }; } @@ -47,7 +45,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { let board = this.get('config.board'); this.set('waiting', true); - if (board === null) { + if (is.null(board)) { if (boards.length) { board = boards[0]; this.set('config.board', board); @@ -56,7 +54,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { this.set('config.board', boards.findBy('id', board.id)); } - Trello.get(`boards/${board.id}/lists/open`, + Trello.get(`boards/${board.id}/lists/open?fields=id,name,url`, function(lists) { let savedLists = self.get('config.lists'); if (savedLists === null) { @@ -74,8 +72,6 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { self.set('config.lists', lists); self.set('waiting', false); - - // self.getListCards(); }); }, @@ -155,25 +151,31 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { this.getBoardLists(); }, - // onListChange(list) { - // this.set('config.list', list); - // this.getListCards(); - // }, - onCancel() { this.attrs.onCancel(); }, onAction(title) { + this.set('waiting', false); + + let self = this; let page = this.get('page'); let meta = this.get('meta'); page.set('title', title); - // meta.set('rawBody', JSON.stringify(this.get("items"))); meta.set('rawBody', ''); meta.set('config', JSON.stringify(this.get('config'))); meta.set('externalSource', true); - this.attrs.onAction(page, meta); + this.get('sectionService').fetch(page, "cards", this.get('config')) + .then(function(response) { + console.log(response); + meta.set('rawBody', JSON.stringify(response)); + self.set('waiting', false); + self.attrs.onAction(page, meta); + }, function(reason) { //jshint ignore: line + self.set('waiting', false); + self.attrs.onAction(page, meta); + }); } } }); \ No newline at end of file diff --git a/app/app/templates/components/section/trello/type-editor.hbs b/app/app/templates/components/section/trello/type-editor.hbs index 5be096b7..6672552f 100644 --- a/app/app/templates/components/section/trello/type-editor.hbs +++ b/app/app/templates/components/section/trello/type-editor.hbs @@ -1,18 +1,18 @@ -{{#section/base-editor document=document folder=folder page=page busy=waiting tip="Trello, yellow, mellow" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}} +{{#section/base-editor document=document folder=folder page=page busy=waiting tip="Trello is the visual way to manage your projects and organize anything (https://trello.com)" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}}
@@ -73,18 +73,16 @@
Select lists to include
-
-
{{config.board.name}}
+
+
{{config.board.name}}
{{#each config.lists as |list|}} -
+
{{#if list.included}} - check_box + check_box {{else}} - check_box_outline_blank + check_box_outline_blank {{/if}} - {{list.name}} - {{!----}} - {{!----}} + {{list.name}}
{{/each}}
diff --git a/app/app/templates/components/section/trello/type-renderer.hbs b/app/app/templates/components/section/trello/type-renderer.hbs index 4c2c28eb..db8fbf6b 100644 --- a/app/app/templates/components/section/trello/type-renderer.hbs +++ b/app/app/templates/components/section/trello/type-renderer.hbs @@ -1,5 +1,5 @@ diff --git a/documize/section/gemini.go b/documize/section/gemini.go index 33fb3a27..31e13c1a 100644 --- a/documize/section/gemini.go +++ b/documize/section/gemini.go @@ -13,8 +13,6 @@ import ( "github.com/documize/community/wordsmith/log" ) -const sectionName = "gemini" - // the HTML that is rendered by this section. const renderTemplate = `

The Gemini workspace {{.Config.WorkspaceName}} contains {{.Config.ItemCount}} items.

@@ -47,17 +45,16 @@ type gemini struct { // Register ourselves. func init() { - sectionsMap[sectionName] = &gemini{} + sectionsMap["gemini"] = &gemini{} } // Meta describes this section type. func (*gemini) Meta() TypeMeta { section := TypeMeta{} - section.ID = "23b133f9-4020-4616-9291-a98fb939735f" section.Title = "Gemini" section.Description = "Display work items and tickets from Gemini workspaces" - section.ContentType = sectionName + section.ContentType = "gemini" section.IconFontLigature = "" section.IconFilePath = "sections/gemini.png" @@ -93,7 +90,7 @@ func (*gemini) Command(w http.ResponseWriter, r *http.Request) { method := query.Get("method") if len(method) == 0 { - writeMessage(w, sectionName, "missing method name") + writeMessage(w, "gemini", "missing method name") return } @@ -222,7 +219,7 @@ func auth(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } @@ -230,24 +227,24 @@ func auth(w http.ResponseWriter, r *http.Request) { err = json.Unmarshal(body, &config) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } config.Clean() if len(config.URL) == 0 { - writeMessage(w, sectionName, "Missing URL value") + writeMessage(w, "gemini", "Missing URL value") return } if len(config.Username) == 0 { - writeMessage(w, sectionName, "Missing Username value") + writeMessage(w, "gemini", "Missing Username value") return } if len(config.APIKey) == 0 { - writeMessage(w, sectionName, "Missing APIKey value") + writeMessage(w, "gemini", "Missing APIKey value") return } @@ -261,7 +258,7 @@ func auth(w http.ResponseWriter, r *http.Request) { if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } @@ -278,7 +275,7 @@ func auth(w http.ResponseWriter, r *http.Request) { if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } @@ -290,7 +287,7 @@ func workspace(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } @@ -298,29 +295,29 @@ func workspace(w http.ResponseWriter, r *http.Request) { err = json.Unmarshal(body, &config) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } config.Clean() if len(config.URL) == 0 { - writeMessage(w, sectionName, "Missing URL value") + writeMessage(w, "gemini", "Missing URL value") return } if len(config.Username) == 0 { - writeMessage(w, sectionName, "Missing Username value") + writeMessage(w, "gemini", "Missing Username value") return } if len(config.APIKey) == 0 { - writeMessage(w, sectionName, "Missing APIKey value") + writeMessage(w, "gemini", "Missing APIKey value") return } if config.UserID == 0 { - writeMessage(w, sectionName, "Missing UserId value") + writeMessage(w, "gemini", "Missing UserId value") return } @@ -334,7 +331,7 @@ func workspace(w http.ResponseWriter, r *http.Request) { if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } @@ -363,7 +360,7 @@ func items(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } @@ -371,24 +368,24 @@ func items(w http.ResponseWriter, r *http.Request) { err = json.Unmarshal(body, &config) if err != nil { - writeMessage(w, sectionName, "Bad payload") + writeMessage(w, "gemini", "Bad payload") return } config.Clean() if len(config.URL) == 0 { - writeMessage(w, sectionName, "Missing URL value") + writeMessage(w, "gemini", "Missing URL value") return } if len(config.Username) == 0 { - writeMessage(w, sectionName, "Missing Username value") + writeMessage(w, "gemini", "Missing Username value") return } if len(config.APIKey) == 0 { - writeMessage(w, sectionName, "Missing APIKey value") + writeMessage(w, "gemini", "Missing APIKey value") return } @@ -397,7 +394,7 @@ func items(w http.ResponseWriter, r *http.Request) { filter, err := json.Marshal(config.Filter) if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } @@ -411,7 +408,7 @@ func items(w http.ResponseWriter, r *http.Request) { if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } @@ -428,7 +425,7 @@ func items(w http.ResponseWriter, r *http.Request) { if err != nil { fmt.Println(err) - writeError(w, sectionName, err) + writeError(w, "gemini", err) return } diff --git a/documize/section/trello.go b/documize/section/trello.go index 77e35afc..28c4f3c9 100644 --- a/documize/section/trello.go +++ b/documize/section/trello.go @@ -1,7 +1,13 @@ package section import ( + "bytes" + "encoding/json" + "fmt" + "html/template" + "io/ioutil" "net/http" + "strings" ) type trello struct { @@ -13,7 +19,6 @@ func init() { func (*trello) Meta() TypeMeta { section := TypeMeta{} - section.ID = "c455a552-202e-441c-ad79-397a8152920b" section.Title = "Trello" section.Description = "Trello boards" @@ -25,15 +30,286 @@ func (*trello) Meta() TypeMeta { // Command stub. func (*trello) Command(w http.ResponseWriter, r *http.Request) { - writeEmpty(w) + query := r.URL.Query() + method := query.Get("method") + + if len(method) == 0 { + writeMessage(w, "trello", "missing method name") + return + } + + switch method { + case "cards": + cards(w, r) + } } // Render just sends back HMTL as-is. func (*trello) Render(config, data string) string { - return data + raw := []trelloListCards{} + payload := trelloRender{} + var c = trelloConfig{} + + json.Unmarshal([]byte(data), &raw) + json.Unmarshal([]byte(config), &c) + + payload.Board = c.Board + payload.Data = raw + payload.ListCount = len(raw) + + for _, list := range raw { + payload.CardCount += len(list.Cards) + } + + t := template.New("trello") + t, _ = t.Parse(trelloTemplate) + + buffer := new(bytes.Buffer) + t.Execute(buffer, payload) + + return buffer.String() } // Refresh just sends back data as-is. func (*trello) Refresh(config, data string) string { return data } + +// Helpers +func cards(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + body, err := ioutil.ReadAll(r.Body) + + if err != nil { + writeMessage(w, "trello", "Bad body") + return + } + + var config = trelloConfig{} + err = json.Unmarshal(body, &config) + + if err != nil { + writeError(w, "trello", err) + // writeMessage(w, "trello", "Bad payload") + return + } + + config.Clean() + + if len(config.AppKey) == 0 { + writeMessage(w, "trello", "Missing appKey") + return + } + + if len(config.Token) == 0 { + writeMessage(w, "trello", "Missing token") + return + } + + render := []trelloListCards{} + + for _, list := range config.Lists { + + if !list.Included { + continue + } + + 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) + client := &http.Client{} + res, err := client.Do(req) + + if err != nil { + fmt.Println(err) + writeError(w, "trello", err) + return + } + + if res.StatusCode != http.StatusOK { + writeForbidden(w) + return + } + + defer res.Body.Close() + var cards []trelloCard + + dec := json.NewDecoder(res.Body) + err = dec.Decode(&cards) + + if err != nil { + fmt.Println(err) + writeError(w, "trello", err) + return + } + + data := trelloListCards{} + data.Cards = cards + data.List = list + + render = append(render, data) + } + + writeJSON(w, render) +} + +type trelloConfig struct { + AppKey string `json:"appKey"` + Token string `json:"token"` + Board trelloBoard `json:"board"` + Lists []trelloList `json:"lists"` +} + +func (c *trelloConfig) Clean() { + c.AppKey = strings.TrimSpace(c.AppKey) + c.Token = strings.TrimSpace(c.Token) +} + +type trelloBoard struct { + ID string `json:"id"` + Name string `json:"name"` + Desc string `json:"desc"` + DescData struct { + Emoji struct{} `json:"emoji"` + } `json:"descData"` + Closed bool `json:"closed"` + OrganizationID string `json:"idOrganization"` + Pinned bool `json:"pinned"` + URL string `json:"url"` + ShortURL string `json:"shortUrl"` + Prefs struct { + PermissionLevel string `json:"permissionLevel"` + Voting string `json:"voting"` + Comments string `json:"comments"` + Invitations string `json:"invitations"` + SelfJoin bool `json:"selfjoin"` + CardCovers bool `json:"cardCovers"` + CardAging string `json:"cardAging"` + CalendarFeedEnabled bool `json:"calendarFeedEnabled"` + Background string `json:"background"` + BackgroundColor string `json:"backgroundColor"` + BackgroundImage string `json:"backgroundImage"` + BackgroundImageScaled []trelloBoardBackground `json:"backgroundImageScaled"` + BackgroundTile bool `json:"backgroundTile"` + BackgroundBrightness string `json:"backgroundBrightness"` + CanBePublic bool `json:"canBePublic"` + CanBeOrg bool `json:"canBeOrg"` + CanBePrivate bool `json:"canBePrivate"` + CanInvite bool `json:"canInvite"` + } `json:"prefs"` + LabelNames struct { + Red string `json:"red"` + Orange string `json:"orange"` + Yellow string `json:"yellow"` + Green string `json:"green"` + Blue string `json:"blue"` + Purple string `json:"purple"` + } `json:"labelNames"` +} + +type trelloBoardBackground struct { + width int `json:"width"` + height int `json:"height"` + url string `json:"url"` +} + +type trelloList struct { + ID string `json:"id"` + Name string `json:"name"` + Closed bool `json:"closed"` + BoardID string `json:"idBoard"` + Pos float32 `json:"pos"` + Included bool `json:"included"` // indicates whether we display cards from this list +} + +type trelloCard struct { + ID string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + ShortID int `json:"idShort"` + AttachmentCoverID string `json:"idAttachmentCover"` + CheckListsID []string `json:"idCheckLists"` + BoardID string `json:"idBoard"` + ListID string `json:"idList"` + MembersID []string `json:"idMembers"` + MembersVotedID []string `json:"idMembersVoted"` + ManualCoverAttachment bool `json:"manualCoverAttachment"` + Closed bool `json:"closed"` + Pos float32 `json:"pos"` + ShortLink string `json:"shortLink"` + DateLastActivity string `json:"dateLastActivity"` + ShortURL string `json:"shortUrl"` + Subscribed bool `json:"subscribed"` + URL string `json:"url"` + Due string `json:"due"` + Desc string `json:"desc"` + DescData struct { + Emoji struct{} `json:"emoji"` + } `json:"descData"` + CheckItemStates []struct { + CheckItemID string `json:"idCheckItem"` + State string `json:"state"` + } `json:"checkItemStates"` + Badges struct { + Votes int `json:"votes"` + ViewingMemberVoted bool `json:"viewingMemberVoted"` + Subscribed bool `json:"subscribed"` + Fogbugz string `json:"fogbugz"` + CheckItems int `json:"checkItems"` + CheckItemsChecked int `json:"checkItemsChecked"` + Comments int `json:"comments"` + Attachments int `json:"attachments"` + Description bool `json:"description"` + Due string `json:"due"` + } `json:"badges"` + Labels []struct { + Color string `json:"color"` + Name string `json:"name"` + } `json:"labels"` +} + +type trelloListCards struct { + List trelloList + Cards []trelloCard +} + +type trelloRender struct { + Board trelloBoard + Data []trelloListCards + CardCount int + ListCount int +} + +// the HTML that is rendered by this section +const trelloTemplate = ` +

There are {{ .CardCount }} cards across {{ .ListCount }} lists for board {{.Board.Name}}.

+
+
{{.Board.Name}}
+ {{range $data := .Data}} +
+
{{ $data.List.Name }}
+ {{range $card := $data.Cards}} + +
+ {{ $card.Name }} +
+
+ {{end}} +
+ {{end}} +
+` + +/* + +refresh method + +does server side load up all data? YES!!?? + +we need method to use different trello accounts + - does this mean logout button? + - does this only work on add section phase? + +is appKey is global? + - where stored? + - how access? + - does section.go ask config to give us saved json +*/