ci: use Gitea API for releases #2
+142
@@ -0,0 +1,142 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const MASTER_KEY = 'enabled';
|
||||||
|
|
||||||
|
async function isEnabled() {
|
||||||
|
const { enabled } = await browser.storage.local.get(MASTER_KEY);
|
||||||
|
return enabled !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoAcceptPrivacy() {
|
||||||
|
const modal = document.getElementById('myModal');
|
||||||
|
if (!modal) return;
|
||||||
|
const checkbox = document.getElementById('Confirmation');
|
||||||
|
const submit = document.getElementById('Submit');
|
||||||
|
if (checkbox && !checkbox.checked) checkbox.click();
|
||||||
|
if (submit) submit.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchPrivacyModal() {
|
||||||
|
autoAcceptPrivacy();
|
||||||
|
const observer = new MutationObserver(() => autoAcceptPrivacy());
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
setTimeout(() => observer.disconnect(), 30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function autoLogin() {
|
||||||
|
const { profiles } = await browser.storage.local.get('profiles');
|
||||||
|
const active = (profiles || []).find((p) => p.enabled);
|
||||||
|
if (!active) return;
|
||||||
|
const userField = document.querySelector(
|
||||||
|
'input[name="UserName"], input[name="username"], input[id="UserName"], input[id="username"]'
|
||||||
|
);
|
||||||
|
const passField = document.querySelector('input[type="password"]');
|
||||||
|
if (!userField || !passField) return;
|
||||||
|
userField.value = active.username;
|
||||||
|
passField.value = active.password;
|
||||||
|
userField.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
passField.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
const form = userField.closest('form') || passField.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
setTimeout(() => {
|
||||||
|
const submitBtn = form.querySelector('input[type="submit"], button[type="submit"]');
|
||||||
|
if (submitBtn) submitBtn.click();
|
||||||
|
else form.submit();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchCourseDescription(courseCode, academicPeriod, academicYear, token) {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
body.set('Courses', courseCode);
|
||||||
|
body.set('AcademicPeriod', academicPeriod);
|
||||||
|
body.set('AcademicYear', academicYear);
|
||||||
|
body.set('AjaxFormVM.Controller', 'CourseSchedule');
|
||||||
|
body.set('AjaxFormVM.Action', 'CourseScheduleOffered');
|
||||||
|
body.set('AjaxFormVM.ResultTargetId', 'CourseScheduleOfferedList');
|
||||||
|
body.set('AjaxFormVM.LinkToReturn', '');
|
||||||
|
body.set('AjaxFormVM.LinkToReturnTargetId', '');
|
||||||
|
body.set('AjaxFormVM.FormHeader', 'Choose term to view courses offered');
|
||||||
|
body.set('AjaxFormVM.FormHeaderIcon', '');
|
||||||
|
body.set('AjaxFormVM.FormId', 'CourseScheduleCourseScheduleOffered');
|
||||||
|
body.set('AjaxFormVM.ShowCloseButton', 'True');
|
||||||
|
body.set('AjaxFormVM.PreventAutoUpdateTarget', 'True');
|
||||||
|
body.set('AjaxFormVM.CloseModalAfterSubmit', 'False');
|
||||||
|
body.set('AjaxFormVM.AjaxFormType', 'Search');
|
||||||
|
body.set('AjaxFormVM.FormNoteLocation', '');
|
||||||
|
body.set('AjaxFormVM.SubmitButton.FaIcon', '');
|
||||||
|
body.set('AjaxFormVM.SubmitButton.ButtonText', '');
|
||||||
|
body.set('AjaxFormVM.SubmitButton.ButtonSize', '');
|
||||||
|
body.set('__RequestVerificationToken', token);
|
||||||
|
const resp = await fetch('/CourseSchedule/CourseScheduleOffered?Length=14', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
|
'X-Requested-With': 'XMLHttpRequest'
|
||||||
|
},
|
||||||
|
body: body.toString(),
|
||||||
|
credentials: 'same-origin'
|
||||||
|
});
|
||||||
|
const html = await resp.text();
|
||||||
|
const courses = ISMIStools.parseOfferedCourses(html);
|
||||||
|
const match = courses.find((c) => c.courseCode === courseCode);
|
||||||
|
return match ? match.description : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTotalUnits(text) {
|
||||||
|
const m = /Total Units:\s*([\d.]+)/i.exec(text);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function scrapeStudyLoad() {
|
||||||
|
const table = document.querySelector('table.table-forum');
|
||||||
|
if (!table) throw new Error('No study load table found on this page.');
|
||||||
|
const courses = ISMIStools.parseStudyLoadTable(table.outerHTML);
|
||||||
|
if (!courses.length) throw new Error('No courses found in study load table.');
|
||||||
|
|
||||||
|
const periodEl = document.getElementById('AcademicPeriod');
|
||||||
|
const yearEl = document.getElementById('AcademicYear');
|
||||||
|
const tokenEl = document.querySelector('input[name="__RequestVerificationToken"]');
|
||||||
|
const academicPeriod = periodEl ? periodEl.value : '';
|
||||||
|
const academicYear = yearEl ? yearEl.value : '';
|
||||||
|
const token = tokenEl ? tokenEl.value : '';
|
||||||
|
|
||||||
|
const uniqueCodes = [...new Set(courses.map((c) => c.courseCode))];
|
||||||
|
const descMap = {};
|
||||||
|
for (const code of uniqueCodes) {
|
||||||
|
try {
|
||||||
|
descMap[code] = await fetchCourseDescription(code, academicPeriod, academicYear, token);
|
||||||
|
} catch (e) {
|
||||||
|
descMap[code] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
courses.forEach((c) => { c.description = descMap[c.courseCode] || ''; });
|
||||||
|
|
||||||
|
let header = {};
|
||||||
|
try {
|
||||||
|
const resp = await fetch('/Manage/Student', { credentials: 'same-origin' });
|
||||||
|
const html = await resp.text();
|
||||||
|
header = ISMIStools.parseProfilePage(html);
|
||||||
|
} catch (e) {
|
||||||
|
header = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalUnits = extractTotalUnits(document.body.innerText);
|
||||||
|
return { header, courses, totalUnits };
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||||
|
if (msg && msg.type === 'scrape-study-load') {
|
||||||
|
scrapeStudyLoad()
|
||||||
|
.then((data) => sendResponse({ ok: true, data }))
|
||||||
|
.catch((err) => sendResponse({ ok: false, error: String((err && err.message) || err) }));
|
||||||
|
return true; // async response
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(async function init() {
|
||||||
|
if (!(await isEnabled())) return;
|
||||||
|
watchPrivacyModal();
|
||||||
|
if (/\/Account\/Login/i.test(location.href)) autoLogin();
|
||||||
|
})();
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user