mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:32:25 -05:00 
			
		
		
		
	[bugfix] Rework MultiError to wrap + unwrap errors properly (#2057)
* rework multierror a bit * test multierror
This commit is contained in:
		
					parent
					
						
							
								2cee8f2dd8
							
						
					
				
			
			
				commit
				
					
						e8a20f587c
					
				
			
		
					 24 changed files with 263 additions and 154 deletions
				
			
		|  | @ -75,14 +75,14 @@ func setupPrune(ctx context.Context) (*prune, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *prune) shutdown(ctx context.Context) error { | func (p *prune) shutdown(ctx context.Context) error { | ||||||
| 	var errs gtserror.MultiError | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	if err := p.storage.Close(); err != nil { | 	if err := p.storage.Close(); err != nil { | ||||||
| 		errs.Appendf("error closing storage backend: %v", err) | 		errs.Appendf("error closing storage backend: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := p.dbService.Stop(ctx); err != nil { | 	if err := p.dbService.Stop(ctx); err != nil { | ||||||
| 		errs.Appendf("error stopping database: %v", err) | 		errs.Appendf("error stopping database: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	p.state.Workers.Stop() | 	p.state.Workers.Stop() | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -105,16 +104,16 @@ func (suite *InboxPostTestSuite) inboxPost( | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// Check expected code + body. | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we got an expected body, return early. | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -90,16 +90,16 @@ func (suite *AccountUpdateTestSuite) updateAccount( | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// Check expected code + body. | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we got an expected body, return early. | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package accounts_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -63,16 +62,16 @@ func (suite *ListsTestSuite) getLists(targetAccountID string, expectedHTTPStatus | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// Check expected code + body. | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we got an expected body, return early. | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package accounts_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -99,16 +98,16 @@ func (suite *AccountSearchTestSuite) getSearch( | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// Check expected code + body. | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we got an expected body, return early. | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package admin_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -84,16 +83,16 @@ func (suite *ReportResolveTestSuite) resolveReport( | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// if we got an expected body, return early | ||||||
| 	if expectedBody != "" { | 	if expectedBody != "" { | ||||||
| 		if string(b) != expectedBody { | 		if string(b) != expectedBody { | ||||||
| 			errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 			errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 		} | 		} | ||||||
| 		return nil, errs.Combine() | 		return nil, errs.Combine() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package admin_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -101,16 +100,16 @@ func (suite *ReportsGetTestSuite) getReports( | ||||||
| 		return nil, "", err | 		return nil, "", err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// if we got an expected body, return early | ||||||
| 	if expectedBody != "" { | 	if expectedBody != "" { | ||||||
| 		if string(b) != expectedBody { | 		if string(b) != expectedBody { | ||||||
| 			errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 			errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 		} | 		} | ||||||
| 		return nil, "", errs.Combine() | 		return nil, "", errs.Combine() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package lists_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -103,17 +102,17 @@ func (suite *ListAccountsTestSuite) getListAccounts( | ||||||
| 		return nil, "", err | 		return nil, "", err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// check code + body | 	// check code + body | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// if we got an expected body, return early | ||||||
| 	if expectedBody != "" { | 	if expectedBody != "" { | ||||||
| 		if string(b) != expectedBody { | 		if string(b) != expectedBody { | ||||||
| 			errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 			errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 		} | 		} | ||||||
| 		return nil, "", errs.Combine() | 		return nil, "", errs.Combine() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package reports_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -77,17 +76,17 @@ func (suite *ReportCreateTestSuite) createReport(expectedHTTPStatus int, expecte | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// check code + body | 	// check code + body | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// if we got an expected body, return early | ||||||
| 	if expectedBody != "" { | 	if expectedBody != "" { | ||||||
| 		if string(b) != expectedBody { | 		if string(b) != expectedBody { | ||||||
| 			errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 			errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 		} | 		} | ||||||
| 		return nil, errs.Combine() | 		return nil, errs.Combine() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package reports_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -64,17 +63,17 @@ func (suite *ReportGetTestSuite) getReport(expectedHTTPStatus int, expectedBody | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// check code + body | 	// check code + body | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// if we got an expected body, return early | ||||||
| 	if expectedBody != "" { | 	if expectedBody != "" { | ||||||
| 		if string(b) != expectedBody { | 		if string(b) != expectedBody { | ||||||
| 			errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 			errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 		} | 		} | ||||||
| 		return nil, errs.Combine() | 		return nil, errs.Combine() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ import ( | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
| 	"crypto/rsa" | 	"crypto/rsa" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -122,16 +121,16 @@ func (suite *SearchGetTestSuite) getSearch( | ||||||
| 		suite.FailNow(err.Error()) | 		suite.FailNow(err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// Check expected code + body. | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d: %v", expectedHTTPStatus, resultCode, ctx.Errors.JSON())) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If we got an expected body, return early. | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ package statuses_test | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -74,20 +73,20 @@ func (suite *StatusPinTestSuite) createPin( | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// check code + body | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(errs) > 0 { | 	if err := errs.Combine(); err != nil { | ||||||
| 		return nil, errs.Combine() | 		suite.FailNow("", "%v (body %s)", err, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	resp := &apimodel.Status{} | 	resp := &apimodel.Status{} | ||||||
|  |  | ||||||
|  | @ -19,7 +19,6 @@ package statuses_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
|  | @ -68,20 +67,20 @@ func (suite *StatusUnpinTestSuite) createUnpin( | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	errs := gtserror.MultiError{} | 	errs := gtserror.NewMultiError(2) | ||||||
| 
 | 
 | ||||||
| 	// check code + body | 	// Check expected code + body. | ||||||
| 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | 	if resultCode := recorder.Code; expectedHTTPStatus != resultCode { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) | 		errs.Appendf("expected %d got %d", expectedHTTPStatus, resultCode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// if we got an expected body, return early | 	// If we got an expected body, return early. | ||||||
| 	if expectedBody != "" && string(b) != expectedBody { | 	if expectedBody != "" && string(b) != expectedBody { | ||||||
| 		errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) | 		errs.Appendf("expected %s got %s", expectedBody, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(errs) > 0 { | 	if err := errs.Combine(); err != nil { | ||||||
| 		return nil, errs.Combine() | 		suite.FailNow("", "%v (body %s)", err, string(b)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	resp := &apimodel.Status{} | 	resp := &apimodel.Status{} | ||||||
|  |  | ||||||
|  | @ -83,19 +83,23 @@ func (c *Cleaner) removeFiles(ctx context.Context, files ...string) (int, error) | ||||||
| 		return len(files), nil | 		return len(files), nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var errs gtserror.MultiError | 	var ( | ||||||
|  | 		errs     gtserror.MultiError | ||||||
|  | 		errCount int | ||||||
|  | 	) | ||||||
| 
 | 
 | ||||||
| 	for _, path := range files { | 	for _, path := range files { | ||||||
| 		// Remove each provided storage path. | 		// Remove each provided storage path. | ||||||
| 		log.Debugf(ctx, "removing file: %s", path) | 		log.Debugf(ctx, "removing file: %s", path) | ||||||
| 		err := c.state.Storage.Delete(ctx, path) | 		err := c.state.Storage.Delete(ctx, path) | ||||||
| 		if err != nil && !errors.Is(err, storage.ErrNotFound) { | 		if err != nil && !errors.Is(err, storage.ErrNotFound) { | ||||||
| 			errs.Appendf("error removing %s: %v", path, err) | 			errs.Appendf("error removing %s: %w", path, err) | ||||||
|  | 			errCount++ | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Calculate no. files removed. | 	// Calculate no. files removed. | ||||||
| 	diff := len(files) - len(errs) | 	diff := len(files) - errCount | ||||||
| 
 | 
 | ||||||
| 	// Wrap the combined error slice. | 	// Wrap the combined error slice. | ||||||
| 	if err := errs.Combine(); err != nil { | 	if err := errs.Combine(); err != nil { | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ package bundb | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | @ -255,7 +254,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func( | ||||||
| func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Account) error { | func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Account) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 3) | 		errs = gtserror.NewMultiError(3) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if account.AvatarMediaAttachment == nil && account.AvatarMediaAttachmentID != "" { | 	if account.AvatarMediaAttachment == nil && account.AvatarMediaAttachmentID != "" { | ||||||
|  | @ -265,7 +264,7 @@ func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Accou | ||||||
| 			account.AvatarMediaAttachmentID, | 			account.AvatarMediaAttachmentID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating account avatar: %w", err)) | 			errs.Appendf("error populating account avatar: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -276,7 +275,7 @@ func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Accou | ||||||
| 			account.HeaderMediaAttachmentID, | 			account.HeaderMediaAttachmentID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating account header: %w", err)) | 			errs.Appendf("error populating account header: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -287,11 +286,15 @@ func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Accou | ||||||
| 			account.EmojiIDs, | 			account.EmojiIDs, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating account emojis: %w", err)) | 			errs.Appendf("error populating account emojis: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (a *accountDB) PutAccount(ctx context.Context, account *gtsmodel.Account) error { | func (a *accountDB) PutAccount(ctx context.Context, account *gtsmodel.Account) error { | ||||||
|  |  | ||||||
|  | @ -173,7 +173,7 @@ func (i *instanceDB) getInstance(ctx context.Context, lookup string, dbQuery fun | ||||||
| func (i *instanceDB) populateInstance(ctx context.Context, instance *gtsmodel.Instance) error { | func (i *instanceDB) populateInstance(ctx context.Context, instance *gtsmodel.Instance) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 2) | 		errs = gtserror.NewMultiError(2) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if instance.DomainBlockID != "" && instance.DomainBlock == nil { | 	if instance.DomainBlockID != "" && instance.DomainBlock == nil { | ||||||
|  | @ -183,7 +183,7 @@ func (i *instanceDB) populateInstance(ctx context.Context, instance *gtsmodel.In | ||||||
| 			instance.Domain, | 			instance.Domain, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(gtserror.Newf("error populating instance domain block: %w", err)) | 			errs.Appendf("error populating instance domain block: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -194,11 +194,15 @@ func (i *instanceDB) populateInstance(ctx context.Context, instance *gtsmodel.In | ||||||
| 			instance.ContactAccountID, | 			instance.ContactAccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(gtserror.Newf("error populating instance contact account: %w", err)) | 			errs.Appendf("error populating instance contact account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (i *instanceDB) PutInstance(ctx context.Context, instance *gtsmodel.Instance) error { | func (i *instanceDB) PutInstance(ctx context.Context, instance *gtsmodel.Instance) error { | ||||||
|  |  | ||||||
|  | @ -117,7 +117,7 @@ func (l *listDB) GetListsForAccountID(ctx context.Context, accountID string) ([] | ||||||
| func (l *listDB) PopulateList(ctx context.Context, list *gtsmodel.List) error { | func (l *listDB) PopulateList(ctx context.Context, list *gtsmodel.List) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 2) | 		errs = gtserror.NewMultiError(2) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if list.Account == nil { | 	if list.Account == nil { | ||||||
|  | @ -127,7 +127,7 @@ func (l *listDB) PopulateList(ctx context.Context, list *gtsmodel.List) error { | ||||||
| 			list.AccountID, | 			list.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating list account: %w", err)) | 			errs.Appendf("error populating list account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -139,11 +139,15 @@ func (l *listDB) PopulateList(ctx context.Context, list *gtsmodel.List) error { | ||||||
| 			"", "", "", 0, | 			"", "", "", 0, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating list entries: %w", err)) | 			errs.Appendf("error populating list entries: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (l *listDB) PutList(ctx context.Context, list *gtsmodel.List) error { | func (l *listDB) PutList(ctx context.Context, list *gtsmodel.List) error { | ||||||
|  |  | ||||||
|  | @ -160,7 +160,7 @@ func (r *relationshipDB) getFollow(ctx context.Context, lookup string, dbQuery f | ||||||
| func (r *relationshipDB) PopulateFollow(ctx context.Context, follow *gtsmodel.Follow) error { | func (r *relationshipDB) PopulateFollow(ctx context.Context, follow *gtsmodel.Follow) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 2) | 		errs = gtserror.NewMultiError(2) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if follow.Account == nil { | 	if follow.Account == nil { | ||||||
|  | @ -170,7 +170,7 @@ func (r *relationshipDB) PopulateFollow(ctx context.Context, follow *gtsmodel.Fo | ||||||
| 			follow.AccountID, | 			follow.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating follow account: %w", err)) | 			errs.Appendf("error populating follow account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -181,11 +181,15 @@ func (r *relationshipDB) PopulateFollow(ctx context.Context, follow *gtsmodel.Fo | ||||||
| 			follow.TargetAccountID, | 			follow.TargetAccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating follow target account: %w", err)) | 			errs.Appendf("error populating follow target account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *relationshipDB) PutFollow(ctx context.Context, follow *gtsmodel.Follow) error { | func (r *relationshipDB) PutFollow(ctx context.Context, follow *gtsmodel.Follow) error { | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"database/sql" | 	"database/sql" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
|  | @ -129,7 +128,7 @@ func (s *statusDB) getStatus(ctx context.Context, lookup string, dbQuery func(*g | ||||||
| func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) error { | func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 9) | 		errs = gtserror.NewMultiError(9) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if status.Account == nil { | 	if status.Account == nil { | ||||||
|  | @ -139,7 +138,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.AccountID, | 			status.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status author: %w", err)) | 			errs.Appendf("error populating status author: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -150,7 +149,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.InReplyToID, | 			status.InReplyToID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status parent: %w", err)) | 			errs.Appendf("error populating status parent: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -162,7 +161,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 				status.InReplyToID, | 				status.InReplyToID, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				errs.Append(fmt.Errorf("error populating status parent: %w", err)) | 				errs.Appendf("error populating status parent: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -173,7 +172,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 				status.InReplyToAccountID, | 				status.InReplyToAccountID, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				errs.Append(fmt.Errorf("error populating status parent author: %w", err)) | 				errs.Appendf("error populating status parent author: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -186,7 +185,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 				status.BoostOfID, | 				status.BoostOfID, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				errs.Append(fmt.Errorf("error populating status boost: %w", err)) | 				errs.Appendf("error populating status boost: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -197,7 +196,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 				status.BoostOfAccountID, | 				status.BoostOfAccountID, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				errs.Append(fmt.Errorf("error populating status boost author: %w", err)) | 				errs.Appendf("error populating status boost author: %w", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -209,7 +208,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.AttachmentIDs, | 			status.AttachmentIDs, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status attachments: %w", err)) | 			errs.Appendf("error populating status attachments: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -220,7 +219,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.TagIDs, | 			status.TagIDs, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status tags: %w", err)) | 			errs.Appendf("error populating status tags: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -231,7 +230,7 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.MentionIDs, | 			status.MentionIDs, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status mentions: %w", err)) | 			errs.Appendf("error populating status mentions: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -242,11 +241,15 @@ func (s *statusDB) PopulateStatus(ctx context.Context, status *gtsmodel.Status) | ||||||
| 			status.EmojiIDs, | 			status.EmojiIDs, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status emojis: %w", err)) | 			errs.Appendf("error populating status emojis: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *statusDB) PutStatus(ctx context.Context, status *gtsmodel.Status) error { | func (s *statusDB) PutStatus(ctx context.Context, status *gtsmodel.Status) error { | ||||||
|  |  | ||||||
|  | @ -149,7 +149,7 @@ func (s *statusFaveDB) GetStatusFavesForStatus(ctx context.Context, statusID str | ||||||
| func (s *statusFaveDB) PopulateStatusFave(ctx context.Context, statusFave *gtsmodel.StatusFave) error { | func (s *statusFaveDB) PopulateStatusFave(ctx context.Context, statusFave *gtsmodel.StatusFave) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = make(gtserror.MultiError, 0, 3) | 		errs = gtserror.NewMultiError(3) | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	if statusFave.Account == nil { | 	if statusFave.Account == nil { | ||||||
|  | @ -159,7 +159,7 @@ func (s *statusFaveDB) PopulateStatusFave(ctx context.Context, statusFave *gtsmo | ||||||
| 			statusFave.AccountID, | 			statusFave.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status fave author: %w", err)) | 			errs.Appendf("error populating status fave author: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -170,7 +170,7 @@ func (s *statusFaveDB) PopulateStatusFave(ctx context.Context, statusFave *gtsmo | ||||||
| 			statusFave.TargetAccountID, | 			statusFave.TargetAccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status fave target account: %w", err)) | 			errs.Appendf("error populating status fave target account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -181,11 +181,15 @@ func (s *statusFaveDB) PopulateStatusFave(ctx context.Context, statusFave *gtsmo | ||||||
| 			statusFave.StatusID, | 			statusFave.StatusID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			errs.Append(fmt.Errorf("error populating status fave status: %w", err)) | 			errs.Appendf("error populating status fave status: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *statusFaveDB) PutStatusFave(ctx context.Context, fave *gtsmodel.StatusFave) error { | func (s *statusFaveDB) PutStatusFave(ctx context.Context, fave *gtsmodel.StatusFave) error { | ||||||
|  |  | ||||||
|  | @ -20,25 +20,48 @@ package gtserror | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strings" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // MultiError allows encapsulating multiple errors under a singular instance, | // MultiError allows encapsulating multiple | ||||||
| // which is useful when you only want to log on errors, not return early / bubble up. | // errors under a singular instance, which | ||||||
| type MultiError []string | // is useful when you only want to log on | ||||||
| 
 | // errors, not return early / bubble up. | ||||||
| func (e *MultiError) Append(err error) { | type MultiError struct { | ||||||
| 	*e = append(*e, err.Error()) | 	e []error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (e *MultiError) Appendf(format string, args ...any) { | // NewMultiError returns a *MultiError with | ||||||
| 	*e = append(*e, fmt.Sprintf(format, args...)) | // the capacity of its underlying error slice | ||||||
| } | // set to the provided value. | ||||||
| 
 | // | ||||||
| // Combine converts this multiError to a singular error instance, returning nil if empty. | // This capacity can be exceeded if necessary, | ||||||
| func (e MultiError) Combine() error { | // but it saves a teeny tiny bit of memory if | ||||||
| 	if len(e) == 0 { | // callers set it correctly. | ||||||
| 		return nil | // | ||||||
|  | // If you don't know in advance what the capacity | ||||||
|  | // must be, just use new(MultiError) instead. | ||||||
|  | func NewMultiError(capacity int) *MultiError { | ||||||
|  | 	return &MultiError{ | ||||||
|  | 		e: make([]error, 0, capacity), | ||||||
| 	} | 	} | ||||||
| 	return errors.New(`"` + strings.Join(e, `","`) + `"`) | } | ||||||
|  | 
 | ||||||
|  | // Append the given error to the MultiError. | ||||||
|  | func (m *MultiError) Append(err error) { | ||||||
|  | 	m.e = append(m.e, err) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Append the given format string to the MultiError. | ||||||
|  | // | ||||||
|  | // It is valid to use %w in the format string | ||||||
|  | // to wrap any other errors. | ||||||
|  | func (m *MultiError) Appendf(format string, args ...any) { | ||||||
|  | 	m.e = append(m.e, fmt.Errorf(format, args...)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Combine the MultiError into a single error. | ||||||
|  | // | ||||||
|  | // Unwrap will work on the returned error as expected. | ||||||
|  | func (m MultiError) Combine() error { | ||||||
|  | 	return errors.Join(m.e...) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										64
									
								
								internal/gtserror/multi_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								internal/gtserror/multi_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | ||||||
|  | // GoToSocial | ||||||
|  | // Copyright (C) GoToSocial Authors admin@gotosocial.org | ||||||
|  | // SPDX-License-Identifier: AGPL-3.0-or-later | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU Affero General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | // GNU Affero General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU Affero General Public License | ||||||
|  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | package gtserror | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestMultiError(t *testing.T) { | ||||||
|  | 	errs := MultiError{ | ||||||
|  | 		e: []error{ | ||||||
|  | 			db.ErrNoEntries, | ||||||
|  | 			errors.New("oopsie woopsie we did a fucky wucky etc"), | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	errs.Appendf("appended + wrapped error: %w", db.ErrAlreadyExists) | ||||||
|  | 
 | ||||||
|  | 	err := errs.Combine() | ||||||
|  | 
 | ||||||
|  | 	if !errors.Is(err, db.ErrNoEntries) { | ||||||
|  | 		t.Error("should be db.ErrNoEntries") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !errors.Is(err, db.ErrAlreadyExists) { | ||||||
|  | 		t.Error("should be db.ErrAlreadyExists") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if errors.Is(err, db.ErrBusyTimeout) { | ||||||
|  | 		t.Error("should not be db.ErrBusyTimeout") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	errString := err.Error() | ||||||
|  | 	expected := `sql: no rows in result set | ||||||
|  | oopsie woopsie we did a fucky wucky etc | ||||||
|  | appended + wrapped error: already exists` | ||||||
|  | 	if errString != expected { | ||||||
|  | 		t.Errorf("errString '%s' should be '%s'", errString, expected) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestMultiErrorEmpty(t *testing.T) { | ||||||
|  | 	err := new(MultiError).Combine() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("should be nil") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -20,7 +20,6 @@ package processing | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/config" | 	"github.com/superseriousbusiness/gotosocial/internal/config" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
|  | @ -42,13 +41,13 @@ import ( | ||||||
| func (p *Processor) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel.Status) error { | func (p *Processor) timelineAndNotifyStatus(ctx context.Context, status *gtsmodel.Status) error { | ||||||
| 	// Ensure status fully populated; including account, mentions, etc. | 	// Ensure status fully populated; including account, mentions, etc. | ||||||
| 	if err := p.state.DB.PopulateStatus(ctx, status); err != nil { | 	if err := p.state.DB.PopulateStatus(ctx, status); err != nil { | ||||||
| 		return fmt.Errorf("timelineAndNotifyStatus: error populating status with id %s: %w", status.ID, err) | 		return gtserror.Newf("error populating status with id %s: %w", status.ID, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Get local followers of the account that posted the status. | 	// Get local followers of the account that posted the status. | ||||||
| 	follows, err := p.state.DB.GetAccountLocalFollowers(ctx, status.AccountID) | 	follows, err := p.state.DB.GetAccountLocalFollowers(ctx, status.AccountID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("timelineAndNotifyStatus: error getting local followers for account id %s: %w", status.AccountID, err) | 		return gtserror.Newf("error getting local followers for account id %s: %w", status.AccountID, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// If the poster is also local, add a fake entry for them | 	// If the poster is also local, add a fake entry for them | ||||||
|  | @ -66,12 +65,12 @@ func (p *Processor) timelineAndNotifyStatus(ctx context.Context, status *gtsmode | ||||||
| 	// This will also handle notifying any followers with notify | 	// This will also handle notifying any followers with notify | ||||||
| 	// set to true on their follow. | 	// set to true on their follow. | ||||||
| 	if err := p.timelineAndNotifyStatusForFollowers(ctx, status, follows); err != nil { | 	if err := p.timelineAndNotifyStatusForFollowers(ctx, status, follows); err != nil { | ||||||
| 		return fmt.Errorf("timelineAndNotifyStatus: error timelining status %s for followers: %w", status.ID, err) | 		return gtserror.Newf("error timelining status %s for followers: %w", status.ID, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Notify each local account that's mentioned by this status. | 	// Notify each local account that's mentioned by this status. | ||||||
| 	if err := p.notifyStatusMentions(ctx, status); err != nil { | 	if err := p.notifyStatusMentions(ctx, status); err != nil { | ||||||
| 		return fmt.Errorf("timelineAndNotifyStatus: error notifying status mentions for status %s: %w", status.ID, err) | 		return gtserror.Newf("error notifying status mentions for status %s: %w", status.ID, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -79,7 +78,7 @@ func (p *Processor) timelineAndNotifyStatus(ctx context.Context, status *gtsmode | ||||||
| 
 | 
 | ||||||
| func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, status *gtsmodel.Status, follows []*gtsmodel.Follow) error { | func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, status *gtsmodel.Status, follows []*gtsmodel.Follow) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		errs  = make(gtserror.MultiError, 0, len(follows)) | 		errs  = gtserror.NewMultiError(len(follows)) | ||||||
| 		boost = status.BoostOfID != "" | 		boost = status.BoostOfID != "" | ||||||
| 		reply = status.InReplyToURI != "" | 		reply = status.InReplyToURI != "" | ||||||
| 	) | 	) | ||||||
|  | @ -100,7 +99,7 @@ func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, sta | ||||||
| 			follow.ID, | 			follow.ID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil && !errors.Is(err, db.ErrNoEntries) { | 		if err != nil && !errors.Is(err, db.ErrNoEntries) { | ||||||
| 			errs.Append(fmt.Errorf("timelineAndNotifyStatusForFollowers: error list timelining status: %w", err)) | 			errs.Appendf("error list timelining status: %w", err) | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -113,7 +112,7 @@ func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, sta | ||||||
| 				status, | 				status, | ||||||
| 				stream.TimelineList+":"+listEntry.ListID, // key streamType to this specific list | 				stream.TimelineList+":"+listEntry.ListID, // key streamType to this specific list | ||||||
| 			); err != nil { | 			); err != nil { | ||||||
| 				errs.Append(fmt.Errorf("timelineAndNotifyStatusForFollowers: error list timelining status: %w", err)) | 				errs.Appendf("error list timelining status: %w", err) | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -128,7 +127,7 @@ func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, sta | ||||||
| 			status, | 			status, | ||||||
| 			stream.TimelineHome, | 			stream.TimelineHome, | ||||||
| 		); err != nil { | 		); err != nil { | ||||||
| 			errs.Append(fmt.Errorf("timelineAndNotifyStatusForFollowers: error home timelining status: %w", err)) | 			errs.Appendf("error home timelining status: %w", err) | ||||||
| 			continue | 			continue | ||||||
| 		} else if !timelined { | 		} else if !timelined { | ||||||
| 			// Status wasn't added to home tomeline, | 			// Status wasn't added to home tomeline, | ||||||
|  | @ -162,11 +161,15 @@ func (p *Processor) timelineAndNotifyStatusForFollowers(ctx context.Context, sta | ||||||
| 			status.AccountID, | 			status.AccountID, | ||||||
| 			status.ID, | 			status.ID, | ||||||
| 		); err != nil { | 		); err != nil { | ||||||
| 			errs.Append(fmt.Errorf("timelineAndNotifyStatusForFollowers: error notifying account %s about new status: %w", follow.AccountID, err)) | 			errs.Appendf("error notifying account %s about new status: %w", follow.AccountID, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // timelineStatus uses the provided ingest function to put the given | // timelineStatus uses the provided ingest function to put the given | ||||||
|  | @ -185,7 +188,7 @@ func (p *Processor) timelineStatus( | ||||||
| 	// Make sure the status is timelineable. | 	// Make sure the status is timelineable. | ||||||
| 	// This works for both home and list timelines. | 	// This works for both home and list timelines. | ||||||
| 	if timelineable, err := p.filter.StatusHomeTimelineable(ctx, account, status); err != nil { | 	if timelineable, err := p.filter.StatusHomeTimelineable(ctx, account, status); err != nil { | ||||||
| 		err = fmt.Errorf("timelineStatusForAccount: error getting timelineability for status for timeline with id %s: %w", account.ID, err) | 		err = gtserror.Newf("error getting timelineability for status for timeline with id %s: %w", account.ID, err) | ||||||
| 		return false, err | 		return false, err | ||||||
| 	} else if !timelineable { | 	} else if !timelineable { | ||||||
| 		// Nothing to do. | 		// Nothing to do. | ||||||
|  | @ -194,7 +197,7 @@ func (p *Processor) timelineStatus( | ||||||
| 
 | 
 | ||||||
| 	// Ingest status into given timeline using provided function. | 	// Ingest status into given timeline using provided function. | ||||||
| 	if inserted, err := ingest(ctx, timelineID, status); err != nil { | 	if inserted, err := ingest(ctx, timelineID, status); err != nil { | ||||||
| 		err = fmt.Errorf("timelineStatusForAccount: error ingesting status %s: %w", status.ID, err) | 		err = gtserror.Newf("error ingesting status %s: %w", status.ID, err) | ||||||
| 		return false, err | 		return false, err | ||||||
| 	} else if !inserted { | 	} else if !inserted { | ||||||
| 		// Nothing more to do. | 		// Nothing more to do. | ||||||
|  | @ -204,12 +207,12 @@ func (p *Processor) timelineStatus( | ||||||
| 	// The status was inserted so stream it to the user. | 	// The status was inserted so stream it to the user. | ||||||
| 	apiStatus, err := p.tc.StatusToAPIStatus(ctx, status, account) | 	apiStatus, err := p.tc.StatusToAPIStatus(ctx, status, account) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		err = fmt.Errorf("timelineStatusForAccount: error converting status %s to frontend representation: %w", status.ID, err) | 		err = gtserror.Newf("error converting status %s to frontend representation: %w", status.ID, err) | ||||||
| 		return true, err | 		return true, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := p.stream.Update(apiStatus, account, []string{streamType}); err != nil { | 	if err := p.stream.Update(apiStatus, account, []string{streamType}); err != nil { | ||||||
| 		err = fmt.Errorf("timelineStatusForAccount: error streaming update for status %s: %w", status.ID, err) | 		err = gtserror.Newf("error streaming update for status %s: %w", status.ID, err) | ||||||
| 		return true, err | 		return true, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -217,7 +220,7 @@ func (p *Processor) timelineStatus( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *Processor) notifyStatusMentions(ctx context.Context, status *gtsmodel.Status) error { | func (p *Processor) notifyStatusMentions(ctx context.Context, status *gtsmodel.Status) error { | ||||||
| 	errs := make(gtserror.MultiError, 0, len(status.Mentions)) | 	errs := gtserror.NewMultiError(len(status.Mentions)) | ||||||
| 
 | 
 | ||||||
| 	for _, m := range status.Mentions { | 	for _, m := range status.Mentions { | ||||||
| 		if err := p.notify( | 		if err := p.notify( | ||||||
|  | @ -231,7 +234,11 @@ func (p *Processor) notifyStatusMentions(ctx context.Context, status *gtsmodel.S | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return errs.Combine() | 	if err := errs.Combine(); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *Processor) notifyFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest) error { | func (p *Processor) notifyFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest) error { | ||||||
|  | @ -255,13 +262,13 @@ func (p *Processor) notifyFollow(ctx context.Context, follow *gtsmodel.Follow, t | ||||||
| 	) | 	) | ||||||
| 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | ||||||
| 		// Proper error while checking. | 		// Proper error while checking. | ||||||
| 		return fmt.Errorf("notifyFollow: db error checking for previous follow request notification: %w", err) | 		return gtserror.Newf("db error checking for previous follow request notification: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if prevNotif != nil { | 	if prevNotif != nil { | ||||||
| 		// Previous notification existed, delete. | 		// Previous notification existed, delete. | ||||||
| 		if err := p.state.DB.DeleteNotificationByID(ctx, prevNotif.ID); err != nil { | 		if err := p.state.DB.DeleteNotificationByID(ctx, prevNotif.ID); err != nil { | ||||||
| 			return fmt.Errorf("notifyFollow: db error removing previous follow request notification %s: %w", prevNotif.ID, err) | 			return gtserror.Newf("db error removing previous follow request notification %s: %w", prevNotif.ID, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -319,7 +326,7 @@ func (p *Processor) notify( | ||||||
| ) error { | ) error { | ||||||
| 	targetAccount, err := p.state.DB.GetAccountByID(ctx, targetAccountID) | 	targetAccount, err := p.state.DB.GetAccountByID(ctx, targetAccountID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("notify: error getting target account %s: %w", targetAccountID, err) | 		return gtserror.Newf("error getting target account %s: %w", targetAccountID, err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !targetAccount.IsLocal() { | 	if !targetAccount.IsLocal() { | ||||||
|  | @ -340,7 +347,7 @@ func (p *Processor) notify( | ||||||
| 		return nil | 		return nil | ||||||
| 	} else if !errors.Is(err, db.ErrNoEntries) { | 	} else if !errors.Is(err, db.ErrNoEntries) { | ||||||
| 		// Real error. | 		// Real error. | ||||||
| 		return fmt.Errorf("notify: error checking existence of notification: %w", err) | 		return gtserror.Newf("error checking existence of notification: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Notification doesn't yet exist, so | 	// Notification doesn't yet exist, so | ||||||
|  | @ -354,17 +361,17 @@ func (p *Processor) notify( | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := p.state.DB.PutNotification(ctx, notif); err != nil { | 	if err := p.state.DB.PutNotification(ctx, notif); err != nil { | ||||||
| 		return fmt.Errorf("notify: error putting notification in database: %w", err) | 		return gtserror.Newf("error putting notification in database: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Stream notification to the user. | 	// Stream notification to the user. | ||||||
| 	apiNotif, err := p.tc.NotificationToAPINotification(ctx, notif) | 	apiNotif, err := p.tc.NotificationToAPINotification(ctx, notif) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("notify: error converting notification to api representation: %w", err) | 		return gtserror.Newf("error converting notification to api representation: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := p.stream.Notify(apiNotif, targetAccount); err != nil { | 	if err := p.stream.Notify(apiNotif, targetAccount); err != nil { | ||||||
| 		return fmt.Errorf("notify: error streaming notification to account: %w", err) | 		return gtserror.Newf("error streaming notification to account: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -479,7 +486,7 @@ func (p *Processor) invalidateStatusFromTimelines(ctx context.Context, statusID | ||||||
| func (p *Processor) emailReport(ctx context.Context, report *gtsmodel.Report) error { | func (p *Processor) emailReport(ctx context.Context, report *gtsmodel.Report) error { | ||||||
| 	instance, err := p.state.DB.GetInstance(ctx, config.GetHost()) | 	instance, err := p.state.DB.GetInstance(ctx, config.GetHost()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("emailReport: error getting instance: %w", err) | 		return gtserror.Newf("error getting instance: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	toAddresses, err := p.state.DB.GetInstanceModeratorAddresses(ctx) | 	toAddresses, err := p.state.DB.GetInstanceModeratorAddresses(ctx) | ||||||
|  | @ -488,20 +495,20 @@ func (p *Processor) emailReport(ctx context.Context, report *gtsmodel.Report) er | ||||||
| 			// No registered moderator addresses. | 			// No registered moderator addresses. | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| 		return fmt.Errorf("emailReport: error getting instance moderator addresses: %w", err) | 		return gtserror.Newf("error getting instance moderator addresses: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if report.Account == nil { | 	if report.Account == nil { | ||||||
| 		report.Account, err = p.state.DB.GetAccountByID(ctx, report.AccountID) | 		report.Account, err = p.state.DB.GetAccountByID(ctx, report.AccountID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("emailReport: error getting report account: %w", err) | 			return gtserror.Newf("error getting report account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if report.TargetAccount == nil { | 	if report.TargetAccount == nil { | ||||||
| 		report.TargetAccount, err = p.state.DB.GetAccountByID(ctx, report.TargetAccountID) | 		report.TargetAccount, err = p.state.DB.GetAccountByID(ctx, report.TargetAccountID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("emailReport: error getting report target account: %w", err) | 			return gtserror.Newf("error getting report target account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -514,7 +521,7 @@ func (p *Processor) emailReport(ctx context.Context, report *gtsmodel.Report) er | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := p.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { | 	if err := p.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { | ||||||
| 		return fmt.Errorf("emailReport: error emailing instance moderators: %w", err) | 		return gtserror.Newf("error emailing instance moderators: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -523,7 +530,7 @@ func (p *Processor) emailReport(ctx context.Context, report *gtsmodel.Report) er | ||||||
| func (p *Processor) emailReportClosed(ctx context.Context, report *gtsmodel.Report) error { | func (p *Processor) emailReportClosed(ctx context.Context, report *gtsmodel.Report) error { | ||||||
| 	user, err := p.state.DB.GetUserByAccountID(ctx, report.Account.ID) | 	user, err := p.state.DB.GetUserByAccountID(ctx, report.Account.ID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("emailReportClosed: db error getting user: %w", err) | 		return gtserror.Newf("db error getting user: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if user.ConfirmedAt.IsZero() || !*user.Approved || *user.Disabled || user.Email == "" { | 	if user.ConfirmedAt.IsZero() || !*user.Approved || *user.Disabled || user.Email == "" { | ||||||
|  | @ -537,20 +544,20 @@ func (p *Processor) emailReportClosed(ctx context.Context, report *gtsmodel.Repo | ||||||
| 
 | 
 | ||||||
| 	instance, err := p.state.DB.GetInstance(ctx, config.GetHost()) | 	instance, err := p.state.DB.GetInstance(ctx, config.GetHost()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("emailReportClosed: db error getting instance: %w", err) | 		return gtserror.Newf("db error getting instance: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if report.Account == nil { | 	if report.Account == nil { | ||||||
| 		report.Account, err = p.state.DB.GetAccountByID(ctx, report.AccountID) | 		report.Account, err = p.state.DB.GetAccountByID(ctx, report.AccountID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("emailReportClosed: error getting report account: %w", err) | 			return gtserror.Newf("error getting report account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if report.TargetAccount == nil { | 	if report.TargetAccount == nil { | ||||||
| 		report.TargetAccount, err = p.state.DB.GetAccountByID(ctx, report.TargetAccountID) | 		report.TargetAccount, err = p.state.DB.GetAccountByID(ctx, report.TargetAccountID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("emailReportClosed: error getting report target account: %w", err) | 			return gtserror.Newf("error getting report target account: %w", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -190,18 +190,18 @@ func (m *manager) GetOldestIndexedID(ctx context.Context, timelineID string) str | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *manager) WipeItemFromAllTimelines(ctx context.Context, itemID string) error { | func (m *manager) WipeItemFromAllTimelines(ctx context.Context, itemID string) error { | ||||||
| 	errors := gtserror.MultiError{} | 	errs := new(gtserror.MultiError) | ||||||
| 
 | 
 | ||||||
| 	m.timelines.Range(func(_ any, v any) bool { | 	m.timelines.Range(func(_ any, v any) bool { | ||||||
| 		if _, err := v.(Timeline).Remove(ctx, itemID); err != nil { | 		if _, err := v.(Timeline).Remove(ctx, itemID); err != nil { | ||||||
| 			errors.Append(err) | 			errs.Append(err) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return true // always continue range | 		return true // always continue range | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	if len(errors) > 0 { | 	if err := errs.Combine(); err != nil { | ||||||
| 		return gtserror.Newf("error(s) wiping status %s: %w", itemID, errors.Combine()) | 		return gtserror.Newf("error(s) wiping status %s: %w", itemID, errs.Combine()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | @ -213,21 +213,21 @@ func (m *manager) WipeItemsFromAccountID(ctx context.Context, timelineID string, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *manager) UnprepareItemFromAllTimelines(ctx context.Context, itemID string) error { | func (m *manager) UnprepareItemFromAllTimelines(ctx context.Context, itemID string) error { | ||||||
| 	errors := gtserror.MultiError{} | 	errs := new(gtserror.MultiError) | ||||||
| 
 | 
 | ||||||
| 	// Work through all timelines held by this | 	// Work through all timelines held by this | ||||||
| 	// manager, and call Unprepare for each. | 	// manager, and call Unprepare for each. | ||||||
| 	m.timelines.Range(func(_ any, v any) bool { | 	m.timelines.Range(func(_ any, v any) bool { | ||||||
| 		// nolint:forcetypeassert | 		// nolint:forcetypeassert | ||||||
| 		if err := v.(Timeline).Unprepare(ctx, itemID); err != nil { | 		if err := v.(Timeline).Unprepare(ctx, itemID); err != nil { | ||||||
| 			errors.Append(err) | 			errs.Append(err) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return true // always continue range | 		return true // always continue range | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	if len(errors) > 0 { | 	if err := errs.Combine(); err != nil { | ||||||
| 		return gtserror.Newf("error(s) unpreparing status %s: %w", itemID, errors.Combine()) | 		return gtserror.Newf("error(s) unpreparing status %s: %w", itemID, errs.Combine()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue