Compare commits

...

37 commits

Author SHA1 Message Date
Matyáš Caras cd14eb62f3 Update README.md 2023-10-14 21:02:40 +02:00
Matyáš Caras 7ea3df0b2b
BREAKING: změnit alergeny na třídu, opravit propisování 2023-10-06 13:24:47 +02:00
Matyáš Caras 58db9adf6e
fix(burza): opravit burzaUrl u multiburza 2023-09-12 22:26:12 +02:00
Matyáš Caras 359cd64dc6
chore: 🔖 bump verze 2023-09-04 18:57:31 +02:00
Matyáš Caras 637744236c
fix: Negativní čísla v kreditu, účet pro platby
Merge pull request #4 from tpkowastaken/uzivatel-fix
2023-09-04 16:52:05 +00:00
tpkowastaken 5d45fdf4bd fix: Negativní čísla v kreditu, účet pro platby 2023-09-03 23:01:17 +02:00
Matyáš Caras eb13ce2e41 docs: upravit příklad 2023-04-07 18:22:13 +02:00
Matyáš Caras 817236c98d docs: upravit README 2023-04-07 18:22:05 +02:00
Matyáš Caras 2e8fb36f26 fix: získávat všechny alergeny (#6) 2023-04-07 18:15:13 +02:00
Matyáš Caras 15d5b02073 chore: odstranit cz 2023-04-07 18:14:06 +02:00
Matyáš Caras a7fa593d15 docs: upravit odkazy 2023-03-08 17:38:35 +01:00
Matyáš Caras 616a84d983 docs: změnit odkazy 2023-03-08 17:37:29 +01:00
Matyáš Caras 3576d5ce28 docs: přidat odkazy do kompatibility 2023-03-08 17:36:27 +01:00
Matyáš Caras d098965883 Merge pull request 'fix: opravit chybu s burzou' (#5) from burzafix into main
Reviewed-on: #5
2022-12-14 18:37:38 +00:00
Matyáš Caras 0d4c597ad2 fix: opravit chybu s burzou 2022-12-14 19:33:40 +01:00
Matyáš Caras 1996707ee4 Merge branch 'main' into burzafix 2022-12-14 19:32:09 +01:00
Matyáš Caras c914984deb Merge pull request 'feat: znealfovat verzi 1.1.0' (#4) from spsei into main
Reviewed-on: #4
2022-12-14 18:30:33 +00:00
Matyáš Caras 91cbf2d390 chore: bump version 2022-12-14 18:56:20 +01:00
Matyáš Caras d0a76eb28d feat: experimentální podpora SPšEI ostrava
Přidává podporu pro SPšEI Ostrava a zobrazení alergenů

#2
2022-10-30 11:15:13 +01:00
Matyáš Caras 97ae7a0be4
Merge pull request #3 from hernikplays/main
ci: vytvořit základní dart CI
2022-10-25 07:07:43 +00:00
Matyáš Caras ba83fcedd1
ci: vytvořit základní dart CI 2022-10-25 09:07:19 +02:00
Matyáš Caras e50e756195
docs: aktualizace kompatibility 2022-10-22 19:59:42 +00:00
Matyáš Caras 1055c44aa3
docs: aktualizace kompatibility 2022-10-22 19:59:24 +00:00
Matyáš Caras 7560af2d6f
docs: aktualizovat issue template 2022-10-05 12:58:58 +00:00
Matyáš Caras abc5a44738 chore(pub): aktualizovat changelog a přidat node soubory do pubignore 2022-10-04 16:46:49 +02:00
Matyáš Caras fa3f5d94a9 fix: změnit získávání názvu jídla a aktualizovat závislosti 2022-10-04 16:45:09 +02:00
Matyáš Caras 94a5451052 chore: přidat commitizen 2022-10-04 16:44:18 +02:00
Matyáš Caras f14ca49886
docs: aktualizovat kompatibilitu 2022-09-04 09:42:35 +00:00
Matyáš Caras 96710617de fix: bump verze 2022-09-04 11:39:04 +02:00
Matyáš Caras 334a74f808 fix: čitelnější kód 2022-09-04 11:38:22 +02:00
Matyáš Caras 32c80ad552 fix: vyhazovat chybu místo false u burzy 2022-06-02 15:25:39 +02:00
Matyáš Caras 77d54f4a3f
Aktualizovat kompatibilitu 2022-05-02 09:59:47 +00:00
Matyáš Caras 5673fa6328 CHANGELOG verze 2022-05-02 11:58:46 +02:00
Matyáš Caras 973d4b43a5 Opravit zobrazení objednání 2022-05-02 11:58:15 +02:00
Matyáš Caras 82f2197a28 Práce na #1 2022-04-20 16:13:24 +02:00
Matyáš Caras 9e03d33ad2 Lepší zacházení s chybami 2022-04-12 14:25:21 +02:00
Matyáš Caras c3333fca95 Přidat fail jako chybu 2022-04-09 17:52:54 +02:00
13 changed files with 313 additions and 129 deletions

View file

@ -16,10 +16,14 @@ assignees: hernikplays
- [ ] ziskejJidelnicek
- [ ] jidelnicekDen
- [ ] objednat
- [ ] doBurzy
- [ ] objednatZBurzy
- [ ] ziskatBurzu
- [ ] ziskejUzivatele
**V případě nefunkčnosti některé z metod vkládejte sem chybové hlášky a váš kód**
*Příklad:*
- *chybová hláška pro `login`*
- *chybová hláška pro `jidelnicekDen`*
- *chybová hláška pro `objednat`*
- *chybová hláška pro `objednat`*

42
.github/workflows/dart.yml vendored Normal file
View file

@ -0,0 +1,42 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Dart check
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Note: This workflow uses the latest stable version of the Dart SDK.
# You can specify other versions if desired, see documentation here:
# https://github.com/dart-lang/setup-dart/blob/main/README.md
# - uses: dart-lang/setup-dart@v1
- uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603
- name: Install dependencies
run: dart pub get
# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .
# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: dart analyze
# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
#- name: Run tests
# run: dart test

4
.gitignore vendored
View file

@ -9,4 +9,6 @@ build/
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
.env*
*.test.dart
*.test.dart
node_modules/

View file

@ -1,3 +1,5 @@
.env
test
*.test.dart
*.test.dart
node_modules
package*.json

View file

@ -1,3 +1,30 @@
## 2.0.0
- Alergeny jsou nyní ve tříde `Alergen`
- Opravena chyba, kdy se HTML alergenů propisovalo do názvu jídla
## 1.1.4
- Opravit info o stavu na burze
## 1.1.3
- Opravit hledání burza URL u jídelen, kde je tlačítko ve tvaru `X ks do burzy`
## 1.1.2
- Opravit negativní čísla v kreditu, účet pro platby by @tpkowastaken in https://github.com/hernikplays/canteenlib/pull/4
## 1.1.1
- Opravit problém s burzou
## 1.1.0-alpha.1
- Experimentální podpora pro SPŠEI Ostrava
- Hezčí kód
- Alergeny
## 1.0.1
- změnit získávání názvu jídla
## 1.0.0
- Stabilizace
## 0.1.0-alpha.17
- Debug informace v `objednatZBurzy`
## 0.1.0-alpha.16
- Opravit zobrazení zda-li jde jídlo objednat, když není objednané žádné jídlo
## 0.1.0-alpha.15
- Úprava nakládání s chybami v `_getRequest`
- `fail` je chyba
## 0.1.0-alpha.14
- Oprava `ziskejBurzu`, kvůli špatnému parsování
## 0.1.0-alpha.13

View file

@ -3,13 +3,16 @@ V následující tabulce naleznete instance iCanteen, které byly testovány pro
Výchozí verze, pro kterou aktuálně je knihovna tvořena, je **2.18.19**
Kantýny, které v adrese obsahují i číslo portu, dokážou být často problémové.
- ❌ - nefunkční nebo netestováno
- ✅ - plně funkční nebo pouze s malými chybami
- ❓ - částečně funkční
| Provozovatel | Verze iCanteen | Funkční | Verze knihovny |
|:--------------:|------------------|---------|----------------|
| SŠTE Brno | iCanteen 2.18.19 | ✅ | 0.1.0-alpha.7 |
| SPŠ Třebíč | iCanteen 2.10.25 | ❓ | 0.1.0-alpha |
| Provozovatel | Verze iCanteen | Funkční | Verze knihovny | Adresa |
|:--------------:|------------------|---------|----------------|---------|
| SŠTE Brno | iCanteen 2.19.13 | ✅ | 2.0.0 | https://stravovani.sstebrno.cz
| SPŠ Třebíč | iCanteen 2.10.25 | ❌ | 0.1.0-alpha | https://icanteen.spst.cz
| SPŠEI Ostrava | iCanteen 2.17.03 | ❌ [zde](https://git.mnau.xyz/hernik/canteenlib/issues/2) | 1.0.1 | https://obedy.spseiostrava.cz:8443/
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://git.mnau.xyz/hernik/canteenlib/issues/new?template=.github%2fISSUE_TEMPLATE%2fhl--en--kompatibility.md)

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Matyáš Caras and contributors
Copyright (c) 2022 Matyáš Caras
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,3 +1,6 @@
## INFO
__Tato verze knihovny není dále vyvíjena. Vývoj teď probíhá na https://github.com/tpkowastaken/canteenlib__
## O knihovně
Experimentální **neoficiální** webscrape knihovna pro komunikaci se systémem [iCanteen](https://www.z-ware.cz/internetove-objednavky). **Knihovna je aktuálně nestabilní! Používejte na vlastní riziko!**
@ -12,7 +15,34 @@ Experimentální **neoficiální** webscrape knihovna pro komunikaci se systéme
## To do
- Kompatibilita se staršími verzemi iCanteen
*\* 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)*
Příklad používání [zde](https://git.mnau.xyz/hernik/canteenlib/src/branch/main/example/canteenlib_example.dart)
*\* 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://git.mnau.xyz/hernik/canteenlib/issues/new)*
### Otestované instance iCanteen
[zde](https://github.com/hernikplays/canteenlib/blob/main/COMPATIBILITY.md)
[zde](https://git.mnau.xyz/hernik/canteenlib/src/branch/main/COMPATIBILITY.md)
## Licence
```
MIT License
Copyright (c) 2022 Matyáš Caras
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.
```

View file

@ -1,20 +1,15 @@
import 'package:canteenlib/canteenlib.dart';
void main(List<String> args) {
Canteen c = Canteen("https://kantyna.neco.cz");
c.login("uzivatel", "heslo").then((value) {
c.jidelnicekDen(den: DateTime.parse("2022-04-04")).then((t) async {
print((await c.ziskejUzivatele()).kredit);
c.objednat(t.jidla[0]).then(
(value) {
t.jidla[0] = value; // divně udělané ale nic lepšího teď nevymyslím
print(t.jidla[0].objednano);
print(t.jidla[0].orderUrl);
},
);
});
}).catchError((o) {
print(o);
return null;
});
void main(List<String> args) async {
Canteen c = Canteen(
"https://kantyna.neco.cz"); // vytvořit instanci kantýny, všechna komunikace probíhá skrz ni
try {
await c.login("uzivatel", "heslo"); // přihlásit se
var jidelnicek = await c.jidelnicekDen(den: DateTime.parse("2022-04-04"));
print((await c.ziskejUzivatele()).kredit);
var objednano = await c.objednat(jidelnicek.jidla[0]);
print(objednano.objednano);
} catch (e) {
print("Při získávání informací nastala chyba: $e");
}
}

View file

@ -48,17 +48,20 @@ class Canteen {
prihlasen = false;
return Future.error("Uživatel není přihlášen");
}
var m = double.tryParse(RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)')
.firstMatch(r)!
.group(1)!
.replaceAll(",", ".")
.replaceAll(RegExp(r"[^\w.]"), ""));
var kreditMatch = double.tryParse(
RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)')
.firstMatch(r)!
.group(1)!
.replaceAll(",", ".")
.replaceAll(RegExp(r"[^\w.-]"), ""));
var jmenoMatch = RegExp(r'(?<=jméno: <b>).+?(?=<\/b)').firstMatch(r);
var prijmeniMatch = RegExp(r'(?<=příjmení: <b>).+?(?=<\/b)').firstMatch(r);
var kategorieMatch =
RegExp(r'(?<=kategorie: <b>).+?(?=<\/b)').firstMatch(r);
var ucetMatch = RegExp(r'(?<=účet pro platby do jídelny: <b>).+?(?=<\/b)')
.firstMatch(r);
var ucetMatch = RegExp(r'účet pro platby do jídelny:\s*<b>(\d+/\d+)</b>')
.firstMatch(r)
?.group(1)
?.replaceAll(RegExp(r'<\/?b>'), ''); //odstranit html tag <b>
var varMatch =
RegExp(r'(?<=variabilní symbol: <b>).+?(?=<\/b)').firstMatch(r);
var specMatch =
@ -67,9 +70,10 @@ class Canteen {
var jmeno = jmenoMatch?.group(0) ?? "";
var prijmeni = prijmeniMatch?.group(0) ?? "";
var kategorie = kategorieMatch?.group(0) ?? "";
var ucet = ucetMatch?.group(0) ?? "";
var ucet = ucetMatch ?? "";
var varSymbol = varMatch?.group(0) ?? "";
var specSymbol = specMatch?.group(0) ?? "";
var kredit = kreditMatch ?? 0.0;
return Uzivatel(
jmeno: jmeno,
@ -78,7 +82,7 @@ class Canteen {
ucetProPlatby: ucet,
varSymbol: varSymbol,
specSymbol: specSymbol,
kredit: m ?? 0.0);
kredit: kredit);
}
Future<void> _getFirstSession() async {
@ -114,14 +118,11 @@ class Canteen {
if (cookies["JSESSIONID"] == "" || cookies["XSRF-TOKEN"] == "") {
await _getFirstSession();
}
var res =
await http.post(Uri.parse(url + "/j_spring_security_check"), headers: {
"Cookie": "JSESSIONID=" +
cookies["JSESSIONID"]! +
"; " +
"XSRF-TOKEN=" +
cookies["XSRF-TOKEN"]! +
";",
await http.post(Uri.parse("$url/j_spring_security_check"), headers: {
"Cookie":
"JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!};",
"Content-Type": "application/x-www-form-urlencoded",
}, body: {
"j_username": user,
@ -132,9 +133,11 @@ class Canteen {
"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}");
}
@ -147,21 +150,25 @@ class Canteen {
/// Builder pro GET request
Future<String> _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"]! + ";"
: ";"),
"Cookie":
"JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!}${cookies.containsKey("remember-me") ? "; ${cookies["remember-me"]!};" : ";"}",
});
if (r.statusCode != 200) {
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("Uživatel není přihlášen");
}
if (r.headers.containsKey("set-cookie")) {
_parseCookies(r.headers["set-cookie"]!);
}
return r.body;
}
@ -178,14 +185,12 @@ class Canteen {
dotAll: true)
.allMatches(res)
.toList();
List<Jidelnicek> jidelnicek = [];
for (var t in reg) {
// projedeme každý den individuálně
var j = t
.group(0)
.toString() /*.replaceAll(RegExp(r'( )+|([^>a-z]\n)'),
'')*/
; // převedeme text na něco přehlednějšího
var j = t.group(0).toString(); // převedeme text na něco přehlednějšího
var den = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
.firstMatch(j)!
.group(0)
@ -204,24 +209,28 @@ class Canteen {
}
List<Jidlo> jidla = [];
for (var jidloNaDen in jidlaDenne) {
// projedeme vsechna jidla
var s = jidloNaDen.group(0)!.replaceAll(
RegExp(
r'[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:] [a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:]'),
''); // odstraní dvojté mezery mezi písmeny
var vydejna = RegExp(r'(?<=<span style="color: #1b75bb;">).+?(?=<)')
.firstMatch(s); // název výdejny / verze 2.18
vydejna ??= RegExp(
// TODO: Lepší systém pro podporu různých verzí iCanteen
r'(?<=<span class="smallBoldTitle" style="color: #1b75bb;">).+?(?=<)')
.firstMatch(s); // název výdejny / verze 2.10
var hlavni = RegExp(
r' {20}(([a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+ )+[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+)',
dotAll: true)
.firstMatch(s)!
.group(1)
.toString(); // Jídlo
jidla.add(Jidlo(
nazev: hlavni,
objednano: false,
@ -248,22 +257,27 @@ class Canteen {
if (!prihlasen) {
return Future.error("Uživatel není přihlášen");
}
den ??= DateTime.now();
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");
if (res.contains("<title>iCanteen - přihlášení uživatele</title>")) {
prihlasen = false;
return Future.error("Uživatel není přihlášen");
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);
}
var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
.firstMatch(res)!
.group(0)
.toString());
var jidla = <Jidlo>[];
var jidelnicek =
RegExp(r'(?<=<div class="jidWrapLeft">).+?((fa-clock))', dotAll: true)
.allMatches(res)
.toList();
var jidelnicek = RegExp(
r'(?<=<div class="jidWrapLeft">).+?((fa-clock)|(fa-ban))',
dotAll: true)
.allMatches(res)
.toList();
for (var obed in jidelnicek) {
// formátování do třídy
var o = obed
@ -271,28 +285,48 @@ class Canteen {
.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"));
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);
RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o);
cenaMatch ??=
RegExp(r'(?<=Cena při objednání jídla:&nbsp;).+?(?=&)').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'(?<=Polévka: ).+')
.firstMatch(o)!
.group(0)
.toString()
.replaceAll(' ,', ",")
.replaceAll(" <br>", "")
.split(" / ");
var jidlaProDen =
RegExp(r'<div class="jidWrapCenter.+?>(.+?)(?=<\/div>)', dotAll: true)
.firstMatch(o)!
.group(1)
.toString()
.replaceAll(' ,', ",")
.replaceAll(" <br>", "")
.replaceAll("\n", "");
var alergenyList =
RegExp(r"""<span(?: |\n).+?title="(.+?)".+?>(\d{1,2})""")
.allMatches(jidlaProDen)
.toList();
var alergeny = alergenyList.map<Alergen>((e) {
var jmeno = RegExp(r'<b>(.+?)<\/b>')
.firstMatch(e.group(1).toString())!
.group(1);
var popis =
RegExp(r'<\/b> - (.+)').firstMatch(e.group(1).toString())?.group(1);
var kod = int.parse(e.group(2).toString());
return Alergen(nazev: jmeno!, kod: kod, popis: popis);
}).toList();
var vydejna = RegExp(
r'(?<=<span class="smallBoldTitle button-link-align">).+?(?=<)')
.firstMatch(o)!
.group(0)
.toString();
String? orderUrl;
String? burzaUrl;
if (lzeObjednat) {
@ -304,24 +338,31 @@ class Canteen {
} else {
// jinak nastavíme URL pro burzu
var match = RegExp(
r"(?<=ajaxOrder\(this, ')(.+?)(?=').+?((do burzy)|(z burzy))")
r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)|(multiburza)).+?(?=')""")
.firstMatch(o);
if (match != null) {
burzaUrl = match.group(1)!.replaceAll("amp;", "");
burzaUrl = match.group(0)!.replaceAll("amp;", "");
}
}
jidla.add(Jidlo(
nazev: jidlaProDen[1]
.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("plusburza")));
var jidloJmeno = RegExp(r'(.+?)(?=<sub>)')
.firstMatch(jidlaProDen)!
.group(1)
.toString();
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),
);
// KONEC formátování do třídy
}
@ -339,18 +380,16 @@ class Canteen {
if (!prihlasen) {
return Future.error("Uživatel není přihlášen");
}
if (!j.lzeObjednat || j.orderUrl == null || j.orderUrl!.isEmpty) {
return Future.error(
"Jídlo nelze objednat nebo nemá adresu pro objednání");
}
var res =
await _getRequest("/faces/secured/" + j.orderUrl!); // provést operaci
if (res.contains("Chyba")) {
return Future.error("Při požadavku došlo k chybě");
}
if (res.contains("přihlášení uživatele")) {
prihlasen = false;
return Future.error("Uživatel není přihlášen");
try {
await _getRequest("/faces/secured/${j.orderUrl!}"); // provést operaci
} catch (e) {
return Future.error(e);
}
var novy = (await jidelnicekDen(den: j.den))
@ -370,20 +409,25 @@ class Canteen {
///
/// Výstup:
/// - Aktualizovaná instance [Jidlo] tohoto jídla NEBO [Future] jako chyba
Future<Jidlo> doBurzy(Jidlo j) async {
Future<Jidlo> doBurzy(Jidlo j, {int amount = 1}) async {
if (!prihlasen) {
return Future.error("Uživatel není přihlášen");
}
if (j.burzaUrl == null || j.burzaUrl!.isEmpty) {
return Future.error(
"Jídlo nelze uložit do burzy nebo nemá adresu pro uložení");
}
var res =
await _getRequest("/faces/secured/" + j.burzaUrl!); // provést operaci
if (res.contains("Chyba")) return Future.error("Chyba při vykonávání");
if (res.contains("přihlášení uživatele")) {
prihlasen = false;
return Future.error("Uživatel není přihlášen");
if (amount < 1 && j.burzaUrl!.endsWith("amount=")) {
return Future.error("Nemůžeš dát do burzy méně než jeden kus");
}
var finalUrl =
(j.burzaUrl!.endsWith("amount=")) ? "${j.burzaUrl}$amount" : j.burzaUrl;
try {
await _getRequest("/faces/secured/$finalUrl"); // provést operaci
} catch (e) {
return Future.error(e);
}
var novy = (await jidelnicekDen(den: j.den))
@ -403,15 +447,17 @@ class Canteen {
Future<List<Burza>> ziskatBurzu() async {
if (!prihlasen) return Future.error("Uživatel není přihlášen");
List<Burza> burza = [];
var r = await _getRequest("/faces/secured/burza.jsp");
if (r.contains("Chyba")) return Future.error("Při požadavku došlo k chybě");
if (r.contains("přihlášení uživatele")) {
prihlasen = false;
return Future.error("Uživatel není přihlášen");
String res;
try {
res = await _getRequest("/faces/secured/burza.jsp");
} catch (e) {
return Future.error(e);
}
var dostupnaJidla =
RegExp(r'(?<=<tr class="mouseOutRow">).+?(?=<\/tr>)', dotAll: true)
.allMatches(r); // vyfiltrujeme jednotlivá jídla
.allMatches(res); // vyfiltrujeme jednotlivá jídla
if (dostupnaJidla.isNotEmpty) {
for (var burzaMatch in dostupnaJidla) {
var bu = burzaMatch.group(0)!;
@ -420,6 +466,7 @@ class Canteen {
dotAll: true)
.allMatches(bu)
.toList();
// Získat datum
var datumRaw = RegExp(r'\d\d\.\d\d\.\d{4}')
.firstMatch(data[1].group(0)!)!
@ -433,7 +480,11 @@ class Canteen {
var nazev = data[2].group(0)!.replaceAll(RegExp(r'\n| '), "");
// Získat počet kusů
var pocet = int.parse(data[4].group(0)!.replaceAll(" ks", ""));
var url = RegExp(r"(?<=')db.+?(?=')").firstMatch(bu)!.group(0)!;
var url = RegExp(r"(?<=')db.+?(?=')")
.firstMatch(bu)!
.group(0)!
.replaceAll("&amp;", "&");
var jidlo = Burza(
den: datum,
varianta: varianta,
@ -452,11 +503,14 @@ class Canteen {
/// - `b` - Jídlo __z burzy__, které chceme objednat | [Burza]
///
/// Výstup:
/// - [bool], `true`, pokud bylo jídlo úspěšně objednáno z burzy, jinak `false`
/// - [bool], `true`, pokud bylo jídlo úspěšně objednáno z burzy, jinak `Exception`
Future<bool> objednatZBurzy(Burza b) async {
if (!prihlasen) return Future.error("Uživatel není přihlášen");
var res = await _getRequest("/faces/secured/" + b.url!);
if (res.contains("Chyba")) return false;
try {
await _getRequest("/faces/secured/${b.url!}");
} catch (e) {
return Future.error(e.toString());
}
return true;
}
}

View file

@ -21,6 +21,11 @@ class Jidlo {
/// Den, který je jídlo vydáváno
DateTime den;
/// Seznam alergenů
///
/// Pokud se žádný nepodařilo najít, vrací prázdný seznam
List<Alergen> alergeny;
/// URL pro požadavek na objednání jídla
final String? orderUrl;
@ -31,6 +36,7 @@ class Jidlo {
required this.objednano,
required this.varianta,
required this.den,
this.alergeny = const [],
this.cena,
required this.lzeObjednat,
this.orderUrl,
@ -38,6 +44,15 @@ class Jidlo {
required this.naBurze});
}
/// Popisuje alergen v jídelníčku
class Alergen {
final int kod;
final String nazev;
final String? popis;
const Alergen({required this.nazev, required this.kod, this.popis});
}
/// Reprezentuje cizí jídlo na burze
class Burza {
/// Den, který je jídlo vydáváno

View file

@ -1,16 +1,15 @@
name: canteenlib
description: Library for communication with the czech canteen food ordering system iCanteen
version: 0.1.0-alpha.14
repository: 'https://github.com/hernikplays/canteenlib'
issue_tracker: 'https://github.com/hernikplays/canteenlib/issues'
documentation: 'https://docs.hernikplays.cz'
version: 2.0.0
repository: 'https://git.mnau.xyz/hernik/canteenlib'
issue_tracker: 'https://git.mnau.xyz/hernik/canteenlib/issues'
environment:
sdk: '>=2.16.1 <3.0.0'
sdk: '>=2.16.1 <4.0.0'
dev_dependencies:
dotenv: ^3.0.0
lints: ^1.0.0
dotenv: ^4.0.1
lints: ^2.0.0
test: ^1.16.0
dependencies:
http: ^0.13.4

View file

@ -1,19 +1,30 @@
import 'package:canteenlib/canteenlib.dart';
import 'package:test/test.dart';
import 'package:dotenv/dotenv.dart' show load, env;
import 'package:dotenv/dotenv.dart';
void main() {
group('A group of tests', () {
load();
var env = DotEnv(includePlatformEnvironment: true)..load();
Canteen c = Canteen(env["ADDRESS"]!);
setUp(() {
c.login(env["USER"]!, env["PASS"]!);
test('Log-in test', () {
c.login(env["USER"]!, env["PASS"]!).then((r) => expect(r, true));
});
test('First Test', () {
c.jidelnicekDen().then((t) {
expect(DateTime.now().day, t.den.day);
c.login(env["USER"]!, env["PASS"]!).then((r) {
c.jidelnicekDen().then((t) {
expect(DateTime.now().day, t.den.day);
});
});
});
test('Neprázdný jídelníček', () {
c.login(env["USER"]!, env["PASS"]!).then((r) {
c.jidelnicekDen(den: DateTime.now().add(Duration(days: 5))).then((t) {
print(t.jidla[0].nazev);
expect(t.jidla[0].nazev.isNotEmpty, true);
});
});
});
});