package translators import ( "context" "time" "git.mstar.dev/mstar/goutils/sliceutils" "github.com/rs/zerolog/log" "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/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/models" webshared "git.mstar.dev/mstar/linstrom/web/shared" ) type UserKey struct { Id string `json:"id"` Owner string `json:"owner"` Pem string `json:"publicKeyPem"` } type User 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 UserKey `json:"publicKey"` Published time.Time `json:"published"` DisplayName string `json:"name"` Description *string `json:"summary,omitempty"` PublicUrl string `json:"url"` Icon *Media `json:"icon,omitempty"` Banner *Media `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"` } func UserFromStorage(ctx context.Context, id string) (*User, error) { user, err := dbgen.User.Where(dbgen.User.ID.Eq(id)). Preload(dbgen.User.Icon).Preload(dbgen.User.Banner). Preload(dbgen.User.BeingTypes). First() err = storage.EnsureLocalUserIdHasLinks(id) 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 := User{ Id: apUrl, Type: "Person", PreferredUsername: user.Username, Inbox: apUrl + "/inbox", Outboux: apUrl + "/outbox", PublicKey: UserKey{ 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 = &Media{ 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 = &Media{ 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 } return &data, nil }