A website inspired by Last.fm that will keep track of your listening statistics
lastfm music statistics
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make registering a user possible. Make rules for validation.

oscar345 9fc13eaf c5ab7e5c

+89 -14
+12 -4
internal/web/requests/authentication.go
··· 24 24 } 25 25 26 26 type RegisterForm struct { 27 - Email string `json:"email"` 28 - Password string `json:"password"` 27 + Email string `json:"email"` 28 + Password string `json:"password"` 29 + ConfirmPassword string `json:"confirm_password"` 29 30 } 30 31 31 32 func (f *RegisterForm) Validate() error { ··· 34 35 validator.Validate("email", map[string]bool{ 35 36 validator.Required(): f.Email != "", 36 37 validator.BetweenValue(3, 20): len(f.Email) >= 3 && len(f.Email) <= 20, 38 + validator.Email(): validation.IsValidEmail(f.Email), 37 39 }) 38 40 39 41 validator.Validate("password", map[string]bool{ 40 - validator.Required(): f.Password != "", 41 - validator.BetweenValue(8, 20): len(f.Password) >= 8 && len(f.Password) <= 20, 42 + validator.Required(): f.Password != "", 43 + validator.Contains("uppercase characters"): validation.HasUpperCase(f.Password), 44 + validator.BetweenValue(8, 20): len(f.Password) >= 8 && len(f.Password) <= 20, 45 + }) 46 + 47 + validator.Validate("confirm_password", map[string]bool{ 48 + validator.Required(): f.ConfirmPassword != "", 49 + validator.EqualTo("password"): f.ConfirmPassword == f.Password, 42 50 }) 43 51 44 52 return validator.Run()
+32
internal/web/router/router.go
··· 12 12 "github.com/gorilla/sessions" 13 13 "github.com/oscar345/keeptrack/internal/config" 14 14 "github.com/oscar345/keeptrack/internal/filters" 15 + "github.com/oscar345/keeptrack/internal/models" 15 16 "github.com/oscar345/keeptrack/internal/services" 16 17 "github.com/oscar345/keeptrack/internal/web/handlers" 17 18 "github.com/oscar345/keeptrack/internal/web/middleware" ··· 107 108 108 109 r.Get("/authentication/register", func(w http.ResponseWriter, r *http.Request) { 109 110 s.inertia.Render(w, r, "authentication/Register", inertia.Props{}) 111 + }) 112 + 113 + r.Post("/authentication/register", func(w http.ResponseWriter, r *http.Request) { 114 + var form requests.RegisterForm 115 + if err := json.NewDecoder(r.Body).Decode(&form); err != nil { 116 + http.Error(w, err.Error(), http.StatusBadRequest) 117 + return 118 + } 119 + 120 + if err := form.Validate(); err != nil { 121 + s.inertia.SetErrors(w, r, err.(validation.Errors)) 122 + http.Redirect(w, r, "/authentication/register", 302) 123 + return 124 + } 125 + 126 + user, err := s.authService.Register(r.Context(), models.User{ 127 + Email: form.Email, 128 + Password: form.Password, 129 + }) 130 + 131 + if err != nil { 132 + http.Error(w, err.Error(), http.StatusBadRequest) 133 + return 134 + } 135 + 136 + if err := s.authProvider.CreateSession(w, r, user.ID); err != nil { 137 + http.Error(w, err.Error(), http.StatusInternalServerError) 138 + return 139 + } 140 + 141 + http.Redirect(w, r, "/", 302) 110 142 }) 111 143 112 144 r.Delete("/authentication/logout", func(w http.ResponseWriter, r *http.Request) {
+12
pkg/validation/message.go
··· 6 6 return "Field is required" 7 7 } 8 8 9 + func (v *Validator) EqualTo(field string) string { 10 + return fmt.Sprintf("Field must be equal to %s", field) 11 + } 12 + 9 13 func (v *Validator) MinLength(length int) string { 10 14 return fmt.Sprintf("Field must be at least %d characters long", length) 11 15 } ··· 33 37 func (v *Validator) BetweenValue(min, max int) string { 34 38 return fmt.Sprintf("Field must be between %d and %d", min, max) 35 39 } 40 + 41 + func (v *Validator) Email() string { 42 + return "Field must be a valid email address" 43 + } 44 + 45 + func (v *Validator) Contains(value string) string { 46 + return fmt.Sprintf("Field must contain %s", value) 47 + }
+19
pkg/validation/rules.go
··· 1 + package validation 2 + 3 + import ( 4 + "net/mail" 5 + "strings" 6 + ) 7 + 8 + func IsValidEmail(value string) bool { 9 + _, err := mail.ParseAddress(value) 10 + return err == nil 11 + } 12 + 13 + func HasLowerCase(value string) bool { 14 + return strings.ContainsAny(value, "abcdefghijklmnopqrstuvwxyz") 15 + } 16 + 17 + func HasUpperCase(value string) bool { 18 + return strings.ContainsAny(value, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") 19 + }
+14 -10
web/views/authentication/Register.svelte
··· 5 5 import { default as Authentication } from "$components/layouts/authentication/Layout.svelte"; 6 6 import { 7 7 GET_AuthenticationLogin, 8 - GET_AuthenticationRegister, 9 - POST_AuthenticationLogin, 8 + POST_AuthenticationRegister, 10 9 } from "$routes"; 11 10 import { Link, useForm } from "@inertiajs/svelte"; 12 11 ··· 16 15 <script lang="ts"> 17 16 import Back from "$components/interaction/Back.svelte"; 18 17 import { GET_Index } from "$routes"; 18 + import type { RegisterForm } from "$schemas/requests"; 19 19 20 20 type Props = {}; 21 21 22 22 let {}: Props = $props(); 23 23 24 24 const form = useForm({ 25 - username: "", 25 + email: "", 26 26 password: "", 27 27 confirm_password: "", 28 - }); 28 + } as RegisterForm); 29 29 30 30 function submit(e?: SubmitEvent) { 31 31 e?.preventDefault(); 32 - $form.submit(POST_AuthenticationLogin(), {}); 32 + $form.submit(POST_AuthenticationRegister(), {}); 33 33 } 34 + 35 + form.subscribe((form) => { 36 + console.log(form.errors); 37 + }); 34 38 </script> 35 39 36 40 <header class="header"> ··· 49 53 <Field 50 54 as="input" 51 55 type="text" 52 - label="Username" 53 - bind:value={$form.username} 54 - description="Enter your username" 55 - errors={$form.errors.username} 56 + label="Email" 57 + bind:value={$form.email} 58 + description="Enter your email" 59 + errors={$form.errors.email} 56 60 /> 57 61 <Field 58 62 as="input" ··· 68 72 label="Confirm password" 69 73 bind:value={$form.confirm_password} 70 74 description="Confirm your password" 71 - errors={$form.errors.confirmPassword} 75 + errors={$form.errors.confirm_password} 72 76 /> 73 77 <Button scheme="primary">submit</Button> 74 78 </form>