mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-30 02:26:16 -06:00
start adding client support for making status edits and viewing history
This commit is contained in:
parent
9ae0c7b363
commit
c8a465f9a0
15 changed files with 1544 additions and 431 deletions
|
|
@ -1216,21 +1216,6 @@ func (c *Converter) StatusToWebStatus(
|
|||
return webStatus, nil
|
||||
}
|
||||
|
||||
// StatusToAPIStatusSource returns the *apimodel.StatusSource of the given status.
|
||||
// Callers should check beforehand whether a requester has permission to view the
|
||||
// source of the status, and ensure they're passing only a local status into this function.
|
||||
func (c *Converter) StatusToAPIStatusSource(ctx context.Context, s *gtsmodel.Status) (*apimodel.StatusSource, error) {
|
||||
// TODO: remove this when edit support is added.
|
||||
text := "**STATUS EDITS ARE NOT CURRENTLY SUPPORTED IN GOTOSOCIAL (coming in 2024)**\n" +
|
||||
"You can review the original text of your status below, but you will not be able to submit this edit.\n\n---\n\n" + s.Text
|
||||
|
||||
return &apimodel.StatusSource{
|
||||
ID: s.ID,
|
||||
Text: text,
|
||||
SpoilerText: s.ContentWarning,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// statusToFrontend is a package internal function for
|
||||
// parsing a status into its initial frontend representation.
|
||||
//
|
||||
|
|
@ -1472,6 +1457,120 @@ func (c *Converter) baseStatusToFrontend(
|
|||
return apiStatus, nil
|
||||
}
|
||||
|
||||
// StatusToAPIEdits ...
|
||||
func (c *Converter) StatusToAPIEdits(ctx context.Context, status *gtsmodel.Status) ([]*apimodel.StatusEdit, error) {
|
||||
var media map[string]*gtsmodel.MediaAttachment
|
||||
|
||||
// Gather attachments of status AND edits.
|
||||
attachmentIDs := status.AllAttachmentIDs()
|
||||
if len(attachmentIDs) > 0 {
|
||||
|
||||
// Fetch all of the gathered status attachments from the database.
|
||||
attachments, err := c.state.DB.GetAttachmentsByIDs(ctx, attachmentIDs)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error getting attachments from db: %w", err)
|
||||
}
|
||||
|
||||
// Generate a lookup map in 'media' of status attachments by their IDs.
|
||||
media = util.KeyBy(attachments, func(m *gtsmodel.MediaAttachment) string {
|
||||
return m.ID
|
||||
})
|
||||
}
|
||||
|
||||
// Convert the status author account to API model.
|
||||
apiAccount, err := c.AccountToAPIAccountPublic(ctx,
|
||||
status.Account,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error converting account: %w", err)
|
||||
}
|
||||
|
||||
// Convert status emojis to their API models.
|
||||
apiEmojis, err := c.convertEmojisToAPIEmojis(ctx,
|
||||
nil,
|
||||
status.EmojiIDs,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error converting emojis: %w", err)
|
||||
}
|
||||
|
||||
// Iterate through status edits, starting at newest (highest index).
|
||||
apiEdits := make([]*apimodel.StatusEdit, 0, len(status.Edits))
|
||||
for i := len(status.Edits) - 1; i >= 0; i-- {
|
||||
edit := status.Edits[i]
|
||||
|
||||
// Iterate through edit attachment IDs, getting model from 'media' lookup.
|
||||
apiAttachments := make([]*apimodel.Attachment, 0, len(edit.AttachmentIDs))
|
||||
for _, id := range edit.AttachmentIDs {
|
||||
attachment, ok := media[id]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert each media attachment to frontend API model.
|
||||
apiAttachment, err := c.AttachmentToAPIAttachment(ctx,
|
||||
attachment,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error(ctx, "error converting attachment: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append converted media attachment to return slice.
|
||||
apiAttachments = append(apiAttachments, &apiAttachment)
|
||||
}
|
||||
|
||||
// If media descriptions are set, update API model descriptions.
|
||||
if len(edit.AttachmentIDs) == len(edit.AttachmentDescriptions) {
|
||||
var j int
|
||||
for i, id := range edit.AttachmentIDs {
|
||||
descr := edit.AttachmentDescriptions[i]
|
||||
for ; j < len(apiAttachments); j++ {
|
||||
if apiAttachments[j].ID == id {
|
||||
apiAttachments[j].Description = &descr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attach status poll if set.
|
||||
var apiPoll *apimodel.Poll
|
||||
if len(edit.PollOptions) > 0 {
|
||||
apiPoll = new(apimodel.Poll)
|
||||
|
||||
// Iterate through poll options and attach to API poll model.
|
||||
apiPoll.Options = make([]apimodel.PollOption, len(edit.PollOptions))
|
||||
for i, option := range edit.PollOptions {
|
||||
apiPoll.Options[i] = apimodel.PollOption{
|
||||
Title: option,
|
||||
}
|
||||
}
|
||||
|
||||
// If poll votes are attached, set vote counts.
|
||||
if len(edit.PollVotes) == len(apiPoll.Options) {
|
||||
for i, votes := range edit.PollVotes {
|
||||
apiPoll.Options[i].VotesCount = &votes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append this status edit to the return slice.
|
||||
apiEdits = append(apiEdits, &apimodel.StatusEdit{
|
||||
CreatedAt: util.FormatISO8601(edit.CreatedAt),
|
||||
Content: edit.Content,
|
||||
SpoilerText: edit.ContentWarning,
|
||||
Sensitive: util.PtrOrZero(edit.Sensitive),
|
||||
Account: apiAccount,
|
||||
Poll: apiPoll,
|
||||
MediaAttachments: apiAttachments,
|
||||
Emojis: apiEmojis,
|
||||
})
|
||||
}
|
||||
|
||||
return apiEdits, nil
|
||||
}
|
||||
|
||||
// VisToAPIVis converts a gts visibility into its api equivalent
|
||||
func (c *Converter) VisToAPIVis(ctx context.Context, m gtsmodel.Visibility) apimodel.Visibility {
|
||||
switch m {
|
||||
|
|
@ -1488,7 +1587,7 @@ func (c *Converter) VisToAPIVis(ctx context.Context, m gtsmodel.Visibility) apim
|
|||
}
|
||||
|
||||
// InstanceRuleToAdminAPIRule converts a local instance rule into its api equivalent for serving at /api/v1/admin/instance/rules/:id
|
||||
func (c *Converter) InstanceRuleToAPIRule(r gtsmodel.Rule) apimodel.InstanceRule {
|
||||
func InstanceRuleToAPIRule(r gtsmodel.Rule) apimodel.InstanceRule {
|
||||
return apimodel.InstanceRule{
|
||||
ID: r.ID,
|
||||
Text: r.Text,
|
||||
|
|
@ -1496,18 +1595,16 @@ func (c *Converter) InstanceRuleToAPIRule(r gtsmodel.Rule) apimodel.InstanceRule
|
|||
}
|
||||
|
||||
// InstanceRulesToAPIRules converts all local instance rules into their api equivalent for serving at /api/v1/instance/rules
|
||||
func (c *Converter) InstanceRulesToAPIRules(r []gtsmodel.Rule) []apimodel.InstanceRule {
|
||||
func InstanceRulesToAPIRules(r []gtsmodel.Rule) []apimodel.InstanceRule {
|
||||
rules := make([]apimodel.InstanceRule, len(r))
|
||||
|
||||
for i, v := range r {
|
||||
rules[i] = c.InstanceRuleToAPIRule(v)
|
||||
rules[i] = InstanceRuleToAPIRule(v)
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
// InstanceRuleToAdminAPIRule converts a local instance rule into its api equivalent for serving at /api/v1/admin/instance/rules/:id
|
||||
func (c *Converter) InstanceRuleToAdminAPIRule(r *gtsmodel.Rule) *apimodel.AdminInstanceRule {
|
||||
func InstanceRuleToAdminAPIRule(r *gtsmodel.Rule) *apimodel.AdminInstanceRule {
|
||||
return &apimodel.AdminInstanceRule{
|
||||
ID: r.ID,
|
||||
CreatedAt: util.FormatISO8601(r.CreatedAt),
|
||||
|
|
@ -1540,7 +1637,7 @@ func (c *Converter) InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Ins
|
|||
ApprovalRequired: true, // approval always required
|
||||
InvitesEnabled: false, // todo: not supported yet
|
||||
MaxTootChars: uint(config.GetStatusesMaxChars()), // #nosec G115 -- Already validated.
|
||||
Rules: c.InstanceRulesToAPIRules(i.Rules),
|
||||
Rules: InstanceRulesToAPIRules(i.Rules),
|
||||
Terms: i.Terms,
|
||||
TermsRaw: i.TermsText,
|
||||
}
|
||||
|
|
@ -1674,7 +1771,7 @@ func (c *Converter) InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Ins
|
|||
CustomCSS: i.CustomCSS,
|
||||
Usage: apimodel.InstanceV2Usage{}, // todo: not implemented
|
||||
Languages: config.GetInstanceLanguages().TagStrs(),
|
||||
Rules: c.InstanceRulesToAPIRules(i.Rules),
|
||||
Rules: InstanceRulesToAPIRules(i.Rules),
|
||||
Terms: i.Terms,
|
||||
TermsText: i.TermsText,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue