diff --git a/internal/api/model/webpushsubscription.go b/internal/api/model/webpushsubscription.go index a28bb7294..38d6cf7ed 100644 --- a/internal/api/model/webpushsubscription.go +++ b/internal/api/model/webpushsubscription.go @@ -138,6 +138,8 @@ type WebPushSubscriptionUpdateRequest struct { DataAlertsPendingFavourite *bool `form:"data[alerts][pending.favourite]" json:"-"` DataAlertsPendingReply *bool `form:"data[alerts][pending.reply]" json:"-"` DataAlertsPendingReblog *bool `form:"data[alerts][pending.reblog]" json:"-"` + + DataPolicy *WebPushNotificationPolicy `form:"data[policy]" json:"-"` } // WebPushSubscriptionRequestData is the part of a Web Push subscription that can be changed after creation. @@ -146,6 +148,9 @@ type WebPushSubscriptionUpdateRequest struct { type WebPushSubscriptionRequestData struct { // Alerts selects the specific events that this Web Push subscription will receive. Alerts *WebPushSubscriptionAlerts `form:"-" json:"alerts"` + + // Policy selects which accounts will trigger Web Push notifications. + Policy *WebPushNotificationPolicy `form:"-" json:"policy"` } // WebPushNotificationPolicy names sets of accounts that can generate notifications. @@ -154,4 +159,10 @@ type WebPushNotificationPolicy string const ( // WebPushNotificationPolicyAll allows all accounts to send notifications to the subscribing user. WebPushNotificationPolicyAll WebPushNotificationPolicy = "all" + // WebPushNotificationPolicyFollowed allows accounts followed by the subscribing user to send notifications. + WebPushNotificationPolicyFollowed WebPushNotificationPolicy = "followed" + // WebPushNotificationPolicyFollower allows accounts following the subscribing user to send notifications. + WebPushNotificationPolicyFollower WebPushNotificationPolicy = "follower" + // WebPushNotificationPolicyNone doesn't allow any acounts to send notifications to the subscribing user. + WebPushNotificationPolicyNone WebPushNotificationPolicy = "none" ) diff --git a/internal/db/bundb/migrations/20250131184755_add_web_push_subscription_policy.go b/internal/db/bundb/migrations/20250131184755_add_web_push_subscription_policy.go new file mode 100644 index 000000000..d833a669f --- /dev/null +++ b/internal/db/bundb/migrations/20250131184755_add_web_push_subscription_policy.go @@ -0,0 +1,83 @@ +// 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 . + +package migrations + +import ( + "context" + "reflect" + "strings" + + "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect" +) + +func init() { + up := func(ctx context.Context, db *bun.DB) error { + return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + model := >smodel.WebPushSubscription{} + + // Get the column definition for the new policy column. + modelType := reflect.TypeOf(model) + columnDef, err := getBunColumnDef(tx, modelType, "Policy") + if err != nil { + return err + } + + // Add the policy column. + switch tx.Dialect().Name() { + case dialect.SQLite: + // Doesn't support Bun feature AlterColumnExists. + if _, err = tx. + NewAddColumn(). + Model(model). + ColumnExpr(columnDef). + Exec(ctx); // nocollapse + err != nil && !strings.Contains(err.Error(), "duplicate column name") { + // Return errors that aren't about this column already existing. + return err + } + + case dialect.PG: + // Supports Bun feature AlterColumnExists. + if _, err = tx. + NewAddColumn(). + Model(model). + ColumnExpr(columnDef). + IfNotExists(). + Exec(ctx); // nocollapse + err != nil { + return err + } + + default: + panic("unsupported db type") + } + + return nil + }) + } + + down := func(ctx context.Context, db *bun.DB) error { + return nil + } + + if err := Migrations.Register(up, down); err != nil { + panic(err) + } +} diff --git a/internal/gtsmodel/webpushsubscription.go b/internal/gtsmodel/webpushsubscription.go index 4aeef654a..1e310bc50 100644 --- a/internal/gtsmodel/webpushsubscription.go +++ b/internal/gtsmodel/webpushsubscription.go @@ -39,12 +39,15 @@ type WebPushSubscription struct { // P256dh is a Base64-encoded Diffie-Hellman public key on the P-256 elliptic curve. P256dh string `bun:",nullzero,notnull"` - // NotificationFlags controls which notifications are delivered to a given subscription. - // Corresponds to model.PushSubscriptionAlerts. + // NotificationFlags controls which notifications are delivered to this subscription. NotificationFlags WebPushSubscriptionNotificationFlags `bun:",notnull"` + + // Policy controls which accounts are allowed to trigger notifications for this subscription. + Policy WebPushNotificationPolicy `bun:",nullzero,notnull,default:1"` } // WebPushSubscriptionNotificationFlags is a bitfield representation of a set of NotificationType. +// Corresponds to apimodel.WebPushSubscriptionAlerts. type WebPushSubscriptionNotificationFlags int64 // WebPushSubscriptionNotificationFlagsFromSlice packs a slice of NotificationType into a WebPushSubscriptionNotificationFlags. @@ -80,3 +83,18 @@ func (n *WebPushSubscriptionNotificationFlags) Set(notificationType Notification *n &= ^(1 << notificationType) } } + +// WebPushNotificationPolicy represents the notification policy of a Web Push subscription. +// Corresponds to apimodel.WebPushNotificationPolicy. +type WebPushNotificationPolicy enumType + +const ( + // WebPushNotificationPolicyAll allows all accounts to send notifications to the subscribing user. + WebPushNotificationPolicyAll WebPushNotificationPolicy = 1 + // WebPushNotificationPolicyFollowed allows accounts followed by the subscribing user to send notifications. + WebPushNotificationPolicyFollowed WebPushNotificationPolicy = 2 + // WebPushNotificationPolicyFollower allows accounts following the subscribing user to send notifications. + WebPushNotificationPolicyFollower WebPushNotificationPolicy = 3 + // WebPushNotificationPolicyNone doesn't allow any accounts to send notifications to the subscribing user. + WebPushNotificationPolicyNone WebPushNotificationPolicy = 4 +)