2024-12-22 16:18:04 +00:00
|
|
|
// 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 subscriptions
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-12-24 17:05:20 +00:00
|
|
|
"encoding/csv"
|
|
|
|
"errors"
|
|
|
|
"time"
|
2024-12-22 16:18:04 +00:00
|
|
|
|
2024-12-24 17:05:20 +00:00
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
2024-12-22 16:18:04 +00:00
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/state"
|
2024-12-24 17:05:20 +00:00
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/transport"
|
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
2024-12-22 16:18:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Subscriptions struct {
|
2024-12-24 17:05:20 +00:00
|
|
|
state *state.State
|
|
|
|
transportController transport.Controller
|
2024-12-22 16:18:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Subscriptions) UpdateDomainPermissions(
|
|
|
|
ctx context.Context,
|
|
|
|
permType gtsmodel.DomainPermissionType,
|
|
|
|
) {
|
|
|
|
l := log.
|
|
|
|
WithContext(ctx).
|
|
|
|
WithField("permType", permType.String())
|
|
|
|
l.Info("start")
|
|
|
|
|
|
|
|
// Get permission subscriptions in priority order (highest -> lowest).
|
|
|
|
permSubs, err := s.state.DB.GetDomainPermissionSubscriptionsByPriority(ctx, permType)
|
2024-12-24 17:05:20 +00:00
|
|
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
|
|
|
// Real db error.
|
2024-12-22 16:18:04 +00:00
|
|
|
l.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(permSubs) == 0 {
|
2024-12-24 17:05:20 +00:00
|
|
|
// No subscriptions of this
|
|
|
|
// type, so nothing to do.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a transport using the instance account,
|
|
|
|
// we can reuse this for each HTTP call.
|
|
|
|
tsport, err := s.transportController.NewTransportForUsername(ctx, "")
|
|
|
|
if err != nil {
|
|
|
|
l.Error(err)
|
2024-12-22 16:18:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, permSub := range permSubs {
|
2024-12-24 17:05:20 +00:00
|
|
|
// Set FetchedAt as we're
|
|
|
|
// going to attempt this now.
|
|
|
|
permSub.FetchedAt = time.Now()
|
|
|
|
columns := []string{"fetched_at"}
|
|
|
|
|
|
|
|
// Call the URI but don't force.
|
|
|
|
resp, err := tsport.DereferenceDomainPermissions(
|
|
|
|
ctx, permSub, false,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
// Bollocks, couldn't get this one.
|
|
|
|
// Just save the error in the db
|
|
|
|
// for later perusal by admin.
|
|
|
|
permSub.Error = err.Error()
|
|
|
|
columns = append(columns, "error")
|
|
|
|
if err := s.state.DB.UpdateDomainPermissionSubscription(
|
|
|
|
ctx, permSub, columns...,
|
|
|
|
); err != nil {
|
|
|
|
// Real db error.
|
|
|
|
l.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip to the
|
|
|
|
// next permSub.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the permissions at URI weren't modified
|
|
|
|
// since last time, just update some metadata
|
|
|
|
// and call this a successful fetch.
|
|
|
|
if resp.Unmodified {
|
|
|
|
permSub.SuccessfullyFetchedAt = time.Now()
|
|
|
|
columns = append(columns, "successfully_fetched_at")
|
2024-12-22 16:18:04 +00:00
|
|
|
|
2024-12-24 17:05:20 +00:00
|
|
|
if permSub.ETag == "" && resp.ETag != "" {
|
|
|
|
// We didn't have an ETag before but
|
|
|
|
// we have one now: probably the remote
|
|
|
|
// added ETag support in the meantime.
|
|
|
|
permSub.ETag = resp.ETag
|
|
|
|
columns = append(columns, "etag")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.state.DB.UpdateDomainPermissionSubscription(
|
|
|
|
ctx, permSub, columns...,
|
|
|
|
); err != nil {
|
|
|
|
// Real db error.
|
|
|
|
l.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip to the
|
|
|
|
// next permSub.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point we know we got a 200 OK from
|
|
|
|
// the URI, so we've got a live body. Make sure
|
|
|
|
// we close it when done, wrapping the close func
|
|
|
|
// with DoOnce for more granular control.
|
|
|
|
close := util.DoOnce(func() { resp.Body.Close() })
|
|
|
|
defer close()
|
|
|
|
|
|
|
|
// Try to parse the body as a
|
|
|
|
// list of domain permissions.
|
|
|
|
switch permSub.ContentType {
|
|
|
|
|
|
|
|
// text/csv
|
|
|
|
case gtsmodel.DomainPermSubContentTypeCSV:
|
|
|
|
records, err := csv.NewReader(resp.Body).ReadAll()
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// application/json
|
|
|
|
case gtsmodel.DomainPermSubContentTypeJSON:
|
|
|
|
|
|
|
|
// text/plain
|
|
|
|
case gtsmodel.DomainPermSubContentTypePlain:
|
|
|
|
}
|
|
|
|
|
|
|
|
// Slice of permission subscriptions that have
|
|
|
|
// a higher priority than this one. We should
|
|
|
|
// not override perms if they already exist
|
|
|
|
// under a higher-priority subscription.
|
|
|
|
higherPrios := permSubs[:i]
|
2024-12-22 16:18:04 +00:00
|
|
|
}
|
|
|
|
}
|