@memberjunction/server 2.1.5 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apolloServer/TransactionPlugin.d.ts +1 -1
- package/dist/apolloServer/TransactionPlugin.d.ts.map +1 -1
- package/dist/apolloServer/TransactionPlugin.js.map +1 -1
- package/dist/apolloServer/index.d.ts +1 -1
- package/dist/apolloServer/index.d.ts.map +1 -1
- package/dist/apolloServer/index.js +2 -2
- package/dist/apolloServer/index.js.map +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +7 -7
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +18 -8
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/newUsers.js +1 -1
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +4 -4
- package/dist/context.js.map +1 -1
- package/dist/directives/Public.d.ts +1 -1
- package/dist/directives/Public.d.ts.map +1 -1
- package/dist/directives/index.d.ts +1 -1
- package/dist/directives/index.d.ts.map +1 -1
- package/dist/directives/index.js +1 -1
- package/dist/directives/index.js.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js +5 -6
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
- package/dist/generated/generated.d.ts +14 -2
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +79 -18
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +3 -3
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +1 -1
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +2 -2
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +1 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +21 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -27
- package/dist/index.js.map +1 -1
- package/dist/orm.js +4 -4
- package/dist/orm.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +3 -3
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +64 -59
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ColorResolver.d.ts +1 -1
- package/dist/resolvers/ColorResolver.d.ts.map +1 -1
- package/dist/resolvers/ColorResolver.js +1 -1
- package/dist/resolvers/ColorResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts +1 -1
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +2 -2
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityCommunicationsResolver.js +9 -4
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -2
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +2 -2
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts +2 -2
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +1 -1
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +2 -2
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts +2 -2
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +3 -3
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +2 -2
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +4 -2
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +2 -2
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/ReportResolver.d.ts +1 -1
- package/dist/resolvers/ReportResolver.d.ts.map +1 -1
- package/dist/resolvers/ReportResolver.js +16 -14
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +17 -16
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserResolver.d.ts +1 -1
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +1 -1
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +2 -2
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +11 -5
- package/dist/util.js.map +1 -1
- package/package.json +27 -23
- package/src/apolloServer/TransactionPlugin.ts +53 -0
- package/src/apolloServer/index.ts +33 -0
- package/src/auth/exampleNewUserSubClass.ts +79 -0
- package/src/auth/index.ts +171 -0
- package/src/auth/newUsers.ts +58 -0
- package/src/auth/tokenExpiredError.ts +12 -0
- package/src/cache.ts +10 -0
- package/src/config.ts +89 -0
- package/src/context.ts +111 -0
- package/src/directives/Public.ts +42 -0
- package/src/directives/index.ts +1 -0
- package/src/entitySubclasses/DuplicateRunEntity.server.ts +29 -0
- package/src/entitySubclasses/entityPermissions.server.ts +104 -0
- package/src/entitySubclasses/userViewEntity.server.ts +187 -0
- package/src/generated/generated.ts +25406 -0
- package/src/generic/DeleteOptionsInput.ts +13 -0
- package/src/generic/KeyInputOutputTypes.ts +35 -0
- package/src/generic/KeyValuePairInput.ts +14 -0
- package/src/generic/PushStatusResolver.ts +40 -0
- package/src/generic/ResolverBase.ts +767 -0
- package/src/generic/RunViewResolver.ts +579 -0
- package/src/index.ts +171 -0
- package/src/orm.ts +36 -0
- package/src/resolvers/AskSkipResolver.ts +1112 -0
- package/src/resolvers/ColorResolver.ts +61 -0
- package/src/resolvers/DatasetResolver.ts +115 -0
- package/src/resolvers/EntityCommunicationsResolver.ts +221 -0
- package/src/resolvers/EntityRecordNameResolver.ts +75 -0
- package/src/resolvers/EntityResolver.ts +35 -0
- package/src/resolvers/FileCategoryResolver.ts +69 -0
- package/src/resolvers/FileResolver.ts +152 -0
- package/src/resolvers/MergeRecordsResolver.ts +175 -0
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +91 -0
- package/src/resolvers/QueryResolver.ts +42 -0
- package/src/resolvers/ReportResolver.ts +144 -0
- package/src/resolvers/UserFavoriteResolver.ts +176 -0
- package/src/resolvers/UserResolver.ts +33 -0
- package/src/resolvers/UserViewResolver.ts +64 -0
- package/src/types.ts +40 -0
- package/src/util.ts +112 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AppContext } from '../types.js';
|
|
2
|
+
import { Ctx, Field, Int, ObjectType, PubSub, PubSubEngine, Query, Resolver, Root, Subscription } from 'type-graphql';
|
|
3
|
+
import { Public } from '../directives/index.js';
|
|
4
|
+
|
|
5
|
+
@ObjectType()
|
|
6
|
+
export class Color {
|
|
7
|
+
@Field(() => Int)
|
|
8
|
+
@Public()
|
|
9
|
+
ID: number;
|
|
10
|
+
|
|
11
|
+
@Field(() => String)
|
|
12
|
+
@Public()
|
|
13
|
+
name: string;
|
|
14
|
+
|
|
15
|
+
@Field(() => String)
|
|
16
|
+
@Public()
|
|
17
|
+
createdZ: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@ObjectType()
|
|
21
|
+
export class ColorNotification {
|
|
22
|
+
@Public()
|
|
23
|
+
@Field(() => String, { nullable: true })
|
|
24
|
+
message?: string;
|
|
25
|
+
|
|
26
|
+
@Public()
|
|
27
|
+
@Field((_type) => Date)
|
|
28
|
+
date!: Date;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ColorNotificationPayload {
|
|
32
|
+
message?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Resolver(Color)
|
|
36
|
+
export class ColorResolver {
|
|
37
|
+
@Subscription(() => ColorNotification, { topics: 'COLOR' })
|
|
38
|
+
@Public()
|
|
39
|
+
colorSubscription(@Root() { message }: ColorNotificationPayload): ColorNotification {
|
|
40
|
+
return { message, date: new Date() };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Query(() => [Color])
|
|
44
|
+
@Public()
|
|
45
|
+
async colors(@Ctx() _ctx: AppContext, @PubSub() pubSub: PubSubEngine) {
|
|
46
|
+
const createdZ = new Date().toISOString();
|
|
47
|
+
|
|
48
|
+
pubSub.publish('COLOR', {
|
|
49
|
+
message: 'Colors were requested!',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return [
|
|
53
|
+
{ ID: 1, name: 'Red', createdZ },
|
|
54
|
+
{ ID: 2, name: 'Orange', createdZ },
|
|
55
|
+
{ ID: 3, name: 'Yellow', createdZ },
|
|
56
|
+
{ ID: 4, name: 'Green', createdZ },
|
|
57
|
+
{ ID: 5, name: 'Blue', createdZ },
|
|
58
|
+
{ ID: 6, name: 'Purple', createdZ },
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Arg, Ctx, Field, InputType, Int, ObjectType, Query, Resolver } from 'type-graphql';
|
|
2
|
+
import { AppContext } from '../types.js';
|
|
3
|
+
import { LogError, Metadata } from '@memberjunction/core';
|
|
4
|
+
|
|
5
|
+
@ObjectType()
|
|
6
|
+
export class DatasetResultType {
|
|
7
|
+
@Field(() => String)
|
|
8
|
+
DatasetID: string;
|
|
9
|
+
|
|
10
|
+
@Field(() => String)
|
|
11
|
+
DatasetName: string;
|
|
12
|
+
|
|
13
|
+
@Field(() => Boolean)
|
|
14
|
+
Success: boolean;
|
|
15
|
+
|
|
16
|
+
@Field(() => String)
|
|
17
|
+
Status: string;
|
|
18
|
+
|
|
19
|
+
@Field(() => Date)
|
|
20
|
+
LatestUpdateDate: Date;
|
|
21
|
+
|
|
22
|
+
@Field(() => String)
|
|
23
|
+
Results: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@InputType()
|
|
27
|
+
export class DatasetItemFilterTypeGQL {
|
|
28
|
+
@Field(() => String)
|
|
29
|
+
ItemCode: string;
|
|
30
|
+
|
|
31
|
+
@Field(() => String)
|
|
32
|
+
Filter: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@Resolver(DatasetResultType)
|
|
37
|
+
export class DatasetResolverExtended {
|
|
38
|
+
@Query(() => DatasetResultType)
|
|
39
|
+
async GetDatasetByName(
|
|
40
|
+
@Arg('DatasetName', () => String) DatasetName: string,
|
|
41
|
+
@Ctx() {}: AppContext,
|
|
42
|
+
@Arg('ItemFilters', () => [DatasetItemFilterTypeGQL], { nullable: 'itemsAndList' }) ItemFilters?: DatasetItemFilterTypeGQL[]
|
|
43
|
+
) {
|
|
44
|
+
try {
|
|
45
|
+
const md = new Metadata();
|
|
46
|
+
const result = await md.GetDatasetByName(DatasetName, ItemFilters);
|
|
47
|
+
if (result) {
|
|
48
|
+
return {
|
|
49
|
+
DatasetID: result.DatasetID,
|
|
50
|
+
DatasetName: result.DatasetName,
|
|
51
|
+
Success: result.Success,
|
|
52
|
+
Status: result.Status,
|
|
53
|
+
LatestUpdateDate: result.LatestUpdateDate,
|
|
54
|
+
Results: JSON.stringify(result.Results),
|
|
55
|
+
};
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error('Error retrieving Dataset: ' + DatasetName);
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
LogError(err);
|
|
61
|
+
throw new Error('Error retrieving Dataset: ' + DatasetName + '\n\n' + err);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@ObjectType()
|
|
67
|
+
export class DatasetStatusResultType {
|
|
68
|
+
@Field(() => String)
|
|
69
|
+
DatasetID: string;
|
|
70
|
+
|
|
71
|
+
@Field(() => String)
|
|
72
|
+
DatasetName: string;
|
|
73
|
+
|
|
74
|
+
@Field(() => Boolean)
|
|
75
|
+
Success: boolean;
|
|
76
|
+
|
|
77
|
+
@Field(() => String)
|
|
78
|
+
Status: string;
|
|
79
|
+
|
|
80
|
+
@Field(() => Date)
|
|
81
|
+
LatestUpdateDate: Date;
|
|
82
|
+
|
|
83
|
+
@Field(() => String)
|
|
84
|
+
EntityUpdateDates: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Resolver(DatasetStatusResultType)
|
|
88
|
+
export class DatasetStatusResolver {
|
|
89
|
+
@Query(() => DatasetStatusResultType)
|
|
90
|
+
async GetDatasetStatusByName(
|
|
91
|
+
@Arg('DatasetName', () => String) DatasetName: string,
|
|
92
|
+
@Ctx() {}: AppContext,
|
|
93
|
+
@Arg('ItemFilters', () => [DatasetItemFilterTypeGQL], { nullable: 'itemsAndList' }) ItemFilters?: DatasetItemFilterTypeGQL[]
|
|
94
|
+
) {
|
|
95
|
+
try {
|
|
96
|
+
const md = new Metadata();
|
|
97
|
+
const result = await md.GetDatasetStatusByName(DatasetName, ItemFilters);
|
|
98
|
+
if (result) {
|
|
99
|
+
return {
|
|
100
|
+
DatasetID: result.DatasetID,
|
|
101
|
+
DatasetName: result.DatasetName,
|
|
102
|
+
Success: result.Success,
|
|
103
|
+
Status: result.Status,
|
|
104
|
+
LatestUpdateDate: result.LatestUpdateDate,
|
|
105
|
+
EntityUpdateDates: JSON.stringify(result.EntityUpdateDates),
|
|
106
|
+
};
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Error retrieving Dataset Status: ' + DatasetName);
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
LogError(err);
|
|
112
|
+
throw new Error('Error retrieving Dataset Status: ' + DatasetName + '\n\n' + err);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Arg, Ctx, Field, InputType, Int, ObjectType, Query, Resolver } from 'type-graphql';
|
|
2
|
+
import { AppContext } from '../types.js';
|
|
3
|
+
import { RunViewByIDInput } from '../generic/RunViewResolver.js';
|
|
4
|
+
import { Message } from '@memberjunction/communication-types';
|
|
5
|
+
import { EntityCommunicationsEngine } from '@memberjunction/entity-communications-server';
|
|
6
|
+
import { RunViewParams } from '@memberjunction/core';
|
|
7
|
+
import { GraphQLJSONObject } from 'graphql-type-json';
|
|
8
|
+
import { TemplateEngineServer } from '@memberjunction/templates';
|
|
9
|
+
import { EntityCommunicationParams } from '@memberjunction/entity-communications-base';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
|
|
12
|
+
@InputType()
|
|
13
|
+
export class CommunicationProviderMessageType {
|
|
14
|
+
@Field()
|
|
15
|
+
ID: number;
|
|
16
|
+
|
|
17
|
+
@Field()
|
|
18
|
+
CommunicationProviderID: number;
|
|
19
|
+
|
|
20
|
+
@Field()
|
|
21
|
+
CommunicationBaseMessageTypeID: number;
|
|
22
|
+
|
|
23
|
+
@Field()
|
|
24
|
+
Name: string;
|
|
25
|
+
|
|
26
|
+
@Field()
|
|
27
|
+
Status: string;
|
|
28
|
+
|
|
29
|
+
@Field()
|
|
30
|
+
AdditionalAttributes: string;
|
|
31
|
+
|
|
32
|
+
@Field()
|
|
33
|
+
_mj_CreatedAt: Date;
|
|
34
|
+
|
|
35
|
+
@Field()
|
|
36
|
+
_mj_UpdatedAt: Date;
|
|
37
|
+
|
|
38
|
+
@Field()
|
|
39
|
+
CommunicationProvider?: string;
|
|
40
|
+
|
|
41
|
+
@Field()
|
|
42
|
+
CommunicationBaseMessageType?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@InputType()
|
|
46
|
+
export class TemplateInputType {
|
|
47
|
+
@Field()
|
|
48
|
+
ID: number;
|
|
49
|
+
|
|
50
|
+
@Field()
|
|
51
|
+
Name: string;
|
|
52
|
+
|
|
53
|
+
@Field()
|
|
54
|
+
Description: string;
|
|
55
|
+
|
|
56
|
+
@Field({ nullable: true })
|
|
57
|
+
UserPrompt?: string;
|
|
58
|
+
|
|
59
|
+
@Field({ nullable: true })
|
|
60
|
+
CategoryID?: number;
|
|
61
|
+
|
|
62
|
+
@Field()
|
|
63
|
+
UserID: number;
|
|
64
|
+
|
|
65
|
+
@Field({ nullable: true })
|
|
66
|
+
ActiveAt?: Date;
|
|
67
|
+
|
|
68
|
+
@Field({ nullable: true })
|
|
69
|
+
DisabledAt?: Date;
|
|
70
|
+
|
|
71
|
+
@Field()
|
|
72
|
+
IsActive: boolean;
|
|
73
|
+
|
|
74
|
+
@Field()
|
|
75
|
+
_mj_CreatedAt: Date;
|
|
76
|
+
|
|
77
|
+
@Field()
|
|
78
|
+
_mj_UpdatedAt: Date;
|
|
79
|
+
|
|
80
|
+
@Field({ nullable: true })
|
|
81
|
+
Category?: string;
|
|
82
|
+
|
|
83
|
+
@Field({ nullable: true })
|
|
84
|
+
User?: string;
|
|
85
|
+
}
|
|
86
|
+
@InputType()
|
|
87
|
+
export class CommunicationMessageInput {
|
|
88
|
+
/**
|
|
89
|
+
* The type of message to send
|
|
90
|
+
*/
|
|
91
|
+
@Field(() => CommunicationProviderMessageType)
|
|
92
|
+
public MessageType: CommunicationProviderMessageType;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The sender of the message, typically an email address but can be anything that is provider-specific for example for a provider that is a social
|
|
96
|
+
* media provider, it might be a user's social media handle
|
|
97
|
+
*/
|
|
98
|
+
@Field()
|
|
99
|
+
public From: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The recipient of the message, typically an email address but can be anything that is provider-specific for example for a provider that is a social
|
|
103
|
+
* media provider, it might be a user's social media handle
|
|
104
|
+
*/
|
|
105
|
+
@Field()
|
|
106
|
+
public To: string;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The body of the message, used if BodyTemplate is not provided.
|
|
110
|
+
*/
|
|
111
|
+
@Field({ nullable: true })
|
|
112
|
+
public Body?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Optional, when provided, Body is ignored and the template is used to render the message. In addition,
|
|
115
|
+
* if BodyTemplate is provided it will be used to render the Body and if the template has HTML content it will
|
|
116
|
+
* also be used to render the HTMLBody
|
|
117
|
+
*/
|
|
118
|
+
@Field(() => TemplateInputType, { nullable: true })
|
|
119
|
+
public BodyTemplate?: TemplateInputType;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The HTML body of the message
|
|
123
|
+
*/
|
|
124
|
+
@Field({ nullable: true })
|
|
125
|
+
public HTMLBody?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Optional, when provided, HTMLBody is ignored and the template is used to render the message. This OVERRIDES
|
|
128
|
+
* the BodyTemplate's HTML content even if BodyTemplate is provided. This allows for flexibility in that you can
|
|
129
|
+
* specify a completely different HTMLBodyTemplate and not just relay on the TemplateContent of the BodyTemplate having
|
|
130
|
+
* an HTML option.
|
|
131
|
+
*/
|
|
132
|
+
@Field(() => TemplateInputType, { nullable: true })
|
|
133
|
+
public HTMLBodyTemplate?: TemplateInputType;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The subject line for the message, used if SubjectTemplate is not provided and only supported by some providers
|
|
137
|
+
*/
|
|
138
|
+
@Field({ nullable: true })
|
|
139
|
+
public Subject?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Optional, when provided, Subject is ignored and the template is used to render the message
|
|
142
|
+
*/
|
|
143
|
+
@Field(() => TemplateInputType, { nullable: true })
|
|
144
|
+
public SubjectTemplate?: TemplateInputType;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Optional, any context data that is needed to render the message template
|
|
148
|
+
*/
|
|
149
|
+
@Field(() => GraphQLJSONObject, { nullable: true })
|
|
150
|
+
public ContextData?: any;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@ObjectType()
|
|
154
|
+
export class RunEntityCommunicationResultType {
|
|
155
|
+
@Field()
|
|
156
|
+
Success: boolean;
|
|
157
|
+
|
|
158
|
+
@Field({ nullable: true })
|
|
159
|
+
ErrorMessage?: string;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Optional, any context data that is needed to render the message template
|
|
163
|
+
*/
|
|
164
|
+
@Field(() => GraphQLJSONObject, { nullable: true })
|
|
165
|
+
public Results?: any;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@Resolver(RunEntityCommunicationResultType)
|
|
169
|
+
export class ReportResolver {
|
|
170
|
+
@Query(() => RunEntityCommunicationResultType)
|
|
171
|
+
async RunEntityCommunicationByViewID(
|
|
172
|
+
@Arg('entityID', () => String) entityID: string,
|
|
173
|
+
@Arg('runViewByIDInput', () => RunViewByIDInput) runViewByIDInput: RunViewByIDInput,
|
|
174
|
+
@Arg('providerName', () => String) providerName: string,
|
|
175
|
+
@Arg('providerMessageTypeName', () => String) providerMessageTypeName: string,
|
|
176
|
+
@Arg('message', () => CommunicationMessageInput) message: CommunicationMessageInput,
|
|
177
|
+
@Arg('previewOnly', () => Boolean) previewOnly: boolean,
|
|
178
|
+
@Arg('includeProcessedMessages', () => Boolean) includeProcessedMessages: boolean,
|
|
179
|
+
@Ctx() { userPayload }: AppContext
|
|
180
|
+
): Promise<RunEntityCommunicationResultType> {
|
|
181
|
+
try {
|
|
182
|
+
await EntityCommunicationsEngine.Instance.Config(false, userPayload.userRecord);
|
|
183
|
+
const newMessage = new Message(message as unknown as Message);
|
|
184
|
+
await TemplateEngineServer.Instance.Config(false, userPayload.userRecord);
|
|
185
|
+
// for the templates, replace the values from the input with the objects from the Template Engine we have here
|
|
186
|
+
if (newMessage.BodyTemplate) {
|
|
187
|
+
newMessage.BodyTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.BodyTemplate.Name);
|
|
188
|
+
}
|
|
189
|
+
if (newMessage.HTMLBodyTemplate) {
|
|
190
|
+
newMessage.HTMLBodyTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.HTMLBodyTemplate.Name);
|
|
191
|
+
}
|
|
192
|
+
if (newMessage.SubjectTemplate) {
|
|
193
|
+
newMessage.SubjectTemplate = TemplateEngineServer.Instance.FindTemplate(newMessage.SubjectTemplate.Name);
|
|
194
|
+
}
|
|
195
|
+
const params: EntityCommunicationParams = {
|
|
196
|
+
EntityID: entityID,
|
|
197
|
+
RunViewParams: <RunViewParams>runViewByIDInput,
|
|
198
|
+
ProviderName: providerName,
|
|
199
|
+
ProviderMessageTypeName: providerMessageTypeName,
|
|
200
|
+
Message: newMessage,
|
|
201
|
+
PreviewOnly: previewOnly,
|
|
202
|
+
IncludeProcessedMessages: includeProcessedMessages,
|
|
203
|
+
};
|
|
204
|
+
const result = await EntityCommunicationsEngine.Instance.RunEntityCommunication(params);
|
|
205
|
+
return {
|
|
206
|
+
Success: result.Success,
|
|
207
|
+
ErrorMessage: result.ErrorMessage,
|
|
208
|
+
Results: includeProcessedMessages && result.Results ? { Results: result.Results } : undefined,
|
|
209
|
+
};
|
|
210
|
+
} catch (e) {
|
|
211
|
+
const { message } = z
|
|
212
|
+
.object({ message: z.string() })
|
|
213
|
+
.catch({ message: JSON.stringify(e) })
|
|
214
|
+
.parse(e);
|
|
215
|
+
return {
|
|
216
|
+
Success: false,
|
|
217
|
+
ErrorMessage: message,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Metadata, CompositeKey } from '@memberjunction/core';
|
|
2
|
+
import { Arg, Ctx, Field, InputType, ObjectType, Query, Resolver } from 'type-graphql';
|
|
3
|
+
import { AppContext } from '../types.js';
|
|
4
|
+
import { CompositeKeyInputType, CompositeKeyOutputType } from '../generic/KeyInputOutputTypes.js';
|
|
5
|
+
|
|
6
|
+
@InputType()
|
|
7
|
+
export class EntityRecordNameInput {
|
|
8
|
+
@Field(() => String)
|
|
9
|
+
EntityName: string;
|
|
10
|
+
|
|
11
|
+
@Field(() => CompositeKeyInputType)
|
|
12
|
+
CompositeKey: CompositeKey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@ObjectType()
|
|
16
|
+
export class EntityRecordNameResult {
|
|
17
|
+
@Field(() => Boolean)
|
|
18
|
+
Success: boolean;
|
|
19
|
+
|
|
20
|
+
@Field(() => String)
|
|
21
|
+
Status: string;
|
|
22
|
+
|
|
23
|
+
@Field(() => CompositeKeyOutputType)
|
|
24
|
+
CompositeKey: CompositeKey;
|
|
25
|
+
|
|
26
|
+
@Field(() => String)
|
|
27
|
+
EntityName: string;
|
|
28
|
+
|
|
29
|
+
@Field(() => String, { nullable: true })
|
|
30
|
+
RecordName?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Resolver(EntityRecordNameResult)
|
|
34
|
+
export class EntityRecordNameResolver {
|
|
35
|
+
@Query(() => EntityRecordNameResult)
|
|
36
|
+
async GetEntityRecordName(
|
|
37
|
+
@Arg('EntityName', () => String) EntityName: string,
|
|
38
|
+
@Arg('CompositeKey', () => CompositeKeyInputType) primaryKey: CompositeKey,
|
|
39
|
+
@Ctx() { userPayload }: AppContext
|
|
40
|
+
): Promise<EntityRecordNameResult> {
|
|
41
|
+
const md = new Metadata();
|
|
42
|
+
return await this.InnerGetEntityRecordName(md, EntityName, primaryKey);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Query(() => [EntityRecordNameResult])
|
|
46
|
+
async GetEntityRecordNames(
|
|
47
|
+
@Arg('info', () => [EntityRecordNameInput]) info: EntityRecordNameInput[],
|
|
48
|
+
@Ctx() {}: AppContext
|
|
49
|
+
): Promise<EntityRecordNameResult[]> {
|
|
50
|
+
const result: EntityRecordNameResult[] = [];
|
|
51
|
+
const md = new Metadata();
|
|
52
|
+
for (const i of info) {
|
|
53
|
+
result.push(await this.InnerGetEntityRecordName(md, i.EntityName, i.CompositeKey));
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async InnerGetEntityRecordName(md: Metadata, EntityName: string, primaryKey: CompositeKeyInputType): Promise<EntityRecordNameResult> {
|
|
59
|
+
const pk = new CompositeKey(primaryKey.KeyValuePairs);
|
|
60
|
+
const e = md.Entities.find((e) => e.Name === EntityName);
|
|
61
|
+
if (e) {
|
|
62
|
+
const recordName = await md.GetEntityRecordName(e.Name, pk);
|
|
63
|
+
if (recordName) return { Success: true, Status: 'OK', CompositeKey: pk, RecordName: recordName, EntityName };
|
|
64
|
+
else
|
|
65
|
+
return {
|
|
66
|
+
Success: false,
|
|
67
|
+
Status: `Name for record, or record ${pk.ToString()} itself not found, could be an access issue if user doesn't have Row Level Access (RLS) if RLS is enabled for this entity`,
|
|
68
|
+
CompositeKey: pk,
|
|
69
|
+
EntityName,
|
|
70
|
+
};
|
|
71
|
+
} else return { Success: false, Status: `Entity ${EntityName} not found`, CompositeKey: pk, EntityName };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default EntityRecordNameResolver;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { EntityPermissionType } from '@memberjunction/core';
|
|
2
|
+
import { AppContext } from '../types.js';
|
|
3
|
+
import { Arg, Ctx, Query, Resolver, InputType, Field } from 'type-graphql';
|
|
4
|
+
import { Entity_, EntityResolverBase } from '../generated/generated.js';
|
|
5
|
+
|
|
6
|
+
@Resolver(Entity_)
|
|
7
|
+
export class EntityResolver extends EntityResolverBase {
|
|
8
|
+
@Query(() => [Entity_])
|
|
9
|
+
EntitiesBySchemas(
|
|
10
|
+
@Ctx() { dataSource, userPayload }: AppContext,
|
|
11
|
+
@Arg('IncludeSchemas', () => [String], { nullable: true }) IncludeSchemas?: string[],
|
|
12
|
+
@Arg('ExcludeSchemas', () => [String], { nullable: true }) ExcludeSchemas?: string[]
|
|
13
|
+
) {
|
|
14
|
+
this.CheckUserReadPermissions('Entities', userPayload);
|
|
15
|
+
const rlsWhere = this.getRowLevelSecurityWhereClause('Entities', userPayload, EntityPermissionType.Read, ' WHERE');
|
|
16
|
+
const includeSchemaSQL =
|
|
17
|
+
IncludeSchemas && IncludeSchemas.length > 0 ? `SchemaName IN (${IncludeSchemas.map((s) => `'${s}'`).join(',')})` : '';
|
|
18
|
+
const excludeSchemaSQL =
|
|
19
|
+
ExcludeSchemas && ExcludeSchemas.length > 0 ? `SchemaName NOT IN (${ExcludeSchemas.map((s) => `'${s}'`).join(',')})` : '';
|
|
20
|
+
let schemaSQL = '';
|
|
21
|
+
if (includeSchemaSQL) schemaSQL = includeSchemaSQL;
|
|
22
|
+
if (excludeSchemaSQL) {
|
|
23
|
+
if (schemaSQL) schemaSQL = `${schemaSQL} AND ${excludeSchemaSQL}`;
|
|
24
|
+
else schemaSQL = excludeSchemaSQL;
|
|
25
|
+
}
|
|
26
|
+
let totalWhere = '';
|
|
27
|
+
if (schemaSQL) totalWhere = ` WHERE ${schemaSQL}`;
|
|
28
|
+
if (rlsWhere) {
|
|
29
|
+
if (totalWhere) totalWhere = `${totalWhere} AND ${rlsWhere}`;
|
|
30
|
+
else totalWhere = ` WHERE ${rlsWhere}`;
|
|
31
|
+
}
|
|
32
|
+
const sSQL = `SELECT * FROM [${this.MJCoreSchema}].vwEntities${totalWhere}`;
|
|
33
|
+
return dataSource.query(sSQL);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { CompositeKey, EntityPermissionType, Metadata, RunView } from '@memberjunction/core';
|
|
2
|
+
import { FileCategoryEntity, FileEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { AppContext, Arg, Ctx, DeleteOptionsInput, Int, Mutation } from '@memberjunction/server';
|
|
4
|
+
import { mj_core_schema } from '../config.js';
|
|
5
|
+
import { FileCategoryResolver as FileCategoryResolverBase, FileCategory_ } from '../generated/generated.js';
|
|
6
|
+
|
|
7
|
+
export class FileResolver extends FileCategoryResolverBase {
|
|
8
|
+
@Mutation(() => FileCategory_)
|
|
9
|
+
async DeleteFileCategory(
|
|
10
|
+
@Arg('ID', () => String) ID: string,
|
|
11
|
+
@Arg('options___', () => DeleteOptionsInput) options: DeleteOptionsInput,
|
|
12
|
+
@Ctx() { dataSource, userPayload }: AppContext
|
|
13
|
+
) {
|
|
14
|
+
const key = new CompositeKey();
|
|
15
|
+
key.LoadFromSingleKeyValuePair('ID', ID);
|
|
16
|
+
if (!(await this.BeforeDelete(dataSource, key))) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const md = new Metadata();
|
|
21
|
+
const user = this.GetUserFromPayload(userPayload);
|
|
22
|
+
const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
|
|
23
|
+
const fileCategoryEntity = await md.GetEntityObject<FileCategoryEntity>('File Categories', user);
|
|
24
|
+
|
|
25
|
+
fileEntity.CheckPermissions(EntityPermissionType.Update, true);
|
|
26
|
+
fileCategoryEntity.CheckPermissions(EntityPermissionType.Delete, true);
|
|
27
|
+
|
|
28
|
+
await fileCategoryEntity.Load(ID);
|
|
29
|
+
const returnValue = fileCategoryEntity.GetAll();
|
|
30
|
+
|
|
31
|
+
// Any files using the deleted category fall back to its parent
|
|
32
|
+
await dataSource.transaction(async () => {
|
|
33
|
+
// SHOULD USE BaseEntity for each of these records to ensure object model
|
|
34
|
+
// is used everywhere - new code below. The below is SLOWER than a single
|
|
35
|
+
// Update statement, but it ensures that the object model is used everywhere
|
|
36
|
+
// in case there are sub-classes and business logic/etc for the updates
|
|
37
|
+
// the direct SQL would bypass that logic.
|
|
38
|
+
|
|
39
|
+
// const sSQL = `UPDATE [${mj_core_schema}].[File]
|
|
40
|
+
// SET [CategoryID]=${fileCategoryEntity.ParentID}
|
|
41
|
+
// WHERE [CategoryID]=${fileCategoryEntity.ID}`;
|
|
42
|
+
|
|
43
|
+
// await dataSource.query(sSQL);
|
|
44
|
+
const rv = new RunView();
|
|
45
|
+
const filesResult = await rv.RunView(
|
|
46
|
+
{
|
|
47
|
+
EntityName: 'Files',
|
|
48
|
+
ExtraFilter: `CategoryID='${fileCategoryEntity.ID}'`,
|
|
49
|
+
ResultType: 'entity_object',
|
|
50
|
+
},
|
|
51
|
+
user
|
|
52
|
+
);
|
|
53
|
+
if (filesResult) {
|
|
54
|
+
// iterate through each of the files in filesResult.Results
|
|
55
|
+
// and update the CategoryID to fileCategoryEntity.ParentID
|
|
56
|
+
for (const file of filesResult.Results) {
|
|
57
|
+
const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
|
|
58
|
+
await fileEntity.Load(file.ID);
|
|
59
|
+
fileEntity.CategoryID = fileCategoryEntity.ParentID;
|
|
60
|
+
await fileEntity.Save();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await fileCategoryEntity.Delete();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await this.AfterDelete(dataSource, key); // fire event
|
|
67
|
+
return returnValue;
|
|
68
|
+
}
|
|
69
|
+
}
|