diff options
author | 2025-01-05 13:20:33 +0100 | |
---|---|---|
committer | 2025-01-05 13:20:33 +0100 | |
commit | e9bb7ddd3aa11da5c48a75c4a600f8fe5cc1c990 (patch) | |
tree | a2897775112a821aa093b6e2686044814912001f /internal/processing | |
parent | [chore] Update robots.txt with more AI bots (#3634) (diff) | |
download | gotosocial-e9bb7ddd3aa11da5c48a75c4a600f8fe5cc1c990.tar.xz |
[feature] Create/update/remove domain permission subscriptions (#3623)
* [feature] Create/update/remove domain permission subscriptions
* lint
* envparsing
* remove errant fmt.Println
* create drafts, subs, exclude, from snapshot models
* name etag column correctly
* remove count column
* lint
Diffstat (limited to 'internal/processing')
-rw-r--r-- | internal/processing/admin/domainpermissionsubscription.go | 285 | ||||
-rw-r--r-- | internal/processing/admin/util.go | 16 |
2 files changed, 301 insertions, 0 deletions
diff --git a/internal/processing/admin/domainpermissionsubscription.go b/internal/processing/admin/domainpermissionsubscription.go new file mode 100644 index 000000000..3d2f63d56 --- /dev/null +++ b/internal/processing/admin/domainpermissionsubscription.go @@ -0,0 +1,285 @@ +// 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 admin + +import ( + "context" + "errors" + "fmt" + "net/url" + + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "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/paging" +) + +// DomainPermissionSubscriptionGet returns one +// domain permission subscription with the given id. +func (p *Processor) DomainPermissionSubscriptionGet( + ctx context.Context, + id string, +) (*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + permSub, err := p.state.DB.GetDomainPermissionSubscriptionByID(ctx, id) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + err := gtserror.Newf("db error getting domain permission subscription %s: %w", id, err) + return nil, gtserror.NewErrorInternalError(err) + } + + if permSub == nil { + err := fmt.Errorf("domain permission subscription %s not found", id) + return nil, gtserror.NewErrorNotFound(err, err.Error()) + } + + return p.apiDomainPermSub(ctx, permSub) +} + +// DomainPermissionSubscriptionsGet returns a page of +// DomainPermissionSubscriptions with the given parameters. +func (p *Processor) DomainPermissionSubscriptionsGet( + ctx context.Context, + permType gtsmodel.DomainPermissionType, + page *paging.Page, +) (*apimodel.PageableResponse, gtserror.WithCode) { + permSubs, err := p.state.DB.GetDomainPermissionSubscriptions( + ctx, + permType, + page, + ) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + err := gtserror.Newf("db error: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + count := len(permSubs) + if count == 0 { + return paging.EmptyResponse(), nil + } + + // Get the lowest and highest + // ID values, used for paging. + lo := permSubs[count-1].ID + hi := permSubs[0].ID + + // Convert each perm sub to API model. + items := make([]any, len(permSubs)) + for i, permSub := range permSubs { + apiPermSub, err := p.converter.DomainPermSubToAPIDomainPermSub(ctx, permSub) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + items[i] = apiPermSub + } + + // Assemble next/prev page queries. + query := make(url.Values, 1) + if permType != gtsmodel.DomainPermissionUnknown { + query.Set(apiutil.DomainPermissionPermTypeKey, permType.String()) + } + + return paging.PackageResponse(paging.ResponseParams{ + Items: items, + Path: "/api/v1/admin/domain_permission_subscriptions", + Next: page.Next(lo, hi), + Prev: page.Prev(lo, hi), + Query: query, + }), nil +} + +// DomainPermissionSubscriptionsGetByPriority returns all domain permission +// subscriptions of the given permission type, in descending priority order. +func (p *Processor) DomainPermissionSubscriptionsGetByPriority( + ctx context.Context, + permType gtsmodel.DomainPermissionType, +) ([]*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + permSubs, err := p.state.DB.GetDomainPermissionSubscriptionsByPriority( + ctx, + permType, + ) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + err := gtserror.Newf("db error: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + // Convert each perm sub to API model. + items := make([]*apimodel.DomainPermissionSubscription, len(permSubs)) + for i, permSub := range permSubs { + apiPermSub, err := p.converter.DomainPermSubToAPIDomainPermSub(ctx, permSub) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + items[i] = apiPermSub + } + + return items, nil +} + +func (p *Processor) DomainPermissionSubscriptionCreate( + ctx context.Context, + acct *gtsmodel.Account, + priority uint8, + title string, + uri string, + contentType gtsmodel.DomainPermSubContentType, + permType gtsmodel.DomainPermissionType, + asDraft bool, + fetchUsername string, + fetchPassword string, +) (*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + permSub := >smodel.DomainPermissionSubscription{ + ID: id.NewULID(), + Priority: priority, + Title: title, + PermissionType: permType, + AsDraft: &asDraft, + CreatedByAccountID: acct.ID, + CreatedByAccount: acct, + URI: uri, + ContentType: contentType, + FetchUsername: fetchUsername, + FetchPassword: fetchPassword, + } + + err := p.state.DB.PutDomainPermissionSubscription(ctx, permSub) + if err != nil { + if errors.Is(err, db.ErrAlreadyExists) { + // Unique constraint conflict. + const errText = "domain permission subscription with given URI or title already exists" + return nil, gtserror.NewErrorConflict(errors.New(errText), errText) + } + + // Real database error. + err := gtserror.Newf("db error putting domain permission subscription: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + return p.apiDomainPermSub(ctx, permSub) +} + +func (p *Processor) DomainPermissionSubscriptionUpdate( + ctx context.Context, + id string, + priority *uint8, + title *string, + uri *string, + contentType *gtsmodel.DomainPermSubContentType, + asDraft *bool, + adoptOrphans *bool, + fetchUsername *string, + fetchPassword *string, +) (*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + permSub, err := p.state.DB.GetDomainPermissionSubscriptionByID(ctx, id) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + err := gtserror.Newf("db error getting domain permission subscription %s: %w", id, err) + return nil, gtserror.NewErrorInternalError(err) + } + + if permSub == nil { + err := fmt.Errorf("domain permission subscription %s not found", id) + return nil, gtserror.NewErrorNotFound(err, err.Error()) + } + + columns := make([]string, 0, 7) + + if priority != nil { + permSub.Priority = *priority + columns = append(columns, "priority") + } + + if title != nil { + permSub.Title = *title + columns = append(columns, "title") + } + + if uri != nil { + permSub.URI = *uri + columns = append(columns, "uri") + } + + if contentType != nil { + permSub.ContentType = *contentType + columns = append(columns, "content_type") + } + + if asDraft != nil { + permSub.AsDraft = asDraft + columns = append(columns, "as_draft") + } + + if adoptOrphans != nil { + permSub.AdoptOrphans = adoptOrphans + columns = append(columns, "adopt_orphans") + } + + if fetchPassword != nil { + permSub.FetchPassword = *fetchPassword + columns = append(columns, "fetch_password") + } + + if fetchUsername != nil { + permSub.FetchUsername = *fetchUsername + columns = append(columns, "fetch_username") + } + + err = p.state.DB.UpdateDomainPermissionSubscription(ctx, permSub, columns...) + if err != nil { + if errors.Is(err, db.ErrAlreadyExists) { + // Unique constraint conflict. + const errText = "domain permission subscription with given URI or title already exists" + return nil, gtserror.NewErrorConflict(errors.New(errText), errText) + } + + // Real database error. + err := gtserror.Newf("db error updating domain permission subscription: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + return p.apiDomainPermSub(ctx, permSub) +} + +func (p *Processor) DomainPermissionSubscriptionRemove( + ctx context.Context, + id string, + removeChildren bool, +) (*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + permSub, err := p.state.DB.GetDomainPermissionSubscriptionByID(ctx, id) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + err := gtserror.Newf("db error getting domain permission subscription %s: %w", id, err) + return nil, gtserror.NewErrorInternalError(err) + } + + if permSub == nil { + err := fmt.Errorf("domain permission subscription %s not found", id) + return nil, gtserror.NewErrorNotFound(err, err.Error()) + } + + // TODO in next PR: if removeChildren, then remove all + // domain permissions that are children of this domain + // permission subscription. If not removeChildren, then + // just unlink them by clearing their subscription ID. + // For now just delete the domain permission subscription. + if err := p.state.DB.DeleteDomainPermissionSubscription(ctx, id); err != nil { + err := gtserror.Newf("db error deleting domain permission subscription: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + return p.apiDomainPermSub(ctx, permSub) +} diff --git a/internal/processing/admin/util.go b/internal/processing/admin/util.go index bc59a2b3b..aef435856 100644 --- a/internal/processing/admin/util.go +++ b/internal/processing/admin/util.go @@ -115,3 +115,19 @@ func (p *Processor) apiDomainPerm( return apiDomainPerm, nil } + +// apiDomainPermSub is a cheeky shortcut for returning the +// API version of the given domain permission subscription, +// or an appropriate error if something goes wrong. +func (p *Processor) apiDomainPermSub( + ctx context.Context, + domainPermSub *gtsmodel.DomainPermissionSubscription, +) (*apimodel.DomainPermissionSubscription, gtserror.WithCode) { + apiDomainPermSub, err := p.converter.DomainPermSubToAPIDomainPermSub(ctx, domainPermSub) + if err != nil { + err := gtserror.NewfAt(3, "error converting domain permission subscription to api model: %w", err) + return nil, gtserror.NewErrorInternalError(err) + } + + return apiDomainPermSub, nil +} |