diff --git a/backend-pg/package-lock.json b/backend-pg/package-lock.json index d105e8109..301e15140 100644 --- a/backend-pg/package-lock.json +++ b/backend-pg/package-lock.json @@ -23,6 +23,7 @@ "@node-saml/passport-saml": "^4.0.4", "@octokit/rest": "^20.0.2", "@octokit/webhooks-types": "^7.3.1", + "@sindresorhus/slugify": "^2.2.1", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -2759,6 +2760,57 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sindresorhus/slugify": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", + "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", + "dependencies": { + "@sindresorhus/transliterate": "^1.0.0", + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/slugify/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@smithy/abort-controller": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.16.tgz", diff --git a/backend-pg/package.json b/backend-pg/package.json index 506d632cd..1a1a90af2 100644 --- a/backend-pg/package.json +++ b/backend-pg/package.json @@ -80,6 +80,7 @@ "@node-saml/passport-saml": "^4.0.4", "@octokit/rest": "^20.0.2", "@octokit/webhooks-types": "^7.3.1", + "@sindresorhus/slugify": "^2.2.1", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", diff --git a/backend-pg/src/db/migrations/20231204092737_organization.ts b/backend-pg/src/db/migrations/20231204092737_organization.ts index cc03babb2..8928b086a 100644 --- a/backend-pg/src/db/migrations/20231204092737_organization.ts +++ b/backend-pg/src/db/migrations/20231204092737_organization.ts @@ -10,7 +10,9 @@ export async function up(knex: Knex): Promise { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("name").notNullable(); t.string("customerId"); + t.string("slug").notNullable(); // does not need update trigger we will do it manually + t.unique("slug"); t.timestamps(true, true, true); }); await knex.schema.alterTable(TableName.AuthTokens, (t) => { diff --git a/backend-pg/src/db/migrations/20231212110939_project.ts b/backend-pg/src/db/migrations/20231212110939_project.ts index 732c80c10..b2764dc1f 100644 --- a/backend-pg/src/db/migrations/20231212110939_project.ts +++ b/backend-pg/src/db/migrations/20231212110939_project.ts @@ -8,10 +8,12 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.Project, (t) => { t.string("id", 36).primary().defaultTo(knex.fn.uuid()); t.string("name").notNullable(); + t.string("slug").notNullable(); t.boolean("autoCapitalization").defaultTo(true); t.uuid("orgId").notNullable(); t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE"); t.timestamps(true, true, true); + t.unique(["orgId", "slug"]); }); } await createOnUpdateTrigger(knex, TableName.Project); diff --git a/backend-pg/src/db/schemas/organizations.ts b/backend-pg/src/db/schemas/organizations.ts index e9ff4555f..e0f70d1c0 100644 --- a/backend-pg/src/db/schemas/organizations.ts +++ b/backend-pg/src/db/schemas/organizations.ts @@ -11,8 +11,9 @@ export const OrganizationsSchema = z.object({ id: z.string().uuid(), name: z.string(), customerId: z.string().nullable().optional(), + slug: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TOrganizations = z.infer; diff --git a/backend-pg/src/db/schemas/projects.ts b/backend-pg/src/db/schemas/projects.ts index f44010674..005e4bbde 100644 --- a/backend-pg/src/db/schemas/projects.ts +++ b/backend-pg/src/db/schemas/projects.ts @@ -10,6 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const ProjectsSchema = z.object({ id: z.string(), name: z.string(), + slug: z.string(), autoCapitalization: z.boolean().default(true).nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), diff --git a/backend-pg/src/ee/services/secret-rotation/secret-rotation-queue/index.ts b/backend-pg/src/ee/services/secret-rotation/secret-rotation-queue/index.ts index aea9a206a..1d8c50b36 100644 --- a/backend-pg/src/ee/services/secret-rotation/secret-rotation-queue/index.ts +++ b/backend-pg/src/ee/services/secret-rotation/secret-rotation-queue/index.ts @@ -1,5 +1,2 @@ -export { - DisableRotationErrors, - secretRotationQueueFactory, - TSecretRotationQueueFactory -} from "./secret-rotation-queue"; +export type { TSecretRotationQueueFactory } from "./secret-rotation-queue"; +export { DisableRotationErrors, secretRotationQueueFactory } from "./secret-rotation-queue"; diff --git a/backend-pg/src/queue/index.ts b/backend-pg/src/queue/index.ts index 638e4715a..665162f59 100644 --- a/backend-pg/src/queue/index.ts +++ b/backend-pg/src/queue/index.ts @@ -1,7 +1,2 @@ -export { - QueueJobs, - QueueName, - queueServiceFactory, - TQueueJobTypes, - TQueueServiceFactory -} from "./queue-service"; +export type { TQueueJobTypes, TQueueServiceFactory } from "./queue-service"; +export { QueueJobs, QueueName, queueServiceFactory } from "./queue-service"; diff --git a/backend-pg/src/services/org/org-service.ts b/backend-pg/src/services/org/org-service.ts index 283443b56..1c5aba54d 100644 --- a/backend-pg/src/services/org/org-service.ts +++ b/backend-pg/src/services/org/org-service.ts @@ -1,4 +1,5 @@ import { ForbiddenError } from "@casl/ability"; +import slugify from "@sindresorhus/slugify"; import jwt from "jsonwebtoken"; import { OrgMembershipRole, OrgMembershipStatus } from "@app/db/schemas"; @@ -13,6 +14,7 @@ import { getConfig } from "@app/lib/config/env"; import { generateAsymmetricKeyPair } from "@app/lib/crypto"; import { generateSymmetricKey, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { alphaNumericNanoId } from "@app/lib/nanoid"; import { isDisposableEmail } from "@app/lib/validator"; import { AuthMethod, AuthTokenType } from "../auth/auth-type"; @@ -128,7 +130,11 @@ export const orgServiceFactory = ({ const customerId = await licenseService.generateOrgCustomerId(orgName, userEmail); const organization = await orgDAL.transaction(async (tx) => { - const org = await orgDAL.create({ name: orgName, customerId }, tx); + // akhilmhdh: for now this is auto created. in future we can input from user and for previous users just modifiy + const org = await orgDAL.create( + { name: orgName, customerId, slug: slugify(`${orgName}-${alphaNumericNanoId(4)}`) }, + tx + ); await orgDAL.createMembership( { userId, diff --git a/backend-pg/src/services/project/project-service.ts b/backend-pg/src/services/project/project-service.ts index 6ae306047..6ed45d717 100644 --- a/backend-pg/src/services/project/project-service.ts +++ b/backend-pg/src/services/project/project-service.ts @@ -1,4 +1,5 @@ import { ForbiddenError } from "@casl/ability"; +import slugify from "@sindresorhus/slugify"; import { ProjectMembershipRole } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; @@ -14,6 +15,7 @@ import { import { getConfig } from "@app/lib/config/env"; import { createSecretBlindIndex } from "@app/lib/crypto"; import { BadRequestError } from "@app/lib/errors"; +import { alphaNumericNanoId } from "@app/lib/nanoid"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal"; @@ -73,7 +75,10 @@ export const projectServiceFactory = ({ } const newProject = projectDAL.transaction(async (tx) => { - const project = await projectDAL.create({ name: workspaceName, orgId }, tx); + const project = await projectDAL.create( + { name: workspaceName, orgId, slug: slugify(`${workspaceName}-${alphaNumericNanoId(4)}`) }, + tx + ); // set user as admin member for proeject await projectMembershipDAL.create( { diff --git a/frontend/src/pages/org/[id]/overview/index.tsx b/frontend/src/pages/org/[id]/overview/index.tsx index e96a1eec1..0c9a16d18 100644 --- a/frontend/src/pages/org/[id]/overview/index.tsx +++ b/frontend/src/pages/org/[id]/overview/index.tsx @@ -475,10 +475,8 @@ const OrganizationPage = withPermission( const router = useRouter(); const { workspaces, isLoading: isWorkspaceLoading } = useWorkspace(); - const orgWorkspaces = - workspaces?.filter((workspace) => workspace.orgId === localStorage.getItem("orgData.id")) || - []; const currentOrg = String(router.query.id); + const orgWorkspaces = workspaces?.filter((workspace) => workspace.orgId === currentOrg) || []; const { createNotification } = useNotificationContext(); const addWsUser = useAddUserToWs(); @@ -614,21 +612,29 @@ const OrganizationPage = withPermission( )}
-
- -
- Scheduled maintenance on January 27th
- We've planned a database upgrade and need to pause certain functionality for approximately 3 hours on Saturday, January 27th, 10am EST. During these hours, read operations will continue to function normally but no resources will be editable. No action is required on your end — your applications can continue to fetch secrets.
-
- + } mb-4 flex w-full flex-row items-center rounded-md border border-primary-600 bg-primary/10 p-2 text-base text-white`} + > + +
+ Scheduled maintenance on January 27th{" "} +
+ We've planned a database upgrade and need to pause certain functionality for + approximately 3 hours on Saturday, January 27th, 10am EST. During these hours, read + operations will continue to function normally but no resources will be editable. No + action is required on your end — your applications can continue to fetch secrets. +
+
+

Projects