package translators import ( "context" "fmt" "time" "git.mstar.dev/mstar/linstrom/config" "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 Tag struct { Type string `json:"type"` Name string `json:"name"` // ---- Section Hashtag & Mention Href *string `json:"href,omitempty"` // Section Emote Id *string `json:"id,omitempty"` Updated *time.Time `json:"updated,omitempty"` Icon *Media `json:"icon,omitempty"` } type ObjectNote struct { // Context should be set, if needed, by the endpoint handler Context any `json:"@context,omitempty"` // Attributes below set from storage Id string `json:"id"` Type string `json:"type"` Summary *string `json:"summary"` InReplyTo *string `json:"inReplyTo"` Published time.Time `json:"published"` Url string `json:"url"` AttributedTo string `json:"attributedTo"` To []string `json:"to"` CC []string `json:"cc"` Sensitive bool `json:"sensitive"` AtomUri string `json:"atomUri"` InReplyToAtomUri *string `json:"inReplyToAtomUri"` // Conversation string `json:"conversation"` // FIXME: Uncomment once understood what this field wants Content string `json:"content"` // ContentMap map[string]string `json:"content_map"` // TODO: Uncomment once/if support for multiple languages available // Attachments []string `json:"attachments"` // FIXME: Change this to document type Tags []Tag `json:"tag"` // Replies any `json:"replies"` // FIXME: Change this to collection type embedding first page // Likes any `json:"likes"` // FIXME: Change this to collection // Shares any `json:"shares"` // FIXME: Change this to collection, is boosts } func NoteFromStorage(ctx context.Context, id string) (*ObjectNote, error) { note, err := dbgen.Note.Where(dbgen.Note.ID.Eq(id)). Preload(dbgen.Note.Creator). Preload(dbgen.Note.PingRelations). Preload(dbgen.Note.Tags). First() if err != nil { return nil, err } // TODO: Check access level, requires acting user to be included in function signature publicUrlPrefix := config.GlobalConfig.General.GetFullPublicUrl() data := &ObjectNote{ Id: publicUrlPrefix + "/api/activitypub/note/" + id, Type: "Note", Published: note.CreatedAt, AttributedTo: publicUrlPrefix + "/api/activitypub/user/" + note.CreatorId, Content: note.RawContent, // FIXME: Escape content Url: publicUrlPrefix + "/@" + note.Creator.Username + "/" + id, AtomUri: publicUrlPrefix + "/api/activitypub/object/" + id, Tags: []Tag{}, } switch note.AccessLevel { case models.NOTE_TARGET_PUBLIC: data.To = []string{ "https://www.w3.org/ns/activitystreams#Public", } data.CC = []string{ fmt.Sprintf("%s/api/activitypub/user/%s/followers", publicUrlPrefix, note.CreatorId), } case models.NOTE_TARGET_HOME: return nil, fmt.Errorf("home access level not implemented") case models.NOTE_TARGET_FOLLOWERS: return nil, fmt.Errorf("followers access level not implemented") case models.NOTE_TARGET_DM: return nil, fmt.Errorf("dm access level not implemented") default: return nil, fmt.Errorf("unknown access level %v", note.AccessLevel) } if note.RepliesTo.Valid { data.InReplyTo = ¬e.RepliesTo.String data.InReplyToAtomUri = ¬e.RepliesTo.String } if note.ContentWarning.Valid { data.Summary = ¬e.ContentWarning.String data.Sensitive = true } for _, ping := range note.PingRelations { target, err := dbgen.User.GetById(ping.PingTargetId) if err != nil { return nil, err } pubUrl := webshared.UserPublicUrl(target.ID) data.Tags = append(data.Tags, Tag{ Type: "Mention", Href: &pubUrl, Name: target.Username, }) } for _, tag := range note.Tags { data.Tags = append(data.Tags, Tag{ Type: "Hashtag", Href: &tag.TagUrl, Name: tag.Tag, }) } return data, nil }