myfap 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- myfap-0.1.0/LICENSE +21 -0
- myfap-0.1.0/PKG-INFO +214 -0
- myfap-0.1.0/README.md +194 -0
- myfap-0.1.0/myfap/__init__.py +3 -0
- myfap-0.1.0/myfap/api.py +226 -0
- myfap-0.1.0/myfap/auth.py +280 -0
- myfap-0.1.0/myfap/auth_var.py +16 -0
- myfap-0.1.0/myfap/cli.py +535 -0
- myfap-0.1.0/myfap/parsers.py +116 -0
- myfap-0.1.0/myfap.egg-info/PKG-INFO +214 -0
- myfap-0.1.0/myfap.egg-info/SOURCES.txt +15 -0
- myfap-0.1.0/myfap.egg-info/dependency_links.txt +1 -0
- myfap-0.1.0/myfap.egg-info/entry_points.txt +2 -0
- myfap-0.1.0/myfap.egg-info/requires.txt +8 -0
- myfap-0.1.0/myfap.egg-info/top_level.txt +1 -0
- myfap-0.1.0/pyproject.toml +33 -0
- myfap-0.1.0/setup.cfg +4 -0
myfap-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WindowScary321
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
myfap-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: myfap
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI Tool dựa trên MyFAP API dành cho Sinh Viên FPTU
|
|
5
|
+
Author-email: Author <author@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/WindowScary321/myfap-api-cli
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: typer>=0.9.0
|
|
12
|
+
Requires-Dist: rich>=13.0.0
|
|
13
|
+
Requires-Dist: playwright>=1.40.0
|
|
14
|
+
Requires-Dist: requests>=2.31.0
|
|
15
|
+
Requires-Dist: pkce>=1.0.3
|
|
16
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
17
|
+
Requires-Dist: ics>=0.7.2
|
|
18
|
+
Requires-Dist: pytz>=2023.3
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# MyFAP API CLI
|
|
22
|
+
|
|
23
|
+
## Giới thiệu
|
|
24
|
+
|
|
25
|
+
Chào mứng đến với dự án đầu tiên của kế hoạch lật đổ FBTU. Cli này tương tác giống hoàn toàn với APP MYFAP trên điện thoại. Bạn có thể xem lịch học, lịch thi, điểm số (sự thất vọng của gia đình), thông tin cá nhân, v.v. 1 cách thuận tiện, không bị gò bó trong giao diện app. <br>
|
|
26
|
+
- Lưu ý: repo này được thực hiện cùng với sự hỗ trợ của Ai (Gemini 3.1 Pro Preview)
|
|
27
|
+
|
|
28
|
+
## Tính năng chính
|
|
29
|
+
- Hỗ trợ đa nền tảng.
|
|
30
|
+
- Login thông qua FEID hoặc Google OAuth.
|
|
31
|
+
- Xem lịch học (từng tuần hoặc cả Kỳ).
|
|
32
|
+
- Xem điểm (từng môn hoặc cả Kỳ).
|
|
33
|
+
- Check điểm danh (từng môn hoặc cả Kỳ).
|
|
34
|
+
- Check tình trạng đơn từ.
|
|
35
|
+
- Xem thông báo của trường.
|
|
36
|
+
- Check Info của sinh viên hoặc phòng dvsv.
|
|
37
|
+
- Convert lịch học Kỳ sang **ICS**, dễ dàng import lịch học vào Google Calendar hoặc các dịch vụ tương tự.
|
|
38
|
+
- Và nhiều hơn nữa ...
|
|
39
|
+
|
|
40
|
+
## Cách sử dụng
|
|
41
|
+
|
|
42
|
+
Do dự án đang trong quá trình phát triển nên chưa thể đem lên pip. Bạn có thể tải sauce về và chạy:
|
|
43
|
+
|
|
44
|
+
- Tạo venv.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
python -m venv .venv && .\.venv\Scripts\activate
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Cài đặt dependency.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
pip install .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- Cài đặt playwright (nếu bạn ko dùng chrome hoặc edge).
|
|
57
|
+
```
|
|
58
|
+
playwright install
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- Lấy danh sách cơ sở.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
myfap campuses
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- Login vào feid (chỉ cần làm 1 lần, mặc định chọn cơ sở Hola).
|
|
68
|
+
```
|
|
69
|
+
myfap login
|
|
70
|
+
```
|
|
71
|
+
Sau khi hoàn thành login, phiên đăng nhập sẽ dc lưu ở ``~/.myfap-api-cli/session.json`` <br>
|
|
72
|
+
- Login cho cơ sở Xavalo.
|
|
73
|
+
```
|
|
74
|
+
myfap login -c HCM
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- Lấy Lịch học (tự động lấy kỳ mới nhất).
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
myfap schedule
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Các Options
|
|
84
|
+
|Option|Chú thích|
|
|
85
|
+
|:-|:-|
|
|
86
|
+
|--help|Hiển thị bảng Commands và Options|
|
|
87
|
+
|-c, --campus <cơ sở>|Mã cơ sở (VD: APHL, HCM, DN) [default: APHL]|
|
|
88
|
+
|-s, --semester <kỳ học>|Tên kỳ học (VD: Summer2026)|
|
|
89
|
+
|-cid, --courseid <mã môn>|Chọn mã môn, chỉ có ở command ``marks``. (VD: 82934, lấy từ bảng điểm của kỳ, ko phải mã môn như PRO192, SWE201c, ...)|
|
|
90
|
+
|-w, --week <số tuần>|Chọn tuần, chỉ có ở command ``week-timetable``|
|
|
91
|
+
|-y, --year <số năm>|Chọn năm học, chỉ có ở command ``week-timetable``|
|
|
92
|
+
|-d, --date \<YYYY-MM-DD\>|Chỉ định ngày chính xác, chỉ có ở command ``week-timetable``|
|
|
93
|
+
|-sc, --subjectcode <mã môn>|Chọn môn học, chỉ có ở command ``attendance``|
|
|
94
|
+
|-cn, --classname <mã lớp>|Chọn lớp học, chỉ có ở command ``attendance``|
|
|
95
|
+
|--ics|Convert Sang **ICS**, dễ dàng import lịch học vào Google Calendar hoặc các dịch vụ tương tự, chỉ có ở command ``schedule``)|
|
|
96
|
+
|-p, --pretty|Format lại bảng điểm gốc của trường sang dạng json, chỉ có ở command ``marks``)|
|
|
97
|
+
|-r, --refresh|Refresh thủ công ``authen_key`` trong file ``session.json``, chỉ có ở command ``login``|
|
|
98
|
+
|-f, --force|Buộc đăng nhập lại, bỏ qua file ``session.json``, chỉ có ở command ``login``|
|
|
99
|
+
|
|
100
|
+
## Các ví dụ sử dụng
|
|
101
|
+
- Lưu ý:
|
|
102
|
+
- Do hầu hết các command đểu trả về json, ``*`` đánh dấu những command trả output ra màn hình.
|
|
103
|
+
- Nếu ko thêm flag _thời gian_ hoặc _kỳ_, ``myfap`` sẽ tự động lấy thời gian mới nhất.
|
|
104
|
+
- ``+`` nghĩa là bạn sẽ ko cần thêm flag ``--semester`` hoặc ``-s`` nếu gọi api vào đúng thời gian trong kỳ. Để xem thông tin của kỳ trước, bạn phải thêm flag này.
|
|
105
|
+
- Xem tất cả command ``*``
|
|
106
|
+
```
|
|
107
|
+
(.venv) PS D:\git\myfap-api-cli> myfap --help
|
|
108
|
+
Usage: myfap [OPTIONS] COMMAND [ARGS]...
|
|
109
|
+
|
|
110
|
+
CLI Tool dựa trên MyFAP dành cho Sinh Viên FPTU
|
|
111
|
+
|
|
112
|
+
Options:
|
|
113
|
+
-c, --campus TEXT Mã cơ sở (VD: APHL, HCM, DN) [default: APHL]
|
|
114
|
+
--help Show this message and exit.
|
|
115
|
+
|
|
116
|
+
Commands:
|
|
117
|
+
login Đăng nhập vào hệ thống FEID
|
|
118
|
+
campuses Xem danh sách các cơ sở (Campus)
|
|
119
|
+
semesters Xem danh sách kỳ học
|
|
120
|
+
schedule Xem lịch học (xuất JSON)
|
|
121
|
+
marks Xem bảng điểm (xuất JSON)
|
|
122
|
+
exams Xem lịch thi (xuất JSON)
|
|
123
|
+
week-timetable Xem lịch học theo tuần (xuất JSON)
|
|
124
|
+
attendance Xem thông tin điểm danh (xuất JSON)
|
|
125
|
+
applications Xem danh sách đơn từ đã gửi cho trường (xuất JSON)
|
|
126
|
+
news Xem 10 thông báo gần nhất (xuất JSON)
|
|
127
|
+
info Xem thông tin chung (sinh viên, campus)
|
|
128
|
+
other Các chức năng phụ trợ khác (survey, feedback, fee...)
|
|
129
|
+
```
|
|
130
|
+
- Xem danh sách kỳ ``*``
|
|
131
|
+
```
|
|
132
|
+
myfap semesters
|
|
133
|
+
```
|
|
134
|
+
- Xem lịch học của Kỳ bất kỳ
|
|
135
|
+
```
|
|
136
|
+
myfap schedule -s Summer2026
|
|
137
|
+
```
|
|
138
|
+
- Convert lịch học sang **ICS** (import vào GG Calendar)
|
|
139
|
+
```
|
|
140
|
+
myfap schedule -s Summer2026 --ics
|
|
141
|
+
```
|
|
142
|
+
- Xem lịch thi của Kỳ bất kỳ
|
|
143
|
+
```
|
|
144
|
+
myfap exams -s Summer2026
|
|
145
|
+
```
|
|
146
|
+
- Xem lịch từng tuần được chỉ định ``+``
|
|
147
|
+
```
|
|
148
|
+
myfap week-timetable --week 22
|
|
149
|
+
```
|
|
150
|
+
- Xem lịch từng tuần bằng thời gian ngày ``+``
|
|
151
|
+
```
|
|
152
|
+
myfap week-timetable --date 2026-6-7
|
|
153
|
+
```
|
|
154
|
+
- Xem danh sách điểm danh của Kỳ bất kỳ
|
|
155
|
+
```
|
|
156
|
+
myfap attendance -s Spring2026
|
|
157
|
+
```
|
|
158
|
+
- Xem danh sách điểm danh của môn bất kỳ trong Kỳ ``+``
|
|
159
|
+
```
|
|
160
|
+
myfap attendance -sc CSD201 -cn SE2026 -s Spring2026
|
|
161
|
+
```
|
|
162
|
+
- Xem ~~sự thất vọng của gia đinh~~ điểm số của Kỳ bất kỳ
|
|
163
|
+
```
|
|
164
|
+
myfap marks -s Fall2025
|
|
165
|
+
```
|
|
166
|
+
- Xem điểm của môn bất kỳ (ví dụ: môn MAD101, xem mã môn ở command trên)
|
|
167
|
+
```
|
|
168
|
+
myfap marks -cid 95619
|
|
169
|
+
```
|
|
170
|
+
- Xem điểm của môn bất kỳ (thêm ``-p`` hoặc ``--pretty`` cho đẹp)
|
|
171
|
+
```
|
|
172
|
+
myfap marks -cid 95619 -p
|
|
173
|
+
```
|
|
174
|
+
- Xem tình trạng gửi đơn của Fap Web
|
|
175
|
+
```
|
|
176
|
+
myfap applications
|
|
177
|
+
```
|
|
178
|
+
- Xem thông báo gửi toàn trường
|
|
179
|
+
```
|
|
180
|
+
myfap news
|
|
181
|
+
```
|
|
182
|
+
- Xem thông tin sinh viên
|
|
183
|
+
```
|
|
184
|
+
myfap info student
|
|
185
|
+
```
|
|
186
|
+
- Xem thông tin phòng dvsv
|
|
187
|
+
```
|
|
188
|
+
myfap info campus
|
|
189
|
+
```
|
|
190
|
+
- Xem thông tin thêm ``*``
|
|
191
|
+
```bash
|
|
192
|
+
myfap other --help
|
|
193
|
+
Usage: myfap other [OPTIONS] COMMAND [ARGS]...
|
|
194
|
+
|
|
195
|
+
Các chức năng phụ trợ khác (survey, feedback, fee...)
|
|
196
|
+
|
|
197
|
+
Options:
|
|
198
|
+
--help Show this message and exit.
|
|
199
|
+
|
|
200
|
+
Commands:
|
|
201
|
+
survey Kiểm tra các survey chưa thực hiện (xuất JSON)
|
|
202
|
+
feedback Kiểm tra Feedback (xuất JSON)
|
|
203
|
+
profile Kiểm tra Update Profile (xuất JSON)
|
|
204
|
+
notification Xem thông báo qua MSSV (xuất JSON)
|
|
205
|
+
fee Lấy danh sách học phí chưa thanh toán (xuất JSON)
|
|
206
|
+
```
|
|
207
|
+
- Refresh thủ công ``authen_key`` trong trường hợp cli bị lỗi
|
|
208
|
+
```
|
|
209
|
+
myfap login -r
|
|
210
|
+
```
|
|
211
|
+
- Đăng nhập lại, bỏ qua file ``session.json``
|
|
212
|
+
```
|
|
213
|
+
myfap login -f
|
|
214
|
+
```
|
myfap-0.1.0/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# MyFAP API CLI
|
|
2
|
+
|
|
3
|
+
## Giới thiệu
|
|
4
|
+
|
|
5
|
+
Chào mứng đến với dự án đầu tiên của kế hoạch lật đổ FBTU. Cli này tương tác giống hoàn toàn với APP MYFAP trên điện thoại. Bạn có thể xem lịch học, lịch thi, điểm số (sự thất vọng của gia đình), thông tin cá nhân, v.v. 1 cách thuận tiện, không bị gò bó trong giao diện app. <br>
|
|
6
|
+
- Lưu ý: repo này được thực hiện cùng với sự hỗ trợ của Ai (Gemini 3.1 Pro Preview)
|
|
7
|
+
|
|
8
|
+
## Tính năng chính
|
|
9
|
+
- Hỗ trợ đa nền tảng.
|
|
10
|
+
- Login thông qua FEID hoặc Google OAuth.
|
|
11
|
+
- Xem lịch học (từng tuần hoặc cả Kỳ).
|
|
12
|
+
- Xem điểm (từng môn hoặc cả Kỳ).
|
|
13
|
+
- Check điểm danh (từng môn hoặc cả Kỳ).
|
|
14
|
+
- Check tình trạng đơn từ.
|
|
15
|
+
- Xem thông báo của trường.
|
|
16
|
+
- Check Info của sinh viên hoặc phòng dvsv.
|
|
17
|
+
- Convert lịch học Kỳ sang **ICS**, dễ dàng import lịch học vào Google Calendar hoặc các dịch vụ tương tự.
|
|
18
|
+
- Và nhiều hơn nữa ...
|
|
19
|
+
|
|
20
|
+
## Cách sử dụng
|
|
21
|
+
|
|
22
|
+
Do dự án đang trong quá trình phát triển nên chưa thể đem lên pip. Bạn có thể tải sauce về và chạy:
|
|
23
|
+
|
|
24
|
+
- Tạo venv.
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
python -m venv .venv && .\.venv\Scripts\activate
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- Cài đặt dependency.
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
pip install .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Cài đặt playwright (nếu bạn ko dùng chrome hoặc edge).
|
|
37
|
+
```
|
|
38
|
+
playwright install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Lấy danh sách cơ sở.
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
myfap campuses
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- Login vào feid (chỉ cần làm 1 lần, mặc định chọn cơ sở Hola).
|
|
48
|
+
```
|
|
49
|
+
myfap login
|
|
50
|
+
```
|
|
51
|
+
Sau khi hoàn thành login, phiên đăng nhập sẽ dc lưu ở ``~/.myfap-api-cli/session.json`` <br>
|
|
52
|
+
- Login cho cơ sở Xavalo.
|
|
53
|
+
```
|
|
54
|
+
myfap login -c HCM
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Lấy Lịch học (tự động lấy kỳ mới nhất).
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
myfap schedule
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Các Options
|
|
64
|
+
|Option|Chú thích|
|
|
65
|
+
|:-|:-|
|
|
66
|
+
|--help|Hiển thị bảng Commands và Options|
|
|
67
|
+
|-c, --campus <cơ sở>|Mã cơ sở (VD: APHL, HCM, DN) [default: APHL]|
|
|
68
|
+
|-s, --semester <kỳ học>|Tên kỳ học (VD: Summer2026)|
|
|
69
|
+
|-cid, --courseid <mã môn>|Chọn mã môn, chỉ có ở command ``marks``. (VD: 82934, lấy từ bảng điểm của kỳ, ko phải mã môn như PRO192, SWE201c, ...)|
|
|
70
|
+
|-w, --week <số tuần>|Chọn tuần, chỉ có ở command ``week-timetable``|
|
|
71
|
+
|-y, --year <số năm>|Chọn năm học, chỉ có ở command ``week-timetable``|
|
|
72
|
+
|-d, --date \<YYYY-MM-DD\>|Chỉ định ngày chính xác, chỉ có ở command ``week-timetable``|
|
|
73
|
+
|-sc, --subjectcode <mã môn>|Chọn môn học, chỉ có ở command ``attendance``|
|
|
74
|
+
|-cn, --classname <mã lớp>|Chọn lớp học, chỉ có ở command ``attendance``|
|
|
75
|
+
|--ics|Convert Sang **ICS**, dễ dàng import lịch học vào Google Calendar hoặc các dịch vụ tương tự, chỉ có ở command ``schedule``)|
|
|
76
|
+
|-p, --pretty|Format lại bảng điểm gốc của trường sang dạng json, chỉ có ở command ``marks``)|
|
|
77
|
+
|-r, --refresh|Refresh thủ công ``authen_key`` trong file ``session.json``, chỉ có ở command ``login``|
|
|
78
|
+
|-f, --force|Buộc đăng nhập lại, bỏ qua file ``session.json``, chỉ có ở command ``login``|
|
|
79
|
+
|
|
80
|
+
## Các ví dụ sử dụng
|
|
81
|
+
- Lưu ý:
|
|
82
|
+
- Do hầu hết các command đểu trả về json, ``*`` đánh dấu những command trả output ra màn hình.
|
|
83
|
+
- Nếu ko thêm flag _thời gian_ hoặc _kỳ_, ``myfap`` sẽ tự động lấy thời gian mới nhất.
|
|
84
|
+
- ``+`` nghĩa là bạn sẽ ko cần thêm flag ``--semester`` hoặc ``-s`` nếu gọi api vào đúng thời gian trong kỳ. Để xem thông tin của kỳ trước, bạn phải thêm flag này.
|
|
85
|
+
- Xem tất cả command ``*``
|
|
86
|
+
```
|
|
87
|
+
(.venv) PS D:\git\myfap-api-cli> myfap --help
|
|
88
|
+
Usage: myfap [OPTIONS] COMMAND [ARGS]...
|
|
89
|
+
|
|
90
|
+
CLI Tool dựa trên MyFAP dành cho Sinh Viên FPTU
|
|
91
|
+
|
|
92
|
+
Options:
|
|
93
|
+
-c, --campus TEXT Mã cơ sở (VD: APHL, HCM, DN) [default: APHL]
|
|
94
|
+
--help Show this message and exit.
|
|
95
|
+
|
|
96
|
+
Commands:
|
|
97
|
+
login Đăng nhập vào hệ thống FEID
|
|
98
|
+
campuses Xem danh sách các cơ sở (Campus)
|
|
99
|
+
semesters Xem danh sách kỳ học
|
|
100
|
+
schedule Xem lịch học (xuất JSON)
|
|
101
|
+
marks Xem bảng điểm (xuất JSON)
|
|
102
|
+
exams Xem lịch thi (xuất JSON)
|
|
103
|
+
week-timetable Xem lịch học theo tuần (xuất JSON)
|
|
104
|
+
attendance Xem thông tin điểm danh (xuất JSON)
|
|
105
|
+
applications Xem danh sách đơn từ đã gửi cho trường (xuất JSON)
|
|
106
|
+
news Xem 10 thông báo gần nhất (xuất JSON)
|
|
107
|
+
info Xem thông tin chung (sinh viên, campus)
|
|
108
|
+
other Các chức năng phụ trợ khác (survey, feedback, fee...)
|
|
109
|
+
```
|
|
110
|
+
- Xem danh sách kỳ ``*``
|
|
111
|
+
```
|
|
112
|
+
myfap semesters
|
|
113
|
+
```
|
|
114
|
+
- Xem lịch học của Kỳ bất kỳ
|
|
115
|
+
```
|
|
116
|
+
myfap schedule -s Summer2026
|
|
117
|
+
```
|
|
118
|
+
- Convert lịch học sang **ICS** (import vào GG Calendar)
|
|
119
|
+
```
|
|
120
|
+
myfap schedule -s Summer2026 --ics
|
|
121
|
+
```
|
|
122
|
+
- Xem lịch thi của Kỳ bất kỳ
|
|
123
|
+
```
|
|
124
|
+
myfap exams -s Summer2026
|
|
125
|
+
```
|
|
126
|
+
- Xem lịch từng tuần được chỉ định ``+``
|
|
127
|
+
```
|
|
128
|
+
myfap week-timetable --week 22
|
|
129
|
+
```
|
|
130
|
+
- Xem lịch từng tuần bằng thời gian ngày ``+``
|
|
131
|
+
```
|
|
132
|
+
myfap week-timetable --date 2026-6-7
|
|
133
|
+
```
|
|
134
|
+
- Xem danh sách điểm danh của Kỳ bất kỳ
|
|
135
|
+
```
|
|
136
|
+
myfap attendance -s Spring2026
|
|
137
|
+
```
|
|
138
|
+
- Xem danh sách điểm danh của môn bất kỳ trong Kỳ ``+``
|
|
139
|
+
```
|
|
140
|
+
myfap attendance -sc CSD201 -cn SE2026 -s Spring2026
|
|
141
|
+
```
|
|
142
|
+
- Xem ~~sự thất vọng của gia đinh~~ điểm số của Kỳ bất kỳ
|
|
143
|
+
```
|
|
144
|
+
myfap marks -s Fall2025
|
|
145
|
+
```
|
|
146
|
+
- Xem điểm của môn bất kỳ (ví dụ: môn MAD101, xem mã môn ở command trên)
|
|
147
|
+
```
|
|
148
|
+
myfap marks -cid 95619
|
|
149
|
+
```
|
|
150
|
+
- Xem điểm của môn bất kỳ (thêm ``-p`` hoặc ``--pretty`` cho đẹp)
|
|
151
|
+
```
|
|
152
|
+
myfap marks -cid 95619 -p
|
|
153
|
+
```
|
|
154
|
+
- Xem tình trạng gửi đơn của Fap Web
|
|
155
|
+
```
|
|
156
|
+
myfap applications
|
|
157
|
+
```
|
|
158
|
+
- Xem thông báo gửi toàn trường
|
|
159
|
+
```
|
|
160
|
+
myfap news
|
|
161
|
+
```
|
|
162
|
+
- Xem thông tin sinh viên
|
|
163
|
+
```
|
|
164
|
+
myfap info student
|
|
165
|
+
```
|
|
166
|
+
- Xem thông tin phòng dvsv
|
|
167
|
+
```
|
|
168
|
+
myfap info campus
|
|
169
|
+
```
|
|
170
|
+
- Xem thông tin thêm ``*``
|
|
171
|
+
```bash
|
|
172
|
+
myfap other --help
|
|
173
|
+
Usage: myfap other [OPTIONS] COMMAND [ARGS]...
|
|
174
|
+
|
|
175
|
+
Các chức năng phụ trợ khác (survey, feedback, fee...)
|
|
176
|
+
|
|
177
|
+
Options:
|
|
178
|
+
--help Show this message and exit.
|
|
179
|
+
|
|
180
|
+
Commands:
|
|
181
|
+
survey Kiểm tra các survey chưa thực hiện (xuất JSON)
|
|
182
|
+
feedback Kiểm tra Feedback (xuất JSON)
|
|
183
|
+
profile Kiểm tra Update Profile (xuất JSON)
|
|
184
|
+
notification Xem thông báo qua MSSV (xuất JSON)
|
|
185
|
+
fee Lấy danh sách học phí chưa thanh toán (xuất JSON)
|
|
186
|
+
```
|
|
187
|
+
- Refresh thủ công ``authen_key`` trong trường hợp cli bị lỗi
|
|
188
|
+
```
|
|
189
|
+
myfap login -r
|
|
190
|
+
```
|
|
191
|
+
- Đăng nhập lại, bỏ qua file ``session.json``
|
|
192
|
+
```
|
|
193
|
+
myfap login -f
|
|
194
|
+
```
|
myfap-0.1.0/myfap/api.py
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import html
|
|
3
|
+
from .auth import FAP_HOST, MAGIC_ID, create_checksum
|
|
4
|
+
|
|
5
|
+
def check_api_error(data):
|
|
6
|
+
if isinstance(data, dict):
|
|
7
|
+
code = str(data.get("code", ""))
|
|
8
|
+
if code == "201":
|
|
9
|
+
msg = data.get("message", "Lỗi API (Mã 201)")
|
|
10
|
+
raise Exception(f"FAP API báo lỗi: {msg}")
|
|
11
|
+
if "data" in data and not data.get("data"): # Báo lỗi nếu data rỗng hoặc null
|
|
12
|
+
raise Exception("Không có dữ liệu (Data rỗng) hoặc bạn chưa hoặc truyền sai flag --semester")
|
|
13
|
+
return data
|
|
14
|
+
|
|
15
|
+
def clean_json(data):
|
|
16
|
+
"""Giải mã các ký tự HTML Entity (ô, á, ...) do server ASP.NET trả về"""
|
|
17
|
+
if isinstance(data, dict):
|
|
18
|
+
return {k: clean_json(v) for k, v in data.items()}
|
|
19
|
+
elif isinstance(data, list):
|
|
20
|
+
return [clean_json(v) for v in data]
|
|
21
|
+
elif isinstance(data, str):
|
|
22
|
+
return html.unescape(data)
|
|
23
|
+
return data
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MyFapEssential:
|
|
27
|
+
def __init__(self, auth=None):
|
|
28
|
+
self.auth = auth
|
|
29
|
+
self.session = requests.Session()
|
|
30
|
+
self.session.headers.update({"User-Agent": "okhttp/4.9.2"})
|
|
31
|
+
|
|
32
|
+
def get_campuses(self):
|
|
33
|
+
"""Lấy danh sách các cơ sở (không cần authenKey)"""
|
|
34
|
+
url = f"{FAP_HOST}/GetAllActiveCampus"
|
|
35
|
+
r = self.session.get(url)
|
|
36
|
+
if r.status_code == 200:
|
|
37
|
+
return clean_json(check_api_error(r.json())).get('data', [])
|
|
38
|
+
return []
|
|
39
|
+
|
|
40
|
+
def get_semesters(self, campus: str = None):
|
|
41
|
+
"""Lấy danh sách các kỳ học. Yêu cầu đối tượng auth hợp lệ."""
|
|
42
|
+
if not self.auth:
|
|
43
|
+
raise Exception("Lỗi: Cần đối tượng auth để lấy danh sách kỳ học.")
|
|
44
|
+
|
|
45
|
+
target_campus = campus or self.auth.campus
|
|
46
|
+
checksum = create_checksum(MAGIC_ID, target_campus)
|
|
47
|
+
url = f"{FAP_HOST}/GetSemester?campusCode={target_campus}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
48
|
+
r = self.session.get(url)
|
|
49
|
+
if r.status_code == 200:
|
|
50
|
+
semesters = check_api_error(r.json()).get('data', [])
|
|
51
|
+
semesters.sort(key=lambda x: x['termID'], reverse=True)
|
|
52
|
+
return semesters
|
|
53
|
+
raise Exception(f"Lỗi lấy danh sách kỳ học: {r.text}")
|
|
54
|
+
|
|
55
|
+
def get_week(self, date_str: str):
|
|
56
|
+
"""Lấy số tuần tương ứng với ngày (YYYY-MM-DD)"""
|
|
57
|
+
url = f"{FAP_HOST}/GetWeekByDate?date={date_str}"
|
|
58
|
+
r = self.session.get(url)
|
|
59
|
+
if r.status_code == 200:
|
|
60
|
+
return int(check_api_error(r.json()).get("data", 0))
|
|
61
|
+
raise Exception(f"Lỗi lấy tuần: {r.text}")
|
|
62
|
+
|
|
63
|
+
def get_news(self, news_type: int = 1):
|
|
64
|
+
"""Lấy 10 thông báo gần nhất (gửi toàn trường)"""
|
|
65
|
+
if not self.auth:
|
|
66
|
+
raise Exception("Lỗi: Không tìm thấy session xác thực (auth).")
|
|
67
|
+
# Identifier cho API này chính là giá trị của 'type'
|
|
68
|
+
checksum = create_checksum(str(news_type), self.auth.campus)
|
|
69
|
+
url = f"{FAP_HOST}/GetTop10News?campusCode={self.auth.campus}&Authen={self.auth.authen_key}&type={news_type}&checksum={checksum}"
|
|
70
|
+
r = self.session.get(url)
|
|
71
|
+
if r.status_code == 200:
|
|
72
|
+
return clean_json(check_api_error(r.json()))
|
|
73
|
+
raise Exception(f"Lỗi lấy thông báo: {r.text}")
|
|
74
|
+
|
|
75
|
+
class MyFapOther:
|
|
76
|
+
def __init__(self, auth):
|
|
77
|
+
self.auth = auth
|
|
78
|
+
self.session = requests.Session()
|
|
79
|
+
self.session.headers.update({"User-Agent": "okhttp/4.9.2"})
|
|
80
|
+
|
|
81
|
+
def get_required_survey(self):
|
|
82
|
+
"""Lấy các survey chưa thực hiện"""
|
|
83
|
+
if not getattr(self.auth, 'email', None):
|
|
84
|
+
raise Exception("Lỗi: Không tìm thấy email trong session. Vui lòng chạy 'myfap login' lại để lấy thông tin.")
|
|
85
|
+
# Identifier cho API này là email (username)
|
|
86
|
+
checksum = create_checksum(self.auth.email, self.auth.campus)
|
|
87
|
+
url = f"https://survey.fpt.edu.vn/API/myFAP/GetRequiredSurvey?username={self.auth.email}&checksum={checksum}"
|
|
88
|
+
r = self.session.get(url)
|
|
89
|
+
if r.status_code == 200:
|
|
90
|
+
return clean_json(check_api_error(r.json()))
|
|
91
|
+
raise Exception(f"Lỗi lấy Survey: {r.text}")
|
|
92
|
+
|
|
93
|
+
def check_open_feedback(self):
|
|
94
|
+
"""Kiểm tra Feedback"""
|
|
95
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
96
|
+
url = f"{FAP_HOST}/CheckOpenFeedBack?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
97
|
+
r = self.session.get(url)
|
|
98
|
+
if r.status_code == 200:
|
|
99
|
+
return clean_json(check_api_error(r.json()))
|
|
100
|
+
raise Exception(f"Lỗi lấy Feedback: {r.text}")
|
|
101
|
+
|
|
102
|
+
def check_update_profile(self):
|
|
103
|
+
"""Kiểm tra Update Profile"""
|
|
104
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
105
|
+
url = f"{FAP_HOST}/CheckUpdateProfile?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
106
|
+
r = self.session.get(url)
|
|
107
|
+
if r.status_code == 200:
|
|
108
|
+
return clean_json(check_api_error(r.json()))
|
|
109
|
+
raise Exception(f"Lỗi lấy Update Profile: {r.text}")
|
|
110
|
+
|
|
111
|
+
def get_notification(self):
|
|
112
|
+
"""Lấy thông báo qua MSSV"""
|
|
113
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
114
|
+
url = f"{FAP_HOST}/GetNotificationByRoll?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
115
|
+
r = self.session.get(url)
|
|
116
|
+
if r.status_code == 200:
|
|
117
|
+
return clean_json(check_api_error(r.json()))
|
|
118
|
+
raise Exception(f"Lỗi lấy Notification: {r.text}")
|
|
119
|
+
|
|
120
|
+
def get_fee(self):
|
|
121
|
+
"""Lấy danh sách học phí chưa thanh toán"""
|
|
122
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
123
|
+
url = f"{FAP_HOST}/GetFeeByRoll?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
124
|
+
r = self.session.get(url)
|
|
125
|
+
if r.status_code == 200:
|
|
126
|
+
return clean_json(check_api_error(r.json()))
|
|
127
|
+
if r.status_code == 404:
|
|
128
|
+
return {"status": "Không có khoản nợ học phí nào cần thanh toán."}
|
|
129
|
+
raise Exception(f"Lỗi lấy Fee: {r.text}")
|
|
130
|
+
|
|
131
|
+
class MyFapClient:
|
|
132
|
+
def __init__(self, auth):
|
|
133
|
+
self.auth = auth
|
|
134
|
+
self.session = requests.Session()
|
|
135
|
+
self.session.headers.update({"User-Agent": "okhttp/4.9.2"})
|
|
136
|
+
|
|
137
|
+
def get_schedule(self, semester: str):
|
|
138
|
+
"""Lấy lịch học theo kỳ"""
|
|
139
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
140
|
+
url = f"{FAP_HOST}/GetActivityStudent?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Semester={semester}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
141
|
+
r = self.session.get(url)
|
|
142
|
+
if r.status_code == 200:
|
|
143
|
+
return clean_json(check_api_error(r.json()))
|
|
144
|
+
raise Exception(f"Lỗi lấy lịch học: {r.text}")
|
|
145
|
+
|
|
146
|
+
def get_marks(self, semester: str):
|
|
147
|
+
"""Lấy bảng điểm theo kỳ"""
|
|
148
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
149
|
+
url = f"{FAP_HOST}/GetStudentMark?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Semester={semester}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
150
|
+
r = self.session.get(url)
|
|
151
|
+
if r.status_code == 200:
|
|
152
|
+
return clean_json(check_api_error(r.json()))
|
|
153
|
+
raise Exception(f"Lỗi lấy bảng điểm: {r.text}")
|
|
154
|
+
|
|
155
|
+
def get_mark_by_course(self, course_id: str):
|
|
156
|
+
"""Lấy điểm chi tiết của một môn học"""
|
|
157
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
158
|
+
url = f"{FAP_HOST}/GetMarkByCourse?campusCode={self.auth.campus}&CourseId={course_id}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
159
|
+
r = self.session.get(url)
|
|
160
|
+
if r.status_code == 200:
|
|
161
|
+
return clean_json(check_api_error(r.json()))
|
|
162
|
+
raise Exception(f"Lỗi lấy điểm môn học: {r.text}")
|
|
163
|
+
|
|
164
|
+
def get_exams(self, semester: str):
|
|
165
|
+
"""Lấy lịch thi theo kỳ"""
|
|
166
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
167
|
+
url = f"{FAP_HOST}/GetScheduleExam?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}&Semester={semester}"
|
|
168
|
+
r = self.session.get(url)
|
|
169
|
+
if r.status_code == 200:
|
|
170
|
+
return clean_json(check_api_error(r.json()))
|
|
171
|
+
raise Exception(f"Lỗi lấy lịch thi: {r.text}")
|
|
172
|
+
|
|
173
|
+
def get_schedule_by_week(self, week: int, semester: str, year: int):
|
|
174
|
+
"""Lấy lịch học theo tuần"""
|
|
175
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
176
|
+
url = f"{FAP_HOST}/GetActivityStudentByWeek?campusCode={self.auth.campus}&week={week}&rollNumber={self.auth.mssv}&Semester={semester}&year={year}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
177
|
+
r = self.session.get(url)
|
|
178
|
+
if r.status_code == 200:
|
|
179
|
+
return clean_json(check_api_error(r.json()))
|
|
180
|
+
raise Exception(f"Lỗi lấy lịch học tuần: {r.text}")
|
|
181
|
+
|
|
182
|
+
def get_attendances(self, semester: str):
|
|
183
|
+
"""Lấy danh sách trạng thái điểm danh tổng quát của kỳ"""
|
|
184
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
185
|
+
url = f"{FAP_HOST}/GetStudentAttendances?campusCode={self.auth.campus}&Semester={semester}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
186
|
+
r = self.session.get(url)
|
|
187
|
+
if r.status_code == 200:
|
|
188
|
+
return clean_json(check_api_error(r.json()))
|
|
189
|
+
raise Exception(f"Lỗi lấy trạng thái điểm danh: {r.text}")
|
|
190
|
+
|
|
191
|
+
def get_course_attendance(self, semester: str, subject_code: str, class_name: str):
|
|
192
|
+
"""Lấy chi tiết điểm danh của một môn học"""
|
|
193
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
194
|
+
url = f"{FAP_HOST}/getCourseAttendance?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Semester={semester}&SubjectCode={subject_code}&ClassName={class_name}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
195
|
+
r = self.session.get(url)
|
|
196
|
+
if r.status_code == 200:
|
|
197
|
+
return clean_json(check_api_error(r.json()))
|
|
198
|
+
raise Exception(f"Lỗi lấy chi tiết điểm danh môn học: {r.text}")
|
|
199
|
+
|
|
200
|
+
def get_applications(self):
|
|
201
|
+
"""Lấy danh sách các đơn từ đã gửi cho trường"""
|
|
202
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
203
|
+
url = f"{FAP_HOST}/GetApplication?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
204
|
+
r = self.session.get(url)
|
|
205
|
+
if r.status_code == 200:
|
|
206
|
+
return clean_json(check_api_error(r.json()))
|
|
207
|
+
raise Exception(f"Lỗi lấy danh sách đơn từ: {r.text}")
|
|
208
|
+
|
|
209
|
+
def get_student_info(self):
|
|
210
|
+
"""Lấy thông tin sinh viên"""
|
|
211
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
212
|
+
url = f"{FAP_HOST}/GetStudentById?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
213
|
+
r = self.session.get(url)
|
|
214
|
+
if r.status_code == 200:
|
|
215
|
+
return clean_json(check_api_error(r.json()))
|
|
216
|
+
raise Exception(f"Lỗi lấy thông tin sinh viên: {r.text}")
|
|
217
|
+
|
|
218
|
+
def get_campus_info(self):
|
|
219
|
+
"""Lấy thông tin phòng Dịch vụ sinh viên"""
|
|
220
|
+
checksum = create_checksum(self.auth.mssv, self.auth.campus)
|
|
221
|
+
url = f"{FAP_HOST}/GetCampusInfo?campusCode={self.auth.campus}&rollNumber={self.auth.mssv}&Authen={self.auth.authen_key}&checksum={checksum}"
|
|
222
|
+
r = self.session.get(url)
|
|
223
|
+
if r.status_code == 200:
|
|
224
|
+
return clean_json(check_api_error(r.json()))
|
|
225
|
+
raise Exception(f"Lỗi lấy thông tin campus: {r.text}")
|
|
226
|
+
|