diff --git a/firka/lib/api/client/kreta_client.dart b/firka/lib/api/client/kreta_client.dart index dc288cb..0da86d7 100644 --- a/firka/lib/api/client/kreta_client.dart +++ b/firka/lib/api/client/kreta_client.dart @@ -3,11 +3,11 @@ import 'dart:convert'; import 'dart:math'; import 'package:dio/dio.dart'; +import 'package:firka/core/extensions.dart'; import 'package:firka/data/models/generic_cache_model.dart'; import 'package:firka/data/models/timetable_cache_model.dart'; -import 'package:intl/intl.dart'; import 'package:isar_community/isar.dart'; -import 'package:kreta_api/kreta_api.dart' hide KretaEndpoints; +import 'package:kreta_api/kreta_api.dart'; import 'package:firka/app/app_state.dart'; import 'package:firka/core/bloc/reauth_cubit.dart'; @@ -46,6 +46,13 @@ class KretaClient { Future _setReauthFlag() async { if (needsReauth) return; + if (Platform.isIOS) { + try { + _watchChannel.invokeMethod('notifyReauthRequired'); + } catch (e) { + debugPrint('[KretaClient] Watch reauth notification skipped: $e'); + } + } _reauthCubit.setNeedsReauth(true); debugPrint('[KretaClient] Reauth flag set'); } @@ -405,94 +412,136 @@ class KretaClient { return (resp.data, resp.statusCode!); } - Future<(dynamic, int, Object?, bool)> _cachingGet( + Future>> _timetableCachingGet( + DateTime weekday, + bool forceCache, + ) async { + var from = weekday.getMonday(); + return await _cachingGet( + genCacheKey(from, model.studentIdNorm!), + KretaEndpoints.getTimeTable( + model.iss!, + from, + from.add(Duration(days: 6)), + ), + forceCache, + 0, + isar.timetableCacheModels, + (key, resp) => TimetableCacheModel() + ..cacheKey = key + ..values = (resp as List) + .map((item) => jsonEncode(item)) + .toList(), + (cache) => cache.values + .map((data) => Lesson.fromJson(jsonDecode(data))) + .toList(), + ); + } + + Future>> _genericListedCachingGet( CacheId id, String url, bool forceCache, - int counter, + R Function(dynamic) mapResultEntries, ) async { - // it would be *ideal* to use xor and left shift here, however - // binary operations seem to round the number down to - // 32 bits for some reason??? - var cacheKey = model.studentIdNorm! + ((id.index + 1) * pow(10, 11)); - var cache = await isar.genericCacheModels.get(cacheKey as int); + return await _genericCachingGet( + id, + url, + forceCache, + (data) => (data as List).map(mapResultEntries).toList(), + ); + } + + Future> _genericCachingGet( + CacheId id, + String url, + bool forceCache, + R Function(dynamic) makeResult, + ) async { + return await _cachingGet( + // it would be *ideal* to use xor and left shift here, however + // binary operations seem to round the number down to + // 32 bits for some reason??? + (model.studentIdNorm! + ((id.index + 1) * pow(10, 11))) as Id, + url, + forceCache, + 0, + isar.genericCacheModels, + (key, resp) => GenericCacheModel() + ..cacheKey = key + ..cacheData = jsonEncode(resp), + (cache) { + return makeResult(jsonDecode(cache.cacheData!)); + }, + ); + } + + Future> _cachingGet( + Id cacheKey, + String url, + bool forceCache, + int counter, + IsarCollection collection, + T Function(Id, dynamic) makeCache, + R Function(T) makeResult, + ) async { + var cache = await collection.get(cacheKey); + + if (forceCache && cache != null) { + logger.finest( + "_cachingGet(forceCache: $forceCache}): decoding cached response for: $url", + ); + return ApiResponse.cached(makeResult(cache)); + } - dynamic resp; - int statusCode; try { - if (forceCache && cache != null) { - logger.finest( - "_cachingGet(forceCache: $forceCache}): decoding cached response for: $url", - ); - return (jsonDecode(cache.cacheData!), 200, null, true); + var (resp, statusCode) = await _authJson("GET", url); + + if (statusCode >= 400 && cache != null) { + logger.finest("request failed: $statusCode, using cache for: $url"); + return ApiResponse(makeResult(cache), statusCode, null, true); } - try { - (resp, statusCode) = await _authJson("GET", url); + var newCache = makeCache(cacheKey, resp); - if (statusCode >= 400) { - if (cache != null) { - logger.finest( - "_cachingGet(forceCache: $forceCache}): decoding uncached response for: $url", - ); - return (jsonDecode(cache.cacheData!), statusCode, null, true); - } - } - } catch (ex) { - if (ex is Error) { - logger.finest( - "Request failed for $url", - ex.toString(), - ex.stackTrace, - ); - } else { - logger.finest("Request failed for $url", ex.toString()); - } + await isar.writeTxn(() async { + collection.put(newCache); + }); + + return ApiResponse(makeResult(newCache), statusCode, null, false); + } catch (ex) { + if (_isTokenExpired(ex)) { + logger.warning("Token expired, setting needsReauth flag"); + await _setReauthFlag(); + + return ApiResponse(null, 0, ex, false); + } + + if (ex is DioException && counter < backoffCount) { logger.finest("Retrying: $counter / $backoffCount"); - if (_isTokenExpired(ex) || - ex is! DioException || - counter >= backoffCount) { - rethrow; - } - final backoffDelay = backoffMin + (counter * backoffStep); logger.finest("Waiting: $backoffDelay"); await Future.delayed(Duration(milliseconds: backoffDelay)); - return _cachingGet(id, url, forceCache, counter + 1); - } - } catch (ex) { - if (_isTokenExpired(ex)) { - await _setReauthFlag(); - logger.warning("Token expired, setting needsReauth flag"); - - if (Platform.isIOS && needsReauth) { - try { - _watchChannel.invokeMethod('notifyReauthRequired'); - } catch (e) { - debugPrint('[KretaClient] Watch reauth notification skipped: $e'); - } - } + return _cachingGet( + cacheKey, + url, + forceCache, + counter + 1, + collection, + makeCache, + makeResult, + ); } if (cache != null) { logger.finest("request failed, using cache for: $url"); - return (jsonDecode(cache.cacheData!), 0, ex, true); - } else { - logger.finest("request failed, no cache for: $url"); - return (null, 0, ex, false); + return ApiResponse(makeResult(cache), 0, ex, true); } + + logger.finest("request failed, no cache for: $url"); + return ApiResponse(null, 0, ex, false); } - - await isar.writeTxn(() async { - var cache = GenericCacheModel(); - cache.cacheKey = cacheKey; - cache.cacheData = jsonEncode(resp); - - isar.genericCacheModels.put(cache); - }); - - return (resp, statusCode, null, false); } ApiResponse>? classGroupAveragesCache; @@ -501,9 +550,8 @@ class KretaClient { ClassGroup classGroup, { bool forceCache = true, }) async { - String? err; if (classGroup.studyTask == null) { - err = "classGroup.studyTask is null"; + String? err = "classGroup.studyTask is null"; logger.warning(err); return ApiResponse([], 0, err, false); } @@ -513,31 +561,17 @@ class KretaClient { return classGroupAveragesCache!; } var studyTaskUid = classGroup.studyTask!.uid.toString().split(",").first; - var (resp, status, ex, cached) = await _cachingGet( + var resp = await _genericListedCachingGet( CacheId.getClassGroupAvg, KretaEndpoints.getClassGroupAvg(model.iss!, studyTaskUid), forceCache, - 0, + (item) => ClassGroupSubjectAverage.fromJson(item), ); - var items = List.empty(growable: true); - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(ClassGroupSubjectAverage.fromJson(item)); - } - } catch (ex) { - err = ex.toString(); + if (resp.err == null) { + classGroupAveragesCache = ApiResponse.cached(resp.response); } - - if (ex != null) { - err = ex.toString(); - } - - if (ex == null) { - classGroupAveragesCache = ApiResponse(items, 200, null, true); - } - return ApiResponse(items, status, err, cached); + return resp; } ApiResponse? studentCache; @@ -548,28 +582,18 @@ class KretaClient { } else if (studentCache != null) { return studentCache!; } - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericCachingGet( CacheId.getStudent, KretaEndpoints.getStudentUrl(model.iss!), forceCache, - 0, - ); - - Student? student; - String? err; - try { - student = Student.fromJson(resp); - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - if (ex == null) studentCache = ApiResponse(student, 200, null, true); - - return ApiResponse(student, status, err, cached); + (cache) => Student.fromJson(cache), + ).then((resp) { + if (resp.err == null) { + studentCache = ApiResponse.cached(resp.response); + } + return resp; + }); } ApiResponse>? classGroupCache; @@ -582,31 +606,18 @@ class KretaClient { } else { if (classGroupCache != null) return classGroupCache!; } - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericListedCachingGet( CacheId.getClassGroup, KretaEndpoints.getClassGroups(model.iss!), forceCache, - 0, - ); - - final classGroups = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - classGroups.add(ClassGroup.fromJson(item)); + (item) => ClassGroup.fromJson(item), + ).then((resp) { + if (resp.err == null) { + classGroupCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - if (ex == null) classGroupCache = ApiResponse(classGroups, 200, null, true); - - return ApiResponse(classGroups, status, err, cached); + return resp; + }); } ApiResponse>? noticeBoardCache; @@ -619,64 +630,40 @@ class KretaClient { } else if (noticeBoardCache != null) { return noticeBoardCache!; } - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericListedCachingGet( CacheId.getNoticeBoard, KretaEndpoints.getNoticeBoard(model.iss!), forceCache, - 0, - ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(NoticeBoardItem.fromJson(item)); + (item) => NoticeBoardItem.fromJson(item), + ).then((resp) { + if (resp.err == null) { + noticeBoardCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - if (err == null) noticeBoardCache = ApiResponse(items, 200, null, true); - - return ApiResponse(items, status, err, cached); + return resp; + }); } ApiResponse>? infoBoardCache; Future>> getInfoBoard({ + DateTime? from, + DateTime? to, bool forceCache = true, }) async { if (forceCache && infoBoardCache != null) return infoBoardCache!; - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericListedCachingGet( CacheId.getInfoBoard, - KretaEndpoints.getInfoBoard(model.iss!), + KretaEndpoints.getInfoBoard(model.iss!, from, to), forceCache, - 0, - ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(InfoBoardItem.fromJson(item)); + (item) => InfoBoardItem.fromJson(item), + ).then((resp) { + if (resp.err == null) { + infoBoardCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - if (err == null) infoBoardCache = ApiResponse(items, 200, null, true); - - return ApiResponse(items, status, err, cached); + return resp; + }); } ApiResponse>? gradeCache; @@ -687,33 +674,19 @@ class KretaClient { } else if (gradeCache != null) { return gradeCache!; } - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericListedCachingGet( CacheId.getGrades, KretaEndpoints.getGrades(model.iss!), forceCache, - 0, - ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(Grade.fromJson(item)); + (item) => Grade.fromJson(item), + ).then((resp) { + if (resp.err == null) { + resp.response!.sort((a, b) => b.recordDate.compareTo(a.recordDate)); + gradeCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - items.sort((a, b) => b.recordDate.compareTo(a.recordDate)); - - if (ex == null) gradeCache = ApiResponse(items, 200, null, true); - - return ApiResponse(items, status, err, cached); + return resp; + }); } ApiResponse>? subjectAverageCache; @@ -739,224 +712,36 @@ class KretaClient { return subjectAverageCache!; } var studyTaskUid = classGroup.studyTask!.uid.toString().split(",").first; - var (resp, status, ex, cached) = await _cachingGet( + + return await _genericListedCachingGet( CacheId.getSubjectAvg, KretaEndpoints.getSubjectAvg(model.iss!, studyTaskUid), forceCache, - 0, - ); - - var items = List.empty(growable: true); - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(SubjectAverage.fromJson(item)); + (item) => SubjectAverage.fromJson(item), + ).then((resp) { + if (resp.err == null) { + subjectAverageCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - if (ex == null) subjectAverageCache = ApiResponse(items, 200, null, true); - return ApiResponse(items, status, err, cached); - } - - Future<(List, int, Object?, bool)> - _timedCachingGet( - IsarCollection cacheModel, - String endpoint, - DateTime from, - DateTime? to, - bool forceCache, - int counter, - Future Function(dynamic, int) storeCache, - ) async { - var cacheKey = genCacheKey(from, model.studentIdNorm!); - var cache = await cacheModel.get(cacheKey); - var formatter = DateFormat('yyyy-MM-dd'); - var fromStr = formatter.format(from); - var toStr = to != null ? formatter.format(to) : null; - var now = timeNow(); - - if (cache != null && (cache as dynamic).values == null) { - (cache as dynamic).values = List.empty(growable: true); - } - - List resp; - int statusCode; - try { - if (forceCache && cache != null) { - var items = List.empty(growable: true); - for (var item in (cache as dynamic).values) { - items.add(jsonDecode(item)); - } - - return (items, 200, null, true); - } - try { - if (toStr == null) { - (resp, statusCode) = await _authJson( - "GET", - "$endpoint?" - "datumTol=$fromStr", - ); - } else { - (resp, statusCode) = await _authJson( - "GET", - "$endpoint?" - "datumTol=$fromStr&datumIg=$toStr", - ); - } - - if (statusCode >= 400) { - if (cache != null) { - var items = List.empty(growable: true); - for (var item in (cache as dynamic).values) { - items.add(jsonDecode(item)); - } - return (items, statusCode, null, true); - } - } - } catch (ex) { - if (_isTokenExpired(ex) || - ex is! DioException || - counter >= backoffCount) { - rethrow; - } - - await Future.delayed( - Duration(milliseconds: backoffMin + (counter * backoffStep)), - ); - - return _timedCachingGet( - cacheModel, - endpoint, - from, - to, - forceCache, - counter + 1, - storeCache, - ); - } - } catch (ex) { - if (_isTokenExpired(ex)) { - await _setReauthFlag(); - logger.warning( - "Token expired in timed request, setting needsReauth flag", - ); - } - - if (cache != null) { - var items = List.empty(growable: true); - for (var item in (cache as dynamic).values) { - items.add(jsonDecode(item)); - } - return (items, 0, ex, true); - } else { - return (List.empty(growable: true), 0, ex, false); - } - } - - // only cache stuff 4 months ago and a month in advance - if (from.millisecondsSinceEpoch >= - now.subtract(Duration(days: 120)).millisecondsSinceEpoch) { - if (to == null || - to.millisecondsSinceEpoch <= - now.add(Duration(days: 31)).millisecondsSinceEpoch) { - await isar.writeTxn(() async { - await storeCache(resp, cacheKey); - }); - } - } - - return (resp, statusCode, null, false); - } - - /// Expects from and to to be 7 days apart - Future>> _getTimeTable( - DateTime from, - DateTime to, - bool forceCache, - ) async { - var ( - resp, - status, - ex, - cached, - ) = await _timedCachingGet( - isar.timetableCacheModels, - KretaEndpoints.getTimeTable(model.iss!), - from, - to, - forceCache, - 0, - (dynamic resp, int cacheKey) async { - TimetableCacheModel cache = TimetableCacheModel(); - var rawClasses = List.empty(growable: true); - - for (var obj in resp) { - rawClasses.add(jsonEncode(obj)); - } - - cache.cacheKey = cacheKey; - cache.values = rawClasses; - - await isar.timetableCacheModels.put(cache as dynamic); - }, - ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(Lesson.fromJson(item)); - } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - return ApiResponse(items, status, err, cached); + return resp; + }); } Future>> getHomework({ + DateTime? from, + DateTime? to, bool forceCache = true, }) async { - final now = timeNow().subtract(Duration(days: 365)); - var formatter = DateFormat('yyyy-MM-dd'); - var start = formatter.format(now); - var (resp, status, ex, cached) = await _cachingGet( + if (from == null && to == null) { + DateTime now = timeNow(); + DateTime start = now.copyWith(month: 9, day: 1); + from = now.isBefore(start) ? start.subtract(Duration(days: 365)) : start; + } + return await _genericListedCachingGet( CacheId.getHomework, - "${KretaEndpoints.getHomework(model.iss!)}?datumTol=$start", + KretaEndpoints.getHomework(model.iss!, from, to), forceCache, - 0, + (item) => Homework.fromJson(item), ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(Homework.fromJson(item)); - } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - // items.sort((a, b) => a.date.compareTo(b.date)); - - return ApiResponse(items, status, err, cached); } /// Automatically aligns requests to start at Monday and end at Sunday @@ -974,30 +759,25 @@ class KretaClient { i < to.millisecondsSinceEpoch; i += 604800000 ) { - var from = DateTime.fromMillisecondsSinceEpoch(i); - var start = from.subtract(Duration(days: from.weekday - 1)); - var end = start.add(Duration(days: 6)); + var weekday = DateTime.fromMillisecondsSinceEpoch(i); - var resp = await _getTimeTable(start, end, forceCache); + var resp = await _timetableCachingGet(weekday, forceCache); if (resp.err != null) { - err = resp.err; - if (!resp.cached) { - return resp; - } else { - lessons.addAll(resp.response!); - } - } else { - lessons.addAll(resp.response!); + return resp; } + + lessons.addAll(resp.response!); + if (!resp.cached) cached = false; } - lessons.sort((a, b) => a.start.compareTo(b.start)); - lessons = lessons - .where( - (lesson) => lesson.start.isAfter(from) && lesson.end.isBefore(to), - ) - .toList(); + lessons = + lessons + .where( + (lesson) => lesson.start.isAfter(from) && lesson.end.isBefore(to), + ) + .toList() + ..sort((a, b) => a.start.compareTo(b.start)); return ApiResponse(lessons, 200, err, cached); } @@ -1005,66 +785,25 @@ class KretaClient { Future>> getLessons({ bool forceCache = true, }) async { - var (resp, status, ex, cached) = await _cachingGet( + return await _genericListedCachingGet( CacheId.getLessons, KretaEndpoints.getLessons(model.iss!), forceCache, - 0, + (item) => AllLessons.fromJson(item), ); - - var items = []; - String? err; - - try { - if (resp is List) { - for (var item in resp) { - if (item != null && item is Map) { - items.add(AllLessons.fromJson(item)); - } else { - logger.warning("$item"); - } - } - } else { - err = "${resp.runtimeType}"; - } - } catch (e, stack) { - err = e.toString(); - logger.warning(e, stack); - } - - if (ex != null) { - err = ex.toString(); - } - - return ApiResponse(items, status, err, cached); } - Future>> getTests({bool forceCache = true}) async { - var (resp, status, ex, cached) = await _cachingGet( + Future>> getTests({ + DateTime? from, + DateTime? to, + bool forceCache = true, + }) async { + return await _genericListedCachingGet( CacheId.getTests, - KretaEndpoints.getTests(model.iss!), + KretaEndpoints.getTests(model.iss!, from, to), forceCache, - 0, + (item) => Test.fromJson(item), ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(Test.fromJson(item)); - } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - // items.sort((a, b) => a.date.compareTo(b.date)); - - return ApiResponse(items, status, err, cached); } ApiResponse>? omissionsCache; @@ -1077,33 +816,18 @@ class KretaClient { } else { if (omissionsCache != null) return omissionsCache!; } - var (resp, status, ex, cached) = await _cachingGet( + return await _genericListedCachingGet( CacheId.getOmissions, KretaEndpoints.getOmissions(model.iss!), forceCache, - 0, - ); - - var items = List.empty(growable: true); - String? err; - try { - List rawItems = resp; - for (var item in rawItems) { - items.add(Omission.fromJson(item)); + (item) => Omission.fromJson(item), + ).then((resp) { + if (resp.err == null) { + resp.response!.sort((a, b) => a.date.compareTo(b.date)); + omissionsCache = ApiResponse.cached(resp.response); } - } catch (ex) { - err = ex.toString(); - } - - if (ex != null) { - err = ex.toString(); - } - - items.sort((a, b) => a.date.compareTo(b.date)); - - if (ex == null) omissionsCache = ApiResponse(items, 200, null, true); - - return ApiResponse(items, status, err, cached); + return resp; + }); } void evictMemCache() { @@ -1116,5 +840,4 @@ class KretaClient { } bool _isTokenExpired(Object ex) => - ex.toString() == TokenExpiredException().toString() || - ex.toString() == InvalidGrantException().toString(); + ex is TokenExpiredException || ex is InvalidGrantException; diff --git a/firka/lib/api/consts.dart b/firka/lib/api/consts.dart index d715c0d..d431161 100644 --- a/firka/lib/api/consts.dart +++ b/firka/lib/api/consts.dart @@ -5,7 +5,6 @@ import 'dart:typed_data'; import 'package:crypto/crypto.dart'; import 'package:firka/app/app_state.dart'; -import 'package:kreta_api/kreta_api.dart' as ka; class Constants { static String get clientId { @@ -41,7 +40,7 @@ class TimetableConsts { static const event = "TanevRendjeEsemeny"; } -class KretaEndpoints { +class KretaLoginEndpoints { static String _generateCodeVerifier() { var random = Random.secure(); final bytes = List.generate(32, (i) => random.nextInt(256)); @@ -63,8 +62,6 @@ class KretaEndpoints { return base64Url.encode(bytes).replaceAll('=', ''); } - static String kreta(String iss) => ka.KretaEndpoints.kreta(iss); - static final String codeVerifier = _generateCodeVerifier(); static final String _codeChallenge = _generateCodeChallenge(codeVerifier); static final String stateOrNonce = generateStateOrNonce(); @@ -77,33 +74,4 @@ class KretaEndpoints { static String kretaLoginUrlRefresh(String username, String schoolId) => "$kretaIdp/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fredirect_uri%3Dhttps%253A%252F%252Fmobil.e-kreta.hu%252Fellenorzo-student%252Fprod%252Foauthredirect%26client_id%3D$clientId%26response_type%3Dcode%26login_hint%3D$username%26prompt%3Dlogin%26state%3D$stateOrNonce%26nonce%3D$stateOrNonce%26scope%3Dopenid%2520email%2520offline_access%2520kreta-ellenorzo-webapi.public%2520kreta-eugyintezes-webapi.public%2520kreta-fileservice-webapi.public%2520kreta-mobile-global-webapi.public%2520kreta-dkt-webapi.public%2520kreta-ier-webapi.public%26code_challenge%3D$_codeChallenge%26code_challenge_method%3DS256%26institute_code%3D$schoolId%26suppressed_prompt%3Dlogin"; static String tokenGrantUrl = "$kretaIdp/connect/token"; - - static String getStudentUrl(String iss) => - ka.KretaEndpoints.getStudentUrl(iss); - - static String getClassGroups(String iss) => - ka.KretaEndpoints.getClassGroups(iss); - - static String getClassGroupAvg(String iss, String studyGroupId) => - ka.KretaEndpoints.getClassGroupAvg(iss, studyGroupId); - - static String getNoticeBoard(String iss) => - ka.KretaEndpoints.getNoticeBoard(iss); - - static String getInfoBoard(String iss) => ka.KretaEndpoints.getInfoBoard(iss); - - static String getGrades(String iss) => ka.KretaEndpoints.getGrades(iss); - - static String getSubjectAvg(String iss, String studyGroupId) => - ka.KretaEndpoints.getSubjectAvg(iss, studyGroupId); - - static String getTimeTable(String iss) => ka.KretaEndpoints.getTimeTable(iss); - - static String getOmissions(String iss) => ka.KretaEndpoints.getOmissions(iss); - - static String getHomework(String iss) => ka.KretaEndpoints.getHomework(iss); - - static String getTests(String iss) => ka.KretaEndpoints.getTests(iss); - - static String getLessons(String iss) => ka.KretaEndpoints.getLessons(iss); } diff --git a/firka/lib/api/token_grant.dart b/firka/lib/api/token_grant.dart index a4f679c..631b21d 100644 --- a/firka/lib/api/token_grant.dart +++ b/firka/lib/api/token_grant.dart @@ -1,8 +1,8 @@ import 'package:dio/dio.dart'; import 'package:firka/data/models/token_model.dart'; -import 'package:kreta_api/kreta_api.dart' hide KretaEndpoints; import 'package:firka/app/app_state.dart'; +import 'package:kreta_api/kreta_api.dart'; import 'consts.dart'; Future getAccessToken(String code) async { @@ -14,7 +14,7 @@ Future getAccessToken(String code) async { final formData = { "code": code, - "code_verifier": KretaEndpoints.codeVerifier, + "code_verifier": KretaLoginEndpoints.codeVerifier, "redirect_uri": "https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect", "client_id": Constants.clientId, @@ -23,7 +23,7 @@ Future getAccessToken(String code) async { try { final response = await dio.post( - KretaEndpoints.tokenGrantUrl, + KretaLoginEndpoints.tokenGrantUrl, options: Options(headers: headers), data: formData, ); @@ -76,7 +76,7 @@ Future extendToken(TokenModel model) async { } final response = await dio.post( - KretaEndpoints.tokenGrantUrl, + KretaLoginEndpoints.tokenGrantUrl, options: Options(headers: headers), data: formData, ); diff --git a/firka/lib/data/util.dart b/firka/lib/data/util.dart index 5c008e6..97897f5 100644 --- a/firka/lib/data/util.dart +++ b/firka/lib/data/util.dart @@ -1,13 +1,12 @@ import 'dart:math'; -import 'package:intl/intl.dart'; import 'package:isar_community/isar.dart'; import 'package:firka/core/debug_helper.dart'; class DatedCacheEntry { Id? cacheKey; - List? values; + late List values; } int genCacheKey(DateTime date, int studentId) { @@ -17,10 +16,9 @@ int genCacheKey(DateTime date, int studentId) { } DateTime getDate(int key) { - var currentDate = timeNow(); var md = key ~/ pow(10, 11); var month = md ~/ pow(10, 2); - var day = md - month * pow(10, 2); + var day = (md - month * pow(10, 2)) as int; - return DateFormat("yyyy-M-d").parse("${currentDate.year}-$month-$day"); + return DateTime(timeNow().year, month, day); } diff --git a/firka/lib/ui/phone/widgets/login_webview.dart b/firka/lib/ui/phone/widgets/login_webview.dart index b03be30..0884f23 100644 --- a/firka/lib/ui/phone/widgets/login_webview.dart +++ b/firka/lib/ui/phone/widgets/login_webview.dart @@ -60,10 +60,10 @@ class _LoginWebviewWidgetState extends FirkaState end: 0.0, ).animate(_fadeAnimationController!); - var loginUrl = KretaEndpoints.kretaLoginUrl; + var loginUrl = KretaLoginEndpoints.kretaLoginUrl; if (widget.username != null && widget.schoolId != null) { - loginUrl = KretaEndpoints.kretaLoginUrlRefresh( + loginUrl = KretaLoginEndpoints.kretaLoginUrlRefresh( widget.username!, widget.schoolId!, ); diff --git a/kreta_api/lib/src/api_response.dart b/kreta_api/lib/src/api_response.dart index dc02ea6..0db4c44 100644 --- a/kreta_api/lib/src/api_response.dart +++ b/kreta_api/lib/src/api_response.dart @@ -1,17 +1,28 @@ class ApiResponse { T? response; int statusCode; - String? err; + Object? err; bool cached; ApiResponse(this.response, this.statusCode, this.err, this.cached); + ApiResponse.fail(this.err) : response = null, statusCode = 0, cached = false; + + ApiResponse.success(this.response, this.statusCode) + : err = null, + cached = false; + + ApiResponse.cached(this.response) + : statusCode = 200, + err = null, + cached = true; + @override String toString() { return "ApiResponse(" "response: $response, " "statusCode: $statusCode, " - "err: \"$err\", " + "err: \"${err.toString()}\", " "cached: $cached" ")"; }