mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 07:22:24 -05:00
[chore] migration to update statuses.thread_id to be notnull (#4160)
# Description This is quite a complex database migration that updates the `statuses.thread_id` column to be notnull, in order that statuses always be threaded, which will be useful in various pieces of upcoming work. This is unfortunately a migration that acts over the entire statuses table, and is quite complex in order to ensure that all existing statuses get correctly threaded together, and where possible fix any issues of statuses in the same thread having incorrect thread_ids. TODO: - ~~update testrig models to all be threaded~~ - ~~update code to ensure thread_id is always set~~ - ~~run on **a copy** of an sqlite production database~~ - ~~run on **a copy** of a postgres production database~~ ## Checklist - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [ ] I/we have made any necessary changes to documentation. - [x] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4160 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
fd64a1e264
commit
311d9a1697
19 changed files with 1660 additions and 386 deletions
|
|
@ -101,7 +101,7 @@ func (d *Dereferencer) EnrichAnnounce(
|
|||
// Generate an ID for the boost wrapper status.
|
||||
boost.ID = id.NewULIDFromTime(boost.CreatedAt)
|
||||
|
||||
// Store the boost wrapper status in database.
|
||||
// Store the remote boost wrapper status in database.
|
||||
switch err = d.state.DB.PutStatus(ctx, boost); {
|
||||
case err == nil:
|
||||
// all groovy.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"code.superseriousbusiness.org/gotosocial/internal/ap"
|
||||
|
|
@ -571,15 +570,6 @@ func (d *Dereferencer) enrichStatus(
|
|||
return nil, nil, gtserror.Newf("error populating mentions for status %s: %w", uri, err)
|
||||
}
|
||||
|
||||
// Ensure status in a thread is connected.
|
||||
threadChanged, err := d.threadStatus(ctx,
|
||||
status,
|
||||
latestStatus,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, gtserror.Newf("error handling threading for status %s: %w", uri, err)
|
||||
}
|
||||
|
||||
// Populate tags associated with status, passing
|
||||
// in existing status to reuse old where possible.
|
||||
tagsChanged, err := d.fetchStatusTags(ctx,
|
||||
|
|
@ -614,7 +604,7 @@ func (d *Dereferencer) enrichStatus(
|
|||
}
|
||||
|
||||
if isNew {
|
||||
// Simplest case, insert this new status into the database.
|
||||
// Simplest case, insert this new remote status into the database.
|
||||
if err := d.state.DB.PutStatus(ctx, latestStatus); err != nil {
|
||||
return nil, nil, gtserror.Newf("error inserting new status %s: %w", uri, err)
|
||||
}
|
||||
|
|
@ -627,7 +617,6 @@ func (d *Dereferencer) enrichStatus(
|
|||
latestStatus,
|
||||
pollChanged,
|
||||
mentionsChanged,
|
||||
threadChanged,
|
||||
tagsChanged,
|
||||
mediaChanged,
|
||||
emojiChanged,
|
||||
|
|
@ -736,81 +725,6 @@ func (d *Dereferencer) fetchStatusMentions(
|
|||
return changed, nil
|
||||
}
|
||||
|
||||
// threadStatus ensures that given status is threaded correctly
|
||||
// where necessary. that is it will inherit a thread ID from the
|
||||
// existing copy if it is threaded correctly, else it will inherit
|
||||
// a thread ID from a parent with existing thread, else it will
|
||||
// generate a new thread ID if status mentions a local account.
|
||||
func (d *Dereferencer) threadStatus(
|
||||
ctx context.Context,
|
||||
existing *gtsmodel.Status,
|
||||
status *gtsmodel.Status,
|
||||
) (
|
||||
changed bool,
|
||||
err error,
|
||||
) {
|
||||
|
||||
// Check for existing status
|
||||
// that is already threaded.
|
||||
if existing.ThreadID != "" {
|
||||
|
||||
// Existing is threaded correctly.
|
||||
if existing.InReplyTo == nil ||
|
||||
existing.InReplyTo.ThreadID == existing.ThreadID {
|
||||
status.ThreadID = existing.ThreadID
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// TODO: delete incorrect thread
|
||||
}
|
||||
|
||||
// Check for existing parent to inherit threading from.
|
||||
if inReplyTo := status.InReplyTo; inReplyTo != nil &&
|
||||
inReplyTo.ThreadID != "" {
|
||||
status.ThreadID = inReplyTo.ThreadID
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Parent wasn't threaded. If this
|
||||
// status mentions a local account,
|
||||
// we should thread it so that local
|
||||
// account can mute it if they want.
|
||||
mentionsLocal := slices.ContainsFunc(
|
||||
status.Mentions,
|
||||
func(m *gtsmodel.Mention) bool {
|
||||
// If TargetAccount couldn't
|
||||
// be deref'd, we know it's not
|
||||
// a local account, so only
|
||||
// check for non-nil accounts.
|
||||
return m.TargetAccount != nil &&
|
||||
m.TargetAccount.IsLocal()
|
||||
},
|
||||
)
|
||||
|
||||
if !mentionsLocal {
|
||||
// Status doesn't mention a
|
||||
// local account, so we don't
|
||||
// need to thread it.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Status mentions a local account.
|
||||
// Create a new thread and assign
|
||||
// it to the status.
|
||||
threadID := id.NewULID()
|
||||
|
||||
// Insert new thread model into db.
|
||||
if err := d.state.DB.PutThread(ctx,
|
||||
>smodel.Thread{ID: threadID},
|
||||
); err != nil {
|
||||
return false, gtserror.Newf("error inserting new thread in db: %w", err)
|
||||
}
|
||||
|
||||
// Set thread on latest status.
|
||||
status.ThreadID = threadID
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// fetchStatusTags populates the tags on 'status', fetching existing
|
||||
// from the database and creating new where needed. 'existing' is used
|
||||
// to fetch tags that have not changed since previous stored status.
|
||||
|
|
@ -1135,7 +1049,6 @@ func (d *Dereferencer) handleStatusEdit(
|
|||
status *gtsmodel.Status,
|
||||
pollChanged bool,
|
||||
mentionsChanged bool,
|
||||
threadChanged bool,
|
||||
tagsChanged bool,
|
||||
mediaChanged bool,
|
||||
emojiChanged bool,
|
||||
|
|
@ -1193,14 +1106,6 @@ func (d *Dereferencer) handleStatusEdit(
|
|||
// been previously populated properly.
|
||||
}
|
||||
|
||||
if threadChanged {
|
||||
cols = append(cols, "thread_id")
|
||||
|
||||
// Thread changed doesn't necessarily
|
||||
// indicate an edit, it may just now
|
||||
// actually be included in a thread.
|
||||
}
|
||||
|
||||
if tagsChanged {
|
||||
cols = append(cols, "tags") // i.e. TagIDs
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue