Andela Notifications Updated
This commit is contained in:
173
job-notifier/andela-appscript/Code.gs
Normal file
173
job-notifier/andela-appscript/Code.gs
Normal file
@@ -0,0 +1,173 @@
|
||||
// Code.gs — Google Apps Script Web App
|
||||
// Deploy as: Web app, Execute as "Me", Who has access: "Anyone"
|
||||
|
||||
// ============================================
|
||||
// CONFIGURATION — change these two, then create a NEW deployment version
|
||||
// ============================================
|
||||
var SECRET_KEY = '5f5bd4c1751f7582f870954da60cafe2'; // e.g. output of: openssl rand -hex 16
|
||||
var ALLOWED_EMAIL = 'justiceawudi@outlook.com'; // must match "Login Email" in extension Settings
|
||||
|
||||
function doPost(e) {
|
||||
try {
|
||||
var data = JSON.parse(e.postData.contents);
|
||||
|
||||
if (!data.key || data.key !== SECRET_KEY) {
|
||||
Logger.log('Unauthorized request - invalid key');
|
||||
return ContentService.createTextOutput(
|
||||
JSON.stringify({ error: 'Unauthorized' }),
|
||||
).setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
|
||||
if (data.email !== ALLOWED_EMAIL) {
|
||||
Logger.log('Unauthorized request - invalid email: ' + data.email);
|
||||
return ContentService.createTextOutput(
|
||||
JSON.stringify({ error: 'Unauthorized email' }),
|
||||
).setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
|
||||
if (data.action === 'pollForLoginLink') {
|
||||
var result = pollForMagicLink(data.requestId);
|
||||
return ContentService.createTextOutput(
|
||||
JSON.stringify(result),
|
||||
).setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
|
||||
return ContentService.createTextOutput(
|
||||
JSON.stringify({ error: 'Unknown action' }),
|
||||
).setMimeType(ContentService.MimeType.JSON);
|
||||
} catch (err) {
|
||||
Logger.log('Error in doPost: ' + err.message);
|
||||
return ContentService.createTextOutput(
|
||||
JSON.stringify({ error: err.message }),
|
||||
).setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Poll for magic login link.
|
||||
//
|
||||
// No "to:" filter — the email is sent to your Outlook address and
|
||||
// lands in Gmail via a forwarding rule, so its To/Delivered-To headers
|
||||
// may still reference Outlook rather than Gmail. from + subject +
|
||||
// newer_than + is:unread is specific enough since this only ever
|
||||
// searches your own mailbox.
|
||||
// ============================================
|
||||
function pollForMagicLink(requestId) {
|
||||
var maxAttempts = 4;
|
||||
var pollInterval = 15000;
|
||||
|
||||
Logger.log('[' + requestId + '] Starting poll for login link...');
|
||||
|
||||
for (var attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
Logger.log('[' + requestId + '] Attempt ' + attempt + '/' + maxAttempts);
|
||||
|
||||
var searchQuery =
|
||||
'from:talent.andela.com subject:"Andela Login Link" newer_than:5m is:unread';
|
||||
var threads = GmailApp.search(searchQuery, 0, 5);
|
||||
|
||||
Logger.log(
|
||||
'[' + requestId + '] Found ' + threads.length + ' matching threads',
|
||||
);
|
||||
|
||||
if (threads.length > 0) {
|
||||
var allMessages = [];
|
||||
for (var i = 0; i < threads.length; i++) {
|
||||
var messages = threads[i].getMessages();
|
||||
for (var j = 0; j < messages.length; j++) allMessages.push(messages[j]);
|
||||
}
|
||||
|
||||
allMessages.sort(function (a, b) {
|
||||
return b.getDate().getTime() - a.getDate().getTime();
|
||||
});
|
||||
|
||||
var latestMessage = allMessages[0];
|
||||
var body = latestMessage.getBody();
|
||||
|
||||
Logger.log(
|
||||
'[' + requestId + '] Processing email from: ' + latestMessage.getDate(),
|
||||
);
|
||||
|
||||
var accessAccountPattern =
|
||||
/<a\s+[^>]*href=["']([^"']+)["'][^>]*>\s*Access account\s*<\/a>/i;
|
||||
var match = body.match(accessAccountPattern);
|
||||
|
||||
if (match && match[1]) {
|
||||
var link = match[1]
|
||||
.replace(/&/g, '&')
|
||||
.replace(/=/g, '=')
|
||||
.replace(/=/g, '=')
|
||||
.replace(/&/g, '&');
|
||||
|
||||
Logger.log('[' + requestId + '] Found Access account link: ' + link);
|
||||
latestMessage.markRead();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
loginLink: link,
|
||||
emailDate: latestMessage.getDate().toISOString(),
|
||||
attempt: attempt,
|
||||
};
|
||||
}
|
||||
|
||||
Logger.log(
|
||||
'[' + requestId + '] Email found but no Access account link detected',
|
||||
);
|
||||
}
|
||||
|
||||
if (attempt < maxAttempts) {
|
||||
Logger.log('[' + requestId + '] Waiting ' + pollInterval / 1000 + 's...');
|
||||
Utilities.sleep(pollInterval);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.log(
|
||||
'[' +
|
||||
requestId +
|
||||
'] No login link found after ' +
|
||||
maxAttempts +
|
||||
' attempts',
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: 'No login link found within timeout',
|
||||
attempts: maxAttempts,
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Debug helpers — run manually from the Apps Script editor's function
|
||||
// dropdown, then check the Executions log
|
||||
// ============================================
|
||||
function debugLoginEmails() {
|
||||
var searchQuery =
|
||||
'from:talent.andela.com subject:"Andela Login Link" newer_than:7d';
|
||||
var threads = GmailApp.search(searchQuery, 0, 5);
|
||||
Logger.log('Found ' + threads.length + ' emails');
|
||||
|
||||
for (var i = 0; i < threads.length; i++) {
|
||||
var messages = threads[i].getMessages();
|
||||
for (var j = 0; j < messages.length; j++) {
|
||||
var msg = messages[j];
|
||||
Logger.log('---');
|
||||
Logger.log('Subject: ' + msg.getSubject());
|
||||
Logger.log('From: ' + msg.getFrom());
|
||||
Logger.log('To: ' + msg.getTo());
|
||||
Logger.log('Date: ' + msg.getDate());
|
||||
|
||||
var body = msg.getBody();
|
||||
var pattern =
|
||||
/<a\s+[^>]*href=["']([^"']+)["'][^>]*>\s*Access account\s*<\/a>/i;
|
||||
var match = body.match(pattern);
|
||||
if (match) {
|
||||
Logger.log('Link found: ' + match[1].substring(0, 100));
|
||||
} else {
|
||||
Logger.log('Access account link not found');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testExtraction() {
|
||||
var result = pollForMagicLink('test-' + Date.now());
|
||||
Logger.log(JSON.stringify(result, null, 2));
|
||||
}
|
||||
19
job-notifier/andela-appscript/README.md
Normal file
19
job-notifier/andela-appscript/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Andela Apps Script (Gmail magic-link fetcher)
|
||||
|
||||
Deploy this as a Google Apps Script Web App under the Google account whose
|
||||
Gmail receives the forwarded Andela login emails.
|
||||
|
||||
## Setup
|
||||
1. https://script.google.com → New project → paste `Code.gs` in as `Code.gs`.
|
||||
2. Edit `SECRET_KEY` (generate with `openssl rand -hex 16`) and `ALLOWED_EMAIL`
|
||||
(the email typed into the Andela login form — your Outlook address, not Gmail).
|
||||
3. Deploy → New deployment → Web app → Execute as **Me** → Who has access **Anyone**.
|
||||
4. Authorize Gmail access when prompted, then copy the `/exec` URL.
|
||||
5. Put that URL + the same SECRET_KEY + the same email into the Chrome
|
||||
extension's Settings page.
|
||||
6. Whenever you edit this file: Deploy → Manage deployments → Edit →
|
||||
Version: New version → Deploy (saving alone does not update the live web app).
|
||||
|
||||
## Debugging
|
||||
Run `debugLoginEmails` from the function dropdown in the editor, then check
|
||||
Executions in the left sidebar for the Logger output.
|
||||
Reference in New Issue
Block a user