diff options
Diffstat (limited to 'internal/processing')
-rw-r--r-- | internal/processing/fromclientapi.go | 13 | ||||
-rw-r--r-- | internal/processing/processor.go | 11 | ||||
-rw-r--r-- | internal/processing/report.go | 39 | ||||
-rw-r--r-- | internal/processing/report/create.go | 103 | ||||
-rw-r--r-- | internal/processing/report/getreport.go | 51 | ||||
-rw-r--r-- | internal/processing/report/getreports.go | 79 | ||||
-rw-r--r-- | internal/processing/report/report.go | 51 |
7 files changed, 347 insertions, 0 deletions
diff --git a/internal/processing/fromclientapi.go b/internal/processing/fromclientapi.go index d2512632e..997e76691 100644 --- a/internal/processing/fromclientapi.go +++ b/internal/processing/fromclientapi.go @@ -121,6 +121,12 @@ func (p *processor) ProcessFromClientAPI(ctx context.Context, clientMsg messages // DELETE ACCOUNT/PROFILE return p.processDeleteAccountFromClientAPI(ctx, clientMsg) } + case ap.ActivityFlag: + // FLAG + if clientMsg.APObjectType == ap.ObjectProfile { + // FLAG/REPORT A PROFILE + return p.processReportAccountFromClientAPI(ctx, clientMsg) + } } return nil } @@ -338,6 +344,13 @@ func (p *processor) processDeleteAccountFromClientAPI(ctx context.Context, clien return p.accountProcessor.Delete(ctx, clientMsg.TargetAccount, origin) } +func (p *processor) processReportAccountFromClientAPI(ctx context.Context, clientMsg messages.FromClientAPI) error { + // TODO: in a separate PR, handle side effects of flag/report + // 1. email admin(s) + // 2. federate report if necessary + return nil +} + // TODO: move all the below functions into federation.Federator func (p *processor) federateAccountDelete(ctx context.Context, account *gtsmodel.Account) error { diff --git a/internal/processing/processor.go b/internal/processing/processor.go index 0967ab9d2..692523042 100644 --- a/internal/processing/processor.go +++ b/internal/processing/processor.go @@ -38,6 +38,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/processing/admin" federationProcessor "github.com/superseriousbusiness/gotosocial/internal/processing/federation" mediaProcessor "github.com/superseriousbusiness/gotosocial/internal/processing/media" + "github.com/superseriousbusiness/gotosocial/internal/processing/report" "github.com/superseriousbusiness/gotosocial/internal/processing/status" "github.com/superseriousbusiness/gotosocial/internal/processing/streaming" "github.com/superseriousbusiness/gotosocial/internal/processing/user" @@ -232,6 +233,13 @@ type Processor interface { // The user belonging to the confirmed email is also returned. UserConfirmEmail(ctx context.Context, token string) (*gtsmodel.User, gtserror.WithCode) + // ReportsGet returns reports created by the given user. + ReportsGet(ctx context.Context, authed *oauth.Auth, resolved *bool, targetAccountID string, maxID string, sinceID string, minID string, limit int) (*apimodel.PageableResponse, gtserror.WithCode) + // ReportGet returns one report created by the given user. + ReportGet(ctx context.Context, authed *oauth.Auth, id string) (*apimodel.Report, gtserror.WithCode) + // ReportCreate creates a new report using the given account and form. + ReportCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.ReportCreateRequest) (*apimodel.Report, gtserror.WithCode) + /* FEDERATION API-FACING PROCESSING FUNCTIONS These functions are intended to be called when the federating client needs an immediate (ie., synchronous) reply @@ -303,6 +311,7 @@ type processor struct { mediaProcessor mediaProcessor.Processor userProcessor user.Processor federationProcessor federationProcessor.Processor + reportProcessor report.Processor } // NewProcessor returns a new Processor. @@ -326,6 +335,7 @@ func NewProcessor( mediaProcessor := mediaProcessor.New(db, tc, mediaManager, federator.TransportController(), storage) userProcessor := user.New(db, emailSender) federationProcessor := federationProcessor.New(db, tc, federator) + reportProcessor := report.New(db, tc, clientWorker) filter := visibility.NewFilter(db) return &processor{ @@ -348,6 +358,7 @@ func NewProcessor( mediaProcessor: mediaProcessor, userProcessor: userProcessor, federationProcessor: federationProcessor, + reportProcessor: reportProcessor, } } diff --git a/internal/processing/report.go b/internal/processing/report.go new file mode 100644 index 000000000..9bbaa3226 --- /dev/null +++ b/internal/processing/report.go @@ -0,0 +1,39 @@ +/* + GoToSocial + Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org + + 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 processing + +import ( + "context" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +func (p *processor) ReportsGet(ctx context.Context, authed *oauth.Auth, resolved *bool, targetAccountID string, maxID string, sinceID string, minID string, limit int) (*apimodel.PageableResponse, gtserror.WithCode) { + return p.reportProcessor.ReportsGet(ctx, authed.Account, resolved, targetAccountID, maxID, sinceID, minID, limit) +} + +func (p *processor) ReportGet(ctx context.Context, authed *oauth.Auth, id string) (*apimodel.Report, gtserror.WithCode) { + return p.reportProcessor.ReportGet(ctx, authed.Account, id) +} + +func (p *processor) ReportCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.ReportCreateRequest) (*apimodel.Report, gtserror.WithCode) { + return p.reportProcessor.Create(ctx, authed.Account, form) +} diff --git a/internal/processing/report/create.go b/internal/processing/report/create.go new file mode 100644 index 000000000..ac4c4390d --- /dev/null +++ b/internal/processing/report/create.go @@ -0,0 +1,103 @@ +/* + GoToSocial + Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org + + 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 report + +import ( + "context" + "errors" + "fmt" + + "github.com/superseriousbusiness/gotosocial/internal/ap" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/id" + "github.com/superseriousbusiness/gotosocial/internal/messages" + "github.com/superseriousbusiness/gotosocial/internal/uris" +) + +func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, form *apimodel.ReportCreateRequest) (*apimodel.Report, gtserror.WithCode) { + if account.ID == form.AccountID { + err := errors.New("cannot report your own account") + return nil, gtserror.NewErrorBadRequest(err, err.Error()) + } + + // validate + fetch target account + targetAccount, err := p.db.GetAccountByID(ctx, form.AccountID) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + err = fmt.Errorf("account with ID %s does not exist", form.AccountID) + return nil, gtserror.NewErrorBadRequest(err, err.Error()) + } + err = fmt.Errorf("db error fetching report target account: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + // fetch statuses by IDs given in the report form (noop if no statuses given) + statuses, err := p.db.GetStatuses(ctx, form.StatusIDs) + if err != nil { + err = fmt.Errorf("db error fetching report target statuses: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + for _, s := range statuses { + if s.AccountID != form.AccountID { + err = fmt.Errorf("status with ID %s does not belong to account %s", s.ID, form.AccountID) + return nil, gtserror.NewErrorBadRequest(err, err.Error()) + } + } + + reportID, err := id.NewULID() + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + + report := >smodel.Report{ + ID: reportID, + URI: uris.GenerateURIForReport(reportID), + AccountID: account.ID, + Account: account, + TargetAccountID: form.AccountID, + TargetAccount: targetAccount, + Comment: form.Comment, + StatusIDs: form.StatusIDs, + Statuses: statuses, + Forwarded: &form.Forward, + } + + if err := p.db.PutReport(ctx, report); err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + + p.clientWorker.Queue(messages.FromClientAPI{ + APObjectType: ap.ObjectProfile, + APActivityType: ap.ActivityFlag, + GTSModel: report, + OriginAccount: account, + }) + + apiReport, err := p.tc.ReportToAPIReport(ctx, report) + if err != nil { + err = fmt.Errorf("error converting report to frontend representation: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + return apiReport, nil +} diff --git a/internal/processing/report/getreport.go b/internal/processing/report/getreport.go new file mode 100644 index 000000000..6d4a18daa --- /dev/null +++ b/internal/processing/report/getreport.go @@ -0,0 +1,51 @@ +/* + GoToSocial + Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org + + 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 report + +import ( + "context" + "fmt" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func (p *processor) ReportGet(ctx context.Context, account *gtsmodel.Account, id string) (*apimodel.Report, gtserror.WithCode) { + report, err := p.db.GetReportByID(ctx, id) + if err != nil { + if err == db.ErrNoEntries { + return nil, gtserror.NewErrorNotFound(err) + } + return nil, gtserror.NewErrorInternalError(err) + } + + if report.AccountID != account.ID { + err = fmt.Errorf("report with id %s does not belong to account %s", report.ID, account.ID) + return nil, gtserror.NewErrorNotFound(err) + } + + apiReport, err := p.tc.ReportToAPIReport(ctx, report) + if err != nil { + return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err)) + } + + return apiReport, nil +} diff --git a/internal/processing/report/getreports.go b/internal/processing/report/getreports.go new file mode 100644 index 000000000..e58e847a2 --- /dev/null +++ b/internal/processing/report/getreports.go @@ -0,0 +1,79 @@ +/* + GoToSocial + Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org + + 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 report + +import ( + "context" + "fmt" + "strconv" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/util" +) + +func (p *processor) ReportsGet(ctx context.Context, account *gtsmodel.Account, resolved *bool, targetAccountID string, maxID string, sinceID string, minID string, limit int) (*apimodel.PageableResponse, gtserror.WithCode) { + reports, err := p.db.GetReports(ctx, resolved, account.ID, targetAccountID, maxID, sinceID, minID, limit) + if err != nil { + if err == db.ErrNoEntries { + return util.EmptyPageableResponse(), nil + } + return nil, gtserror.NewErrorInternalError(err) + } + + count := len(reports) + items := make([]interface{}, 0, count) + nextMaxIDValue := "" + prevMinIDValue := "" + for i, r := range reports { + item, err := p.tc.ReportToAPIReport(ctx, r) + if err != nil { + return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err)) + } + + if i == count-1 { + nextMaxIDValue = item.ID + } + + if i == 0 { + prevMinIDValue = item.ID + } + + items = append(items, item) + } + + extraQueryParams := []string{} + if resolved != nil { + extraQueryParams = append(extraQueryParams, "resolved="+strconv.FormatBool(*resolved)) + } + if targetAccountID != "" { + extraQueryParams = append(extraQueryParams, "target_account_id="+targetAccountID) + } + + return util.PackagePageableResponse(util.PageableResponseParams{ + Items: items, + Path: "/api/v1/reports", + NextMaxIDValue: nextMaxIDValue, + PrevMinIDValue: prevMinIDValue, + Limit: limit, + ExtraQueryParams: extraQueryParams, + }) +} diff --git a/internal/processing/report/report.go b/internal/processing/report/report.go new file mode 100644 index 000000000..8658ac808 --- /dev/null +++ b/internal/processing/report/report.go @@ -0,0 +1,51 @@ +/* + GoToSocial + Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org + + 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 report + +import ( + "context" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/concurrency" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/messages" + "github.com/superseriousbusiness/gotosocial/internal/typeutils" +) + +type Processor interface { + ReportsGet(ctx context.Context, account *gtsmodel.Account, resolved *bool, targetAccountID string, maxID string, sinceID string, minID string, limit int) (*apimodel.PageableResponse, gtserror.WithCode) + ReportGet(ctx context.Context, account *gtsmodel.Account, id string) (*apimodel.Report, gtserror.WithCode) + Create(ctx context.Context, account *gtsmodel.Account, form *apimodel.ReportCreateRequest) (*apimodel.Report, gtserror.WithCode) +} + +type processor struct { + db db.DB + tc typeutils.TypeConverter + clientWorker *concurrency.WorkerPool[messages.FromClientAPI] +} + +func New(db db.DB, tc typeutils.TypeConverter, clientWorker *concurrency.WorkerPool[messages.FromClientAPI]) Processor { + return &processor{ + tc: tc, + db: db, + clientWorker: clientWorker, + } +} |