diff --git a/pixelapi/pixelapi.go b/pixelapi/pixelapi.go index 4874b16..ab2ca91 100644 --- a/pixelapi/pixelapi.go +++ b/pixelapi/pixelapi.go @@ -44,7 +44,8 @@ func (e Error) Error() string { return e.Value } // SuccessResponse is a generic response the API returns when the action was // successful and there is nothing interesting to report type SuccessResponse struct { - Success bool `json:"success"` + Success bool `json:"success"` + Message string `json:"message"` } func (p *PixelAPI) jsonRequest(method, url string, target interface{}) error { @@ -72,7 +73,7 @@ func (p *PixelAPI) jsonRequest(method, url string, target interface{}) error { } defer resp.Body.Close() - return parseJSONResponse(resp, target) + return parseJSONResponse(resp, target, true) } func (p *PixelAPI) getString(url string) (string, error) { @@ -84,8 +85,6 @@ func (p *PixelAPI) getString(url string) (string, error) { req.SetBasicAuth("", p.apiKey) } - client := &http.Client{} - resp, err := client.Do(req) if err != nil { return "", err @@ -115,10 +114,16 @@ func (p *PixelAPI) getRaw(url string) (io.ReadCloser, error) { return resp.Body, err } -func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) error { - req, err := http.NewRequest("POST", url, strings.NewReader(vals.Encode())) +func (p *PixelAPI) form( + method string, + url string, + vals url.Values, + target interface{}, + catchErrors bool, +) error { + req, err := http.NewRequest(method, url, strings.NewReader(vals.Encode())) if err != nil { - return &Error{ + return Error{ ReqError: true, Success: false, Value: err.Error(), @@ -129,9 +134,11 @@ func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) err req.SetBasicAuth("", p.apiKey) } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + resp, err := client.Do(req) if err != nil { - return &Error{ + return Error{ ReqError: true, Success: false, Value: err.Error(), @@ -140,22 +147,22 @@ func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) err } defer resp.Body.Close() - return parseJSONResponse(resp, target) + return parseJSONResponse(resp, target, catchErrors) } -func parseJSONResponse(resp *http.Response, target interface{}) error { +func parseJSONResponse(resp *http.Response, target interface{}, catchErrors bool) error { var jdec = json.NewDecoder(resp.Body) var err error // Test for client side and server side errors - if resp.StatusCode >= 400 { - var errResp = &Error{ + if catchErrors && resp.StatusCode >= 400 { + var errResp = Error{ ReqError: false, } err = jdec.Decode(&errResp) if err != nil { log.Error("Can't decode this: %v", err) - return &Error{ + return Error{ ReqError: true, Success: false, Value: err.Error(), @@ -169,7 +176,7 @@ func parseJSONResponse(resp *http.Response, target interface{}) error { if err != nil { r, _ := ioutil.ReadAll(resp.Body) log.Error("Can't decode this: %v. %s", err, r) - return &Error{ + return Error{ ReqError: true, Success: false, Value: err.Error(), diff --git a/pixelapi/user.go b/pixelapi/user.go index d08e23a..7df6bd4 100644 --- a/pixelapi/user.go +++ b/pixelapi/user.go @@ -5,22 +5,24 @@ import ( "net/url" ) +// Registration is the response to the UserRegister API. The register API can +// return multiple errors, which will be stored in the Errors array. Check for +// len(Errors) == 0 to see if an error occurred type Registration struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Errors []RegistrationError `json:"errors,omitempty"` -} - -type RegistrationError struct { - Code string `json:"error_code"` - Message string `json:"message"` + Success bool `json:"success"` + Message string `json:"message,omitempty"` + Errors []Error `json:"errors,omitempty"` } // UserRegister registers a new user on the Pixeldrain server. username and -// password are always required. email is optional, but without it you will -// never be able to reset your password in case you forget it. captcha depends -// on whether reCaptcha is enabled on the Pixeldrain server, this can be checked +// password are always required. email is optional, but without it you will not +// be able to reset your password in case you forget it. captcha depends on +// whether reCaptcha is enabled on the Pixeldrain server, this can be checked // through the GetRecaptcha function. +// +// The register API can return multiple errors, which will be stored in the +// Errors array. Check for len(Errors) == 0 to see if an error occurred. If err +// != nil it means a connection error occurred func (p *PixelAPI) UserRegister(username, email, password, captcha string) (resp *Registration, err error) { resp = &Registration{} var form = url.Values{} @@ -28,13 +30,38 @@ func (p *PixelAPI) UserRegister(username, email, password, captcha string) (resp form.Add("email", email) form.Add("password", password) form.Add("recaptcha_response", captcha) - err = p.postForm(p.apiEndpoint+"/user/register", form, resp) + err = p.form("POST", p.apiEndpoint+"/user/register", form, resp, false) if err != nil { return nil, err } return resp, nil } +// Login is the success response to the `user/login` API +type Login struct { + Success bool `json:"success"` + APIKey string `json:"api_key"` +} + +// UserLogin logs a user in with the provided credentials. The response will +// contain the returned API key. If saveKey is true the API key will also be +// saved in the client and following requests with this client will be +// autenticated +func (p *PixelAPI) UserLogin(username, password string, saveKey bool) (resp *Login, err error) { + resp = &Login{} + var form = url.Values{} + form.Add("username", username) + form.Add("password", password) + err = p.form("POST", p.apiEndpoint+"/user/login", form, resp, true) + if err != nil { + return nil, err + } + if saveKey { + p.apiKey = resp.APIKey + } + return resp, nil +} + // UserInfo contains information about the logged in user type UserInfo struct { Success bool `json:"success"` @@ -97,3 +124,15 @@ func (p *PixelAPI) UserLists(page, limit int) (resp *UserLists, err error) { } return resp, nil } + +func (p *PixelAPI) UserPasswordSet(oldPW, newPW string) (resp *SuccessResponse, err error) { + resp = &SuccessResponse{} + var form = url.Values{} + form.Add("old_password", oldPW) + form.Add("new_password", newPW) + err = p.form("PUT", p.apiEndpoint+"/user/password", form, resp, true) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/res/template/account/user_home.html b/res/template/account/user_home.html index db769a0..e7a7edd 100644 --- a/res/template/account/user_home.html +++ b/res/template/account/user_home.html @@ -11,6 +11,14 @@ {{template "menu" .}}
What would you like to do?
+ {{template "footer"}}Welcome to the club!
"), } - err := wc.templates.Get().ExecuteTemplate(w, "form_page", td) - if err != nil { - log.Error("Error executing template '%s': %s", "register", err) - } + if f.ReadInput(r) { + if f.FieldVal("password1") != f.FieldVal("password2") { + f.SubmitMessages = []template.HTML{ + "Password verification failed. Please enter the same " + + "password in both password fields"} + return f + } + resp, err := td.PixelAPI.UserRegister( + f.FieldVal("username"), + f.FieldVal("e-mail"), + f.FieldVal("password1"), + f.FieldVal("recaptcha_response"), + ) + if err != nil { + if apiErr, ok := err.(pixelapi.Error); ok { + f.SubmitMessages = []template.HTML{template.HTML(apiErr.Message)} + } else { + log.Error("%s", err) + f.SubmitMessages = []template.HTML{"Internal Server Error"} + } + } else if len(resp.Errors) != 0 { + // Registration errors occurred + for _, rerr := range resp.Errors { + f.SubmitMessages = append(f.SubmitMessages, template.HTML(rerr.Message)) + } + } else { + // Request was a success + f.SubmitSuccess = true + f.SubmitMessages = []template.HTML{ + `Registration completed! You can now log in ` + + `to your account.