Skip to content

Commit

Permalink
feat(api): add variable module and relevant features
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b committed Feb 19, 2024
1 parent 3960581 commit d0fedc2
Show file tree
Hide file tree
Showing 18 changed files with 950 additions and 23 deletions.
4 changes: 3 additions & 1 deletion apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { WorkspaceModule } from '../workspace/workspace.module'
import { WorkspaceRoleModule } from '../workspace-role/workspace-role.module'
import { ApiKeyGuard } from '../auth/guard/api-key/api-key.guard'
import { EventModule } from '../event/event.module'
import { VariableModule } from '../variable/variable.module'

@Module({
controllers: [AppController],
Expand All @@ -34,7 +35,8 @@ import { EventModule } from '../event/event.module'
EnvironmentModule,
WorkspaceModule,
WorkspaceRoleModule,
EventModule
EventModule,
VariableModule
],
providers: [
{
Expand Down
18 changes: 16 additions & 2 deletions apps/api/src/common/create-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
Secret,
User,
Workspace,
WorkspaceRole
WorkspaceRole,
Variable
} from '@prisma/client'
import { JsonObject } from '@prisma/client/runtime/library'

Expand All @@ -19,7 +20,14 @@ export default async function createEvent(
triggerer?: EventTriggerer
severity?: EventSeverity
triggeredBy?: User
entity?: Workspace | Project | Environment | WorkspaceRole | ApiKey | Secret
entity?:
| Workspace
| Project
| Environment
| WorkspaceRole
| ApiKey
| Secret
| Variable
type: EventType
source: EventSource
title: string
Expand Down Expand Up @@ -85,6 +93,12 @@ export default async function createEvent(
}
break
}
case EventSource.VARIABLE: {
if (data.entity) {
baseData.sourceVariableId = data.entity.id
}
break
}
case EventSource.USER: {
break
}
Expand Down
13 changes: 13 additions & 0 deletions apps/api/src/common/get-default-project-environemnt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Environment, PrismaClient, Project } from '@prisma/client'

export default async function getDefaultEnvironmentOfProject(
projectId: Project['id'],
prisma: PrismaClient
): Promise<Environment | null> {
return await prisma.environment.findFirst({
where: {
projectId,
isDefault: true
}
})
}
57 changes: 57 additions & 0 deletions apps/api/src/common/get-variable-with-authority.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Authority, PrismaClient, User, Variable } from '@prisma/client'
import getCollectiveProjectAuthorities from './get-collective-project-authorities'
import { NotFoundException, UnauthorizedException } from '@nestjs/common'
import { VariableWithProjectAndVersion } from '../variable/variable.types'

export default async function getVariableWithAuthority(
userId: User['id'],
variableId: Variable['id'],
authority: Authority,
prisma: PrismaClient
): Promise<VariableWithProjectAndVersion> {
// Fetch the variable
let variable: VariableWithProjectAndVersion

try {
variable = await prisma.variable.findUnique({
where: {
id: variableId
},
include: {
versions: true,
project: true,
environment: {
select: {
id: true,
name: true
}
}
}
})
} catch (error) {
/* empty */
}

if (!variable) {
throw new NotFoundException(`Variable with id ${variableId} not found`)
}

// Check if the user has the project in their workspace role list
const permittedAuthorities = await getCollectiveProjectAuthorities(
userId,
variable.project,
prisma
)

// Check if the user has the required authorities
if (
!permittedAuthorities.has(authority) &&
!permittedAuthorities.has(Authority.WORKSPACE_ADMIN)
) {
throw new UnauthorizedException(
`User ${userId} does not have the required authorities`
)
}

return variable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.


ALTER TYPE "Authority" ADD VALUE 'CREATE_VARIABLE';
ALTER TYPE "Authority" ADD VALUE 'READ_VARIABLE';
ALTER TYPE "Authority" ADD VALUE 'UPDATE_VARIABLE';
ALTER TYPE "Authority" ADD VALUE 'DELETE_VARIABLE';

-- AlterEnum
ALTER TYPE "EventSource" ADD VALUE 'VARIABLE';

-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.


ALTER TYPE "EventType" ADD VALUE 'VARIABLE_UPDATED';
ALTER TYPE "EventType" ADD VALUE 'VARIABLE_DELETED';
ALTER TYPE "EventType" ADD VALUE 'VARIABLE_ADDED';

-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.


ALTER TYPE "NotificationType" ADD VALUE 'VARIABLE_UPDATED';
ALTER TYPE "NotificationType" ADD VALUE 'VARIABLE_DELETED';
ALTER TYPE "NotificationType" ADD VALUE 'VARIABLE_ADDED';

-- AlterTable
ALTER TABLE "Event" ADD COLUMN "sourceVariableId" TEXT;

-- CreateTable
CREATE TABLE "VariableVersion" (
"id" TEXT NOT NULL,
"value" TEXT NOT NULL,
"version" INTEGER NOT NULL DEFAULT 1,
"variableId" TEXT NOT NULL,
"createdOn" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"createdById" TEXT,

CONSTRAINT "VariableVersion_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Variable" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"lastUpdatedById" TEXT,
"projectId" TEXT NOT NULL,
"environmentId" TEXT NOT NULL,

CONSTRAINT "Variable_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "VariableVersion_variableId_version_key" ON "VariableVersion"("variableId", "version");

-- CreateIndex
CREATE UNIQUE INDEX "Variable_projectId_environmentId_name_key" ON "Variable"("projectId", "environmentId", "name");

-- AddForeignKey
ALTER TABLE "Event" ADD CONSTRAINT "Event_sourceVariableId_fkey" FOREIGN KEY ("sourceVariableId") REFERENCES "Variable"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "VariableVersion" ADD CONSTRAINT "VariableVersion_variableId_fkey" FOREIGN KEY ("variableId") REFERENCES "Variable"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "VariableVersion" ADD CONSTRAINT "VariableVersion_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Variable" ADD CONSTRAINT "Variable_lastUpdatedById_fkey" FOREIGN KEY ("lastUpdatedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Variable" ADD CONSTRAINT "Variable_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Variable" ADD CONSTRAINT "Variable_environmentId_fkey" FOREIGN KEY ("environmentId") REFERENCES "Environment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
65 changes: 59 additions & 6 deletions apps/api/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ datasource db {

enum EventSource {
SECRET
VARIABLE
API_KEY
ENVIRONMENT
PROJECT
Expand Down Expand Up @@ -48,6 +49,9 @@ enum EventType {
SECRET_UPDATED
SECRET_DELETED
SECRET_ADDED
VARIABLE_UPDATED
VARIABLE_DELETED
VARIABLE_ADDED
API_KEY_UPDATED
API_KEY_DELETED
API_KEY_ADDED
Expand Down Expand Up @@ -85,6 +89,10 @@ enum Authority {
READ_ENVIRONMENT
UPDATE_ENVIRONMENT
DELETE_ENVIRONMENT
CREATE_VARIABLE
READ_VARIABLE
UPDATE_VARIABLE
DELETE_VARIABLE
// User authorities
CREATE_WORKSPACE
Expand Down Expand Up @@ -112,6 +120,9 @@ enum NotificationType {
ENVIRONMENT_UPDATED
ENVIRONMENT_DELETED
ENVIRONMENT_ADDED
VARIABLE_UPDATED
VARIABLE_DELETED
VARIABLE_ADDED
}

model Event {
Expand All @@ -137,6 +148,8 @@ model Event {
sourceEnvironmentId String?
sourceSecret Secret? @relation(fields: [sourceSecretId], references: [id], onDelete: SetNull, onUpdate: Cascade)
sourceSecretId String?
sourceVariable Variable? @relation(fields: [sourceVariableId], references: [id], onDelete: SetNull, onUpdate: Cascade)
sourceVariableId String?
sourceApiKey ApiKey? @relation(fields: [sourceApiKeyId], references: [id], onDelete: SetNull, onUpdate: Cascade)
sourceApiKeyId String?
sourceWorkspaceMembership WorkspaceMember? @relation(fields: [sourceWorkspaceMembershipId], references: [id], onDelete: SetNull, onUpdate: Cascade)
Expand Down Expand Up @@ -170,9 +183,11 @@ model User {
otp Otp?
notifications Notification[]
secrets Secret[] // Stores the secrets the user updated
variables Variable[] // Stores the variables the user updated
projects Project[] // Stores the projects the user updated
environments Environment[] // Stores the environments the user updated
secretVersion SecretVersion[]
variableVersion VariableVersion[]
events Event[]
@@index([email], name: "email")
Expand All @@ -198,7 +213,8 @@ model Environment {
lastUpdatedBy User? @relation(fields: [lastUpdatedById], references: [id], onUpdate: Cascade, onDelete: SetNull)
lastUpdatedById String?
secrets Secret[]
secrets Secret[]
variables Variable[]
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
projectId String
Expand Down Expand Up @@ -226,11 +242,12 @@ model Project {
workspaceId String
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade, onUpdate: Cascade)
events Event[]
secrets Secret[]
environments Environment[]
workspaceRole WorkspaceRole? @relation(fields: [workspaceRoleId], references: [id], onDelete: SetNull, onUpdate: Cascade)
workspaceRoleId String?
events Event[]
secrets Secret[]
variables Variable[]
environments Environment[]
workspaceRole WorkspaceRole? @relation(fields: [workspaceRoleId], references: [id], onDelete: SetNull, onUpdate: Cascade)
workspaceRoleId String?
}

model WorkspaceRole {
Expand Down Expand Up @@ -317,6 +334,42 @@ model Secret {
@@unique([projectId, environmentId, name])
}

model VariableVersion {
id String @id @default(cuid())
value String
version Int @default(1)
variableId String
variable Variable @relation(fields: [variableId], references: [id], onDelete: Cascade, onUpdate: Cascade)
createdOn DateTime @default(now())
createdBy User? @relation(fields: [createdById], references: [id], onUpdate: Cascade, onDelete: SetNull)
createdById String?
@@unique([variableId, version])
}

model Variable {
id String @id @default(cuid())
name String
versions VariableVersion[] // Stores the versions of the variable
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastUpdatedBy User? @relation(fields: [lastUpdatedById], references: [id], onUpdate: Cascade, onDelete: SetNull)
lastUpdatedById String?
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
environmentId String
environment Environment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade)
events Event[]
@@unique([projectId, environmentId, name])
}

model ApiKey {
id String @id @default(cuid())
name String
Expand Down
Loading

0 comments on commit d0fedc2

Please sign in to comment.