<commit_before>import * as Promise from 'bluebird';
import * as fs from 'fs';
import * as _ from 'lodash';
import * as nodemailer from 'nodemailer';

import { logger } from './Logger';

export interface IEmailOptions {
  service: string;
  email: string;
  password: string;
  stored: string;
}

export interface IMessage {
  [index: string]: string;
  to: string;
  subject: string;
  text: string;
  html: string;
}

export interface IBuiltMessage {
  from: string;
  html: string;
  subject: string;
  text: string;
  to: string;
}

interface IStoredEmail {
  to: string;
  title: string;
  content: string;
}

export default class Email {
  private service: string;
  private username: string;
  private transporter: nodemailer.Transporter;
  private online: boolean;

  constructor(options: IEmailOptions) {
    // The type of service used for emailing.
    this.service = options.service;

    // The email that will be used to make the connection.
    this.username = options.email;

    // Transporter that will be sending the emails
    this.transporter = this.build(options.password);

    // Status for checking that the email connection is working.
    this.online = false;

    this.verify()
    .then(() => {
      this.online = true;
      return this.sendStoredEmails(options.stored);
    })
    .then(() => logger.info(`[Email] Email Client is ready, service=${this.service}, email=${this.username}`))
    .catch(error => logger.error(`[Email] Error creating email connection, error=${error}`));
  }

 /**
  * Take any stored emails in sthe email path and send them when the connection system is up
  * @param jsonPath The path to the json file of the stored emails to be send later
  */
  public sendStoredEmails(jsonPath: string) {
    if (!this.online) {
      return Promise.reject(new Error(`[Email] Service must be online to send stored emails`));
    }

    // If the file does not exist already we shall create it but resolve as there is no emails to be sent.
    if (!fs.existsSync(jsonPath)) {
      const template: { emails: any } = { emails: [] };

      fs.writeFileSync(jsonPath, JSON.stringify(template, null, '\t'));
      logger.info(`[Email] Stored json file does not exist to retrieve late email content, creating...`);
      return Promise.resolve();
    }

    const storedEmails: { emails: IStoredEmail[] } = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));

    if (_.isNil(storedEmails.emails[0])) {
      logger.info(`[Email] No late stored emails to send 😊`);
      return Promise.resolve();
    }

    storedEmails.emails.forEach((element: IStoredEmail) => {
      this.send(this.username, element.to, element.title, element.content)
      .then((info: nodemailer.SentMessageInfo) => logger.info(`Sent stored email: ${info.messageId}`))
      .catch((error: Error) => logger.warn(`Failed to send store email ${error.message}`));
    });

    return Promise.resolve();
  }

  /**
   * Sends a email to the provided person with the provided content.
   * @param {string} to The person who is getting sent the email.
   * @param {string} subject The subject text for the email.
   * @param {string} text  The content text for the email.
   * @param {undefined} html The html to be used instead of the text (defaults to the text)
   */
  public send(from: string, to: string, subject: string, text: string, html?: string): Promise<nodemailer.SentMessageInfo | Error> {
    const content = [
      { name: 'from', type: from },
      { name: 'subject', type: subject },
      { name: 'text', type: text },
      { name: 'to', type: to },
    ];

    _.forEach(content, (item) => {
      if (_.isNil(item.type) || !_.isString(item.type)) {
        throw new Error(`${item.name} has to be specified and of type string`);
      }
    });

    return new Promise((resolve, reject) => {<commit_msg>Late email removing<commit_after>import * as Promise from 'bluebird';
import * as fs from 'fs';
import * as _ from 'lodash';
import * as nodemailer from 'nodemailer';

import { logger } from './Logger';

export interface IEmailOptions {
  service: string;
  email: string;
  password: string;
  stored: string;
}

export interface IMessage {
  [index: string]: string;
  to: string;
  subject: string;
  text: string;
  html: string;
}

export interface IBuiltMessage {
  from: string;
  html: string;
  subject: string;
  text: string;
  to: string;
}

interface IStoredEmail {
  to: string;
  title: string;
  content: string;
}

export default class Email {
  private service: string;
  private username: string;
  private transporter: nodemailer.Transporter;
  private online: boolean;

  constructor(options: IEmailOptions) {
    // The type of service used for emailing.
    this.service = options.service;

    // The email that will be used to make the connection.
    this.username = options.email;

    // Transporter that will be sending the emails
    this.transporter = this.build(options.password);

    // Status for checking that the email connection is working.
    this.online = false;

    this.verify()
    .then(() => {
      this.online = true;
      return this.sendStoredEmails(options.stored);
    })
    .then(() => logger.info(`[Email] Email Client is ready, service=${this.service}, email=${this.username}`))
    .catch(error => logger.error(`[Email] Error creating email connection, error=${error}`));
  }

 /**
  * Take any stored emails in sthe email path and send them when the connection system is up
  * @param jsonPath The path to the json file of the stored emails to be send later
  */
  public sendStoredEmails(jsonPath: string) {
    if (!this.online) {
      return Promise.reject(new Error(`[Email] Service must be online to send stored emails`));
    }

    // If the file does not exist already we shall create it but resolve as there is no emails to be sent.
    if (!fs.existsSync(jsonPath)) {
      const template: { emails: any } = { emails: [] };

      fs.writeFileSync(jsonPath, JSON.stringify(template, null, '\t'));
      logger.info(`[Email] Stored json file does not exist to retrieve late email content, creating...`);
      return Promise.resolve();
    }

    const storedEmails: { emails: IStoredEmail[] } = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
    const updatedStoredEmails: { emails: IStoredEmail[] } = { emails: storedEmails.emails.slice() };
    let sentEmails: number = 0;

    if (_.isNil(storedEmails.emails[0])) {
      logger.info(`[Email] No late stored emails to send 😊`);
      return Promise.resolve();
    }

    storedEmails.emails.forEach((email: IStoredEmail) => {
      this.send(this.username, email.to, email.title, email.content, email.content)
      .then((info: nodemailer.SentMessageInfo) => {
        logger.info(`[Email] Sent stored email: ${info.messageId}`);
        updatedStoredEmails.emails.shift();
      })
      .finally(() => {
        sentEmails += 1;

        if (sentEmails === storedEmails.emails.length) {
          fs.writeFileSync(jsonPath, JSON.stringify(updatedStoredEmails, null, '\t'));
          return Promise.resolve();
        }
      })
      .catch((error: Error) => logger.warn(`[Email] Failed to send store email ${error.message}`));
    });

    return Promise.resolve();
  }

  /**
   * Sends a email to the provided person with the provided content.
   * @param {string} to The person who is getting sent the email.
   * @param {string} subject The subject text for the email.
   * @param {string} text  The content text for the email.
   * @param {undefined} html The html to be used instead of the text (defaults to the text)
   */
  public send(from: string, to: string, subject: string, text: string, html?: string): Promise<nodemailer.SentMessageInfo | Error> {
    const content = [
      { name: 'from', type: from },
      { name: 'subject', type: subject },
      { name: 'text', type: text },
      { name: 'to', type: to },
    ];

    _.forEach(content, (item) => {
      if (_.isNil(item.type) || !_.isString(item.type)) {
        throw new Error(`${item.name} has to be specified and of type string`);
      }
    });

    return new Promise((resolve, reject) => {
{'fraction_non_alphanumeric': 0.12812000491823436, 'fraction_numerical': 0.0007377351530800443, 'mean_word_length': 3.212325220093216, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3707972', 'n_tokens_mistral': 2408, 'n_tokens_neox': 2385, 'n_words': 812}