Move translators db->ap to separate module

This commit is contained in:
Melody Becker 2025-06-13 13:42:56 +02:00
parent cfe5047433
commit d86ad370df
Signed by: mstar
SSH key fingerprint: SHA256:9VAo09aaVNTWKzPW7Hq2LW+ox9OdwmTSHRoD4mlz1yI
16 changed files with 456 additions and 423 deletions

View file

@ -5,7 +5,6 @@ import (
"fmt"
"net/http"
"strconv"
"time"
webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/other"
@ -14,143 +13,21 @@ import (
"gorm.io/gorm"
"git.mstar.dev/mstar/linstrom/activitypub"
"git.mstar.dev/mstar/linstrom/config"
"git.mstar.dev/mstar/linstrom/shared"
"git.mstar.dev/mstar/linstrom/storage-new"
"git.mstar.dev/mstar/linstrom/activitypub/translators"
"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 users(w http.ResponseWriter, r *http.Request) {
type OutboundKey struct {
Id string `json:"id"`
Owner string `json:"owner"`
Pem string `json:"publicKeyPem"`
}
type OutboundMedia struct {
Type string `json:"type"`
Url string `json:"url"`
MediaType string `json:"mediaType"`
}
type Outbound struct {
Context []any `json:"@context"`
Id string `json:"id"`
Type string `json:"type"`
PreferredUsername string `json:"preferredUsername"`
Inbox string `json:"inbox"`
Outboux string `json:"outbox"`
PublicKey OutboundKey `json:"publicKey"`
Published time.Time `json:"published"`
DisplayName string `json:"name"`
Description *string `json:"summary,omitempty"`
PublicUrl string `json:"url"`
Icon *OutboundMedia `json:"icon,omitempty"`
Banner *OutboundMedia `json:"image,omitempty"`
Discoverable bool `json:"discoverable"`
Location *string `json:"vcard:Address,omitempty"`
Birthday *string `json:"vcard:bday,omitempty"`
SpeakAsCat bool `json:"speakAsCat"`
IsCat bool `json:"isCat"`
RestrictedFollow bool `json:"manuallyApprovesFollowers"`
Following string `json:"following"`
Followers string `json:"followers"`
}
log := hlog.FromRequest(r)
userId := r.PathValue("id")
user, err := dbgen.User.Where(dbgen.User.ID.Eq(userId)).
Preload(dbgen.User.Icon).Preload(dbgen.User.Banner).
Preload(dbgen.User.BeingTypes).
First()
user, err := translators.UserFromStorage(r.Context(), userId)
if err != nil {
_ = webutils.ProblemDetails(
w,
500,
"/errors/db-failure",
"internal database failure",
nil,
nil,
)
if storage.HandleReconnectError(err) {
log.Warn().Msg("Connection to db lost. Reconnect attempt started")
} else {
log.Error().Err(err).Msg("Failed to get total user count from db")
}
log.Error().Err(err).Msg("Failed to get user from db")
_ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
// FIXME: Remove this later
// (or rather move to dedicated module in storage for old migration stuff),
// temporary fix for old data. User creation locations are fixed already
err = storage.EnsureLocalUserIdHasLinks(userId)
if err != nil {
log.Warn().Err(err).Msg("Failed to create links for local user")
}
apUrl := activitypub.UserIdToApUrl(user.ID)
var keyBytes string
if config.GlobalConfig.Experimental.UseEd25519Keys {
keyBytes = shared.KeyBytesToPem(user.PublicKeyEd, true)
} else {
keyBytes = shared.KeyBytesToPem(user.PublicKeyRsa, false)
}
data := Outbound{
Context: activitypub.BaseLdContext,
Id: apUrl,
Type: "Person",
PreferredUsername: user.Username,
Inbox: apUrl + "/inbox",
Outboux: apUrl + "/outbox",
PublicKey: OutboundKey{
Id: apUrl + "#main-key",
Owner: apUrl,
Pem: keyBytes,
},
Published: user.CreatedAt,
DisplayName: user.DisplayName,
PublicUrl: config.GlobalConfig.General.GetFullPublicUrl() + "/user/" + user.Username,
Discoverable: user.Indexable,
RestrictedFollow: user.RestrictedFollow,
Following: apUrl + "/following",
Followers: apUrl + "/followers",
}
if user.Description != "" {
data.Description = &user.Description
}
if user.Icon != nil {
log.Debug().Msg("icon found")
data.Icon = &OutboundMedia{
Type: "Image",
Url: config.GlobalConfig.General.GetFullPublicUrl() + webshared.EnsurePublicUrl(
user.Icon.Location,
),
MediaType: user.Icon.Type,
}
}
if user.Banner != nil {
log.Debug().Msg("icon banner")
data.Banner = &OutboundMedia{
Type: "Image",
Url: config.GlobalConfig.General.GetFullPublicUrl() + webshared.EnsurePublicUrl(
user.Banner.Location,
),
MediaType: user.Banner.Type,
}
}
if sliceutils.ContainsFunc(user.BeingTypes, func(t models.UserToBeing) bool {
return t.Being == string(models.BEING_CAT)
}) {
data.IsCat = true
// data.SpeakAsCat = true // TODO: Move to check of separate field in db model
}
if user.Location.Valid {
data.Location = &user.Location.String
}
if user.Birthday.Valid {
data.Birthday = &user.Birthday.String
// data.Birthday = other.IntoPointer(user.Birthday.Time.Format("2006-Jan-02")) //YYYY-Month-DD
}
encoded, err := json.Marshal(data)
encoded, err := json.Marshal(user)
if err != nil {
log.Error().Err(err).Msg("Failed to marshal response")
_ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
@ -183,7 +60,7 @@ func userFollowing(w http.ResponseWriter, r *http.Request) {
return
}
if pageNrStr == "" {
col := collectionOut{
col := translators.CollectionOut{
Context: "https://www.w3.org/ns/activitystreams",
Type: "OrderedCollection",
Id: apUrl + "/following",
@ -222,7 +99,7 @@ func userFollowing(w http.ResponseWriter, r *http.Request) {
_ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
page := collectionPageOut{
page := translators.CollectionPageOut{
Context: "https://www.w3.org/ns/activitystreams",
Type: "OrderedCollectionPage",
Id: fmt.Sprintf("%s/following?page=%d", apUrl, pageNr),
@ -270,7 +147,7 @@ func userFollowers(w http.ResponseWriter, r *http.Request) {
return
}
if pageNrStr == "" {
col := collectionOut{
col := translators.CollectionOut{
Context: activitypub.BaseLdContext,
Type: "OrderedCollection",
Id: apUrl + "/followers",
@ -310,7 +187,7 @@ func userFollowers(w http.ResponseWriter, r *http.Request) {
_ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError)
return
}
page := collectionPageOut{
page := translators.CollectionPageOut{
Context: activitypub.BaseLdContext,
Type: "OrderedCollectionPage",
Id: fmt.Sprintf("%s/followers?page=%d", apUrl, pageNr),