github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/core/section/github/github.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 github 13 14 import ( 15 "bytes" 16 "encoding/json" 17 "errors" 18 //"fmt" 19 "html/template" 20 "io/ioutil" 21 "net/http" 22 "strings" 23 24 "github.com/documize/community/core/log" 25 "github.com/documize/community/core/section/provider" 26 27 gogithub "github.com/google/go-github/github" 28 ) 29 30 // TODO find a smaller image than the one below 31 const githubGravatar = "https://i2.wp.com/assets-cdn.github.com/images/gravatars/gravatar-user-420.png" 32 33 var meta provider.TypeMeta 34 35 func init() { 36 meta = provider.TypeMeta{} 37 38 meta.ID = "38c0e4c5-291c-415e-8a4d-262ee80ba5df" 39 meta.Title = "GitHub" 40 meta.Description = "Link code commits and issues" 41 meta.ContentType = "github" 42 meta.PageType = "tab" 43 meta.Callback = Callback 44 } 45 46 // Provider represents GitHub 47 type Provider struct { 48 } 49 50 // Meta describes us. 51 func (*Provider) Meta() provider.TypeMeta { 52 return meta 53 } 54 55 // Command to run the various functions required... 56 func (p *Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.Request) { 57 query := r.URL.Query() 58 method := query.Get("method") 59 60 if len(method) == 0 { 61 msg := "missing method name" 62 log.ErrorString("github: " + msg) 63 provider.WriteMessage(w, "gitub", msg) 64 return 65 } 66 67 if method == "config" { 68 var ret struct { 69 CID string `json:"clientID"` 70 URL string `json:"authorizationCallbackURL"` 71 } 72 ret.CID = clientID() 73 ret.URL = authorizationCallbackURL() 74 provider.WriteJSON(w, ret) 75 return 76 } 77 78 defer r.Body.Close() // ignore error 79 80 body, err := ioutil.ReadAll(r.Body) 81 82 if err != nil { 83 msg := "Bad body" 84 log.ErrorString("github: " + msg) 85 provider.WriteMessage(w, "github", msg) 86 return 87 } 88 89 if method == "saveSecret" { // secret Token update code 90 91 // write the new one, direct from JS 92 if err = ctx.SaveSecrets(string(body)); err != nil { 93 log.Error("github settoken configuration", err) 94 provider.WriteError(w, "github", err) 95 return 96 } 97 provider.WriteEmpty(w) 98 return 99 100 } 101 102 // load the config from the client-side 103 config := githubConfig{} 104 err = json.Unmarshal(body, &config) 105 106 if err != nil { 107 log.Error("github Command Unmarshal", err) 108 provider.WriteError(w, "github", err) 109 return 110 } 111 112 config.Clean() 113 // always use DB version of the token 114 config.Token = ctx.GetSecrets("token") // get the secret token in the database 115 116 client := p.githubClient(&config) 117 118 switch method { 119 120 case "checkAuth": 121 122 if len(config.Token) == 0 { 123 err = errors.New("empty github token") 124 } else { 125 err = validateToken(config.Token) 126 } 127 if err != nil { 128 // token now invalid, so wipe it 129 ctx.SaveSecrets("") // ignore error, already in an error state 130 log.Error("github check token validation", err) 131 provider.WriteError(w, "github", err) 132 return 133 } 134 provider.WriteEmpty(w) 135 136 default: 137 138 if listFailed(method, config, client, w) { 139 140 gr := githubRender{} 141 for _, rep := range reports { 142 log.IfErr(rep.refresh(&gr, &config, client)) 143 } 144 provider.WriteJSON(w, &gr) 145 146 } 147 148 } 149 } 150 151 // Refresh ... gets the latest version 152 func (p *Provider) Refresh(ctx *provider.Context, configJSON, data string) string { 153 var c = githubConfig{} 154 155 err := json.Unmarshal([]byte(configJSON), &c) 156 157 if err != nil { 158 log.Error("unable to unmarshall github config", err) 159 return "internal configuration error '" + err.Error() + "'" 160 } 161 162 c.Clean() 163 c.Token = ctx.GetSecrets("token") 164 165 client := p.githubClient(&c) 166 167 byts, err := json.Marshal(refreshReportData(&c, client)) 168 if err != nil { 169 log.Error("unable to marshall github data", err) 170 return "internal configuration error '" + err.Error() + "'" 171 } 172 173 return string(byts) 174 175 } 176 177 func refreshReportData(c *githubConfig, client *gogithub.Client) *githubRender { 178 var gr = githubRender{} 179 for _, rep := range reports { 180 log.IfErr(rep.refresh(&gr, c, client)) 181 } 182 return &gr 183 } 184 185 // Render ... just returns the data given, suitably formatted 186 func (p *Provider) Render(ctx *provider.Context, config, data string) string { 187 var err error 188 189 payload := githubRender{} 190 var c = githubConfig{} 191 192 err = json.Unmarshal([]byte(config), &c) 193 194 if err != nil { 195 log.Error("unable to unmarshall github config", err) 196 return "Please delete and recreate this Github section." 197 } 198 199 c.Clean() 200 c.Token = ctx.GetSecrets("token") 201 202 data = strings.TrimSpace(data) 203 if len(data) == 0 { 204 // TODO review why this error occurs & if it should be reported - seems to occur for new sections 205 // log.ErrorString(fmt.Sprintf("Rendered empty github JSON payload as '' for owner %s repos %#v", c.Owner, c.Lists)) 206 return "" 207 } 208 209 err = json.Unmarshal([]byte(data), &payload) 210 if err != nil { 211 log.Error("unable to unmarshall github data", err) 212 return "Please delete and recreate this Github section." 213 } 214 215 payload.Config = c 216 payload.Limit = c.BranchLines 217 payload.List = c.Lists 218 219 ret := "" 220 for _, repID := range c.ReportOrder { 221 222 rep, ok := reports[repID] 223 if !ok { 224 msg := "github report not found for: " + repID 225 log.ErrorString(msg) 226 return "Documize internal error: " + msg 227 } 228 229 if err = rep.render(&payload, &c); err != nil { 230 log.Error("unable to render "+repID, err) 231 return "Documize internal github render " + repID + " error: " + err.Error() + "<BR>" + data 232 } 233 234 t := template.New("github") 235 236 t, err = t.Parse(rep.template) 237 238 if err != nil { 239 log.Error("github render template.Parse error:", err) 240 //for k, v := range strings.Split(rep.template, "\n") { 241 // fmt.Println("DEBUG", k+1, v) 242 //} 243 return "Documize internal github template.Parse error: " + err.Error() 244 } 245 246 buffer := new(bytes.Buffer) 247 err = t.Execute(buffer, payload) 248 if err != nil { 249 log.Error("github render template.Execute error:", err) 250 return "Documize internal github template.Execute error: " + err.Error() 251 } 252 253 ret += buffer.String() 254 255 } 256 return ret 257 }