add account page
This commit is contained in:
parent
aac72f2a9e
commit
ffe6dc1fea
12 changed files with 188 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
41
internal/web/account.go
Normal 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)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
62
views/account.tmpl
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue