Skip to content

Commit 7e687e4

Browse files
Packages update (#423)
* use nodejs 12 * fix docker image * Bump version up to 1.0.21 * use nodejs 14 * use nodejs 16 * update some packages * update typescript version * update packages and rewrite one directive * rewrite default value directive * rewrite validate directive * rewrite upload image directive * refactor all directives * fix upload * Bump version up to 1.0.22 * remove unnecessary stuff Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 4e15bd3 commit 7e687e4

25 files changed

+997
-1144
lines changed

.github/config.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.

package.json

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hawk.api",
3-
"version": "1.0.21",
3+
"version": "1.0.22",
44
"main": "index.ts",
55
"license": "UNLICENSED",
66
"scripts": {
@@ -24,47 +24,49 @@
2424
"jest": "^26.2.2",
2525
"nodemon": "^2.0.2",
2626
"ts-jest": "^26.1.4",
27-
"ts-node": "^8.6.2",
28-
"typescript": "^3.7.5"
27+
"ts-node": "^10.9.1",
28+
"typescript": "^4.7.4"
2929
},
3030
"dependencies": {
3131
"@amplitude/node": "^1.10.0",
32+
"@graphql-tools/merge": "^8.3.1",
33+
"@graphql-tools/schema": "^8.5.1",
34+
"@graphql-tools/utils": "^8.9.0",
3235
"@hawk.so/nodejs": "^3.1.1",
3336
"@hawk.so/types": "^0.1.18",
3437
"@types/amqp-connection-manager": "^2.0.4",
3538
"@types/bson": "^4.0.5",
3639
"@types/debug": "^4.1.5",
3740
"@types/escape-html": "^1.0.0",
41+
"@types/graphql-upload": "^8.0.11",
3842
"@types/jsonwebtoken": "^8.3.5",
3943
"@types/mime-types": "^2.1.0",
4044
"@types/mongodb": "^3.6.20",
41-
"@types/node": "^14.0.13",
45+
"@types/node": "^16.11.46",
4246
"@types/node-fetch": "^2.5.4",
43-
"@types/uuid": "^3.4.6",
47+
"@types/uuid": "^8.3.4",
4448
"amqp-connection-manager": "^3.1.0",
4549
"amqplib": "^0.5.5",
46-
"apollo-server-express": "^2.14.2",
47-
"argon2": "^0.26.2",
50+
"apollo-server-express": "^3.10.0",
51+
"argon2": "^0.28.7",
4852
"aws-sdk": "^2.1174.0",
49-
"axios": "^0.21.2",
53+
"axios": "^0.27.2",
5054
"body-parser": "^1.19.0",
5155
"bson": "^4.6.5",
5256
"dataloader": "^2.0.0",
53-
"dotenv": "^8.2.0",
57+
"dotenv": "^16.0.1",
5458
"escape-html": "^1.0.3",
5559
"express": "^4.17.1",
56-
"graphql": "^14.5.8",
57-
"graphql-iso-date": "^3.6.1",
58-
"graphql-list-fields": "^2.0.2",
59-
"graphql-scalars": "^1.2.7",
60+
"graphql": "^16.5.0",
61+
"graphql-scalars": "^1.17.0",
6062
"graphql-type-json": "^0.3.0",
61-
"graphql-upload": "^9.0.0",
63+
"graphql-upload": "^13",
6264
"jsonwebtoken": "^8.5.1",
6365
"lodash": "^4.17.15",
6466
"migrate-mongo": "^7.0.1",
6567
"mime-types": "^2.1.25",
6668
"mongodb": "^3.7.3",
67-
"ts-node-dev": "^1.0.0-pre.44",
68-
"uuid": "^3.3.3"
69+
"ts-node-dev": "^2.0.0",
70+
"uuid": "^8.3.2"
6971
}
7072
}

src/directives/defaultValue.ts

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,45 @@
1-
import { UnknownGraphQLField, UnknownGraphQLResolverResult } from '../types/graphql';
2-
import {
3-
SchemaDirectiveVisitor
4-
} from 'apollo-server-express';
5-
import { defaultFieldResolver } from 'graphql';
1+
import {defaultFieldResolver, GraphQLSchema} from "graphql";
2+
import {mapSchema, MapperKind, getDirective} from '@graphql-tools/utils'
3+
import {UnknownGraphQLResolverResult} from "../types/graphql";
64

7-
/**
8-
* Directive for setting field default value
9-
*/
10-
export default class DefaultValueDirective extends SchemaDirectiveVisitor {
11-
/**
12-
* Method to be called on field visit
13-
* @param field {UnknownGraphQLField} - GraphQL field definition
14-
*/
15-
public visitFieldDefinition(field: UnknownGraphQLField): void {
16-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
17-
let value: any;
5+
export default function defaultValueDirective(directiveName = 'default') {
6+
return {
7+
defaultValueDirectiveTypeDefs:`
8+
"""
9+
Directive for setting field default value
10+
"""
11+
directive @${directiveName}(
12+
"Default field value encoded in JSON"
13+
value: String!
14+
) on FIELD_DEFINITION
15+
`,
16+
defaultValueDirectiveTransformer: (schema: GraphQLSchema) =>
17+
mapSchema(schema, {
18+
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => {
19+
const defaultValueDirective = getDirective(schema, fieldConfig, directiveName)?.[0];
1820

19-
try {
20-
value = JSON.parse(this.args.value);
21-
} catch (_) {
22-
console.warn('Value for @default directive should be JSON string.');
23-
}
24-
const { resolve = defaultFieldResolver } = field;
21+
if (defaultValueDirective) {
22+
let { value } = defaultValueDirective as {value: string};
23+
try {
24+
value = JSON.parse(value);
25+
} catch (_) {
26+
console.warn('Value for @default directive should be JSON string.');
27+
}
2528

26-
field.resolve = async (object, args, context, info): UnknownGraphQLResolverResult => {
27-
let result = await resolve.call(this, object, args, context, info);
29+
const { resolve = defaultFieldResolver } = fieldConfig;
2830

29-
if (value && !result) {
30-
result = value;
31-
}
31+
fieldConfig.resolve = async (object, args, context, info): UnknownGraphQLResolverResult => {
32+
let result = await resolve(object, args, context, info);
3233

33-
return result;
34-
};
34+
if (value && !result) {
35+
result = value;
36+
}
37+
38+
return result;
39+
};
40+
}
41+
return fieldConfig;
42+
}
43+
})
3544
}
36-
};
45+
}

src/directives/renameFrom.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/directives/renameFrom.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {defaultFieldResolver, GraphQLSchema} from "graphql";
2+
import {mapSchema, MapperKind, getDirective} from '@graphql-tools/utils'
3+
4+
export default function renameFromDirective(directiveName = 'renameFrom') {
5+
return {
6+
renameFromDirectiveTypeDefs:`
7+
"""
8+
Directive for field renaming
9+
"""
10+
directive @${directiveName}(
11+
"Parent's field name"
12+
name: String!
13+
) on FIELD_DEFINITION
14+
`,
15+
renameFromDirectiveTransformer: (schema: GraphQLSchema) =>
16+
mapSchema(schema, {
17+
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => {
18+
const renameFromDirective = getDirective(schema, fieldConfig, directiveName)?.[0];
19+
20+
if (renameFromDirective) {
21+
const { name } = renameFromDirective as {name: string};
22+
23+
const { resolve = defaultFieldResolver } = fieldConfig;
24+
fieldConfig.resolve = (parent, args, context, info) => {
25+
parent[fieldName] = parent[name];
26+
27+
return resolve(parent, args, context, info);
28+
}
29+
}
30+
return fieldConfig;
31+
}
32+
})
33+
}
34+
}

src/directives/requireAdmin.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {defaultFieldResolver, GraphQLSchema} from "graphql";
2+
import {mapSchema, MapperKind, getDirective} from '@graphql-tools/utils'
3+
import {ResolverContextWithUser, UnknownGraphQLResolverResult} from "../types/graphql";
4+
import {ForbiddenError, UserInputError} from "apollo-server-express";
5+
import WorkspaceModel from "../models/workspace";
6+
7+
/**
8+
* Check is user admin via workspace id
9+
* @param context - resolver context
10+
* @param workspaceId - workspace id to check
11+
*/
12+
async function checkByWorkspaceId(context: ResolverContextWithUser, workspaceId: string): Promise<void> {
13+
const workspace = await context.factories.workspacesFactory.findById(workspaceId);
14+
15+
if (!workspace) {
16+
throw new UserInputError('There is no workspace with that id');
17+
}
18+
19+
const member = await workspace.getMemberInfo(context.user.id);
20+
21+
if (!member || WorkspaceModel.isPendingMember(member)) {
22+
throw new ForbiddenError('You are not a member of this workspace');
23+
}
24+
25+
if (!member.isAdmin) {
26+
throw new ForbiddenError('Not enough permissions');
27+
}
28+
}
29+
30+
/**
31+
* Check is user admin via project id
32+
* @param context - resolver context
33+
* @param projectId - project id to check
34+
*/
35+
async function checkByProjectId(context: ResolverContextWithUser, projectId: string): Promise<void> {
36+
const project = await context.factories.projectsFactory.findById(projectId);
37+
38+
if (!project) {
39+
throw new UserInputError('There is no project with provided ID');
40+
}
41+
42+
await checkByWorkspaceId(context, project.workspaceId.toString());
43+
}
44+
45+
/**
46+
* Defines directive for accessing to a field only for admins
47+
*
48+
* Order to check workspace or project id:
49+
* 1) args.workspaceId
50+
* 2) args.input.workspaceId
51+
* 3) args.projectId
52+
* 4) args.input.projectId
53+
*/
54+
export default function requireAdminDirective(directiveName = 'requireAdmin') {
55+
return {
56+
requireAdminDirectiveTypeDefs: `
57+
"""
58+
Access to the field only for admins
59+
"""
60+
directive @${directiveName} on FIELD_DEFINITION
61+
`,
62+
requireAdminDirectiveTransformer: (schema: GraphQLSchema) =>
63+
mapSchema(schema, {
64+
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => {
65+
const requireAdminDirective = getDirective(schema, fieldConfig, directiveName)?.[0];
66+
67+
if (requireAdminDirective) {
68+
const {
69+
resolve = defaultFieldResolver,
70+
} = fieldConfig;
71+
72+
/**
73+
* New field resolver
74+
* @param resolverArgs - default GraphQL resolver args
75+
*/
76+
fieldConfig.resolve = async (...resolverArgs): UnknownGraphQLResolverResult => {
77+
const [, args, context] = resolverArgs;
78+
79+
if (args.workspaceId) {
80+
await checkByWorkspaceId(context, args.workspaceId);
81+
}
82+
83+
if (args.input?.projectId) {
84+
await checkByProjectId(context, args.input.projectId);
85+
}
86+
87+
return resolve(...resolverArgs);
88+
};
89+
}
90+
return fieldConfig;
91+
}
92+
})
93+
}
94+
}

src/directives/requireAdminDirective.ts

Lines changed: 0 additions & 84 deletions
This file was deleted.

0 commit comments

Comments
 (0)