code refactoring and added extensive documentation
This commit is contained in:
352
src/generate.ts
352
src/generate.ts
@@ -1,151 +1,233 @@
|
||||
/**
|
||||
* Dennis Gunia (c) 2020
|
||||
*
|
||||
* Generator Implementation.
|
||||
* This File provides the implementation of the code generator and mail sending functionality.
|
||||
*
|
||||
*
|
||||
* @summary Generator Implementation.
|
||||
* @author Dennis Gunia <info@dennisgunia.de>
|
||||
* @license Licensed under the Apache License, Version 2.0 (the "License").
|
||||
*
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import * as cliProgress from 'cli-progress'
|
||||
import { shuffleArray } from './util/shuffle';
|
||||
import { mkstring } from './util/token';
|
||||
|
||||
import * as Handlebars from "handlebars";
|
||||
import Mail from 'nodemailer/lib/mailer';
|
||||
import { SecureVault } from './vault';
|
||||
import { parseMails } from './mailParser';
|
||||
import { SVault } from './vault';
|
||||
import { MLParser } from './mailParser';
|
||||
import { shuffleArray } from './util/shuffle';
|
||||
import { delay, mkstringCN } from './util/misc';
|
||||
|
||||
interface mail{
|
||||
mail: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface genReturn{
|
||||
codes: string[];
|
||||
mails: mail[];
|
||||
}
|
||||
|
||||
export function generateToken(config: any,dataSafe: SecureVault): Promise<genReturn>{
|
||||
return new Promise<genReturn>((resolve,error) => {
|
||||
parseMails(config, dataSafe).then(res => {
|
||||
generateCodes(resolve,error,res,config,dataSafe);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// generate codes
|
||||
async function generateCodes(resolve: (value?: genReturn) => void,error: (reason?: any) => void,mailArray: mail[],config: any,dataSafe: SecureVault){
|
||||
console.log("\nGenerating codes")
|
||||
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0,{
|
||||
speed: "N/A"
|
||||
});
|
||||
let position = 0;
|
||||
|
||||
let codeArray: string[] = [];
|
||||
let checkString: string = '';
|
||||
|
||||
for(let i = 0; i < mailArray.length; i++){ // as many codes as adresses
|
||||
// check that codes are unique
|
||||
let code = '';
|
||||
do{
|
||||
code = mkstring(4);
|
||||
}while ( (config.force ? codeArray : [...codeArray, ...config.usedTokens]).includes(code))
|
||||
codeArray.push(code);
|
||||
checkString = `${checkString}|${code}`
|
||||
position ++;
|
||||
pbar.update(position);
|
||||
/**
|
||||
* Namespace containing the code for Generating the Code and delivering the mails
|
||||
*/
|
||||
export namespace MLGenerator {
|
||||
|
||||
/**
|
||||
* Interface used to Return codes and mails form the main Function {@link generateToken}
|
||||
*/
|
||||
export interface MLGenReturn{
|
||||
/** List of generated codes */
|
||||
codes: string[];
|
||||
/** List of processed mails */
|
||||
mails: MLParser.MLItem[];
|
||||
}
|
||||
checkString = checkString.substr(1);
|
||||
pbar.stop();
|
||||
//write code lists
|
||||
try {
|
||||
if (!fs.existsSync(path.dirname(config.outFileMatch))){
|
||||
fs.mkdirSync(path.dirname(config.outFileMatch));
|
||||
}
|
||||
fs.writeFileSync(config.outFileMatch, checkString);
|
||||
} catch (err) {
|
||||
|
||||
error(err);
|
||||
}
|
||||
sendMails(resolve,error,mailArray,codeArray,config,dataSafe);
|
||||
}
|
||||
|
||||
|
||||
// randomize mails and tokens
|
||||
async function sendMails(resolve: (value?: genReturn) => void,error: (reason?: any) => void,mailArray: mail[],codeArray: string[],config: any,dataSafe: SecureVault){
|
||||
let mailserver = nodemailer.createTransport(config.mail);
|
||||
// read mail template
|
||||
let template!: HandlebarsTemplateDelegate<any>;
|
||||
try {
|
||||
const htmlSrc=fs.readFileSync(config.htmlPath, "utf8")
|
||||
template = Handlebars.compile(htmlSrc)
|
||||
} catch (error) {
|
||||
console.error("Cannote read template file!")
|
||||
error(error);
|
||||
}
|
||||
|
||||
console.log("\nSending mails")
|
||||
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0,{
|
||||
speed: "N/A"
|
||||
});
|
||||
let position = 0;
|
||||
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
if (config.force){dataSafe.clearVault();}
|
||||
for(let i = 0; i < mailArray.length; i++){
|
||||
// send mail
|
||||
dataSafe.writeTransaction(`process: ${mailArray[i].mail}`);
|
||||
if (!config.dryrun){
|
||||
dataSafe.pushData({
|
||||
name: mailArray[i].name,
|
||||
mail: mailArray[i].mail,
|
||||
code: codeArray[i]
|
||||
|
||||
/**
|
||||
* Main function used to generate and deliver codes
|
||||
* @param config Main configuration object
|
||||
* @param dataSafe Main safe used for logging and storing data
|
||||
* @returns used codes and processed mails
|
||||
*/
|
||||
export function generateToken(config: any,dataSafe: SVault.SecureVault): Promise<MLGenReturn>{
|
||||
return new Promise<MLGenReturn>((resolve,error) => {
|
||||
MLParser.parseMails(config, dataSafe).then(res => {
|
||||
// next step
|
||||
generateCodes(resolve,error,res,config,dataSafe);
|
||||
})
|
||||
}
|
||||
await send(mailArray[i].name, mailArray[i].mail, codeArray[i],template,mailserver,config,dataSafe);
|
||||
position ++;
|
||||
pbar.update(position);
|
||||
});
|
||||
}
|
||||
pbar.stop();
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
resolve({
|
||||
codes: config.force ? codeArray : (config.dryrun ? config.usedTokens : [...codeArray, ...config.usedTokens]),
|
||||
mails: config.force ? mailArray : (config.dryrun ? config.usedMails : [...mailArray, ...config.usedMails])
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async function send(name: string, mail: string, code: string,template: HandlebarsTemplateDelegate<any>,mailserver: Mail,config: any,dataSafe: SecureVault){
|
||||
if (config.dryrun){
|
||||
await delay(100);
|
||||
console.log(`\n\x1b[36m -> dryrun: would send to ${mail}\x1b[0m`);
|
||||
}else{
|
||||
// fill template
|
||||
let html = template({
|
||||
"name": name,
|
||||
"mail": mail,
|
||||
"code": code
|
||||
})
|
||||
let mailOptions = {
|
||||
from: `${config.mailFrom} <${config.mail.auth.user}>`, // sender address
|
||||
to: mail, // list of receivers
|
||||
subject: `Dein Zugangscode zur BJR Wahl`, // Subject line
|
||||
html: html
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate the same amout of codes as distinct mail adresses and stores them to the list file
|
||||
* This function also includes previously used tokens to prevent duplicate tokens.
|
||||
* Rejects if matchfile cannot be saved.
|
||||
* @internal
|
||||
* @param resolve Callback to resolve promise
|
||||
* @param error Callback to reject promise
|
||||
* @param mailArray list of mail adresses
|
||||
* @param config Main configuration object
|
||||
* This Function uses the following variables:
|
||||
* usedTokens -> List of previosly used tokens
|
||||
* outFileMatch -> Path to match file
|
||||
* @param dataSafe Main safe used for logging and storing data
|
||||
*/
|
||||
async function generateCodes(resolve: (value?: MLGenReturn) => void,error: (reason?: any) => void,mailArray: MLParser.MLItem[],config: any,dataSafe: SVault.SecureVault){
|
||||
console.log("\nGenerating codes")
|
||||
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0,{
|
||||
speed: "N/A"
|
||||
});
|
||||
let position = 0;
|
||||
|
||||
let codeArray: string[] = [];
|
||||
let checkString: string = '';
|
||||
|
||||
for(let i = 0; i < mailArray.length; i++){ // as many codes as adresses
|
||||
// check that codes are unique
|
||||
let code = '';
|
||||
do{
|
||||
code = mkstringCN(4);
|
||||
}while ( (config.force ? codeArray : [...codeArray, ...config.usedTokens]).includes(code))
|
||||
codeArray.push(code);
|
||||
checkString = `${checkString}|${code}`
|
||||
position ++;
|
||||
pbar.update(position);
|
||||
}
|
||||
checkString = checkString.substr(1);
|
||||
pbar.stop();
|
||||
//write code lists
|
||||
try {
|
||||
await mailserver.sendMail(mailOptions);
|
||||
dataSafe.writeTransaction(` -> mail sent`);
|
||||
if (!fs.existsSync(path.dirname(config.outFileMatch))){
|
||||
fs.mkdirSync(path.dirname(config.outFileMatch));
|
||||
}
|
||||
fs.writeFileSync(config.outFileMatch, checkString);
|
||||
} catch (err) {
|
||||
|
||||
error(err);
|
||||
}
|
||||
// next
|
||||
sendMails(resolve,error,mailArray,codeArray,config,dataSafe);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads template file and compiles template.
|
||||
* Iterate through mails and codes, randomly assign code to mail and send mail to recipient.
|
||||
* If dryrun is enabled, mails will not be sent and new mails won't be included in return.
|
||||
* Rejects if template cannot be read.
|
||||
* @internal
|
||||
* @param resolve Callback to resolve promise
|
||||
* @param error Callback to reject promise
|
||||
* @param mailArray list of mail adresses
|
||||
* @param codeArray list of generated codes
|
||||
* @param config Main configuration object
|
||||
* This Function uses the following variables:
|
||||
* htmlPath -> Path to html template
|
||||
* dryrun -> Boolean value. If true no mails will be sent and list won't be updated.
|
||||
* force -> Boolean value. If true all mails are resent.
|
||||
* usedTokens -> Array of Strings. Specifies already used tokens adresses.
|
||||
* usedMails -> Array of Strings. Specifies already served mail adresses.
|
||||
* mail -> mailserver settings
|
||||
* @param dataSafe Main safe used for logging and storing data
|
||||
*/
|
||||
async function sendMails(resolve: (value?: MLGenReturn) => void,error: (reason?: any) => void,mailArray: MLParser.MLItem[],codeArray: string[],config: any,dataSafe: SVault.SecureVault){
|
||||
let mailserver = nodemailer.createTransport(config.mail);
|
||||
// read mail template and compile
|
||||
let template!: HandlebarsTemplateDelegate<any>;
|
||||
try {
|
||||
const htmlSrc=fs.readFileSync(config.htmlPath, "utf8")
|
||||
template = Handlebars.compile(htmlSrc)
|
||||
} catch (error) {
|
||||
console.log(`Error sendign mail to ${mail} : ${error}`)
|
||||
dataSafe.writeTransaction(` -> mail failed : ${error}`);
|
||||
console.error("Cannote read template file!")
|
||||
error(error);
|
||||
}
|
||||
|
||||
// send mails
|
||||
console.log("\nSending mails")
|
||||
const pbar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
pbar.start(mailArray.length, 0,{
|
||||
speed: "N/A"
|
||||
});
|
||||
let position = 0;
|
||||
|
||||
// randomize arrays
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
if (config.force){dataSafe.clearVault();}
|
||||
for(let i = 0; i < mailArray.length; i++){
|
||||
// send mail
|
||||
dataSafe.writeTransaction(`process: ${mailArray[i].mail}`);
|
||||
if (!config.dryrun){
|
||||
dataSafe.pushData({
|
||||
name: mailArray[i].name,
|
||||
mail: mailArray[i].mail,
|
||||
code: codeArray[i]
|
||||
})
|
||||
}
|
||||
await send(mailArray[i].name, mailArray[i].mail, codeArray[i],template,mailserver,config,dataSafe);
|
||||
position ++;
|
||||
pbar.update(position);
|
||||
}
|
||||
pbar.stop();
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
shuffleArray(mailArray);
|
||||
shuffleArray(codeArray);
|
||||
resolve({
|
||||
codes: config.force ? codeArray : (config.dryrun ? config.usedTokens : [...codeArray, ...config.usedTokens]),
|
||||
mails: config.force ? mailArray : (config.dryrun ? config.usedMails : [...mailArray, ...config.usedMails])
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads template file and compiles template.
|
||||
* Iterate through mails and codes, randomly assign code to mail and send mail to recipient.
|
||||
* If dryrun is enabled, mails will not be sent and new mails won't be included in return.
|
||||
* Rejects if template cannot be read.
|
||||
* @internal
|
||||
* @param name Name of recpipient
|
||||
* @param mail Mail of recpipient
|
||||
* @param code Code of recpipient
|
||||
* @param template compiled mail template
|
||||
* @param mailserver Mailserver settings
|
||||
* @param config Main configuration object
|
||||
* This Function uses the following variables:
|
||||
* mail.auth.user -> sender mail adress
|
||||
* mailFrom -> sender mail ailas
|
||||
* dryrun -> Boolean value. If true no mails will be sent.
|
||||
* @param dataSafe Main safe used for logging and storing data
|
||||
*/
|
||||
async function send(name: string, mail: string, code: string,template: HandlebarsTemplateDelegate<any>,mailserver: Mail,config: any,dataSafe: SVault.SecureVault){
|
||||
if (config.dryrun){
|
||||
await delay(100);
|
||||
console.log(`\n\x1b[36m -> dryrun: would send to ${mail}\x1b[0m`);
|
||||
}else{
|
||||
// fill template
|
||||
let html = template({
|
||||
"name": name,
|
||||
"mail": mail,
|
||||
"code": code
|
||||
})
|
||||
let mailOptions = {
|
||||
from: `${config.mailFrom} <${config.mail.auth.user}>`, // sender address
|
||||
to: mail, // list of receivers
|
||||
subject: `Dein Zugangscode zur BJR Wahl`, // Subject line
|
||||
html: html
|
||||
};
|
||||
try {
|
||||
await mailserver.sendMail(mailOptions);
|
||||
dataSafe.writeTransaction(` -> mail sent`);
|
||||
} catch (error) {
|
||||
console.log(`Error sendign mail to ${mail} : ${error}`)
|
||||
dataSafe.writeTransaction(` -> mail failed : ${error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delay(t: number, val?: number) {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(function() {
|
||||
resolve(val);
|
||||
}, t);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user