All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.oliviercailloux.javagrade.utils.SendEmails Maven / Gradle / Ivy

The newest version!
package io.github.oliviercailloux.javagrade.utils;

import static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.math.Quantiles;
import com.google.common.math.Stats;
import io.github.oliviercailloux.email.EmailAddress;
import io.github.oliviercailloux.email.EmailAddressAndPersonal;
import io.github.oliviercailloux.git.github.model.GitHubUsername;
import io.github.oliviercailloux.grade.Exam;
import io.github.oliviercailloux.grade.Grade;
import io.github.oliviercailloux.grade.Mark;
import io.github.oliviercailloux.grade.MarksTree;
import io.github.oliviercailloux.grade.comm.Email;
import io.github.oliviercailloux.grade.comm.Emailer;
import io.github.oliviercailloux.grade.comm.EmailerDauphineHelper;
import io.github.oliviercailloux.grade.comm.GradesInEmails;
import io.github.oliviercailloux.grade.comm.json.JsonStudents;
import io.github.oliviercailloux.grade.format.HtmlGrades;
import io.github.oliviercailloux.grade.format.json.JsonSimpleGrade;
import io.github.oliviercailloux.jaris.collections.CollectionUtils;
import io.github.oliviercailloux.xml.XmlUtils;
import jakarta.mail.Folder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

public class SendEmails {
  @SuppressWarnings("unused")
  private static final Logger LOGGER = LoggerFactory.getLogger(SendEmails.class);

  private static final Path WORK_DIR = Path.of("");

  public static void main(String[] args) throws Exception {
    // final String prefix = Colors.PREFIX + " second";
    // final String prefix = CompCust.PREFIX;
    // final String prefix = Strings.PREFIX + " second";
    final String prefix = "";
    // final String prefix = "Présentation";

    final JsonStudents students =
        JsonStudents.from(Files.readString(WORK_DIR.resolve("usernames.json")));
    // final JsonObject jsonS =
    // PrintableJsonObjectFactory.
    // wrapRawString(Files.readString(WORK_DIR.resolve("usernames.json"))).asJsonObject();
    // final StudentOnGitHubKnown studentsK =
    // JsonStudentOnGitHubKnown.asStudentOnGitHubKnown(jsonS);
    final Exam exam = JsonSimpleGrade.asExam(Files.readString(
        WORK_DIR.resolve("grades" + (prefix.equals("") ? "" : " ") + prefix + ".json")));

    final boolean allKnown = students.getInstitutionalStudentsByGitHubUsername().keySet()
        .containsAll(exam.getUsernames());
    checkState(allKnown, Sets.difference(exam.getUsernames(),
        students.getInstitutionalStudentsByGitHubUsername().keySet()));

    final ImmutableSet missing =
        Sets.difference(students.getInstitutionalStudentsByGitHubUsername().keySet(),
            exam.getUsernames()).immutableCopy();
    if (!missing.isEmpty()) {
      LOGGER.warn("Missing: {}.", missing);
    }

    final Mark defaultMark = Mark.given(0d, "GitHub repository not found");
    final ImmutableMap marksByEmail = exam.getUsernames().stream().collect(ImmutableMap.toImmutableMap(
            u -> students.getInstitutionalStudentsByGitHubUsername().get(u).getEmail(),
            u -> exam.getUsernames().contains(u) ? exam.getGrade(u).toMarksTree() : defaultMark));
    final ImmutableMap gradesByEmail = ImmutableMap
        .copyOf(Maps.transformValues(marksByEmail, m -> Grade.given(exam.aggregator(), m)));

    final ImmutableList points = gradesByEmail.values().stream().map(Grade::mark)
        .map(Mark::getPoints).collect(ImmutableList.toImmutableList());
    final Stats stats = Stats.of(points);
    final Map quartiles = Quantiles.quartiles().indexes(1, 2, 3).compute(points);

    try (GradesInEmails gradesInEmails = GradesInEmails.newInstance()) {
      @SuppressWarnings("resource")
      final Emailer emailer = gradesInEmails.getEmailer();
      EmailerDauphineHelper.connect(emailer);
      @SuppressWarnings("resource")
      final Folder folder = emailer.getFolderReadWrite("Grades");
      gradesInEmails.setFolder(folder);

      final ImmutableSet addresses = gradesByEmail.keySet().stream()
          .map(EmailAddressAndPersonal::getAddress).collect(ImmutableSet.toImmutableSet());
      gradesInEmails.filterRecipients(addresses);
      final String prefixOrFinal = prefix.equals("") ? "final" : prefix;
      final ImmutableMap lastGrades =
          gradesInEmails.getLastGrades(prefixOrFinal);
      LOGGER.debug("Searching grades sent to {}, got those sent to {}.", addresses,
          lastGrades.keySet());

      // checkState(!lastGrades.isEmpty());

      for (EmailAddressAndPersonal address : gradesByEmail.keySet()) {
        if (!lastGrades.containsKey(address.getAddress())) {
          LOGGER.info("Not found {} among {}.", address, lastGrades.keySet());
        }
      }

      final Map gradesDiffering = gradesByEmail.entrySet().stream()
              .filter(e -> isDiff(Optional.ofNullable(lastGrades.get(e.getKey().getAddress())),
                  e.getValue()))
              // .filter(e -> !e.getKey().getPersonal().contains("…"))
              .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));

      for (EmailAddressAndPersonal address : gradesDiffering.keySet()) {
        final Grade lastGrade = lastGrades.get(address.getAddress());
        if (lastGrade == null) {
          continue;
        }
        final Grade gradeFromJson = gradesByEmail.get(address);
        // LOGGER.info("Diff {}: {} (before {}, after {}).", address, getDiff(lastGrade,
        // gradeFromJson),
        // lastGrade, gradeFromJson);
        final double before = lastGrade.mark().getPoints();
        final double after = gradeFromJson.mark().getPoints();
        LOGGER.info("Diff {} (before {}, after {}).", address, before, after);
        if (before > after) {
          LOGGER.warn("Losing points.");
        }
      }

      // final String json = JsonSimpleGrade.toJson(gradesByEmail);
      final String title = "grades " + prefix + " sent";
      // Files.writeString(Path.of(title + ".json"), json);
      final ImmutableMap gradesByStr = CollectionUtils.transformKeys(lastGrades,
          e -> students.getInstitutionalStudentsByEmail().get(e).getUsername());
      final Document doc = HtmlGrades.asHtmlGrades(gradesByStr, title, 20d);
      Files.writeString(Path.of(title + ".html"), XmlUtils.asString(doc));

      final ImmutableSet emails = gradesDiffering
          .entrySet().stream().map(e -> GradesInEmails.asEmail(getDestination(e.getKey()),
              prefixOrFinal, e.getValue(), stats, quartiles))
          .collect(ImmutableSet.toImmutableSet());

      final Optional first = emails.stream().findFirst();
      LOGGER.info("Prepared first doc (out of {}): {}, to {}.", emails.size(),
          first.map(Email::getDocument).map(XmlUtils::asString), first.map(Email::getTo));
      // LOGGER.info("Prepared {}.", effectiveEmails);

      emailer.saveInto(folder);
      // emailer.send(emails, EmailerDauphineHelper.FROM);
    }
  }

  private static boolean isDiff(Optional lastGrade, Grade current) {
    final boolean isSame =
        current.toAggregator().equals(lastGrade.map(Grade::toAggregator).orElse(null))
            && current.toMarksTree().equals(lastGrade.map(Grade::toMarksTree).orElse(null));
    return !isSame;
    // return !DoubleMath.fuzzyEquals(lastGrade.map(IGrade::getPoints).orElse(-1d),
    // current.getPoints(), 1e-8d);
  }

  private static EmailAddressAndPersonal getDestination(EmailAddressAndPersonal e) {
    return e;
    // return EmailAddressAndPersonal.given(EmailerDauphineHelper.FROM.getAddress().getAddress(),
    // e.getPersonal());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy