227 lines
5.9 KiB
Go
227 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/dchest/authcookie"
|
|
"github.com/drone/drone/pkg/database"
|
|
"github.com/drone/drone/pkg/mail"
|
|
. "github.com/drone/drone/pkg/model"
|
|
)
|
|
|
|
// 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)
|
|
}
|
|
|
|
// Return an HTML form for creating a new Team Member.
|
|
func TeamMemberAdd(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, "members_add.html", &data)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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(team.Name, 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)
|
|
}
|
|
|
|
func TeamMemberAccept(w http.ResponseWriter, r *http.Request, u *User) error {
|
|
// get the team name from the token
|
|
token := r.FormValue("token")
|
|
teamName := authcookie.Login(token, secret)
|
|
if len(teamName) == 0 {
|
|
return ErrInvalidTeamName
|
|
}
|
|
|
|
// get the team from the database
|
|
// TODO it might make more sense to use the ID in case the Slug changes
|
|
team, err := database.GetTeamSlug(teamName)
|
|
if err != nil {
|
|
return RenderError(w, err, http.StatusNotFound)
|
|
}
|
|
|
|
// add the user to the team.
|
|
// by default the user has write access to the team, which means
|
|
// they can add and manage new repositories.
|
|
if err := database.SaveMember(u.ID, team.ID, RoleWrite); err != nil {
|
|
return RenderError(w, err, http.StatusInternalServerError)
|
|
}
|
|
|
|
// send the user to the dashboard
|
|
http.Redirect(w, r, "/dashboard/team/"+team.Name, http.StatusSeeOther)
|
|
return nil
|
|
}
|