261 lines
7.6 KiB
Go
261 lines
7.6 KiB
Go
package handler
|
|
|
|
import (
|
|
// "fmt"
|
|
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
// "time"
|
|
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/db"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/models"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/pkg/kit/validate"
|
|
|
|
// "git.duckylabs.xyz/duckbox/ducky-dash/view"
|
|
|
|
// "git.duckylabs.xyz/duckbox/ducky-dash/pkg/logger"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/pkg/sb"
|
|
|
|
// "git.duckylabs.xyz/duckbox/ducky-dash/pkg/util"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/view/auth"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/view/settings"
|
|
"git.duckylabs.xyz/duckbox/ducky-dash/view/ui"
|
|
|
|
"github.com/nedpals/supabase-go"
|
|
)
|
|
|
|
func HandleLoginIndex(w http.ResponseWriter, r *http.Request) error {
|
|
return render(r, w, auth.Login())
|
|
}
|
|
|
|
func HandleSignupIndex(w http.ResponseWriter, r *http.Request) error {
|
|
return render(r, w, auth.Signup())
|
|
}
|
|
|
|
func HandleResetPasswordIndex(w http.ResponseWriter, r *http.Request) error {
|
|
return render(r, w, auth.ResetPassword())
|
|
}
|
|
|
|
func HandleAuthCallback(w http.ResponseWriter, r *http.Request) error {
|
|
accessToken := r.URL.Query().Get("access_token")
|
|
if len(accessToken) == 0 {
|
|
return render(r, w, auth.CallbackScript())
|
|
}
|
|
setAuthCookie(w, accessToken)
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
return nil
|
|
}
|
|
|
|
func setAuthCookie(w http.ResponseWriter, accessToken string) {
|
|
cookie := &http.Cookie{
|
|
Value: accessToken,
|
|
Name: "at",
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: false,
|
|
}
|
|
http.SetCookie(w, cookie)
|
|
}
|
|
|
|
func HandleLoginCreate(w http.ResponseWriter, r *http.Request) error {
|
|
credentials := supabase.UserCredentials{
|
|
Email: r.FormValue("email"),
|
|
Password: r.FormValue("password"),
|
|
}
|
|
resp, err := sb.Client.Auth.SignIn(r.Context(), credentials)
|
|
if err != nil {
|
|
slog.Error("login authentication error", "err", err, "user", credentials.Email)
|
|
return render(r, w, auth.SignInForm(credentials, auth.LoginErrors{
|
|
InvalidCredentials: "The credentials you have entered are invalid",
|
|
}))
|
|
}
|
|
setAuthCookie(w, resp.AccessToken)
|
|
fmt.Println("user logged in")
|
|
slog.Info("login authentication successful", "user", credentials.Email)
|
|
// TEST: delay for loading spinner
|
|
// time.Sleep(1 * time.Second)
|
|
return hxRedirect(w, r, "/")
|
|
}
|
|
|
|
func HandleLogoutCreate(w http.ResponseWriter, r *http.Request) error {
|
|
cookie := http.Cookie{
|
|
Value: "",
|
|
Name: "at",
|
|
MaxAge: -1,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: false,
|
|
}
|
|
http.SetCookie(w, &cookie)
|
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
|
slog.Info("authenticated user logged out")
|
|
return nil
|
|
}
|
|
|
|
func HandleSignupCreate(w http.ResponseWriter, r *http.Request) error {
|
|
params := auth.SignupParams{
|
|
Email: r.FormValue("email"),
|
|
Password: r.FormValue("password"),
|
|
ConfirmPassword: r.FormValue("confirmPassword"),
|
|
}
|
|
errors := auth.SignupErrors{}
|
|
if ok := validate.New(¶ms, validate.Fields{
|
|
"Email": validate.Rules(validate.Email),
|
|
"Password": validate.Rules(validate.Password),
|
|
"ConfirmPassword": validate.Rules(
|
|
validate.Equal(params.Password),
|
|
validate.Message("Passwords do not match"),
|
|
),
|
|
}).Validate(&errors); !ok {
|
|
slog.Error("error validating signup form", "err", errors, "user", params.Email)
|
|
return render(r, w, auth.SignUpForm(params, errors))
|
|
}
|
|
user, err := sb.Client.Auth.SignUp(r.Context(), supabase.UserCredentials{
|
|
Email: params.Email,
|
|
Password: params.Password,
|
|
})
|
|
if err != nil {
|
|
slog.Error("new signup error", "err", err, "user", user.Email)
|
|
return render(r, w, ui.ToastError("Error signing up on the server"))
|
|
}
|
|
slog.Info("user sign up successful", "user", params.Email)
|
|
return render(r, w, auth.SignupSuccess(user.Email))
|
|
}
|
|
|
|
// Unautheticated users reset password
|
|
func HandleResetPasswordCreate(w http.ResponseWriter, r *http.Request) error {
|
|
params := auth.ResetPasswordParams{
|
|
Email: r.FormValue("email"),
|
|
}
|
|
errors := auth.ResetPasswordErrors{}
|
|
if ok := validate.New(¶ms, validate.Fields{
|
|
"Email": validate.Rules(validate.Email),
|
|
}).Validate(&errors); !ok {
|
|
slog.Error("error validating reset password form", "err", errors, "user", params.Email)
|
|
return render(r, w, auth.ResetPasswordForm(params, errors))
|
|
}
|
|
slog.Info("user reset password request", "user", params.Email)
|
|
err := sb.Client.Auth.ResetPasswordForEmail(r.Context(), params.Email)
|
|
if err != nil {
|
|
slog.Error("error sending reset password email", "err", err, "user", params.Email)
|
|
return err
|
|
}
|
|
slog.Info("user reset password email sent", "user", params.Email)
|
|
return render(r, w, auth.ResetPasswordToast(params))
|
|
}
|
|
|
|
// Authenticated users reset password
|
|
func HandleResetPasswordUpdate(w http.ResponseWriter, r *http.Request) error {
|
|
user := getAuthenticatedUser(r)
|
|
params := map[string]any{
|
|
"password": r.FormValue("password"),
|
|
}
|
|
|
|
_, err := sb.Client.Auth.UpdateUser(r.Context(), user.AccessToken, params)
|
|
errors := settings.UpdatePasswordErrors{
|
|
NewPassword: "Please enter a valid password",
|
|
}
|
|
if err != nil {
|
|
return render(r, w, settings.UpdatePasswordForm(errors))
|
|
}
|
|
|
|
return hxRedirect(w, r, "/")
|
|
}
|
|
|
|
func HandleAccountCreate(w http.ResponseWriter, r *http.Request) error {
|
|
user := getAuthenticatedUser(r)
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
params := settings.AccountSetupParams{
|
|
Username: r.FormValue("username"),
|
|
Bio: r.FormValue("bio"),
|
|
Title: r.FormValue("title"),
|
|
Location: r.FormValue("location"),
|
|
Department: r.FormValue("department"),
|
|
Status: r.FormValue("status"),
|
|
}
|
|
|
|
var errors settings.AccountSetupErrors
|
|
ok := validate.New(¶ms, validate.Fields{
|
|
"Username": validate.Rules(validate.Min(2), validate.Max(50)),
|
|
"Bio": validate.Rules(validate.Max(200)),
|
|
}).Validate(&errors)
|
|
if !ok {
|
|
return render(r, w, settings.AccountSetupForm(params, errors, user))
|
|
}
|
|
|
|
account := models.Account{
|
|
UserID: user.ID,
|
|
Username: params.Username,
|
|
Bio: params.Bio,
|
|
Title: params.Title,
|
|
Location: params.Location,
|
|
Department: params.Department,
|
|
Status: params.Status,
|
|
}
|
|
fmt.Println(account)
|
|
if err := db.CreateAccount(&account); err != nil {
|
|
slog.Error("error creating account", "err", err, "user", user.Username)
|
|
return render(r, w, ui.ToastError("Error setting up account on the server"))
|
|
}
|
|
|
|
return hxRedirect(w, r, "/")
|
|
}
|
|
|
|
func HandleAccountUpdate(w http.ResponseWriter, r *http.Request) error {
|
|
user := getAuthenticatedUser(r)
|
|
r.ParseForm()
|
|
params := settings.SettingsFormParams{
|
|
Username: r.FormValue("username"),
|
|
Email: r.FormValue("email"),
|
|
Department: r.FormValue("department"),
|
|
Title: r.FormValue("title"),
|
|
Status: r.FormValue("status"),
|
|
Location: r.FormValue("location"),
|
|
Bio: r.FormValue("bio"),
|
|
}
|
|
fmt.Println(params.Status)
|
|
var errors settings.SettingsFormErrors
|
|
|
|
// ok := validate.New(¶ms, validate.Fields{
|
|
// "Username": validate.Rules(validate.Min(2), validate.Max(50)),
|
|
// }).Validate(&errors)
|
|
// if !ok {
|
|
// return render(r, w, settings.SettingsForm(params, errors, user))
|
|
// }
|
|
|
|
if err := db.UpdateAccount(&user.Account); err != nil {
|
|
slog.Error("failed to update account", "err", err, "user", user.Username)
|
|
return err
|
|
}
|
|
return render(r, w, settings.SettingsForm(params, errors, user))
|
|
}
|
|
|
|
func HandleAccountsQuery(w http.ResponseWriter, r *http.Request) error {
|
|
accounts, err := db.GetAllAccounts()
|
|
if err != nil {
|
|
slog.Error("error querying accounts", "err", err)
|
|
return err
|
|
}
|
|
// TEST: Print accounts to CLI
|
|
for _, account := range accounts {
|
|
fmt.Println(account.Username)
|
|
}
|
|
|
|
// Load accounts into response header
|
|
w.Header().Add("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
encoder := json.NewEncoder(w)
|
|
encoder.SetEscapeHTML(false)
|
|
if err := encoder.Encode(accounts); err != nil {
|
|
slog.Error("error encoding accounts", "err", err)
|
|
return err
|
|
}
|
|
return err
|
|
}
|