Skip to content

Commit

Permalink
♻️: add one service for each feature (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
julesartd authored Apr 15, 2024
1 parent 5d79158 commit 8fdb943
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 81 deletions.
2 changes: 1 addition & 1 deletion backend/.php-cs-fixer.cache

Large diffs are not rendered by default.

56 changes: 35 additions & 21 deletions backend/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,41 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
app.schedule_url: '%env(APP_3IL_SCHEDULE_URL)%'
app.schedule_url: '%env(APP_3IL_SCHEDULE_URL)%'
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'

# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\Service\Scrapper\ClassesScraperService:
arguments:
$schedule_url: '%app.schedule_url%'
App\Service\TimetableService:
arguments:
$schedule_url: '%app.schedule_url%'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\Service\Scrapper\ClassesScraperService:
arguments:
$schedule_url: '%app.schedule_url%'

App\Service\TimetableService:
arguments:
$schedule_url: '%app.schedule_url%'

App\Service\Scrapper\StudentSpaceScrapperService:
arguments:
$url: '%env(APP_3IL_LOGIN_URL)%'

App\Service\StudentService:
arguments:
$marksSheetUrl: '%env(APP_3IL_MARKS_SHEET_URL)%'
$absencesSheetUrl: '%env(APP_3IL_ABSENCES_SHEET_URL)%'

App\Service\LoginService:
arguments:
$loginUrl: '%env(APP_3IL_POST_LOGIN_URL)%'
53 changes: 53 additions & 0 deletions backend/src/Controller/Api/LoginController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Controller\Api;

use App\Service\Scrapper\StudentSpaceScrapperService;
use App\Service\LoginService;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;

class LoginController extends AbstractController
{
private StudentSpaceScrapperService $studentScrapper;
private LoginService $loginService;

public function __construct(StudentSpaceScrapperService $studentScrapper, LoginService $loginService)
{
$this->studentScrapper = $studentScrapper;
$this->loginService = $loginService;
}

/**
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws GuzzleException
* @throws ClientExceptionInterface
*/
#[Route('/api/login', name: 'app_api_student_login')]
public function login(Request $request): Response
{
$username = $request->get('username');
$password = $request->get('password');

if (null === $username || null === $password) {
return $this->json(['message' => 'Veuillez renseigner un nom d\'utilisateur et un mot de passe'], 400);
}

$htmlContent = $this->studentScrapper->getLoginToken();
$cookieJar = $this->studentScrapper->getCookies();
$login = $this->loginService->login($username, $password, $htmlContent, $cookieJar);

if (false === $login) {
return $this->json(['message' => 'Erreur de connexion'], 401);
} else {
return $this->json(['message' => 'Connexion réussie', 'studentId' => $login], 200);
}
}
}
50 changes: 50 additions & 0 deletions backend/src/Controller/Api/StudentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Controller\Api;

use App\Service\StudentService;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class StudentController extends AbstractController
{
private StudentService $studentService;

public function __construct(StudentService $studentService)
{
$this->studentService = $studentService;
}

/**
* @throws GuzzleException
*/
#[Route('/api/student/marks/{studentId}', name: 'app_api_student_rating')]
public function getMarks(int $studentId): Response
{
$pdfContent = $this->studentService->marksSheet($studentId);
if (!$pdfContent) {
return $this->json(['message' => 'Erreur de récupération du PDF'], 500);
} else {
return new Response($pdfContent, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="releve.pdf"',
]);
}
}

#[Route('/api/student/absences/{studentId}', name: 'app_api_student_absence')]
public function getAbsence(int $studentId): Response
{
$pdfContent = $this->studentService->absencesSheet($studentId);
if (!$pdfContent) {
return $this->json(['message' => 'Erreur de récupération du PDF'], 500);
} else {
return new Response($pdfContent, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="releve.pdf"',
]);
}
}
}
48 changes: 0 additions & 48 deletions backend/src/Controller/Api/StudentLoginController.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@

use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;

class StudentLoginService
class LoginService
{
private string $loginUrl;

public function __construct(string $loginUrl)
{
$this->loginUrl = $loginUrl;
}

/**
* @throws GuzzleException
*/
public function login(string $username, string $password, string $token, CookieJar $cookieJar): int|bool|null
{
$client = new Client(['cookies' => $cookieJar, 'allow_redirects' => true]);
$response = $client->request('POST', 'https://eleves.groupe3il.fr/index.php/component/users/?task=user.login&Itemid=435', [
$response = $client->request('POST', $this->loginUrl, [
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
],
Expand All @@ -25,6 +36,7 @@ public function login(string $username, string $password, string $token, CookieJ

$htmlContent = $response->getBody()->getContents();

# check if user logged in
if (str_contains($htmlContent, 'Voici la liste des relevés disponibles')) {
$pattern = '/\[NoteEleveId\] => (\d+)/';
preg_match($pattern, $htmlContent, $matches);
Expand Down
17 changes: 8 additions & 9 deletions backend/src/Service/Scrapper/StudentSpaceScrapperService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
Expand All @@ -20,10 +21,9 @@ public function __construct(string $url)
}

/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
* @throws ClientExceptionInterface|GuzzleException
*/
private function getHtmlContent(): string
{
Expand Down Expand Up @@ -52,20 +52,19 @@ private function parseLoginToken(string $htmlContent): string
return '';
}

/**
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws GuzzleException
* @throws ClientExceptionInterface
*/
public function getLoginToken(): string
{
$htmlContent = $this->getHtmlContent();

return $this->parseLoginToken($htmlContent);
}

public function getMarksPDF(int $studentId): string
{
$client = new Client();
$response = $client->request('GET', 'https://eleves.groupe3il.fr/pdf/'.$studentId.'_2024_RN.pdf');

return $response->getBody()->getContents();
}

public function getCookies(): CookieJar
{
Expand Down
43 changes: 43 additions & 0 deletions backend/src/Service/StudentService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Service;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class StudentService
{

private string $marksSheetUrl;
private string $absencesSheetUrl;

public function __construct(string $marksSheetUrl, string $absencesSheetUrl)
{
$this->marksSheetUrl = $marksSheetUrl;
$this->absencesSheetUrl = $absencesSheetUrl;
}

/**
* @throws GuzzleException
*/
public function marksSheet(int $studentId): string
{
$client = new Client();
$url = str_replace('{studentId}', $studentId, $this->marksSheetUrl);
$response = $client->request('GET', $url);

return $response->getBody()->getContents();
}

/**
* @throws GuzzleException
*/
public function absencesSheet(int $studentId): string
{
$client = new Client();
$url = str_replace('{studentId}', $studentId, $this->absencesSheetUrl);
$response = $client->request('GET', $url);

return $response->getBody()->getContents();
}
}

0 comments on commit 8fdb943

Please sign in to comment.