From cba4e5911a1fe91f9d6a3f57bcdd9a2b25c50ade Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sat, 2 Dec 2023 02:03:30 +0100 Subject: [PATCH 01/24] feat(dev): added testing html to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 29439b3..47f45e2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ pubspec.lock .vscode/settings.json .vscode hidden_testing +jidelnicek.html From 3a1d3a824d32fe592c017ca9f09557395dc0eca4 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sat, 2 Dec 2023 02:04:01 +0100 Subject: [PATCH 02/24] feat: added support for getting lunches for 2.10.27 --- lib/src/canteen.dart | 13 +- lib/src/canteen_2_10_27.dart | 299 ++++++++++++++++++++++++++++++++++ lib/src/canteen_versions.dart | 1 + 3 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 lib/src/canteen_2_10_27.dart diff --git a/lib/src/canteen.dart b/lib/src/canteen.dart index 46a928b..4bd158d 100644 --- a/lib/src/canteen.dart +++ b/lib/src/canteen.dart @@ -193,6 +193,9 @@ class Canteen { case '2.19.13': canteenInstance = Canteen2v19v13(url); break; + case '2.10.27': + canteenInstance = Canteen2v10v27(url); + break; default: if (loginData == null) { //pokud není loginData, tak se nemůže získat verze. Tudíž prostě zkusíme jednu verzi a je možné, že nebude fungovat... @@ -221,7 +224,15 @@ class Canteen { throw 'Nepodařilo se přihlásit do iCanteenu'; } } catch (e) { - rethrow; + try { + canteenInstance = Canteen2v10v27(url); + await canteenInstance!.login(loginData.username, loginData.password); + if (!canteenInstance!.prihlasen) { + throw 'Nepodařilo se přihlásit do iCanteenu'; + } + } catch (e) { + rethrow; + } } } } diff --git a/lib/src/canteen_2_10_27.dart b/lib/src/canteen_2_10_27.dart new file mode 100644 index 0000000..bc753a2 --- /dev/null +++ b/lib/src/canteen_2_10_27.dart @@ -0,0 +1,299 @@ +/* + MIT License + +Copyright (c) 2023 Tomáš Protiva and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +import 'package:html/parser.dart' as parser; +import 'package:html/dom.dart' as dom; + +import 'dart:io'; + +import 'package:http/http.dart' as http; +import 'package:canteenlib/canteenlib.dart'; + +/// Reprezentuje kantýnu verze 2.10.27 +/// +/// **Všechny metody v případě chyby vrací [Future] s chybovou hláškou.** +class Canteen2v10v27 extends Canteen { + /// Sušenky potřebné pro komunikaci + Map cookies = {"JSESSIONID": ""}; + + /// Je uživatel přihlášen? + @override + bool prihlasen = false; + + Canteen2v10v27(String url) : super(url); + + /// Vrátí informace o uživateli ve formě instance [Uzivatel] + @override + Future ziskejUzivatele() async { + if (!prihlasen) return Future.error("Nejdříve se musíte přihlásit"); + var r = await _getRequest("/web/setting"); + if (r.contains("přihlášení uživatele")) { + prihlasen = false; + return Future.error("Nejdříve se musíte přihlásit"); + } + var kreditMatch = double.tryParse( + RegExp(r' +(.+?)(?=&)').firstMatch(r)!.group(1)!.replaceAll(",", ".").replaceAll(RegExp(r"[^\w.-]"), "")); + var jmenoMatch = RegExp(r'(?<=jméno: ).+?(?=<\/b)').firstMatch(r); + var prijmeniMatch = RegExp(r'(?<=příjmení: ).+?(?=<\/b)').firstMatch(r); + var kategorieMatch = RegExp(r'(?<=kategorie: ).+?(?=<\/b)').firstMatch(r); + var ucetMatch = + RegExp(r'účet pro platby do jídelny:\s*(\d+/\d+)').firstMatch(r)?.group(1)?.replaceAll(RegExp(r'<\/?b>'), ''); //odstranit html tag + var varMatch = RegExp(r'(?<=variabilní symbol: ).+?(?=<\/b)').firstMatch(r); + var specMatch = RegExp(r'(?<=specifický symbol: ).+?(?=<\/b)').firstMatch(r); + + var jmeno = jmenoMatch?.group(0) ?? ""; + var prijmeni = prijmeniMatch?.group(0) ?? ""; + var kategorie = kategorieMatch?.group(0) ?? ""; + var ucet = ucetMatch ?? ""; + var varSymbol = varMatch?.group(0) ?? ""; + var specSymbol = specMatch?.group(0) ?? ""; + var kredit = kreditMatch ?? 0.0; + + return Uzivatel( + jmeno: jmeno, prijmeni: prijmeni, kategorie: kategorie, ucetProPlatby: ucet, varSymbol: varSymbol, specSymbol: specSymbol, kredit: kredit); + } + + Future _getFirstSession() async { + var res = await http.get(Uri.parse('$url/faces/login.jsp')); + _parseCookies(res.headers['set-cookie']!); + } + + /// Převede cookie řetězec z požadavku do mapy + void _parseCookies(String cookieString) { + Map cookies = this.cookies; + var regCookie = RegExp(r'([A-Z\-]+=.+?(?=;))|(remember-me=.+?)(?=;)').allMatches(cookieString).toList(); + for (var cook in regCookie) { + var c = cook.group(0).toString().split("="); + cookies[c[0]] = c[1]; + } + } + + /// Přihlášení do iCanteen + /// + /// Vstup: + /// + /// - `user` - uživatelské jméno | [String] + /// - `password` - heslo | [String] + /// + /// Výstup: + /// - [bool] ve [Future], v případě přihlášení `true`, v případě špatného hesla `false` + @override + Future login(String user, String password) async { + if (cookies["JSESSIONID"] == "") { + await _getFirstSession(); + } + + var res = await http.post(Uri.parse("$url/j_spring_security_check"), headers: { + "Cookie": "JSESSIONID=${cookies["JSESSIONID"]!};", + "Content-Type": "application/x-www-form-urlencoded", + }, body: { + "j_username": user, + "j_password": password, + "terminal": "false", + "_spring_security_remember_me": "on", + "targetUrl": "/faces/secured/main.jsp?terminal=false&status=true&printer=&keyboard=" + }); + + if (res.headers['set-cookie']!.contains("remember-me=;")) { + return false; // špatné heslo + } + + if (res.statusCode != 302) { + return Future.error("Chyba: ${res.body}"); + } + _parseCookies(res.headers['set-cookie']!); + + prihlasen = true; + return true; + } + + /// Builder pro GET request + Future _getRequest(String path) async { + var r = await http.get(Uri.parse(url + path), headers: { + "Cookie": + "JSESSIONID=${cookies["JSESSIONID"]!}; ${cookies.containsKey("COOKIE") ? "SPRING_SECURITY_REMEMBER_ME_COOKIE=${cookies["COOKIE"]!};" : ""}", + }); + + if (r.statusCode != 200 || r.body.contains("fail") || r.body.contains("Chyba")) { + return Future.error("Chyba: ${r.body}"); + } + + if (r.body.contains("přihlášení uživatele")) { + prihlasen = false; + return Future.error("Nejdříve se musíte přihlásit"); + } + + if (r.headers.containsKey("set-cookie")) { + _parseCookies(r.headers["set-cookie"]!); + } + + return r.body; + } + + /// Získá jídelníček bez cen + /// + /// Výstup: + /// - [List] s [Jidelnicek], který neobsahuje ceny + /// + /// __Lze použít bez přihlášení__ + @override + Future> ziskejJidelnicek() async { + return []; //tato verze nemá jídelníček bez cen + } + + /// Získá jídlo pro daný den + /// + /// __Vyžaduje přihlášení pomocí [login]__ + /// + /// Vstup: + /// - `den` - *volitelné*, určuje pro jaký den chceme získat jídelníček | [DateTime] + /// + /// Výstup: + /// - [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel + @override + Future jidelnicekDen({DateTime? den}) async { + if (!prihlasen) { + return Future.error("Nejdříve se musíte přihlásit"); + } + + den ??= DateTime.now(); + + String res; + try { + res = await _getRequest( + "/faces/secured/main.jsp?day=${den.year}-${(den.month < 10) ? "0${den.month}" : den.month}-${(den.day < 10) ? "0${den.day}" : den.day}&terminal=false&printer=false&keyboard=false"); + } catch (e) { + return Future.error(e); + } + //save response to file + File("jidelnicek.html").writeAsStringSync(res); + dom.Document document = parser.parse(res); + late dom.Element jidelnicekData; + try { + jidelnicekData = document.getElementsByClassName("orderContent")[0]; + } catch (e) { + return Future.error("Obědy nenalezeny"); + } + + List jidla = []; + + for (dom.Element obed in jidelnicekData.children[0].children) { + // formátování do třídy + String nazev = cleanString(obed.children[0].children[1].text); + dom.Element tlacitko = obed.children[0].children[0].children[0]; + String objednavaciUrl = RegExp(r"'(.*?)'").firstMatch(tlacitko.attributes["onclick"]!.trim())!.group(1)!; + print(objednavaciUrl); + String textNaTlacitku = tlacitko.children[0].text.toLowerCase(); + String varianta = tlacitko.children[1].text.toLowerCase(); + double cena = double.parse(tlacitko.children[3].text.toLowerCase().replaceAll('kč', '').trim()); + bool objednano = textNaTlacitku.contains("zrušit"); + bool lzeObjednat = !textNaTlacitku.contains("nelze"); + print(objednano); + jidla.add( + Jidlo( + nazev: nazev, + objednano: objednano, + varianta: varianta, + lzeObjednat: lzeObjednat, + cena: cena, + orderUrl: objednavaciUrl, + den: den, + burzaUrl: null, //verze 2.10 nemá burzu + naBurze: false, //verze 2.10 nemá burzu + alergeny: [], + kategorizovano: parseJidlo(nazev), + ), + ); + // KONEC formátování do třídy + } + + return Jidelnicek(den, jidla); + } + + /// Objedná vybrané jídlo + /// + /// Vstup: + /// - `j` - Jídlo, které chceme objednat | [Jidlo] + /// + /// Výstup: + /// - Aktualizovaná instance [Jidlo] tohoto jídla + @override + Future objednat(Jidlo j) async { + if (!prihlasen) { + return Future.error("Nejdříve se musíte přihlásit"); + } + + if (!j.lzeObjednat || j.orderUrl == null || j.orderUrl!.isEmpty) { + return Future.error("Jídlo nelze objednat nebo nemá adresu pro objednání"); + } + + try { + await _getRequest("/faces/secured/${j.orderUrl!}"); // provést operaci + } catch (e) { + return Future.error(e); + } + + var novy = (await jidelnicekDen(den: j.den)) + .jidla + .where( + (element) => element.nazev == j.nazev, + ) + .toList()[0]; + + return novy; // vrátit novou instanci + } + + /// Uloží vaše jídlo z/do burzy + /// + /// Vstup: + /// - `j` - Jídlo, které chceme dát/vzít do/z burzy | [Jidlo] + /// + /// Výstup: + /// - Aktualizovaná instance [Jidlo] tohoto jídla NEBO [Future] jako chyba + @override + Future doBurzy(Jidlo j, {int amount = 1}) async { + return Future.error("Tato verze iCanteenu nemá burzu"); + } + + /// Získá aktuální jídla v burze + /// + /// Výstup: + /// - List instancí [Burza], každá obsahuje informace o jídle v burze + @override + Future> ziskatBurzu() async { + return Future.error("Tato verze iCanteenu nemá burzu"); + } + + /// Objedná jídlo z burzy pomocí URL z instance třídy Burza + /// + /// Vstup: + /// - `b` - Jídlo __z burzy__, které chceme objednat | [Burza] + /// + /// Výstup: + /// - [bool], `true`, pokud bylo jídlo úspěšně objednáno z burzy, jinak `Exception` + @override + Future objednatZBurzy(Burza b) async { + return Future.error("Tato verze iCanteenu nemá burzu"); + } +} diff --git a/lib/src/canteen_versions.dart b/lib/src/canteen_versions.dart index 55487cb..15e0de7 100644 --- a/lib/src/canteen_versions.dart +++ b/lib/src/canteen_versions.dart @@ -1,3 +1,4 @@ export './canteen_2_18_19.dart'; export './canteen_2_19_13.dart'; export './canteen_2_18_03.dart'; +export './canteen_2_10_27.dart'; From 89bcdda358c2d59c9c28e94f1f7c98267fc97ff5 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sat, 2 Dec 2023 20:53:06 +0100 Subject: [PATCH 03/24] =?UTF-8?q?docs:=20up=C5=99esn=C4=9Bna=20full=20comp?= =?UTF-8?q?atibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Full Compatibility.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Full Compatibility.md b/Full Compatibility.md index 033b85f..dfb9620 100644 --- a/Full Compatibility.md +++ b/Full Compatibility.md @@ -1,6 +1,6 @@ # V tomto souboru je rozepsaná každá featura pro každou instituci. Je to takový to-do list -➖ - v instituci není featura potřeba +➖ - v instituci není featura potřeba nebo není v dané verzi icanteen ✅ - featura funguje ❌ - featura nefunguje ❓ - featura funguje částečně nebo nelze vyzkoušet @@ -109,8 +109,8 @@ - funguje objednávání ✅ - funguje zrušení ✅ - Burza - - získání burzy - - Objednávání z burzy + - získání burzy ✅ + - Objednávání z burzy ✅ - vložení jídla na burzu ✅ - zrušit vložení jídla na burzu ✅ - počet ➖ From ab559e2efbf93c179db6e1ff92b0d26edc531be7 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Tue, 16 Jan 2024 09:31:32 +0100 Subject: [PATCH 04/24] =?UTF-8?q?feat:=20p=C5=99id=C3=A1na=20podpora=20pro?= =?UTF-8?q?=20z=C3=ADsk=C3=A1n=C3=AD=20j=C3=ADdeln=C3=AD=C4=8Dku=20na=20m?= =?UTF-8?q?=C4=9Bs=C3=ADc=20v=202.18.03?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen.dart | 4 + lib/src/canteen_2_18_03.dart | 178 ++++++++++++++++++++++------------- lib/src/tridy.dart | 20 ++++ test/canteenlib_test.dart | 6 ++ 4 files changed, 142 insertions(+), 66 deletions(-) diff --git a/lib/src/canteen.dart b/lib/src/canteen.dart index 789f02d..d275dbf 100644 --- a/lib/src/canteen.dart +++ b/lib/src/canteen.dart @@ -29,6 +29,9 @@ import 'package:html/parser.dart' as parser; import 'package:html/dom.dart' as dom; class Canteen { + /// Seznam chybějících funkcí pro danou verzi iCanteenu - funkce, které nejsou ve vanilla webové verzi iCanteenu + List missingFeatures = []; + /// URL iCanteenu String url; @@ -261,6 +264,7 @@ class Canteen { if (loginData != null && !canteenInstance!.prihlasen) { await canteenInstance!.login(loginData.username, loginData.password); } + missingFeatures = canteenInstance!.missingFeatures; return canteenInstance!; } diff --git a/lib/src/canteen_2_18_03.dart b/lib/src/canteen_2_18_03.dart index 2e3fcb5..60af315 100644 --- a/lib/src/canteen_2_18_03.dart +++ b/lib/src/canteen_2_18_03.dart @@ -21,6 +21,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import 'dart:io'; + +import 'package:html/parser.dart' as parser; +import 'package:html/dom.dart' as dom; + import 'package:canteenlib/canteenlib.dart'; import 'package:http/http.dart' as http; @@ -147,7 +152,7 @@ class Canteen2v18v03 extends Canteen { Future _getRequest(String path) async { var r = await http.get(Uri.parse(url + path), headers: { "Cookie": - "JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!}${cookies.containsKey("remember-me") ? "; ${cookies["remember-me"]!};" : ";"}", + "JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!}${cookies.containsKey("remember-me") ? "; ${cookies["remember-me"]!}" : ""}", }); if (r.statusCode != 200 || r.body.contains("fail") || r.body.contains("Chyba")) { @@ -217,6 +222,74 @@ class Canteen2v18v03 extends Canteen { return jidelnicek; } + Jidlo _parsePrihlasenyJidlo(RegExpMatch obed) { + // formátování do třídy + var o = obed.group(0).toString().replaceAll(RegExp(r'( )+|([^>a-z]\n)'), ''); + var objednano = o.contains("Máte objednáno"); + var lzeObjednat = !(o.contains("nelze zrušit") || o.contains("nelze objednat") || o.contains("nelze změnit")); + var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true).firstMatch(o)!.group(0).toString()); + + var cenaMatch = RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o); + cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o); + cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o); + + var cena = double.parse(cenaMatch!.group(0).toString().replaceAll(",", ".")); + var jidlaProDen = RegExp(r'
", "") + .replaceAll("\n", ""); + var vydejna = RegExp(r'(?<=).+?(?=<)').firstMatch(o)!.group(0).toString(); + + String? orderUrl; + String? burzaUrl; + if (lzeObjednat) { + // pokud lze objednat, nastavíme adresu pro objednání + var match = RegExp(r"(?<=ajaxOrder\(this, ').+?(?=')").firstMatch(o); + if (match != null) { + orderUrl = match.group(0)!.replaceAll("amp;", ""); + } + } else { + // jinak nastavíme URL pro burzu + var match = RegExp(r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)).+?(?=')""").firstMatch(o); + if (match != null) { + burzaUrl = match.group(0)!.replaceAll("amp;", ""); + } + } + var alergenyDetailMatch = RegExp(r' alergenyList = []; + + if (jidlaProDen.contains('(')) { + nazevjidla = jidlaProDen.split('(')[0].trim(); + String alergeny = jidlaProDen.split('(')[1].trim(); + alergeny = alergeny.replaceAll(')', ''); + List alergenyListRaw = alergeny.split(', '); + int mensiDelka = alergenyListRaw.length < alergenyDetailMatch.length ? alergenyListRaw.length : alergenyDetailMatch.length; + for (int i = 0; i < mensiDelka; i++) { + alergenyList.add(Alergen(nazev: alergenyListRaw[i], popis: alergenyDetailMatch[i].group(1))); + } + } + + return Jidlo( + nazev: nazevjidla, + objednano: objednano, + varianta: vydejna, + lzeObjednat: lzeObjednat, + cena: cena, + orderUrl: orderUrl, + den: obedDen, + burzaUrl: burzaUrl, + naBurze: (burzaUrl == null) ? false : !burzaUrl.contains("plusburza"), + alergeny: alergenyList, + kategorizovano: parseJidlo(nazevjidla)); + } + /// Získá jídlo pro daný den /// /// __Vyžaduje přihlášení pomocí [login]__ @@ -245,76 +318,49 @@ class Canteen2v18v03 extends Canteen { var jidla = []; var jidelnicek = RegExp(r'(?<=
).+?((fa-clock)|(fa-ban))', dotAll: true).allMatches(res).toList(); for (var obed in jidelnicek) { - // formátování do třídy - var o = obed.group(0).toString().replaceAll(RegExp(r'( )+|([^>a-z]\n)'), ''); - var objednano = o.contains("Máte objednáno"); - var lzeObjednat = !(o.contains("nelze zrušit") || o.contains("nelze objednat") || o.contains("nelze změnit")); - - var cenaMatch = RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o); - cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o); - cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o); - - var cena = double.parse(cenaMatch!.group(0).toString().replaceAll(",", ".")); - var jidlaProDen = RegExp(r'
", "") - .replaceAll("\n", ""); - var vydejna = RegExp(r'(?<=).+?(?=<)').firstMatch(o)!.group(0).toString(); - - String? orderUrl; - String? burzaUrl; - if (lzeObjednat) { - // pokud lze objednat, nastavíme adresu pro objednání - var match = RegExp(r"(?<=ajaxOrder\(this, ').+?(?=')").firstMatch(o); - if (match != null) { - orderUrl = match.group(0)!.replaceAll("amp;", ""); - } - } else { - // jinak nastavíme URL pro burzu - var match = RegExp(r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)).+?(?=')""").firstMatch(o); - if (match != null) { - burzaUrl = match.group(0)!.replaceAll("amp;", ""); - } - } - var alergenyDetailMatch = RegExp(r' alergenyList = []; - - if (jidlaProDen.contains('(')) { - nazevjidla = jidlaProDen.split('(')[0].trim(); - String alergeny = jidlaProDen.split('(')[1].trim(); - alergeny = alergeny.replaceAll(')', ''); - List alergenyListRaw = alergeny.split(', '); - int mensiDelka = alergenyListRaw.length < alergenyDetailMatch.length ? alergenyListRaw.length : alergenyDetailMatch.length; - for (int i = 0; i < mensiDelka; i++) { - alergenyList.add(Alergen(nazev: alergenyListRaw[i], popis: alergenyDetailMatch[i].group(1))); - } - } - - jidla.add(Jidlo( - nazev: nazevjidla, - objednano: objednano, - varianta: vydejna, - lzeObjednat: lzeObjednat, - cena: cena, - orderUrl: orderUrl, - den: den, - burzaUrl: burzaUrl, - naBurze: (burzaUrl == null) ? false : !burzaUrl.contains("plusburza"), - alergeny: alergenyList, - kategorizovano: parseJidlo(nazevjidla))); - // KONEC formátování do třídy + jidla.add(_parsePrihlasenyJidlo(obed)); } return Jidelnicek(den, jidla); } + /// Získá jídlo do konce měsíce od aktuálního dne + /// + /// __Vyžaduje přihlášení pomocí [login]__ + /// + /// Výstup: + /// - list instancí [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel + Future> jidelnicekMesic() async { + if (!prihlasen) { + return Future.error("Nejdříve se musíte přihlásit"); + } + String res; + try { + await jidelnicekDen(); // replikování komunikace probíhající s prohlížečem, jinak nevrátí informace o obědech... + res = await _getRequest("/faces/secured/month.jsp"); + } catch (e) { + return Future.error(e); + } + var jidla = []; + var jidelnicek = RegExp(r'(?<=
).+?((fa-clock)|(fa-ban))', dotAll: true).allMatches(res).toList(); + for (var obed in jidelnicek) { + jidla.add(_parsePrihlasenyJidlo(obed)); + } + Map> jidlaMap = {}; + for (var jidlo in jidla) { + if (jidlaMap.containsKey(jidlo.den)) { + jidlaMap[jidlo.den]!.add(jidlo); + } else { + jidlaMap[jidlo.den] = [jidlo]; + } + } + List jidelnicekList = []; + for (var jidelnicek in jidlaMap.values) { + jidelnicekList.add(Jidelnicek(jidelnicek[0].den, jidelnicek)); + } + return jidelnicekList; + } + /// Objedná vybrané jídlo /// /// Vstup: diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index a905ca3..4ce1c3c 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -66,6 +66,26 @@ class Alergen { const Alergen({required this.nazev, this.kod, this.popis}); } +enum Features { + /// Získat informace o přihlášeném uživateli + ziskatUzivatele, + + /// Získat informace o jídelníčku zvěřejněném na webu bez nutnosti přihlášení + jidelnicekBezCen, + + /// Získat informace o jídelníčku zvěřejněném na webu s nutností přihlášení + objednání obědů + jidelnicekDen, + + // Informace o jídelníčku za měsíc + jidelnicekMesic, + + /// burza + burza, + + /// alergeny + alergeny, +} + /// Reprezentuje cizí jídlo na burze class Burza { /// Den, který je jídlo vydáváno diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index 97f8c66..d9194a2 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -35,6 +35,7 @@ void main() { }); group('Jídelníček:', () { + if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.jidelnicekDen)) return; test('Jídelníček není prázdný', () async { await prihlasitSe(); await ziskatJidelnicek(); @@ -82,11 +83,16 @@ void main() { test('Jídelníček má alergeny', () async { await prihlasitSe(); await ziskatJidelnicek(); + if (canteenInstance!.missingFeatures.contains(Features.alergeny)) { + expect(true, true); + return; + } expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); }); }); group('Uživatel', () { + if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.ziskatUzivatele)) return; test('Uživatel má kredit', () async { await prihlasitSe(); await ziskatUzivatele(); From 7746d592262776b9bf1637f37e05645921e5b627 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Tue, 16 Jan 2024 09:32:37 +0100 Subject: [PATCH 05/24] chore: cleanup --- lib/src/canteen_2_18_03.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/src/canteen_2_18_03.dart b/lib/src/canteen_2_18_03.dart index 60af315..458d634 100644 --- a/lib/src/canteen_2_18_03.dart +++ b/lib/src/canteen_2_18_03.dart @@ -21,11 +21,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import 'dart:io'; - -import 'package:html/parser.dart' as parser; -import 'package:html/dom.dart' as dom; - import 'package:canteenlib/canteenlib.dart'; import 'package:http/http.dart' as http; From bc8d7388dd87cffe47e15767c11a690922d2852e Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Tue, 16 Jan 2024 09:57:08 +0100 Subject: [PATCH 06/24] docs: kompatibilita --- COMPATIBILITY.md | 15 ++++++++------- Full Compatibility.md | 7 +++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index cce8f15..db9b5e9 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -8,12 +8,13 @@ Kantýny, které v adrese obsahují i číslo portu, dokážou být často probl - ✅ - plně funkční nebo pouze s malými chybami - ❓ - částečně funkční -| Provozovatel | Verze iCanteen | Funkční | Adresa | -| :-------------------: | ---------------- | ------- | ----------------------------------- | -| SŠTE Brno | iCanteen 2.19.13 | ✅ | https://stravovani.sstebrno.cz | -| SPŠ Třebíč | iCanteen 2.10.25 | ❌ | https://icanteen.spst.cz | -| SPŠEI Ostrava | iCanteen 2.17.03 | ❌ | https://obedy.spseiostrava.cz:8443/ | -| SPŠ a G Na Třebešíně | iCanteen 2.18.03 | ✅ | https://jidelna.trebesin.cz | -| ZŠ Ostrava, Matiční 5 | iCanteen 2.18.19 | ✅ | http://obedy.zs-mat5.cz | +| Provozovatel | Verze iCanteen | Funkční | Adresa | +| :-------------------------------: | ---------------- | ------- | ----------------------------------- | +| SŠTE Brno | iCanteen 2.19.13 | ✅ | https://stravovani.sstebrno.cz | +| SPŠ Třebíč | iCanteen 2.10.25 | ❌ | https://icanteen.spst.cz | +| SPŠEI Ostrava | iCanteen 2.17.03 | ❌ | https://obedy.spseiostrava.cz:8443/ | +| SOŠ stavební a SOU stavební Kolín | iCanteen 2.10.27 | ❓ | http://obedy.ss-stavebnikolin.cz/ | +| SPŠ a G Na Třebešíně | iCanteen 2.18.03 | ✅ | https://jidelna.trebesin.cz | +| ZŠ Ostrava, Matiční 5 | iCanteen 2.18.19 | ✅ | http://obedy.zs-mat5.cz | Pokud chcete přispět s testem, otestujte tuto knihovnu na instanci iCanteen, kde, nejlépe legálně, máte přístup, a nahlašte své poznatky do [github issues](https://github.com/tpkowastaken/icanteenlib/issues/new?assignees=tpkowastaken&labels=kompatibilita&projects=&template=hl--en--kompatibility.md&title=Kompatibilita%3A+) (i pokud fungují prosím) diff --git a/Full Compatibility.md b/Full Compatibility.md index dfb9620..0134db8 100644 --- a/Full Compatibility.md +++ b/Full Compatibility.md @@ -34,6 +34,7 @@ - název - rozdělení na kategorie - blokováno (vypršela platnost) +- Jídelníček pro měsíc - Objednávání - funguje objednávání - funguje zrušení @@ -56,7 +57,7 @@ - specifický symbol ❓ - Uživatelské jméno ✅ - Jídelníček pro den ✅ - - správný počet jídel ❓ - v autojídelně vyřešeno wrapperem. + - správný počet jídel ✅ - jídlo ✅ - název ✅ - cena ✅ @@ -69,6 +70,7 @@ - podrobnosti ✅ - název ✅ - rozdělení na kategorie ✅ +- Jídelníček pro měsíc ✅ - Objednávání - funguje objednávání ✅ - funguje zrušení ✅ @@ -92,7 +94,7 @@ - specifický symbol ❓ - Uživatelské jméno ✅ - Jídelníček pro den ✅ - - správný počet jídel ❓ - v autojídelně vyřešeno wrapperem. + - správný počet jídel ✅ - jídlo ✅ - název ✅ má dvě mezery - cena ✅ @@ -105,6 +107,7 @@ - podrobnosti ✅ - název ✅ - rozdělení na kategorie ✅ +- Jídelníček pro měsíc ❌ - Objednávání - funguje objednávání ✅ - funguje zrušení ✅ From e9cda5a51c5dcbe96b88d999ab052d5e930c3389 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Tue, 16 Jan 2024 09:58:29 +0100 Subject: [PATCH 07/24] =?UTF-8?q?fix:=20chybov=C3=A1=20hl=C3=A1=C5=A1ka=20?= =?UTF-8?q?p=C5=99i=20nepodporovan=C3=A9=20feature=20ve=20verzi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen.dart | 37 +++++++++++++++++++++++++++++++++++- lib/src/canteen_2_18_03.dart | 4 ++++ lib/src/canteen_2_18_19.dart | 3 +++ lib/src/canteen_2_19_13.dart | 3 +++ lib/src/tridy.dart | 3 +++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/src/canteen.dart b/lib/src/canteen.dart index d275dbf..34143d2 100644 --- a/lib/src/canteen.dart +++ b/lib/src/canteen.dart @@ -29,7 +29,7 @@ import 'package:html/parser.dart' as parser; import 'package:html/dom.dart' as dom; class Canteen { - /// Seznam chybějících funkcí pro danou verzi iCanteenu - funkce, které nejsou ve vanilla webové verzi iCanteenu + /// Seznam chybějících funkcí pro danou verzi iCanteenu - funkce, které nejsou ve vanilla webové verzi iCanteenu nebo nejsou podporovány List missingFeatures = []; /// URL iCanteenu @@ -339,6 +339,10 @@ class Canteen { if (canteenInstance != null) { return canteenInstance!.ziskejJidelnicek(); } + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekBezCen)) { + throw 'nepodporovaná funkce'; + } + await _ziskatInstanciProVerzi(); return canteenInstance!.ziskejJidelnicek(); } @@ -356,14 +360,36 @@ class Canteen { if (canteenInstance == null) { throw 'Nejdříve se musíte přihlásit'; } + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) { + throw 'nepodporovaná funkce'; + } return canteenInstance!.jidelnicekDen(den: den); } + /// Získá jídlo do konce měsíce od aktuálního dne + /// + /// __Vyžaduje přihlášení pomocí [login]__ + /// + /// Výstup: + /// - list instancí [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel + Future> jidelnicekMesic() async { + if (canteenInstance == null) { + throw 'Nejdříve se musíte přihlásit'; + } + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) { + throw 'nepodporovaná funkce'; + } + return canteenInstance!.jidelnicekMesic(); + } + /// Vrátí informace o uživateli ve formě instance [Uzivatel] Future ziskejUzivatele() async { if (canteenInstance == null) { throw 'Nejdříve se musíte přihlásit'; } + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) { + throw 'nepodporovaná funkce'; + } return canteenInstance!.ziskejUzivatele(); } @@ -392,6 +418,9 @@ class Canteen { if (canteenInstance == null) { throw 'Nejdříve se musíte přihlásit'; } + if (canteenInstance!.missingFeatures.contains(Features.burza)) { + throw 'nepodporovaná funkce'; + } return canteenInstance!.doBurzy(j, amount: amount); } @@ -403,6 +432,9 @@ class Canteen { if (canteenInstance == null) { throw 'Nejdříve se musíte přihlásit'; } + if (canteenInstance!.missingFeatures.contains(Features.burza)) { + throw 'nepodporovaná funkce'; + } return canteenInstance!.ziskatBurzu(); } @@ -417,6 +449,9 @@ class Canteen { if (canteenInstance == null) { throw 'Nejdříve se musíte přihlásit'; } + if (canteenInstance!.missingFeatures.contains(Features.burza)) { + throw 'nepodporovaná funkce'; + } return canteenInstance!.objednatZBurzy(b); } } diff --git a/lib/src/canteen_2_18_03.dart b/lib/src/canteen_2_18_03.dart index 458d634..89cfe09 100644 --- a/lib/src/canteen_2_18_03.dart +++ b/lib/src/canteen_2_18_03.dart @@ -37,6 +37,9 @@ class Canteen2v18v03 extends Canteen { /// icanteen je v této verzi buglý, takže je potřeba si uživatelské jméno pamatovat String username = ""; + @override + get missingFeatures => [Features.burzaAmount]; + /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; @@ -325,6 +328,7 @@ class Canteen2v18v03 extends Canteen { /// /// Výstup: /// - list instancí [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel + @override Future> jidelnicekMesic() async { if (!prihlasen) { return Future.error("Nejdříve se musíte přihlásit"); diff --git a/lib/src/canteen_2_18_19.dart b/lib/src/canteen_2_18_19.dart index 097f14d..edb01d4 100644 --- a/lib/src/canteen_2_18_19.dart +++ b/lib/src/canteen_2_18_19.dart @@ -35,6 +35,9 @@ class Canteen2v18v19 extends Canteen { /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; + @override + get missingFeatures => [Features.jidelnicekMesic, Features.burzaAmount]; + /// Je uživatel přihlášen? @override bool prihlasen = false; diff --git a/lib/src/canteen_2_19_13.dart b/lib/src/canteen_2_19_13.dart index 98b6bf7..fd569b1 100644 --- a/lib/src/canteen_2_19_13.dart +++ b/lib/src/canteen_2_19_13.dart @@ -32,6 +32,9 @@ class Canteen2v19v13 extends Canteen { /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; + @override + get missingFeatures => [Features.jidelnicekMesic, Features.burzaAmount]; + /// Je uživatel přihlášen? @override bool prihlasen = false; diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index 4ce1c3c..30507b0 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -82,6 +82,9 @@ enum Features { /// burza burza, + // dát počet jídel na burzu + burzaAmount, + /// alergeny alergeny, } From 4897200da996279db2808279ffe54aeb8dbf7868 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Wed, 17 Jan 2024 11:14:20 +0100 Subject: [PATCH 08/24] added jidelnicekMesic support for 2.18.19 --- lib/src/canteen_2_18_19.dart | 164 ++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 62 deletions(-) diff --git a/lib/src/canteen_2_18_19.dart b/lib/src/canteen_2_18_19.dart index edb01d4..0ec25af 100644 --- a/lib/src/canteen_2_18_19.dart +++ b/lib/src/canteen_2_18_19.dart @@ -217,6 +217,106 @@ class Canteen2v18v19 extends Canteen { return jidelnicek; } + /// Získá jídlo do konce měsíce od aktuálního dne + /// + /// __Vyžaduje přihlášení pomocí [login]__ + /// + /// Výstup: + /// - list instancí [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel + @override + Future> jidelnicekMesic() async { + if (!prihlasen) { + return Future.error("Nejdříve se musíte přihlásit"); + } + String res; + try { + await jidelnicekDen(); // replikování komunikace probíhající s prohlížečem, jinak nevrátí informace o obědech... + res = await _getRequest("/faces/secured/month.jsp"); + } catch (e) { + return Future.error(e); + } + var jidla = []; + var jidelnicek = RegExp(r'(?<=
).+?((fa-clock)|(fa-ban))', dotAll: true).allMatches(res).toList(); + for (var obed in jidelnicek) { + jidla.add(_parsePrihlasenyJidlo(obed)); + } + Map> jidlaMap = {}; + for (var jidlo in jidla) { + if (jidlaMap.containsKey(jidlo.den)) { + jidlaMap[jidlo.den]!.add(jidlo); + } else { + jidlaMap[jidlo.den] = [jidlo]; + } + } + List jidelnicekList = []; + for (var jidelnicek in jidlaMap.values) { + jidelnicekList.add(Jidelnicek(jidelnicek[0].den, jidelnicek)); + } + return jidelnicekList; + } + + Jidlo _parsePrihlasenyJidlo(obed) { + // formátování do třídy + var o = obed.group(0).toString().replaceAll(RegExp(r'( )+|([^>a-z]\n)'), ''); + var objednano = o.contains("Máte objednáno"); + var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true).firstMatch(o)!.group(0).toString()); + var lzeObjednat = !(o.contains("nelze zrušit") || o.contains("nelze objednat") || o.contains("nelze změnit")); + + var cenaMatch = RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o); + cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o); + cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o); + + var cena = double.parse(cenaMatch!.group(0).toString().replaceAll(",", ".")); + var jidlaProDen = RegExp(r'
", "") + .replaceAll("\n", ""); + var alergenyList = RegExp(r'()').allMatches(jidlaProDen).toList(); + var alergeny = alergenyList.map((e) { + var jmeno = RegExp(r'(.+?)<\/b>').firstMatch(e.group(1).toString())!.group(1); + var popis = RegExp(r'<\/b> - (.+)').firstMatch(e.group(1).toString())?.group(1); + var kod = RegExp(r'class="textGrey">(\d+?),?\s?').firstMatch(e.group(1).toString())?.group(1); + return Alergen(nazev: jmeno!, kod: kod == null ? null : int.parse(kod), popis: popis); + }).toList(); + + var vydejna = RegExp(r'(?<=).+?(?=<)').firstMatch(o)!.group(0).toString(); + + String? orderUrl; + String? burzaUrl; + if (lzeObjednat) { + // pokud lze objednat, nastavíme adresu pro objednání + var match = RegExp(r"(?<=ajaxOrder\(this, ').+?(?=')").firstMatch(o); + if (match != null) { + orderUrl = match.group(0)!.replaceAll("amp;", ""); + } + } else { + // jinak nastavíme URL pro burzu + var match = RegExp(r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)|(multiburza)).+?(?=')""").firstMatch(o); + if (match != null) { + burzaUrl = match.group(0)!.replaceAll("amp;", ""); + } + } + var jidloJmeno = jidlaProDen.split('')[0]; + jidloJmeno = cleanString(jidloJmeno); + return Jidlo( + nazev: jidloJmeno.replaceAll(r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''), + objednano: objednano, + varianta: vydejna, + lzeObjednat: lzeObjednat, + cena: cena, + orderUrl: orderUrl, + den: obedDen, + burzaUrl: burzaUrl, + naBurze: (burzaUrl == null) ? false : burzaUrl.contains("minusburza"), + alergeny: alergeny, + kategorizovano: parseJidlo(jidloJmeno), + ); + // KONEC formátování do třídy + } + /// Získá jídlo pro daný den /// /// __Vyžaduje přihlášení pomocí [login]__ @@ -242,73 +342,13 @@ class Canteen2v18v19 extends Canteen { return Future.error(e); } - var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true).firstMatch(res)!.group(0).toString()); var jidla = []; var jidelnicek = RegExp(r'(?<=
).+?((fa-clock)|(fa-ban))', dotAll: true).allMatches(res).toList(); for (var obed in jidelnicek) { - // formátování do třídy - var o = obed.group(0).toString().replaceAll(RegExp(r'( )+|([^>a-z]\n)'), ''); - var objednano = o.contains("Máte objednáno"); - var lzeObjednat = !(o.contains("nelze zrušit") || o.contains("nelze objednat") || o.contains("nelze změnit")); - - var cenaMatch = RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o); - cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o); - cenaMatch ??= RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o); - - var cena = double.parse(cenaMatch!.group(0).toString().replaceAll(",", ".")); - var jidlaProDen = RegExp(r'
", "") - .replaceAll("\n", ""); - var alergenyList = RegExp(r'()').allMatches(jidlaProDen).toList(); - var alergeny = alergenyList.map((e) { - var jmeno = RegExp(r'(.+?)<\/b>').firstMatch(e.group(1).toString())!.group(1); - var popis = RegExp(r'<\/b> - (.+)').firstMatch(e.group(1).toString())?.group(1); - var kod = RegExp(r'class="textGrey">(\d+?),?\s?').firstMatch(e.group(1).toString())?.group(1); - return Alergen(nazev: jmeno!, kod: kod == null ? null : int.parse(kod), popis: popis); - }).toList(); - - var vydejna = RegExp(r'(?<=).+?(?=<)').firstMatch(o)!.group(0).toString(); - - String? orderUrl; - String? burzaUrl; - if (lzeObjednat) { - // pokud lze objednat, nastavíme adresu pro objednání - var match = RegExp(r"(?<=ajaxOrder\(this, ').+?(?=')").firstMatch(o); - if (match != null) { - orderUrl = match.group(0)!.replaceAll("amp;", ""); - } - } else { - // jinak nastavíme URL pro burzu - var match = RegExp(r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)|(multiburza)).+?(?=')""").firstMatch(o); - if (match != null) { - burzaUrl = match.group(0)!.replaceAll("amp;", ""); - } - } - var jidloJmeno = jidlaProDen.split('')[0]; - jidloJmeno = cleanString(jidloJmeno); - jidla.add( - Jidlo( - nazev: jidloJmeno.replaceAll(r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''), - objednano: objednano, - varianta: vydejna, - lzeObjednat: lzeObjednat, - cena: cena, - orderUrl: orderUrl, - den: obedDen, - burzaUrl: burzaUrl, - naBurze: (burzaUrl == null) ? false : burzaUrl.contains("minusburza"), - alergeny: alergeny, - kategorizovano: parseJidlo(jidloJmeno), - ), - ); - // KONEC formátování do třídy + jidla.add(_parsePrihlasenyJidlo(obed)); } - return Jidelnicek(obedDen, jidla); + return Jidelnicek(den, jidla); } /// Objedná vybrané jídlo From 07faf4c6b01a216406c285110da3b8553f4a4606 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Wed, 17 Jan 2024 11:19:42 +0100 Subject: [PATCH 09/24] =?UTF-8?q?feat:=20p=C5=99id=C3=A1n=20jidelnicekMesi?= =?UTF-8?q?c=20support=20for=20testing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen_2_18_19.dart | 2 +- test/canteenlib_test.dart | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/src/canteen_2_18_19.dart b/lib/src/canteen_2_18_19.dart index 0ec25af..be475e4 100644 --- a/lib/src/canteen_2_18_19.dart +++ b/lib/src/canteen_2_18_19.dart @@ -36,7 +36,7 @@ class Canteen2v18v19 extends Canteen { Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; @override - get missingFeatures => [Features.jidelnicekMesic, Features.burzaAmount]; + get missingFeatures => [Features.burzaAmount]; /// Je uživatel přihlášen? @override diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index d9194a2..8dadfc0 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -7,6 +7,7 @@ import 'package:dotenv/dotenv.dart'; DotEnv? envSecrets; Canteen? canteenInstance; Jidelnicek? jidelnicek; +Jidelnicek? jidelnicekMesic; Uzivatel? uzivatel; Future ziskatUzivatele() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); @@ -21,6 +22,12 @@ Future ziskatJidelnicek() async { jidelnicek ??= await canteenInstance!.jidelnicekDen(den: funkcniDatum); } +Future ziskatJidelnicekMesic() async { + envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); + canteenInstance ??= Canteen(envSecrets!["URL"]!); + jidelnicek ??= (await canteenInstance!.jidelnicekMesic())[0]; +} + Future prihlasitSe() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); @@ -91,6 +98,63 @@ void main() { }); }); + group('Jídelníček měsíc:', () { + if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.jidelnicekMesic)) return; + test('Jídelníček není prázdný', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + expect(jidelnicek!.jidla.isNotEmpty, true); + }); + + test('Jídelníček má aspoň dva obědy', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + expect(jidelnicek!.jidla.length >= 2, true); + }); + + test('Jídelníček má název', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + print(jidelnicek!.jidla[0].nazev); + expect(jidelnicek!.jidla[0].nazev.isNotEmpty, true); + }); + + test('Jídelníček má cenu', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + expect(jidelnicek!.jidla[0].cena! > 10, true); + }); + + test('Jídelníček má variantu', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + expect(jidelnicek!.jidla[0].varianta.isNotEmpty, true); + }); + + test('Jídelníček je kategorizovaný', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + print('--------------------Jídelníček--------------------'); + print('Jídlo: ${jidelnicek!.jidla[0].nazev}'); + print('Hlavní jídlo: ${jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo}'); + print('pití: ${jidelnicek!.jidla[0].kategorizovano!.piti}'); + print('polévka: ${jidelnicek!.jidla[0].kategorizovano!.polevka}'); + print('Salátový bar: ${jidelnicek!.jidla[0].kategorizovano!.salatovyBar}'); + print('ostatní: ${jidelnicek!.jidla[0].kategorizovano!.ostatni}'); + print('--------------------------------------------------'); + expect(jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo!.isNotEmpty, true); + }); + test('Jídelníček má alergeny', () async { + await prihlasitSe(); + await ziskatJidelnicekMesic(); + if (canteenInstance!.missingFeatures.contains(Features.alergeny)) { + expect(true, true); + return; + } + expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); + }); + }); + group('Uživatel', () { if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.ziskatUzivatele)) return; test('Uživatel má kredit', () async { From b15e9ec9595c9fd7f9a0ab7ef63e14e8bc334508 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Wed, 17 Jan 2024 12:52:36 +0100 Subject: [PATCH 10/24] chore: full compatibility edit --- Full Compatibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Full Compatibility.md b/Full Compatibility.md index 0134db8..cfd3e16 100644 --- a/Full Compatibility.md +++ b/Full Compatibility.md @@ -107,7 +107,7 @@ - podrobnosti ✅ - název ✅ - rozdělení na kategorie ✅ -- Jídelníček pro měsíc ❌ +- Jídelníček pro měsíc ✅ - Objednávání - funguje objednávání ✅ - funguje zrušení ✅ From cd5995776b6f4b473586c7cd3e1adff53cf27baf Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Wed, 17 Jan 2024 13:00:22 +0100 Subject: [PATCH 11/24] =?UTF-8?q?feat:=20p=C5=99id=C3=A1ny=20polo=C5=BEky?= =?UTF-8?q?=20do=20filtru?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen.dart | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/src/canteen.dart b/lib/src/canteen.dart index 34143d2..631fd16 100644 --- a/lib/src/canteen.dart +++ b/lib/src/canteen.dart @@ -65,25 +65,42 @@ class Canteen { List salatoveBary = ['salát', 'kompot']; List piticka = [ 'nápoj', + 'napoj', 'čaj', + 'caj', 'káva', + 'kava', + 'mošt', + 'most', 'sirup', 'voda', 'mléko', + 'mleko', 'vit. nápoj' /*vitamínový nápoj*/, 'vit.nápoj' /*vitamínový nápoj*/, 'džus', + 'dzus', 'kakao', ]; List ostatniVeci = [ 'ovoce', 'pečivo', + 'pecivo', 'chléb', + 'chleb', 'rohlík', + 'rohlik', 'tyčinka', + 'tycinka', 'dezert', - 'termix' - 'šáteč' /*šáteček/šátečky */ + 'termix', + 'tvarohá' /*Tvaroháček/Tvaroháčky*/, + 'tvaroha' /*tvaroháček/tvaroháčky*/, + 'šáteč' /*šáteček/šátečky */, + 'satec' /*šáteček/šátečky */, + 'šateč', + 'šatec', + 'sateč', ]; bool kategorie(String vec, List kategorie) { From 39f6d9c88cba845591212270f2b968522d65474c Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Thu, 18 Jan 2024 10:31:03 +0100 Subject: [PATCH 12/24] removed debugging options --- lib/src/canteen_2_10_27.dart | 43 +++++++++++++++++------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/lib/src/canteen_2_10_27.dart b/lib/src/canteen_2_10_27.dart index bc753a2..a28f0b2 100644 --- a/lib/src/canteen_2_10_27.dart +++ b/lib/src/canteen_2_10_27.dart @@ -34,6 +34,9 @@ import 'package:canteenlib/canteenlib.dart'; /// /// **Všechny metody v případě chyby vrací [Future] s chybovou hláškou.** class Canteen2v10v27 extends Canteen { + @override + get missingFeatures => [Features.alergeny, Features.burza, Features.jidelnicekBezCen, Features.burzaAmount, Features.jidelnicekMesic]; + /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": ""}; @@ -47,31 +50,27 @@ class Canteen2v10v27 extends Canteen { @override Future ziskejUzivatele() async { if (!prihlasen) return Future.error("Nejdříve se musíte přihlásit"); - var r = await _getRequest("/web/setting"); + var r = await _getRequest("/faces/secured/setting.jsp?terminal=false&keyboard=false&printer=false"); + File("jidelnicek.html").writeAsStringSync(r); if (r.contains("přihlášení uživatele")) { prihlasen = false; return Future.error("Nejdříve se musíte přihlásit"); } - var kreditMatch = double.tryParse( - RegExp(r' +(.+?)(?=&)').firstMatch(r)!.group(1)!.replaceAll(",", ".").replaceAll(RegExp(r"[^\w.-]"), "")); - var jmenoMatch = RegExp(r'(?<=jméno: ).+?(?=<\/b)').firstMatch(r); - var prijmeniMatch = RegExp(r'(?<=příjmení: ).+?(?=<\/b)').firstMatch(r); - var kategorieMatch = RegExp(r'(?<=kategorie: ).+?(?=<\/b)').firstMatch(r); - var ucetMatch = - RegExp(r'účet pro platby do jídelny:\s*(\d+/\d+)').firstMatch(r)?.group(1)?.replaceAll(RegExp(r'<\/?b>'), ''); //odstranit html tag - var varMatch = RegExp(r'(?<=variabilní symbol: ).+?(?=<\/b)').firstMatch(r); - var specMatch = RegExp(r'(?<=specifický symbol: ).+?(?=<\/b)').firstMatch(r); - - var jmeno = jmenoMatch?.group(0) ?? ""; - var prijmeni = prijmeniMatch?.group(0) ?? ""; - var kategorie = kategorieMatch?.group(0) ?? ""; - var ucet = ucetMatch ?? ""; - var varSymbol = varMatch?.group(0) ?? ""; - var specSymbol = specMatch?.group(0) ?? ""; - var kredit = kreditMatch ?? 0.0; - + dom.Document document = parser.parse(r); + List elementList = document.getElementsByTagName("tbody"); + dom.Element? element; + for (dom.Element e in elementList) { + if (e.text.contains('Datum narození')) { + element = e; + break; + } + } + if (element == null) return Future.error("nepodařilo se získat informace o uživateli"); + return Future.error("nepodařilo se získat informace o uživateli"); +/* return Uzivatel( jmeno: jmeno, prijmeni: prijmeni, kategorie: kategorie, ucetProPlatby: ucet, varSymbol: varSymbol, specSymbol: specSymbol, kredit: kredit); + */ } Future _getFirstSession() async { @@ -136,6 +135,7 @@ class Canteen2v10v27 extends Canteen { }); if (r.statusCode != 200 || r.body.contains("fail") || r.body.contains("Chyba")) { + File("jidelnicek.html").writeAsStringSync(r.body); return Future.error("Chyba: ${r.body}"); } @@ -159,7 +159,7 @@ class Canteen2v10v27 extends Canteen { /// __Lze použít bez přihlášení__ @override Future> ziskejJidelnicek() async { - return []; //tato verze nemá jídelníček bez cen + return Future.error('nepodporovaná funkce'); //tato verze nemá jídelníček bez cen } /// Získá jídlo pro daný den @@ -187,7 +187,6 @@ class Canteen2v10v27 extends Canteen { return Future.error(e); } //save response to file - File("jidelnicek.html").writeAsStringSync(res); dom.Document document = parser.parse(res); late dom.Element jidelnicekData; try { @@ -203,13 +202,11 @@ class Canteen2v10v27 extends Canteen { String nazev = cleanString(obed.children[0].children[1].text); dom.Element tlacitko = obed.children[0].children[0].children[0]; String objednavaciUrl = RegExp(r"'(.*?)'").firstMatch(tlacitko.attributes["onclick"]!.trim())!.group(1)!; - print(objednavaciUrl); String textNaTlacitku = tlacitko.children[0].text.toLowerCase(); String varianta = tlacitko.children[1].text.toLowerCase(); double cena = double.parse(tlacitko.children[3].text.toLowerCase().replaceAll('kč', '').trim()); bool objednano = textNaTlacitku.contains("zrušit"); bool lzeObjednat = !textNaTlacitku.contains("nelze"); - print(objednano); jidla.add( Jidlo( nazev: nazev, From a50126a9e4133c14d882219b564527e651a4fd08 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Thu, 18 Jan 2024 10:31:16 +0100 Subject: [PATCH 13/24] updated full Compatibility.md --- Full Compatibility.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Full Compatibility.md b/Full Compatibility.md index cfd3e16..3efc1a5 100644 --- a/Full Compatibility.md +++ b/Full Compatibility.md @@ -43,6 +43,8 @@ - Objednávání z burzy - vložení jídla na burzu - zrušit vložení jídla na burzu + - počet +- Terminal (jiné lokace) # Spš a G Na Třebešíně - verze 2.18.03 @@ -117,3 +119,41 @@ - vložení jídla na burzu ✅ - zrušit vložení jídla na burzu ✅ - počet ➖ + +# SOŠ stavební a SOU stavební Kolín + +- Login ✅ +- Získej uživatele ❌ + - kredit ❌ + - jméno ❌ + - Příjmení ❌ + - Kategorie ❌ + - Účet pro platby ❌ + - Variabilní symbol ❌ + - specifický symbol ❌ + - Uživatelské jméno ❌ +- Jídelníček pro den ✅ + - správný počet jídel ✅ + - jídlo ✅ + - název ✅ + - cena ✅ + - varianta ✅ + - objednáno ✅ + - lze objednat ✅ + - na burze ➖ + - alergeny ➖ + - kódy➖ + - podrobnosti➖ + - název➖ + - rozdělení na kategorie ✅ + - blokováno (vypršela platnost) ✅ +- Jídelníček pro měsíc ❌ +- Objednávání ✅ + - funguje objednávání✅ + - funguje zrušení✅ +- Burza➖ + - získání burzy➖ + - Objednávání z burzy➖ + - vložení jídla na burzu➖ + - zrušit vložení jídla na burzu➖ +- Terminal (jiné lokace)❌ From 27e3d0fca65bb791b736da8183276c228b0cc921 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Thu, 18 Jan 2024 14:46:53 +0100 Subject: [PATCH 14/24] chore: format --- lib/src/tridy.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index 30507b0..c6dcc8e 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -145,8 +145,16 @@ class Uzivatel { /// Aktuální stav kreditu double kredit; - Uzivatel( - {this.uzivatelskeJmeno, this.jmeno, this.prijmeni, this.kategorie, this.ucetProPlatby, this.varSymbol, this.kredit = 0.0, this.specSymbol}); + Uzivatel({ + this.uzivatelskeJmeno, + this.jmeno, + this.prijmeni, + this.kategorie, + this.ucetProPlatby, + this.varSymbol, + this.kredit = 0.0, + this.specSymbol, + }); } class LoginData { From 831aa8589464fad7b425ec401de7259ac291e8df Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Thu, 18 Jan 2024 14:54:56 +0100 Subject: [PATCH 15/24] =?UTF-8?q?fix:=20testy=20nyn=C3=AD=20funguj=C3=AD?= =?UTF-8?q?=20pro=20SOS=20stavebni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen_2_10_27.dart | 80 +++++++++++++++++++++++++++++++++--- lib/src/tridy.dart | 3 ++ test/canteenlib_test.dart | 1 + 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/lib/src/canteen_2_10_27.dart b/lib/src/canteen_2_10_27.dart index a28f0b2..6129097 100644 --- a/lib/src/canteen_2_10_27.dart +++ b/lib/src/canteen_2_10_27.dart @@ -34,8 +34,18 @@ import 'package:canteenlib/canteenlib.dart'; /// /// **Všechny metody v případě chyby vrací [Future] s chybovou hláškou.** class Canteen2v10v27 extends Canteen { + /// icanteen v této verzi nemá uživatelské jméno + String username = ""; + @override - get missingFeatures => [Features.alergeny, Features.burza, Features.jidelnicekBezCen, Features.burzaAmount, Features.jidelnicekMesic]; + get missingFeatures => [ + Features.alergeny, + Features.burza, + Features.jidelnicekBezCen, + Features.burzaAmount, + Features.jidelnicekMesic, + Features.variabilniSymbol + ]; /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": ""}; @@ -57,6 +67,7 @@ class Canteen2v10v27 extends Canteen { return Future.error("Nejdříve se musíte přihlásit"); } dom.Document document = parser.parse(r); + File("jidelnicek.html").writeAsStringSync(document.outerHtml); List elementList = document.getElementsByTagName("tbody"); dom.Element? element; for (dom.Element e in elementList) { @@ -65,12 +76,70 @@ class Canteen2v10v27 extends Canteen { break; } } + //print(element!.innerHtml); if (element == null) return Future.error("nepodařilo se získat informace o uživateli"); - return Future.error("nepodařilo se získat informace o uživateli"); -/* + + dom.Element jmenoElement = element.firstChild!.firstChild!.children[0].children[0].children[1]; + dom.Element kategorieElement = element.firstChild!.firstChild!.children[0].children[0].children[3]; + dom.Element? kreditElement = document.getElementById('Kredit'); + String kredit = kreditElement?.text ?? '0.0'; + kredit = kredit.split(' ')[0]; + /* + dom.Element datumNarozeniElement = element.firstChild!.firstChild!.children[0].children[0].children[2]; + dom.Element tridaElement = element.firstChild!.firstChild!.children[0].children[0].children[4]; + dom.Element cislaElement = element.firstChild!.firstChild!.children[0].children[0].children[5]; + dom.Element omezeniElement = element.firstChild!.firstChild!.children[0].children[0].children[6]; + dom.Element kontaktniUdajeElement = element.firstChild!.children[1].children[0].children[0].children[1]; + dom.Element adresaElement = element.firstChild!.children[1].children[0].children[0].children[2]; + dom.Element telefonElement = element.firstChild!.children[1].children[0].children[0].children[3]; + dom.Element zakonnyZastupceElement = element.firstChild!.children[1].children[0].children[0].children[4]; + */ + + dom.Element variabilniSymbolElement = element.children[1].children[0].children[0].children[0].children[1]; + dom.Element ucetProPlatbyElement = element.children[1].children[0].children[0].children[0].children[2]; + //dom.Element ucetProVraceniPreplatku = element.children[1].children[0].children[0].children[0].children[2]; + + String? jmeno = jmenoElement.children[0].text; + String? prijmeni = jmenoElement.children[1].text; + String? kategorie = kategorieElement.children[0].text; + String? ucetProPlatby = ucetProPlatbyElement.children[0].text; + String? variabilniSymbol = variabilniSymbolElement.children[0].text; + try { + variabilniSymbol = variabilniSymbol.split(': ')[1].trim(); + } catch (e) { + variabilniSymbol = null; + } + try { + ucetProPlatby = ucetProPlatby.split(': ')[1].trim(); + } catch (e) { + ucetProPlatby = null; + } + try { + jmeno = jmeno.split(': ')[1].trim(); + } catch (e) { + jmeno = null; + } + try { + kategorie = kategorie.split(': ')[1].trim(); + } catch (e) { + kategorie = null; + } + try { + prijmeni = prijmeni.split(': ')[1].trim(); + } catch (e) { + prijmeni = null; + } + return Uzivatel( - jmeno: jmeno, prijmeni: prijmeni, kategorie: kategorie, ucetProPlatby: ucet, varSymbol: varSymbol, specSymbol: specSymbol, kredit: kredit); - */ + jmeno: jmeno, + prijmeni: prijmeni, + kategorie: kategorie, + ucetProPlatby: ucetProPlatby, + varSymbol: variabilniSymbol, + specSymbol: null, // not supported + kredit: double.parse(kredit), + uzivatelskeJmeno: username, + ); } Future _getFirstSession() async { @@ -122,6 +191,7 @@ class Canteen2v10v27 extends Canteen { return Future.error("Chyba: ${res.body}"); } _parseCookies(res.headers['set-cookie']!); + username = user; prihlasen = true; return true; diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index c6dcc8e..e943bdd 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -67,6 +67,9 @@ class Alergen { } enum Features { + /// zda má test očekávat variabilní/specifický symbol + variabilniSymbol, + /// Získat informace o přihlášeném uživateli ziskatUzivatele, diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index 8dadfc0..eb46feb 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -182,6 +182,7 @@ void main() { }); test('Uživatel má variablilní nebo specifický symbol', () async { + if (canteenInstance!.missingFeatures.contains(Features.variabilniSymbol)) return expect(true, true); await prihlasitSe(); await ziskatUzivatele(); expect((uzivatel!.varSymbol ?? "").isNotEmpty || (uzivatel!.specSymbol ?? "").isNotEmpty, true); From 68871170198e93063bbced49bdb0009297e1f861 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 21:53:16 +0100 Subject: [PATCH 16/24] chore(dev): gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 47f45e2..74904c3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ pubspec.lock .vscode hidden_testing jidelnicek.html +s.html From 5bb5c948208ef05914c57a8104fc1256634e7f0d Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 21:54:12 +0100 Subject: [PATCH 17/24] =?UTF-8?q?feat:=20podpora=20pro=20v=C3=ADce=20j?= =?UTF-8?q?=C3=ADdelen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Full Compatibility.md | 6 ++- lib/src/canteen.dart | 7 ++++ lib/src/canteen_2_10_27.dart | 80 +++++++++++++++++++++++------------- lib/src/tridy.dart | 5 ++- 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/Full Compatibility.md b/Full Compatibility.md index 3efc1a5..1c522e6 100644 --- a/Full Compatibility.md +++ b/Full Compatibility.md @@ -44,7 +44,7 @@ - vložení jídla na burzu - zrušit vložení jídla na burzu - počet -- Terminal (jiné lokace) +- Výdejny (jiné lokace) # Spš a G Na Třebešíně - verze 2.18.03 @@ -82,6 +82,7 @@ - vložení jídla na burzu ✅ - zrušit vložení jídla na burzu ✅ - počet ➖ +- Výdejny (jiné lokace) ➖ # Základní škola Ostrava, Matiční 5 @@ -119,6 +120,7 @@ - vložení jídla na burzu ✅ - zrušit vložení jídla na burzu ✅ - počet ➖ +- Výdejny (jiné lokace) ➖ # SOŠ stavební a SOU stavební Kolín @@ -156,4 +158,4 @@ - Objednávání z burzy➖ - vložení jídla na burzu➖ - zrušit vložení jídla na burzu➖ -- Terminal (jiné lokace)❌ +- Výdejny (jiné lokace) ✅ diff --git a/lib/src/canteen.dart b/lib/src/canteen.dart index 631fd16..dfbc08a 100644 --- a/lib/src/canteen.dart +++ b/lib/src/canteen.dart @@ -46,6 +46,13 @@ class Canteen { // Je uživatel přihlášen? bool get prihlasen => canteenInstance?.prihlasen ?? false; + int get vydejna => canteenInstance?.vydejna ?? 1; + set vydejna(int value) { + if (canteenInstance != null) { + canteenInstance!.vydejna = value; + } + } + ///zpracuje jídlo a rozdělí ho na kategorie (hlavní jídlo, polévka, salátový bar, pití...) JidloKategorizovano parseJidlo(String jidlo) { List cistyListJidel = jidlo.split(','); diff --git a/lib/src/canteen_2_10_27.dart b/lib/src/canteen_2_10_27.dart index 6129097..d9866d7 100644 --- a/lib/src/canteen_2_10_27.dart +++ b/lib/src/canteen_2_10_27.dart @@ -36,6 +36,10 @@ import 'package:canteenlib/canteenlib.dart'; class Canteen2v10v27 extends Canteen { /// icanteen v této verzi nemá uživatelské jméno String username = ""; + @override + int vydejna = 1; + + bool firstRequest = false; @override get missingFeatures => [ @@ -59,15 +63,14 @@ class Canteen2v10v27 extends Canteen { /// Vrátí informace o uživateli ve formě instance [Uzivatel] @override Future ziskejUzivatele() async { + firstRequest = false; if (!prihlasen) return Future.error("Nejdříve se musíte přihlásit"); var r = await _getRequest("/faces/secured/setting.jsp?terminal=false&keyboard=false&printer=false"); - File("jidelnicek.html").writeAsStringSync(r); if (r.contains("přihlášení uživatele")) { prihlasen = false; return Future.error("Nejdříve se musíte přihlásit"); } dom.Document document = parser.parse(r); - File("jidelnicek.html").writeAsStringSync(document.outerHtml); List elementList = document.getElementsByTagName("tbody"); dom.Element? element; for (dom.Element e in elementList) { @@ -205,7 +208,6 @@ class Canteen2v10v27 extends Canteen { }); if (r.statusCode != 200 || r.body.contains("fail") || r.body.contains("Chyba")) { - File("jidelnicek.html").writeAsStringSync(r.body); return Future.error("Chyba: ${r.body}"); } @@ -243,6 +245,11 @@ class Canteen2v10v27 extends Canteen { /// - [Jidelnicek] obsahující detaily, které vidí přihlášený uživatel @override Future jidelnicekDen({DateTime? den}) async { + if (!firstRequest && den != null) { + DateTime den = DateTime.now(); + await _getRequest( + "/faces/secured/main.jsp?day=${den.year}-${(den.month < 10) ? "0${den.month}" : den.month}-${(den.day < 10) ? "0${den.day}" : den.day}&terminal=false&printer=false&keyboard=false"); + } if (!prihlasen) { return Future.error("Nejdříve se musíte přihlásit"); } @@ -252,12 +259,23 @@ class Canteen2v10v27 extends Canteen { String res; try { res = await _getRequest( - "/faces/secured/main.jsp?day=${den.year}-${(den.month < 10) ? "0${den.month}" : den.month}-${(den.day < 10) ? "0${den.day}" : den.day}&terminal=false&printer=false&keyboard=false"); + "/faces/secured/main.jsp?vydejna=$vydejna&day=${den.year}-${(den.month < 10) ? "0${den.month}" : den.month}-${(den.day < 10) ? "0${den.day}" : den.day}&terminal=false&printer=false&keyboard=false"); } catch (e) { return Future.error(e); } + File('jidelnicek.html').writeAsStringSync(res); //debug //save response to file dom.Document document = parser.parse(res); + + RegExp regex = RegExp( + r'''onclick="javascript:location\.replace\('main\.jsp\?vydejna=(\d*)&terminal=false&keyboard=false&printer=false'\);\"\/>\s*(.*)\<\/a\>'''); + + Map vydejny = {}; + Iterable regExpMatch = regex.allMatches(res); + for (RegExpMatch match in regExpMatch) { + vydejny[int.parse(match.group(1)!)] = match.group(2)!; + } + late dom.Element jidelnicekData; try { jidelnicekData = document.getElementsByClassName("orderContent")[0]; @@ -269,33 +287,37 @@ class Canteen2v10v27 extends Canteen { for (dom.Element obed in jidelnicekData.children[0].children) { // formátování do třídy - String nazev = cleanString(obed.children[0].children[1].text); - dom.Element tlacitko = obed.children[0].children[0].children[0]; - String objednavaciUrl = RegExp(r"'(.*?)'").firstMatch(tlacitko.attributes["onclick"]!.trim())!.group(1)!; - String textNaTlacitku = tlacitko.children[0].text.toLowerCase(); - String varianta = tlacitko.children[1].text.toLowerCase(); - double cena = double.parse(tlacitko.children[3].text.toLowerCase().replaceAll('kč', '').trim()); - bool objednano = textNaTlacitku.contains("zrušit"); - bool lzeObjednat = !textNaTlacitku.contains("nelze"); - jidla.add( - Jidlo( - nazev: nazev, - objednano: objednano, - varianta: varianta, - lzeObjednat: lzeObjednat, - cena: cena, - orderUrl: objednavaciUrl, - den: den, - burzaUrl: null, //verze 2.10 nemá burzu - naBurze: false, //verze 2.10 nemá burzu - alergeny: [], - kategorizovano: parseJidlo(nazev), - ), - ); - // KONEC formátování do třídy + try { + String nazev = cleanString(obed.children[0].children[1].text); + dom.Element tlacitko = obed.children[0].children[0].children[0]; + String objednavaciUrl = RegExp(r"'(.*?)'").firstMatch(tlacitko.attributes["onclick"]!.trim())!.group(1)!; + String textNaTlacitku = tlacitko.children[0].text.toLowerCase(); + String varianta = tlacitko.children[1].text.toLowerCase(); + double cena = double.parse(tlacitko.children[3].text.toLowerCase().replaceAll('kč', '').trim()); + bool objednano = textNaTlacitku.contains("zrušit"); + bool lzeObjednat = !textNaTlacitku.contains("nelze"); + jidla.add( + Jidlo( + nazev: nazev, + objednano: objednano, + varianta: varianta, + lzeObjednat: lzeObjednat, + cena: cena, + orderUrl: objednavaciUrl, + den: den, + burzaUrl: null, //verze 2.10 nemá burzu + naBurze: false, //verze 2.10 nemá burzu + alergeny: [], + kategorizovano: parseJidlo(nazev), + ), + // KONEC formátování do třídy + ); + } catch (e) { + // jídlo chybí = není v nabídce v daný den + } } - return Jidelnicek(den, jidla); + return Jidelnicek(den, jidla, vydejny: vydejny); } /// Objedná vybrané jídlo diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index e943bdd..d86a8e5 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -119,7 +119,10 @@ class Jidelnicek { /// Seznam jídel List jidla; - Jidelnicek(this.den, this.jidla); + + // Seznam výdejen (je prázdný, pokud je pouze jedna) + Map vydejny; + Jidelnicek(this.den, this.jidla, {this.vydejny = const {}}); } /// Reprezentuje informace o přihlášeném uživateli From e46d6d782b44faf298149f9c12d6b3c9b74770e2 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:08:50 +0100 Subject: [PATCH 18/24] fix(dev): fixed tests --- lib/src/tridy.dart | 2 + test/canteenlib_test.dart | 79 ++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/lib/src/tridy.dart b/lib/src/tridy.dart index d86a8e5..2430f1b 100644 --- a/lib/src/tridy.dart +++ b/lib/src/tridy.dart @@ -67,6 +67,8 @@ class Alergen { } enum Features { + viceVydejen, + /// zda má test očekávat variabilní/specifický symbol variabilniSymbol, diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index eb46feb..60c03f2 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -25,7 +25,7 @@ Future ziskatJidelnicek() async { Future ziskatJidelnicekMesic() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); - jidelnicek ??= (await canteenInstance!.jidelnicekMesic())[0]; + jidelnicekMesic ??= (await canteenInstance!.jidelnicekMesic())[0]; } Future prihlasitSe() async { @@ -42,21 +42,30 @@ void main() { }); group('Jídelníček:', () { - if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.jidelnicekDen)) return; + test('Jídelníček má více výdejen', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatJidelnicek(); + expect(jidelnicek!.vydejny.length > 1, true); + }); test('Jídelníček není prázdný', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); expect(jidelnicek!.jidla.isNotEmpty, true); }); test('Jídelníček má aspoň dva obědy', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); expect(jidelnicek!.jidla.length >= 2, true); }); test('Jídelníček má název', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); print(jidelnicek!.jidla[0].nazev); expect(jidelnicek!.jidla[0].nazev.isNotEmpty, true); @@ -64,18 +73,21 @@ void main() { test('Jídelníček má cenu', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); expect(jidelnicek!.jidla[0].cena! > 10, true); }); test('Jídelníček má variantu', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); expect(jidelnicek!.jidla[0].varianta.isNotEmpty, true); }); test('Jídelníček je kategorizovaný', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; await ziskatJidelnicek(); print('--------------------Jídelníček--------------------'); print('Jídlo: ${jidelnicek!.jidla[0].nazev}'); @@ -89,106 +101,119 @@ void main() { }); test('Jídelníček má alergeny', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + if (canteenInstance!.missingFeatures.contains(Features.alergeny)) return; await ziskatJidelnicek(); - if (canteenInstance!.missingFeatures.contains(Features.alergeny)) { - expect(true, true); - return; - } expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); }); }); group('Jídelníček měsíc:', () { - if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.jidelnicekMesic)) return; + test('Jídelníček má více výdejen', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; + await ziskatJidelnicekMesic(); + expect(jidelnicekMesic!.vydejny.length > 1, true); + }); test('Jídelníček není prázdný', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - expect(jidelnicek!.jidla.isNotEmpty, true); + expect(jidelnicekMesic!.jidla.isNotEmpty, true); }); test('Jídelníček má aspoň dva obědy', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - expect(jidelnicek!.jidla.length >= 2, true); + expect(jidelnicekMesic!.jidla.length >= 2, true); }); test('Jídelníček má název', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - print(jidelnicek!.jidla[0].nazev); - expect(jidelnicek!.jidla[0].nazev.isNotEmpty, true); + print(jidelnicekMesic!.jidla[0].nazev); + expect(jidelnicekMesic!.jidla[0].nazev.isNotEmpty, true); }); test('Jídelníček má cenu', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - expect(jidelnicek!.jidla[0].cena! > 10, true); + expect(jidelnicekMesic!.jidla[0].cena! > 10, true); }); test('Jídelníček má variantu', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - expect(jidelnicek!.jidla[0].varianta.isNotEmpty, true); + expect(jidelnicekMesic!.jidla[0].varianta.isNotEmpty, true); }); test('Jídelníček je kategorizovaný', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); print('--------------------Jídelníček--------------------'); - print('Jídlo: ${jidelnicek!.jidla[0].nazev}'); - print('Hlavní jídlo: ${jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo}'); - print('pití: ${jidelnicek!.jidla[0].kategorizovano!.piti}'); - print('polévka: ${jidelnicek!.jidla[0].kategorizovano!.polevka}'); - print('Salátový bar: ${jidelnicek!.jidla[0].kategorizovano!.salatovyBar}'); - print('ostatní: ${jidelnicek!.jidla[0].kategorizovano!.ostatni}'); + print('Jídlo: ${jidelnicekMesic!.jidla[0].nazev}'); + print('Hlavní jídlo: ${jidelnicekMesic!.jidla[0].kategorizovano!.hlavniJidlo}'); + print('pití: ${jidelnicekMesic!.jidla[0].kategorizovano!.piti}'); + print('polévka: ${jidelnicekMesic!.jidla[0].kategorizovano!.polevka}'); + print('Salátový bar: ${jidelnicekMesic!.jidla[0].kategorizovano!.salatovyBar}'); + print('ostatní: ${jidelnicekMesic!.jidla[0].kategorizovano!.ostatni}'); print('--------------------------------------------------'); - expect(jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo!.isNotEmpty, true); + expect(jidelnicekMesic!.jidla[0].kategorizovano!.hlavniJidlo!.isNotEmpty, true); }); test('Jídelníček má alergeny', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; + if (canteenInstance!.missingFeatures.contains(Features.alergeny)) return; await ziskatJidelnicekMesic(); - if (canteenInstance!.missingFeatures.contains(Features.alergeny)) { - expect(true, true); - return; - } - expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); + expect(jidelnicekMesic!.jidla[0].alergeny.isNotEmpty, true); }); }); group('Uživatel', () { - if ((canteenInstance?.missingFeatures ?? List.empty()).contains(Features.ziskatUzivatele)) return; test('Uživatel má kredit', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect(uzivatel!.kredit > -10000 && uzivatel!.kredit < 10000, true); }); test('Uživatel má jméno', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect(uzivatel!.jmeno!.isNotEmpty, true); }); test('Uživatel má příjmení', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect(uzivatel!.prijmeni!.isNotEmpty, true); }); test('Uživatel má účet pro platby', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect(uzivatel!.ucetProPlatby!.isNotEmpty, true); }); test('Uživatel má variablilní nebo specifický symbol', () async { - if (canteenInstance!.missingFeatures.contains(Features.variabilniSymbol)) return expect(true, true); await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.variabilniSymbol)) return; + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect((uzivatel!.varSymbol ?? "").isNotEmpty || (uzivatel!.specSymbol ?? "").isNotEmpty, true); }); test('Uživatel má uživatelské jméno', () async { await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.ziskatUzivatele)) return; await ziskatUzivatele(); expect((uzivatel?.uzivatelskeJmeno ?? "").isNotEmpty, true); }); From bd0ff76f4277516def11733bfc5d8d3ee1007911 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:11:19 +0100 Subject: [PATCH 19/24] =?UTF-8?q?fix:=20p=C5=99id=C3=A1na=20nepodporovan?= =?UTF-8?q?=C3=A1=20feature=20viceVydejen=20do=20spravnych=20Canteen=20Cla?= =?UTF-8?q?ss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/canteen_2_18_03.dart | 2 +- lib/src/canteen_2_18_19.dart | 2 +- lib/src/canteen_2_19_13.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/canteen_2_18_03.dart b/lib/src/canteen_2_18_03.dart index 89cfe09..06cc8c9 100644 --- a/lib/src/canteen_2_18_03.dart +++ b/lib/src/canteen_2_18_03.dart @@ -38,7 +38,7 @@ class Canteen2v18v03 extends Canteen { String username = ""; @override - get missingFeatures => [Features.burzaAmount]; + get missingFeatures => [Features.burzaAmount, Features.viceVydejen]; /// Sušenky potřebné pro komunikaci Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; diff --git a/lib/src/canteen_2_18_19.dart b/lib/src/canteen_2_18_19.dart index be475e4..01ba127 100644 --- a/lib/src/canteen_2_18_19.dart +++ b/lib/src/canteen_2_18_19.dart @@ -36,7 +36,7 @@ class Canteen2v18v19 extends Canteen { Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; @override - get missingFeatures => [Features.burzaAmount]; + get missingFeatures => [Features.burzaAmount, Features.viceVydejen]; /// Je uživatel přihlášen? @override diff --git a/lib/src/canteen_2_19_13.dart b/lib/src/canteen_2_19_13.dart index fd569b1..9d1b02c 100644 --- a/lib/src/canteen_2_19_13.dart +++ b/lib/src/canteen_2_19_13.dart @@ -33,7 +33,7 @@ class Canteen2v19v13 extends Canteen { Map cookies = {"JSESSIONID": "", "XSRF-TOKEN": ""}; @override - get missingFeatures => [Features.jidelnicekMesic, Features.burzaAmount]; + get missingFeatures => [Features.jidelnicekMesic, Features.burzaAmount, Features.viceVydejen]; /// Je uživatel přihlášen? @override From c3024f3218559be170e9f1192aea59ec366592b1 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:15:55 +0100 Subject: [PATCH 20/24] fixed JidelnicekMesic test to work on the weekends (except if the weekend is the last day in the month) --- test/canteenlib_test.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index 60c03f2..e43f533 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -25,7 +25,13 @@ Future ziskatJidelnicek() async { Future ziskatJidelnicekMesic() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); - jidelnicekMesic ??= (await canteenInstance!.jidelnicekMesic())[0]; + List jidelnickyProMesic = await canteenInstance!.jidelnicekMesic(); + for (Jidelnicek jidelnicek in jidelnickyProMesic) { + if (jidelnicek.jidla.isNotEmpty) { + jidelnicekMesic = jidelnicek; + break; + } + } } Future prihlasitSe() async { From 2ff5eac67c8e64c1cd038c8a7d6b576efe80b325 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:19:30 +0100 Subject: [PATCH 21/24] Revert "fixed JidelnicekMesic test to work on the weekends (except if the weekend is the last day in the month)" This reverts commit c3024f3218559be170e9f1192aea59ec366592b1. --- test/canteenlib_test.dart | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index e43f533..60c03f2 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -25,13 +25,7 @@ Future ziskatJidelnicek() async { Future ziskatJidelnicekMesic() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); - List jidelnickyProMesic = await canteenInstance!.jidelnicekMesic(); - for (Jidelnicek jidelnicek in jidelnickyProMesic) { - if (jidelnicek.jidla.isNotEmpty) { - jidelnicekMesic = jidelnicek; - break; - } - } + jidelnicekMesic ??= (await canteenInstance!.jidelnicekMesic())[0]; } Future prihlasitSe() async { From c55f68824859c5eaff2dd7878d632856404be669 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:24:27 +0100 Subject: [PATCH 22/24] =?UTF-8?q?fix(testing):=20m=C3=A9n=C4=9B=20restrikt?= =?UTF-8?q?ivn=C3=AD=20ob=C4=9Bdy=20u=20jidelnicekMesic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/canteenlib_test.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index 60c03f2..b57ed35 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -25,7 +25,13 @@ Future ziskatJidelnicek() async { Future ziskatJidelnicekMesic() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); - jidelnicekMesic ??= (await canteenInstance!.jidelnicekMesic())[0]; + List jidelnickyProMesic = await canteenInstance!.jidelnicekMesic(); + for (Jidelnicek jidelnicek in jidelnickyProMesic) { + if (jidelnicek.jidla.isNotEmpty) { + jidelnicekMesic = jidelnicek; + break; + } + } } Future prihlasitSe() async { @@ -123,11 +129,11 @@ void main() { expect(jidelnicekMesic!.jidla.isNotEmpty, true); }); - test('Jídelníček má aspoň dva obědy', () async { + test('Jídelníček má aspoň jeden oběd', () async { await prihlasitSe(); if (canteenInstance!.missingFeatures.contains(Features.jidelnicekMesic)) return; await ziskatJidelnicekMesic(); - expect(jidelnicekMesic!.jidla.length >= 2, true); + expect(jidelnicekMesic!.jidla.isNotEmpty, true); }); test('Jídelníček má název', () async { From 2d84b6e0593a9f0863206311e4564c074c9ac7d3 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:35:53 +0100 Subject: [PATCH 23/24] feat(dev): added testing for ss-stavebnikolin.cz --- .github/workflows/dart.yml | 10 ++++ .github/workflows/pub-publish.yml | 10 ++++ test/canteenlib_test.dart | 84 +++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 834c49c..c84e506 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -51,3 +51,13 @@ jobs: - name: Test pro obedy.zs-mat5.cz run: dart test + + # Testing pro obedy.ss-stavebnikolin.cz + - name: Test pro obedy.ss-stavebnikolin.cz + run: | + echo "URL= 'obedy.ss-stavebnikolin.cz'" > .env + echo "USER= '${{ secrets.USER3 }}'" >> .env + echo "PASS= '${{ secrets.PASS3 }}'" >> .env + + - name: Test pro obedy.ss-stavebnikolin.cz + run: dart test diff --git a/.github/workflows/pub-publish.yml b/.github/workflows/pub-publish.yml index 48f62d7..c5d7cf0 100644 --- a/.github/workflows/pub-publish.yml +++ b/.github/workflows/pub-publish.yml @@ -67,6 +67,16 @@ jobs: - name: Test pro obedy.zs-mat5.cz run: dart test + # Testing pro obedy.ss-stavebnikolin.cz + - name: Test pro obedy.ss-stavebnikolin.cz + run: | + echo "URL= 'obedy.ss-stavebnikolin.cz'" > .env + echo "USER= '${{ secrets.USER3 }}'" >> .env + echo "PASS= '${{ secrets.PASS3 }}'" >> .env + + - name: Test pro obedy.ss-stavebnikolin.cz + run: dart test + - name: Removing credentials run: rm -rf .env diff --git a/test/canteenlib_test.dart b/test/canteenlib_test.dart index b57ed35..11eb81c 100644 --- a/test/canteenlib_test.dart +++ b/test/canteenlib_test.dart @@ -7,6 +7,7 @@ import 'package:dotenv/dotenv.dart'; DotEnv? envSecrets; Canteen? canteenInstance; Jidelnicek? jidelnicek; +Jidelnicek? druhaVydejnaJidelnicek; Jidelnicek? jidelnicekMesic; Uzivatel? uzivatel; Future ziskatUzivatele() async { @@ -19,12 +20,22 @@ Future ziskatJidelnicek() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); DateTime funkcniDatum = DateTime(2023, 11, 22); + canteenInstance!.vydejna = 1; + jidelnicek ??= await canteenInstance!.jidelnicekDen(den: funkcniDatum); +} + +Future ziskatDruhaVydejnaJidelnicek() async { + envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); + canteenInstance ??= Canteen(envSecrets!["URL"]!); + DateTime funkcniDatum = DateTime(2023, 11, 22); + canteenInstance!.vydejna = 2; jidelnicek ??= await canteenInstance!.jidelnicekDen(den: funkcniDatum); } Future ziskatJidelnicekMesic() async { envSecrets ??= DotEnv(includePlatformEnvironment: true)..load(); canteenInstance ??= Canteen(envSecrets!["URL"]!); + canteenInstance!.vydejna = 1; List jidelnickyProMesic = await canteenInstance!.jidelnicekMesic(); for (Jidelnicek jidelnicek in jidelnickyProMesic) { if (jidelnicek.jidla.isNotEmpty) { @@ -113,6 +124,79 @@ void main() { expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); }); }); + group('Jídelníček, druhá výdejna:', () { + test('Jídelníček má více výdejen', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.vydejny.length > 1, true); + }); + test('Jídelníček není prázdný', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.jidla.isNotEmpty, true); + }); + + test('Jídelníček má aspoň dva obědy', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.jidla.length >= 2, true); + }); + + test('Jídelníček má název', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + print(jidelnicek!.jidla[0].nazev); + expect(jidelnicek!.jidla[0].nazev.isNotEmpty, true); + }); + + test('Jídelníček má cenu', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.jidla[0].cena! > 10, true); + }); + + test('Jídelníček má variantu', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.jidla[0].varianta.isNotEmpty, true); + }); + + test('Jídelníček je kategorizovaný', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + await ziskatDruhaVydejnaJidelnicek(); + print('--------------------Jídelníček--------------------'); + print('Jídlo: ${jidelnicek!.jidla[0].nazev}'); + print('Hlavní jídlo: ${jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo}'); + print('pití: ${jidelnicek!.jidla[0].kategorizovano!.piti}'); + print('polévka: ${jidelnicek!.jidla[0].kategorizovano!.polevka}'); + print('Salátový bar: ${jidelnicek!.jidla[0].kategorizovano!.salatovyBar}'); + print('ostatní: ${jidelnicek!.jidla[0].kategorizovano!.ostatni}'); + print('--------------------------------------------------'); + expect(jidelnicek!.jidla[0].kategorizovano!.hlavniJidlo!.isNotEmpty, true); + }); + test('Jídelníček má alergeny', () async { + await prihlasitSe(); + if (canteenInstance!.missingFeatures.contains(Features.viceVydejen)) return; + if (canteenInstance!.missingFeatures.contains(Features.jidelnicekDen)) return; + if (canteenInstance!.missingFeatures.contains(Features.alergeny)) return; + await ziskatDruhaVydejnaJidelnicek(); + expect(jidelnicek!.jidla[0].alergeny.isNotEmpty, true); + }); + }); group('Jídelníček měsíc:', () { test('Jídelníček má více výdejen', () async { From 8739298084fced570cd8c714507eaa2979f8a515 Mon Sep 17 00:00:00 2001 From: tpkowastaken Date: Sun, 21 Jan 2024 22:40:42 +0100 Subject: [PATCH 24/24] fix: fixed wrong name --- .github/workflows/dart.yml | 2 +- .github/workflows/pub-publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c84e506..41c799b 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -53,7 +53,7 @@ jobs: run: dart test # Testing pro obedy.ss-stavebnikolin.cz - - name: Test pro obedy.ss-stavebnikolin.cz + - name: Credentials pro obedy.ss-stavebnikolin.cz run: | echo "URL= 'obedy.ss-stavebnikolin.cz'" > .env echo "USER= '${{ secrets.USER3 }}'" >> .env diff --git a/.github/workflows/pub-publish.yml b/.github/workflows/pub-publish.yml index c5d7cf0..257e15a 100644 --- a/.github/workflows/pub-publish.yml +++ b/.github/workflows/pub-publish.yml @@ -68,7 +68,7 @@ jobs: run: dart test # Testing pro obedy.ss-stavebnikolin.cz - - name: Test pro obedy.ss-stavebnikolin.cz + - name: Credentials pro obedy.ss-stavebnikolin.cz run: | echo "URL= 'obedy.ss-stavebnikolin.cz'" > .env echo "USER= '${{ secrets.USER3 }}'" >> .env