github.com/robryk/drone@v0.2.1-0.20140602202253-40fe4305815d/pkg/handler/handler.go (about) 1 package handler 2 3 import ( 4 "fmt" 5 "log" 6 "net/http" 7 "net/url" 8 9 "github.com/drone/drone/pkg/database" 10 . "github.com/drone/drone/pkg/model" 11 ) 12 13 // ErrorHandler wraps the default http.HandleFunc to handle an 14 // error as the return value. 15 type ErrorHandler func(w http.ResponseWriter, r *http.Request) error 16 17 func (h ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 18 if err := h(w, r); err != nil { 19 log.Print(err) 20 } 21 } 22 23 // UserHandler wraps the default http.HandlerFunc to include 24 // the currently authenticated User in the method signature, 25 // in addition to handling an error as the return value. 26 type UserHandler func(w http.ResponseWriter, r *http.Request, user *User) error 27 28 func (h UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 29 user, err := readUser(r) 30 if err != nil { 31 redirectLogin(w, r) 32 return 33 } 34 35 if err = h(w, r, user); err != nil { 36 log.Print(err) 37 RenderError(w, err, http.StatusBadRequest) 38 } 39 } 40 41 // AdminHandler wraps the default http.HandlerFunc to include 42 // the currently authenticated User in the method signature, 43 // in addition to handling an error as the return value. It also 44 // verifies the user has Administrative privileges. 45 type AdminHandler func(w http.ResponseWriter, r *http.Request, user *User) error 46 47 func (h AdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 48 user, err := readUser(r) 49 if err != nil { 50 redirectLogin(w, r) 51 return 52 } 53 54 // User MUST have administrative privileges in order 55 // to execute the handler. 56 if user.Admin == false { 57 RenderNotFound(w) 58 return 59 } 60 61 if err = h(w, r, user); err != nil { 62 log.Print(err) 63 RenderError(w, err, http.StatusBadRequest) 64 } 65 } 66 67 // RepoHandler wraps the default http.HandlerFunc to include 68 // the currently authenticated User and requested Repository 69 // in the method signature, in addition to handling an error 70 // as the return value. 71 type RepoHandler func(w http.ResponseWriter, r *http.Request, user *User, repo *Repo) error 72 73 func (h RepoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 74 75 // repository name from the URL parameters 76 hostParam := r.FormValue(":host") 77 userParam := r.FormValue(":owner") 78 nameParam := r.FormValue(":name") 79 repoName := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam) 80 81 repo, err := database.GetRepoSlug(repoName) 82 if err != nil || repo == nil { 83 RenderNotFound(w) 84 return 85 } 86 87 // retrieve the user from the database 88 user, err := readUser(r) 89 90 // if the user is not found, we can still 91 // serve the page assuming the repository 92 // is public. 93 switch { 94 case err != nil && repo.Private == true: 95 redirectLogin(w, r) 96 return 97 case err != nil && repo.Private == false: 98 h(w, r, nil, repo) 99 return 100 } 101 102 // The User must own the repository OR be a member 103 // of the Team that owns the repository OR the repo 104 // must not be private. 105 if repo.Private && user.ID != repo.UserID { 106 if member, _ := database.IsMember(user.ID, repo.TeamID); !member { 107 RenderNotFound(w) 108 return 109 } 110 } 111 112 if err = h(w, r, user, repo); err != nil { 113 log.Print(err) 114 RenderError(w, err, http.StatusBadRequest) 115 } 116 } 117 118 // RepoHandler wraps the default http.HandlerFunc to include 119 // the currently authenticated User and requested Repository 120 // in the method signature, in addition to handling an error 121 // as the return value. 122 type RepoAdminHandler func(w http.ResponseWriter, r *http.Request, user *User, repo *Repo) error 123 124 func (h RepoAdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 125 user, err := readUser(r) 126 if err != nil { 127 redirectLogin(w, r) 128 return 129 } 130 131 // repository name from the URL parameters 132 hostParam := r.FormValue(":host") 133 userParam := r.FormValue(":owner") 134 nameParam := r.FormValue(":name") 135 repoName := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam) 136 137 repo, err := database.GetRepoSlug(repoName) 138 if err != nil { 139 RenderNotFound(w) 140 return 141 } 142 143 // The User must own the repository OR be a member 144 // of the Team that owns the repository. 145 if admin, _ := database.IsRepoAdmin(user, repo); admin == false { 146 RenderNotFound(w) 147 return 148 } 149 150 if err = h(w, r, user, repo); err != nil { 151 log.Print(err) 152 RenderError(w, err, http.StatusBadRequest) 153 } 154 } 155 156 // helper function that reads the currently authenticated 157 // user from the given http.Request. 158 func readUser(r *http.Request) (*User, error) { 159 username := GetCookie(r, "_sess") 160 if len(username) == 0 { 161 return nil, fmt.Errorf("No user session") 162 } 163 164 // get the user from the database 165 user, err := database.GetUserEmail(username) 166 if err != nil || user == nil || user.ID == 0 { 167 return nil, err 168 } 169 170 return user, nil 171 } 172 173 // helper function that retrieves the repository based 174 // on the URL parameters 175 func readRepo(r *http.Request) (*Repo, error) { 176 // get the repo data from the URL parameters 177 hostParam := r.FormValue(":host") 178 userParam := r.FormValue(":owner") 179 nameParam := r.FormValue(":slug") 180 repoSlug := fmt.Sprintf("%s/%s/%s", hostParam, userParam, nameParam) 181 182 // get the repo from the database 183 return database.GetRepoSlug(repoSlug) 184 } 185 186 // helper function that sends the user to the login page. 187 func redirectLogin(w http.ResponseWriter, r *http.Request) { 188 v := url.Values{} 189 v.Add("return_to", r.URL.String()) 190 http.Redirect(w, r, "/login?"+v.Encode(), http.StatusSeeOther) 191 } 192 193 func renderNotFound(w http.ResponseWriter, r *http.Request) { 194 w.WriteHeader(http.StatusNotFound) 195 RenderTemplate(w, "404.amber", nil) 196 } 197 198 func renderBadRequest(w http.ResponseWriter, r *http.Request) { 199 w.WriteHeader(http.StatusBadRequest) 200 RenderTemplate(w, "500.amber", nil) 201 }