// Update a specific Team Member. func TeamMemberUpdate(w http.ResponseWriter, r *http.Request, u *User) error { roleParam := r.FormValue("Role") teamParam := r.FormValue(":team") // get the team from the database team, err := database.GetTeamSlug(teamParam) if err != nil { return RenderError(w, err, http.StatusNotFound) } // verify the user is a admin member of the team if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // get the ID from the URL parameter idstr := r.FormValue("id") id, err := strconv.Atoi(idstr) if err != nil { return err } // get the user from the database user, err := database.GetUser(int64(id)) if err != nil { return RenderError(w, err, http.StatusNotFound) } // add the user to the team if err := database.SaveMember(user.ID, team.ID, roleParam); err != nil { return RenderError(w, err, http.StatusInternalServerError) } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
func (g *GitlabHandler) Create(w http.ResponseWriter, r *http.Request, u *User) error { teamName := r.FormValue("team") owner := r.FormValue("owner") name := r.FormValue("name") repo, err := g.newGitlabRepo(u, owner, name) if err != nil { return err } if len(teamName) > 0 { team, err := database.GetTeamSlug(teamName) if err != nil { return fmt.Errorf("Unable to find Team %s.", teamName) } // user must be an admin member of the team if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok { return fmt.Errorf("Invalid permission to access Team %s.", teamName) } repo.TeamID = team.ID } // Save to the database if err := database.SaveRepo(repo); err != nil { return fmt.Errorf("Error saving repository to the database. %s", err) } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
// Return an HTML form for editing a Team Member. func TeamMemberEdit(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // get the ID from the URL parameter idstr := r.FormValue("id") id, err := strconv.Atoi(idstr) if err != nil { return err } user, err := database.GetUser(int64(id)) if err != nil { return err } member, err := database.GetMember(user.ID, team.ID) if err != nil { return err } data := struct { User *User Team *Team Member *Member }{u, team, member} return RenderTemplate(w, "members_edit.html", &data) }
// TestGetTeamName tests the ability to retrieve a Team // from the database by Unique Team Name (aka Slug). func TestGetTeamSlug(t *testing.T) { Setup() defer Teardown() team, err := database.GetTeamSlug("drone") if err != nil { t.Error(err) } if team.ID != 1 { t.Errorf("Exepected ID %d, got %d", 1, team.ID) } if team.Name != "Drone" { t.Errorf("Exepected Name %s, got %s", "Drone", team.Name) } if team.Slug != "drone" { t.Errorf("Exepected Slug %s, got %s", "drone", team.Slug) } if team.Email != "*****@*****.**" { t.Errorf("Exepected Email %s, got %s", "*****@*****.**", team.Email) } if team.Gravatar != "8c58a0be77ee441bb8f8595b7f1b4e87" { t.Errorf("Exepected Gravatar %s, got %s", "8c58a0be77ee441bb8f8595b7f1b4e87", team.Gravatar) } }
// Display a specific Team. func TeamShow(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } if member, _ := database.IsMember(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // list of repositories owned by Team repos, err := database.ListReposTeam(team.ID) if err != nil { return err } // list all user teams teams, err := database.ListTeams(u.ID) if err != nil { return err } // list of recent commits commits, err := database.ListCommitsTeam(team.ID) if err != nil { return err } data := struct { User *User Team *Team Teams []*Team Repos []*Repo Commits []*RepoCommit }{u, team, teams, repos, commits} return RenderTemplate(w, "team_dashboard.html", &data) }
// Return an HTML form for editing a Team. func TeamEdit(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } data := struct { User *User Team *Team }{u, team} return RenderTemplate(w, "team_profile.html", &data) }
// Wall display for the team func TeamWall(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } if member, _ := database.IsMember(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } data := struct { Token string }{channel.CreateStream(fmt.Sprintf("%s", channel.WallDisplay))} return RenderTemplate(w, "watcher.html", &data) }
// Updates an existing repository. func RepoUpdate(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error { switch r.FormValue("action") { case "params": repo.Params = map[string]string{} if err := goyaml.Unmarshal([]byte(r.FormValue("params")), &repo.Params); err != nil { return err } default: repo.URL = r.FormValue("URL") repo.Disabled = len(r.FormValue("Disabled")) == 0 repo.DisabledPullRequest = len(r.FormValue("DisabledPullRequest")) == 0 repo.Private = len(r.FormValue("Private")) > 0 repo.Privileged = u.Admin && len(r.FormValue("Privileged")) > 0 // value of "" indicates the currently authenticated user // should be set as the administrator. if len(r.FormValue("Owner")) == 0 { repo.UserID = u.ID repo.TeamID = 0 } else { // else the user has chosen a team team, err := database.GetTeamSlug(r.FormValue("Owner")) if err != nil { return err } // verify the user is a member of the team if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // set the team ID repo.TeamID = team.ID } } // save the page if err := database.SaveRepo(repo); err != nil { return err } http.Redirect(w, r, r.URL.Path, http.StatusSeeOther) return nil }
// API endpoint for fetching the initial wall display data via AJAX func TeamWallData(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } if member, _ := database.IsMember(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // list of recent commits commits, err := database.ListCommitsTeamWall(team.ID) if err != nil { return err } w.WriteHeader(http.StatusOK) return json.NewEncoder(w).Encode(commits) }
// Delete a specific Team. func TeamDelete(w http.ResponseWriter, r *http.Request, u *User) error { // get the team from the database teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return RenderNotFound(w) } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // the user must confirm their password before deleting password := r.FormValue("password") if err := u.ComparePassword(password); err != nil { return RenderError(w, err, http.StatusBadRequest) } database.DeleteTeam(team.ID) http.Redirect(w, r, "/account/user/teams", http.StatusSeeOther) return nil }
// Display a list of Team Members. func TeamMembers(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return err } // user must be a team member admin if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } members, err := database.ListMembers(team.ID) if err != nil { return err } data := struct { User *User Team *Team Members []*Member }{u, team, members} return RenderTemplate(w, "team_members.html", &data) }
// Update a specific Team. func TeamUpdate(w http.ResponseWriter, r *http.Request, u *User) error { // get team from the database teamName := r.FormValue(":team") team, err := database.GetTeamSlug(teamName) if err != nil { return fmt.Errorf("Forbidden") } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } team.Name = r.FormValue("name") team.SetEmail(r.FormValue("email")) if err := team.Validate(); err != nil { return RenderError(w, err, http.StatusBadRequest) } if err := database.SaveTeam(team); err != nil { return RenderError(w, err, http.StatusBadRequest) } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
// Invite a new Team Member. func TeamMemberInvite(w http.ResponseWriter, r *http.Request, u *User) error { teamParam := r.FormValue(":team") mailParam := r.FormValue("email") team, err := database.GetTeamSlug(teamParam) if err != nil { return RenderError(w, err, http.StatusNotFound) } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // generate a token that is valid for 3 days to join the team token := authcookie.New(strconv.Itoa(int(team.ID)), time.Now().Add(72*time.Hour), secret) // hostname from settings hostname := database.SettingsMust().URL().String() emailEnabled := database.SettingsMust().SmtpServer != "" if !emailEnabled { // Email is not enabled, so must let the user know the signup link link := fmt.Sprintf("%v/accept?token=%v", hostname, token) return RenderText(w, link, http.StatusOK) } // send the invitation data := struct { User *User Team *Team Token string Host string }{u, team, token, hostname} // send email async go mail.SendInvitation(team.Name, mailParam, &data) return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
// Delete a specific Team Member. func TeamMemberDelete(w http.ResponseWriter, r *http.Request, u *User) error { // get the team from the database teamParam := r.FormValue(":team") team, err := database.GetTeamSlug(teamParam) if err != nil { return RenderNotFound(w) } if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member { return fmt.Errorf("Forbidden") } // get the ID from the URL parameter idstr := r.FormValue("id") id, err := strconv.Atoi(idstr) if err != nil { return err } // get the user from the database user, err := database.GetUser(int64(id)) if err != nil { return RenderNotFound(w) } // must be at least 1 member members, err := database.ListMembers(team.ID) if err != nil { return err } else if len(members) == 1 { return fmt.Errorf("There must be at least 1 member per team") } // delete the member database.DeleteMember(user.ID, team.ID) http.Redirect(w, r, fmt.Sprintf("/account/team/%s/members", team.Name), http.StatusSeeOther) return nil }
func RepoCreateGithub(w http.ResponseWriter, r *http.Request, u *User) error { teamName := r.FormValue("team") owner := r.FormValue("owner") name := r.FormValue("name") // get the github settings from the database settings := database.SettingsMust() // create the GitHub client client := github.New(u.GithubToken) githubRepo, err := client.Repos.Find(owner, name) if err != nil { return err } repo, err := NewGitHubRepo(owner, name, githubRepo.Private) if err != nil { return err } repo.UserID = u.ID repo.Private = githubRepo.Private // if the user chose to assign to a team account // we need to retrieve the team, verify the user // has access, and then set the team id. if len(teamName) > 0 { team, err := database.GetTeamSlug(teamName) if err != nil { log.Printf("error retrieving team %s", teamName) return err } // user must be an admin member of the team if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok { return fmt.Errorf("Forbidden") } repo.TeamID = team.ID } // if the repository is private we'll need // to upload a github key to the repository if repo.Private { // name the key keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain) // create the github key, or update if one already exists _, err := client.RepoKeys.CreateUpdate(owner, name, repo.PublicKey, keyName) if err != nil { return fmt.Errorf("Unable to add Private Key to your GitHub repository") } } else { } // create a hook so that we get notified when code // is pushed to the repository and can execute a build. link := fmt.Sprintf("%s://%s/hook/github.com?id=%s", settings.Scheme, settings.Domain, repo.Slug) // add the hook if _, err := client.Hooks.CreateUpdate(owner, name, link); err != nil { return fmt.Errorf("Unable to add Hook to your GitHub repository. %s", err.Error()) } // Save to the database if err := database.SaveRepo(repo); err != nil { log.Print("error saving new repository to the database") return err } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
func RepoCreateGithubLimited(w http.ResponseWriter, r *http.Request, u *User) error { teamName := r.FormValue("team") owner := r.FormValue("owner") name := r.FormValue("name") readToken := r.FormValue("read-token") writeToken := r.FormValue("write-token") u.GithubToken = readToken u.GithubWriteToken = writeToken // get the github settings from the database settings := database.SettingsMust() fmt.Printf("got settings: %s\n", settings) // create the GitHub client rClient := github.New(readToken) wClient := github.New(writeToken) rClient.ApiUrl = settings.GitHubApiUrl wClient.ApiUrl = settings.GitHubApiUrl githubRepo, err := rClient.Repos.Find(owner, name) if err != nil { fmt.Printf("err1, %s\n", err) return err } repo, err := NewGitHubRepo(settings.GitHubDomain, owner, name, githubRepo.Private) if err != nil { fmt.Printf("err2, %s\n", err) return err } repo.URL = fmt.Sprintf("https://%s@%s/%s/%s", readToken, settings.GitHubDomain, owner, name) repo.UserID = u.ID repo.Private = githubRepo.Private // if the user chose to assign to a team account // we need to retrieve the team, verify the user // has access, and then set the team id. if len(teamName) > 0 { team, err := database.GetTeamSlug(teamName) if err != nil { return fmt.Errorf("Unable to find Team %s.", teamName) } // user must be an admin member of the team if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok { return fmt.Errorf("Invalid permission to access Team %s.", teamName) } repo.TeamID = team.ID } // create a hook so that we get notified when code // is pushed to the repository and can execute a build. link := fmt.Sprintf("%s://%s/hook/github.com?id=%s", settings.Scheme, settings.Domain, repo.Slug) // add the hook if _, err := wClient.Hooks.CreateUpdate(owner, name, link); err != nil { return fmt.Errorf("Unable to add Hook to your GitHub repository. %s", err.Error()) } // Save to the database if err := database.SaveRepo(repo); err != nil { return fmt.Errorf("Error saving repository to the database. %s", err) } // Save user to the database if err := database.SaveUser(u); err != nil { return fmt.Errorf("Error saving user to the database. %s", err) } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
func RepoCreateBitbucket(w http.ResponseWriter, r *http.Request, u *User) error { teamName := r.FormValue("team") owner := r.FormValue("owner") name := r.FormValue("name") // get the bitbucket settings from the database settings := database.SettingsMust() // create the Bitbucket client client := bitbucket.New( settings.BitbucketKey, settings.BitbucketSecret, u.BitbucketToken, u.BitbucketSecret, ) bitbucketRepo, err := client.Repos.Find(owner, name) if err != nil { return fmt.Errorf("Unable to find Bitbucket repository %s/%s.", owner, name) } repo, err := NewBitbucketRepo(owner, name, bitbucketRepo.Private) if err != nil { return err } repo.UserID = u.ID repo.Private = bitbucketRepo.Private // if the user chose to assign to a team account // we need to retrieve the team, verify the user // has access, and then set the team id. if len(teamName) > 0 { team, err := database.GetTeamSlug(teamName) if err != nil { return fmt.Errorf("Unable to find Team %s.", teamName) } // user must be an admin member of the team if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok { return fmt.Errorf("Invalid permission to access Team %s.", teamName) } repo.TeamID = team.ID } // if the repository is private we'll need // to upload a bitbucket key to the repository if repo.Private { // name the key keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain) // create the bitbucket key, or update if one already exists _, err := client.RepoKeys.CreateUpdate(owner, name, repo.PublicKey, keyName) if err != nil { return fmt.Errorf("Unable to add Public Key to your Bitbucket repository: %s", err) } } else { } // create a hook so that we get notified when code // is pushed to the repository and can execute a build. link := fmt.Sprintf("%s://%s/hook/bitbucket.org?id=%s", settings.Scheme, settings.Domain, repo.Slug) // add the hook if _, err := client.Brokers.CreateUpdate(owner, name, link, bitbucket.BrokerTypePost); err != nil { return fmt.Errorf("Unable to add Hook to your Bitbucket repository. %s", err.Error()) } // Save to the database if err := database.SaveRepo(repo); err != nil { return fmt.Errorf("Error saving repository to the database. %s", err) } return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) }
// Tests the ability to create GitHub repositories. func Test_GitHubCreate(t *testing.T) { // seed the database with values SetupFixtures() defer TeardownFixtures() // mock request req := http.Request{} req.Form = url.Values{} // get user that will add repositories user, _ := database.GetUser(1) settings := database.SettingsMust() Convey("Given request to setup github repo", t, func() { Convey("When repository is public", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) repo, _ := database.GetRepoSlug(settings.GitHubDomain + "/example/public") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) So(repo.Owner, ShouldEqual, "example") So(repo.Name, ShouldEqual, "public") So(repo.Host, ShouldEqual, settings.GitHubDomain) So(repo.TeamID, ShouldEqual, 0) So(repo.UserID, ShouldEqual, user.ID) So(repo.Private, ShouldEqual, false) So(repo.SCM, ShouldEqual, "git") }) Convey("The repository is public", func() { So(repo.Private, ShouldEqual, false) }) }) Convey("When repository is private", func() { req.Form.Set("owner", "example") req.Form.Set("name", "private") req.Form.Set("team", "") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) repo, _ := database.GetRepoSlug(settings.GitHubDomain + "/example/private") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) }) Convey("The repository is private", func() { So(repo.Private, ShouldEqual, true) }) }) Convey("When repository is not found", func() { req.Form.Set("owner", "example") req.Form.Set("name", "notfound") req.Form.Set("team", "") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to find GitHub repository example/notfound.") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/notfound") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When repository hook is not writable", func() { req.Form.Set("owner", "example") req.Form.Set("name", "hookerr") req.Form.Set("team", "") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to add Hook to your GitHub repository.") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/hookerr") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When repository ssh key is not writable", func() { req.Form.Set("owner", "example") req.Form.Set("name", "keyerr") req.Form.Set("team", "") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to add Public Key to your GitHub repository.") }) Convey("The repository is not created", func() { _, err := database.GetRepoSlug("example/keyerr") So(err, ShouldNotBeNil) So(err, ShouldEqual, sql.ErrNoRows) }) }) Convey("When a team is provided", func() { req.Form.Set("owner", "example") req.Form.Set("name", "team") req.Form.Set("team", "drone") res := httptest.NewRecorder() // invoke handler err := handler.RepoCreateGithub(res, &req, user) team, _ := database.GetTeamSlug("drone") repo, _ := database.GetRepoSlug(settings.GitHubDomain + "/example/team") Convey("The repository is created", func() { So(err, ShouldBeNil) So(repo, ShouldNotBeNil) So(repo.ID, ShouldNotEqual, 0) }) Convey("The team should be set", func() { So(repo.TeamID, ShouldEqual, team.ID) }) }) Convey("When a team is not found", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "faketeam") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Unable to find Team faketeam.") }) }) Convey("When a team is forbidden", func() { req.Form.Set("owner", "example") req.Form.Set("name", "public") req.Form.Set("team", "golang") res := httptest.NewRecorder() err := handler.RepoCreateGithub(res, &req, user) Convey("The result is an error", func() { So(err, ShouldNotBeNil) So(err.Error(), ShouldEqual, "Invalid permission to access Team golang.") }) }) }) }