Compare commits
31 commits
0.1.0-alph
...
main
Author | SHA1 | Date | |
---|---|---|---|
cd14eb62f3 | |||
7ea3df0b2b | |||
58db9adf6e | |||
359cd64dc6 | |||
637744236c | |||
5d45fdf4bd | |||
eb13ce2e41 | |||
817236c98d | |||
2e8fb36f26 | |||
15d5b02073 | |||
a7fa593d15 | |||
616a84d983 | |||
3576d5ce28 | |||
d098965883 | |||
0d4c597ad2 | |||
1996707ee4 | |||
c914984deb | |||
91cbf2d390 | |||
d0a76eb28d | |||
97ae7a0be4 | |||
ba83fcedd1 | |||
e50e756195 | |||
1055c44aa3 | |||
7560af2d6f | |||
abc5a44738 | |||
fa3f5d94a9 | |||
94a5451052 | |||
f14ca49886 | |||
96710617de | |||
334a74f808 | |||
32c80ad552 |
|
@ -16,10 +16,14 @@ assignees: hernikplays
|
||||||
- [ ] ziskejJidelnicek
|
- [ ] ziskejJidelnicek
|
||||||
- [ ] jidelnicekDen
|
- [ ] jidelnicekDen
|
||||||
- [ ] objednat
|
- [ ] objednat
|
||||||
|
- [ ] doBurzy
|
||||||
|
- [ ] objednatZBurzy
|
||||||
|
- [ ] ziskatBurzu
|
||||||
|
- [ ] ziskejUzivatele
|
||||||
|
|
||||||
**V případě nefunkčnosti některé z metod vkládejte sem chybové hlášky a váš kód**
|
**V případě nefunkčnosti některé z metod vkládejte sem chybové hlášky a váš kód**
|
||||||
|
|
||||||
*Příklad:*
|
*Příklad:*
|
||||||
- *chybová hláška pro `login`*
|
- *chybová hláška pro `login`*
|
||||||
- *chybová hláška pro `jidelnicekDen`*
|
- *chybová hláška pro `jidelnicekDen`*
|
||||||
- *chybová hláška pro `objednat`*
|
- *chybová hláška pro `objednat`*
|
||||||
|
|
42
.github/workflows/dart.yml
vendored
Normal file
42
.github/workflows/dart.yml
vendored
Normal 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
4
.gitignore
vendored
|
@ -9,4 +9,6 @@ build/
|
||||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
.env*
|
.env*
|
||||||
*.test.dart
|
*.test.dart
|
||||||
|
|
||||||
|
node_modules/
|
|
@ -1,3 +1,5 @@
|
||||||
.env
|
.env
|
||||||
test
|
test
|
||||||
*.test.dart
|
*.test.dart
|
||||||
|
node_modules
|
||||||
|
package*.json
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,3 +1,25 @@
|
||||||
|
## 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
|
## 0.1.0-alpha.16
|
||||||
- Opravit zobrazení zda-li jde jídlo objednat, když není objednané žádné jídlo
|
- Opravit zobrazení zda-li jde jídlo objednat, když není objednané žádné jídlo
|
||||||
## 0.1.0-alpha.15
|
## 0.1.0-alpha.15
|
||||||
|
|
|
@ -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**
|
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
|
- ❌ - nefunkční nebo netestováno
|
||||||
- ✅ - plně funkční nebo pouze s malými chybami
|
- ✅ - plně funkční nebo pouze s malými chybami
|
||||||
- ❓ - částečně funkční
|
- ❓ - částečně funkční
|
||||||
|
|
||||||
| Provozovatel | Verze iCanteen | Funkční | Verze knihovny |
|
| Provozovatel | Verze iCanteen | Funkční | Verze knihovny | Adresa |
|
||||||
|:--------------:|------------------|---------|----------------|
|
|:--------------:|------------------|---------|----------------|---------|
|
||||||
| SŠTE Brno | iCanteen 2.18.19 | ✅ | 0.1.0-alpha.16 |
|
| 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 |
|
| 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)
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
34
README.md
34
README.md
|
@ -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ě
|
## 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!**
|
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
|
## To do
|
||||||
- Kompatibilita se staršími verzemi iCanteen
|
- 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
|
### 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.
|
||||||
|
```
|
|
@ -1,20 +1,15 @@
|
||||||
import 'package:canteenlib/canteenlib.dart';
|
import 'package:canteenlib/canteenlib.dart';
|
||||||
|
|
||||||
void main(List<String> args) {
|
void main(List<String> args) async {
|
||||||
Canteen c = Canteen("https://kantyna.neco.cz");
|
Canteen c = Canteen(
|
||||||
c.login("uzivatel", "heslo").then((value) {
|
"https://kantyna.neco.cz"); // vytvořit instanci kantýny, všechna komunikace probíhá skrz ni
|
||||||
c.jidelnicekDen(den: DateTime.parse("2022-04-04")).then((t) async {
|
try {
|
||||||
print((await c.ziskejUzivatele()).kredit);
|
await c.login("uzivatel", "heslo"); // přihlásit se
|
||||||
c.objednat(t.jidla[0]).then(
|
var jidelnicek = await c.jidelnicekDen(den: DateTime.parse("2022-04-04"));
|
||||||
(value) {
|
print((await c.ziskejUzivatele()).kredit);
|
||||||
t.jidla[0] = value; // divně udělané ale nic lepšího teď nevymyslím
|
var objednano = await c.objednat(jidelnicek.jidla[0]);
|
||||||
print(t.jidla[0].objednano);
|
print(objednano.objednano);
|
||||||
print(t.jidla[0].orderUrl);
|
} catch (e) {
|
||||||
},
|
print("Při získávání informací nastala chyba: $e");
|
||||||
);
|
}
|
||||||
});
|
|
||||||
}).catchError((o) {
|
|
||||||
print(o);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,17 +48,20 @@ class Canteen {
|
||||||
prihlasen = false;
|
prihlasen = false;
|
||||||
return Future.error("Uživatel není přihlášen");
|
return Future.error("Uživatel není přihlášen");
|
||||||
}
|
}
|
||||||
var m = double.tryParse(RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)')
|
var kreditMatch = double.tryParse(
|
||||||
.firstMatch(r)!
|
RegExp(r' +<span id="Kredit" .+?>(.+?)(?=&)')
|
||||||
.group(1)!
|
.firstMatch(r)!
|
||||||
.replaceAll(",", ".")
|
.group(1)!
|
||||||
.replaceAll(RegExp(r"[^\w.]"), ""));
|
.replaceAll(",", ".")
|
||||||
|
.replaceAll(RegExp(r"[^\w.-]"), ""));
|
||||||
var jmenoMatch = RegExp(r'(?<=jméno: <b>).+?(?=<\/b)').firstMatch(r);
|
var jmenoMatch = RegExp(r'(?<=jméno: <b>).+?(?=<\/b)').firstMatch(r);
|
||||||
var prijmeniMatch = RegExp(r'(?<=příjmení: <b>).+?(?=<\/b)').firstMatch(r);
|
var prijmeniMatch = RegExp(r'(?<=příjmení: <b>).+?(?=<\/b)').firstMatch(r);
|
||||||
var kategorieMatch =
|
var kategorieMatch =
|
||||||
RegExp(r'(?<=kategorie: <b>).+?(?=<\/b)').firstMatch(r);
|
RegExp(r'(?<=kategorie: <b>).+?(?=<\/b)').firstMatch(r);
|
||||||
var ucetMatch = RegExp(r'(?<=účet pro platby do jídelny: <b>).+?(?=<\/b)')
|
var ucetMatch = RegExp(r'účet pro platby do jídelny:\s*<b>(\d+/\d+)</b>')
|
||||||
.firstMatch(r);
|
.firstMatch(r)
|
||||||
|
?.group(1)
|
||||||
|
?.replaceAll(RegExp(r'<\/?b>'), ''); //odstranit html tag <b>
|
||||||
var varMatch =
|
var varMatch =
|
||||||
RegExp(r'(?<=variabilní symbol: <b>).+?(?=<\/b)').firstMatch(r);
|
RegExp(r'(?<=variabilní symbol: <b>).+?(?=<\/b)').firstMatch(r);
|
||||||
var specMatch =
|
var specMatch =
|
||||||
|
@ -67,9 +70,10 @@ class Canteen {
|
||||||
var jmeno = jmenoMatch?.group(0) ?? "";
|
var jmeno = jmenoMatch?.group(0) ?? "";
|
||||||
var prijmeni = prijmeniMatch?.group(0) ?? "";
|
var prijmeni = prijmeniMatch?.group(0) ?? "";
|
||||||
var kategorie = kategorieMatch?.group(0) ?? "";
|
var kategorie = kategorieMatch?.group(0) ?? "";
|
||||||
var ucet = ucetMatch?.group(0) ?? "";
|
var ucet = ucetMatch ?? "";
|
||||||
var varSymbol = varMatch?.group(0) ?? "";
|
var varSymbol = varMatch?.group(0) ?? "";
|
||||||
var specSymbol = specMatch?.group(0) ?? "";
|
var specSymbol = specMatch?.group(0) ?? "";
|
||||||
|
var kredit = kreditMatch ?? 0.0;
|
||||||
|
|
||||||
return Uzivatel(
|
return Uzivatel(
|
||||||
jmeno: jmeno,
|
jmeno: jmeno,
|
||||||
|
@ -78,7 +82,7 @@ class Canteen {
|
||||||
ucetProPlatby: ucet,
|
ucetProPlatby: ucet,
|
||||||
varSymbol: varSymbol,
|
varSymbol: varSymbol,
|
||||||
specSymbol: specSymbol,
|
specSymbol: specSymbol,
|
||||||
kredit: m ?? 0.0);
|
kredit: kredit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getFirstSession() async {
|
Future<void> _getFirstSession() async {
|
||||||
|
@ -114,14 +118,11 @@ class Canteen {
|
||||||
if (cookies["JSESSIONID"] == "" || cookies["XSRF-TOKEN"] == "") {
|
if (cookies["JSESSIONID"] == "" || cookies["XSRF-TOKEN"] == "") {
|
||||||
await _getFirstSession();
|
await _getFirstSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
var res =
|
var res =
|
||||||
await http.post(Uri.parse(url + "/j_spring_security_check"), headers: {
|
await http.post(Uri.parse("$url/j_spring_security_check"), headers: {
|
||||||
"Cookie": "JSESSIONID=" +
|
"Cookie":
|
||||||
cookies["JSESSIONID"]! +
|
"JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!};",
|
||||||
"; " +
|
|
||||||
"XSRF-TOKEN=" +
|
|
||||||
cookies["XSRF-TOKEN"]! +
|
|
||||||
";",
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
}, body: {
|
}, body: {
|
||||||
"j_username": user,
|
"j_username": user,
|
||||||
|
@ -132,9 +133,11 @@ class Canteen {
|
||||||
"targetUrl":
|
"targetUrl":
|
||||||
"/faces/secured/main.jsp?terminal=false&status=true&printer=&keyboard="
|
"/faces/secured/main.jsp?terminal=false&status=true&printer=&keyboard="
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.headers['set-cookie']!.contains("remember-me=;")) {
|
if (res.headers['set-cookie']!.contains("remember-me=;")) {
|
||||||
return false; // špatné heslo
|
return false; // špatné heslo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.statusCode != 302) {
|
if (res.statusCode != 302) {
|
||||||
return Future.error("Chyba: ${res.body}");
|
return Future.error("Chyba: ${res.body}");
|
||||||
}
|
}
|
||||||
|
@ -147,27 +150,25 @@ class Canteen {
|
||||||
/// Builder pro GET request
|
/// Builder pro GET request
|
||||||
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":
|
||||||
cookies["JSESSIONID"]! +
|
"JSESSIONID=${cookies["JSESSIONID"]!}; XSRF-TOKEN=${cookies["XSRF-TOKEN"]!}${cookies.containsKey("remember-me") ? "; ${cookies["remember-me"]!};" : ";"}",
|
||||||
"; " +
|
|
||||||
"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("fail") ||
|
||||||
r.body.contains("Chyba")) {
|
r.body.contains("Chyba")) {
|
||||||
return Future.error("Chyba: ${r.body}");
|
return Future.error("Chyba: ${r.body}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.body.contains("přihlášení uživatele")) {
|
if (r.body.contains("přihlášení uživatele")) {
|
||||||
prihlasen = false;
|
prihlasen = false;
|
||||||
return Future.error("Uživatel není přihlášen");
|
return Future.error("Uživatel není přihlášen");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.headers.containsKey("set-cookie")) {
|
if (r.headers.containsKey("set-cookie")) {
|
||||||
_parseCookies(r.headers["set-cookie"]!);
|
_parseCookies(r.headers["set-cookie"]!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.body;
|
return r.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,14 +185,12 @@ class Canteen {
|
||||||
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) {
|
||||||
// projedeme každý den individuálně
|
// projedeme každý den individuálně
|
||||||
var j = t
|
var j = t.group(0).toString(); // převedeme text na něco přehlednějšího
|
||||||
.group(0)
|
|
||||||
.toString() /*.replaceAll(RegExp(r'( )+|([^>a-z]\n)'),
|
|
||||||
'')*/
|
|
||||||
; // převedeme text na něco přehlednějšího
|
|
||||||
var den = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
|
var den = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
|
||||||
.firstMatch(j)!
|
.firstMatch(j)!
|
||||||
.group(0)
|
.group(0)
|
||||||
|
@ -210,24 +209,28 @@ class Canteen {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Jidlo> jidla = [];
|
List<Jidlo> jidla = [];
|
||||||
|
|
||||||
for (var jidloNaDen in jidlaDenne) {
|
for (var jidloNaDen in jidlaDenne) {
|
||||||
// projedeme vsechna jidla
|
// projedeme vsechna jidla
|
||||||
var s = jidloNaDen.group(0)!.replaceAll(
|
var s = jidloNaDen.group(0)!.replaceAll(
|
||||||
RegExp(
|
RegExp(
|
||||||
r'[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:] [a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:]'),
|
r'[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:] [a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:]'),
|
||||||
''); // odstraní dvojté mezery mezi písmeny
|
''); // odstraní dvojté mezery mezi písmeny
|
||||||
|
|
||||||
var vydejna = RegExp(r'(?<=<span style="color: #1b75bb;">).+?(?=<)')
|
var vydejna = RegExp(r'(?<=<span style="color: #1b75bb;">).+?(?=<)')
|
||||||
.firstMatch(s); // název výdejny / verze 2.18
|
.firstMatch(s); // název výdejny / verze 2.18
|
||||||
vydejna ??= RegExp(
|
vydejna ??= RegExp(
|
||||||
// TODO: Lepší systém pro podporu různých verzí iCanteen
|
// TODO: Lepší systém pro podporu různých verzí iCanteen
|
||||||
r'(?<=<span class="smallBoldTitle" style="color: #1b75bb;">).+?(?=<)')
|
r'(?<=<span class="smallBoldTitle" style="color: #1b75bb;">).+?(?=<)')
|
||||||
.firstMatch(s); // název výdejny / verze 2.10
|
.firstMatch(s); // název výdejny / verze 2.10
|
||||||
|
|
||||||
var hlavni = RegExp(
|
var hlavni = RegExp(
|
||||||
r' {20}(([a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+ )+[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+)',
|
r' {20}(([a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+ )+[a-zA-ZěščřžýáíéÉÍÁÝŽŘČŠĚŤŇťň.,:\/]+)',
|
||||||
dotAll: true)
|
dotAll: true)
|
||||||
.firstMatch(s)!
|
.firstMatch(s)!
|
||||||
.group(1)
|
.group(1)
|
||||||
.toString(); // Jídlo
|
.toString(); // Jídlo
|
||||||
|
|
||||||
jidla.add(Jidlo(
|
jidla.add(Jidlo(
|
||||||
nazev: hlavni,
|
nazev: hlavni,
|
||||||
objednano: false,
|
objednano: false,
|
||||||
|
@ -254,23 +257,27 @@ class Canteen {
|
||||||
if (!prihlasen) {
|
if (!prihlasen) {
|
||||||
return Future.error("Uživatel není přihlášen");
|
return Future.error("Uživatel není přihlášen");
|
||||||
}
|
}
|
||||||
|
|
||||||
den ??= DateTime.now();
|
den ??= DateTime.now();
|
||||||
|
|
||||||
String res;
|
String res;
|
||||||
try {
|
try {
|
||||||
res = await _getRequest(
|
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}" : den.month}-${(den.day < 10) ? "0${den.day}" : den.day}&terminal=false&printer=false&keyboard=false");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Future.error(e);
|
return Future.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
|
var obedDen = DateTime.parse(RegExp(r'(?<=day-).+?(?=")', dotAll: true)
|
||||||
.firstMatch(res)!
|
.firstMatch(res)!
|
||||||
.group(0)
|
.group(0)
|
||||||
.toString());
|
.toString());
|
||||||
var jidla = <Jidlo>[];
|
var jidla = <Jidlo>[];
|
||||||
var jidelnicek =
|
var jidelnicek = RegExp(
|
||||||
RegExp(r'(?<=<div class="jidWrapLeft">).+?((fa-clock))', dotAll: true)
|
r'(?<=<div class="jidWrapLeft">).+?((fa-clock)|(fa-ban))',
|
||||||
.allMatches(res)
|
dotAll: true)
|
||||||
.toList();
|
.allMatches(res)
|
||||||
|
.toList();
|
||||||
for (var obed in jidelnicek) {
|
for (var obed in jidelnicek) {
|
||||||
// formátování do třídy
|
// formátování do třídy
|
||||||
var o = obed
|
var o = obed
|
||||||
|
@ -281,26 +288,45 @@ class Canteen {
|
||||||
var lzeObjednat = !(o.contains("nelze zrušit") ||
|
var lzeObjednat = !(o.contains("nelze zrušit") ||
|
||||||
o.contains("nelze objednat") ||
|
o.contains("nelze objednat") ||
|
||||||
o.contains("nelze změnit"));
|
o.contains("nelze změnit"));
|
||||||
|
|
||||||
var cenaMatch =
|
var cenaMatch =
|
||||||
RegExp(r'(?<=Cena objednaného jídla">).+?(?=&)').firstMatch(o);
|
RegExp(r'((?<=Cena objednaného jídla">).+?(?=&))').firstMatch(o);
|
||||||
cenaMatch ??=
|
cenaMatch ??=
|
||||||
RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o);
|
RegExp(r'(?<=Cena při objednání jídla: ).+?(?=&)').firstMatch(o);
|
||||||
cenaMatch ??=
|
cenaMatch ??=
|
||||||
RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o);
|
RegExp(r'(?<=Cena při objednání jídla">).+?(?=&)').firstMatch(o);
|
||||||
|
|
||||||
var cena =
|
var cena =
|
||||||
double.parse(cenaMatch!.group(0).toString().replaceAll(",", "."));
|
double.parse(cenaMatch!.group(0).toString().replaceAll(",", "."));
|
||||||
var jidlaProDen = RegExp(r'(?<=Polévka: ).+')
|
var jidlaProDen =
|
||||||
.firstMatch(o)!
|
RegExp(r'<div class="jidWrapCenter.+?>(.+?)(?=<\/div>)', dotAll: true)
|
||||||
.group(0)
|
.firstMatch(o)!
|
||||||
.toString()
|
.group(1)
|
||||||
.replaceAll(' ,', ",")
|
.toString()
|
||||||
.replaceAll(" <br>", "")
|
.replaceAll(' ,', ",")
|
||||||
.split(" / ");
|
.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(
|
var vydejna = RegExp(
|
||||||
r'(?<=<span class="smallBoldTitle button-link-align">).+?(?=<)')
|
r'(?<=<span class="smallBoldTitle button-link-align">).+?(?=<)')
|
||||||
.firstMatch(o)!
|
.firstMatch(o)!
|
||||||
.group(0)
|
.group(0)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
String? orderUrl;
|
String? orderUrl;
|
||||||
String? burzaUrl;
|
String? burzaUrl;
|
||||||
if (lzeObjednat) {
|
if (lzeObjednat) {
|
||||||
|
@ -312,24 +338,31 @@ class Canteen {
|
||||||
} else {
|
} else {
|
||||||
// jinak nastavíme URL pro burzu
|
// jinak nastavíme URL pro burzu
|
||||||
var match = RegExp(
|
var match = RegExp(
|
||||||
r"(?<=ajaxOrder\(this, ')(.+?)(?=').+?((do burzy)|(z burzy))")
|
r"""db\/dbProcessOrder\.jsp.+?type=((plusburza)|(minusburza)|(multiburza)).+?(?=')""")
|
||||||
.firstMatch(o);
|
.firstMatch(o);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
burzaUrl = match.group(1)!.replaceAll("amp;", "");
|
burzaUrl = match.group(0)!.replaceAll("amp;", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jidla.add(Jidlo(
|
var jidloJmeno = RegExp(r'(.+?)(?=<sub>)')
|
||||||
nazev: jidlaProDen[1]
|
.firstMatch(jidlaProDen)!
|
||||||
.replaceAll(r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''),
|
.group(1)
|
||||||
objednano: objednano,
|
.toString();
|
||||||
varianta: vydejna,
|
jidla.add(
|
||||||
lzeObjednat: lzeObjednat,
|
Jidlo(
|
||||||
cena: cena,
|
nazev: jidloJmeno.replaceAll(
|
||||||
orderUrl: orderUrl,
|
r' (?=[^a-zA-ZěščřžýáíéĚŠČŘŽÝÁÍÉŤŇťň])', ''),
|
||||||
den: obedDen,
|
objednano: objednano,
|
||||||
burzaUrl: burzaUrl,
|
varianta: vydejna,
|
||||||
naBurze:
|
lzeObjednat: lzeObjednat,
|
||||||
(burzaUrl == null) ? false : !burzaUrl.contains("plusburza")));
|
cena: cena,
|
||||||
|
orderUrl: orderUrl,
|
||||||
|
den: obedDen,
|
||||||
|
burzaUrl: burzaUrl,
|
||||||
|
naBurze:
|
||||||
|
(burzaUrl == null) ? false : burzaUrl.contains("minusburza"),
|
||||||
|
alergeny: alergeny),
|
||||||
|
);
|
||||||
// KONEC formátování do třídy
|
// KONEC formátování do třídy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,13 +380,14 @@ class Canteen {
|
||||||
if (!prihlasen) {
|
if (!prihlasen) {
|
||||||
return Future.error("Uživatel není přihlášen");
|
return Future.error("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 Future.error(
|
return Future.error(
|
||||||
"Jídlo nelze objednat nebo nemá adresu pro objednání");
|
"Jídlo nelze objednat nebo nemá adresu pro objednání");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _getRequest("/faces/secured/" + j.orderUrl!); // provést operaci
|
await _getRequest("/faces/secured/${j.orderUrl!}"); // provést operaci
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Future.error(e);
|
return Future.error(e);
|
||||||
}
|
}
|
||||||
|
@ -375,16 +409,23 @@ class Canteen {
|
||||||
///
|
///
|
||||||
/// Výstup:
|
/// Výstup:
|
||||||
/// - Aktualizovaná instance [Jidlo] tohoto jídla NEBO [Future] jako chyba
|
/// - 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) {
|
if (!prihlasen) {
|
||||||
return Future.error("Uživatel není přihlášen");
|
return Future.error("Uživatel není přihlášen");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j.burzaUrl == null || j.burzaUrl!.isEmpty) {
|
if (j.burzaUrl == null || j.burzaUrl!.isEmpty) {
|
||||||
return Future.error(
|
return Future.error(
|
||||||
"Jídlo nelze uložit do burzy nebo nemá adresu pro uložení");
|
"Jídlo nelze uložit do burzy nebo nemá adresu pro ulož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 {
|
try {
|
||||||
await _getRequest("/faces/secured/" + j.burzaUrl!); // provést operaci
|
await _getRequest("/faces/secured/$finalUrl"); // provést operaci
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Future.error(e);
|
return Future.error(e);
|
||||||
}
|
}
|
||||||
|
@ -425,6 +466,7 @@ class Canteen {
|
||||||
dotAll: true)
|
dotAll: true)
|
||||||
.allMatches(bu)
|
.allMatches(bu)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
// Získat datum
|
// Získat datum
|
||||||
var datumRaw = RegExp(r'\d\d\.\d\d\.\d{4}')
|
var datumRaw = RegExp(r'\d\d\.\d\d\.\d{4}')
|
||||||
.firstMatch(data[1].group(0)!)!
|
.firstMatch(data[1].group(0)!)!
|
||||||
|
@ -442,6 +484,7 @@ class Canteen {
|
||||||
.firstMatch(bu)!
|
.firstMatch(bu)!
|
||||||
.group(0)!
|
.group(0)!
|
||||||
.replaceAll("&", "&");
|
.replaceAll("&", "&");
|
||||||
|
|
||||||
var jidlo = Burza(
|
var jidlo = Burza(
|
||||||
den: datum,
|
den: datum,
|
||||||
varianta: varianta,
|
varianta: varianta,
|
||||||
|
@ -460,13 +503,13 @@ class Canteen {
|
||||||
/// - `b` - Jídlo __z burzy__, které chceme objednat | [Burza]
|
/// - `b` - Jídlo __z burzy__, které chceme objednat | [Burza]
|
||||||
///
|
///
|
||||||
/// Výstup:
|
/// 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 {
|
Future<bool> objednatZBurzy(Burza b) async {
|
||||||
if (!prihlasen) return Future.error("Uživatel není přihlášen");
|
if (!prihlasen) return Future.error("Uživatel není přihlášen");
|
||||||
try {
|
try {
|
||||||
await _getRequest("/faces/secured/" + b.url!);
|
await _getRequest("/faces/secured/${b.url!}");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return Future.error(e.toString());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,11 @@ class Jidlo {
|
||||||
/// Den, který je jídlo vydáváno
|
/// Den, který je jídlo vydáváno
|
||||||
DateTime den;
|
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
|
/// URL pro požadavek na objednání jídla
|
||||||
final String? orderUrl;
|
final String? orderUrl;
|
||||||
|
|
||||||
|
@ -31,6 +36,7 @@ class Jidlo {
|
||||||
required this.objednano,
|
required this.objednano,
|
||||||
required this.varianta,
|
required this.varianta,
|
||||||
required this.den,
|
required this.den,
|
||||||
|
this.alergeny = const [],
|
||||||
this.cena,
|
this.cena,
|
||||||
required this.lzeObjednat,
|
required this.lzeObjednat,
|
||||||
this.orderUrl,
|
this.orderUrl,
|
||||||
|
@ -38,6 +44,15 @@ class Jidlo {
|
||||||
required this.naBurze});
|
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
|
/// Reprezentuje cizí jídlo na burze
|
||||||
class Burza {
|
class Burza {
|
||||||
/// Den, který je jídlo vydáváno
|
/// Den, který je jídlo vydáváno
|
||||||
|
|
13
pubspec.yaml
13
pubspec.yaml
|
@ -1,16 +1,15 @@
|
||||||
name: canteenlib
|
name: canteenlib
|
||||||
description: Library for communication with the czech canteen food ordering system iCanteen
|
description: Library for communication with the czech canteen food ordering system iCanteen
|
||||||
version: 0.1.0-alpha.16
|
version: 2.0.0
|
||||||
repository: 'https://github.com/hernikplays/canteenlib'
|
repository: 'https://git.mnau.xyz/hernik/canteenlib'
|
||||||
issue_tracker: 'https://github.com/hernikplays/canteenlib/issues'
|
issue_tracker: 'https://git.mnau.xyz/hernik/canteenlib/issues'
|
||||||
documentation: 'https://docs.hernikplays.cz'
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.16.1 <3.0.0'
|
sdk: '>=2.16.1 <4.0.0'
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
dotenv: ^3.0.0
|
dotenv: ^4.0.1
|
||||||
lints: ^1.0.0
|
lints: ^2.0.0
|
||||||
test: ^1.16.0
|
test: ^1.16.0
|
||||||
dependencies:
|
dependencies:
|
||||||
http: ^0.13.4
|
http: ^0.13.4
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
import 'package:canteenlib/canteenlib.dart';
|
import 'package:canteenlib/canteenlib.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:dotenv/dotenv.dart' show load, env;
|
import 'package:dotenv/dotenv.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('A group of tests', () {
|
group('A group of tests', () {
|
||||||
load();
|
var env = DotEnv(includePlatformEnvironment: true)..load();
|
||||||
Canteen c = Canteen(env["ADDRESS"]!);
|
Canteen c = Canteen(env["ADDRESS"]!);
|
||||||
|
|
||||||
setUp(() {
|
test('Log-in test', () {
|
||||||
c.login(env["USER"]!, env["PASS"]!);
|
c.login(env["USER"]!, env["PASS"]!).then((r) => expect(r, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('First Test', () {
|
test('First Test', () {
|
||||||
c.jidelnicekDen().then((t) {
|
c.login(env["USER"]!, env["PASS"]!).then((r) {
|
||||||
expect(DateTime.now().day, t.den.day);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Reference in a new issue