Signup page: check for username uniqueness
This commit is contained in:
parent
be0d401de8
commit
4d1a057a73
57
pkg/controller/api/username_check.go
Normal file
57
pkg/controller/api/username_check.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UsernameCheck API.
|
||||||
|
func UsernameCheck() http.HandlerFunc {
|
||||||
|
// Request JSON schema.
|
||||||
|
type Request struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response JSON schema.
|
||||||
|
type Response struct {
|
||||||
|
OK bool `json:"OK"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
SendJSON(w, http.StatusNotAcceptable, Response{
|
||||||
|
Error: "POST method only",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse request payload.
|
||||||
|
var req Request
|
||||||
|
if err := ParseJSON(r, &req); err != nil {
|
||||||
|
SendJSON(w, http.StatusBadRequest, Response{
|
||||||
|
Error: fmt.Sprintf("Error with request payload: %s", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Username to test.
|
||||||
|
var username = strings.TrimSpace(strings.ToLower(req.Username))
|
||||||
|
|
||||||
|
// Does it exist?
|
||||||
|
if _, err := models.FindUser(username); err == nil {
|
||||||
|
SendJSON(w, http.StatusOK, Response{
|
||||||
|
Error: "That username is already taken, please try another one.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send success response.
|
||||||
|
SendJSON(w, http.StatusOK, Response{
|
||||||
|
OK: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -93,6 +93,7 @@ func New() http.Handler {
|
||||||
// JSON API endpoints.
|
// JSON API endpoints.
|
||||||
mux.HandleFunc("/v1/version", api.Version())
|
mux.HandleFunc("/v1/version", api.Version())
|
||||||
mux.HandleFunc("/v1/users/me", api.LoginOK())
|
mux.HandleFunc("/v1/users/me", api.LoginOK())
|
||||||
|
mux.HandleFunc("/v1/users/check-username", api.UsernameCheck())
|
||||||
mux.Handle("/v1/likes", middleware.LoginRequired(api.Likes()))
|
mux.Handle("/v1/likes", middleware.LoginRequired(api.Likes()))
|
||||||
mux.Handle("/v1/notifications/read", middleware.LoginRequired(api.ReadNotification()))
|
mux.Handle("/v1/notifications/read", middleware.LoginRequired(api.ReadNotification()))
|
||||||
mux.Handle("/v1/notifications/delete", middleware.LoginRequired(api.ClearNotification()))
|
mux.Handle("/v1/notifications/delete", middleware.LoginRequired(api.ClearNotification()))
|
||||||
|
|
|
@ -108,6 +108,20 @@
|
||||||
value="{{.Username}}"
|
value="{{.Username}}"
|
||||||
required>
|
required>
|
||||||
<small class="has-text-grey">Usernames are 3 to 32 characters a-z 0-9 . -</small>
|
<small class="has-text-grey">Usernames are 3 to 32 characters a-z 0-9 . -</small>
|
||||||
|
|
||||||
|
<!-- Username checking -->
|
||||||
|
<div class="notification is-info is-light py-2 px-4 mt-1"
|
||||||
|
id="username-checking" style="display: none">
|
||||||
|
<i class="fa fa-spinner fa-spin mr-1"></i> Checking username...
|
||||||
|
</div>
|
||||||
|
<div class="notification is-success is-light py-2 px-4 mt-1"
|
||||||
|
id="username-ok" style="display: none">
|
||||||
|
<i class="fa fa-check mr-1"></i> Looks good!
|
||||||
|
</div>
|
||||||
|
<div class="notification is-danger is-light py-2 px-4 mt-1"
|
||||||
|
id="username-error" style="display: none">
|
||||||
|
<i class="fa fa-xmark mr-1"></i> That username is already taken!
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="password">Enter a passphrase:</label>
|
<label class="label" for="password">Enter a passphrase:</label>
|
||||||
|
@ -153,3 +167,61 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{define "scripts"}}
|
||||||
|
<script>
|
||||||
|
window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
// Set up username checking script.
|
||||||
|
const $username = document.querySelector("#username"),
|
||||||
|
$unCheck = document.querySelector("#username-checking"),
|
||||||
|
$unOK = document.querySelector("#username-ok"),
|
||||||
|
$unError = document.querySelector("#username-error");
|
||||||
|
|
||||||
|
let onChange = (e) => {
|
||||||
|
$unCheck.style.display = "block";
|
||||||
|
$unOK.style.display = "none";
|
||||||
|
$unError.style.display = "none";
|
||||||
|
|
||||||
|
if ($username.value.length < 3) {
|
||||||
|
$unCheck.style.display = "none";
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
return fetch("/v1/users/check-username", {
|
||||||
|
method: "POST",
|
||||||
|
mode: "same-origin",
|
||||||
|
cache: "no-cache",
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"username": $username.value,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.StatusCode !== 200) {
|
||||||
|
window.alert(data.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = data.data;
|
||||||
|
if (result.OK) {
|
||||||
|
$unOK.style.display = "block";
|
||||||
|
$unError.style.display = "none";
|
||||||
|
} else {
|
||||||
|
$unOK.style.display = "none";
|
||||||
|
$unError.style.display = "block";
|
||||||
|
}
|
||||||
|
}).catch(resp => {
|
||||||
|
window.alert(resp);
|
||||||
|
}).finally(() => {
|
||||||
|
$unCheck.style.display = "none";
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
$username.addEventListener("change", onChange);
|
||||||
|
$username.addEventListener("blur", onChange);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user