charlesv3 1.0.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.
Potentially problematic release.
This version of charlesv3 might be problematic. Click here for more details.
- package/README.md +35 -0
- package/charles.bat +3 -0
- package/configCharles.js +43 -0
- package/connectToChurch/averageFilter.js +22 -0
- package/connectToChurch/cookieHandler.js +43 -0
- package/connectToChurch/getAverage.js +121 -0
- package/connectToChurch/getBearer.js +55 -0
- package/connectToChurch/listToday.js +49 -0
- package/connectToChurch/sneakyChurch.js +132 -0
- package/connectToChurch/superParse.js +27 -0
- package/connectToFacebook/crazyJob.json +10 -0
- package/connectToFacebook/editPayload.js +52 -0
- package/connectToFacebook/kindMessages.json +36 -0
- package/connectToFacebook/prettyString.js +25 -0
- package/connectToFacebook/randomMessage.js +8 -0
- package/connectToFacebook/sneakyFacebook.js +215 -0
- package/createConfig.js +46 -0
- package/createPayload.js +54 -0
- package/getZone.js +103 -0
- package/index.js +123 -0
- package/lastRun.js +24 -0
- package/package.json +28 -0
- package/prettyStringZones.js +18 -0
- package/smlReport.js +143 -0
package/smlReport.js
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
import chalk from "chalk"
|
2
|
+
import cliProgress from 'cli-progress'
|
3
|
+
import fetch from 'node-fetch'
|
4
|
+
import { promises } from "fs"
|
5
|
+
import { averageFilter } from "./connectToChurch/averageFilter.js"
|
6
|
+
import Bottleneck from "bottleneck"
|
7
|
+
|
8
|
+
function formatTime(minutes) {
|
9
|
+
const days = Math.floor(minutes / 1440); // 1 day = 1440 minutes
|
10
|
+
const hours = Math.floor((minutes % 1440) / 60); // Remaining hours
|
11
|
+
const mins = Math.floor(minutes % 60); // Remaining minutes
|
12
|
+
|
13
|
+
let result = [];
|
14
|
+
if (days > 0) result.push(`${days} day${days > 1 ? 's' : ''}`);
|
15
|
+
if (hours > 0) result.push(`${hours} hr${hours > 1 ? 's' : ''}`);
|
16
|
+
if (mins > 0 || result.length === 0) result.push(`${mins} min${mins > 1 ? 's' : ''}`);
|
17
|
+
|
18
|
+
return result.join(" ");
|
19
|
+
}
|
20
|
+
|
21
|
+
async function processContactTime(timeline) {
|
22
|
+
const reversedTimeline = [...timeline].reverse();
|
23
|
+
|
24
|
+
let referralSent = null;
|
25
|
+
let lastContact = null;
|
26
|
+
|
27
|
+
for (const item of reversedTimeline) {
|
28
|
+
switch (item.timelineItemType) {
|
29
|
+
case "NEW_REFERRAL":
|
30
|
+
referralSent = new Date(item.itemDate);
|
31
|
+
lastContact = null; // Reset when a new referral is found
|
32
|
+
break;
|
33
|
+
case "CONTACT":
|
34
|
+
case "TEACHING":
|
35
|
+
if (!lastContact) {
|
36
|
+
lastContact = new Date(item.itemDate);
|
37
|
+
}
|
38
|
+
break;
|
39
|
+
default:
|
40
|
+
continue;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
if (referralSent && lastContact) {
|
45
|
+
const duration = (lastContact - referralSent) / (1000 * 60); // Convert milliseconds to minutes
|
46
|
+
return Math.floor(duration);
|
47
|
+
}
|
48
|
+
|
49
|
+
return null;
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
const getPersonTimeline = async (person, bearer, cookie, bar, unprocessed) => {
|
54
|
+
const personTimeline = await fetch(`https://referralmanager.churchofjesuschrist.org/services/progress/timeline/${person.guid}`, {
|
55
|
+
method: 'GET',
|
56
|
+
'headers': {
|
57
|
+
"Authorization": `Bearer ${bearer}`,
|
58
|
+
"Cookie": cookie,
|
59
|
+
"User-Agent": "Mozilla/5.0"
|
60
|
+
}
|
61
|
+
})
|
62
|
+
.then(response => response.json())
|
63
|
+
|
64
|
+
bar.increment()
|
65
|
+
|
66
|
+
const time = await processContactTime(personTimeline)
|
67
|
+
|
68
|
+
if (!unprocessed[person.areaName]) {
|
69
|
+
unprocessed[person.areaName] = [];
|
70
|
+
}
|
71
|
+
unprocessed[person.areaName].push(time);
|
72
|
+
}
|
73
|
+
|
74
|
+
export const smlReport = async () => {
|
75
|
+
|
76
|
+
const bar = new cliProgress.SingleBar({
|
77
|
+
format: 'But the fat Hobbit, he knows. Eyes always watching. |' + chalk.magenta('{bar}') + '| {value}/{total} People || ETA: {eta_formatted}',
|
78
|
+
barCompleteChar: '\u2588',
|
79
|
+
barIncompleteChar: '\u2591',
|
80
|
+
hideCursor: true
|
81
|
+
});
|
82
|
+
|
83
|
+
|
84
|
+
let rawList
|
85
|
+
try {
|
86
|
+
rawList = await JSON.parse( await promises.readFile('resources/rawList.json'))
|
87
|
+
// eslint-disable-next-line no-unused-vars
|
88
|
+
} catch(e) {
|
89
|
+
console.log(chalk.red("You shall not pass! Run Charles at least once before accessing SML features."))
|
90
|
+
return
|
91
|
+
}
|
92
|
+
|
93
|
+
// Filter list down
|
94
|
+
const filtered = await averageFilter(rawList.persons)
|
95
|
+
const bearer = (await promises.readFile('resources/bearer.txt')).toString().trim()
|
96
|
+
const cookieDough = await JSON.parse(await promises.readFile('resources/cookies.json'))
|
97
|
+
const cookieString = cookieDough
|
98
|
+
.map(cookie => `${cookie.name}=${cookie.value}`)
|
99
|
+
.join("; ");
|
100
|
+
|
101
|
+
bar.start(filtered.length, 0)
|
102
|
+
let contactsWithoutAveraging = {}
|
103
|
+
|
104
|
+
const limiter = new Bottleneck({
|
105
|
+
maxConcurrent: 10,
|
106
|
+
})
|
107
|
+
|
108
|
+
|
109
|
+
// If you don't await these promises the church servers will block you so you don't DDoS them.
|
110
|
+
let tasks = filtered
|
111
|
+
.filter(person => person.guid) // Ignore people without a GUID
|
112
|
+
.map(person =>
|
113
|
+
limiter.schedule(() =>
|
114
|
+
getPersonTimeline(person, bearer, cookieString, bar, contactsWithoutAveraging)
|
115
|
+
)
|
116
|
+
);
|
117
|
+
await Promise.all(tasks)
|
118
|
+
|
119
|
+
bar.stop();
|
120
|
+
|
121
|
+
// DELETE anything empty that remains
|
122
|
+
|
123
|
+
delete contactsWithoutAveraging[null];
|
124
|
+
delete contactsWithoutAveraging[undefined];
|
125
|
+
delete contactsWithoutAveraging[""];
|
126
|
+
|
127
|
+
let areaAverages = Object.entries(contactsWithoutAveraging)
|
128
|
+
.map(([area, times]) => ({ area: area.trim(), avgTime: times.reduce((sum, t) => sum + (t || 0), 0) / times.length })) // Compute numeric average
|
129
|
+
.sort((a, b) => a.avgTime - b.avgTime); // Sort by shortest average contact time
|
130
|
+
|
131
|
+
let message = "-->Contact Times<--\n\n"
|
132
|
+
for (const { area, avgTime } of areaAverages) {
|
133
|
+
let prefix = "⌛"
|
134
|
+
if (avgTime < 360) {
|
135
|
+
prefix = '🔥'
|
136
|
+
} else if (avgTime > 720) {
|
137
|
+
prefix = '😱'
|
138
|
+
}
|
139
|
+
message += `${prefix} ${area}: ${formatTime(avgTime)}\n`
|
140
|
+
}
|
141
|
+
|
142
|
+
return message
|
143
|
+
}
|