Move login screen to new forms framework

This commit is contained in:
2019-03-31 22:33:22 +02:00
parent e4e965516f
commit 86921e9b3b
7 changed files with 99 additions and 89 deletions

View File

@@ -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));

View File

@@ -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}}

View File

@@ -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

View File

@@ -12,11 +12,10 @@
<h1 class="highlight_middle border_bottom">Welcome home, {{.Username}}!</h1> <h1 class="highlight_middle border_bottom">Welcome home, {{.Username}}!</h1>
<!--<a href="/user/settings">Change user settings</a><br/>-->
<h2>Actions</h2> <h2>Actions</h2>
<ul> <ul>
<li><a href="/user/logout">Log out</a></li>
<li><a href="/user/change_password">Change my password</a></li> <li><a href="/user/change_password">Change my password</a></li>
<li><a href="/logout">Log out</a></li>
</ul> </ul>
<h2>Your most recently uploaded files:</h2> <h2>Your most recently uploaded files:</h2>

View File

@@ -29,6 +29,9 @@ type Form struct {
// Used for letting the browser know which user is logged in // Used for letting the browser know which user is logged in
Username string Username string
// Actions to perform when the form is rendered
Extra ExtraActions
} }
// Field is a single input field in a form // Field is a single input field in a form
@@ -54,11 +57,22 @@ type Field struct {
Type FieldType Type FieldType
// Only used when Type = `captcha`. When using reCaptcha the field name has // Only used when Type == FieldTypeCaptcha
// to be `recaptcha_response`
CaptchaSiteKey string 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 // FieldType defines the type a form field has and how it should be rendered
type FieldType string type FieldType string
@@ -82,15 +96,17 @@ func (f *Form) ReadInput(r *http.Request) (success bool) {
} }
f.Submitted = true f.Submitted = true
var val string
for i, field := range f.Fields { for i, field := range f.Fields {
val = r.FormValue(field.Name) field.EnteredValue = r.FormValue(field.Name)
field.EnteredValue = val
if field.DefaultValue == "" { if field.DefaultValue == "" {
field.DefaultValue = val 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 f.Fields[i] = field // Update the new values in the array
} }

View File

@@ -3,6 +3,7 @@ package webcontroller
import ( import (
"html/template" "html/template"
"net/http" "net/http"
"time"
"fornaxian.com/pixeldrain-web/pixelapi" "fornaxian.com/pixeldrain-web/pixelapi"
"fornaxian.com/pixeldrain-web/webcontroller/forms" "fornaxian.com/pixeldrain-web/webcontroller/forms"
@@ -99,7 +100,7 @@ func (wc *WebController) registerForm(td *TemplateData, r *http.Request) (f form
"website with fake accounts", "website with fake accounts",
Separator: true, Separator: true,
Type: forms.FieldTypeCaptcha, Type: forms.FieldTypeCaptcha,
CaptchaSiteKey: wc.captchaSiteKey, CaptchaSiteKey: wc.captchaKey(),
}, },
}, },
BackLink: "/", BackLink: "/",
@@ -114,7 +115,7 @@ func (wc *WebController) registerForm(td *TemplateData, r *http.Request) (f form
"password in both password fields"} "password in both password fields"}
return f return f
} }
log.Debug("capt: %s", f.FieldVal("recaptcha_response"))
resp, err := td.PixelAPI.UserRegister( resp, err := td.PixelAPI.UserRegister(
f.FieldVal("username"), f.FieldVal("username"),
f.FieldVal("e-mail"), f.FieldVal("e-mail"),
@@ -145,6 +146,57 @@ func (wc *WebController) registerForm(td *TemplateData, r *http.Request) (f form
return f 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) { func (wc *WebController) passwordForm(td *TemplateData, r *http.Request) (f forms.Form) {
td.Title = "Change Password" td.Title = "Change Password"
f = forms.Form{ f = forms.Form{

View File

@@ -64,7 +64,9 @@ func New(r *httprouter.Router, prefix string, conf *conf.PixelWebConfig) *WebCon
r.GET(p+"/register_old" /* */, wc.serveRegister) r.GET(p+"/register_old" /* */, wc.serveRegister)
r.GET(p+"/register" /* */, wc.serveForm(wc.registerForm, false)) r.GET(p+"/register" /* */, wc.serveForm(wc.registerForm, false))
r.POST(p+"/register" /* */, wc.serveForm(wc.registerForm, false)) r.POST(p+"/register" /* */, wc.serveForm(wc.registerForm, false))
r.GET(p+"/login" /* */, wc.serveTemplate("login", 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))
@@ -133,8 +135,18 @@ func (wc *WebController) serveForm(
td.Form.Username = td.Username 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 // Remove the recaptcha field if captcha is disabled
if wc.captchaSiteKey == "none" { if wc.captchaKey() == "none" {
for i, field := range td.Form.Fields { for i, field := range td.Form.Fields {
if field.Type == forms.FieldTypeCaptcha { if field.Type == forms.FieldTypeCaptcha {
td.Form.Fields = append( td.Form.Fields = append(