diff --git a/models/organization/org.go b/models/organization/org.go index 7dcb78cb9b..02794ba2cb 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -397,6 +397,14 @@ func DeleteOrganization(ctx context.Context, org *Organization) error { return fmt.Errorf("%s is a user not an organization", org.Name) } + // Decrease following count of users that follow the organisation. + followerIDs, err := db.FindIDs(ctx, "follow", "follow.user_id", builder.Eq{"follow.follow_id": org.ID}) + if err != nil { + return fmt.Errorf("get all followers: %w", err) + } else if err = db.DecrByIDs(ctx, followerIDs, "num_following", new(user_model.User)); err != nil { + return fmt.Errorf("decrease user num_following: %w", err) + } + if err := db.DeleteBeans(ctx, &Team{OrgID: org.ID}, &OrgUser{OrgID: org.ID}, @@ -406,6 +414,8 @@ func DeleteOrganization(ctx context.Context, org *Organization) error { &secret_model.Secret{OwnerID: org.ID}, &actions_model.ActionRunner{OwnerID: org.ID}, &actions_model.ActionRunnerToken{OwnerID: optional.Some(org.ID)}, + &user_model.BlockedUser{UserID: org.ID}, + &user_model.Follow{FollowID: org.ID}, ); err != nil { return fmt.Errorf("DeleteBeans: %w", err) } diff --git a/release-notes/11699.md b/release-notes/11699.md new file mode 100644 index 0000000000..8ecf708442 --- /dev/null +++ b/release-notes/11699.md @@ -0,0 +1 @@ +fix: The DB entries about users following an organization and users blocked by an organization were not deleted when an organization was deleted. Orphaned entries can be cleaned up by running `forgejo doctor check --run check-db-consistency --fix`. diff --git a/services/org/TestDeleteOrganization/follow.yml b/services/org/TestDeleteOrganization/follow.yml new file mode 100644 index 0000000000..7677806934 --- /dev/null +++ b/services/org/TestDeleteOrganization/follow.yml @@ -0,0 +1,4 @@ +- + id: 1001 + user_id: 1001 + follow_id: 6 diff --git a/services/org/TestDeleteOrganization/forgejo_blocked_user.yml b/services/org/TestDeleteOrganization/forgejo_blocked_user.yml new file mode 100644 index 0000000000..f1281fb65d --- /dev/null +++ b/services/org/TestDeleteOrganization/forgejo_blocked_user.yml @@ -0,0 +1,5 @@ +- + id: 1001 + user_id: 6 + block_id: 1 + created_unix: 1772018142 diff --git a/services/org/TestDeleteOrganization/user.yml b/services/org/TestDeleteOrganization/user.yml new file mode 100644 index 0000000000..cb1ac4138f --- /dev/null +++ b/services/org/TestDeleteOrganization/user.yml @@ -0,0 +1,13 @@ +- + id: 1001 + lower_name: user1001 + name: user1001 + full_name: User That loves Upper Cases + email: AnotherTestUserWithUpperCaseEmail@otto.splvs.net + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + avatar: '' + avatar_email: anothertestuserwithuppercaseemail@otto.splvs.net + login_name: user1 + created_unix: 1772018142 + num_following: 1 diff --git a/services/org/org_test.go b/services/org/org_test.go index 38736286f4..fdb7f14008 100644 --- a/services/org/org_test.go +++ b/services/org/org_test.go @@ -32,6 +32,8 @@ func TestDeleteOrganization(t *testing.T) { unittest.AssertNotExistsBean(t, &organization.OrgUser{OrgID: 6}) unittest.AssertNotExistsBean(t, &organization.Team{OrgID: 6}) unittest.AssertNotExistsBean(t, &actions.ActionRunnerToken{OwnerID: optional.Some[int64](6)}) + unittest.AssertNotExistsBean(t, &user_model.Follow{FollowID: 6}) + unittest.AssertNotExistsBean(t, &user_model.BlockedUser{UserID: 6}) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) err := DeleteOrganization(db.DefaultContext, org, false) @@ -41,4 +43,6 @@ func TestDeleteOrganization(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 5}) require.Error(t, DeleteOrganization(db.DefaultContext, user, false)) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) + + assert.Zero(t, unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1001}).NumFollowing) }