agendash 1.0.0 → 3.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.
- package/Dockerfile +3 -2
- package/History.md +80 -58
- package/LICENSE +1 -1
- package/README.md +173 -49
- package/all-jobs.png +0 -0
- package/app.js +12 -7
- package/bin/agendash-standalone-fastify.js +61 -0
- package/bin/agendash-standalone-hapi.js +60 -0
- package/bin/agendash-standalone-koa.js +56 -0
- package/bin/agendash-standalone.js +47 -15
- package/create-job.png +0 -0
- package/entrypoint.sh +1 -1
- package/lib/controllers/agendash.js +340 -0
- package/lib/middlewares/README.md +12 -5
- package/lib/middlewares/express.js +58 -34
- package/lib/middlewares/fastify.js +75 -0
- package/lib/middlewares/hapi.js +65 -88
- package/lib/middlewares/koa.js +71 -0
- package/mobile-ui-sm.png +0 -0
- package/mobile-ui-xs.png +0 -0
- package/package.json +45 -36
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/app/assets/ArgensdashV2Logo.svg +18 -0
- package/public/app/css/styles.css +221 -0
- package/public/app/js/confirmDelete.js +40 -0
- package/public/app/js/confirmDeleteMulti.js +45 -0
- package/public/app/js/confirmRequeue.js +40 -0
- package/public/app/js/confirmRequeueMulti.js +45 -0
- package/public/app/js/confirms.js +8 -0
- package/public/app/js/jobdetail.js +48 -0
- package/public/app/js/joblist.js +239 -0
- package/public/app/js/main.js +275 -0
- package/public/app/js/newJob.js +89 -0
- package/public/app/js/sidebar.js +121 -0
- package/public/app/js/topbar.js +95 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +40 -164
- package/public/site.webmanifest +1 -0
- package/search.png +0 -0
- package/.editorconfig +0 -7
- package/.travis.yml +0 -24
- package/job-details.png +0 -0
- package/lib/agendash.js +0 -295
- package/public/css/bootstrap-theme.css +0 -587
- package/public/css/bootstrap-theme.css.map +0 -1
- package/public/css/bootstrap-theme.min.css +0 -6
- package/public/css/bootstrap-theme.min.css.map +0 -1
- package/public/css/bootstrap.css +0 -6760
- package/public/css/bootstrap.css.map +0 -1
- package/public/css/bootstrap.min.css +0 -6
- package/public/css/bootstrap.min.css.map +0 -1
- package/public/css/dashboard.css +0 -94
- package/public/fonts/glyphicons-halflings-regular.eot +0 -0
- package/public/fonts/glyphicons-halflings-regular.svg +0 -288
- package/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- package/public/fonts/glyphicons-halflings-regular.woff +0 -0
- package/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
- package/public/js/backbone-min.js +0 -2
- package/public/js/backbone-min.map +0 -1
- package/public/js/bootstrap.js +0 -2363
- package/public/js/bootstrap.min.js +0 -7
- package/public/js/jquery-2.2.0.min.js +0 -4
- package/public/js/lodash.min.js +0 -120
- package/public/js/main.js +0 -414
- package/public/js/moment.min.js +0 -7
- package/test/test-express.js +0 -98
- package/test/test-hapi.js +0 -104
- package/yarn.lock +0 -4412
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const { Agenda } = require("agenda");
|
|
4
|
+
const agendash = require("../app");
|
|
5
|
+
const Koa = require("koa");
|
|
6
|
+
const program = require("commander");
|
|
7
|
+
|
|
8
|
+
program
|
|
9
|
+
.option(
|
|
10
|
+
"-d, --db <db>",
|
|
11
|
+
"[required] Mongo connection string, same as Agenda connection string"
|
|
12
|
+
)
|
|
13
|
+
.option(
|
|
14
|
+
"-c, --collection <collection>",
|
|
15
|
+
"[optional] Mongo collection, same as Agenda collection name, default agendaJobs",
|
|
16
|
+
"agendaJobs"
|
|
17
|
+
)
|
|
18
|
+
.option(
|
|
19
|
+
"-p, --port <port>",
|
|
20
|
+
"[optional] Server port, default 3000",
|
|
21
|
+
(n, d) => Number(n) || d,
|
|
22
|
+
3000
|
|
23
|
+
)
|
|
24
|
+
.option(
|
|
25
|
+
"-t, --title <title>",
|
|
26
|
+
"[optional] Page title, default Agendash",
|
|
27
|
+
"Agendash"
|
|
28
|
+
)
|
|
29
|
+
.parse(process.argv);
|
|
30
|
+
|
|
31
|
+
if (!program.db) {
|
|
32
|
+
console.error("--db required");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const init = async () => {
|
|
37
|
+
const agenda = new Agenda().database(program.db, program.collection);
|
|
38
|
+
|
|
39
|
+
const app = new Koa();
|
|
40
|
+
const middlewares = agendash(agenda, {
|
|
41
|
+
middleware: "koa",
|
|
42
|
+
});
|
|
43
|
+
for (const middleware of middlewares) {
|
|
44
|
+
app.use(middleware);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await app.listen(program.port);
|
|
48
|
+
console.log("Server running on port %s", program.port);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
process.on("unhandledRejection", (error) => {
|
|
52
|
+
console.log(error);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
init();
|
|
@@ -1,32 +1,64 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const http = require(
|
|
4
|
-
const Agenda = require(
|
|
5
|
-
const
|
|
6
|
-
const
|
|
2
|
+
"use strict";
|
|
3
|
+
const http = require("http");
|
|
4
|
+
const { Agenda } = require("agenda");
|
|
5
|
+
const agendash = require("../app");
|
|
6
|
+
const express = require("express");
|
|
7
|
+
const program = require("commander");
|
|
7
8
|
|
|
8
9
|
program
|
|
9
|
-
.option(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
.option(
|
|
11
|
+
"-d, --db <db>",
|
|
12
|
+
"[required] Mongo connection string, same as Agenda connection string"
|
|
13
|
+
)
|
|
14
|
+
.option(
|
|
15
|
+
"-c, --collection <collection>",
|
|
16
|
+
"[optional] Mongo collection, same as Agenda collection name, default agendaJobs",
|
|
17
|
+
"agendaJobs"
|
|
18
|
+
)
|
|
19
|
+
.option(
|
|
20
|
+
"-p, --port <port>",
|
|
21
|
+
"[optional] Server port, default 3000",
|
|
22
|
+
(n, d) => Number(n) || d,
|
|
23
|
+
3000
|
|
24
|
+
)
|
|
25
|
+
.option(
|
|
26
|
+
"-t, --title <title>",
|
|
27
|
+
"[optional] Page title, default Agendash",
|
|
28
|
+
"Agendash"
|
|
29
|
+
)
|
|
30
|
+
.option(
|
|
31
|
+
"-p, --path <path>",
|
|
32
|
+
"[optional] Path to bind Agendash to, default /",
|
|
33
|
+
"/"
|
|
34
|
+
)
|
|
13
35
|
.parse(process.argv);
|
|
14
36
|
|
|
15
37
|
if (!program.db) {
|
|
16
|
-
console.error(
|
|
38
|
+
console.error("--db required");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!program.path.startsWith("/")) {
|
|
43
|
+
console.error("--path must begin with /");
|
|
17
44
|
process.exit(1);
|
|
18
45
|
}
|
|
19
46
|
|
|
20
47
|
const app = express();
|
|
21
48
|
|
|
22
49
|
const agenda = new Agenda().database(program.db, program.collection);
|
|
23
|
-
app.use(
|
|
24
|
-
|
|
25
|
-
|
|
50
|
+
app.use(
|
|
51
|
+
program.path,
|
|
52
|
+
agendash(agenda, {
|
|
53
|
+
title: program.title,
|
|
54
|
+
})
|
|
55
|
+
);
|
|
26
56
|
|
|
27
|
-
app.set(
|
|
57
|
+
app.set("port", program.port);
|
|
28
58
|
|
|
29
59
|
const server = http.createServer(app);
|
|
30
60
|
server.listen(program.port, () => {
|
|
31
|
-
console.log(
|
|
61
|
+
console.log(
|
|
62
|
+
`Agendash started http://localhost:${program.port}${program.path}`
|
|
63
|
+
);
|
|
32
64
|
});
|
package/create-job.png
ADDED
|
Binary file
|
package/entrypoint.sh
CHANGED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const semver = require("semver");
|
|
3
|
+
const { ObjectId } = require("mongodb"); // We rely on the Agenda's "mongodb", thus our package.json lists "*" as required version
|
|
4
|
+
|
|
5
|
+
module.exports = function (agenda, options) {
|
|
6
|
+
options = options || {};
|
|
7
|
+
|
|
8
|
+
agenda.on("ready", () => {
|
|
9
|
+
const collection = agenda._collection.collection || agenda._collection;
|
|
10
|
+
collection.createIndexes(
|
|
11
|
+
[
|
|
12
|
+
{ key: { nextRunAt: -1, lastRunAt: -1, lastFinishedAt: -1 } },
|
|
13
|
+
{ key: { name: 1, nextRunAt: -1, lastRunAt: -1, lastFinishedAt: -1 } },
|
|
14
|
+
],
|
|
15
|
+
(error) => {
|
|
16
|
+
if (error) {
|
|
17
|
+
// Ignoring for now
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Mongoose internals changed at some point. This will fix crash for older versions.
|
|
23
|
+
const mdb = agenda._mdb.admin ? agenda._mdb : agenda._mdb.db;
|
|
24
|
+
|
|
25
|
+
mdb.admin().serverInfo((error, serverInfo) => {
|
|
26
|
+
if (error) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!semver.satisfies(semver.coerce(serverInfo.version), ">=3.6.0")) {
|
|
31
|
+
throw new Error("MongoDB version not supported");
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Options = {query = '', property = '', isObjectId = false, limit, skip}
|
|
37
|
+
const getJobs = function (job, state, options) {
|
|
38
|
+
const preMatch = {};
|
|
39
|
+
if (job) {
|
|
40
|
+
preMatch.name = job;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (options.query && options.property) {
|
|
44
|
+
if (options.isObjectId) {
|
|
45
|
+
preMatch[options.property] = ObjectId(options.query);
|
|
46
|
+
} else if (/^\d+$/.test(options.query)) {
|
|
47
|
+
preMatch[options.property] = Number.parseInt(options.query, 10);
|
|
48
|
+
} else {
|
|
49
|
+
preMatch[options.property] = { $regex: options.query, $options: "i" };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const postMatch = {};
|
|
54
|
+
if (state) {
|
|
55
|
+
postMatch[state] = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const collection = agenda._collection.collection || agenda._collection;
|
|
59
|
+
return collection
|
|
60
|
+
.aggregate([
|
|
61
|
+
{ $match: preMatch },
|
|
62
|
+
{
|
|
63
|
+
$sort: {
|
|
64
|
+
nextRunAt: -1,
|
|
65
|
+
lastRunAt: -1,
|
|
66
|
+
lastFinishedAt: -1,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
$project: {
|
|
71
|
+
job: "$$ROOT",
|
|
72
|
+
_id: "$$ROOT._id",
|
|
73
|
+
running: {
|
|
74
|
+
$and: ["$lastRunAt", { $gt: ["$lastRunAt", "$lastFinishedAt"] }],
|
|
75
|
+
},
|
|
76
|
+
scheduled: {
|
|
77
|
+
$and: ["$nextRunAt", { $gte: ["$nextRunAt", new Date()] }],
|
|
78
|
+
},
|
|
79
|
+
queued: {
|
|
80
|
+
$and: [
|
|
81
|
+
"$nextRunAt",
|
|
82
|
+
{ $gte: [new Date(), "$nextRunAt"] },
|
|
83
|
+
{ $gte: ["$nextRunAt", "$lastFinishedAt"] },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
completed: {
|
|
87
|
+
$and: [
|
|
88
|
+
"$lastFinishedAt",
|
|
89
|
+
{ $gt: ["$lastFinishedAt", "$failedAt"] },
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
failed: {
|
|
93
|
+
$and: [
|
|
94
|
+
"$lastFinishedAt",
|
|
95
|
+
"$failedAt",
|
|
96
|
+
{ $eq: ["$lastFinishedAt", "$failedAt"] },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
repeating: {
|
|
100
|
+
$and: ["$repeatInterval", { $ne: ["$repeatInterval", null] }],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{ $match: postMatch },
|
|
105
|
+
{
|
|
106
|
+
$facet: {
|
|
107
|
+
pages: [
|
|
108
|
+
{ $count: "totalMatchs" },
|
|
109
|
+
{
|
|
110
|
+
$project: {
|
|
111
|
+
totalPages: {
|
|
112
|
+
$ceil: { $divide: ["$totalMatchs", options.limit] },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
filtered: [{ $skip: options.skip }, { $limit: options.limit }],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
])
|
|
121
|
+
.toArray();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const getOverview = async () => {
|
|
125
|
+
const collection = agenda._collection.collection || agenda._collection;
|
|
126
|
+
const results = await collection
|
|
127
|
+
.aggregate([
|
|
128
|
+
{
|
|
129
|
+
$group: {
|
|
130
|
+
_id: "$name",
|
|
131
|
+
displayName: { $first: "$name" },
|
|
132
|
+
meta: {
|
|
133
|
+
$addToSet: {
|
|
134
|
+
type: "$type",
|
|
135
|
+
priority: "$priority",
|
|
136
|
+
repeatInterval: "$repeatInterval",
|
|
137
|
+
repeatTimezone: "$repeatTimezone",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
total: { $sum: 1 },
|
|
141
|
+
running: {
|
|
142
|
+
$sum: {
|
|
143
|
+
$cond: [
|
|
144
|
+
{
|
|
145
|
+
$and: [
|
|
146
|
+
"$lastRunAt",
|
|
147
|
+
{ $gt: ["$lastRunAt", "$lastFinishedAt"] },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
1,
|
|
151
|
+
0,
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
scheduled: {
|
|
156
|
+
$sum: {
|
|
157
|
+
$cond: [
|
|
158
|
+
{
|
|
159
|
+
$and: ["$nextRunAt", { $gte: ["$nextRunAt", new Date()] }],
|
|
160
|
+
},
|
|
161
|
+
1,
|
|
162
|
+
0,
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
queued: {
|
|
167
|
+
$sum: {
|
|
168
|
+
$cond: [
|
|
169
|
+
{
|
|
170
|
+
$and: [
|
|
171
|
+
"$nextRunAt",
|
|
172
|
+
{ $gte: [new Date(), "$nextRunAt"] },
|
|
173
|
+
{ $gte: ["$nextRunAt", "$lastFinishedAt"] },
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
1,
|
|
177
|
+
0,
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
completed: {
|
|
182
|
+
$sum: {
|
|
183
|
+
$cond: [
|
|
184
|
+
{
|
|
185
|
+
$and: [
|
|
186
|
+
"$lastFinishedAt",
|
|
187
|
+
{ $gt: ["$lastFinishedAt", "$failedAt"] },
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
1,
|
|
191
|
+
0,
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
failed: {
|
|
196
|
+
$sum: {
|
|
197
|
+
$cond: [
|
|
198
|
+
{
|
|
199
|
+
$and: [
|
|
200
|
+
"$lastFinishedAt",
|
|
201
|
+
"$failedAt",
|
|
202
|
+
{ $eq: ["$lastFinishedAt", "$failedAt"] },
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
1,
|
|
206
|
+
0,
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
repeating: {
|
|
211
|
+
$sum: {
|
|
212
|
+
$cond: [
|
|
213
|
+
{
|
|
214
|
+
$and: [
|
|
215
|
+
"$repeatInterval",
|
|
216
|
+
{ $ne: ["$repeatInterval", null] },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
1,
|
|
220
|
+
0,
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
])
|
|
227
|
+
.toArray();
|
|
228
|
+
const states = {
|
|
229
|
+
total: 0,
|
|
230
|
+
running: 0,
|
|
231
|
+
scheduled: 0,
|
|
232
|
+
queued: 0,
|
|
233
|
+
completed: 0,
|
|
234
|
+
failed: 0,
|
|
235
|
+
repeating: 0,
|
|
236
|
+
};
|
|
237
|
+
const totals = { displayName: "All Jobs", ...states };
|
|
238
|
+
|
|
239
|
+
for (const job of results) {
|
|
240
|
+
for (const state of Object.keys(states)) {
|
|
241
|
+
totals[state] += job[state];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
results.unshift(totals);
|
|
246
|
+
return results;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const api = async function (
|
|
250
|
+
job,
|
|
251
|
+
state,
|
|
252
|
+
{ query: q, property, isObjectId, skip, limit }
|
|
253
|
+
) {
|
|
254
|
+
if (!agenda) {
|
|
255
|
+
return Promise.reject(new Error("Agenda instance is not ready"));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
limit = Number.parseInt(limit, 10) || 200;
|
|
259
|
+
skip = Number.parseInt(skip, 10) || 0;
|
|
260
|
+
|
|
261
|
+
const [overview, jobs] = await Promise.all([
|
|
262
|
+
getOverview(),
|
|
263
|
+
getJobs(job, state, { query: q, property, isObjectId, skip, limit }),
|
|
264
|
+
]);
|
|
265
|
+
const apiResponse = {
|
|
266
|
+
overview,
|
|
267
|
+
jobs: jobs[0].filtered,
|
|
268
|
+
totalPages: jobs[0].pages[0] ? jobs[0].pages[0].totalPages : 0,
|
|
269
|
+
};
|
|
270
|
+
apiResponse.title = options.title || "Agendash";
|
|
271
|
+
apiResponse.currentRequest = {
|
|
272
|
+
title: options.title || "Agendash",
|
|
273
|
+
job: job || "All Jobs",
|
|
274
|
+
state,
|
|
275
|
+
};
|
|
276
|
+
return apiResponse;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const requeueJobs = async (jobIds) => {
|
|
280
|
+
if (!agenda) {
|
|
281
|
+
return Promise.reject(new Error("Agenda instance is not ready"));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const collection = agenda._collection.collection || agenda._collection;
|
|
285
|
+
const jobs = await collection
|
|
286
|
+
.find({
|
|
287
|
+
_id: { $in: jobIds.map((jobId) => ObjectId(jobId)) },
|
|
288
|
+
})
|
|
289
|
+
.toArray();
|
|
290
|
+
if (jobs.length === 0) {
|
|
291
|
+
throw new Error("Job not found");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (const job of jobs) {
|
|
295
|
+
const newJob = agenda.create(job.name, job.data);
|
|
296
|
+
// eslint-disable-next-line no-await-in-loop
|
|
297
|
+
await newJob.save();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return "Jobs create successfully";
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const deleteJobs = (jobIds) => {
|
|
304
|
+
if (!agenda) {
|
|
305
|
+
return Promise.reject(new Error("Agenda instance is not ready"));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return agenda.cancel({
|
|
309
|
+
_id: { $in: jobIds.map((jobId) => ObjectId(jobId)) },
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const createJob = (jobName, jobSchedule, jobRepeatEvery, jobData) => {
|
|
314
|
+
if (!agenda) {
|
|
315
|
+
return Promise.reject(new Error("Agenda instance is not ready"));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// @TODO: Need to validate user input.
|
|
319
|
+
const job = agenda.create(jobName, jobData);
|
|
320
|
+
if (jobSchedule && jobRepeatEvery) {
|
|
321
|
+
job.repeatAt(jobSchedule);
|
|
322
|
+
job.repeatEvery(jobRepeatEvery);
|
|
323
|
+
} else if (jobSchedule) {
|
|
324
|
+
job.schedule(jobSchedule);
|
|
325
|
+
} else if (jobRepeatEvery) {
|
|
326
|
+
job.repeatEvery(jobRepeatEvery);
|
|
327
|
+
} else {
|
|
328
|
+
return Promise.reject(new Error("Jobs not created"));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return job.save();
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
api,
|
|
336
|
+
requeueJobs,
|
|
337
|
+
deleteJobs,
|
|
338
|
+
createJob,
|
|
339
|
+
};
|
|
340
|
+
};
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
# Middlewares
|
|
2
|
+
|
|
2
3
|
## Hapi
|
|
3
|
-
|
|
4
|
+
|
|
5
|
+
Works with [Hapijs](https://hapijs.com/) >= v18
|
|
6
|
+
|
|
4
7
|
### usage
|
|
8
|
+
|
|
5
9
|
First install the dependencies in your app:
|
|
10
|
+
|
|
6
11
|
```bash
|
|
7
|
-
npm install hapi inert agenda agendash
|
|
12
|
+
npm install @hapi/hapi @hapi/inert agenda agendash
|
|
8
13
|
```
|
|
14
|
+
|
|
9
15
|
Then use it as follows:
|
|
16
|
+
|
|
10
17
|
```javascript
|
|
11
18
|
'use strict';
|
|
12
19
|
|
|
13
20
|
const Hapi = require('hapi');
|
|
14
|
-
const Agenda = require('agenda');
|
|
21
|
+
const { Agenda } = require('agenda');
|
|
15
22
|
const Agendash = require('agendash');
|
|
16
23
|
|
|
17
24
|
var agenda = new Agenda({
|
|
@@ -26,7 +33,7 @@ const server = Hapi.server({
|
|
|
26
33
|
const init = async () => {
|
|
27
34
|
|
|
28
35
|
await server.register(
|
|
29
|
-
require('inert'),
|
|
36
|
+
require('@hapi/inert'),
|
|
30
37
|
{
|
|
31
38
|
plugin: Agendash(agenda, {
|
|
32
39
|
middleware: 'hapi'
|
|
@@ -49,4 +56,4 @@ process.on('unhandledRejection', (err) => {
|
|
|
49
56
|
});
|
|
50
57
|
|
|
51
58
|
init();
|
|
52
|
-
```
|
|
59
|
+
```
|
|
@@ -1,48 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const bodyParser = require('body-parser');
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const express = require("express");
|
|
3
|
+
const bodyParser = require("body-parser");
|
|
5
4
|
|
|
6
|
-
module.exports = agendash => {
|
|
5
|
+
module.exports = (agendash) => {
|
|
6
|
+
const { api, requeueJobs, deleteJobs, createJob } = agendash;
|
|
7
7
|
const app = express();
|
|
8
8
|
app.use(bodyParser.json());
|
|
9
|
-
app.use(bodyParser.urlencoded({extended: false}));
|
|
10
|
-
app.use(
|
|
9
|
+
app.use(bodyParser.urlencoded({ extended: false }));
|
|
10
|
+
app.use("/", express.static(path.join(__dirname, "../../public")));
|
|
11
11
|
|
|
12
|
-
app.get(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
app.get("/api", async (request, response) => {
|
|
13
|
+
try {
|
|
14
|
+
const {
|
|
15
|
+
job,
|
|
16
|
+
state,
|
|
17
|
+
skip,
|
|
18
|
+
limit,
|
|
19
|
+
q,
|
|
20
|
+
property,
|
|
21
|
+
isObjectId,
|
|
22
|
+
} = request.query;
|
|
23
|
+
const apiResponse = await api(job, state, {
|
|
24
|
+
query: q,
|
|
25
|
+
property,
|
|
26
|
+
isObjectId,
|
|
27
|
+
skip,
|
|
28
|
+
limit,
|
|
29
|
+
});
|
|
30
|
+
response.json(apiResponse);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
response.status(400).json(error);
|
|
33
|
+
}
|
|
19
34
|
});
|
|
20
35
|
|
|
21
|
-
app.post(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
36
|
+
app.post("/api/jobs/requeue", async (request, response) => {
|
|
37
|
+
try {
|
|
38
|
+
const newJobs = await requeueJobs(request.body.jobIds);
|
|
39
|
+
response.send(newJobs);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
response.status(404).json(error);
|
|
42
|
+
}
|
|
28
43
|
});
|
|
29
44
|
|
|
30
|
-
app.post(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
app.post("/api/jobs/delete", async (request, response) => {
|
|
46
|
+
try {
|
|
47
|
+
const deleted = await deleteJobs(request.body.jobIds);
|
|
48
|
+
if (deleted) {
|
|
49
|
+
response.json({ deleted: true });
|
|
50
|
+
} else {
|
|
51
|
+
response.json({ message: "Jobs not deleted" });
|
|
34
52
|
}
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
} catch (error) {
|
|
54
|
+
response.status(404).json(error);
|
|
55
|
+
}
|
|
37
56
|
});
|
|
38
57
|
|
|
39
|
-
app.post(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
app.post("/api/jobs/create", async (request, response) => {
|
|
59
|
+
try {
|
|
60
|
+
await createJob(
|
|
61
|
+
request.body.jobName,
|
|
62
|
+
request.body.jobSchedule,
|
|
63
|
+
request.body.jobRepeatEvery,
|
|
64
|
+
request.body.jobData
|
|
65
|
+
);
|
|
66
|
+
response.json({ created: true });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
response.status(400).json(error);
|
|
69
|
+
}
|
|
46
70
|
});
|
|
47
71
|
|
|
48
72
|
return app;
|