Burza + snad to co mi furt padá

This commit is contained in:
Matyáš Caras 2022-03-30 15:30:51 +02:00
parent 1399dbca3a
commit 567aea179b
6 changed files with 140 additions and 30 deletions

View file

@ -1,6 +1,16 @@
## 0.1.0-alpha.4
- Přidáno získání a objednávání cizích jídel z burzy
- Třída `Jidlo`: ~~cislo~~ 👉 **varianta**
- Nová třída `Burza` pro cizí jídla z burzy
- Více Exceptionů
[Všechny změny](https://github.com/hernikplays/canteenlib/compare/0.1.0-alpha.3...0.1.0-alpha.4)
## 0.1.0-alpha.3 ## 0.1.0-alpha.3
- Kontrolovat správný status kód u GET požadavků - Kontrolovat správný status kód u GET požadavků
[Všechny změny](https://github.com/hernikplays/canteenlib/compare/0.1.0-alpha.1...0.1.0-alpha.4)
## 0.1.0-alpha.2 ## 0.1.0-alpha.2
- Nevytvářet debugovací soubor - Nevytvářet debugovací soubor
- Místo ziskejKredit používáme ziskejUzivatele (Třída Uzivatel) - Místo ziskejKredit používáme ziskejUzivatele (Třída Uzivatel)

View file

@ -9,7 +9,7 @@ Výchozí verze, pro kterou aktuálně je knihovna tvořena, je **2.18.19**
| Provozovatel | Verze iCanteen | Funkční | Verze knihovny | | Provozovatel | Verze iCanteen | Funkční | Verze knihovny |
|:--------------:|------------------|---------|----------------| |:--------------:|------------------|---------|----------------|
| SŠTE Brno | iCanteen 2.18.19 | ✅ | 0.1.0-alpha | | SŠTE Brno | iCanteen 2.18.19 | ✅ | 0.1.0-alpha.4 |
| SPŠ Třebíč | iCanteen 2.10.25 | ❓ | 0.1.0-alpha | | SPŠ Třebíč | iCanteen 2.10.25 | ❓ | 0.1.0-alpha |
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 [zde](https://github.com/hernikplays/canteenlib/issues/new?assignees=hernikplays&labels=kompatibilita&template=hl--en--kompatibility.md&title=Kompatibilita%3A+) 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 [zde](https://github.com/hernikplays/canteenlib/issues/new?assignees=hernikplays&labels=kompatibilita&template=hl--en--kompatibility.md&title=Kompatibilita%3A+)

View file

@ -1,16 +1,17 @@
## O knihovně ## O knihovně
Experimentální **neoficiální** webscrape knihovna pro komunikaci se systémem [iCanteen](https://www.z-ware.cz/internetove-objednavky) Experimentální **neoficiální** webscrape knihovna pro komunikaci se systémem [iCanteen](https://www.z-ware.cz/internetove-objednavky)
[![wakatime](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/82873d93-5b79-4978-a5f6-612e21641817.svg)](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/82873d93-5b79-4978-a5f6-612e21641817) [![wakatime](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/82873d93-5b79-4978-a5f6-612e21641817.svg)](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/82873d93-5b79-4978-a5f6-612e21641817) [![Pub Version (including pre-releases)](https://img.shields.io/pub/v/canteenlib?color=lightblue&include_prereleases&label=latest%20version)](https://pub.dev/packages/canteenlib)
## Funkční funkce(*) ## Funkční funkce(*)
- získání jídelníčku na aktuální den (s cenami) - získání jídelníčku na aktuální den (s cenami)
- Objednání / zrušení objednávek - Objednání / zrušení objednávek
- Nabídnutí jídla do burzy / zrušení - Nabídnutí jídla do burzy / zrušení
- Získání a objednání cizího jídla z burzy
## To do ## To do
- Získání a objednání cizího jídla z burzy
- Kompatibilita se staršími verzemi iCanteen - Kompatibilita se staršími verzemi iCanteen
- Stabilita
*\* Knihovna nemusí fungovat na všech instancích systému iCanteen, proto žádám každého, kdo může a je uživatelem iCanteen, aby otestoval funkčnost této knihovny a případné problémy [nahlásil](https://github.com/hernikplays/canteenlib/issues)* *\* Knihovna nemusí fungovat na všech instancích systému iCanteen, proto žádám každého, kdo může a je uživatelem iCanteen, aby otestoval funkčnost této knihovny a případné problémy [nahlásil](https://github.com/hernikplays/canteenlib/issues)*

View file

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'tridy.dart'; import 'tridy.dart';
@ -35,9 +33,11 @@ class Canteen {
/// Vrátí informace o uživateli ve formě instance [Uzivatel] /// Vrátí informace o uživateli ve formě instance [Uzivatel]
Future<Uzivatel> ziskejUzivatele() async { Future<Uzivatel> ziskejUzivatele() async {
if (!prihlasen) throw Exception("Bez přihlášení"); if (!prihlasen) throw Exception("Uživatel není přihlášený");
var r = await _getRequest("/web/setting"); var r = await _getRequest("/web/setting");
if (r == null) throw Exception("Při požadavku došlo k chybě"); if (r.contains("přihlášení uživatele")) {
throw Exception("Uživatel není přihlášený");
}
var m = double.tryParse(RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)') var m = double.tryParse(RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)')
.firstMatch(r)! .firstMatch(r)!
.group(1)! .group(1)!
@ -72,8 +72,9 @@ class Canteen {
} }
Future<void> getFirstSession() async { Future<void> getFirstSession() async {
if (url.endsWith("/")) if (url.endsWith("/")) {
url = url.substring(0, url.length - 1); // odstranit lomítko url = url.substring(0, url.length - 1);
} // odstranit lomítko
var res = await http.get(Uri.parse(url)); var res = await http.get(Uri.parse(url));
_parseCookies(res.headers['set-cookie']!); _parseCookies(res.headers['set-cookie']!);
} }
@ -134,7 +135,7 @@ class Canteen {
/// Builder pro GET request /// Builder pro GET request
/// V případě chyby na serveru (divný status kód) vyhodí [Exception] /// V případě chyby na serveru (divný status kód) vyhodí [Exception]
Future<String?> _getRequest(String path) async { Future<String> _getRequest(String path) async {
var r = await http.get(Uri.parse(url + path), headers: { var r = await http.get(Uri.parse(url + path), headers: {
"Cookie": "JSESSIONID=" + "Cookie": "JSESSIONID=" +
cookies["JSESSIONID"]! + cookies["JSESSIONID"]! +
@ -161,7 +162,7 @@ class Canteen {
var reg = RegExp( var reg = RegExp(
r'((?=<div class="jidelnicekDen">).+?(?=<div class="jidelnicekDen">))|((?=<div class="jidelnicekDen">).*<\/span>)', r'((?=<div class="jidelnicekDen">).+?(?=<div class="jidelnicekDen">))|((?=<div class="jidelnicekDen">).*<\/span>)',
dotAll: true) dotAll: true)
.allMatches(res!) .allMatches(res)
.toList(); .toList();
List<Jidelnicek> jidelnicek = []; List<Jidelnicek> jidelnicek = [];
for (var t in reg) { for (var t in reg) {
@ -210,7 +211,7 @@ class Canteen {
jidla.add(Jidlo( jidla.add(Jidlo(
nazev: hlavni, nazev: hlavni,
objednano: false, objednano: false,
cislo: vydejna!.group(0).toString(), varianta: vydejna!.group(0).toString(),
lzeObjednat: false, lzeObjednat: false,
den: den, den: den,
naBurze: false)); naBurze: false));
@ -223,10 +224,13 @@ class Canteen {
/// Získá jídlo pro daný den /// Získá jídlo pro daný den
/// Vyžaduje přihlášení pomocí [login] /// Vyžaduje přihlášení pomocí [login]
Future<Jidelnicek> jidelnicekDen({DateTime? den}) async { Future<Jidelnicek> jidelnicekDen({DateTime? den}) async {
if (!prihlasen) {
throw Exception("Uživatel není přihlášen");
}
den ??= DateTime.now(); den ??= DateTime.now();
var res = await _getRequest( var res = await _getRequest(
"/faces/secured/main.jsp?day=${den.year}-${(den.month < 10) ? "0" + den.month.toString() : den.month}-${(den.day < 10) ? "0" + den.day.toString() : den.day}&terminal=false&printer=false&keyboard=false"); "/faces/secured/main.jsp?day=${den.year}-${(den.month < 10) ? "0" + den.month.toString() : den.month}-${(den.day < 10) ? "0" + den.day.toString() : den.day}&terminal=false&printer=false&keyboard=false");
if (res!.contains("<title>iCanteen - přihlášení uživatele</title>")) { if (res.contains("<title>iCanteen - přihlášení uživatele</title>")) {
prihlasen = false; prihlasen = false;
throw Exception("Nepřihlášen"); throw Exception("Nepřihlášen");
} }
@ -286,7 +290,7 @@ class Canteen {
nazev: jidlaProDen[1] nazev: jidlaProDen[1]
.replaceAll(r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''), .replaceAll(r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''),
objednano: objednano, objednano: objednano,
cislo: vydejna, varianta: vydejna,
lzeObjednat: lzeObjednat, lzeObjednat: lzeObjednat,
cena: cena, cena: cena,
orderUrl: orderUrl, orderUrl: orderUrl,
@ -301,18 +305,25 @@ class Canteen {
} }
/// Objedná vybrané jídlo /// Objedná vybrané jídlo
/// Vrátí upravenou instanci [Jidlo], v případě chyby vrací originální ///
/// Vrátí upravenou instanci [Jidlo], v případě chyby vyhodí [Exception]
Future<Jidlo> objednat(Jidlo j) async { Future<Jidlo> objednat(Jidlo j) async {
if (!prihlasen) {
throw Exception("Uživatel není přihlášen");
}
if (!j.lzeObjednat || j.orderUrl == null || j.orderUrl!.isEmpty) { if (!j.lzeObjednat || j.orderUrl == null || j.orderUrl!.isEmpty) {
return j; throw Exception("Jídlo nelze objednat nebo nemá adresu pro objednání");
} }
var res = var res =
await _getRequest("/faces/secured/" + j.orderUrl!); // provést operaci await _getRequest("/faces/secured/" + j.orderUrl!); // provést operaci
if (res == null || res.contains("Chyba")) return j; if (res.contains("Chyba")) throw Exception("Při požadavku došlo k chybě");
if (res.contains("přihlášení uživatele")) {
prihlasen = false;
throw Exception("Uživatel není přihlášen");
}
var novy = await _getRequest( var novy = await _getRequest(
"/faces/secured/db/dbJidelnicekOnDayView.jsp?day=${j.den.year}-${(j.den.month < 10) ? "0" + j.den.month.toString() : j.den.month}-${(j.den.day < 10) ? "0" + j.den.day.toString() : j.den.day}&terminal=false&rating=null&printer=false&keyboard=false"); // získat novou URL pro objednávání "/faces/secured/db/dbJidelnicekOnDayView.jsp?day=${j.den.year}-${(j.den.month < 10) ? "0" + j.den.month.toString() : j.den.month}-${(j.den.day < 10) ? "0" + j.den.day.toString() : j.den.day}&terminal=false&rating=null&printer=false&keyboard=false"); // získat novou URL pro objednávání
if (novy == null) return j;
var lzeObjednat = var lzeObjednat =
!(novy.contains("nelze zrušit") || novy.contains("nelze objednat")); !(novy.contains("nelze zrušit") || novy.contains("nelze objednat"));
String? orderUrl; String? orderUrl;
@ -334,7 +345,7 @@ class Canteen {
} }
return Jidlo( return Jidlo(
cislo: j.cislo, varianta: j.varianta,
nazev: j.nazev, nazev: j.nazev,
objednano: !j.objednano, objednano: !j.objednano,
cena: j.cena, cena: j.cena,
@ -347,19 +358,27 @@ class Canteen {
: !burzaUrl.contains("plusburza")); // vrátit upravenou instanci : !burzaUrl.contains("plusburza")); // vrátit upravenou instanci
} }
/// Uloží jídlo z/do burzy /// Uloží vaše jídlo z/do burzy
/// ///
/// Vrací upravenou instanci [Jidlo], v případě chyby vrací originální /// Vrací upravenou instanci [Jidlo], v případě chyby vyhodí [Exception]
Future<Jidlo> doBurzy(Jidlo j) async { Future<Jidlo> doBurzy(Jidlo j) async {
if (!prihlasen) {
throw Exception("Uživatel není přihlášen");
}
if (j.burzaUrl == null || j.burzaUrl!.isEmpty) { if (j.burzaUrl == null || j.burzaUrl!.isEmpty) {
return j; throw Exception(
"Jídlo nelze uložit do burzy nebo nemá adresu pro uložení");
} }
var res = var res =
await _getRequest("/faces/secured/" + j.burzaUrl!); // provést operaci await _getRequest("/faces/secured/" + j.burzaUrl!); // provést operaci
if (res == null || res.contains("Chyba")) return j; if (res.contains("Chyba")) return j;
if (res.contains("přihlášení uživatele")) {
prihlasen = false;
throw Exception("Uživatel není přihlášen");
}
var novy = await _getRequest( var novy = await _getRequest(
"/faces/secured/db/dbJidelnicekOnDayView.jsp?day=${j.den.year}-${(j.den.month < 10) ? "0" + j.den.month.toString() : j.den.month}-${(j.den.day < 10) ? "0" + j.den.day.toString() : j.den.day}&terminal=false&rating=null&printer=false&keyboard=false"); // získat novou URL pro objednávání "/faces/secured/db/dbJidelnicekOnDayView.jsp?day=${j.den.year}-${(j.den.month < 10) ? "0" + j.den.month.toString() : j.den.month}-${(j.den.day < 10) ? "0" + j.den.day.toString() : j.den.day}&terminal=false&rating=null&printer=false&keyboard=false"); // získat novou URL pro objednávání
if (novy == null) return j;
var lzeObjednat = var lzeObjednat =
!(novy.contains("nelze zrušit") || novy.contains("nelze objednat")); !(novy.contains("nelze zrušit") || novy.contains("nelze objednat"));
String? orderUrl; String? orderUrl;
@ -381,7 +400,7 @@ class Canteen {
} }
return Jidlo( return Jidlo(
cislo: j.cislo, varianta: j.varianta,
nazev: j.nazev, nazev: j.nazev,
objednano: !j.objednano, objednano: !j.objednano,
cena: j.cena, cena: j.cena,
@ -393,4 +412,60 @@ class Canteen {
? false ? false
: !burzaUrl.contains("plusburza")); // vrátit upravenou instanci : !burzaUrl.contains("plusburza")); // vrátit upravenou instanci
} }
/// Získá aktuální jídla v burze
Future<List<Burza>> ziskatBurzu() async {
if (!prihlasen) throw Exception("Uživatel není přihlášen");
List<Burza> burza = [];
var r = await _getRequest("/faces/secured/burza.jsp");
if (r.contains("Chyba")) throw Exception("Při požadavku došlo k chybě");
if (r.contains("přihlášení uživatele")) {
prihlasen = false;
throw Exception("Uživatel není přihlášen");
}
var dostupnaJidla =
RegExp(r'(?<=<tr class="mouseOutRow">).+?(?=<\/tr>)', dotAll: true)
.allMatches(r); // vyfiltrujeme jednotlivá jídla
if (dostupnaJidla.isNotEmpty) {
for (var burzaMatch in dostupnaJidla) {
var bu = burzaMatch.group(0)!;
var data = RegExp(
r'((?<=<td>).+?(?=<))|(?<=<td align="left">).+?(?=<)|((?<=<td align="right">).+?(?=<))',
dotAll: true)
.allMatches(bu)
.toList();
// Získat datum
var datumRaw = RegExp(r'\d\d\.\d\d\.\d{4}')
.firstMatch(data[1].group(0)!)!
.group(0)!
.split(".");
var datum =
DateTime.parse("${datumRaw[2]}-${datumRaw[1]}-${datumRaw[0]}");
// Získat variantu
var varianta = data[0].group(0)!;
// Získat název jídla
var nazev = data[2].group(0)!.replaceAll(RegExp(r'\n| '), "");
// Získat počet kusů
var pocet = int.parse(data[3].group(0)!.replaceAll(" ks", ""));
var url = RegExp(r"(?<=')db.+?(?=')").firstMatch(bu)!.group(0)!;
var jidlo = Burza(
den: datum,
varianta: varianta,
jidlo: nazev,
pocet: pocet,
url: url);
burza.add(jidlo);
}
}
return burza;
}
/// Objedná jídlo z burzy pomocí URL z instance třídy Burza
///
/// Vrací [bool] - true pokud se podařilo objednat, jinak false
Future<bool> objednatZBurzy(Burza b) async {
var res = await _getRequest("/faces/secured/" + b.url!);
if (res.contains("Chyba")) return false;
return true;
}
} }

View file

@ -6,8 +6,8 @@ class Jidlo {
/// Objednal si uživatel toto jídlo? /// Objednal si uživatel toto jídlo?
bool objednano; bool objednano;
/// Název výdejny /// Název varianty
String cislo; String varianta;
/// Cena /// Cena
double? cena; double? cena;
@ -29,7 +29,7 @@ class Jidlo {
Jidlo( Jidlo(
{required this.nazev, {required this.nazev,
required this.objednano, required this.objednano,
required this.cislo, required this.varianta,
required this.den, required this.den,
this.cena, this.cena,
required this.lzeObjednat, required this.lzeObjednat,
@ -38,6 +38,30 @@ class Jidlo {
required this.naBurze}); required this.naBurze});
} }
class Burza {
/// Den, který je jídlo vydáváno
DateTime den;
/// URL pro objednání
final String? url;
/// Název jídla
String jidlo;
/// Varianta
String? varianta;
/// Počet kusů tohoto jídla dostupného na burze
int pocet;
Burza(
{required this.den,
required this.url,
required this.jidlo,
required this.pocet,
this.varianta});
}
/// Reprezentuje jídelníček pro jeden dan /// Reprezentuje jídelníček pro jeden dan
class Jidelnicek { class Jidelnicek {
/// Den, pro který je jídelníček zveřejněn /// Den, pro který je jídelníček zveřejněn

View file

@ -1,6 +1,6 @@
name: canteenlib name: canteenlib
description: Knihovna pro komunikaci se stravovacím systémem iCanteen description: Knihovna pro komunikaci se stravovacím systémem iCanteen s možností objednávání jídla
version: 0.1.0-alpha.3 version: 0.1.0-alpha.4
repository: 'https://github.com/hernikplays/canteenlib' repository: 'https://github.com/hernikplays/canteenlib'
issue_tracker: 'https://github.com/hernikplays/canteenlib/issues' issue_tracker: 'https://github.com/hernikplays/canteenlib/issues'