-
-
Notifications
You must be signed in to change notification settings - Fork 365
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[bugfix] Fix filter title unique constraint (#3458)
- Loading branch information
1 parent
0d0314b
commit fab7d17
Showing
5 changed files
with
259 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
internal/db/bundb/migrations/20240126064004_add_filters/filter.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// GoToSocial | ||
// Copyright (C) GoToSocial Authors [email protected] | ||
// 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 gtsmodel | ||
|
||
import ( | ||
"regexp" | ||
"time" | ||
) | ||
|
||
// Filter stores a filter created by a local account. | ||
type Filter struct { | ||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database | ||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created | ||
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated | ||
ExpiresAt time.Time `bun:"type:timestamptz,nullzero"` // Time filter should expire. If null, should not expire. | ||
AccountID string `bun:"type:CHAR(26),notnull,nullzero"` // ID of the local account that created the filter. | ||
Title string `bun:",nullzero,notnull,unique"` // The name of the filter. | ||
Action string `bun:",nullzero,notnull"` // The action to take. | ||
Keywords []*FilterKeyword `bun:"-"` // Keywords for this filter. | ||
Statuses []*FilterStatus `bun:"-"` // Statuses for this filter. | ||
ContextHome *bool `bun:",nullzero,notnull,default:false"` // Apply filter to home timeline and lists. | ||
ContextNotifications *bool `bun:",nullzero,notnull,default:false"` // Apply filter to notifications. | ||
ContextPublic *bool `bun:",nullzero,notnull,default:false"` // Apply filter to home timeline and lists. | ||
ContextThread *bool `bun:",nullzero,notnull,default:false"` // Apply filter when viewing a status's associated thread. | ||
ContextAccount *bool `bun:",nullzero,notnull,default:false"` // Apply filter when viewing an account profile. | ||
} | ||
|
||
// FilterKeyword stores a single keyword to filter statuses against. | ||
type FilterKeyword struct { | ||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database | ||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created | ||
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated | ||
AccountID string `bun:"type:CHAR(26),notnull,nullzero"` // ID of the local account that created the filter keyword. | ||
FilterID string `bun:"type:CHAR(26),notnull,nullzero,unique:filter_keywords_filter_id_keyword_uniq"` // ID of the filter that this keyword belongs to. | ||
Filter *Filter `bun:"-"` // Filter corresponding to FilterID | ||
Keyword string `bun:",nullzero,notnull,unique:filter_keywords_filter_id_keyword_uniq"` // The keyword or phrase to filter against. | ||
WholeWord *bool `bun:",nullzero,notnull,default:false"` // Should the filter consider word boundaries? | ||
Regexp *regexp.Regexp `bun:"-"` // pre-prepared regular expression | ||
} | ||
|
||
// FilterStatus stores a single status to filter. | ||
type FilterStatus struct { | ||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database | ||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created | ||
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated | ||
AccountID string `bun:"type:CHAR(26),notnull,nullzero"` // ID of the local account that created the filter keyword. | ||
FilterID string `bun:"type:CHAR(26),notnull,nullzero,unique:filter_statuses_filter_id_status_id_uniq"` // ID of the filter that this keyword belongs to. | ||
Filter *Filter `bun:"-"` // Filter corresponding to FilterID | ||
StatusID string `bun:"type:CHAR(26),notnull,nullzero,unique:filter_statuses_filter_id_status_id_uniq"` // ID of the status to filter. | ||
} |
131 changes: 131 additions & 0 deletions
131
internal/db/bundb/migrations/20241018151036_filter_unique_fix.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// GoToSocial | ||
// Copyright (C) GoToSocial Authors [email protected] | ||
// 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 migrations | ||
|
||
import ( | ||
"context" | ||
|
||
"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 { | ||
|
||
// Create the new filters table | ||
// with the unique constraint | ||
// set on AccountID + Title. | ||
if _, err := tx. | ||
NewCreateTable(). | ||
ModelTableExpr("new_filters"). | ||
Model((*gtsmodel.Filter)(nil)). | ||
Exec(ctx); err != nil { | ||
return err | ||
} | ||
|
||
// Explicitly specify columns to bring | ||
// from old table to new, to avoid any | ||
// potential Postgres shenanigans. | ||
columns := []string{ | ||
"id", | ||
"created_at", | ||
"updated_at", | ||
"expires_at", | ||
"account_id", | ||
"title", | ||
"action", | ||
"context_home", | ||
"context_notifications", | ||
"context_public", | ||
"context_thread", | ||
"context_account", | ||
} | ||
|
||
// Copy all data for existing | ||
// filters to the new table. | ||
if _, err := tx. | ||
NewInsert(). | ||
Table("new_filters"). | ||
Table("filters"). | ||
Column(columns...). | ||
Exec(ctx); err != nil { | ||
return err | ||
} | ||
|
||
// Drop the old table. | ||
if _, err := tx. | ||
NewDropTable(). | ||
Table("filters"). | ||
Exec(ctx); err != nil { | ||
return err | ||
} | ||
|
||
// Rename new table to old table. | ||
if _, err := tx. | ||
ExecContext( | ||
ctx, | ||
"ALTER TABLE ? RENAME TO ?", | ||
bun.Ident("new_filters"), | ||
bun.Ident("filters"), | ||
); err != nil { | ||
return err | ||
} | ||
|
||
// Index the new version | ||
// of the filters table. | ||
if _, err := tx. | ||
NewCreateIndex(). | ||
Table("filters"). | ||
Index("filters_account_id_idx"). | ||
Column("account_id"). | ||
IfNotExists(). | ||
Exec(ctx); err != nil { | ||
return err | ||
} | ||
|
||
if db.Dialect().Name() == dialect.PG { | ||
// Rename "new_filters_pkey" from the | ||
// new table to just "filters_pkey". | ||
// This is only necessary on Postgres. | ||
if _, err := tx.ExecContext( | ||
ctx, | ||
"ALTER TABLE ? RENAME CONSTRAINT ? TO ?", | ||
bun.Ident("public.filters"), | ||
bun.Safe("new_filters_pkey"), | ||
bun.Safe("filters_pkey"), | ||
); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
}) | ||
} | ||
|
||
down := func(ctx context.Context, db *bun.DB) error { | ||
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { | ||
return nil | ||
}) | ||
} | ||
|
||
if err := Migrations.Register(up, down); err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters