mirror of
https://github.com/dd060606/WebAurion-API.git
synced 2026-01-18 16:47:26 +01:00
Gestion de la session + En cours: Emploi du temps
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -128,3 +128,5 @@ dist
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
.env
|
||||
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 4
|
||||
}
|
||||
12
jest.config.ts
Normal file
12
jest.config.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { Config } from "jest";
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
|
||||
dotenv.config({ path: path.resolve(__dirname, "./.env") });
|
||||
const config: Config = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
testMatch: ["**/tests/**/*.test.ts"],
|
||||
};
|
||||
|
||||
export default config;
|
||||
4088
package-lock.json
generated
Normal file
4088
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "webaurion-api",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"lint": "eslint src --ext .ts"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"cheerio": "^1.0.0",
|
||||
"dotenv": "^16.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
||||
89
src/api/ScheduleApi.ts
Normal file
89
src/api/ScheduleApi.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { getJSONSchedule, getViewState } from "../utils/AurionUtils";
|
||||
import Session from "./Session";
|
||||
|
||||
class ScheduleApi {
|
||||
private session: Session;
|
||||
constructor(session: Session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public fetchSchedule(): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
try {
|
||||
const schedulePage = await this.session.sendGET<string>(
|
||||
"/faces/Planning.xhtml",
|
||||
);
|
||||
let viewState = getViewState(schedulePage);
|
||||
if (viewState) {
|
||||
const params = new URLSearchParams();
|
||||
// On ajoute les paramètres nécessaires pour effectuer une requête POST
|
||||
params.append("javax.faces.partial.ajax", "true");
|
||||
params.append("javax.faces.source", "form:j_idt46");
|
||||
params.append(
|
||||
"javax.faces.partial.execute",
|
||||
"form:j_idt46",
|
||||
);
|
||||
params.append("javax.faces.partial.render", "form:sidebar");
|
||||
params.append("form:j_idt46", "form:j_idt46");
|
||||
params.append(
|
||||
"webscolaapp.Sidebar.ID_SUBMENU",
|
||||
"submenu_291906",
|
||||
);
|
||||
params.append("form", "form");
|
||||
params.append("javax.faces.ViewState", viewState);
|
||||
const response = await this.session.sendPOST<string>(
|
||||
"faces/Planning.xhtml",
|
||||
params,
|
||||
);
|
||||
|
||||
const params2 = new URLSearchParams();
|
||||
// On ajoute les paramètres nécessaires pour effectuer une requête POST
|
||||
params2.append("form", "form");
|
||||
params2.append("javax.faces.ViewState", viewState);
|
||||
params2.append("form:sidebar", "form:sidebar");
|
||||
params2.append("form:sidebar_menuid", "1_4");
|
||||
const response2 = await this.session.sendPOST<string>(
|
||||
"faces/Planning.xhtml",
|
||||
params2,
|
||||
);
|
||||
viewState = getViewState(response2);
|
||||
if (!viewState) {
|
||||
return reject(new Error("Viewstate not found"));
|
||||
}
|
||||
const params3 = new URLSearchParams();
|
||||
params3.append("javax.faces.partial.ajax", "true");
|
||||
params3.append("javax.faces.source", "form:j_idt118");
|
||||
params3.append(
|
||||
"javax.faces.partial.execute",
|
||||
"form:j_idt118",
|
||||
);
|
||||
params3.append(
|
||||
"javax.faces.partial.render",
|
||||
"form:j_idt118",
|
||||
);
|
||||
params3.append("form:j_idt118", "form:j_idt118");
|
||||
params3.append("form:j_idt118_start", "1731279600000");
|
||||
params3.append("form:j_idt118_end", "1731798000000");
|
||||
params3.append("form", "form");
|
||||
params3.append(
|
||||
"form:idInit",
|
||||
"webscolaapp.Planning_-6802915683822110557",
|
||||
);
|
||||
params3.append("javax.faces.ViewState", viewState);
|
||||
const response3 = await this.session.sendPOST<string>(
|
||||
"faces/Planning.xhtml",
|
||||
params3,
|
||||
);
|
||||
console.log(getJSONSchedule(response3));
|
||||
resolve(response2);
|
||||
} else {
|
||||
reject(new Error("Viewstate not found"));
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ScheduleApi;
|
||||
77
src/api/Session.ts
Normal file
77
src/api/Session.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import ScheduleApi from "./ScheduleApi";
|
||||
|
||||
class Session {
|
||||
private client: AxiosInstance;
|
||||
|
||||
constructor(baseURL: string, token: string) {
|
||||
this.client = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Cookie: `JSESSIONID=${token}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// API pour le calendrier
|
||||
public getScheduleApi(): ScheduleApi {
|
||||
return new ScheduleApi(this);
|
||||
}
|
||||
|
||||
public sendGET<T>(url: string): Promise<T> {
|
||||
return this.client.get<T>(url).then((response) => response.data);
|
||||
}
|
||||
|
||||
public sendPOST<T>(url: string, data: unknown): Promise<T> {
|
||||
return this.client.post<T>(url, data).then((response) => response.data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentifie un utilisateur avec un nom d'utilisateur et un mot de passe.
|
||||
*
|
||||
* @param {string} username - Le nom d'utilisateur de l'utilisateur.
|
||||
* @param {string} password - Le mot de passe de l'utilisateur.
|
||||
* @returns {Promise<Session>} Une promesse qui se résout avec une instance de Session si l'authentification réussit.
|
||||
* @throws {Error} Si l'authentification échoue.
|
||||
*/
|
||||
export function login(username: string, password: string): Promise<Session> {
|
||||
const baseURL = "https://web.isen-ouest.fr/webAurion";
|
||||
return new Promise<Session>((resolve, reject) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append("username", username);
|
||||
params.append("password", password);
|
||||
axios
|
||||
.post(`${baseURL}/login`, params, {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
maxRedirects: 0,
|
||||
})
|
||||
.then((response) => {
|
||||
//Si la réponse est 302 et que le cookie est défini alors on retourne une nouvelle session
|
||||
if (response.status === 302 && response.headers["set-cookie"]) {
|
||||
const token = response.headers["set-cookie"][0]
|
||||
.split(";")[0]
|
||||
.split("=")[1];
|
||||
resolve(new Session(baseURL, token));
|
||||
} else {
|
||||
reject(new Error("Login failed."));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
//Si la réponse est 302 et que le cookie est défini alors on retourne une nouvelle session
|
||||
if (err.response && err.response.status === 302) {
|
||||
const token = err.response.headers["set-cookie"][0]
|
||||
.split(";")[0]
|
||||
.split("=")[1];
|
||||
resolve(new Session(baseURL, token));
|
||||
} else {
|
||||
reject(new Error("Login failed."));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default Session;
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Session } from "./api/Session";
|
||||
24
src/utils/AurionUtils.ts
Normal file
24
src/utils/AurionUtils.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { load } from "cheerio";
|
||||
|
||||
// Extraction du ViewState de la page HTML (obligatoire pour effectuer une requête)
|
||||
export function getViewState(html: string): string | undefined {
|
||||
const parser = load(html);
|
||||
//On recherche l'élément input avec l'attribut name="javax.faces.ViewState"
|
||||
const inputElement = parser('input[name="javax.faces.ViewState"]');
|
||||
|
||||
if (inputElement.length > 0) {
|
||||
//On récupère la valeur de l'attribut value
|
||||
const viewState = inputElement.attr("value");
|
||||
return viewState;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Conversion du calendrier au format JSON
|
||||
export function getJSONSchedule(xml: string): object {
|
||||
const parser = load(xml, {
|
||||
xmlMode: true,
|
||||
});
|
||||
const json = parser('update[id="form:j_idt118"]').text();
|
||||
return JSON.parse(json)["events"];
|
||||
}
|
||||
0
src/utils/types.ts
Normal file
0
src/utils/types.ts
Normal file
15
tests/ScheduleApi.test.ts
Normal file
15
tests/ScheduleApi.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { login } from "../src/api/Session";
|
||||
describe("ScheduleApi", () => {
|
||||
it("should receive a schedule", async () => {
|
||||
const username = process.env.TEST_USERNAME;
|
||||
const password = process.env.TEST_PASSWORD;
|
||||
if (!username || !password) {
|
||||
throw new Error(
|
||||
"TEST_USERNAME or TEST_PASSWORD is not set in environment variables.",
|
||||
);
|
||||
}
|
||||
|
||||
const session = await login(username, password);
|
||||
await session.getScheduleApi().fetchSchedule();
|
||||
});
|
||||
});
|
||||
15
tests/Session.test.ts
Normal file
15
tests/Session.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { login } from "../src/api/Session";
|
||||
describe("AuthApi", () => {
|
||||
it("should log in a user and receive a session", async () => {
|
||||
const username = process.env.TEST_USERNAME;
|
||||
const password = process.env.TEST_PASSWORD;
|
||||
if (!username || !password) {
|
||||
throw new Error(
|
||||
"TEST_USERNAME or TEST_PASSWORD is not set in environment variables.",
|
||||
);
|
||||
}
|
||||
|
||||
const result = await login(username, password);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "tests"]
|
||||
}
|
||||
Reference in New Issue
Block a user