Move new web stuff into dedicated folder
This commit is contained in:
parent
7bb32cb429
commit
befaccd59c
4 changed files with 234 additions and 1 deletions
|
@ -13,6 +13,9 @@ type Server struct {
|
||||||
|
|
||||||
func New() *Server {
|
func New() *Server {
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
|
handler.HandleFunc("GET /non-deleted", getNonDeletedUsers)
|
||||||
|
handler.HandleFunc("POST /local-user", createLocalUser)
|
||||||
|
handler.HandleFunc("GET /delete", deleteUser)
|
||||||
web := http.Server{
|
web := http.Server{
|
||||||
Addr: DebugAddr,
|
Addr: DebugAddr,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
|
@ -26,6 +29,7 @@ func (s *Server) Start() error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Stop() error {
|
func (s *Server) Stop() error {
|
||||||
return s.server.Shutdown(context.Background())
|
return s.server.Shutdown(context.Background())
|
||||||
}
|
}
|
119
web/debug/users.go
Normal file
119
web/debug/users.go
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
package webdebug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/rand"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
httputils "git.mstar.dev/mstar/goutils/http"
|
||||||
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||||
|
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||||
|
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNonDeletedUsers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
pageStr := r.FormValue("page")
|
||||||
|
page := 0
|
||||||
|
if pageStr != "" {
|
||||||
|
var err error
|
||||||
|
page, err = strconv.Atoi(pageStr)
|
||||||
|
if err != nil {
|
||||||
|
httputils.HttpErr(w, 0, "page is not a number", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users, err := dbgen.User.GetPagedAllNonDeleted(uint(page))
|
||||||
|
if err != nil {
|
||||||
|
httputils.HttpErr(w, 0, "failed to get users", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
marshalled, err := json.Marshal(sliceutils.Map(users, func(t models.User) webshared.User {
|
||||||
|
u := webshared.User{}
|
||||||
|
u.FromModel(&t)
|
||||||
|
return u
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
httputils.HttpErr(w, 0, "failed to marshal users", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, string(marshalled))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLocalUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
type Inbound struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Displayname string `json:"displayname"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Birthday *time.Time `json:"birthday"`
|
||||||
|
Location *string `json:"location"`
|
||||||
|
IsBot bool `json:"is_bot"`
|
||||||
|
}
|
||||||
|
jsonDecoder := json.NewDecoder(r.Body)
|
||||||
|
data := Inbound{}
|
||||||
|
err := jsonDecoder.Decode(&data)
|
||||||
|
if err != nil {
|
||||||
|
httputils.HttpErr(w, 0, "decode failed", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKey, privateKey, err := ed25519.GenerateKey(nil)
|
||||||
|
pkeyId := make([]byte, 64)
|
||||||
|
_, err = rand.Read(pkeyId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Failed to generate passkey id")
|
||||||
|
httputils.HttpErr(w, 0, "failed to generate passkey id", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u := dbgen.User
|
||||||
|
query := u.Select(
|
||||||
|
u.Username,
|
||||||
|
u.DisplayName,
|
||||||
|
u.Description,
|
||||||
|
u.IsBot,
|
||||||
|
u.ServerId,
|
||||||
|
u.PrivateKey,
|
||||||
|
u.PublicKey,
|
||||||
|
u.PasskeyId,
|
||||||
|
)
|
||||||
|
if data.Birthday != nil {
|
||||||
|
query = query.Select(u.Birthday)
|
||||||
|
}
|
||||||
|
if data.Location != nil {
|
||||||
|
query = query.Select(u.Location)
|
||||||
|
}
|
||||||
|
user := models.User{
|
||||||
|
Username: data.Username,
|
||||||
|
DisplayName: data.Displayname,
|
||||||
|
Description: data.Description,
|
||||||
|
IsBot: data.IsBot,
|
||||||
|
ServerId: 1, // Hardcoded, Self is always first ID
|
||||||
|
PublicKey: publicKey,
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
PasskeyId: pkeyId,
|
||||||
|
}
|
||||||
|
if data.Birthday != nil {
|
||||||
|
user.Birthday = sql.NullTime{Valid: true, Time: *data.Birthday}
|
||||||
|
}
|
||||||
|
if data.Location != nil {
|
||||||
|
user.Location = sql.NullString{Valid: true, String: *data.Location}
|
||||||
|
}
|
||||||
|
if err = u.Create(&user); err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to create new local user")
|
||||||
|
httputils.HttpErr(w, 0, "db failure", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := r.FormValue("id")
|
||||||
|
dbgen.User.Where(dbgen.User.ID.Eq(id)).Delete()
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package webpublic
|
||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
110
web/shared/User.go
Normal file
110
web/shared/User.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package webshared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.mstar.dev/mstar/linstrom/shared"
|
||||||
|
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Web/json representation of a user
|
||||||
|
type User struct {
|
||||||
|
// ---- Section public data ----
|
||||||
|
// All data here will always be included, even if empty,
|
||||||
|
// in which case it will be marked as null instead of omitted
|
||||||
|
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
ServerId uint `json:"server_id"`
|
||||||
|
Displayname string `json:"displayname"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
IsBot bool `json:"is_bot"`
|
||||||
|
IconId *string `json:"icon_id"`
|
||||||
|
BackgroundId *string `json:"background_id"`
|
||||||
|
BannerId *string `json:"banner_id"`
|
||||||
|
Indexable bool `json:"indexable"`
|
||||||
|
PublicKey []byte `json:"public_key"`
|
||||||
|
RestrictedFollow bool `json:"restricted_follow"`
|
||||||
|
Location *string `json:"location"`
|
||||||
|
Birthday *time.Time `json:"birthday"`
|
||||||
|
|
||||||
|
// ---- Section Debug data ----
|
||||||
|
// All these entries should only be available
|
||||||
|
// for the debug server and should be cleared
|
||||||
|
// before serving on the public server.
|
||||||
|
// Every debug field must be omitempty
|
||||||
|
Verified *bool `json:"verified,omitempty"`
|
||||||
|
FinishedRegistration *bool `json:"finished_registration,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiler assertations for interface implementations
|
||||||
|
var _ shared.Santisable = &User{}
|
||||||
|
var _ shared.Clonable = &User{}
|
||||||
|
|
||||||
|
func (u *User) Sanitize() {
|
||||||
|
u.Verified = nil
|
||||||
|
u.FinishedRegistration = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Clone() shared.Clonable {
|
||||||
|
user := *u
|
||||||
|
if u.IconId != nil {
|
||||||
|
tmp := *u.IconId
|
||||||
|
user.IconId = &tmp
|
||||||
|
}
|
||||||
|
if u.BackgroundId != nil {
|
||||||
|
tmp := *u.BackgroundId
|
||||||
|
user.BackgroundId = &tmp
|
||||||
|
}
|
||||||
|
if u.BannerId != nil {
|
||||||
|
tmp := *u.BannerId
|
||||||
|
user.BannerId = &tmp
|
||||||
|
}
|
||||||
|
if u.Location != nil {
|
||||||
|
tmp := *u.Location
|
||||||
|
user.Location = &tmp
|
||||||
|
}
|
||||||
|
if u.Birthday != nil {
|
||||||
|
tmp := *u.Birthday
|
||||||
|
user.Birthday = &tmp
|
||||||
|
}
|
||||||
|
if u.Verified != nil {
|
||||||
|
tmp := *u.Verified
|
||||||
|
user.Verified = &tmp
|
||||||
|
}
|
||||||
|
if u.FinishedRegistration != nil {
|
||||||
|
tmp := *u.FinishedRegistration
|
||||||
|
user.FinishedRegistration = &tmp
|
||||||
|
}
|
||||||
|
user.PublicKey = slices.Clone(u.PublicKey)
|
||||||
|
return &user
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) FromModel(m *models.User) {
|
||||||
|
u.ID = m.ID
|
||||||
|
u.CreatedAt = m.CreatedAt
|
||||||
|
u.ServerId = m.ServerId
|
||||||
|
u.Displayname = m.DisplayName
|
||||||
|
u.IsBot = m.IsBot
|
||||||
|
if m.IconId.Valid {
|
||||||
|
u.IconId = &m.IconId.String
|
||||||
|
}
|
||||||
|
if m.BackgroundId.Valid {
|
||||||
|
u.BackgroundId = &m.IconId.String
|
||||||
|
}
|
||||||
|
if m.BannerId.Valid {
|
||||||
|
u.BannerId = &m.IconId.String
|
||||||
|
}
|
||||||
|
u.Indexable = m.Indexable
|
||||||
|
u.PublicKey = append(u.PublicKey, m.PublicKey...)
|
||||||
|
u.RestrictedFollow = m.RestrictedFollow
|
||||||
|
if m.Location.Valid {
|
||||||
|
u.Location = &m.Location.String
|
||||||
|
}
|
||||||
|
if m.Birthday.Valid {
|
||||||
|
u.Birthday = &m.Birthday.Time
|
||||||
|
}
|
||||||
|
u.Verified = &m.Verified
|
||||||
|
u.FinishedRegistration = &m.FinishedRegistration
|
||||||
|
}
|
Loading…
Reference in a new issue