···15151616 "github.com/labstack/echo/v4"
1717 dto "github.com/prometheus/client_model/go"
1818- "gorm.io/gorm"
1918)
20192120// this is the same as the regular com.atproto.sync.requestCrawl endpoint, except it sets a flag to bypass configuration checks
···8584 return err
8685 }
87868888- if err := s.relay.UpdateAccountStatus(ctx, did, models.AccountStatusTakendown); err != nil {
8989- if errors.Is(err, gorm.ErrRecordNotFound) {
8787+ if err := s.relay.UpdateAccountLocalStatus(ctx, did, models.AccountStatusTakendown, true); err != nil {
8888+ if errors.Is(err, relay.ErrAccountNotFound) {
9089 return &echo.HTTPError{
9190 Code: http.StatusNotFound,
9291 Message: "account not found",
···112111 return err
113112 }
114113115115- if err := s.relay.UpdateAccountStatus(ctx, did, models.AccountStatusActive); err != nil {
116116- if errors.Is(err, gorm.ErrRecordNotFound) {
114114+ if err := s.relay.UpdateAccountLocalStatus(ctx, did, models.AccountStatusActive, true); err != nil {
115115+ if errors.Is(err, relay.ErrAccountNotFound) {
117116 return &echo.HTTPError{
118117 Code: http.StatusNotFound,
119118 Message: "repo not found",
+40-2
cmd/relay/relay/account.go
···66 "fmt"
77 "strings"
8899+ comatproto "github.com/bluesky-social/indigo/api/atproto"
910 "github.com/bluesky-social/indigo/atproto/syntax"
1011 "github.com/bluesky-social/indigo/cmd/relay/relay/models"
1212+ "github.com/bluesky-social/indigo/cmd/relay/stream"
11131214 "gorm.io/gorm"
1315)
···181183 return nil
182184}
183185184184-func (r *Relay) UpdateAccountStatus(ctx context.Context, did syntax.DID, status models.AccountStatus) error {
186186+// This updates the account's "upstream" status (eg, at the account's PDS). Usually this is called in response to an `#account` event.
187187+//
188188+// The DID and UID are both required, and *must* match; it is assumed that calling code has already done an account lookup.
189189+func (r *Relay) UpdateAccountUpstreamStatus(ctx context.Context, did syntax.DID, uid uint64, status models.AccountStatus) error {
190190+191191+ if err := r.db.Model(models.Account{}).Where("uid = ?", uid).Update("upstream_status", status).Error; err != nil {
192192+ return err
193193+ }
194194+195195+ // clear account cache
196196+ r.accountCache.Remove(did.String())
197197+198198+ return nil
199199+}
200200+201201+// This method updates the "local" account status (as opposed to "upstream" status, eg at the account's PDS).
202202+//
203203+// If the `emitEvent` flag is set true, a `#account` event is broadcase. This should be used for account-level takedowns.
204204+func (r *Relay) UpdateAccountLocalStatus(ctx context.Context, did syntax.DID, status models.AccountStatus, emitEvent bool) error {
185205 acc, err := r.GetAccount(ctx, did)
186206 if err != nil {
187207 return err
···194214 // clear account cache
195215 r.accountCache.Remove(did.String())
196216197197- // NOTE: not wiping events for user from persister (backfill window)
217217+ // update copy of row for computing public status field
218218+ acc.Status = status
219219+220220+ if emitEvent {
221221+ err = r.Events.AddEvent(ctx, &stream.XRPCStreamEvent{
222222+ RepoAccount: &comatproto.SyncSubscribeRepos_Account{
223223+ Active: acc.IsActive(),
224224+ Did: acc.DID,
225225+ Status: acc.StatusField(),
226226+ Time: syntax.DatetimeNow().String(),
227227+ },
228228+ PrivUid: acc.UID,
229229+ })
230230+ if err != nil {
231231+ r.Logger.Error("failed to emit #account event after status change", "did", did, "newStatus", status, "error", err)
232232+ return fmt.Errorf("failed to broadcast #account event: %w", err)
233233+ }
234234+ }
235235+198236 return nil
199237}
200238