Merge branch 'easy-forms'
This commit is contained in:
@@ -44,7 +44,8 @@ func (e Error) Error() string { return e.Value }
|
|||||||
// SuccessResponse is a generic response the API returns when the action was
|
// SuccessResponse is a generic response the API returns when the action was
|
||||||
// successful and there is nothing interesting to report
|
// successful and there is nothing interesting to report
|
||||||
type SuccessResponse struct {
|
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 {
|
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()
|
defer resp.Body.Close()
|
||||||
return parseJSONResponse(resp, target)
|
return parseJSONResponse(resp, target, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PixelAPI) getString(url string) (string, error) {
|
func (p *PixelAPI) getString(url string) (string, error) {
|
||||||
@@ -84,8 +85,6 @@ func (p *PixelAPI) getString(url string) (string, error) {
|
|||||||
req.SetBasicAuth("", p.apiKey)
|
req.SetBasicAuth("", p.apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{}
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -115,10 +114,16 @@ func (p *PixelAPI) getRaw(url string) (io.ReadCloser, error) {
|
|||||||
return resp.Body, err
|
return resp.Body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) error {
|
func (p *PixelAPI) form(
|
||||||
req, err := http.NewRequest("POST", url, strings.NewReader(vals.Encode()))
|
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 {
|
if err != nil {
|
||||||
return &Error{
|
return Error{
|
||||||
ReqError: true,
|
ReqError: true,
|
||||||
Success: false,
|
Success: false,
|
||||||
Value: err.Error(),
|
Value: err.Error(),
|
||||||
@@ -129,9 +134,11 @@ func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) err
|
|||||||
req.SetBasicAuth("", p.apiKey)
|
req.SetBasicAuth("", p.apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Error{
|
return Error{
|
||||||
ReqError: true,
|
ReqError: true,
|
||||||
Success: false,
|
Success: false,
|
||||||
Value: err.Error(),
|
Value: err.Error(),
|
||||||
@@ -140,22 +147,22 @@ func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
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 jdec = json.NewDecoder(resp.Body)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Test for client side and server side errors
|
// Test for client side and server side errors
|
||||||
if resp.StatusCode >= 400 {
|
if catchErrors && resp.StatusCode >= 400 {
|
||||||
var errResp = &Error{
|
var errResp = Error{
|
||||||
ReqError: false,
|
ReqError: false,
|
||||||
}
|
}
|
||||||
err = jdec.Decode(&errResp)
|
err = jdec.Decode(&errResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Can't decode this: %v", err)
|
log.Error("Can't decode this: %v", err)
|
||||||
return &Error{
|
return Error{
|
||||||
ReqError: true,
|
ReqError: true,
|
||||||
Success: false,
|
Success: false,
|
||||||
Value: err.Error(),
|
Value: err.Error(),
|
||||||
@@ -169,7 +176,7 @@ func parseJSONResponse(resp *http.Response, target interface{}) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
r, _ := ioutil.ReadAll(resp.Body)
|
r, _ := ioutil.ReadAll(resp.Body)
|
||||||
log.Error("Can't decode this: %v. %s", err, r)
|
log.Error("Can't decode this: %v. %s", err, r)
|
||||||
return &Error{
|
return Error{
|
||||||
ReqError: true,
|
ReqError: true,
|
||||||
Success: false,
|
Success: false,
|
||||||
Value: err.Error(),
|
Value: err.Error(),
|
||||||
|
@@ -5,22 +5,24 @@ import (
|
|||||||
"net/url"
|
"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 {
|
type Registration struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Errors []RegistrationError `json:"errors,omitempty"`
|
Errors []Error `json:"errors,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
type RegistrationError struct {
|
|
||||||
Code string `json:"error_code"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserRegister registers a new user on the Pixeldrain server. username and
|
// UserRegister registers a new user on the Pixeldrain server. username and
|
||||||
// password are always required. email is optional, but without it you will
|
// password are always required. email is optional, but without it you will not
|
||||||
// never be able to reset your password in case you forget it. captcha depends
|
// be able to reset your password in case you forget it. captcha depends on
|
||||||
// on whether reCaptcha is enabled on the Pixeldrain server, this can be checked
|
// whether reCaptcha is enabled on the Pixeldrain server, this can be checked
|
||||||
// through the GetRecaptcha function.
|
// 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) {
|
func (p *PixelAPI) UserRegister(username, email, password, captcha string) (resp *Registration, err error) {
|
||||||
resp = &Registration{}
|
resp = &Registration{}
|
||||||
var form = url.Values{}
|
var form = url.Values{}
|
||||||
@@ -28,13 +30,38 @@ func (p *PixelAPI) UserRegister(username, email, password, captcha string) (resp
|
|||||||
form.Add("email", email)
|
form.Add("email", email)
|
||||||
form.Add("password", password)
|
form.Add("password", password)
|
||||||
form.Add("recaptcha_response", captcha)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp, nil
|
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
|
// UserInfo contains information about the logged in user
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
@@ -97,3 +124,15 @@ func (p *PixelAPI) UserLists(page, limit int) (resp *UserLists, err error) {
|
|||||||
}
|
}
|
||||||
return resp, nil
|
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
|
||||||
|
}
|
||||||
|
@@ -103,7 +103,7 @@ body{
|
|||||||
font-family: "Lato Thin", sans-serif;
|
font-family: "Lato Thin", sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.8em;
|
font-size: 1.8em;
|
||||||
transition: box-shadow 2s;
|
transition: box-shadow 5s;
|
||||||
}
|
}
|
||||||
.navigation a:hover {
|
.navigation a:hover {
|
||||||
background: linear-gradient(var(--highlight_color), var(--highlight_color_dark));
|
background: linear-gradient(var(--highlight_color), var(--highlight_color_dark));
|
||||||
|
@@ -1,69 +0,0 @@
|
|||||||
{{define "login"}}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
{{template "meta_tags" "Login"}}
|
|
||||||
{{template "user_style" .}}
|
|
||||||
<script type="text/javascript">var apiEndpoint = '{{.APIEndpoint}}';</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id='body' class="body">
|
|
||||||
{{template "menu" .}}
|
|
||||||
|
|
||||||
<h1>Log in to your PixelDrain account</h1>
|
|
||||||
<div id="submit_result"></div>
|
|
||||||
<form onSubmit="return submitForm();" class="highlight_dark border_top border_bottom">
|
|
||||||
<table class="form">
|
|
||||||
<tr class="form">
|
|
||||||
<td>Username / e-mail</td>
|
|
||||||
<td><input id="username" name="username" type="text" autocomplete="username" value="" class="form_input"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="form">
|
|
||||||
<td>Password</td>
|
|
||||||
<td><input id="password" name="password" type="password" autocomplete="current-password" class="form_input"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="form">
|
|
||||||
<td colspan=2 style="text-align: right;"><input type="submit" value="Login" class="button_highlight"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
<br/>
|
|
||||||
If you don't have a PixelDrain account yet, you can <a href="/register">register here</a>. No e-mail address is required.<br/>
|
|
||||||
{{template "footer"}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
function submitForm(){
|
|
||||||
var req = new XMLHttpRequest();
|
|
||||||
req.onreadystatechange = function(){
|
|
||||||
if (this.readyState === 4) {
|
|
||||||
var response = JSON.parse(req.responseText);
|
|
||||||
var resultDiv = document.getElementById("submit_result");
|
|
||||||
if (response.success) {
|
|
||||||
resultDiv.className = "border_top border_bottom highlight_green";
|
|
||||||
resultDiv.innerHTML = 'Success! Proceeding to user portal...<br/>'
|
|
||||||
+'<a href="/user">Click here if you are not redirected automatically</a>';
|
|
||||||
window.location.href = "/user";
|
|
||||||
} else {
|
|
||||||
resultDiv.className = "border_top border_bottom highlight_red";
|
|
||||||
resultDiv.innerHTML = response.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = new FormData();
|
|
||||||
data.append("username", document.getElementById("username").value);
|
|
||||||
data.append("password", document.getElementById("password").value);
|
|
||||||
|
|
||||||
req.open("POST", apiEndpoint+"/user/login", true);
|
|
||||||
req.send(data);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{{template "analytics"}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
{{end}}
|
|
@@ -8,18 +8,18 @@
|
|||||||
<div id='body' class="body">
|
<div id='body' class="body">
|
||||||
{{template "menu" .}}
|
{{template "menu" .}}
|
||||||
|
|
||||||
<h1>Please confirm that you want to log out of your Pixeldrain account</h1>
|
<h1>Please confirm that you want to log out of your pixeldrain account</h1>
|
||||||
<form method="POST" action="/logout" class="highlight_light border_top border_bottom">
|
<form method="POST" action="/logout" class="highlight_light border_top border_bottom">
|
||||||
<input type="submit" value="I want to log out of pixeldrain on this computer" class="button_highlight"/>
|
<input type="submit" value="I want to log out of pixeldrain on this computer" class="button_highlight"/>
|
||||||
</form>
|
</form>
|
||||||
<br/>
|
<br/>
|
||||||
<h2>Why do I need to confirm my logout?</h2>
|
<h2>Why do I need to confirm my logout?</h2>
|
||||||
<p>
|
<p>
|
||||||
We need you to confirm your action here so we can be sure that
|
We need you to confirm your action so we can be sure that you
|
||||||
you really requested a logout. If we didn't do this, anyone (or
|
really requested a logout. If we didn't do this, anyone (or any
|
||||||
any website) would be able to send you to this page and you
|
website) would be able to send you to this page and you would
|
||||||
would automatically get logged out of Pixeldrain, which would be
|
automatically get logged out of pixeldrain, which would be very
|
||||||
very annoying.
|
annoying.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
To prevent this from happening we're verifying that you actually
|
To prevent this from happening we're verifying that you actually
|
||||||
|
@@ -11,6 +11,13 @@
|
|||||||
{{template "menu" .}}
|
{{template "menu" .}}
|
||||||
|
|
||||||
<h1 class="highlight_middle border_bottom">Welcome home, {{.Username}}!</h1>
|
<h1 class="highlight_middle border_bottom">Welcome home, {{.Username}}!</h1>
|
||||||
|
|
||||||
|
<h2>Actions</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/user/change_password">Change my password</a></li>
|
||||||
|
<li><a href="/logout">Log out</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2>Your most recently uploaded files:</h2>
|
<h2>Your most recently uploaded files:</h2>
|
||||||
<div class="highlight_dark border_top border_bottom">
|
<div class="highlight_dark border_top border_bottom">
|
||||||
{{$files := .PixelAPI.UserFiles 0 18}}
|
{{$files := .PixelAPI.UserFiles 0 18}}
|
||||||
|
@@ -10,8 +10,10 @@
|
|||||||
<div id='body' class="body">
|
<div id='body' class="body">
|
||||||
{{template "menu" .}}
|
{{template "menu" .}}
|
||||||
<h1>User configuration</h1>
|
<h1>User configuration</h1>
|
||||||
|
<p>What would you like to do?</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/user/change_password">Change my password</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
{{template "footer"}}
|
{{template "footer"}}
|
||||||
</div>
|
</div>
|
||||||
|
21
res/template/admin.html
Normal file
21
res/template/admin.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{{define "widgets"}}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{{template "meta_tags" "Administrator panel"}}
|
||||||
|
{{template "user_style" .}}
|
||||||
|
<script type="text/javascript">var apiEndpoint = '{{.APIEndpoint}}';</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img id="header_image" class="header_image" src="/res/img/header_neuropol.png" alt="Header image"/>
|
||||||
|
<br/>
|
||||||
|
<div id="body" class="body">
|
||||||
|
{{template "menu" .}}
|
||||||
|
|
||||||
|
<h1>System statistics</h1>
|
||||||
|
|
||||||
|
{{template "footer"}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{end}}
|
106
res/template/fragments/form.html
Normal file
106
res/template/fragments/form.html
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{{define "form"}}
|
||||||
|
<h1>{{.Title}}</h1>
|
||||||
|
{{.PreFormHTML}}
|
||||||
|
{{if eq .Submitted true}}
|
||||||
|
{{if eq .SubmitSuccess true}}
|
||||||
|
<div id="submit_result" class="highlight_green border_top border_bottom">
|
||||||
|
{{index .SubmitMessages 0}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div id="submit_result" class="highlight_red border_top border_bottom">
|
||||||
|
Something went wrong, please correct these errors before continuing:<br/>
|
||||||
|
<ul>
|
||||||
|
{{range $msg := .SubmitMessages}}
|
||||||
|
<li>{{$msg}}</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<form class="highlight_dark border_top border_bottom" method="POST">
|
||||||
|
<input type="text" name="form" value="{{.Name}}" style="display: none;" readonly="readonly"/>
|
||||||
|
{{if ne .Username ""}}
|
||||||
|
<!-- The invisible username field is so browsers know which user the form was for -->
|
||||||
|
<input type="text" autocomplete="username" value="{{.Username}}" style="display: none;" readonly="readonly"/>
|
||||||
|
{{end}}
|
||||||
|
<table style="margin-left: auto; margin-right: auto; text-align: left; max-width: 30em;">
|
||||||
|
{{range $index, $field := .Fields}}
|
||||||
|
<tr class="form">
|
||||||
|
<td>{{$field.Label}}</td>
|
||||||
|
<td>
|
||||||
|
{{if eq $field.Type "text"}}
|
||||||
|
<input id="input_{{$field.Name}}" name="{{$field.Name}}" value="{{$field.DefaultValue}}" type="text" class="form_input"/>
|
||||||
|
{{else if eq $field.Type "username"}}
|
||||||
|
<input id="input_{{$field.Name}}" name="{{$field.Name}}" value="{{$field.DefaultValue}}" type="text" autocomplete="username" class="form_input"/>
|
||||||
|
{{else if eq $field.Type "email"}}
|
||||||
|
<input id="input_{{$field.Name}}" name="{{$field.Name}}" value="{{$field.DefaultValue}}" type="email" autocomplete="email" class="form_input"/>
|
||||||
|
{{else if eq $field.Type "current-password"}}
|
||||||
|
<input id="input_{{$field.Name}}" name="{{$field.Name}}" value="{{$field.DefaultValue}}" type="password" autocomplete="current-password" class="form_input"/>
|
||||||
|
{{else if eq $field.Type "new-password"}}
|
||||||
|
<input id="input_{{$field.Name}}" name="{{$field.Name}}" value="{{$field.DefaultValue}}" type="password" autocomplete="new-password" class="form_input"/>
|
||||||
|
{{else if eq $field.Type "captcha"}}
|
||||||
|
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||||
|
<div class="g-recaptcha" data-theme="dark" data-sitekey="{{$field.CaptchaSiteKey}}"></div>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
{{if or (ne $field.Description "") (eq $field.Separator true)}}
|
||||||
|
<tr class="form">
|
||||||
|
<td colspan="2">
|
||||||
|
{{$field.Description}}
|
||||||
|
{{if eq $field.Separator true}}
|
||||||
|
<hr/>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
<tr class="form">
|
||||||
|
{{if eq .BackLink ""}}
|
||||||
|
<td colspan="2" style="text-align: right;">
|
||||||
|
{{if eq .SubmitRed true}}
|
||||||
|
<input type="submit" value="{{.SubmitLabel}}" class="button_red"/>
|
||||||
|
{{else}}
|
||||||
|
<input type="submit" value="{{.SubmitLabel}}" class="button_highlight"/>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
{{else}}
|
||||||
|
<td style="text-align: left;">
|
||||||
|
<a href="{{.BackLink}}" class="button button_red"/>Back</a>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: right;">
|
||||||
|
{{if eq .SubmitRed true}}
|
||||||
|
<input type="submit" value="{{.SubmitLabel}}" class="button_red"/>
|
||||||
|
{{else}}
|
||||||
|
<input type="submit" value="{{.SubmitLabel}}" class="button_highlight"/>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
{{end}}
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
{{.PostFormHTML}}
|
||||||
|
{{end}}
|
||||||
|
{{define "form_page"}}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{{template "meta_tags" .Title}}
|
||||||
|
{{template "user_style" .}}
|
||||||
|
<script type="text/javascript">var apiEndpoint = '{{.APIEndpoint}}';</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id='body' class="body">
|
||||||
|
{{template "menu" .}}
|
||||||
|
|
||||||
|
{{template "form" .Form}}
|
||||||
|
|
||||||
|
{{template "footer"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "analytics"}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{end}}
|
127
webcontroller/forms/form.go
Normal file
127
webcontroller/forms/form.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Form is a form which can be rendered in HTML and submitted
|
||||||
|
type Form struct {
|
||||||
|
// Name of the form. When this form is submitted this name will be in the `form` parameter
|
||||||
|
Name string
|
||||||
|
|
||||||
|
Title string // Shown in a large font above the form
|
||||||
|
PreFormHTML template.HTML // Content to be rendered above the form
|
||||||
|
|
||||||
|
Fields []Field
|
||||||
|
|
||||||
|
BackLink string // Empty for no back link
|
||||||
|
SubmitLabel string // Label for the submit button
|
||||||
|
SubmitRed bool // If the submit button should be red or green
|
||||||
|
|
||||||
|
PostFormHTML template.HTML // Content to be rendered below the form
|
||||||
|
|
||||||
|
// Fields to render if the form has been submitted once
|
||||||
|
Submitted bool // If the form has been submitted
|
||||||
|
SubmitSuccess bool // If the submission was a success
|
||||||
|
SubmitMessages []template.HTML // Messages telling the user the results
|
||||||
|
|
||||||
|
// Used for letting the browser know which user is logged in
|
||||||
|
Username string
|
||||||
|
|
||||||
|
// Actions to perform when the form is rendered
|
||||||
|
Extra ExtraActions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field is a single input field in a form
|
||||||
|
type Field struct {
|
||||||
|
// Used for reading the data. Entered data is POSTed back to the same URL with this name
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Is entered in the input field by default. If this is empty when running
|
||||||
|
// Form.ReadInput() it will be set to the value entered by the user
|
||||||
|
DefaultValue string
|
||||||
|
|
||||||
|
// The value entered by the user. Filled in when running Form.ReadInput()
|
||||||
|
EnteredValue string
|
||||||
|
|
||||||
|
// Text next to the input field
|
||||||
|
Label string
|
||||||
|
|
||||||
|
// Text below the input field
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// Separates fields with a horizontal rule
|
||||||
|
Separator bool
|
||||||
|
|
||||||
|
Type FieldType
|
||||||
|
|
||||||
|
// Only used when Type == FieldTypeCaptcha
|
||||||
|
CaptchaSiteKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtraActions contains extra actions to performs when rendering the form
|
||||||
|
type ExtraActions struct {
|
||||||
|
// Redirects the browser to a different URL with a HTTP 303: See Other
|
||||||
|
// status. This is useful for redirecting the user to a different page if
|
||||||
|
// the form submission was successful
|
||||||
|
RedirectTo string
|
||||||
|
|
||||||
|
// A cookie to install in the browser when the form is rendered. Useful for
|
||||||
|
// setting / destroying user sessions or configurations
|
||||||
|
SetCookie *http.Cookie
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldType defines the type a form field has and how it should be rendered
|
||||||
|
type FieldType string
|
||||||
|
|
||||||
|
// Fields which can be in a form
|
||||||
|
const (
|
||||||
|
FieldTypeText FieldType = "text"
|
||||||
|
FieldTypeUsername FieldType = "username"
|
||||||
|
FieldTypeEmail FieldType = "email"
|
||||||
|
FieldTypeCurrentPassword FieldType = "current-password"
|
||||||
|
FieldTypeNewPassword FieldType = "new-password"
|
||||||
|
FieldTypeCaptcha FieldType = "captcha"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadInput reads the form of a request and fills in the values for each field.
|
||||||
|
// The return value will be true if this form was submitted and false if the
|
||||||
|
// form was not submitted
|
||||||
|
func (f *Form) ReadInput(r *http.Request) (success bool) {
|
||||||
|
if r.FormValue("form") != f.Name {
|
||||||
|
f.Submitted = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.Submitted = true
|
||||||
|
|
||||||
|
for i, field := range f.Fields {
|
||||||
|
field.EnteredValue = r.FormValue(field.Name)
|
||||||
|
|
||||||
|
if field.DefaultValue == "" {
|
||||||
|
field.DefaultValue = field.EnteredValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.Type == FieldTypeCaptcha && field.EnteredValue == "" {
|
||||||
|
field.EnteredValue = r.FormValue("g-recaptcha-response")
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Fields[i] = field // Update the new values in the array
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldVal is a utility function for getting the entered value of a field by
|
||||||
|
// its name. By using this function you don't have to use nondescriptive array
|
||||||
|
// indexes to get the values. It panics if the field name is not found in the
|
||||||
|
// form
|
||||||
|
func (f *Form) FieldVal(name string) (enteredValue string) {
|
||||||
|
for _, field := range f.Fields {
|
||||||
|
if field.Name == name {
|
||||||
|
return field.EnteredValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Errorf("FieldVal called on unregistered field name '%s'", name))
|
||||||
|
}
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fornaxian.com/pixeldrain-web/pixelapi"
|
"fornaxian.com/pixeldrain-web/pixelapi"
|
||||||
|
"fornaxian.com/pixeldrain-web/webcontroller/forms"
|
||||||
"github.com/Fornaxian/log"
|
"github.com/Fornaxian/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,12 +20,15 @@ type TemplateData struct {
|
|||||||
APIEndpoint template.URL
|
APIEndpoint template.URL
|
||||||
PixelAPI *pixelapi.PixelAPI
|
PixelAPI *pixelapi.PixelAPI
|
||||||
|
|
||||||
Other interface{}
|
|
||||||
URLQuery url.Values
|
|
||||||
|
|
||||||
// Only used on file viewer page
|
// Only used on file viewer page
|
||||||
Title string
|
Title string
|
||||||
OGData OGData
|
OGData OGData
|
||||||
|
|
||||||
|
Other interface{}
|
||||||
|
URLQuery url.Values
|
||||||
|
|
||||||
|
// Only used for pages containing forms
|
||||||
|
Form forms.Form
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request) *TemplateData {
|
func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request) *TemplateData {
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package webcontroller
|
package webcontroller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"fornaxian.com/pixeldrain-web/pixelapi"
|
"fornaxian.com/pixeldrain-web/pixelapi"
|
||||||
|
"fornaxian.com/pixeldrain-web/webcontroller/forms"
|
||||||
"github.com/Fornaxian/log"
|
"github.com/Fornaxian/log"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
)
|
)
|
||||||
@@ -37,3 +40,213 @@ func (wc *WebController) serveLogout(
|
|||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wc *WebController) registerForm(td *TemplateData, r *http.Request) (f forms.Form) {
|
||||||
|
// This only runs on the first request
|
||||||
|
if wc.captchaSiteKey == "" {
|
||||||
|
capt, err := td.PixelAPI.GetRecaptcha()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error getting recaptcha key: %s", err)
|
||||||
|
f.SubmitMessages = []template.HTML{
|
||||||
|
"An internal server error had occurred. Registration is " +
|
||||||
|
"unavailable at the moment. Please return later",
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
if capt.SiteKey == "" {
|
||||||
|
wc.captchaSiteKey = "none"
|
||||||
|
} else {
|
||||||
|
wc.captchaSiteKey = capt.SiteKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the form
|
||||||
|
td.Title = "Register a new Pixeldrain account"
|
||||||
|
f = forms.Form{
|
||||||
|
Name: "register",
|
||||||
|
Title: td.Title,
|
||||||
|
Fields: []forms.Field{
|
||||||
|
{
|
||||||
|
Name: "username",
|
||||||
|
Label: "Username",
|
||||||
|
Description: "used for logging into your account",
|
||||||
|
Separator: true,
|
||||||
|
Type: forms.FieldTypeUsername,
|
||||||
|
}, {
|
||||||
|
Name: "e-mail",
|
||||||
|
Label: "E-mail address",
|
||||||
|
Description: "not required. your e-mail address will only be " +
|
||||||
|
"used for password resets and important account " +
|
||||||
|
"notifications",
|
||||||
|
Separator: true,
|
||||||
|
Type: forms.FieldTypeEmail,
|
||||||
|
}, {
|
||||||
|
Name: "password1",
|
||||||
|
Label: "Password",
|
||||||
|
Type: forms.FieldTypeNewPassword,
|
||||||
|
}, {
|
||||||
|
Name: "password2",
|
||||||
|
Label: "Password verification",
|
||||||
|
Description: "you need to enter your password twice so we " +
|
||||||
|
"can verify that no typing errors were made, which would " +
|
||||||
|
"prevent you from logging into your new account",
|
||||||
|
Separator: true,
|
||||||
|
Type: forms.FieldTypeNewPassword,
|
||||||
|
}, {
|
||||||
|
Name: "recaptcha_response",
|
||||||
|
Label: "Turing test (click the white box)",
|
||||||
|
Description: "the reCaptcha turing test verifies that you " +
|
||||||
|
"are not an evil robot that is trying to flood the " +
|
||||||
|
"website with fake accounts",
|
||||||
|
Separator: true,
|
||||||
|
Type: forms.FieldTypeCaptcha,
|
||||||
|
CaptchaSiteKey: wc.captchaKey(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BackLink: "/",
|
||||||
|
SubmitLabel: "Register",
|
||||||
|
PostFormHTML: template.HTML("<p>Welcome to the club!</p>"),
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
log.Debug("capt: %s", f.FieldVal("recaptcha_response"))
|
||||||
|
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 <a href="/login">log in ` +
|
||||||
|
`to your account</a>.<br/>We're glad to have you on ` +
|
||||||
|
`board, have fun sharing!`}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wc *WebController) loginForm(td *TemplateData, r *http.Request) (f forms.Form) {
|
||||||
|
td.Title = "Login"
|
||||||
|
f = forms.Form{
|
||||||
|
Name: "login",
|
||||||
|
Title: "Log in to your pixeldrain account",
|
||||||
|
Fields: []forms.Field{
|
||||||
|
{
|
||||||
|
Name: "username",
|
||||||
|
Label: "Username / e-mail",
|
||||||
|
Type: forms.FieldTypeUsername,
|
||||||
|
}, {
|
||||||
|
Name: "password",
|
||||||
|
Label: "Password",
|
||||||
|
Type: forms.FieldTypeCurrentPassword,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BackLink: "/",
|
||||||
|
SubmitLabel: "Login",
|
||||||
|
PostFormHTML: template.HTML(
|
||||||
|
`<br/>If you don't have a pixeldrain account yet, you can ` +
|
||||||
|
`<a href="/register">register here</a>. No e-mail address is ` +
|
||||||
|
`required.<br/>`,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.ReadInput(r) {
|
||||||
|
loginResp, err := td.PixelAPI.UserLogin(f.FieldVal("username"), f.FieldVal("password"), false)
|
||||||
|
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 {
|
||||||
|
log.Debug("key %s", loginResp.APIKey)
|
||||||
|
// Request was a success
|
||||||
|
f.SubmitSuccess = true
|
||||||
|
f.SubmitMessages = []template.HTML{"Success!"}
|
||||||
|
f.Extra.SetCookie = &http.Cookie{
|
||||||
|
Name: "pd_auth_key",
|
||||||
|
Value: loginResp.APIKey,
|
||||||
|
Path: "/",
|
||||||
|
Expires: time.Now().AddDate(50, 0, 0),
|
||||||
|
}
|
||||||
|
f.Extra.RedirectTo = "/user"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wc *WebController) passwordForm(td *TemplateData, r *http.Request) (f forms.Form) {
|
||||||
|
td.Title = "Change Password"
|
||||||
|
f = forms.Form{
|
||||||
|
Name: "password_change",
|
||||||
|
Title: td.Title,
|
||||||
|
Fields: []forms.Field{
|
||||||
|
{
|
||||||
|
Name: "old_password",
|
||||||
|
Label: "Old Password",
|
||||||
|
Type: forms.FieldTypeCurrentPassword,
|
||||||
|
}, {
|
||||||
|
Name: "new_password1",
|
||||||
|
Label: "New Password",
|
||||||
|
Type: forms.FieldTypeNewPassword,
|
||||||
|
}, {
|
||||||
|
Name: "new_password2",
|
||||||
|
Label: "New Password verification",
|
||||||
|
Type: forms.FieldTypeCurrentPassword,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BackLink: "/user",
|
||||||
|
SubmitLabel: "Submit",
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.ReadInput(r) {
|
||||||
|
if f.FieldVal("new_password1") != f.FieldVal("new_password2") {
|
||||||
|
f.SubmitMessages = []template.HTML{
|
||||||
|
"Password verification failed. Please enter the same " +
|
||||||
|
"password in both new password fields"}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passwords match, send the request and fill in the response in the
|
||||||
|
// form
|
||||||
|
_, err := td.PixelAPI.UserPasswordSet(
|
||||||
|
f.FieldVal("old_password"),
|
||||||
|
f.FieldVal("new_password1"),
|
||||||
|
)
|
||||||
|
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 {
|
||||||
|
// Request was a success
|
||||||
|
f.SubmitSuccess = true
|
||||||
|
f.SubmitMessages = []template.HTML{"Success! Your password has been updated"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"fornaxian.com/pixeldrain-web/init/conf"
|
"fornaxian.com/pixeldrain-web/init/conf"
|
||||||
"fornaxian.com/pixeldrain-web/pixelapi"
|
"fornaxian.com/pixeldrain-web/pixelapi"
|
||||||
|
"fornaxian.com/pixeldrain-web/webcontroller/forms"
|
||||||
"github.com/Fornaxian/log"
|
"github.com/Fornaxian/log"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
)
|
)
|
||||||
@@ -48,20 +49,24 @@ func New(r *httprouter.Router, prefix string, conf *conf.PixelWebConfig) *WebCon
|
|||||||
})
|
})
|
||||||
|
|
||||||
// General navigation
|
// General navigation
|
||||||
r.GET(p+"/" /* */, wc.serveTemplate("home", false))
|
r.GET(p+"/" /* */, wc.serveTemplate("home", false))
|
||||||
r.GET(p+"/favicon.ico" /* */, wc.serveFile("/favicon.ico"))
|
r.GET(p+"/favicon.ico" /* */, wc.serveFile("/favicon.ico"))
|
||||||
r.GET(p+"/api" /* */, wc.serveTemplate("apidoc", false))
|
r.GET(p+"/api" /* */, wc.serveTemplate("apidoc", false))
|
||||||
r.GET(p+"/history" /* */, wc.serveTemplate("history_cookies", false))
|
r.GET(p+"/history" /* */, wc.serveTemplate("history_cookies", false))
|
||||||
r.GET(p+"/u/:id" /* */, wc.serveFileViewer)
|
r.GET(p+"/u/:id" /* */, wc.serveFileViewer)
|
||||||
r.GET(p+"/u/:id/preview" /* */, wc.serveFilePreview)
|
r.GET(p+"/u/:id/preview" /**/, wc.serveFilePreview)
|
||||||
r.GET(p+"/l/:id" /* */, wc.serveListViewer)
|
r.GET(p+"/l/:id" /* */, wc.serveListViewer)
|
||||||
r.GET(p+"/t" /* */, wc.serveTemplate("paste", false))
|
r.GET(p+"/t" /* */, wc.serveTemplate("paste", false))
|
||||||
r.GET(p+"/donation" /* */, wc.serveTemplate("donation", false))
|
r.GET(p+"/donation" /* */, wc.serveTemplate("donation", false))
|
||||||
r.GET(p+"/widgets" /* */, wc.serveTemplate("widgets", false))
|
r.GET(p+"/widgets" /* */, wc.serveTemplate("widgets", false))
|
||||||
|
|
||||||
// User account pages
|
// User account pages
|
||||||
r.GET(p+"/register" /* */, wc.serveRegister)
|
r.GET(p+"/register_old" /* */, wc.serveRegister)
|
||||||
r.GET(p+"/login" /* */, wc.serveTemplate("login", false))
|
r.GET(p+"/register" /* */, wc.serveForm(wc.registerForm, false))
|
||||||
|
r.POST(p+"/register" /* */, wc.serveForm(wc.registerForm, false))
|
||||||
|
r.GET(p+"/login" /* */, wc.serveForm(wc.loginForm, false))
|
||||||
|
r.POST(p+"/login" /* */, wc.serveForm(wc.loginForm, false))
|
||||||
|
// r.GET(p+"/login" /* */, wc.serveTemplate("login", false))
|
||||||
r.GET(p+"/logout" /* */, wc.serveTemplate("logout", true))
|
r.GET(p+"/logout" /* */, wc.serveTemplate("logout", true))
|
||||||
r.POST(p+"/logout" /* */, wc.serveLogout)
|
r.POST(p+"/logout" /* */, wc.serveLogout)
|
||||||
r.GET(p+"/user" /* */, wc.serveTemplate("user_home", true))
|
r.GET(p+"/user" /* */, wc.serveTemplate("user_home", true))
|
||||||
@@ -69,6 +74,11 @@ func New(r *httprouter.Router, prefix string, conf *conf.PixelWebConfig) *WebCon
|
|||||||
r.GET(p+"/user/lists" /* */, wc.serveTemplate("user_lists", true))
|
r.GET(p+"/user/lists" /* */, wc.serveTemplate("user_lists", true))
|
||||||
r.GET(p+"/user/filemanager" /**/, wc.serveTemplate("file_manager", true))
|
r.GET(p+"/user/filemanager" /**/, wc.serveTemplate("file_manager", true))
|
||||||
|
|
||||||
|
// User account settings
|
||||||
|
r.GET(p+"/user/settings" /* */, wc.serveTemplate("user_settings", true))
|
||||||
|
r.GET(p+"/user/change_password" /* */, wc.serveForm(wc.passwordForm, true))
|
||||||
|
r.POST(p+"/user/change_password" /**/, wc.serveForm(wc.passwordForm, true))
|
||||||
|
|
||||||
r.NotFound = http.HandlerFunc(wc.serveNotFound)
|
r.NotFound = http.HandlerFunc(wc.serveNotFound)
|
||||||
|
|
||||||
return wc
|
return wc
|
||||||
@@ -105,6 +115,66 @@ func (wc *WebController) serveFile(path string) httprouter.Handle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wc *WebController) serveForm(
|
||||||
|
handler func(*TemplateData, *http.Request) forms.Form,
|
||||||
|
requireAuth bool,
|
||||||
|
) httprouter.Handle {
|
||||||
|
return func(
|
||||||
|
w http.ResponseWriter,
|
||||||
|
r *http.Request,
|
||||||
|
p httprouter.Params,
|
||||||
|
) {
|
||||||
|
var td = wc.newTemplateData(w, r)
|
||||||
|
if requireAuth && !td.Authenticated {
|
||||||
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The handler retuns the form which will be rendered
|
||||||
|
td.Form = handler(td, r)
|
||||||
|
|
||||||
|
td.Form.Username = td.Username
|
||||||
|
|
||||||
|
// Execute the extra actions if any
|
||||||
|
if td.Form.Extra.SetCookie != nil {
|
||||||
|
http.SetCookie(w, td.Form.Extra.SetCookie)
|
||||||
|
}
|
||||||
|
if td.Form.Extra.RedirectTo != "" {
|
||||||
|
http.Redirect(w, r, td.Form.Extra.RedirectTo, http.StatusSeeOther)
|
||||||
|
log.Debug("redirect: %s", td.Form.Extra.RedirectTo)
|
||||||
|
return // Don't need to render a form if the user is redirected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the recaptcha field if captcha is disabled
|
||||||
|
if wc.captchaKey() == "none" {
|
||||||
|
for i, field := range td.Form.Fields {
|
||||||
|
if field.Type == forms.FieldTypeCaptcha {
|
||||||
|
td.Form.Fields = append(
|
||||||
|
td.Form.Fields[:i],
|
||||||
|
td.Form.Fields[i+1:]...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the entered values if the request was successful
|
||||||
|
if td.Form.SubmitSuccess {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
for i, field := range td.Form.Fields {
|
||||||
|
field.EnteredValue = ""
|
||||||
|
td.Form.Fields[i] = field
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := wc.templates.Get().ExecuteTemplate(w, "form_page", td)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error executing form page: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (wc *WebController) serveNotFound(w http.ResponseWriter, r *http.Request) {
|
func (wc *WebController) serveNotFound(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Debug("Not Found: %s", r.URL)
|
log.Debug("Not Found: %s", r.URL)
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
Reference in New Issue
Block a user