io.github.oliviercailloux.plaquette.M1AltBuilder Maven / Gradle / Ivy
The newest version!
package io.github.oliviercailloux.plaquette;
import static com.google.common.base.Verify.verify;
import com.google.common.base.Verify;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.io.MoreFiles;
import ebx.ebx_dataservices.StandardException;
import io.github.oliviercailloux.jaris.xml.DomHelper;
import io.github.oliviercailloux.publish.AsciidocWriter;
import io.github.oliviercailloux.publish.DocBookConformityChecker;
import io.github.oliviercailloux.publish.DocBookTransformer;
import io.github.oliviercailloux.publish.ToBytesTransformer;
import jakarta.xml.bind.JAXBElement;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.xml.transform.stream.StreamSource;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Options;
import org.jsoup.Jsoup;
import org.jsoup.helper.W3CDom;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import schemas.ebx.dataservices_1.CourseType.Root.Course;
import schemas.ebx.dataservices_1.PersonType.Root.Person;
import schemas.ebx.dataservices_1.ProgramType.Root.Program;
public class M1AltBuilder {
@SuppressWarnings("unused")
private static final Logger LOGGER = LoggerFactory.getLogger(M1AltBuilder.class);
private static final boolean WRITE_HTML = false;
public static final String MENTION_ID = "FRUAI0750736TPRMEA5IFO";
public static final String PROGRAM_IDENT = "PRA4AMIA-100";
public static final String PROGRAM_ID_PREFIX = "FRUAI0750736TPR";
public static final String PROGRAM_ID = PROGRAM_ID_PREFIX + PROGRAM_IDENT;
public static final String PROGRAM_URL =
"https://dauphine.psl.eu/formations/masters/informatique/1re-annee-de-master-miage/programme";
public static final String PROGRAM_ID_S1 = "FRUAI0750736TPRCPA4AMIA-100-S1";
public static final String PROGRAM_ID_S1_L1 = "FRUAI0750736TPRCPA4AMIA-100-S1L1";
public static final String S1_L1_NAME = "UE Obligatoires S1";
public static final String PROGRAM_ID_S1_L2 = "FRUAI0750736TPRCPA4AMIAS1L2";
public static final String S1_L2_NAME = "Bloc UE d'application";
public static final String PROGRAM_ID_S2 = "FRUAI0750736TPRCPA4AMIA-100-S2";
public static final String PROGRAM_ID_S2_L1 = "FRUAI0750736TPRCPA4AMIA-100-S2L1";
public static final String S2_L1_NAME = "UE Obligatoires S2";
public static final String PROGRAM_ID_S2_L2 = "FRUAI0750736TPRCPA4AMIA-100-S2L2";
public static final String S2_L2_NAME = "UE Optionnelles S2";
public static void main(String[] args) throws Exception {
LOGGER.info("Obtained {}.", M1AltBuilder.class.getResource("M1ApprBuilder.class"));
AuthenticatorHelper.setDefaultAuthenticator();
final M1AltBuilder builder = new M1AltBuilder();
builder.proceed();
}
private final AsciidocWriter writer;
private Cacher cache;
private final Querier querier;
public M1AltBuilder() {
writer = new AsciidocWriter();
cache = null;
querier = Querier.instance();
}
private void proceed() throws StandardException, IOException {
final ImmutableSet programs = ImmutableSet.of(PROGRAM_ID, PROGRAM_ID_S1,
PROGRAM_ID_S1_L1, PROGRAM_ID_S2, PROGRAM_ID_S2_L1, PROGRAM_ID_S2_L2);
LOGGER.info("Caching.");
cache = Cacher.cache(querier, programs);
verify();
writer.h1("Programme des cours du M1 MIAGE en alternance");
writer.addAttribute("lang", "fr");
writer.addAttribute("toc", "preamble");
writer.eol();
writer.paragraph("Généré le "
+ DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(Locale.FRANCE)
.withZone(ZoneId.of("Europe/Paris")).format(Instant.now())
+ " à partir des données du " + PROGRAM_URL + "[site internet] de Dauphine.");
writeSummary();
{
final String subProgramName =
cache.getProgram(PROGRAM_ID_S1).getProgramName().getValue().getFr().getValue();
writer.h2(subProgramName);
}
{
final Program program = cache.getProgram(PROGRAM_ID_S1_L1);
final String programNameFr = program.getProgramName().getValue().getFr().getValue();
writer.h3(programNameFr);
for (Course course : cache.getProgramCourses(PROGRAM_ID_S1_L1).values()) {
writeCourse(course);
}
}
// {
// final Program program = cache.getProgram(PROGRAM_ID_S1_L2);
// Verify.verify(program.getProgramStructure().getValue().getRefProgram().isEmpty());
// final String programNameFr = program.getProgramName().getValue().getFr().getValue();
// Verify.verify(programNameFr.equals(S1_L2_NAME), programNameFr);
// writer.h3(programNameFr);
//
// for (Course course : cache.getProgramCourses(PROGRAM_ID_S1_L2).values()) {
// writeCourse(course);
// }
// }
{
final String subProgramName =
cache.getProgram(PROGRAM_ID_S2).getProgramName().getValue().getFr().getValue();
writer.h2(subProgramName);
}
{
final Program program = cache.getProgram(PROGRAM_ID_S2_L1);
final String programNameFr = program.getProgramName().getValue().getFr().getValue();
writer.h3(programNameFr);
for (Course course : cache.getProgramCourses(PROGRAM_ID_S2_L1).values()) {
writeCourse(course);
}
}
{
final Program program = cache.getProgram(PROGRAM_ID_S2_L2);
final String programNameFr = program.getProgramName().getValue().getFr().getValue();
writer.h3(programNameFr);
for (Course course : cache.getProgramCourses(PROGRAM_ID_S2_L2).values()) {
writeCourse(course);
}
}
final String adoc = writer.getContent();
Files.writeString(Paths.get("out.adoc"), adoc);
LOGGER.info("Creating Asciidoctor converter.");
final String docBook;
try (Asciidoctor adocConverter = Asciidoctor.Factory.create()) {
LOGGER.info("Converting to Docbook.");
docBook = adocConverter.convert(adoc,
Options.builder().headerFooter(true).backend("docbook").build());
}
LOGGER.info("Validating Docbook.");
LOGGER.debug("Docbook: {}.", docBook);
DocBookConformityChecker.usingDefaults()
.verifyValid(new StreamSource(new StringReader(docBook)));
final StreamSource myStyle =
new StreamSource(M1AltBuilder.class.getResource("dauphine.xsl").toString());
final ToBytesTransformer toPdf =
DocBookTransformer.usingDefaultFactory().usingFoStylesheet(myStyle, ImmutableMap.of())
.asDocBookToPdfTransformer(Path.of("non-existent-" + Instant.now()).toUri());
toPdf.toSink(new StreamSource(new StringReader(docBook)),
MoreFiles.asByteSink(Path.of("out.pdf")));
}
private void writeSummary() {
writer.h2("Vue d’ensemble");
final ImmutableList.Builder> summaryBuilder = ImmutableList.builder();
for (Course course : cache.getCourses().values()) {
final String courseId = course.getCourseID();
final ImmutableSet teachers = cache.getCourseTeachers(courseId).values();
final String names = teachers.stream()
.map(t -> t.getGivenName().getValue() + " " + t.getFamilyName().getValue())
.collect(Collectors.joining("; "));
final ImmutableList row = ImmutableList.of(
course.getCourseName().getValue().getFr().getValue(), names, course.getEcts().getValue());
summaryBuilder.add(row);
}
final boolean someMultipleTeachers = cache.getCourses().keySet().stream()
.map(cache::getCourseTeachers).map(Map::values).map(Collection::size).anyMatch(i -> i >= 2);
final String resp =
someMultipleTeachers ? "Enseignant·e·s responsables" : "Enseignant·e responsable";
writer.table("6, 6, 1", ImmutableList.of("Cours", resp, "ECTS"), summaryBuilder.build());
}
private void verify() {
final Program main = cache.getProgram(PROGRAM_ID);
Verify.verify(main.getIdent().getValue().equals(PROGRAM_IDENT));
Verify.verify(main.getProgramID().equals(PROGRAM_ID_PREFIX + PROGRAM_IDENT));
{
final String programNameFr = main.getProgramName().getValue().getFr().getValue();
Verify.verify(programNameFr.contains("MIAGE"), programNameFr);
}
Verify.verify(main.getRefMention().getValue().equals(MENTION_ID));
final List subPrograms = main.getProgramStructure().getValue().getRefProgram();
Verify.verify(subPrograms.equals(ImmutableList.of(PROGRAM_ID_S1, PROGRAM_ID_S2)));
final Program s1 = cache.getProgram(PROGRAM_ID_S1);
Verify.verify(s1.getRefMention().getValue().equals(MENTION_ID));
final List refProgram = s1.getProgramStructure().getValue().getRefProgram();
Verify.verify(refProgram.equals(ImmutableList.of(PROGRAM_ID_S1_L1)), refProgram.toString());
final Program s2 = cache.getProgram(PROGRAM_ID_S2);
Verify.verify(s2.getRefMention().getValue().equals(MENTION_ID));
final List refProgramS2 = s2.getProgramStructure().getValue().getRefProgram();
Verify.verify(refProgramS2.equals(ImmutableList.of(PROGRAM_ID_S2_L1, PROGRAM_ID_S2_L2)),
ImmutableList.copyOf(refProgramS2).toString());
final Program s1l1 = cache.getProgram(PROGRAM_ID_S1_L1);
Verify.verify(s1l1.getProgramStructure().getValue().getRefProgram().isEmpty());
{
final String programNameFr = s1l1.getProgramName().getValue().getFr().getValue();
Verify.verify(programNameFr.equals(S1_L1_NAME), programNameFr);
}
final Program s2l1 = cache.getProgram(PROGRAM_ID_S2_L1);
Verify.verify(s2l1.getProgramStructure().getValue().getRefProgram().isEmpty());
{
final String programNameFr = s2l1.getProgramName().getValue().getFr().getValue();
Verify.verify(programNameFr.equals(S2_L1_NAME), programNameFr);
}
final Program s2l2 = cache.getProgram(PROGRAM_ID_S2_L2);
Verify.verify(s2l2.getProgramStructure().getValue().getRefProgram().isEmpty());
{
final String programNameFr = s2l2.getProgramName().getValue().getFr().getValue();
Verify.verify(programNameFr.equals(S2_L2_NAME), programNameFr);
}
}
private void writeCourse(Course course) {
final String courseName = course.getCourseName().getValue().getFr().getValue();
writer.h4(courseName);
final String volume = course.getVolume().getValue();
Verify.verify(volume.equals("0") == courseName.equals("Mémoire"), courseName);
final String volumeText = volume.equals("0") ? "" : volume + " h" + " ; ";
String shortInfo = volumeText + course.getEcts().getValue() + " ECTS";
ImmutableSet> otherLangs =
ImmutableSet.of(ImmutableList.of("fr+en"), ImmutableList.of("en"));
ImmutableSet> langs = Sets
.>union(ImmutableSet.of(ImmutableList.of("fr")), otherLangs).immutableCopy();
Verify.verify(langs.contains(course.getTeachingLang()));
if (course.getTeachingLang().equals(ImmutableList.of("en"))) {
shortInfo += " ; Dispensé en anglais";
}
writer.paragraph(shortInfo);
Verify.verify(course.getAdmissionInfo() == null);
// Verify.verify(course.getCoefficient().getValue().getFr().getValue()
// .equals("\nCapitalisation : Non
\n
"));
// LOGGER.info(course.getCoefficient().getValue().getFr().getValue());
final ImmutableSet teachers = cache.getCourseTeachers(course.getCourseID()).values();
// Verify.verify(teachers.isEmpty() == courseName.equals("Mémoire"), courseName);
if (!teachers.isEmpty()) {
final String names = teachers.stream()
.map(t -> t.getGivenName().getValue() + " " + t.getFamilyName().getValue())
.collect(Collectors.joining("; "));
final String prefix =
teachers.size() == 1 ? "Enseignant·e responsable : " : "Enseignant·e·s responsables : ";
writer.paragraph(prefix + names);
}
Verify.verify(course.getCourseIntroduction() == null);
Verify.verify(course.getFormOfTeaching() == null);
Verify.verify(course.getLevel() == null);
Verify.verify(course.getLevelLang() == null);
Verify.verify(course.getTeachers().isEmpty());
writer.eol();
final Optional recommendedPrerequisitesOpt =
valueOpt(course.getRecommendedPrerequisites(), Course.RecommendedPrerequisites::getFr);
addOptionalSection("Prérequis recommandés", recommendedPrerequisitesOpt);
final Optional formalPrerequisitesOpt =
valueOpt(course.getFormalPrerequisites(), Course.FormalPrerequisites::getFr);
addOptionalSection("Prérequis obligatoires", formalPrerequisitesOpt);
final Optional learningObjectivesOpt =
valueOpt(course.getLearningObjectives(), Course.LearningObjectives::getFr);
addOptionalSection("Compétences à acquérir", learningObjectivesOpt);
final Optional courseDescriptionOpt =
valueOpt(course.getCourseDescription(), Course.CourseDescription::getFr);
addOptionalSection("Contenu", courseDescriptionOpt);
if (courseDescriptionOpt.isEmpty()) {
Verify.verify(courseName.equals("Mémoire"), courseName);
}
final Optional syllabusOpt = valueOpt(course.getSyllabus(), Course.Syllabus::getFr);
addOptionalSection("Références", syllabusOpt);
final Optional formOfAssessmentOpt =
valueOpt(course.getFormOfAssessment(), Course.FormOfAssessment::getFr);
addOptionalSection("Évaluation", formOfAssessmentOpt);
}
private void addOptionalSection(final String title, final Optional contentOpt) {
if (contentOpt.isPresent()) {
final String content = contentOpt.get();
if (WRITE_HTML) {
writer.h5(title + " html");
writer.verbatim(content);
writer.eol();
}
writer.h5(title);
writer.append(getText(content));
writer.eol();
}
}
private String getText(String htmlText) {
final Document parsed = Jsoup.parse(htmlText);
final List children = parsed.body().childNodes();
return getText(children);
}
private String getText(List children) {
final StringBuilder textBuilder = new StringBuilder();
for (Node node : children) {
final String text = getText(node);
textBuilder.append(text);
}
final String text = textBuilder.toString();
return text;
}
private String getText(Node node) {
final String text;
if (node instanceof TextNode) {
text = AsciidocWriter.quote(((TextNode) node).text().strip());
} else if (node instanceof Element) {
final Element element = (Element) node;
final String tag = element.normalName();
if (tag.equals("br")) {
text = "\n\n";
} else if (tag.equals("strong")) {
text = "*" + getText(element.childNodes()) + "*";
} else if (tag.equals("p")) {
text = "\n\n" + getText(element.childNodes());
} else if (tag.equals("ul")) {
text = "\n\n" + getText(element.childNodes());
} else if (tag.equals("li")) {
final List liChildren = element.childNodes();
if (liChildren.size() == 1) {
final Node liChild = liChildren.get(0);
Verify.verify(liChild instanceof TextNode);
final String inner = ((TextNode) liChild).text();
Verify.verify(!inner.isBlank());
text = "- " + inner + "\n";
} else {
String outerHtml = node.outerHtml();
Document asDoc = Jsoup.parseBodyFragment(outerHtml);
String asString = W3CDom.convert(asDoc).getDocumentElement().getTextContent();
// LOGGER.info("Outer: {}.", outerHtml);
// LOGGER.info("As string: {}.", asString);
text = "- " + asString.replace("\n", "");
}
} else {
throw new IllegalArgumentException(node.outerHtml());
}
} else {
throw new IllegalArgumentException(node.outerHtml());
}
return text;
}
public static Optional valueOpt(JAXBElement element) {
return element == null ? Optional.empty() : Optional.of(element.getValue());
}
public Optional valueOpt(JAXBElement element,
Function> toFunction) {
return element == null ? Optional.empty()
: Optional.of(element.getValue()).map(toFunction).map(JAXBElement::getValue);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy