Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Ajout des universités prise en charge par ESUP Multi #324

Merged
merged 9 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Voici un aperçu de ce que nous avons accompli jusqu'à présent et de ce qu'il
- [x] 🟡 Skolengo
- [x] 🏫 Universités
- Limoges
- Lorraine
- Nîmes
- Polytechnique Hauts-de-France (UPHF)
- Rennes 1
- Rennes 2
Expand Down
Binary file added assets/images/service_ulorraine.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/service_unimes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 18 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"buffer": "^6.0.3",
"cal-parser": "^1.0.2",
"date-fns": "^3.6.0",
"esup-multi.js": "^1.0.1",
"expo": "^51.0.36",
"expo-asset": "^10.0.10",
"expo-auth-session": "~5.5.2",
Expand Down Expand Up @@ -92,7 +93,6 @@
"scolengo-api": "^3.0.5",
"text-encoding": "^0.7.0",
"turbawself": "^1.1.1",
"uphf-api": "^2.2.0",
"zustand": "^4.5.2"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion src/router/helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type pronote from "pawnote";
import type React from "react";
import type { School as SkolengoSchool} from "scolengo-api/types/models/School";
import {Information} from "@/services/shared/Information";
import { ImageSourcePropType } from "react-native";

export type RouteParameters = {
// welcome.index
Expand Down Expand Up @@ -51,11 +52,11 @@ export type RouteParameters = {

// login.identityProvider
IdentityProviderSelector: undefined;
Multi_Login: { instanceURL: string, title: string, image: ImageSourcePropType };
UnivRennes1_Login: undefined;
UnivRennes2_Login: undefined;
UnivLimoges_Login: undefined;
UnivSorbonneParisNord_login: undefined;
UnivUphf_Login: undefined;

// login.skolengo
SkolengoAuthenticationSelector: undefined;
Expand Down
6 changes: 3 additions & 3 deletions src/router/screens/login/identityProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UnivRennes1_Login from "@/views/login/IdentityProvider/providers/UnivRenn
import UnivLimoges_Login from "@/views/login/IdentityProvider/providers/UnivLimoges";
import UnivRennes2_Login from "@/views/login/IdentityProvider/providers/UnivRennes2";
import UnivSorbonneParisNord_login from "@/views/login/IdentityProvider/providers/UnivSorbonneParisNord";
import UnivUphf_Login from "@/views/login/IdentityProvider/providers/UnivUphf";
import Muli_Login from "@/views/login/IdentityProvider/providers/Multi";

export default [
createScreen("IdentityProviderSelector", IdentityProviderSelector, {
Expand Down Expand Up @@ -33,9 +33,9 @@ export default [
headerTitle: "Université Sorbonne Paris Nord",
}),

createScreen("UnivUphf_Login", UnivUphf_Login, {
createScreen("Multi_Login", Muli_Login, {
headerBackVisible: true,
headerTitle: "Université Polytechnique Hauts-de-France",
headerTitle: "ESUP Multi",
}),

] as const;
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { UphfAccount } from "@/stores/account/types";
import { MultiAccount } from "@/stores/account/types";
import { Information } from "../../shared/Information";
import { type ActualitiesResponse, UPHF } from "uphf-api";
import { AttachmentType } from "@/services/shared/Attachment";
import { ErrorServiceUnauthenticated } from "@/services/shared/errors";
import { ActualitiesResponse } from "esup-multi.js";

const parseInformation = (i: ActualitiesResponse): Information => ({
id: i.pubDate,
Expand All @@ -10,13 +11,16 @@ const parseInformation = (i: ActualitiesResponse): Information => ({
acknowledged: false,
attachments: [{"name": i.title,"type":"link" as AttachmentType, "url": i.link}],
content: i.content,
author: "UPHF Actualités",
author: "Actualités",
category: "Actualités",
read: false,
ref: i,
});

export const getNews = async (account: UphfAccount): Promise<Information[]> => {
const news = await UPHF.getActualities();
export const getNews = async (account: MultiAccount): Promise<Information[]> => {
if (!account.instance)
throw new ErrorServiceUnauthenticated("Multi");

const news = await account.instance.getActualities();
return news.map(parseInformation);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { UphfAccount } from "@/stores/account/types";
import type { MultiAccount } from "@/stores/account/types";
import type { Timetable, TimetableClass} from "../../shared/Timetable";
import { weekNumberToDateRange } from "@/utils/epochWeekNumber";
import type { EventResponse } from "uphf-api";
import type { EventResponse } from "esup-multi.js";
import { ErrorServiceUnauthenticated } from "@/services/shared/errors";

const decodeTimetableClass = (c: EventResponse): TimetableClass => ({
Expand All @@ -17,11 +17,11 @@ const decodeTimetableClass = (c: EventResponse): TimetableClass => ({
source: "UPHF",
});

export const getTimetableForWeek = async (account: UphfAccount, weekNumber: number): Promise<Timetable> => {
export const getTimetableForWeek = async (account: MultiAccount, weekNumber: number): Promise<Timetable> => {
if (!account.instance)
throw new ErrorServiceUnauthenticated("UPHF");
throw new ErrorServiceUnauthenticated("Multi");

const timetable = await account.instance.getSchedule({startDate: weekNumberToDateRange(weekNumber).start.toISOString().split("T")[0], endDate:weekNumberToDateRange(weekNumber).end.toISOString().split("T")[0]});
const timetable = await account.instance.getSchedules({startDate: weekNumberToDateRange(weekNumber).start.toISOString().split("T")[0], endDate:weekNumberToDateRange(weekNumber).end.toISOString().split("T")[0]});
const eventsList = timetable.plannings.flatMap((planning) =>
planning.events.map((event: EventResponse) => ({
id: event.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Personalization, UphfAccount } from "@/stores/account/types";
import type { MultiAccount, Personalization } from "@/stores/account/types";
import { defaultTabs } from "@/consts/DefaultTabs";
import type pronote from "pawnote";

Expand All @@ -10,14 +10,10 @@ const defaultUphfTabs = [
"News",
] as typeof defaultTabs[number]["tab"][];

const defaultPersonalization = async (instance: UphfAccount["instance"]): Promise<Partial<Personalization>> => {
const profilePictureAsBase64 = await instance?.getProfilePictureAsBase64();
const defaultPersonalization = async (instance: MultiAccount["instance"]): Promise<Partial<Personalization>> => {
return {
color: colors[0],
magicEnabled: true,
profilePictureB64: (profilePictureAsBase64 !== null && profilePictureAsBase64 != "")
? await profilePictureAsBase64
: void 0,
tabs: defaultTabs.filter(current => defaultUphfTabs.includes(current.tab)).map((tab, index) => ({
name: tab.tab,
enabled: index <= 4
Expand Down
15 changes: 15 additions & 0 deletions src/services/multi/reload-multi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { MultiAccount } from "@/stores/account/types";
import type { Reconnected } from "../reload-account";
import { authWithRefreshToken } from "esup-multi.js";

export const reloadInstance = async (authentication: MultiAccount["authentication"]): Promise<Reconnected<MultiAccount>> => {
const session = await authWithRefreshToken(authentication.instanceURL, { refreshAuthToken: authentication.refreshAuthToken });

return {
instance: session,
authentication: {
instanceURL: authentication.instanceURL,
refreshAuthToken: session.userData.refreshAuthToken || ""
}
};
};
6 changes: 3 additions & 3 deletions src/services/news.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export async function updateNewsInCache <T extends Account> (account: T): Promis
useNewsStore.getState().updateInformations(informations);
break;
}
case AccountService.UPHF: {
const { getNews } = await import("./uphf/data/news");
case AccountService.Multi: {
const { getNews } = await import("./multi/data/news");
const informations = await getNews(account);
useNewsStore.getState().updateInformations(informations);
break;
Expand All @@ -64,7 +64,7 @@ export async function setNewsRead <T extends Account> (account: T, message: Info
}
case AccountService.Local:
case AccountService.EcoleDirecte:
case AccountService.UPHF:
case AccountService.Multi:
break;
default: {
throw new Error("Service not implemented.");
Expand Down
4 changes: 2 additions & 2 deletions src/services/reload-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export async function reload <T extends Account> (account: T): Promise<Reconnect
const res = await reload(account);
return { instance: res.instance, authentication: res.authentication };
}
case AccountService.UPHF: {
const { reloadInstance } = await import("./uphf/reload-uphf");
case AccountService.Multi: {
const { reloadInstance } = await import("./multi/reload-multi");
return await reloadInstance(account.authentication) as Reconnected<T>;
}
default: {
Expand Down
2 changes: 1 addition & 1 deletion src/services/shared/errors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export class ErrorServiceUnauthenticated extends Error {
constructor (service: "pronote"|"ARD"|"turboself"|"skolengo"|"ecoledirecte"|"UPHF") {
constructor (service: "pronote"|"ARD"|"turboself"|"skolengo"|"ecoledirecte"|"Multi") {
super(`${service}: "account.instance" is not defined, you need to authenticate first.`);
this.name = "ErrorServiceUnauthenticated";
}
Expand Down
4 changes: 2 additions & 2 deletions src/services/timetable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export async function updateTimetableForWeekInCache <T extends Account> (account
useTimetableStore.getState().updateClasses(epochWeekNumber, timetable);
break;
}
case AccountService.UPHF: {
const { getTimetableForWeek } = await import("./uphf/data/timetable");
case AccountService.Multi: {
const { getTimetableForWeek } = await import("./multi/data/timetable");
const timetable = await getTimetableForWeek(account, epochWeekNumber);
useTimetableStore.getState().updateClasses(epochWeekNumber, timetable);
break;
Expand Down
14 changes: 0 additions & 14 deletions src/services/uphf/reload-uphf.ts

This file was deleted.

13 changes: 7 additions & 6 deletions src/stores/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Account as PawdirecteAccount, Session as PawdirecteSession } from
import type { Session as TSSession, Authentication as TSAuthentication } from "turbawself";
import type { Client as ARDClient } from "pawrd";
import type ScolengoAPI from "scolengo-api";
import type UphfAPI from "uphf-api";
import type MultiAPI from "esup-multi.js";
import { SkolengoAuthConfig } from "@/services/skolengo/skolengo-types";
import { User as ScolengoAPIUser } from "scolengo-api/types/models/Common";

Expand Down Expand Up @@ -75,7 +75,7 @@ export enum AccountService {
ARD,
Parcoursup,
Onisep,
UPHF
Multi
}

/**
Expand Down Expand Up @@ -134,10 +134,11 @@ export interface SkolengoAccount extends BaseAccount {
identityProvider?: undefined
}

export interface UphfAccount extends BaseAccount {
service: AccountService.UPHF
instance?: UphfAPI.UPHF
export interface MultiAccount extends BaseAccount {
service: AccountService.Multi
instance?: MultiAPI.Multi
authentication: {
instanceURL: string
refreshAuthToken: string
}
identityProvider?: undefined
Expand Down Expand Up @@ -181,7 +182,7 @@ export type PrimaryAccount = (
| PronoteAccount
| EcoleDirecteAccount
| SkolengoAccount
| UphfAccount
| MultiAccount
| LocalAccount
);
export type ExternalAccount = (
Expand Down
23 changes: 20 additions & 3 deletions src/views/login/IdentityProvider/IdentityProviderSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { memo, useEffect, useState } from "react";
import { Image, View, StyleSheet, Text } from "react-native";
import { Image, View, StyleSheet, Text, ImageSourcePropType } from "react-native";

import type { Screen } from "@/router/helpers/types";
import { ScrollView } from "react-native-gesture-handler";
Expand All @@ -8,12 +8,29 @@ import { Info } from "lucide-react-native";

const IdentityProviderSelector: Screen<"IdentityProviderSelector"> = ({ navigation }) => {
const universityProviders = [
{
name: "univ_lorraine",
title: "Université de Lorraine",
description: "Utilisez votre compte Sésame pour vous connecter",
image: require("@/../assets/images/service_ulorraine.png"),
instanceURL: "https://mobile-back.univ-lorraine.fr",
navigate: (instanceURL: string, title: string, image: ImageSourcePropType) => navigation.navigate("Multi_Login", { instanceURL, title, image }),
},
{
name: "univ_unimes",
title: "Université de Nîmes",
description: "Utilisez votre compte Sésame pour vous connecter",
image: require("@/../assets/images/service_unimes.png"),
instanceURL: "https://mobile-back.unimes.fr",
navigate: (instanceURL: string, title: string, image: ImageSourcePropType) => navigation.navigate("Multi_Login", { instanceURL, title, image }),
},
{
name: "univ_uphf",
title: "Université Polytechnique Hauts-de-France",
description: "Utilisez votre compte UPHF pour vous connecter",
image: require("@/../assets/images/service_uphf.png"),
navigate: () => navigation.navigate("UnivUphf_Login"),
instanceURL: "https://appmob.uphf.fr/backend",
navigate: (instanceURL: string, title: string, image: ImageSourcePropType) => navigation.navigate("Multi_Login", { instanceURL, title, image }),
},
];

Expand Down Expand Up @@ -59,7 +76,7 @@ const IdentityProviderSelector: Screen<"IdentityProviderSelector"> = ({ navigati
{universityProviders.map((identityProvider) => (
<NativeItem
key={identityProvider.name}
onPress={() => identityProvider.navigate()}
onPress={() => identityProvider.navigate(identityProvider.instanceURL, identityProvider.title, identityProvider.image)}
leading={<Image source={identityProvider.image} style={{ width: 40, height: 40, borderRadius: 10 }} />}
>
<NativeText variant="title">{identityProvider.title}</NativeText>
Expand Down
Loading
Loading