Skip to content

Commit

Permalink
Merge pull request #21 from MathieuSoysal/20-add-logg-system
Browse files Browse the repository at this point in the history
20 add logg system
  • Loading branch information
MathieuSoysal authored Dec 30, 2023
2 parents ad0eed3 + 76188d1 commit 059a1b7
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 12 deletions.
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,21 @@
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>


<dependencies>
<!-- Dependencies -->
<dependency>
<groupId>com.github.forax</groupId>
<artifactId>beautiful_logger</artifactId>
<version>0.10.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/io/github/mathieusoysal/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,46 @@

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.github.forax.beautifullogger.Logger;

import io.github.mathieusoysal.exceptions.ApiRequestFailedException;
import io.github.mathieusoysal.exceptions.PropertiesNotFoundRuntimeException;
import io.github.mathieusoysal.logement.data.DataCollector;
import io.github.mathieusoysal.logement.data.DataSaver;

public class App {

private static final Logger LOGGER = Logger.getLogger();
private static final String MAIL_PROPERTIES_NAME = "MAIL";
private static final String PASSWORD_PROPERTIES_NAME = "PASSWORD";

public static void main(String[] args)
throws StreamReadException, DatabindException, ApiRequestFailedException, IOException,
InterruptedException {
LOGGER.info(() -> "Starting application");
var logements = DataCollector.getAvailableLogementsWithConnection(getEmail(), getPassword());
DataSaver.createArchiveLogements(logements);
LOGGER.info(() -> "Application finished");
}

private static String getEmail() {
LOGGER.info(() -> "Getting email from environment variables");
String email = System.getenv(MAIL_PROPERTIES_NAME);
if (email == null)
{
LOGGER.error(() -> "Email not found in environment variables");
throw new PropertiesNotFoundRuntimeException(MAIL_PROPERTIES_NAME);
}
return email;
}

private static String getPassword() {
LOGGER.info(() -> "Getting password from environment variables");
String password = System.getenv(PASSWORD_PROPERTIES_NAME);
if (password == null)
{
LOGGER.error(() -> "Password not found in environment variables");
throw new PropertiesNotFoundRuntimeException(PASSWORD_PROPERTIES_NAME);
}
return password;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.BooleanSupplier;

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.github.forax.beautifullogger.Logger;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Browser.NewContextOptions;
import com.microsoft.playwright.BrowserContext;
Expand All @@ -27,6 +27,8 @@
import io.github.mathieusoysal.logement.pojo.Logement;

public class DataCollector {
private static final Logger LOGGER = Logger.getLogger();
private static final String LINK_TO_GET_ALL_LOGEMENTS = "https://trouverunlogement.lescrous.fr/api/fr/search/32";
private static final String BODY_POST_TO_GET_LOGEMENTS = "{\r\n \"idTool\": 32,\r\n \"need_aggregation\": false,\r\n \"page\": 1,\r\n \"pageSize\": 2500,\r\n \"sector\": null,\r\n \"occupationModes\": [],\r\n \"location\": [\r\n {\r\n \"lon\": -9.9079,\r\n \"lat\": 51.7087\r\n },\r\n {\r\n \"lon\": 14.3224,\r\n \"lat\": 40.5721\r\n }\r\n ],\r\n \"residence\": null,\r\n \"precision\": 9,\r\n \"equipment\": [],\r\n \"price\": {\r\n \"min\": 0,\r\n \"max\": 10000000\r\n }\r\n}";
private static final RequestOptions REQUEST_TO_GET_LOGEMENTS = RequestOptions.create()
.setMethod("POST")
Expand All @@ -36,55 +38,76 @@ public class DataCollector {
public static List<Logement> getAvailableLogementsWithoutConnection()
throws ApiRequestFailedException, StreamReadException, DatabindException, IOException {
List<Logement> logements;
LOGGER.info(() -> "Creating profil to request logements");
try (Playwright playwright = Playwright.create()) {
LOGGER.info(() -> "profil created");
LOGGER.info(() -> "Requesting logements from " + LINK_TO_GET_ALL_LOGEMENTS);
var respons = playwright.request().newContext()
.head("https://trouverunlogement.lescrous.fr/api/fr/search/32", REQUEST_TO_GET_LOGEMENTS);
.head(LINK_TO_GET_ALL_LOGEMENTS, REQUEST_TO_GET_LOGEMENTS);
if (!respons.ok())
throw new ApiRequestFailedException(respons);
LOGGER.info(() -> "Logements received");
logements = Convertor.getLogementsFromBruteJsonString(respons.text());
}
LOGGER.info(() -> "profil closed");
return logements;
}

public static List<Logement> getAllLogementsWithoutConnection()
throws ApiRequestFailedException, StreamReadException, DatabindException, IOException {
LOGGER.info(() -> "Getting all logements");
List<Logement> logements;
LOGGER.info(() -> "Creating profil to request logements");
try (Playwright playwright = Playwright.create()) {
var respons = playwright.request().newContext()
.head("https://trouverunlogement.lescrous.fr/api/fr/search/29", REQUEST_TO_GET_LOGEMENTS);
if (!respons.ok())
if (!respons.ok()) {
LOGGER.error(() -> "Request failed");
throw new ApiRequestFailedException(respons);
}
LOGGER.info(() -> "Request succeed");
logements = Convertor.getLogementsFromBruteJsonString(respons.text());
}
LOGGER.info(() -> "profil closed");
LOGGER.info(() -> "All logements received");
return logements;
}

public static List<Logement> getAvailableLogementsWithConnection(String email, String password)
throws ApiRequestFailedException, StreamReadException, DatabindException, IOException,
InterruptedException {
LOGGER.info(() -> "Getting available logements");
LOGGER.info(() -> "Creating profil to request logements");
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions());
BrowserContext context = browser.newContext(new NewContextOptions().setScreenSize(1920, 1080));
Page page = context.newPage();
List<Logement> logements;
try {

context.tracing().start(new Tracing.StartOptions()
.setScreenshots(true)
.setSnapshots(true)
.setSources(true));
goToLoginPage(page);
selectLoginOption(playwright, page);
connectToTheCrous(email, password, playwright, page);
LOGGER.info(() -> "Going to logements page");
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Lancer une recherche"))
.click();
page.waitForLoadState();
LOGGER.info(() -> "Requesting logements from " + LINK_TO_GET_ALL_LOGEMENTS);
var respons = page.request()
.head("https://trouverunlogement.lescrous.fr/api/fr/search/32",
.head(LINK_TO_GET_ALL_LOGEMENTS,
REQUEST_TO_GET_LOGEMENTS);
if (!respons.ok())
if (!respons.ok()) {
LOGGER.error(() -> "Request failed");
throw new ApiRequestFailedException(respons);
}
LOGGER.info(() -> "Logements received");
logements = Convertor.getLogementsFromBruteJsonString(respons.text());
} catch (TimeoutError | LoginOptionCantBeSelectedError | CannotBeConnectedError e) {
LOGGER.error("Request failed", e);
context.tracing().stop(new Tracing.StopOptions()
.setPath(Paths.get("trace.zip")));
throw e;
Expand All @@ -93,11 +116,13 @@ public static List<Logement> getAvailableLogementsWithConnection(String email, S
context.close();
browser.close();
playwright.close();
LOGGER.info(() -> "profil closed");
}
return logements;
}

private static void goToLoginPage(Page page) {
LOGGER.info(() -> "Going to login page");
page.navigate("https://trouverunlogement.lescrous.fr/tools/32/search");
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Identification")).click();
page.waitForLoadState();
Expand All @@ -106,6 +131,7 @@ private static void goToLoginPage(Page page) {
private static void selectLoginOption(Playwright playwright, Page page) {
playwright.selectors().setTestIdAttribute("id");
String currentUrl = page.url();
LOGGER.info(() -> "Selecting login option");
try {
page.locator("#boxlogin div").nth(0).click();
if (page.url().equals(currentUrl))
Expand All @@ -117,30 +143,38 @@ private static void selectLoginOption(Playwright playwright, Page page) {
page.waitForLoadState(LoadState.DOMCONTENTLOADED);
waitForUrlChange(currentUrl, page);
} catch (TimeoutError e) {
LOGGER.error(() -> "Login option can't be selected");
throw new LoginOptionCantBeSelectedError(e.getMessage(), page.content());
}
LOGGER.info(() -> "Login option selected");
}

private static void connectToTheCrous(String email, String password, Playwright playwright, Page page) {
LOGGER.info(() -> "Connecting to the crous");
playwright.selectors().setTestIdAttribute("type");
String currentUrl = page.url();
try {
fillForm(email, password, page);
waitForPageLoad(page);
waitForUrlChange(currentUrl, page);
} catch (TimeoutError e) {
LOGGER.error(() -> "Can't connect to the crous");
throw new CannotBeConnectedError(e.getMessage(), page.content());
}
LOGGER.info(() -> "Connected to the crous");
}

private static void fillForm(String email, String password, Page page) {
LOGGER.info(() -> "Filling form");
var emailField = page.getByTestId("email");
emailField.hover();
emailField.click();
emailField.fill(email);
var passwordField = page.getByTestId("password");
passwordField.click();
passwordField.fill(password);
LOGGER.info(() -> "Form filled");
LOGGER.info(() -> "Submitting form");
passwordField.press("Enter");
}

Expand Down
38 changes: 33 additions & 5 deletions src/main/java/io/github/mathieusoysal/logement/data/DataSaver.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.time.DateTimeException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
Expand All @@ -12,15 +13,21 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.github.forax.beautifullogger.Logger;

import io.github.mathieusoysal.logement.pojo.Logement;

public class DataSaver {
private static final Logger LOGGER = Logger.getLogger();

public static File createArchiveFolder() {
LOGGER.info(() -> "getting archive folder");
File archiveFolder = new File("archive");
if (!archiveFolder.exists())
if (!archiveFolder.exists()) {
archiveFolder.mkdir();
LOGGER.info(() -> "Archive folder created");
}

return archiveFolder;
}

Expand All @@ -33,33 +40,54 @@ public static File createArchiveLogements(List<Logement> logements) throws JsonP
}

private static void writeLogementsDataInsideArchiveFile(String logementsJson, File archiveFile) {
LOGGER.info(() -> "Writing logements to file");
try (FileWriter fileWriter = new FileWriter(archiveFile)) {
fileWriter.write(logementsJson);
} catch (IOException e) {
LOGGER.error("Error while writing logements to file", e);
throw new RuntimeException("Error while writing logements to file", e);
}
LOGGER.info(() -> "Logements written to file");
}

private static File getArchiveFile(File archiveFolder) throws DateTimeException {
LOGGER.info(() -> "Getting archive file");
String archiveFileName = OffsetDateTime.now().toLocalTime().format(DateTimeFormatter.ofPattern("HH"));
Stream.of(archiveFolder.listFiles())
.filter(file -> file.getName().equals(archiveFileName))
.findFirst()
.ifPresent(File::delete);
return new File(archiveFolder, archiveFileName);
.ifPresent(file -> {
LOGGER.error(() -> "Archive file already exists");
try {
Files.delete(file.toPath());
} catch (IOException e) {
LOGGER.error("Error while deleting archive file", e);
e.printStackTrace();
}
LOGGER.info(() -> "Archive file deleted");
});
var archiveFile = new File(archiveFolder, archiveFileName);
LOGGER.info(() -> "Archive file got");
return archiveFile;
}

private static String convertLogementsToJson(List<Logement> logements) throws JsonProcessingException {
LOGGER.info(() -> "Converting logements to json");
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
return ow.writeValueAsString(logements);
var result = ow.writeValueAsString(logements);
LOGGER.info(() -> "Logements converted to json");
return result;
}

private static File getArchiveFolderForCurrentDate() {
LOGGER.info(() -> "Getting archive folder for current date");
File archiveFolder = createArchiveFolder();
String archiveFolderName = OffsetDateTime.now().toLocalDate().toString();
File archiveFile = new File(archiveFolder, archiveFolderName);
if (!archiveFile.exists())
if (!archiveFile.exists()) {
archiveFile.mkdir();
LOGGER.info(() -> "Archive folder for current date created");
}
return archiveFile;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.forax.beautifullogger.Logger;

import io.github.mathieusoysal.logement.Address;
import io.github.mathieusoysal.logement.BedKind;
Expand All @@ -16,24 +17,32 @@
import io.github.mathieusoysal.logement.TransportUnitOfMeasure;

public class Convertor {
private static final Logger LOGGER = Logger.getLogger();

private Convertor() {
}

static List<Item> getItemsFromJsonFile(File file) throws StreamReadException, DatabindException, IOException {
LOGGER.info(() -> "Reading json file for convertion to java object");
ObjectMapper objectMapper = new ObjectMapper();
Input results = objectMapper.readValue(file, Input.class);
LOGGER.info(() -> "Json file converted to java object");
return results.getResults().getItems();
}

static List<Item> getItemsFromJsonString(String json) throws StreamReadException, DatabindException, IOException {
LOGGER.info(() -> "Reading json string for convertion to java object");
ObjectMapper objectMapper = new ObjectMapper();
Input results = objectMapper.readValue(json, Input.class);
LOGGER.info(() -> "Json string converted to java object");
return results.getResults().getItems();
}

static List<Logement> convertItemsToLogements(List<Item> items) {
return items.stream().map(Convertor::convertItemToLogement).toList();
LOGGER.info(() -> "Converting items to logements");
var result = items.stream().map(Convertor::convertItemToLogement).toList();
LOGGER.info(() -> "Items converted to logements");
return result;
}

public static List<Logement> getLogementsFromBruteJsonFile(File file)
Expand Down

0 comments on commit 059a1b7

Please sign in to comment.