func UserLoginHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { if !cas.IsAuthenticated(r) { // save the referrer sessionmw.Set(ctx, CASReferrer, r.Referer()) // shut off rendering dataRenderer := data.FromContext(ctx) dataRenderer.Type = data.DataNoRender // and redirect cas.RedirectToLogin(rw, r) } else { // get the referrer referrer, has := sessionmw.Get(ctx, CASReferrer) sessionmw.Delete(ctx, CASReferrer) // shut off rendering dataRenderer := data.FromContext(ctx) dataRenderer.Type = data.DataNoRender // and redirect if !has { http.Redirect(rw, r, render.ConvertURL("/"), http.StatusTemporaryRedirect) } else { http.Redirect(rw, r, referrer.(string), http.StatusTemporaryRedirect) } } }
// MainHandler shows the main page. func MainHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) stat, err := os.Stat("news.md") var time time.Time if err == nil { time = stat.ModTime() } bte, err := ioutil.ReadFile("news.md") markdown := []byte("_Couldn't retrieve the latest news._") if err == nil { markdown = bte } output := blackfriday.MarkdownCommon(markdown) dataRenderer.Data = map[string]interface{}{ "Title": "Main", "News": template.HTML(bluemonday.UGCPolicy().SanitizeBytes(output)), "Time": time, "Nav": 0, } dataRenderer.Template = "index" }
func ActivityHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) // we more or less have Vue.js show recent activity, so just render the template dataRenderer.Data = map[string]interface{}{ "Title": "Recent Activity", "Nav": 1, } dataRenderer.Template = "i/activity" }
func UserLogoutHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { // shut off rendering dataRenderer := data.FromContext(ctx) dataRenderer.Type = data.DataNoRender // Destroy the session sessionmw.Destroy(ctx, rw) // CAS logouts are always one-way. cas.RedirectToLogout(rw, r) }
func ActivityJSONHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) page := int(to.Int64(r.FormValue("page"))) if page <= 0 { page = 1 } limit := int(to.Int64(r.FormValue("limit"))) if limit <= 0 { limit = 50 } var cnt int if err := models.DB.Model(&models.ListActivity{}).Count(&cnt).Error; err != nil { panic(err) } totalpages := cnt / 50 if cnt%50 != 0 { totalpages++ } if page > totalpages { page = totalpages } var activities []models.ListActivity if err := models.DB.Limit(limit).Offset((page - 1) * limit).Order("created_at desc").Find(&activities).Error; err != nil && err != gorm.ErrRecordNotFound { panic(err) } // render a better karma view var rendered []*activityJSON for _, v := range activities { // load the username... rendered = append(rendered, &activityJSON{ ListId: v.ListID, User: models.FindUserByID(v.UserID).Username, Comment: string(bluemonday.UGCPolicy().SanitizeBytes(blackfriday.MarkdownCommon([]byte(v.Activity)))), Time: v.CreatedAt, URL: render.ConvertURL("/b/" + to.String(v.ListID)), }) } dataRenderer.Data = map[string]interface{}{ "totalpages": totalpages, "page": page, "activities": rendered, } dataRenderer.Type = data.DataJSON }
// IntegrationHandler handles webhooks to integration handlers in the integration // package by calling their hook function with the request. func IntegrationHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { // integration is push only with status code returns. no response output. dataRender := data.FromContext(ctx) dataRender.Type = data.DataNoRender // get the handler name (as the first part) handlerName := pattern.Path(ctx) impl := integration.Implementations[strings.Split(handlerName, "/")[0]] if impl == nil { http.NotFound(rw, r) } impl.Hook(r) rw.WriteHeader(200) }
func StaticHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { file := pattern.Path(ctx) f, err := staticDir.Open(file) if err != nil { panic(ErrNotFound) // assume not found } defer f.Close() fi, err := f.Stat() if err != nil { panic(err) // this is weird } // try to serve index file if fi.IsDir() { // redirect if missing trailing slash if !strings.HasSuffix(r.URL.Path, "/") { http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound) return } file = path.Join(file, indexFile) f, err = staticDir.Open(file) if err != nil { panic(ErrNotFound) // just hide its existence } defer f.Close() fi, err = f.Stat() if err != nil || fi.IsDir() { panic(ErrNotFound) // go away } } // okay, we don't need to render this. dataRender := data.FromContext(ctx) dataRender.Type = data.DataNoRender http.ServeContent(rw, r, file, fi.ModTime(), f) }
// ListsHandler shows the collection of lists (HTML). func ListsHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) // filters that will be passed on by Vue.js to the API platform := r.FormValue("platform") channel := r.FormValue("channel") status := r.FormValue("status") limit := r.FormValue("limit") page := r.FormValue("page") dataRenderer.Data = map[string]interface{}{ "Title": "Lists", "Nav": 2, "Platform": platform, "Channel": channel, "Status": status, "Limit": limit, "Page": page, } dataRenderer.Template = "i/list" }
// BuildGetHandler displays build information for a specific build func BuildGetHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) toRender := map[string]interface{}{} id := to.Uint64(pat.Param(ctx, "id")) var pkg models.List if err := models.DB.Where("id = ?", id).First(&pkg).Error; err != nil { if err == gorm.ErrRecordNotFound { panic(ErrNotFound) } else { panic(err) } } toRender["Title"] = "Build " + to.String(id) + ": " + pkg.Name toRender["Nav"] = 2 toRender["ID"] = to.String(id) dataRenderer.Data = toRender dataRenderer.Template = "builds/build" }
// AdminGetHandler controls the central dashboard for Kahinah. func AdminGetHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { adminCheck(r) dataRenderer := data.FromContext(ctx) toRender := map[string]interface{}{ "Loc": 0, "Tab": -1, "Title": "Admin", } user := r.FormValue("username") if user != "" { userModel := models.FindUser(user) toRender["User"] = userModel } var perms []models.UserPermission if err := models.DB.Find(&perms).Error; err != nil && err != gorm.ErrRecordNotFound { panic(err) } rendered := map[string][]string{} for _, perm := range perms { if _, ok := rendered[perm.Permission]; !ok { rendered[perm.Permission] = []string{} } rendered[perm.Permission] = append(rendered[perm.Permission], models.FindUserByID(perm.UserID).Username) } toRender["Permissions"] = rendered dataRenderer.Data = toRender dataRenderer.Template = "admin" }
// ListsAPIHandler shows the collection of lists, with filters, paginated, JSON'ified. func ListsAPIHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) dataRenderer.Type = data.DataJSON platform := r.FormValue("platform") channel := r.FormValue("channel") status := r.FormValue("status") limit := int(to.Int64(r.FormValue("limit"))) if limit <= 0 { limit = 50 // reasonable } page := int(to.Int64(r.FormValue("page"))) if page <= 0 { page = 1 } baseDB := models.DB.Model(&models.List{}) if platform != "" { baseDB = baseDB.Where("platform = ?", platform) } if channel != "" { baseDB = baseDB.Where("channel = ?", channel) } if status == models.ListRunning || status == models.ListPending || status == models.ListSuccess || status == models.ListFailed { baseDB = baseDB.Where("stage_result = ?", status) } else if status != "" { panic(ErrBadRequest) } var cnt int if err := baseDB.Count(&cnt).Error; err != nil { panic(err) } totalpages := cnt / limit if cnt%limit != 0 { totalpages++ } if page > totalpages { page = totalpages } var packages []*models.List if err := baseDB.Limit(limit).Offset((page - 1) * limit).Order("updated_at desc").Find(&packages).Error; err != nil && err != gorm.ErrRecordNotFound { panic(err) } dataRenderer.Data = map[string]interface{}{ "lists": packages, "pages": map[string]interface{}{ "prev": page - 1, "current": page, "next": page + 1, "total": totalpages, }, } }
// BuildPostHandler handles post actions that occur to the current active stage. func BuildPostHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { // check for authentication user := models.FindUser(MustAuthenticate(r)) // setup dataRenderer := data.FromContext(ctx) // read parameters id := to.Uint64(pat.Param(ctx, "id")) target := r.FormValue("target") // either activity or process name := r.FormValue("name") // activity (ignored), process - find process action := r.FormValue("action") // activity (ignored), process passed on value := r.FormValue("value") // activity (comment), process passed on // find the build list var pkg models.List if err := models.DB.Where("id = ?", id).First(&pkg).Related(&pkg.Stages, "Stages").Error; err != nil { if err == gorm.ErrRecordNotFound { panic(ErrNotFound) } else { panic(err) } } var result interface{} // act based on target switch target { case "activity": if value == "" { panic(ErrBadRequest) } pkg.AddActivity(user, value) result = map[string]interface{}{ "success": true, } case "process": // load up the stage & process if err := models.DB.Related(&pkg.Stages, "Stages").Error; err != nil { panic(err) } var currentStage *models.ListStage for _, v := range pkg.Stages { if v.Name == pkg.StageCurrent { currentStage = &v break } } if currentStage == nil { panic(ErrNoCurrentStage) } if err := models.DB.Related(¤tStage.Processes).Error; err != nil { panic(err) } var selectedProcess *models.ListStageProcess for _, v := range currentStage.Processes { if v.Name == name { selectedProcess = &v break } } if selectedProcess == nil { panic(ErrBadRequest) } // initialise the process process, err := processes.BuildProcess(selectedProcess) if err != nil { panic(err) } r, err := process.APIRequest(user, action, value) if err != nil { result = map[string]interface{}{ "error": true, "message": err.Error(), "result": r, } } else { result = r } default: panic(ErrBadRequest) } dataRenderer.Type = data.DataJSON dataRenderer.Data = result //http.Redirect(rw, r, r.URL.String(), http.StatusTemporaryRedirect) }
// BuildGetJSONHandler displays build information in JSON for a specific build. func BuildGetJSONHandler(ctx context.Context, rw http.ResponseWriter, r *http.Request) { dataRenderer := data.FromContext(ctx) id := to.Uint64(pat.Param(ctx, "id")) user := models.FindUserNoCreate(Authenticated(r)) // load the requested build list var pkg models.List if err := models.DB.Where("id = ?", id).First(&pkg).Related(&pkg.Activity, "Activity").Related(&pkg.Artifacts, "Artifacts").Related(&pkg.Links, "Links").Related(&pkg.Stages, "Stages").Error; err != nil { if err == gorm.ErrRecordNotFound { panic(ErrNotFound) } else { panic(err) } } // load stage information var stageInfo []buildGetJSONStage for _, v := range pkg.Stages { if err := models.DB.Related(&v.Processes, "Processes").Error; err != nil && err != gorm.ErrRecordNotFound { panic(err) } // get all process info status := map[string]processes.ProcessStatus{} metadata := map[string]interface{}{} optional := map[string]bool{} for _, p := range v.Processes { process, err := processes.BuildProcess(&p) if err != nil { panic(err) } status[p.Name] = process.Status() metadata[p.Name] = process.APIMetadata(user) optional[p.Name] = p.Optional } stageInfo = append(stageInfo, buildGetJSONStage{ Name: v.Name, Status: status, Metadata: metadata, Optional: optional, }) } // render the data in a nice way dataRenderer.Data = &buildGetJSON{ ID: pkg.ID, Platform: pkg.Platform, Channel: pkg.Channel, Variants: strings.Split(pkg.Variants, ";"), Name: pkg.Name, Artifacts: pkg.Artifacts, Links: pkg.Links, Activity: pkg.Activity, Changes: pkg.Changes, BuildDate: pkg.BuildDate, Updated: pkg.UpdatedAt, PlatformConfig: pkg.PlatformGitConfig, Stages: stageInfo, CurrentStage: pkg.StageCurrent, Status: pkg.StageResult, Advisory: pkg.AdvisoryID, } dataRenderer.Type = data.DataJSON }