package activitypub import ( "encoding/json" "fmt" "io" "net/http" "time" webutils "git.mstar.dev/mstar/goutils/http" "git.mstar.dev/mstar/goutils/other" "git.mstar.dev/mstar/goutils/sliceutils" "github.com/rs/zerolog/hlog" "git.mstar.dev/mstar/linstrom/activitypub/shared/types" "git.mstar.dev/mstar/linstrom/config" "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" ) 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"` 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"` } 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() 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") } return } apUrl := userIdToApUrl(user.ID) var keyBytes string if config.GlobalConfig.Experimental.UseEd25519Keys { keyBytes = keyBytesToPem(user.PublicKeyEd) } else { keyBytes = keyBytesToPem(user.PublicKeyRsa) } data := Outbound{ Context: types.BaseLdContext, Id: apUrl, Type: "Person", PreferredUsername: user.Username, Inbox: apUrl + "/inbox", 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, } 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 == 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 = other.IntoPointer(user.Birthday.Time.Format("2006-Jan-02")) //YYYY-Month-DD } encoded, err := json.Marshal(data) w.Header().Add("Content-Type", "application/activity+json") fmt.Fprint(w, string(encoded)) } func userInbox(w http.ResponseWriter, r *http.Request) { log := hlog.FromRequest(r) userId := r.PathValue("id") data, err := io.ReadAll(r.Body) log.Info().Err(err).Str("userId", userId).Bytes("body", data).Msg("Inbox message") } /* Fine. You win JsonLD. I can't get you to work properly. I'll just treat you like normal json then Fuck you. If anyone wants to get this shit working *the propper way* with JsonLD, here's the original code var chain goap.BaseApChain = &goap.EmptyBaseObject{} chain = goap.AppendUDIdData(chain, apUrl) chain = goap.AppendUDTypeData(chain, "Person") chain = goap.AppendASPreferredNameData(chain, goap.ValueValue[string]{Value: user.DisplayName}) chain = goap.AppendW3SecurityPublicKeyData( chain, apUrl+"#main-key", apUrl, keyBytesToPem(user.PublicKey), ) chainMap := chain.MarshalToMap() proc := ld.NewJsonLdProcessor() options := ld.NewJsonLdOptions("") tmp, tmperr := json.Marshal(chainMap) fmt.Println(string(tmp), tmperr) data, err := proc.Compact(chainMap, baseLdContext, options) // data, err := goap.Compact(chain, baseLdContext) if err != nil { log.Error().Err(err).Msg("Failed to marshal ap chain") webutils.ProblemDetailsStatusOnly(w, 500) return } */