identity-admin 1.0.0

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.
Files changed (167) hide show
  1. package/README.md +127 -0
  2. package/lib/Dashboard.d.ts +14 -0
  3. package/lib/Dashboard.js +84 -0
  4. package/lib/container/helpers/HelperInversify.d.ts +6 -0
  5. package/lib/container/helpers/HelperInversify.js +10 -0
  6. package/lib/container/helpers/HelperTypes.d.ts +5 -0
  7. package/lib/container/helpers/HelperTypes.js +7 -0
  8. package/lib/container/index.d.ts +1 -0
  9. package/lib/container/index.js +14 -0
  10. package/lib/container/repositories/RepositoryInversify.d.ts +4 -0
  11. package/lib/container/repositories/RepositoryInversify.js +13 -0
  12. package/lib/container/repositories/RepositoryTypes.d.ts +4 -0
  13. package/lib/container/repositories/RepositoryTypes.js +6 -0
  14. package/lib/container/types.d.ts +8 -0
  15. package/lib/container/types.js +9 -0
  16. package/lib/controllers/ActionController.d.ts +8 -0
  17. package/lib/controllers/ActionController.js +74 -0
  18. package/lib/controllers/DashboardController.d.ts +36 -0
  19. package/lib/controllers/DashboardController.js +335 -0
  20. package/lib/controllers/ResourceController.d.ts +9 -0
  21. package/lib/controllers/ResourceController.js +95 -0
  22. package/lib/helpers/ActionsGenerator.d.ts +9 -0
  23. package/lib/helpers/ActionsGenerator.js +77 -0
  24. package/lib/helpers/LocalesHelper.d.ts +4 -0
  25. package/lib/helpers/LocalesHelper.js +73 -0
  26. package/lib/helpers/ResourceGenerator.d.ts +4 -0
  27. package/lib/helpers/ResourceGenerator.js +68 -0
  28. package/lib/helpers/ResourceHelper.d.ts +23 -0
  29. package/lib/helpers/ResourceHelper.js +274 -0
  30. package/lib/helpers/SchemaGenerator.d.ts +5 -0
  31. package/lib/helpers/SchemaGenerator.js +87 -0
  32. package/lib/helpers/SchemaHelper.d.ts +5 -0
  33. package/lib/helpers/SchemaHelper.js +21 -0
  34. package/lib/locales/en.json +11 -0
  35. package/lib/middlewares/isAuth.d.ts +13 -0
  36. package/lib/middlewares/isAuth.js +43 -0
  37. package/lib/models/ModelNames.d.ts +4 -0
  38. package/lib/models/ModelNames.js +7 -0
  39. package/lib/models/request-log/IRequestLog.d.ts +22 -0
  40. package/lib/models/request-log/IRequestLog.js +2 -0
  41. package/lib/models/request-log/RequestLog.d.ts +3 -0
  42. package/lib/models/request-log/RequestLog.js +51 -0
  43. package/lib/repositories/DashboardRepository.d.ts +5 -0
  44. package/lib/repositories/DashboardRepository.js +12 -0
  45. package/lib/repositories/Repository.d.ts +68 -0
  46. package/lib/repositories/Repository.js +212 -0
  47. package/lib/repositories/RequestLogRepository.d.ts +10 -0
  48. package/lib/repositories/RequestLogRepository.js +54 -0
  49. package/lib/repositories/SaveResult.d.ts +14 -0
  50. package/lib/repositories/SaveResult.js +18 -0
  51. package/lib/router/index.d.ts +8 -0
  52. package/lib/router/index.js +95 -0
  53. package/lib/types/DashbordConfig.d.ts +19 -0
  54. package/lib/types/DashbordConfig.js +2 -0
  55. package/lib/types/IResourceFile.d.ts +123 -0
  56. package/lib/types/IResourceFile.js +2 -0
  57. package/lib/types/helpers.d.ts +15 -0
  58. package/lib/types/helpers.js +21 -0
  59. package/lib/utils/ResourceUtils.d.ts +2 -0
  60. package/lib/utils/ResourceUtils.js +7 -0
  61. package/lib/utils/ResponseUtils.d.ts +12 -0
  62. package/lib/utils/ResponseUtils.js +72 -0
  63. package/lib/utils/StringUtils.d.ts +9 -0
  64. package/lib/utils/StringUtils.js +46 -0
  65. package/lib/view/_redirects +1 -0
  66. package/lib/view/asset-manifest.json +19 -0
  67. package/lib/view/assets/bg_card.png +0 -0
  68. package/lib/view/assets/bg_gradient.jpeg +0 -0
  69. package/lib/view/assets/icons/delete_icon.svg +3 -0
  70. package/lib/view/assets/icons/flags/ic_flag_cn.svg +10 -0
  71. package/lib/view/assets/icons/flags/ic_flag_de.svg +1 -0
  72. package/lib/view/assets/icons/flags/ic_flag_en.svg +1 -0
  73. package/lib/view/assets/icons/flags/ic_flag_fr.svg +1 -0
  74. package/lib/view/assets/icons/flags/ic_flag_kr.svg +1 -0
  75. package/lib/view/assets/icons/flags/ic_flag_sa.svg +10 -0
  76. package/lib/view/assets/icons/flags/ic_flag_us.svg +1 -0
  77. package/lib/view/assets/icons/flags/ic_flag_vn.svg +10 -0
  78. package/lib/view/assets/icons/info_icon.svg +3 -0
  79. package/lib/view/assets/icons/navbar/ic_analytics.svg +1 -0
  80. package/lib/view/assets/icons/navbar/ic_banking.svg +5 -0
  81. package/lib/view/assets/icons/navbar/ic_blog.svg +1 -0
  82. package/lib/view/assets/icons/navbar/ic_booking.svg +1 -0
  83. package/lib/view/assets/icons/navbar/ic_calendar.svg +1 -0
  84. package/lib/view/assets/icons/navbar/ic_cart.svg +1 -0
  85. package/lib/view/assets/icons/navbar/ic_chat.svg +1 -0
  86. package/lib/view/assets/icons/navbar/ic_dashboard.svg +1 -0
  87. package/lib/view/assets/icons/navbar/ic_ecommerce.svg +1 -0
  88. package/lib/view/assets/icons/navbar/ic_invoice.svg +4 -0
  89. package/lib/view/assets/icons/navbar/ic_kanban.svg +8 -0
  90. package/lib/view/assets/icons/navbar/ic_mail.svg +1 -0
  91. package/lib/view/assets/icons/navbar/ic_menu_item.svg +9 -0
  92. package/lib/view/assets/icons/navbar/ic_user.svg +1 -0
  93. package/lib/view/assets/icons/small_info_icon.svg +3 -0
  94. package/lib/view/assets/illustrations/Group 16.svg +4 -0
  95. package/lib/view/assets/illustrations/illustration_components.png +0 -0
  96. package/lib/view/assets/illustrations/illustration_dashboard.png +0 -0
  97. package/lib/view/assets/illustrations/illustration_empty_cart.svg +1 -0
  98. package/lib/view/assets/illustrations/illustration_empty_content.svg +1 -0
  99. package/lib/view/assets/illustrations/illustration_empty_mail.svg +1 -0
  100. package/lib/view/assets/illustrations/illustration_invite.png +0 -0
  101. package/lib/view/assets/illustrations/illustration_login.png +0 -0
  102. package/lib/view/assets/illustrations/illustration_register.png +0 -0
  103. package/lib/view/assets/illustrations/logo.svg +5 -0
  104. package/lib/view/assets/illustrations/welcome_image.png +0 -0
  105. package/lib/view/assets/overlay.svg +1 -0
  106. package/lib/view/assets/placeholder.svg +1 -0
  107. package/lib/view/favicon/android-chrome-192x192.png +0 -0
  108. package/lib/view/favicon/android-chrome-512x512.png +0 -0
  109. package/lib/view/favicon/apple-touch-icon-precomposed.png +0 -0
  110. package/lib/view/favicon/apple-touch-icon.png +0 -0
  111. package/lib/view/favicon/browserconfig.xml +9 -0
  112. package/lib/view/favicon/favicon-16x16.png +0 -0
  113. package/lib/view/favicon/favicon-32x32.png +0 -0
  114. package/lib/view/favicon/favicon.ico +0 -0
  115. package/lib/view/favicon/mstile-150x150.png +0 -0
  116. package/lib/view/favicon/safari-pinned-tab.svg +182 -0
  117. package/lib/view/favicon/site.webmanifest +19 -0
  118. package/lib/view/fonts/CircularStd-Bold.otf +0 -0
  119. package/lib/view/fonts/CircularStd-Book.otf +0 -0
  120. package/lib/view/fonts/CircularStd-Medium.otf +0 -0
  121. package/lib/view/fonts/Roboto-Bold.ttf +0 -0
  122. package/lib/view/fonts/Roboto-Regular.ttf +0 -0
  123. package/lib/view/fonts/index.css +18 -0
  124. package/lib/view/index.html +1 -0
  125. package/lib/view/logo/logo_full.jpg +0 -0
  126. package/lib/view/logo/logo_full.svg +1 -0
  127. package/lib/view/logo/logo_single.svg +1 -0
  128. package/lib/view/manifest.json +20 -0
  129. package/lib/view/robots.txt +3 -0
  130. package/lib/view/static/css/main.faf63983.css +2 -0
  131. package/lib/view/static/css/main.faf63983.css.map +1 -0
  132. package/lib/view/static/js/13.d8bc0c19.chunk.js +2 -0
  133. package/lib/view/static/js/13.d8bc0c19.chunk.js.map +1 -0
  134. package/lib/view/static/js/574.f1fff658.chunk.js +2 -0
  135. package/lib/view/static/js/574.f1fff658.chunk.js.map +1 -0
  136. package/lib/view/static/js/678.fddff388.chunk.js +2 -0
  137. package/lib/view/static/js/678.fddff388.chunk.js.map +1 -0
  138. package/lib/view/static/js/main.2a2ccfb1.js +3 -0
  139. package/lib/view/static/js/main.2a2ccfb1.js.LICENSE.txt +223 -0
  140. package/lib/view/static/js/main.2a2ccfb1.js.map +1 -0
  141. package/package.json +44 -0
  142. package/src/Dashboard.ts +74 -0
  143. package/src/controllers/ActionController.ts +64 -0
  144. package/src/controllers/DashboardController.ts +388 -0
  145. package/src/controllers/ResourceController.ts +62 -0
  146. package/src/helpers/ActionsGenerator.ts +106 -0
  147. package/src/helpers/ResourceGenerator.ts +90 -0
  148. package/src/helpers/ResourceHelper.ts +391 -0
  149. package/src/helpers/SchemaGenerator.ts +120 -0
  150. package/src/helpers/SchemaHelper.ts +27 -0
  151. package/src/locales/en.json +11 -0
  152. package/src/middlewares/isAuth.ts +46 -0
  153. package/src/models/ModelNames.ts +6 -0
  154. package/src/models/request-log/IRequestLog.ts +25 -0
  155. package/src/models/request-log/RequestLog.ts +52 -0
  156. package/src/repositories/DashboardRepository.ts +11 -0
  157. package/src/repositories/Repository.ts +269 -0
  158. package/src/repositories/RequestLogRepository.ts +40 -0
  159. package/src/repositories/SaveResult.ts +31 -0
  160. package/src/router/index.ts +91 -0
  161. package/src/types/DashbordConfig.ts +24 -0
  162. package/src/types/IResourceFile.ts +240 -0
  163. package/src/types/helpers.ts +17 -0
  164. package/src/utils/ResourceUtils.ts +5 -0
  165. package/src/utils/ResponseUtils.ts +68 -0
  166. package/src/utils/StringUtils.ts +63 -0
  167. package/tsconfig.json +17 -0
@@ -0,0 +1,27 @@
1
+ import { Schema } from 'mongoose';
2
+
3
+ export default class SchemaHelper {
4
+
5
+ public static belongsTo(schema: Schema, modelName: string): void {
6
+
7
+ const fieldName = this.lowerFirstLetter(modelName);
8
+ const localFieldName = fieldName + 'Id';
9
+
10
+ schema.virtual(fieldName, {
11
+ ref: modelName,
12
+ localField: localFieldName,
13
+ foreignField: '_id',
14
+ justOne: true
15
+ });
16
+ }
17
+
18
+ private static lowerFirstLetter(value: string): string {
19
+
20
+ if(value.length == 0) {
21
+ return '';
22
+ }
23
+
24
+ return value.charAt(0).toLowerCase() + value.slice(1);
25
+ }
26
+
27
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "actions_new": "Create New",
3
+ "actions_edit": "Edit",
4
+ "actions_delete": "Delete",
5
+ "actions_delete_confirmMessage_title": "Do you really want to delete this record?",
6
+ "actions_delete_confirmMessage_body": "If you clicked yes, this record will be permanently deleted.",
7
+ "actions_bulkDelete_confirmMessage_title": "Do you really want to delete these records?",
8
+ "actions_bulkDelete_confirmMessage_body": "If you clicked yes, these records will be permanently deleted.",
9
+ "actions_delete_options_yes": "Delete",
10
+ "actions_delete_options_no": "No"
11
+ }
@@ -0,0 +1,46 @@
1
+ import ResponseUtils from "../utils/ResponseUtils";
2
+ import { NextFunction, Router, Request, Response } from "express";
3
+ import { AuthenticateMiddleWare } from "../types/DashbordConfig";
4
+ import { Document } from "mongoose";
5
+
6
+
7
+ export interface IRequest extends Request {
8
+ user: Document;
9
+ language: string;
10
+ timezone: string;
11
+ startTime: Date;
12
+ }
13
+
14
+
15
+ export const defaultHeaders = function(req: IRequest, res: Response, next: NextFunction) {
16
+
17
+ req.language = req.headers['accept-language'] ? req.headers['accept-language'] as string : 'en';
18
+ req.timezone = req.headers.timezone ? req.headers.timezone as string : 'UTC';
19
+
20
+ next();
21
+ };
22
+
23
+ export const authenticate = async (req: IRequest, res: Response, next: NextFunction, authenticate: AuthenticateMiddleWare) => {
24
+ const adminCredentials = {
25
+ email: req.body.user.email,
26
+ password: req.body.user.password
27
+ }
28
+ const user = await authenticate(adminCredentials);
29
+ if(!user) {
30
+ return ResponseUtils.unauthorized(res);
31
+ }
32
+ req.user = user as Document;
33
+ next();
34
+ }
35
+
36
+ const isAuth = function(req: IRequest, res: Response, next: NextFunction) {
37
+ const session: any = req.session;
38
+ if(!session.userName) {
39
+ return ResponseUtils.unauthorized(res);
40
+ }
41
+ next();
42
+ }
43
+
44
+
45
+
46
+ export default isAuth
@@ -0,0 +1,6 @@
1
+ export default class ModelNames {
2
+
3
+ public static User = 'IdentityUser';
4
+ public static RequestLog = 'RequestLog';
5
+
6
+ }
@@ -0,0 +1,25 @@
1
+ import { Document, Model, Types } from 'mongoose';
2
+
3
+
4
+ export interface IRequestLogProps {
5
+ _id?: Types.ObjectId;
6
+ method: string;
7
+ endpoint: string;
8
+ url: string;
9
+ startTime: Date;
10
+ durationInMilliseconds: number;
11
+ query: string;
12
+ body: string;
13
+ userAgent?: string;
14
+ headers?: string;
15
+ status?: number;
16
+ message?: string;
17
+ }
18
+
19
+ export interface IRequestLogDocument extends IRequestLogProps, Document {
20
+ _id: Types.ObjectId;
21
+ createdAt: Date;
22
+ updatedAt: Date;
23
+ }
24
+
25
+ export default interface IRequestLogModel extends Model<IRequestLogDocument> { }
@@ -0,0 +1,52 @@
1
+ import SchemaHelper from '../../helpers/SchemaHelper';
2
+ import { model, Schema } from 'mongoose';
3
+ import ModelNames from '../ModelNames';
4
+
5
+ import IRequestLogModel, { IRequestLogDocument } from './IRequestLog';
6
+
7
+ // belongs_to User
8
+ const RequestLogSchema: Schema = new Schema({
9
+ method: {
10
+ type: String
11
+ },
12
+ endpoint: {
13
+ type: String
14
+ },
15
+ url: {
16
+ type: String
17
+ },
18
+ startTime: {
19
+ type: Date
20
+ },
21
+ durationInMilliseconds: {
22
+ type: Number
23
+ },
24
+ userId: {
25
+ type: Schema.Types.ObjectId,
26
+ default: null
27
+ },
28
+ query: {
29
+ type: String
30
+ },
31
+ body: {
32
+ type: String
33
+ },
34
+ userAgent: {
35
+ type: String
36
+ },
37
+ headers: {
38
+ type: String
39
+ },
40
+ message: {
41
+ type: String
42
+ },
43
+ status: {
44
+ type: Number
45
+ }
46
+ }, { timestamps: true });
47
+
48
+ SchemaHelper.belongsTo(RequestLogSchema, ModelNames.User);
49
+
50
+ const RequestLog: IRequestLogModel = model<IRequestLogDocument, IRequestLogModel>(ModelNames.RequestLog, RequestLogSchema);
51
+
52
+ export default RequestLog;
@@ -0,0 +1,11 @@
1
+ import Repository from "./Repository"
2
+ import mongoose, { Document, Model } from "mongoose";
3
+
4
+ export default class DashboardRepository extends Repository<Document> {
5
+
6
+ constructor(model: Model<Document, Model<Document>>) {
7
+ super(model);
8
+ }
9
+
10
+
11
+ }
@@ -0,0 +1,269 @@
1
+ import { injectable, unmanaged } from 'inversify';
2
+ import { Aggregate, Document, Error, HydratedDocument, Model, Query } from 'mongoose';
3
+
4
+ import SaveResult, { ISaveError } from './SaveResult';
5
+
6
+ export interface PaginateParams {
7
+ page: number;
8
+ perPage: number;
9
+ }
10
+
11
+ interface IQueryOptions {
12
+ filter?: any;
13
+ sort?: any;
14
+ select?: any;
15
+ limit?: number;
16
+ skip?: number;
17
+ paginateParams?: PaginateParams;
18
+ populate?: any;
19
+ }
20
+
21
+ interface PageInfo {
22
+ currentPage: number;
23
+ pagesCount: number;
24
+ nextPage: number;
25
+ recordsCount: number;
26
+ perPage: number;
27
+ }
28
+
29
+ interface Page<T> {
30
+ records: T [];
31
+ pageInfo: PageInfo;
32
+ }
33
+
34
+ export interface IDashboardRepository{}
35
+
36
+ export interface IRepository<T extends Document> {
37
+ findById(id: any): Promise<T | null>;
38
+
39
+ findOne(queryOptions?: IQueryOptions): Promise<T | null>;
40
+
41
+ findMany(queryOptions?: IQueryOptions): Promise<T[]>;
42
+
43
+ count(filterOptions: any): Promise<number>;
44
+
45
+ save(props: any): Promise<SaveResult<T>>;
46
+
47
+ saveAll(props: any []): Promise<any>
48
+
49
+ findByIdAndUpdate(id: any, props: any): Promise<T | null>;
50
+
51
+ findOneAndUpdate(filter: any, props: any, options?: any): Promise<T | null>;
52
+
53
+ remove(filterOptions: any): Promise<T | null>;
54
+
55
+ distinct(field: string, filterOptions: any): Promise<T[] | null>;
56
+
57
+ paginate(queryOptions: IQueryOptions): Promise<Page<T>>;
58
+
59
+ update(instance: T, props: any): Promise<SaveResult<T>>;
60
+
61
+ saveInstance(instance: T): Promise<SaveResult<T>>;
62
+ }
63
+
64
+ @injectable()
65
+ export default class Repository<T extends Document> implements IRepository<T>,IDashboardRepository {
66
+
67
+ private static NO_NEXT_PAGE = -1;
68
+
69
+ public constructor(@unmanaged() protected model: Model<T>) {}
70
+
71
+ public async findById(id: any): Promise<T | null> {
72
+ return await this.model.findById(id);
73
+ }
74
+
75
+ public async findOne(queryOptions?: IQueryOptions): Promise<T | null> {
76
+
77
+ const filter = queryOptions?.filter ? queryOptions.filter : {};
78
+ const populate = queryOptions?.populate;
79
+ return this.model.findOne(filter).populate(populate).exec() as Promise<T | null>;
80
+ }
81
+
82
+ public async findMany(queryOptions: IQueryOptions): Promise<T []> {
83
+
84
+ const filter = queryOptions.filter ? queryOptions.filter : {};
85
+ const sort = queryOptions.sort;
86
+ const select = queryOptions.select;
87
+ const limit = this.getLimit(queryOptions);
88
+ const skip = this.getSkip(queryOptions);
89
+ const populate = queryOptions.populate;
90
+
91
+ var query = this.model.find(filter);
92
+
93
+ if (select) {
94
+ query = query.select(select);
95
+ }
96
+ if (sort) {
97
+ query = query.sort(sort);
98
+ }
99
+ if (skip) {
100
+ query = query.skip(skip);
101
+ }
102
+ if (limit) {
103
+ query = query.limit(limit);
104
+ }
105
+ if (populate) {
106
+ query = query.populate(populate) as Query<HydratedDocument<T, {}, {}>[], HydratedDocument<T, {}, {}>, {}, T>;
107
+ }
108
+
109
+ return await query;
110
+ }
111
+
112
+ public async paginate(queryOptions: IQueryOptions): Promise<Page<T>> {
113
+
114
+ const filter = queryOptions.filter ? queryOptions.filter : {};
115
+
116
+ const limit = this.getLimit(queryOptions)!;
117
+ const skip = this.getSkip(queryOptions)!;
118
+
119
+ const pageInfoPromise = await this.createPageInfo(filter, skip, limit);
120
+ const recordsPromise = await this.findMany(queryOptions);
121
+
122
+ const [records, pageInfo] = await Promise.all([recordsPromise, pageInfoPromise]);
123
+
124
+ return {
125
+ records: records,
126
+ pageInfo
127
+ };
128
+ }
129
+
130
+ private getLimit(queryOptions: IQueryOptions): number | undefined {
131
+
132
+ if (queryOptions.paginateParams) {
133
+ return queryOptions.paginateParams.perPage;
134
+ }
135
+ return queryOptions.limit;
136
+ }
137
+
138
+ private getSkip(queryOptions: IQueryOptions): number | undefined {
139
+
140
+ if (queryOptions.paginateParams) {
141
+ return queryOptions.paginateParams.perPage * (queryOptions.paginateParams.page - 1);
142
+ }
143
+
144
+ return queryOptions.skip;
145
+ }
146
+
147
+ public toLimitSkip(paginateParams: PaginateParams): [number, number]{
148
+
149
+ return [paginateParams.perPage, paginateParams.perPage * (paginateParams.page - 1)];
150
+ }
151
+
152
+ protected async createPageInfo(filter: any, skip: number, limit: number): Promise<PageInfo> {
153
+
154
+ const count = await this.count(filter);
155
+
156
+ const currentPage = (skip / limit) + 1;
157
+ const pagesCount = Math.ceil(count / limit);
158
+ const nextPage = currentPage < pagesCount ? (currentPage + 1) : Repository.NO_NEXT_PAGE;
159
+
160
+ return {
161
+ currentPage,
162
+ pagesCount,
163
+ nextPage,
164
+ perPage: limit,
165
+ recordsCount: count
166
+ }
167
+ }
168
+
169
+ protected async createPageInfoFromAggregate(aggregate: Aggregate<any []>, skip: number, limit: number): Promise<PageInfo> {
170
+
171
+ const count = await this.countAggregate(aggregate);
172
+
173
+ const currentPage = (skip / limit) + 1;
174
+ const pagesCount = Math.ceil(count / limit);
175
+ const nextPage = currentPage < pagesCount ? (currentPage + 1) : Repository.NO_NEXT_PAGE;
176
+
177
+ return {
178
+ currentPage,
179
+ pagesCount,
180
+ nextPage,
181
+ perPage: limit,
182
+ recordsCount: count
183
+ }
184
+ }
185
+
186
+ public async count(filter: any): Promise<number> {
187
+ return this.model.countDocuments(filter);
188
+ }
189
+
190
+ public async countAggregate(aggregate: Aggregate<any []>): Promise<number> {
191
+
192
+ const queryResult = await aggregate.count('count');
193
+ if (queryResult.length == 0) {
194
+ return 0;
195
+ }
196
+
197
+ return queryResult[0].count;
198
+ }
199
+
200
+ public async update(instance: T, props: any): Promise<SaveResult<T>> {
201
+
202
+ const allProps = {
203
+ ...instance.toObject(),
204
+ ...props
205
+ };
206
+
207
+ return this.save(allProps);
208
+ }
209
+
210
+ public async save(props: any): Promise<SaveResult<T>> {
211
+
212
+ const instance = new this.model(props);
213
+ const hasId = !!props._id;
214
+ instance.isNew = !hasId;
215
+
216
+ return this.saveInstance(instance);
217
+ }
218
+
219
+ public async saveInstance(instance: T): Promise<SaveResult<T>> {
220
+
221
+ var document: T | undefined;
222
+ var errors: ISaveError[] = [];
223
+
224
+ try {
225
+
226
+ document = await instance.save();
227
+ return new SaveResult(document, errors);
228
+ } catch(e) {
229
+
230
+ if (e instanceof Error.ValidationError) {
231
+
232
+ errors = Object.keys(e.errors).map((key) => {
233
+
234
+ const saveError: any = (e as Error.ValidationError).errors[key];
235
+
236
+ return {
237
+ path: saveError.path,
238
+ type: saveError.kind,
239
+ message: saveError.message
240
+ } as ISaveError
241
+ });
242
+ }
243
+ }
244
+
245
+ return new SaveResult(document, errors);
246
+ }
247
+
248
+ public async saveAll(props: any []): Promise<any> {
249
+ return this.model.insertMany(props);
250
+ }
251
+
252
+ public async findByIdAndUpdate(id: any, props: any): Promise<T | null> {
253
+ return await this.model.findByIdAndUpdate(id, props, {new: true, returnOriginal: false, returnDocument: 'after' });
254
+ }
255
+
256
+ public async findOneAndUpdate(filter: any, props: any): Promise<T | null> {
257
+ return await this.model.findOneAndUpdate(filter, props, {new: true, returnOriginal: false, returnDocument: 'after', setDefaultsOnInsert: true, upsert: true });
258
+ }
259
+
260
+ public async remove(filter: any): Promise<T | null> {
261
+ return await this.model.findOneAndRemove(filter);
262
+ }
263
+
264
+
265
+ public async distinct(field: string, filter: any): Promise<T[] | null> {
266
+ return await this.model.distinct(field, filter);
267
+ }
268
+
269
+ }
@@ -0,0 +1,40 @@
1
+ import { injectable } from 'inversify';
2
+ import { IRequestLogDocument } from '../models/request-log/IRequestLog';
3
+ import RequestLog from '../models/request-log/RequestLog';
4
+ import Repository, { IRepository } from './Repository';
5
+
6
+
7
+ export interface IRequestLogRepository extends IRepository<IRequestLogDocument> {
8
+ deleteTillLastDays(days: number): Promise<void>;
9
+ }
10
+
11
+ @injectable()
12
+ export default class RequestLogRepository extends Repository<IRequestLogDocument> {
13
+
14
+ constructor() {
15
+ super(RequestLog);
16
+ }
17
+
18
+ public async deleteTillLastDays(days: number): Promise<void> {
19
+ const day = 1000 * 60 * 60 * 24;
20
+ const currentTime = Date.now();
21
+ const time = new Date(currentTime - days * day)
22
+ await RequestLog.deleteMany({ createdAt: {$lt: time } });
23
+ }
24
+
25
+ public async getRequestLogsStats() {
26
+
27
+ const stats = await RequestLog
28
+ .aggregate()
29
+ .match({})
30
+ .group({
31
+ _id: { endpoint: '$endpoint' },
32
+ count: { $sum: 1 },
33
+ average: {$avg: '$durationInMilliseconds'}
34
+ })
35
+ .sort({ count: -1 })
36
+
37
+ return stats;
38
+ }
39
+
40
+ }
@@ -0,0 +1,31 @@
1
+ import { Document } from "mongoose";
2
+
3
+ export default class SaveResult <T extends Document> {
4
+
5
+ private document: T | undefined;
6
+ private errors: ISaveError [];
7
+
8
+ constructor(document: T | undefined, errors: ISaveError []) {
9
+ this.document = document;
10
+ this.errors = errors;
11
+ }
12
+
13
+ public getDocument(): T | undefined {
14
+ return this.document;
15
+ }
16
+
17
+ public getErrors(): ISaveError [] {
18
+ return this.errors;
19
+ }
20
+
21
+ public isValid(): boolean {
22
+ return this.errors.length === 0;
23
+ }
24
+ }
25
+
26
+ export interface ISaveError {
27
+
28
+ type: string;
29
+ path: string;
30
+ message: string;
31
+ }
@@ -0,0 +1,91 @@
1
+ import express, { NextFunction, Router, Request, Response } from "express";
2
+ import DashboardController from "../controllers/DashboardController";
3
+ import ResourceController from "../controllers/ResourceController";
4
+ import path from "path";
5
+ import i18n from "i18n";
6
+ import ResponseUtils from "../utils/ResponseUtils";
7
+ import { AuthenticateMiddleWare } from "../types/DashbordConfig";
8
+ import isAuth, { authenticate, defaultHeaders, IRequest } from "../middlewares/isAuth";
9
+ import ActionController from "../controllers/ActionController";
10
+
11
+ const createMainRouter = (router: Router, controller: DashboardController) => {
12
+ router.use((req, res, next) => defaultHeaders(req as IRequest, res, next));
13
+
14
+ router
15
+ .route(`/api/:resource`)
16
+ .get((req: Request, res: Response) => controller.index(req as IRequest, res))
17
+ .post((req: Request, res: Response) => controller.create(req as IRequest, res));
18
+
19
+ router
20
+ .route("/api/:resource/:id")
21
+ .get((req: Request, res: Response) => controller.show(req as IRequest, res))
22
+ .patch((req: Request, res: Response) => controller.update(req as IRequest, res))
23
+ .delete((req: Request, res: Response) => controller.delete(req as IRequest, res));
24
+ };
25
+
26
+ const createResourceRouter = (
27
+ router: Router,
28
+ controller: ResourceController
29
+ ) => {
30
+ router
31
+ .route("/api/resources")
32
+ .get((req: Request, res: Response) => controller.index(req as IRequest, res));
33
+ };
34
+
35
+ const createActionsRouter = (router: Router, controller: ActionController) => {
36
+ router
37
+ .route("actions/:actionKey")
38
+ .post((req: Request, res: Response) => controller.execute(req as IRequest, res));
39
+ };
40
+
41
+ const createLoginRoute = (router: Router, verify: AuthenticateMiddleWare) => {
42
+ router
43
+ .route("/api/auth/login")
44
+ .all((req: Request, res, next) => authenticate(req as IRequest, res, next, verify))
45
+ .post(async (req, res) => {
46
+ const session: any = req.session;
47
+ session.userName = (req.user as any).email;
48
+
49
+ return ResponseUtils.ok(res, {
50
+ user: req.user,
51
+ });
52
+ });
53
+ };
54
+
55
+ const createRouter = (
56
+ dashboardController: DashboardController,
57
+ resourceController: ResourceController,
58
+ ActionController: ActionController,
59
+ authenticate?: AuthenticateMiddleWare
60
+ ): Router => {
61
+ const router = Router();
62
+
63
+
64
+
65
+ if (authenticate) {
66
+ createLoginRoute(router, authenticate);
67
+ router.route(`/api/:resource`).all((req: Request, res, next) => isAuth(req as IRequest, res, next));
68
+ }
69
+
70
+ createResourceRouter(router, resourceController);
71
+ createMainRouter(router, dashboardController);
72
+ createActionsRouter(router, ActionController);
73
+
74
+ router.use(i18n.init);
75
+
76
+
77
+ return router;
78
+ };
79
+
80
+ export const createViewRoute = (router: Router, appPath: string) => {
81
+ router
82
+ .get(`(/*)?`,
83
+ async (req: Request, res: Response, next: NextFunction) => {
84
+ console.log(req.path);
85
+ console.log(appPath);
86
+ return res.sendFile(path.join(appPath, "index.html"));
87
+ }
88
+ );
89
+ }
90
+
91
+ export default createRouter;
@@ -0,0 +1,24 @@
1
+ import { Document } from "mongoose";
2
+ import { IResourceFile } from "./IResourceFile";
3
+ import i18n from "i18n";
4
+
5
+ export type AuthenticateMiddleWare = (adminCredentials: AdminCredentials) => Promise<boolean| Document>;
6
+
7
+ export interface AdminCredentials {
8
+ email: string;
9
+ password: string;
10
+ }
11
+
12
+ export interface CookieConfiguration {
13
+ cookiesSecret: string;
14
+ cookieName: string;
15
+ }
16
+
17
+
18
+ export default interface DashboardConfig {
19
+ resources: IResourceFile[];
20
+ rootPath?: string;
21
+ localesOptions?: i18n.ConfigurationOptions;
22
+ cookiesConfiguration?: CookieConfiguration;
23
+ authenticate?: AuthenticateMiddleWare;
24
+ }