Skip to content

Commit befe1af

Browse files
authored
1 parent 3e89e75 commit befe1af

20 files changed

+511
-107
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Migration `20210724121852-roles`
2+
3+
This migration has been generated by Pavlo Strunkin <[email protected]> at 7/24/2021, 3:18:52 PM.
4+
You can check out the [state of the schema](./schema.prisma) after the migration.
5+
6+
## Database Steps
7+
8+
```sql
9+
CREATE TYPE "public"."Role" AS ENUM ('admin', 'editor', 'guest')
10+
11+
ALTER TABLE "User" ADD COLUMN "role" "Role" NOT NULL DEFAULT E'guest'
12+
```
13+
14+
## Changes
15+
16+
```diff
17+
diff --git schema.prisma schema.prisma
18+
migration 20210709133029-275-project-to-testrun-relation..20210724121852-roles
19+
--- datamodel.dml
20+
+++ datamodel.dml
21+
@@ -3,9 +3,9 @@
22+
}
23+
datasource db {
24+
provider = "postgresql"
25+
- url = "***"
26+
+ url = "***"
27+
}
28+
model Build {
29+
id String @id @default(uuid())
30+
@@ -122,8 +122,9 @@
31+
apiKey String @unique
32+
isActive Boolean @default(true)
33+
builds Build[]
34+
baselines Baseline[]
35+
+ role Role @default(guest)
36+
updatedAt DateTime @updatedAt
37+
createdAt DateTime @default(now())
38+
}
39+
@@ -140,4 +141,10 @@
40+
pixelmatch
41+
lookSame
42+
odiff
43+
}
44+
+
45+
+enum Role {
46+
+ admin
47+
+ editor
48+
+ guest
49+
+}
50+
```
51+
52+
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
generator client {
2+
provider = "prisma-client-js"
3+
}
4+
5+
datasource db {
6+
provider = "postgresql"
7+
url = "***"
8+
}
9+
10+
model Build {
11+
id String @id @default(uuid())
12+
ciBuildId String?
13+
number Int?
14+
branchName String?
15+
status String?
16+
testRuns TestRun[]
17+
projectId String
18+
project Project @relation(fields: [projectId], references: [id])
19+
updatedAt DateTime @updatedAt
20+
createdAt DateTime @default(now())
21+
user User? @relation(fields: [userId], references: [id])
22+
userId String?
23+
isRunning Boolean?
24+
25+
@@unique([projectId, ciBuildId])
26+
}
27+
28+
model Project {
29+
id String @id @default(uuid())
30+
name String
31+
mainBranchName String @default("master")
32+
builds Build[]
33+
buildsCounter Int @default(0)
34+
maxBuildAllowed Int @default(100)
35+
maxBranchLifetime Int @default(30)
36+
testVariations TestVariation[]
37+
updatedAt DateTime @updatedAt
38+
createdAt DateTime @default(now())
39+
// config
40+
autoApproveFeature Boolean @default(false)
41+
imageComparison ImageComparison @default(pixelmatch)
42+
imageComparisonConfig String @default("{ \"threshold\": 0.1, \"ignoreAntialiasing\": true, \"allowDiffDimensions\": false }")
43+
44+
TestRun TestRun[]
45+
@@unique([name])
46+
}
47+
48+
model TestRun {
49+
id String @id @default(uuid())
50+
imageName String
51+
diffName String?
52+
diffPercent Float?
53+
diffTollerancePercent Float @default(0)
54+
pixelMisMatchCount Int?
55+
status TestStatus
56+
buildId String
57+
build Build @relation(fields: [buildId], references: [id])
58+
testVariationId String?
59+
testVariation TestVariation? @relation(fields: [testVariationId], references: [id])
60+
projectId String?
61+
project Project? @relation(fields: [projectId], references: [id])
62+
merge Boolean @default(false)
63+
updatedAt DateTime @updatedAt
64+
createdAt DateTime @default(now())
65+
// Test variation data
66+
name String @default("")
67+
browser String?
68+
device String?
69+
os String?
70+
viewport String?
71+
customTags String? @default("")
72+
baselineName String?
73+
comment String?
74+
baseline Baseline?
75+
branchName String @default("master")
76+
baselineBranchName String?
77+
ignoreAreas String @default("[]")
78+
tempIgnoreAreas String @default("[]")
79+
}
80+
81+
model TestVariation {
82+
id String @id @default(uuid())
83+
name String
84+
branchName String @default("master")
85+
browser String @default("")
86+
device String @default("")
87+
os String @default("")
88+
viewport String @default("")
89+
customTags String @default("")
90+
baselineName String?
91+
ignoreAreas String @default("[]")
92+
projectId String
93+
project Project @relation(fields: [projectId], references: [id])
94+
testRuns TestRun[]
95+
baselines Baseline[]
96+
comment String?
97+
updatedAt DateTime @updatedAt
98+
createdAt DateTime @default(now())
99+
100+
@@unique([projectId, name, browser, device, os, viewport, customTags, branchName])
101+
}
102+
103+
model Baseline {
104+
id String @id @default(uuid())
105+
baselineName String
106+
testVariationId String
107+
testVariation TestVariation @relation(fields: [testVariationId], references: [id])
108+
testRunId String?
109+
testRun TestRun? @relation(fields: [testRunId], references: [id])
110+
userId String?
111+
user User? @relation(fields: [userId], references: [id])
112+
updatedAt DateTime @updatedAt
113+
createdAt DateTime @default(now())
114+
}
115+
116+
model User {
117+
id String @id @default(uuid())
118+
email String @unique
119+
password String
120+
firstName String?
121+
lastName String?
122+
apiKey String @unique
123+
isActive Boolean @default(true)
124+
builds Build[]
125+
baselines Baseline[]
126+
role Role @default(guest)
127+
updatedAt DateTime @updatedAt
128+
createdAt DateTime @default(now())
129+
}
130+
131+
enum TestStatus {
132+
failed
133+
new
134+
ok
135+
unresolved
136+
approved
137+
autoApproved
138+
}
139+
140+
enum ImageComparison {
141+
pixelmatch
142+
lookSame
143+
odiff
144+
}
145+
146+
enum Role {
147+
admin
148+
editor
149+
guest
150+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"version": "0.3.14-fixed",
3+
"steps": [
4+
{
5+
"tag": "CreateEnum",
6+
"enum": "Role",
7+
"values": [
8+
"admin",
9+
"editor",
10+
"guest"
11+
]
12+
},
13+
{
14+
"tag": "CreateField",
15+
"model": "User",
16+
"field": "role",
17+
"type": "Role",
18+
"arity": "Required"
19+
},
20+
{
21+
"tag": "CreateDirective",
22+
"location": {
23+
"path": {
24+
"tag": "Field",
25+
"model": "User",
26+
"field": "role"
27+
},
28+
"directive": "default"
29+
}
30+
},
31+
{
32+
"tag": "CreateArgument",
33+
"location": {
34+
"tag": "Directive",
35+
"path": {
36+
"tag": "Field",
37+
"model": "User",
38+
"field": "role"
39+
},
40+
"directive": "default"
41+
},
42+
"argument": "",
43+
"value": "guest"
44+
}
45+
]
46+
}

prisma/migrations/migrate.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
20210705154453-baseline-author
2424
20210709115233-gh-275-max-branch-lifetime
2525
20210709133029-275-project-to-testrun-relation
26+
20210724121852-roles

prisma/schema.prisma

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ model User {
123123
isActive Boolean @default(true)
124124
builds Build[]
125125
baselines Baseline[]
126+
role Role @default(guest)
126127
updatedAt DateTime @updatedAt
127128
createdAt DateTime @default(now())
128129
}
@@ -141,3 +142,9 @@ enum ImageComparison {
141142
lookSame
142143
odiff
143144
}
145+
146+
enum Role {
147+
admin
148+
editor
149+
guest
150+
}

prisma/seed.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PrismaClient } from '@prisma/client';
1+
import { PrismaClient, Role } from '@prisma/client';
22
import uuidAPIKey from 'uuid-apikey';
33
import { genSalt, hash } from 'bcryptjs';
44

@@ -20,29 +20,38 @@ seed()
2020
async function createDefaultUser() {
2121
const userList = await prisma.user.findMany();
2222
console.log(userList);
23-
if (userList.length === 0) {
24-
const defaultEmail = '[email protected]';
25-
const defaultPassword = '123456';
26-
const salt = await genSalt(10);
27-
await prisma.user
28-
.create({
29-
data: {
30-
email: defaultEmail,
31-
firstName: 'fname',
32-
lastName: 'lname',
33-
apiKey: uuidAPIKey.create({ noDashes: true }).apiKey,
34-
password: await hash(defaultPassword, salt),
35-
},
36-
})
37-
.then((user) => {
38-
console.log('###########################');
39-
console.log('## CREATING DEFAULT USER ##');
40-
console.log('###########################');
41-
console.log('');
42-
console.log(`The user with the email "${defaultEmail}" and password "${defaultPassword}" was created`);
43-
console.log(`The Api key is: ${user.apiKey}`);
44-
});
45-
}
23+
24+
const defaultEmail = '[email protected]';
25+
const defaultPassword = '123456';
26+
const salt = await genSalt(10);
27+
28+
await prisma.user
29+
.upsert({
30+
where: {
31+
email: defaultEmail,
32+
},
33+
update: {
34+
role: Role.admin,
35+
},
36+
create: {
37+
email: defaultEmail,
38+
firstName: 'fname',
39+
lastName: 'lname',
40+
role: Role.admin,
41+
apiKey: uuidAPIKey.create({ noDashes: true }).apiKey,
42+
password: await hash(defaultPassword, salt),
43+
},
44+
})
45+
.then((user) => {
46+
console.log('###########################');
47+
console.log('####### DEFAULT USER ######');
48+
console.log('###########################');
49+
console.log('');
50+
console.log(
51+
`The user with the email "${defaultEmail}" and password "${defaultPassword}" was created (if not changed before)`
52+
);
53+
console.log(`The Api key is: ${user.apiKey}`);
54+
});
4655
}
4756

4857
async function createDefaultProject() {

src/auth/guards/role.guard.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ExecutionContext, Injectable, CanActivate } from '@nestjs/common';
2+
import { Role, User } from '@prisma/client';
3+
import { Request } from 'express';
4+
import { PrismaService } from '../../prisma/prisma.service';
5+
import { Reflector } from '@nestjs/core';
6+
7+
@Injectable()
8+
export class RoleGuard implements CanActivate {
9+
constructor(private readonly prismaService: PrismaService, private reflector: Reflector) {}
10+
11+
async canActivate(context: ExecutionContext): Promise<boolean> {
12+
const roles = this.reflector.get<Role[]>('roles', context.getHandler());
13+
if (!roles) {
14+
return true;
15+
}
16+
17+
const user = await this.getUser(context);
18+
return this.checkPermission(user);
19+
}
20+
21+
checkPermission = (user: User): boolean => {
22+
switch (user.role) {
23+
case Role.admin: {
24+
return true;
25+
}
26+
case Role.editor: {
27+
// check project permissions later
28+
return true;
29+
}
30+
default:
31+
return false;
32+
}
33+
};
34+
35+
getUser = async (context: ExecutionContext): Promise<User> => {
36+
const request: Request = context.switchToHttp().getRequest();
37+
38+
if (request.user) {
39+
return request.user as User;
40+
}
41+
42+
return this.prismaService.user.findUnique({
43+
where: { apiKey: request.header('apiKey') },
44+
});
45+
};
46+
}

0 commit comments

Comments
 (0)