diff --git a/components/gitpod-db/go/organization.go b/components/gitpod-db/go/organization.go index 4fcbb005709350..76ad6ac7c83e2e 100644 --- a/components/gitpod-db/go/organization.go +++ b/components/gitpod-db/go/organization.go @@ -23,9 +23,6 @@ type Organization struct { LastModified time.Time `gorm:"column:_lastModified;type:timestamp;default:CURRENT_TIMESTAMP(6);" json:"_lastModified"` MarkedDeleted bool `gorm:"column:markedDeleted;type:tinyint;default:0;" json:"marked_deleted"` - - // deleted is reserved for use by periodic deleter - _ bool `gorm:"column:deleted;type:tinyint;default:0;" json:"deleted"` } // TableName sets the insert table name for this struct type @@ -85,7 +82,6 @@ func GetSingleOrganizationWithActiveSSO(ctx context.Context, conn *gorm.DB) (Org WithContext(ctx). Table(fmt.Sprintf("%s as team", (&Organization{}).TableName())). Joins(fmt.Sprintf("JOIN %s AS config ON team.id = config.organizationId", (&OIDCClientConfig{}).TableName())). - Where("team.deleted = ?", 0). Where("config.deleted = ?", 0). Where("config.active = ?", 1). Find(&orgs) diff --git a/components/gitpod-db/go/organization_membership.go b/components/gitpod-db/go/organization_membership.go index 59dc5dd7ef1db0..37e04765747fea 100644 --- a/components/gitpod-db/go/organization_membership.go +++ b/components/gitpod-db/go/organization_membership.go @@ -24,9 +24,6 @@ type OrganizationMembership struct { CreationTime VarcharTime `gorm:"column:creationTime;type:varchar;size:255;" json:"creationTime"` // Read-only (-> property). LastModified time.Time `gorm:"->:column:_lastModified;type:timestamp;default:CURRENT_TIMESTAMP(6);" json:"_lastModified"` - - // deleted column is reserved for use by periodic deleter - _ bool `gorm:"column:deleted;type:tinyint;default:0;" json:"deleted"` } // TableName sets the insert table name for this struct type @@ -54,7 +51,6 @@ func GetOrganizationMembership(ctx context.Context, conn *gorm.DB, userID, orgID tx := conn.WithContext(ctx). Where("userId = ?", userID.String()). Where("teamId = ?", orgID.String()). - Where("deleted = ?", false). First(&membership) if tx.Error != nil { if errors.Is(tx.Error, gorm.ErrRecordNotFound) { @@ -79,8 +75,7 @@ func DeleteOrganizationMembership(ctx context.Context, conn *gorm.DB, userID uui Model(&OrganizationMembership{}). Where("userId = ?", userID.String()). Where("teamId = ?", orgID.String()). - Where("deleted = ?", 0). - Update("deleted", 1) + Delete(&OrganizationMembership{}) if tx.Error != nil { return fmt.Errorf("failed to retrieve organization membership for user %s, organization %s: %w", userID.String(), orgID.String(), tx.Error) } diff --git a/components/gitpod-db/go/project.go b/components/gitpod-db/go/project.go index d0f2854277be84..73ccc103d01ead 100644 --- a/components/gitpod-db/go/project.go +++ b/components/gitpod-db/go/project.go @@ -28,9 +28,6 @@ type Project struct { UserID sql.NullString `gorm:"column:userId;type:char;size:36;" json:"userId"` MarkedDeleted bool `gorm:"column:markedDeleted;type:tinyint;default:0;" json:"markedDeleted"` - - // deleted is reserved for use by periodic deleter - _ bool `gorm:"column:deleted;type:tinyint;default:0;" json:"deleted"` } // TableName sets the insert table name for this struct type diff --git a/components/gitpod-db/go/project_test.go b/components/gitpod-db/go/project_test.go index 608bc990b0c8ff..ea2679c19d02e0 100644 --- a/components/gitpod-db/go/project_test.go +++ b/components/gitpod-db/go/project_test.go @@ -23,7 +23,6 @@ var projectJSON = map[string]interface{}{ "teamId": "0e433063-1358-4892-9ed2-68e273d17d07", "appInstallationId": "20446411", "creationTime": "2021-11-01T19:36:07.532Z", - "deleted": 0, "_lastModified": "2021-11-02 10:49:12.473658", "name": "gptest1-repo1-private", "markedDeleted": 1, @@ -49,7 +48,7 @@ func TestProject_ReadExistingRecords(t *testing.T) { func insertRawProject(t *testing.T, conn *gorm.DB, obj map[string]interface{}) uuid.UUID { columns := []string{ - "id", "cloneUrl", "teamId", "appInstallationId", "creationTime", "deleted", "_lastModified", "name", "markedDeleted", "userId", "slug", "settings", + "id", "cloneUrl", "teamId", "appInstallationId", "creationTime", "_lastModified", "name", "markedDeleted", "userId", "slug", "settings", } statement := fmt.Sprintf(`INSERT INTO d_b_project (%s) VALUES ?;`, strings.Join(columns, ", ")) id := uuid.MustParse(obj["id"].(string)) diff --git a/components/gitpod-db/src/auth-provider-entry.spec.db.ts b/components/gitpod-db/src/auth-provider-entry.spec.db.ts index be74aa65ef419c..0509dae4460e8c 100644 --- a/components/gitpod-db/src/auth-provider-entry.spec.db.ts +++ b/components/gitpod-db/src/auth-provider-entry.spec.db.ts @@ -38,7 +38,6 @@ describe("AuthProviderEntryDBSpec", async () => { status: "verified", type: "GitHub", oauthRevision: undefined, - deleted: false, ...ap, oauth: { callBackUrl: "example.org/some/callback", @@ -74,7 +73,7 @@ describe("AuthProviderEntryDBSpec", async () => { await db.storeAuthProvider(ap2, false); const all = await db.findAllHosts(); - expect(all, "findAllHosts([])").to.deep.equal(["foo", "bar"]); + expect(all.sort(), "findAllHosts([])").to.deep.equal(["foo", "bar"].sort()); }); it("should oauthRevision", async () => { diff --git a/components/gitpod-db/src/tables.ts b/components/gitpod-db/src/tables.ts index 62e1e48c036092..0309f7c2e48707 100644 --- a/components/gitpod-db/src/tables.ts +++ b/components/gitpod-db/src/tables.ts @@ -62,55 +62,18 @@ export class GitpodTableDescriptionProvider implements TableDescriptionProvider primaryKeys: ["id"], timeColumn: "_lastModified", }, - { - name: "d_b_token_entry", - primaryKeys: ["uid"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, - { - name: "d_b_gitpod_token", - primaryKeys: ["tokenHash"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - dependencies: ["d_b_user"], - }, { name: "d_b_one_time_secret", primaryKeys: ["id"], deletionColumn: "deleted", timeColumn: "_lastModified", }, - { - name: "d_b_auth_provider_entry", - primaryKeys: ["id"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, - { - name: "d_b_team", - primaryKeys: ["id"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, - { - name: "d_b_team_membership", - primaryKeys: ["id"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, { name: "d_b_team_membership_invite", primaryKeys: ["id"], deletionColumn: "deleted", timeColumn: "_lastModified", }, - { - name: "d_b_project", - primaryKeys: ["id"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, { name: "d_b_project_env_var", primaryKeys: ["id", "projectId"], @@ -123,18 +86,6 @@ export class GitpodTableDescriptionProvider implements TableDescriptionProvider deletionColumn: "deleted", timeColumn: "_lastModified", }, - { - name: "d_b_project_usage", - primaryKeys: ["projectId"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, - { - name: "d_b_user_ssh_public_key", - primaryKeys: ["id"], - deletionColumn: "deleted", - timeColumn: "_lastModified", - }, { name: "d_b_stripe_customer", primaryKeys: ["stripeCustomerId"], diff --git a/components/gitpod-db/src/typeorm/auth-provider-entry-db-impl.ts b/components/gitpod-db/src/typeorm/auth-provider-entry-db-impl.ts index f63e5dc932bd47..d811f2d155b570 100644 --- a/components/gitpod-db/src/typeorm/auth-provider-entry-db-impl.ts +++ b/components/gitpod-db/src/typeorm/auth-provider-entry-db-impl.ts @@ -46,7 +46,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { [id], ); - // 2. then mark as deleted + // 2. then delete const repo = await this.getAuthProviderRepo(); await repo.delete({ id }); } @@ -55,7 +55,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { exceptOAuthRevisions = exceptOAuthRevisions.filter((r) => r !== ""); // never filter out '' which means "undefined" in the DB const repo = await this.getAuthProviderRepo(); - let query = repo.createQueryBuilder("auth_provider").where("auth_provider.deleted != true"); + let query = repo.createQueryBuilder("auth_provider"); if (exceptOAuthRevisions.length > 0) { query = query.andWhere("auth_provider.oauthRevision NOT IN (:...exceptOAuthRevisions)", { exceptOAuthRevisions, @@ -68,7 +68,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { const hostField: keyof DBAuthProviderEntry = "host"; const repo = await this.getAuthProviderRepo(); - const query = repo.createQueryBuilder("auth_provider").select(hostField).where("auth_provider.deleted != true"); + const query = repo.createQueryBuilder("auth_provider").select(hostField); const result = (await query.execute()) as Pick[]; // HINT: host is expected to be lower case return result.map((r) => r.host?.toLowerCase()).filter((h) => !!h); @@ -76,10 +76,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { async findByHost(host: string): Promise { const repo = await this.getAuthProviderRepo(); - const query = repo - .createQueryBuilder("auth_provider") - .where(`auth_provider.host = :host`, { host }) - .andWhere("auth_provider.deleted != true"); + const query = repo.createQueryBuilder("auth_provider").where(`auth_provider.host = :host`, { host }); return query.getOne(); } @@ -93,8 +90,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { const query = repo .createQueryBuilder("auth_provider") .where(`auth_provider.ownerId = :ownerId`, { ownerId }) - .andWhere("(auth_provider.organizationId IS NULL OR auth_provider.organizationId = '')") - .andWhere("auth_provider.deleted != true"); + .andWhere("(auth_provider.organizationId IS NULL OR auth_provider.organizationId = '')"); return query.getMany(); } @@ -102,8 +98,7 @@ export class AuthProviderEntryDBImpl implements AuthProviderEntryDB { const repo = await this.getAuthProviderRepo(); const query = repo .createQueryBuilder("auth_provider") - .where(`auth_provider.organizationId = :organizationId`, { organizationId }) - .andWhere("auth_provider.deleted != true"); + .where(`auth_provider.organizationId = :organizationId`, { organizationId }); return query.getMany(); } diff --git a/components/gitpod-db/src/typeorm/entity/db-auth-provider-entry.ts b/components/gitpod-db/src/typeorm/entity/db-auth-provider-entry.ts index 0fa2dcec1637d8..6f0a4468268b9e 100644 --- a/components/gitpod-db/src/typeorm/entity/db-auth-provider-entry.ts +++ b/components/gitpod-db/src/typeorm/entity/db-auth-provider-entry.ts @@ -45,7 +45,4 @@ export class DBAuthProviderEntry implements AuthProviderEntry { transformer: Transformer.MAP_EMPTY_STR_TO_UNDEFINED, }) oauthRevision?: string; - - @Column() - deleted?: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-gitpod-token.ts b/components/gitpod-db/src/typeorm/entity/db-gitpod-token.ts index 1a7634bfa67008..a4029b807f62b9 100644 --- a/components/gitpod-db/src/typeorm/entity/db-gitpod-token.ts +++ b/components/gitpod-db/src/typeorm/entity/db-gitpod-token.ts @@ -32,7 +32,4 @@ export class DBGitpodToken implements GitpodToken { @Column() created: string; - - @Column() - deleted?: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-project-usage.ts b/components/gitpod-db/src/typeorm/entity/db-project-usage.ts index a8626dbba38169..3e099f5a0cd434 100644 --- a/components/gitpod-db/src/typeorm/entity/db-project-usage.ts +++ b/components/gitpod-db/src/typeorm/entity/db-project-usage.ts @@ -19,8 +19,4 @@ export class DBProjectUsage { @Column("varchar") lastWorkspaceStart: string; - - // This column triggers the periodic deleter deletion mechanism. It's not intended for public consumption. - @Column() - deleted: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-project.ts b/components/gitpod-db/src/typeorm/entity/db-project.ts index 3f8ea64dbd372b..ac662e04c46234 100644 --- a/components/gitpod-db/src/typeorm/entity/db-project.ts +++ b/components/gitpod-db/src/typeorm/entity/db-project.ts @@ -6,12 +6,12 @@ import { Entity, Column, PrimaryColumn, Index } from "typeorm"; import { TypeORM } from "../typeorm"; -import { ProjectSettings } from "@gitpod/gitpod-protocol"; +import { Project, ProjectSettings } from "@gitpod/gitpod-protocol"; import { Transformer } from "../transformer"; @Entity() // on DB but not Typeorm: @Index("ind_lastModified", ["_lastModified"]) // DBSync -export class DBProject { +export class DBProject implements Project { @PrimaryColumn(TypeORM.UUID_COLUMN_TYPE) id: string; @@ -38,10 +38,6 @@ export class DBProject { @Column("varchar") creationTime: string; - // This column triggers the periodic deleter deletion mechanism. It's not intended for public consumption. - @Column() - deleted: boolean; - @Column() markedDeleted: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-team-membership.ts b/components/gitpod-db/src/typeorm/entity/db-team-membership.ts index 87d9e2c9a91f2b..83299d21990450 100644 --- a/components/gitpod-db/src/typeorm/entity/db-team-membership.ts +++ b/components/gitpod-db/src/typeorm/entity/db-team-membership.ts @@ -27,8 +27,4 @@ export class DBTeamMembership { @Column("varchar") creationTime: string; - - // This column triggers the periodic deleter deletion mechanism. It's not intended for public consumption. - @Column() - deleted: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-team.ts b/components/gitpod-db/src/typeorm/entity/db-team.ts index c301fa6153cd70..8b3dc8138f480c 100644 --- a/components/gitpod-db/src/typeorm/entity/db-team.ts +++ b/components/gitpod-db/src/typeorm/entity/db-team.ts @@ -25,8 +25,4 @@ export class DBTeam implements Team { @Column() markedDeleted?: boolean; - - // This column triggers the periodic deleter deletion mechanism. It's not intended for public consumption. - @Column() - deleted: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-token-entry.ts b/components/gitpod-db/src/typeorm/entity/db-token-entry.ts index b42ea0c939ce22..68cf781aa1cc8d 100644 --- a/components/gitpod-db/src/typeorm/entity/db-token-entry.ts +++ b/components/gitpod-db/src/typeorm/entity/db-token-entry.ts @@ -42,7 +42,4 @@ export class DBTokenEntry implements TokenEntry { ), }) token: Token; - - @Column() - deleted?: boolean; } diff --git a/components/gitpod-db/src/typeorm/entity/db-user-ssh-public-key.ts b/components/gitpod-db/src/typeorm/entity/db-user-ssh-public-key.ts index bff7d40bd03d30..6452be4e6fd65f 100644 --- a/components/gitpod-db/src/typeorm/entity/db-user-ssh-public-key.ts +++ b/components/gitpod-db/src/typeorm/entity/db-user-ssh-public-key.ts @@ -49,8 +49,4 @@ export class DBUserSshPublicKey implements UserSSHPublicKey { transformer: Transformer.MAP_EMPTY_STR_TO_UNDEFINED, }) lastUsedTime?: string; - - // This column triggers the periodic deleter deletion mechanism. It's not intended for public consumption. - @Column() - deleted: boolean; } diff --git a/components/gitpod-db/src/typeorm/migration/1695810605786-TeamDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695810605786-TeamDropDeleted.ts new file mode 100644 index 00000000000000..fab031a85d1b1e --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695810605786-TeamDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_team"; +const COLUMN_NAME = "deleted"; + +export class TeamDropDeleted1695810605786 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695817445588-ProjectDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695817445588-ProjectDropDeleted.ts new file mode 100644 index 00000000000000..88a8c6a0b382f4 --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695817445588-ProjectDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_project"; +const COLUMN_NAME = "deleted"; + +export class ProjectDropDeleted1695817445588 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695819413747-DropTableUserStorageResource.ts b/components/gitpod-db/src/typeorm/migration/1695819413747-DropTableUserStorageResource.ts new file mode 100644 index 00000000000000..ae4f60266400e1 --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695819413747-DropTableUserStorageResource.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class DropTableUserStorageResource1695819413747 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query("DROP TABLE IF EXISTS `d_b_user_storage_resource`"); + } + + public async down(queryRunner: QueryRunner): Promise {} +} diff --git a/components/gitpod-db/src/typeorm/migration/1695820427730-TokenEntryDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695820427730-TokenEntryDropDeleted.ts new file mode 100644 index 00000000000000..9c719ee14ec5fb --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695820427730-TokenEntryDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_token_entry"; +const COLUMN_NAME = "deleted"; + +export class TokenEntryDropDeleted1695820427730 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695820658574-AuthProviderEntryDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695820658574-AuthProviderEntryDropDeleted.ts new file mode 100644 index 00000000000000..f189589c82274d --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695820658574-AuthProviderEntryDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_auth_provider_entry"; +const COLUMN_NAME = "deleted"; + +export class AuthProviderEntryDropDeleted1695820658574 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695821079717-GitpodTokenDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695821079717-GitpodTokenDropDeleted.ts new file mode 100644 index 00000000000000..9c6b169f723eed --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695821079717-GitpodTokenDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_gitpod_token"; +const COLUMN_NAME = "deleted"; + +export class GitpodTokenDropDeleted1695821079717 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695821464987-TeamMembershipDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695821464987-TeamMembershipDropDeleted.ts new file mode 100644 index 00000000000000..b441f5556424a4 --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695821464987-TeamMembershipDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_team_membership"; +const COLUMN_NAME = "deleted"; + +export class TeamMembershipDropDeleted1695821464987 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695821957148-ProjectUsageDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695821957148-ProjectUsageDropDeleted.ts new file mode 100644 index 00000000000000..fa17df8750e32c --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695821957148-ProjectUsageDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_project_usage"; +const COLUMN_NAME = "deleted"; + +export class ProjectUsageDropDeleted1695821957148 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/migration/1695822248160-UserSshPublicKeyDropDeleted.ts b/components/gitpod-db/src/typeorm/migration/1695822248160-UserSshPublicKeyDropDeleted.ts new file mode 100644 index 00000000000000..b01c1593221bba --- /dev/null +++ b/components/gitpod-db/src/typeorm/migration/1695822248160-UserSshPublicKeyDropDeleted.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2023 Gitpod GmbH. All rights reserved. + * Licensed under the GNU Affero General Public License (AGPL). + * See License.AGPL.txt in the project root for license information. + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; +import { columnExists } from "./helper/helper"; + +const TABLE_NAME = "d_b_user_ssh_public_key"; +const COLUMN_NAME = "deleted"; + +export class UserSshPublicKeyDropDeleted1695822248160 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + if (await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME)) { + await queryRunner.query(`ALTER TABLE \`${TABLE_NAME}\` DROP COLUMN \`${COLUMN_NAME}\``); + } + } + + public async down(queryRunner: QueryRunner): Promise { + if (!(await columnExists(queryRunner, TABLE_NAME, COLUMN_NAME))) { + await queryRunner.query( + `ALTER TABLE \`${TABLE_NAME}\` ADD COLUMN \`${COLUMN_NAME}\` tinyint(4) NOT NULL DEFAULT '0'`, + ); + } + } +} diff --git a/components/gitpod-db/src/typeorm/team-db-impl.ts b/components/gitpod-db/src/typeorm/team-db-impl.ts index 32a6c71e3402a9..0268a784a80428 100644 --- a/components/gitpod-db/src/typeorm/team-db-impl.ts +++ b/components/gitpod-db/src/typeorm/team-db-impl.ts @@ -71,12 +71,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { searchTerm: `%${searchTerm}%`, }); } - queryBuilder = queryBuilder - .andWhere("deleted = 0") - .andWhere("markedDeleted = 0") - .skip(offset) - .take(limit) - .orderBy(orderBy, orderDir); + queryBuilder = queryBuilder.andWhere("markedDeleted = 0").skip(offset).take(limit).orderBy(orderBy, orderDir); const [rows, total] = await queryBuilder.getManyAndCount(); return { total, rows }; @@ -84,12 +79,12 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async findTeamById(teamId: string): Promise { const teamRepo = await this.getTeamRepo(); - return teamRepo.findOne({ id: teamId, deleted: false, markedDeleted: false }); + return teamRepo.findOne({ id: teamId, markedDeleted: false }); } public async findTeamByMembershipId(membershipId: string): Promise { const membershipRepo = await this.getMembershipRepo(); - const membership = await membershipRepo.findOne({ id: membershipId, deleted: false }); + const membership = await membershipRepo.findOne({ id: membershipId }); if (!membership) { return; } @@ -99,7 +94,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async findMembersByTeam(teamId: string): Promise { const membershipRepo = await this.getMembershipRepo(); const userRepo = await this.getUserRepo(); - const memberships = await membershipRepo.find({ teamId, deleted: false }); + const memberships = await membershipRepo.find({ teamId }); const users = await userRepo.findByIds(memberships.map((m) => m.userId)); const infos = users.map((u) => { const m = memberships.find((m) => m.userId === u.id)!; @@ -118,13 +113,13 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async findTeamMembership(userId: string, teamId: string): Promise { const membershipRepo = await this.getMembershipRepo(); - return membershipRepo.findOne({ userId, teamId, deleted: false }); + return membershipRepo.findOne({ userId, teamId }); } public async findTeamsByUser(userId: string): Promise { const teamRepo = await this.getTeamRepo(); const membershipRepo = await this.getMembershipRepo(); - const memberships = await membershipRepo.find({ userId, deleted: false }); + const memberships = await membershipRepo.find({ userId }); const teams = await teamRepo.findByIds(memberships.map((m) => m.teamId)); return teams.filter((t) => !t.markedDeleted); } @@ -154,7 +149,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { return await this.transaction(async (_, ctx) => { const teamRepo = ctx.entityManager.getRepository(DBTeam); - const existingTeam = await teamRepo.findOne({ id: teamId, deleted: false, markedDeleted: false }); + const existingTeam = await teamRepo.findOne({ id: teamId, markedDeleted: false }); if (!existingTeam) { throw new ApplicationError(ErrorCodes.NOT_FOUND, "Organization not found"); } @@ -230,7 +225,6 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { tries++ < 5 && (await teamRepo.findOne({ slug, - deleted: false, markedDeleted: false, })) ) { @@ -257,7 +251,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { private async deleteOrgSettings(orgId: string): Promise { const orgSettingsRepo = await this.getOrgSettingsRepo(); - const orgSettings = await orgSettingsRepo.findOne({ where: { orgId, deleted: false } }); + const orgSettings = await orgSettingsRepo.findOne({ where: { orgId } }); if (orgSettings) { orgSettings.deleted = true; orgSettingsRepo.save(orgSettings); @@ -267,11 +261,11 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async addMemberToTeam(userId: string, teamId: string): Promise<"added" | "already_member"> { const teamRepo = await this.getTeamRepo(); const team = await teamRepo.findOne(teamId); - if (!team || !!team.deleted) { + if (!team) { throw new ApplicationError(ErrorCodes.NOT_FOUND, "An organization with this ID could not be found"); } const membershipRepo = await this.getMembershipRepo(); - const membership = await membershipRepo.findOne({ teamId, userId, deleted: false }); + const membership = await membershipRepo.findOne({ teamId, userId }); if (!!membership) { // already a member, this is the desired outcome return "already_member"; @@ -289,7 +283,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async setTeamMemberRole(userId: string, teamId: string, role: TeamMemberRole): Promise { const teamRepo = await this.getTeamRepo(); const team = await teamRepo.findOne(teamId); - if (!team || !!team.deleted) { + if (!team) { throw new ApplicationError(ErrorCodes.NOT_FOUND, "An organization with this ID could not be found"); } const membershipRepo = await this.getMembershipRepo(); @@ -298,7 +292,6 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { const allOwners = await membershipRepo.find({ teamId, role: "owner", - deleted: false, }); const otherOwnerCount = allOwners.filter((m) => m.userId != userId).length; if (otherOwnerCount === 0) { @@ -306,7 +299,7 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { } } - const membership = await membershipRepo.findOne({ teamId, userId, deleted: false }); + const membership = await membershipRepo.findOne({ teamId, userId }); if (!membership) { throw new ApplicationError(ErrorCodes.NOT_FOUND, "The user is not currently a member of this organization"); } @@ -317,11 +310,11 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { public async removeMemberFromTeam(userId: string, teamId: string): Promise { const teamRepo = await this.getTeamRepo(); const team = await teamRepo.findOne(teamId); - if (!team || !!team.deleted) { + if (!team) { throw new ApplicationError(ErrorCodes.NOT_FOUND, "An organization with this ID could not be found"); } const membershipRepo = await this.getMembershipRepo(); - const membership = await membershipRepo.findOne({ teamId, userId, deleted: false }); + const membership = await membershipRepo.findOne({ teamId, userId }); if (!membership) { throw new ApplicationError( ErrorCodes.BAD_REQUEST, @@ -403,7 +396,6 @@ export class TeamDBImpl extends TransactionalDBImpl implements TeamDB { `select org.id from d_b_team as org inner join d_b_oidc_client_config as oidc on org.id = oidc.organizationId where oidc.active = 1 and oidc.deleted = 0 - and org.deleted = 0 and org.markedDeleted = 0 and org.id = ? limit 1;`, diff --git a/components/gitpod-db/src/typeorm/user-db-impl.ts b/components/gitpod-db/src/typeorm/user-db-impl.ts index 9e2ba87a87da5d..3ffd955b65e594 100644 --- a/components/gitpod-db/src/typeorm/user-db-impl.ts +++ b/components/gitpod-db/src/typeorm/user-db-impl.ts @@ -221,7 +221,6 @@ export class TypeORMUserDBImpl extends TransactionalDBImpl implements Us } else { qBuilder.where("gitpodToken.tokenHash = :tokenHash", { tokenHash }); } - qBuilder.andWhere("gitpodToken.deleted <> TRUE"); const token = await qBuilder.getOne(); if (!token) { return; @@ -340,10 +339,10 @@ export class TypeORMUserDBImpl extends TransactionalDBImpl implements Us } } - public async findTokensForIdentity(identity: Identity, includeDeleted?: boolean): Promise { + public async findTokensForIdentity(identity: Identity): Promise { const repo = await this.getTokenRepo(); const entry = await repo.find({ authProviderId: identity.authProviderId, authId: identity.authId }); - return entry.filter((te) => includeDeleted || !te.deleted); + return entry; } private mapUserToDBUser(user: User): DBUser { @@ -426,18 +425,18 @@ export class TypeORMUserDBImpl extends TransactionalDBImpl implements Us public async hasSSHPublicKey(userId: string): Promise { const repo = await this.getSSHPublicKeyRepo(); - return !!(await repo.findOne({ where: { userId, deleted: false } })); + return !!(await repo.findOne({ where: { userId } })); } public async getSSHPublicKeys(userId: string): Promise { const repo = await this.getSSHPublicKeyRepo(); - return repo.find({ where: { userId, deleted: false }, order: { creationTime: "ASC" } }); + return repo.find({ where: { userId }, order: { creationTime: "ASC" } }); } public async addSSHPublicKey(userId: string, value: SSHPublicKeyValue): Promise { const repo = await this.getSSHPublicKeyRepo(); const fingerprint = SSHPublicKeyValue.getFingerprint(value); - const allKeys = await repo.find({ where: { userId, deleted: false } }); + const allKeys = await repo.find({ where: { userId } }); const prevOne = allKeys.find((e) => e.fingerprint === fingerprint); if (!!prevOne) { throw new Error(`Key already in use`); diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index b21fdeb6716d10..706b0e7f0cc656 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -683,9 +683,6 @@ export interface GitpodToken { /** Created timestamp */ created: string; - - // token is deleted on the database and about to be collected by periodic deleter - deleted?: boolean; } export enum GitpodTokenType { @@ -754,8 +751,6 @@ export interface TokenEntry { token: Token; expiryDate?: string; refreshable?: boolean; - /** This is a flag that triggers the HARD DELETION of this entity */ - deleted?: boolean; } export interface EmailDomainFilterEntry { diff --git a/components/gitpod-protocol/src/teams-projects-protocol.ts b/components/gitpod-protocol/src/teams-projects-protocol.ts index 897a63c7f1934e..1e7ebfb5ece80b 100644 --- a/components/gitpod-protocol/src/teams-projects-protocol.ts +++ b/components/gitpod-protocol/src/teams-projects-protocol.ts @@ -97,8 +97,6 @@ export interface Project { appInstallationId: string; settings?: ProjectSettings; creationTime: string; - /** This is a flag that triggers the HARD DELETION of this entity */ - deleted?: boolean; markedDeleted?: boolean; } @@ -236,8 +234,6 @@ export interface Organization { slug?: string; creationTime: string; markedDeleted?: boolean; - /** This is a flag that triggers the HARD DELETION of this entity */ - deleted?: boolean; } export interface OrganizationSettings { diff --git a/components/server/src/user/gitpod-token-service.ts b/components/server/src/user/gitpod-token-service.ts index aea23b1965383b..fbcb390dbd3457 100644 --- a/components/server/src/user/gitpod-token-service.ts +++ b/components/server/src/user/gitpod-token-service.ts @@ -21,7 +21,7 @@ export class GitpodTokenService { async getGitpodTokens(requestorId: string, userId: string): Promise { await this.auth.checkPermissionOnUser(requestorId, "read_tokens", userId); const gitpodTokens = await this.userDB.findAllGitpodTokensOfUser(userId); - return gitpodTokens.filter((v) => !v.deleted); + return gitpodTokens; } async generateNewGitpodToken( @@ -56,9 +56,6 @@ export class GitpodTokenService { } catch (error) { log.error({ userId }, "failed to resolve gitpod token: ", error); } - if (token?.deleted) { - token = undefined; - } return token; }