biz-a-cli 2.3.1 → 2.3.3

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.
@@ -0,0 +1,105 @@
1
+ import dayjs from 'dayjs';
2
+ import weekOfYear from 'dayjs/plugin/weekOfYear.js';
3
+ import utc from 'dayjs/plugin/utc.js';
4
+ import timezone from 'dayjs/plugin/timezone.js';
5
+ import { checkSchedule } from './datalib.js';
6
+
7
+ dayjs.extend(weekOfYear);
8
+ dayjs.extend(utc);
9
+ dayjs.extend(timezone);
10
+
11
+ const DEFAULT_DATE_FORMAT = 'YYYY-M-D H:mm:ss';
12
+
13
+ function isOnTime(watchTime, nowDate) {
14
+ if (watchTime.hourly) {
15
+ if (!Array.isArray(watchTime.hourly)) return false
16
+ // return watchTime.time.hourly.includes(nowDate.format('H:mm'))
17
+ return watchTime.hourly.includes(nowDate.format('H:mm'))
18
+ // } else if (watchTime.time.everyMin) {
19
+ } else if (watchTime.minutely.everyMin) {
20
+ const getTime = (jam) => {
21
+ let arr = jam.split(':')
22
+ return nowDate.set('hour', arr[0]).set('minute', arr[1])
23
+ }
24
+ if (nowDate.isBefore(getTime(watchTime.minutely.from), 'minute')) return false
25
+ if (nowDate.isAfter(getTime(watchTime.minutely.to), 'minute')) return false
26
+ return (nowDate.minute() % watchTime.minutely.everyMin) == 0
27
+ }
28
+ return false
29
+ }
30
+
31
+ function getMonthlyWatcher(watchTime, nowDate) {
32
+ if (!Array.isArray(watchTime.monthly)) return false
33
+ // if (!watchTime.monthly.includes(nowDate.date())) return false
34
+ const eom = watchTime.monthly.includes('eom')
35
+ if (!watchTime.monthly.includes(nowDate.date()) && !eom) return false
36
+ if (eom && (dayjs(nowDate).daysInMonth() !== nowDate.date())) return false
37
+
38
+ return isOnTime(watchTime, nowDate)
39
+ }
40
+
41
+ function getWeeklyWatcher(watchTime, nowDate) {
42
+ if (!Array.isArray(watchTime.weekly.days)) return false
43
+ if (!Array.isArray(watchTime.weekly.ordinal)) return false
44
+ let weekOfMonth = Math.ceil(nowDate.date() / 7)
45
+ if (!watchTime.weekly.ordinal.includes(weekOfMonth)) return false
46
+ if (!watchTime.weekly.days.includes(nowDate.day())) return false
47
+ return isOnTime(watchTime, nowDate)
48
+ }
49
+
50
+ function getDailyWatcher(watchTime, nowDate) {
51
+ // if (!watchTime.time) return false
52
+ if (!Array.isArray(watchTime.daily)) return false
53
+ if (!watchTime.daily.includes(nowDate.day())) return false
54
+ return isOnTime(watchTime, nowDate)
55
+ }
56
+
57
+ export function checkPerWatchTime(watchTime, nowDate) {
58
+ if (!watchTime.minutely && !watchTime.hourly) return false
59
+
60
+ if (watchTime.daily) {
61
+ return getDailyWatcher(watchTime, nowDate);
62
+ } else if (watchTime.weekly) {
63
+ return getWeeklyWatcher(watchTime, nowDate);
64
+ } else if (watchTime.monthly) {
65
+ return getMonthlyWatcher(watchTime, nowDate);
66
+ }
67
+ return false
68
+ }
69
+
70
+ export function setTimeZoneDate(now, timezone) {
71
+ return dayjs(now, DEFAULT_DATE_FORMAT).tz(timezone);
72
+ }
73
+
74
+ // export function isItTime(watchTimes, now) {
75
+ // nowDate = [];
76
+
77
+ // return watchTimes.reduce((result, watchTime, index) => {
78
+ // // nowDate.push(dayjs(now, DEFAULT_DATE_FORMAT).tz(watchTime.timezone));
79
+
80
+ // nowDate.push(setTimeZoneDate(now, watchTime.timezone));
81
+ // // return result || (watchTime.active ? checkPerWatchTime(watchTime, index) : false)
82
+ // return result || (watchTime.active ? checkPerWatchTime(watchTime, nowDate[index]) : false)
83
+ // }, false)
84
+ // }
85
+
86
+ export function isItTime(watchTime, now) {
87
+ const timeZoneDate = setTimeZoneDate(now, watchTime.timezone);
88
+ return (watchTime.active ? checkPerWatchTime(watchTime, timeZoneDate) : false);
89
+ }
90
+
91
+ // export async function loopTimer(watchTimes, now, companyObjectId, needCheckSchedule) {
92
+ export function loopTimer(watchTimes, now, selectedConfig, needCheckSchedule) {
93
+ // const selectedConfig = await getSelectedConfig(companyObjectId);
94
+ if (selectedConfig) {
95
+ return watchTimes.map(watchTime => {
96
+ const isRightTime = isItTime(watchTime, now);
97
+ if (isRightTime && needCheckSchedule) {
98
+ checkSchedule(selectedConfig, watchTime, true);
99
+ }
100
+ return isRightTime;
101
+ });
102
+ } else {
103
+ return false;
104
+ }
105
+ }
@@ -0,0 +1,99 @@
1
+ const {
2
+ historyRecordToJson,
3
+ watcherRecordToJson
4
+ } = await import('../scheduler/converter.js');
5
+
6
+ describe('converter test', () => {
7
+ test('convert history record to json', async () => {
8
+ const data = [{
9
+ history_id: 1,
10
+ timer_id: 2,
11
+ latest_run: '01.03.2024, 14:43:27.899'
12
+ }]
13
+ expect(historyRecordToJson(data)).toStrictEqual([{
14
+ _id: 1,
15
+ timerObjectId: 2,
16
+ latestRun: new Date('2024-01-03T07:43:27.899Z')
17
+ }]);
18
+ });
19
+
20
+ test('convert watcher record to json', async () => {
21
+ const data = [{
22
+ watcher_id: 1,
23
+ company_id: '62948492f7d559fba6f32196',
24
+ timer_id: 1,
25
+ timer_watcher_id: 1,
26
+ name: 'New Watcher 1',
27
+ active: true,
28
+ timezone: 'Asia/Jakarta',
29
+ templateName: 'cekUser.js',
30
+ seq: 0,
31
+ daily_days: '0,1,2,3,4,5,6',
32
+ weekly_ordinal: '',
33
+ weekly_days: '',
34
+ monthly_days: '',
35
+ minutely_everymin: 1,
36
+ minutely_time_from: '08:00',
37
+ minutely_time_to: '22:00',
38
+ hourly_hours: '',
39
+ scriptId: 1,
40
+ cli_script: 'abc'
41
+ }, {
42
+ watcher_id: 1,
43
+ company_id: '62948492f7d559fba6f32196',
44
+ timer_id: 2,
45
+ timer_watcher_id: 1,
46
+ name: 'New Watcher 2',
47
+ active: true,
48
+ timezone: 'Asia/Makassar',
49
+ templateName: 'cekUser2.js',
50
+ seq: 1,
51
+ daily_days: '',
52
+ weekly_ordinal: '',
53
+ weekly_days: '',
54
+ monthly_days: '2,3',
55
+ minutely_everymin: 0,
56
+ minutely_time_from: '',
57
+ minutely_time_to: '',
58
+ hourly_hours: '12:00,13:00',
59
+ scriptId: 2,
60
+ cli_script: 'def'
61
+ }]
62
+
63
+ expect(watcherRecordToJson(data)).toStrictEqual([{
64
+ _id: 1,
65
+ companyObjectId: '62948492f7d559fba6f32196',
66
+ timer: [{
67
+ _id: 1,
68
+ watcherObjectId: 1,
69
+ name: 'New Watcher 1',
70
+ active: true,
71
+ timezone: 'Asia/Jakarta',
72
+ templateName: 'cekUser.js',
73
+ seq: 0,
74
+ daily: [0, 1, 2, 3, 4, 5, 6],
75
+ minutely: {
76
+ everyMin: 1,
77
+ from: '08:00',
78
+ to: '22:00'
79
+ },
80
+ scriptId: 1,
81
+ script: '"abc"'
82
+ }, {
83
+ _id: 2,
84
+ watcherObjectId: 1,
85
+ name: 'New Watcher 2',
86
+ active: true,
87
+ timezone: 'Asia/Makassar',
88
+ templateName: 'cekUser2.js',
89
+ seq: 1,
90
+ monthly: [2, 3],
91
+ hourly: ['12:00', '13:00'],
92
+ scriptId: 2,
93
+ script: '"def"'
94
+
95
+ }]
96
+ }]);
97
+ });
98
+
99
+ })
@@ -0,0 +1,80 @@
1
+ import { jest } from '@jest/globals'
2
+
3
+ const mockInsertHistory = jest.fn();
4
+ jest.unstable_mockModule("../scheduler/watcherController.js", () => ({
5
+ insertHistory: mockInsertHistory.mockResolvedValue('OK')
6
+ }))
7
+
8
+ // const mockModule = await import('../scheduler/datalib.js');
9
+ // const mockExtractFunctionScript = jest.fn();
10
+ // jest.unstable_mockModule("../scheduler/datalib.js", () => ({
11
+ // ...mockModule,
12
+ // extractFunctionScript: mockExtractFunctionScript
13
+ // }))
14
+
15
+ const {
16
+ scheduleSubscription,
17
+ getConfig,
18
+ getQueryDataObsParameters,
19
+ } = await import('../scheduler/datalib.js');
20
+
21
+ describe('data test', () => {
22
+ test('check schedule subscription no history', () => {
23
+ const config = {
24
+ _id: 'ffffffff2ae49fab9ea654e1',
25
+ API_URL: 'localhost'
26
+ }
27
+
28
+ const data = [{ template: '7b2266756e6374696f6e73223a7b226f6e496e6974223a5b2277696e646f772e46756e6374696f6e222c5b22636f6e666967222c222064617461225d2c5b2220202020202020202020202020202020636f6e737420646f6974203d206173796e63202829203d3e207b222c222020202020202020202020202020202020202020636f6e7374207b20746170207d203d20617761697420696d706f7274282772786a732729222c222020202020202020202020202020202020202020636f6e7374207b20717565727944617461207d203d20617761697420696d706f727428272e2f646174616c69622e6a732729222c222020202020202020202020202020202020202020636f6e737420706172616d203d207b222c222020202020202020202020202020202020202020202020206c656e6774683a2031302c222c22202020202020202020202020202020202020202020202020636f6c756d6e733a205b222c22202020202020202020202020202020202020202020202020202020207b20646174613a202755534552532e555345524944272c206b65793a202775736572696427207d222c222020202020202020202020202020202020202020202020205d2c222c222020202020202020202020202020202020202020202020206462496e6465783a2031222c2220202020202020202020202020202020202020207d222c22202020202020202020202020202020202020202071756572794461746128706172616d2c20636f6e6669672c2074727565292e7069706528222c2220202020202020202020202020202020202020202020202074617028726573203d3e20636f6e736f6c652e6c6f672872657329292c222c222020202020202020202020202020202020202020292e73756273637269626528726573203d3e207b222c22202020202020202020202020202020202020202020202020636f6e736f6c652e6c6f67287265732c20277375627363726962652729222c2220202020202020202020202020202020202020207d29222c22202020202020202020202020202020207d222c2220202020202020202020202020202020646f69742829222c222020202020202020202020202020202072657475726e20276f6b20646172692063656b55736572273b225d5d7d7d' }]
29
+ const trigger = {
30
+ _id: 1,
31
+ name: 'New Watcher 1',
32
+ }
33
+
34
+ scheduleSubscription(config, data, trigger, false, true);
35
+ expect(mockInsertHistory).toBeCalledTimes(0);
36
+ });
37
+
38
+ test('check schedule subscription with history', () => {
39
+ const config = {
40
+ _id: 'ffffffff2ae49fab9ea654e1',
41
+ API_URL: 'localhost'
42
+ }
43
+
44
+ const data = [{ template: '7b2266756e6374696f6e73223a7b226f6e496e6974223a5b2277696e646f772e46756e6374696f6e222c5b22636f6e666967222c222064617461225d2c5b2220202020202020202020202020202020636f6e737420646f6974203d206173796e63202829203d3e207b222c222020202020202020202020202020202020202020636f6e7374207b20746170207d203d20617761697420696d706f7274282772786a732729222c222020202020202020202020202020202020202020636f6e7374207b20717565727944617461207d203d20617761697420696d706f727428272e2f646174616c69622e6a732729222c222020202020202020202020202020202020202020636f6e737420706172616d203d207b222c222020202020202020202020202020202020202020202020206c656e6774683a2031302c222c22202020202020202020202020202020202020202020202020636f6c756d6e733a205b222c22202020202020202020202020202020202020202020202020202020207b20646174613a202755534552532e555345524944272c206b65793a202775736572696427207d222c222020202020202020202020202020202020202020202020205d2c222c222020202020202020202020202020202020202020202020206462496e6465783a2031222c2220202020202020202020202020202020202020207d222c22202020202020202020202020202020202020202071756572794461746128706172616d2c20636f6e6669672c2074727565292e7069706528222c2220202020202020202020202020202020202020202020202074617028726573203d3e20636f6e736f6c652e6c6f672872657329292c222c222020202020202020202020202020202020202020292e73756273637269626528726573203d3e207b222c22202020202020202020202020202020202020202020202020636f6e736f6c652e6c6f67287265732c20277375627363726962652729222c2220202020202020202020202020202020202020207d29222c22202020202020202020202020202020207d222c2220202020202020202020202020202020646f69742829222c222020202020202020202020202020202072657475726e20276f6b20646172692063656b55736572273b225d5d7d7d' }]
45
+ const trigger = {
46
+ _id: 1,
47
+ name: 'New Watcher 1',
48
+ }
49
+
50
+ scheduleSubscription(config, data, trigger, true, true);
51
+ expect(mockInsertHistory).toBeCalledTimes(1);
52
+ });
53
+
54
+ test('get config', () => {
55
+ const config = {
56
+ _id: 'ffffffff2ae49fab9ea654e1',
57
+ API_URL: 'localhost'
58
+ }
59
+
60
+ expect(getConfig(config)).toStrictEqual(config);
61
+ });
62
+
63
+ test('get config array', () => {
64
+ const config = [{
65
+ _id: 'ffffffff2ae49fab9ea654e1',
66
+ API_URL: 'localhost'
67
+ }]
68
+
69
+ expect(getConfig(config)).toStrictEqual(config[0]);
70
+ });
71
+
72
+ // test('get config array', () => {
73
+ // const trigger = {
74
+ // _id: 'abc'
75
+ // }
76
+
77
+ // expect(getQueryDataObsParameters(trigger)).toStrictEqual();
78
+ // });
79
+ })
80
+
@@ -0,0 +1,87 @@
1
+ import { Server } from 'socket.io';
2
+ import { createServer } from 'node:http'
3
+ import hubEvent from '../bin/hubEvent.js'
4
+ import { io as ioc } from "socket.io-client";
5
+ import { jest } from '@jest/globals';
6
+ import { of } from "rxjs";
7
+ import { Axios } from "axios-observable";
8
+
9
+ let socketsBySubdomain = {};
10
+
11
+ const createSocket2CLI = (socket) => {
12
+ return (subdomain, responseCb) => {
13
+ const responseCallback = (error) => { if (responseCb) responseCb(error) }
14
+ let subdomainStr = subdomain.toString();
15
+
16
+ socketsBySubdomain[subdomainStr] = socket;
17
+ socket.subdomain = subdomainStr;
18
+ // console.log(new Date() + ': ' + subdomainStr + ' registered successfully');
19
+
20
+ responseCallback(null);
21
+ }
22
+ }
23
+
24
+ const deleteSubdomain = (socket) => () => {
25
+ if (socket.subdomain) {
26
+ delete socketsBySubdomain[socket.subdomain];
27
+ console.log(new Date() + ': ' + socket.subdomain + ' unregistered');
28
+ }
29
+ }
30
+
31
+ const toPromise = (cb) => new Promise((resolve, reject) => {
32
+ cb(resolve)
33
+ setTimeout(() => reject(new Error('timeout')), 1000)
34
+ })
35
+
36
+ describe('cli req test', () => {
37
+ let io, port;
38
+ const startSocket = function startSocket(server) {
39
+ let io = new Server(server);
40
+ io.on('connection', (socket) => {
41
+ // console.log('socket client connect')
42
+ socket.on('createTunnel', createSocket2CLI(socket));
43
+ socket.on('disconnect', deleteSubdomain(socket));
44
+ });
45
+
46
+ return io;
47
+ }
48
+
49
+ beforeAll((done) => {
50
+ const httpServer = createServer()
51
+ io = startSocket(httpServer)
52
+
53
+ httpServer.listen(async () => {
54
+ port = httpServer.address().port;
55
+ done()
56
+ })
57
+ })
58
+
59
+ afterAll(() => {
60
+ io.close();
61
+ })
62
+
63
+ test('request to cli', async () => {
64
+ jest.spyOn(Axios, 'request').mockReturnValue(of({ data: 'OK' }));
65
+
66
+ let socket;
67
+ try {
68
+ socket = ioc(`http://localhost:${port}`);
69
+
70
+ await hubEvent(socket, {
71
+ server: `http://localhost:${port}`,
72
+ subdomain: 'scy',
73
+ hostname: 'localhost',
74
+ port: 212,
75
+ });
76
+
77
+ const result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
78
+ 'cli-req', { d: 1, }, cb => resolve(cb)
79
+ ))
80
+
81
+ expect(result).toStrictEqual('OK');
82
+ socket.disconnect();
83
+ } catch (error) {
84
+ console.log(error);
85
+ }
86
+ })
87
+ })
@@ -0,0 +1,34 @@
1
+
2
+ import { jest } from '@jest/globals'
3
+
4
+ const mockSendMail = jest.fn();
5
+ const mockCreateTransport = jest.fn();
6
+ mockCreateTransport.mockImplementation(() => ({
7
+ sendMail: mockSendMail
8
+ }))
9
+
10
+ jest.unstable_mockModule('nodemailer', () => ({
11
+ createTransport: (data) => mockCreateTransport(data)
12
+ }))
13
+
14
+ const { sendMailWatcher } = await import('../mailController.js');
15
+
16
+ describe('Mail Controller', () => {
17
+ let req;
18
+
19
+ test('transporter.sendmailWatcher is called', () => {
20
+ req = {
21
+ body: {
22
+ companyname: 'abc',
23
+ smtpConfig: {
24
+ smtp: 'test'
25
+ }
26
+ },
27
+ }
28
+
29
+ sendMailWatcher(req);
30
+ expect(mockSendMail).toBeCalledTimes(1);
31
+ expect(mockCreateTransport).toHaveBeenCalledWith({ smtp: 'test' });
32
+
33
+ })
34
+ })
@@ -0,0 +1,91 @@
1
+ import { jest } from '@jest/globals'
2
+
3
+ const mockCheckSchedule = jest.fn();
4
+ jest.unstable_mockModule("../scheduler/datalib.js", () => ({
5
+ checkSchedule: mockCheckSchedule.mockResolvedValue('OK'),
6
+ queryData: jest.fn().mockResolvedValue('OK'),
7
+ crudData: jest.fn().mockResolvedValue('OK'),
8
+ genId: jest.fn().mockResolvedValue('OK'),
9
+ delay: jest.fn().mockResolvedValue('OK')
10
+ }))
11
+
12
+ const {
13
+ SCHEDULE_INTERVAL,
14
+ getSelectedData,
15
+ increaseInterval,
16
+ runHistory
17
+ } = await import('../scheduler/timer.js');
18
+ const { ObjectId } = await import('mongodb');
19
+
20
+ describe('timer and mitigation test', () => {
21
+ test('increase interval', async () => {
22
+ const nextTime = increaseInterval('2024-02-16T10:30:10.593Z');
23
+ expect(new Date(nextTime).toISOString()).toStrictEqual('2024-02-16T10:31:10.593Z');
24
+ });
25
+
26
+ test('get selected data from array', async () => {
27
+ const SELECTED_HISTORY = {
28
+ _id: new ObjectId('65c34df55e7c9d9448804738'),
29
+ timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a9'),
30
+ latestRun: '2024-02-03T10:30:10.593Z'
31
+ };
32
+ const HISTORIES = [
33
+ {
34
+ _id: new ObjectId('65c34df55e7c9d9448804737'),
35
+ timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a8'),
36
+ latestRun: '2024-02-16T10:30:10.593Z'
37
+ },
38
+ SELECTED_HISTORY,
39
+ {
40
+ _id: new ObjectId('65c3613d5e7c9d94489a32d2'),
41
+ timerObjectId: new ObjectId('65c35aa937be3a626388ba6e'),
42
+ latestRun: '2024-02-04T11:00:26.783Z'
43
+ }
44
+ ]
45
+ expect(getSelectedData(HISTORIES, 'timerObjectId', '65c34bd774ae2595b5efb5a9')).toStrictEqual(SELECTED_HISTORY);
46
+ });
47
+
48
+ test('run history', async () => {
49
+ function decreaseInterval(now) {
50
+ const subtractInterval = new Date(now).getMilliseconds() - (3 * SCHEDULE_INTERVAL);
51
+ return new Date(now).setMilliseconds(subtractInterval);
52
+ }
53
+
54
+ const NOW = new Date('2024-02-29T07:00:00.000Z');
55
+ const HISTORIES = [
56
+ {
57
+ _id: new ObjectId('65c34df55e7c9d9448804737'),
58
+ timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a8'),
59
+ latestRun: new Date(decreaseInterval(NOW)).toISOString()
60
+ }
61
+ ]
62
+ const CONFIGS = [{
63
+ companyObjectId: new ObjectId('62948492f7d559fba6f32196')
64
+ }]
65
+ const WATCHERS = [
66
+ {
67
+ _id: new ObjectId('65c34bd674ae2595b5efb5a7'),
68
+ companyObjectId: new ObjectId('62948492f7d559fba6f32196'),
69
+ timer: [
70
+ {
71
+ _id: new ObjectId('65c34bd774ae2595b5efb5a8'),
72
+ name: 'New Watcher 1',
73
+ active: true,
74
+ timezone: 'Asia/Jakarta',
75
+ templateName: 'cekUser.js',
76
+ daily: [
77
+ 0, 1, 2, 3,
78
+ 4, 5, 6
79
+ ],
80
+ minutely: { everyMin: 1, from: '09:00', to: '18:00' },
81
+ watcherObjectId: new ObjectId('65c34bd674ae2595b5efb5a7'),
82
+ seq: 0,
83
+ }
84
+ ]
85
+ }
86
+ ]
87
+
88
+ await runHistory(HISTORIES, CONFIGS, WATCHERS, new Date('2024-02-29T07:00:00.000Z'));
89
+ expect(mockCheckSchedule).toBeCalledTimes(3);
90
+ });
91
+ })