mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-10-30 00:23:54 +00:00 
			
		
		
		
	Custom client for UTBM UV API calls
This commit is contained in:
		| @@ -10,13 +10,13 @@ from ninja_extra.pagination import PageNumberPaginationExtra, PaginatedResponseS | ||||
| from core.auth.api_permissions import HasPerm | ||||
| from pedagogy.models import UV | ||||
| from pedagogy.schemas import SimpleUvSchema, UvFilterSchema, UvSchema | ||||
| from pedagogy.utbm_api import find_uv | ||||
| from pedagogy.utbm_api import UtbmApiClient | ||||
|  | ||||
|  | ||||
| @api_controller("/uv") | ||||
| class UvController(ControllerBase): | ||||
|     @route.get( | ||||
|         "/{year}/{code}", | ||||
|         "/{code}", | ||||
|         permissions=[ | ||||
|             # this route will almost always be called in the context | ||||
|             # of a UV creation/edition | ||||
| @@ -26,10 +26,14 @@ class UvController(ControllerBase): | ||||
|         response=UvSchema, | ||||
|     ) | ||||
|     def fetch_from_utbm_api( | ||||
|         self, year: Annotated[int, Ge(2010)], code: str, lang: Query[str] = "fr" | ||||
|         self, | ||||
|         code: str, | ||||
|         lang: Query[str] = "fr", | ||||
|         year: Query[Annotated[int, Ge(2010)] | None] = None, | ||||
|     ): | ||||
|         """Fetch UV data from the UTBM API and returns it after some parsing.""" | ||||
|         res = find_uv(lang, year, code) | ||||
|         with UtbmApiClient() as client: | ||||
|             res = client.find_uv(lang, code, year) | ||||
|         if res is None: | ||||
|             raise NotFound | ||||
|         return res | ||||
|   | ||||
| @@ -46,12 +46,7 @@ | ||||
|       const codeInput = document.querySelector('input[name="code"]') | ||||
|  | ||||
|       autofillBtn.addEventListener('click', () => { | ||||
|         const today = new Date() | ||||
|         let year = today.getFullYear() | ||||
|         if (today.getMonth() < 7) {  // student year starts in september | ||||
|           year-- | ||||
|         } | ||||
|         const url = `/api/uv/${year}/${codeInput.value}`; | ||||
|         const url = `/api/uv/${codeInput.value}`; | ||||
|         deleteQuickNotifs() | ||||
|  | ||||
|         $.ajax({ | ||||
|   | ||||
| @@ -2,24 +2,56 @@ | ||||
|  | ||||
| import requests | ||||
| from django.conf import settings | ||||
| from django.utils.functional import cached_property | ||||
|  | ||||
| from pedagogy.schemas import ShortUvList, UtbmFullUvSchema, UtbmShortUvSchema, UvSchema | ||||
|  | ||||
|  | ||||
| def find_uv(lang, year, code) -> UvSchema | None: | ||||
| class UtbmApiClient(requests.Session): | ||||
|     """A wrapper around `requests.Session` to perform requests to the UTBM UV API.""" | ||||
|  | ||||
|     BASE_URL = settings.SITH_PEDAGOGY_UTBM_API | ||||
|     _cache = {} | ||||
|  | ||||
|     @cached_property | ||||
|     def current_year(self) -> int: | ||||
|         """Fetch from the API the latest existing year""" | ||||
|         url = f"{self.BASE_URL}/guides/fr" | ||||
|         response = self.get(url) | ||||
|         return response.json()[-1]["annee"] | ||||
|  | ||||
|     def fetch_short_uvs( | ||||
|         self, lang: str = "fr", year: int | None = None | ||||
|     ) -> list[UtbmShortUvSchema]: | ||||
|         """Get the list of UVs in their short format from the UTBM API""" | ||||
|         if year is None: | ||||
|             year = self.current_year | ||||
|         if "short_uvs" not in self._cache: | ||||
|             self._cache["short_uvs"] = {} | ||||
|         if lang not in self._cache["short_uvs"]: | ||||
|             self._cache["short_uvs"][lang] = {} | ||||
|         if year not in self._cache["short_uvs"][lang]: | ||||
|             url = f"{self.BASE_URL}/uvs/{lang}/{year}" | ||||
|             response = self.get(url) | ||||
|             uvs = ShortUvList.validate_json(response.content) | ||||
|             self._cache["short_uvs"][lang][year] = uvs | ||||
|         return self._cache["short_uvs"][lang][year] | ||||
|  | ||||
|     def find_uv(self, lang: str, code: str, year: int | None = None) -> UvSchema | None: | ||||
|         """Find an UV from the UTBM API.""" | ||||
|         # query the UV list | ||||
|     base_url = settings.SITH_PEDAGOGY_UTBM_API | ||||
|     uvs_url = f"{base_url}/uvs/{lang}/{year}" | ||||
|     response = requests.get(uvs_url) | ||||
|     uvs: list[UtbmShortUvSchema] = ShortUvList.validate_json(response.content) | ||||
|  | ||||
|     short_uv = next((uv for uv in uvs if uv.code == code), None) | ||||
|         if not year: | ||||
|             year = self.current_year | ||||
|         # the UTBM API has no way to fetch a single short uv, | ||||
|         # and short uvs contain infos that we need and are not | ||||
|         # in the full uv schema, so we must fetch everything. | ||||
|         short_uvs = self.fetch_short_uvs(lang, year) | ||||
|         short_uv = next((uv for uv in short_uvs if uv.code == code), None) | ||||
|         if short_uv is None: | ||||
|             return None | ||||
|  | ||||
|         # get detailed information about the UV | ||||
|     uv_url = f"{base_url}/uv/{lang}/{year}/{code}/{short_uv.code_formation}" | ||||
|         uv_url = f"{self.BASE_URL}/uv/{lang}/{year}/{code}/{short_uv.code_formation}" | ||||
|         response = requests.get(uv_url) | ||||
|         full_uv = UtbmFullUvSchema.model_validate_json(response.content) | ||||
|         return make_clean_uv(short_uv, full_uv) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user