add account page

This commit is contained in:
Adora Laura Kalb 2023-06-16 14:30:27 +02:00
parent aac72f2a9e
commit ffe6dc1fea
Signed by: adoralaura
GPG key ID: 7A4552166FC8C056
12 changed files with 188 additions and 4 deletions

View file

@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- added Changelog
- Ability to change the url and description of shortlinks
- /api/v1/users/me endpoint to get user details
- Account page for user overview and later use
### Changed
- License changed to MIT

View file

@ -1,10 +1,12 @@
package api
import (
"codeberg.org/lauralani/go-urlsh/internal/db"
"codeberg.org/lauralani/go-urlsh/internal/misc"
"codeberg.org/lauralani/go-urlsh/models"
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"github.com/gofiber/fiber/v2"
@ -58,3 +60,69 @@ func HandleUserPost(c *fiber.Ctx) error {
return nil
}
}
func HandleUserMe(c *fiber.Ctx) error {
if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) && !db.IsApiKeyValid(c.GetRespHeader("x-api-key", "")) {
return fiber.NewError(fiber.StatusUnauthorized, "401 Unauthorized")
}
cookie := c.Cookies(misc.CookieName, "")
apikey := c.GetRespHeader("x-api-key", "")
var authmethod string
var user models.User
if cookie != "" {
authmethod = "cookie"
} else {
authmethod = "apikey"
}
switch authmethod {
case "cookie":
var session models.Session
err := models.DB.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background())
if err != nil {
if err == sql.ErrNoRows {
log.Printf("[HandleUserMe] Session %v not found\n", cookie)
} else {
log.Printf("[HandleUserMe] Error querying session %v from database: %v\n", cookie, err)
}
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
err = models.DB.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background())
if err != nil {
log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", session.UserName, err)
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
case "apikey":
var key models.ApiKey
err := models.DB.NewSelect().Model(&key).Where("key = ?", apikey).Scan(context.Background())
if err != nil {
if err == sql.ErrNoRows {
log.Printf("[HandleUserMe] ApiKey %v not found\n", apikey)
} else {
log.Printf("[HandleUserMe] Error querying apikey %v from database: %v\n", apikey, err)
}
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
err = models.DB.NewSelect().Model(&user).Where("username = ?", key.UserName).Scan(context.Background())
if err != nil {
log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", key.UserName, err)
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
}
var userresponse = new(models.UserResponse)
userresponse.UserName = user.UserName
userresponse.Created = user.Created
err := c.JSON(userresponse)
if err != nil {
return err
}
return nil
}

View file

@ -53,6 +53,8 @@ func SetupFiber() error {
fiberapp.Get("/admin/", web.HandleAdminLinkIndexGet)
fiberapp.Get("/admin/account/", web.HandleAdminAccountGet)
fiberapp.Get("/admin/login", web.HandleAdminLoginGet)
fiberapp.Post("/admin/login", web.HandleAdminLoginPost)

View file

@ -14,7 +14,7 @@ func IsCookieValid(val string) bool {
return false
}
count, err := models.DB.NewSelect().Model((*models.Login)(nil)).Where("cookie = ?", val).Count(context.Background())
count, err := models.DB.NewSelect().Model((*models.Session)(nil)).Where("cookie = ?", val).Count(context.Background())
if err != nil {
log.Printf("Error checking cookie validity for cookie %v\n", val)
return false

View file

@ -25,7 +25,7 @@ func InitializeDB() error {
return fmt.Errorf("couldn't create database: [%w]", err)
}
_, err = models.DB.NewCreateTable().IfNotExists().Model((*models.Login)(nil)).Exec(context.Background())
_, err = models.DB.NewCreateTable().IfNotExists().Model((*models.Session)(nil)).Exec(context.Background())
if err != nil {
return fmt.Errorf("couldn't create database: [%w]", err)
}

41
internal/web/account.go Normal file
View file

@ -0,0 +1,41 @@
package web
import (
"codeberg.org/lauralani/go-urlsh/internal/db"
"codeberg.org/lauralani/go-urlsh/internal/misc"
"codeberg.org/lauralani/go-urlsh/models"
"context"
"database/sql"
"github.com/gofiber/fiber/v2"
"log"
)
func HandleAdminAccountGet(c *fiber.Ctx) error {
if !db.IsCookieValid(c.Cookies(misc.CookieName, "")) {
c.Location("/admin/")
c.Status(fiber.StatusSeeOther)
return nil
}
cookie := c.Cookies(misc.CookieName, "")
var session models.Session
var user models.User
err := models.DB.NewSelect().Model(&session).Where("cookie = ?", cookie).Scan(context.Background())
if err != nil {
if err == sql.ErrNoRows {
log.Printf("[HandleUserMe] Session %v not found\n", cookie)
} else {
log.Printf("[HandleUserMe] Error querying session %v from database: %v\n", cookie, err)
}
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
err = models.DB.NewSelect().Model(&user).Where("username = ?", session.UserName).Scan(context.Background())
if err != nil {
log.Printf("[HandleUserMe] Error querying user %v from database: %v\n", session.UserName, err)
return fiber.NewError(fiber.StatusInternalServerError, "500 Internal Server Error")
}
return c.Render("account", user)
}

View file

@ -41,7 +41,7 @@ func HandleAdminLoginPost(c *fiber.Ctx) error {
}
key := uuid.New().String()
dblogin := new(models.Login)
dblogin := new(models.Session)
cookie := new(fiber.Cookie)
cookie.Name = misc.CookieName

View file

@ -5,7 +5,7 @@ import (
"time"
)
type Login struct {
type Session struct {
bun.BaseModel `bun:"table:logins"`
Cookie string `bun:"cookie,pk,type:uuid"`
UserName string `bun:"username,notnull"`

62
views/account.tmpl Normal file
View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Account - go-urlsh</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" href="/admin/pico.min.css">
<link rel="stylesheet" href="/admin/custom.css">
<script src="/admin/main.js" defer></script>
<style>
h1, h2, h3, h4, h5, h6 {
margin-bottom: 30px;
}
</style>
</head>
<body>
<nav class="container-fluid">
<ul>
<li>
<a href="/admin/" class="contrast"><strong>go-urlsh</strong></a>
</li>
</ul>
<ul>
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>
<li>
<a href="javascript: void(0)" >Users (coming soon)</a>
</li>
<li>
<a href="javascript: Logout()" style="color: red;">Logout</a>
</li>
</ul>
</nav>
<main class="container" style="padding: 0">
<h1>Account</h1>
<h2>User Details</h2>
<p>Username: {{ .UserName }}</p>
<p>Created at: {{ .Created }}</p>
<h2>Security</h2>
<p>nothing here yet</p>
<dialog id="dialog-info">
<h2 id="dialog-heading"></h2>
<p id="dialog-text"></p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
</main>
{{template "partials/footer" .}}
</body>
</html>

View file

@ -23,6 +23,9 @@
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/account/">Account</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>

View file

@ -23,6 +23,9 @@
<li>
<a href="/admin/">Links</a>
</li>
<li>
<a href="/admin/account/">Account</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>

View file

@ -29,6 +29,9 @@
<li>
<a href="/admin/links/new" style="color: greenyellow;">Add new Shortlink</a>
</li>
<li>
<a href="/admin/account/">Account</a>
</li>
<li>
<a href="/admin/apikeys/">API Keys</a>
</li>