csuf-en 1.0.10
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/cli.js +5 -0
- package/index.js +199 -0
- package/package.json +31 -0
package/cli.js
ADDED
package/index.js
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
const puppeteer = require("puppeteer");
|
4
|
+
const prompt = require("prompt-sync")();
|
5
|
+
|
6
|
+
function promptHeadlessOption() {
|
7
|
+
const response = prompt(
|
8
|
+
"Do you want to run Puppeteer in headless mode? (yes/no): "
|
9
|
+
).toLowerCase();
|
10
|
+
|
11
|
+
if (response === "yes" || response === "y") {
|
12
|
+
return true;
|
13
|
+
} else if (response === "no" || response === "n") {
|
14
|
+
return false;
|
15
|
+
} else {
|
16
|
+
console.log("Please enter a valid option (yes/no).");
|
17
|
+
return promptHeadlessOption();
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
const headless = promptHeadlessOption();
|
22
|
+
|
23
|
+
if (headless === null) {
|
24
|
+
console.log("You must choose a mode (yes/no) before starting.");
|
25
|
+
process.exit(1);
|
26
|
+
}
|
27
|
+
|
28
|
+
if (headless) {
|
29
|
+
console.log("Puppeteer will run in headless mode.");
|
30
|
+
} else {
|
31
|
+
console.log("Puppeteer will run in non-headless mode.");
|
32
|
+
}
|
33
|
+
|
34
|
+
const CWID = prompt("Enter CWID: ");
|
35
|
+
const FIRST_NAME = prompt("Enter First Name: ");
|
36
|
+
const LAST_NAME = prompt("Enter Last Name: ");
|
37
|
+
const EMAIL = prompt("Enter Email: ");
|
38
|
+
const HOME_PHONE = prompt("Enter Home Phone: ");
|
39
|
+
const MOBILE_PHONE = prompt("Enter Mobile Phone: ");
|
40
|
+
const BIRTHDAY = prompt("Enter Birthday (DD/MM/YYYY): ");
|
41
|
+
const GENDER = prompt("Enter Gender: ");
|
42
|
+
const ADDRESS_LINE_1 = prompt("Enter Address Line 1: ");
|
43
|
+
const ADDRESS_LINE_2 = prompt("Enter Address Line 2: ");
|
44
|
+
const CITY = prompt("Enter City: ");
|
45
|
+
const STATE = prompt("Enter State: ");
|
46
|
+
const ZIP_CODE = prompt("Enter Zip Code: ");
|
47
|
+
const COUNTRY = prompt("Enter Country: ");
|
48
|
+
|
49
|
+
async function scrapeClassIds(browser) {
|
50
|
+
const page = await browser.newPage();
|
51
|
+
await page.goto(
|
52
|
+
"https://cmsweb.fullerton.edu/psc/CFULPRD/EMPLOYEE/SA/c/SA_LEARNER_SERVICES.CLASS_SEARCH.GBL?&public",
|
53
|
+
{
|
54
|
+
waitUntil: "networkidle2"
|
55
|
+
}
|
56
|
+
);
|
57
|
+
await page.setViewport({ width: 1080, height: 1024 });
|
58
|
+
await page.select("#SSR_CLSRCH_WRK_SUBJECT_SRCH\\$0", "ENGL");
|
59
|
+
await page.type("#SSR_CLSRCH_WRK_CATALOG_NBR\\$1", "101");
|
60
|
+
await page.select("#SSR_CLSRCH_WRK_SSR_EXACT_MATCH1\\$1", "T");
|
61
|
+
await page.click("#SSR_CLSRCH_WRK_SSR_OPEN_ONLY\\$3");
|
62
|
+
await page.click("#CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH");
|
63
|
+
await page.waitForSelector('input[id="\\#ICSave"]');
|
64
|
+
await page.click('input[id="\\#ICSave"]');
|
65
|
+
await page.waitForSelector("#MTG_CLASS_NBR\\$0");
|
66
|
+
const elements = await page.$$('[id^="MTG_CLASS_NBR"]');
|
67
|
+
const classIds = new Set();
|
68
|
+
for (const element of elements) {
|
69
|
+
const classId = await page.evaluate((el) => el.textContent, element);
|
70
|
+
classIds.add(classId);
|
71
|
+
}
|
72
|
+
await page.close();
|
73
|
+
return classIds;
|
74
|
+
}
|
75
|
+
|
76
|
+
async function createRequest(browser, classId) {
|
77
|
+
const page = await browser.newPage();
|
78
|
+
await page.goto("https://extension.fullerton.edu/app/Create", {
|
79
|
+
waitUntil: "networkidle2"
|
80
|
+
});
|
81
|
+
await page.setViewport({ width: 1080, height: 1024 });
|
82
|
+
await page.type("input[name=cwid]", CWID);
|
83
|
+
await page.click(
|
84
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
85
|
+
);
|
86
|
+
await page.click('input[name="ques1"][value="0"]');
|
87
|
+
await page.click('input[name="ques2"][value="0"]');
|
88
|
+
await page.click('input[name="ques3"][value="0"]');
|
89
|
+
await page.click('input[name="ques4"][value="1"]');
|
90
|
+
await page.click('input[name="ques5"][value="0"]');
|
91
|
+
await page.click('input[name="ques6"][value="1"]');
|
92
|
+
await page.click('input[name="ques7"][value="0"]');
|
93
|
+
await page.click('input[name="ques8"][value="1"]');
|
94
|
+
await page.click('input[name="ques9"][value="0"]');
|
95
|
+
await page.click('input[name="immigrationStatus"][value="4"]');
|
96
|
+
await page.click('input[name="ques10"][value="1"]');
|
97
|
+
await page.click(
|
98
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
99
|
+
);
|
100
|
+
await page.type("input[name=classnbr]", classId);
|
101
|
+
await page.evaluate(() => {
|
102
|
+
const buttons = Array.from(
|
103
|
+
document.querySelectorAll(
|
104
|
+
"button.MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary"
|
105
|
+
)
|
106
|
+
);
|
107
|
+
const targetButton = buttons.find((button) =>
|
108
|
+
button.innerText.includes("REQUEST CLASS")
|
109
|
+
);
|
110
|
+
if (targetButton) {
|
111
|
+
targetButton.click();
|
112
|
+
}
|
113
|
+
});
|
114
|
+
await page.waitForFunction(
|
115
|
+
(classId) =>
|
116
|
+
document.body.textContent.includes("Class: " + classId) ||
|
117
|
+
document.body.textContent.includes("Alert"),
|
118
|
+
{},
|
119
|
+
classId
|
120
|
+
);
|
121
|
+
if (await page.evaluate(() => document.body.textContent.includes("Alert"))) {
|
122
|
+
console.log("!! Class not available !!");
|
123
|
+
await page.close();
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
await page.waitForFunction(
|
127
|
+
(classId) => document.body.textContent.includes("Class: " + classId),
|
128
|
+
{},
|
129
|
+
classId
|
130
|
+
);
|
131
|
+
|
132
|
+
await page.click(
|
133
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
134
|
+
);
|
135
|
+
|
136
|
+
await page.type("input[name=firstname]", FIRST_NAME);
|
137
|
+
await page.type("input[name=lastname]", LAST_NAME);
|
138
|
+
await page.type("input[name=email]", EMAIL);
|
139
|
+
await page.type("input[name=confirmemail]", EMAIL);
|
140
|
+
await page.type("input[name=phonehome]", HOME_PHONE);
|
141
|
+
await page.type("input[name=phonemobile]", MOBILE_PHONE);
|
142
|
+
await page.type("input[name=birthdate]", BIRTHDAY);
|
143
|
+
await page.select('select[name="gender"]', GENDER);
|
144
|
+
await page.type("input[name=address1]", ADDRESS_LINE_1);
|
145
|
+
await page.type("input[name=address2]", ADDRESS_LINE_2);
|
146
|
+
await page.type("input[name=city]", CITY);
|
147
|
+
await page.type("input[name=state]", STATE);
|
148
|
+
await page.type("input[name=zip]", ZIP_CODE);
|
149
|
+
await page.type("input[name=country]", COUNTRY);
|
150
|
+
await page.select('select[name="immigrationStatus"]', "10");
|
151
|
+
await page.click(
|
152
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
153
|
+
);
|
154
|
+
await page.click(
|
155
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
156
|
+
);
|
157
|
+
await page.click(
|
158
|
+
".MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-fullWidth"
|
159
|
+
);
|
160
|
+
|
161
|
+
await page.waitForFunction(
|
162
|
+
() =>
|
163
|
+
document.body.textContent.includes(
|
164
|
+
"Your request for approval to enroll has been submitted successfully."
|
165
|
+
),
|
166
|
+
{}
|
167
|
+
);
|
168
|
+
|
169
|
+
const trackingCode = await page.evaluate(() => {
|
170
|
+
const h6 = document.querySelector(
|
171
|
+
"h6.MuiTypography-root.MuiTypography-subtitle2"
|
172
|
+
);
|
173
|
+
const text = h6 ? h6.innerText : null;
|
174
|
+
const match = text ? text.match(/Tracking Code: (\w+)/) : null;
|
175
|
+
return match ? match[1] : null;
|
176
|
+
});
|
177
|
+
|
178
|
+
console.log("Tracking code:", trackingCode);
|
179
|
+
|
180
|
+
await page.close();
|
181
|
+
}
|
182
|
+
|
183
|
+
(async () => {
|
184
|
+
const browser = await puppeteer.launch({ headless });
|
185
|
+
|
186
|
+
console.log("Running for CWID " + CWID);
|
187
|
+
|
188
|
+
const classIds = await scrapeClassIds(browser);
|
189
|
+
console.log("Got class ids:", classIds);
|
190
|
+
|
191
|
+
for (const classId of classIds) {
|
192
|
+
console.log("Requesting class " + classId);
|
193
|
+
await createRequest(browser, classId);
|
194
|
+
}
|
195
|
+
|
196
|
+
await browser.close();
|
197
|
+
|
198
|
+
console.log("Done");
|
199
|
+
})();
|
package/package.json
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
{
|
2
|
+
"name": "csuf-en",
|
3
|
+
"version": "1.0.10",
|
4
|
+
"description": "A Puppeteer script for csuf eng101 class",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
8
|
+
},
|
9
|
+
"repository": {
|
10
|
+
"type": "git",
|
11
|
+
"url": "git+https://github.com/Apromodo/csuf-eng.git"
|
12
|
+
},
|
13
|
+
"keywords": [
|
14
|
+
"puppeteer",
|
15
|
+
"automation",
|
16
|
+
"script"
|
17
|
+
],
|
18
|
+
"author": "Kaya Unal",
|
19
|
+
"license": "MIT",
|
20
|
+
"bin": {
|
21
|
+
"csuf-eng": "index.js"
|
22
|
+
},
|
23
|
+
"bugs": {
|
24
|
+
"url": "https://github.com/Apromodo/csuf-eng/issues"
|
25
|
+
},
|
26
|
+
"homepage": "https://github.com/Apromodo/csuf-eng#readme",
|
27
|
+
"dependencies": {
|
28
|
+
"prompt-sync": "^4.2.0",
|
29
|
+
"puppeteer": "^21.11.0"
|
30
|
+
}
|
31
|
+
}
|