Compare commits

...

29 Commits
v0.1 ... master

Author SHA1 Message Date
Abdulkadir Furkan Şanlı
853c50bd13
Update licensing and copyright 2019-01-23 20:39:47 +01:00
Abdulkadir Furkan Şanlı
5369ed069d
Update README.md 2019-01-23 20:34:39 +01:00
Abdulkadir Furkan Şanlı
defb98498e
Add runtime copyright notice 2019-01-23 14:07:38 +01:00
Abdulkadir Furkan Şanlı
ca3c8fb580
Fix error in get_data docstring 2019-01-18 19:52:06 +01:00
Abdulkadir Furkan Şanlı
4f863ab71d
Add forgotten import 2019-01-17 18:31:22 +01:00
Abdulkadir Furkan Şanlı
623f87ad48
Functionalize comparison and clearance message bit 2019-01-17 18:02:12 +01:00
Abdulkadir Furkan Şanlı
c095d1d330
Functionalize exit sequence 2019-01-17 17:19:22 +01:00
Abdulkadir Furkan Şanlı
19559802d8
Rename stuple 2019-01-15 16:57:53 +01:00
Abdulkadir Furkan Şanlı
201d2d4a65
Rewrite get_data, unnecessary Python data processing 2019-01-15 12:43:51 +01:00
Abdulkadir Furkan Şanlı
cab6fdff4f
Change 2018 to 2019. 2019-01-11 23:31:38 +01:00
Abdulkadir Furkan Şanlı
3836735b12
Remove unnecessary comment. 2019-01-11 23:28:08 +01:00
Abdulkadir Furkan Şanlı
4e05e3380a
Properly document the damn thing. 2019-01-11 15:06:35 +01:00
Abdulkadir Furkan Şanlı
42e6042405 Intuitivize exit sequence. 2019-01-11 12:53:06 +01:00
Abdulkadir Furkan Şanlı
ce7286545b Prettify output. 2019-01-11 12:00:44 +01:00
Abdulkadir Furkan Şanlı
820936ae98 Fix select_final_time(). 2019-01-11 11:54:57 +01:00
Abdulkadir Furkan Şanlı
4280f46509 Update TODO.md 2019-01-06 09:28:46 +00:00
Abdulkadir Furkan Şanlı
c363abc56a
Update README.md 2019-01-06 10:11:45 +01:00
Abdulkadir Furkan Şanlı
1a309834af
Implement extra (non-IB) subject support, update README.md and TODO.md 2019-01-06 10:04:44 +01:00
Abdulkadir Furkan Şanlı
e8f51079d7
Databases now contain all classes' data 2019-01-05 10:49:18 +01:00
Abdulkadir Furkan Şanlı
b7611be5ee
Handle ValueErrors and rewrite code 2018-12-30 09:28:16 +01:00
Abdulkadir Furkan Şanlı
be5ff7177c
Handle ValueError. 2018-12-26 21:03:01 +01:00
Abdulkadir Furkan Şanlı
d1c98cd9c7
Update TODO.md 2018-12-19 22:39:24 +01:00
Abdulkadir Furkan Şanlı
fa2b91235e Update README.md 2018-12-16 10:48:40 +00:00
Abdulkadir Furkan Şanlı
ffddcd2978 Update TODO.md 2018-12-16 10:48:32 +00:00
Abdulkadir Furkan Şanlı
2e7fa574bd Minor fixes and add TODO.md 2018-12-13 10:00:22 +01:00
Abdulkadir Furkan Şanlı
9db07eaa97 Fix source file encoding and add starting title 2018-12-10 16:08:14 +01:00
Abdulkadir Furkan Şanlı
2b33b4719d Update README.md 2018-12-01 08:35:07 +01:00
Abdulkadir Furkan Şanlı
70a4ca18ca Minor changes 2018-11-04 11:33:43 +01:00
Abdulkadir Furkan Şanlı
8d5fa18966 Remove database 2018-11-03 10:14:57 +01:00
6 changed files with 194 additions and 115 deletions

1
.gitignore vendored
View File

@ -112,3 +112,4 @@ dmypy.json
# database files (may contain sensitive student info)
*.db
.vscode

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Abdulkadir Furkan Şanlı
Copyright 2018-2019 Abdulkadir Furkan Şanlı
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,64 +1,56 @@
# ib-clearance
ib-clearance is a program which helps schools manage the entrance and exiting of their IB students. Due to the unique nature of IB students' timetables, the program helps check individual timetables and give clearance to students who have finished for the day.
ib-clearance is a program which helps schools manage the entrance and exiting of their IB Diploma Program students. Due to the unique nature of IB students' timetables, the program helps to automatically check individual timetables and give clearance to students who have finished for the day.
### Building
## Building & running
The code is currently designed to run on Python 3.6.*.
The code is currently designed to run on Python 3.6.* and requires the [`getch`](https://pypi.org/project/getch/) module on platforms other than Windows.
I recommend building executables with `pyinstaller` with `pyinstaller --onefile ib-clearance.py`.
Binaries can be built using [`pyinstaller`](https://pypi.org/project/PyInstaller/): `pyinstaller --onefile ib-clearance.py`
### Lesson IDs
## Database specification
Equivalents of lesson names for use in class databases.
The program requires a SQLite database `database.db` in the working directory, containing data for all school classes.
- Academic Writing
- 'aw'
- Biology
- 'bi'
- Business Management
- 'bm'
- Chemistry
- 'ch'
- Computer Science
- 'cs'
- Economics
- 'ec'
- English A
- 'ena'
- English B
- 'enb'
- French
- 'fr'
- Geography
- 'ge'
- German
- 'de'
- Guidance
- 'gu'
- Mathematical Studies
- 'mst'
- Mathematics HL
- 'mhl'
- Mathematics SL
- 'msl'
- Polish A
- 'pl'
- Psychology
- 'ps'
- Self-Taught Language A
- 'st'
- Spanish
- 'es'
- Theory of Knowledge
- 'tok'
- Turkish A
- 'tr'
- Visual Arts
- 'va'
`database.db` must contain:
| Table | Description |
| ----------- | ------------------------------------------------------------ |
| `students` | Contains students' names, ID numbers and subject preferences |
| `timetable` | Timetable information (lessons) |
### `students`
| Column | Data type | Description |
| --------------- | --------- | ----------------------------------------------- |
| `id` | `INTEGER` | Student ID number used in program |
| `student_class` | `INTEGER` | IB class number (e.g. `1`, `2`) |
| `name` | `TEXT` | Full name of student |
| `g1` | `TEXT` | Group 1 subject ID |
| `g2` | `TEXT` | Group 2 subject ID |
| `g3` | `TEXT` | Group 3 subject ID |
| `g4` | `TEXT` | Group 4 subject ID |
| `g5` | `TEXT` | Group 5 subject ID |
| `g6` | `TEXT` | Group 6 subject ID |
| `other` | `TEXT` | ID(s) of other class(es) taken, space seperated |
### `timetable`
| Column | Data type | Description |
| -------------- | --------- | --------------------------------------------- |
| `lesson_class` | `INTEGER` | IB class which takes lesson (e.g. `1`) |
| `day` | `TEXT` | Day of the week (e.g. `monday`) |
| `end_time` | `TEXT` | Ending time of lesson (e.g. `09:55`, `13:05`) |
| `lesson_id` | `TEXT` | Subject ID of the lesson (e.g. `tok`) |
#### Subject IDs
Subject IDs may be anything, as long as consistency is maintained throughout the tables.
## License
Copyright (C) 2018 Abdulkadir Furkan Şanlı
ib-clearance is made available under the Apache License 2.0.
Copyright 2018-2019 Abdulkadir Furkan Şanlı
Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.

13
TODO.md Normal file
View File

@ -0,0 +1,13 @@
To-Do List
==========
## v0.2
- [x] Error handling (when entering invalid data types)
- [x] Make database contain data for all classes
- [x] Flexible mandatory subjects
- [x] Make script functional (sorta)
- [x] Document the damn thing
## v0.3
- [ ] Usability and GUI
- [ ] Timetable editor (add & remove lessons, view timetable)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Copyright 2018 Abdulkadir Furkan Şanlı
# Copyright 2018-2019 Abdulkadir Furkan Şanlı
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -14,54 +14,72 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import sqlite3
import time
from os import name
from sys import exit
# Windows has standard library getch, use that.
if name == "nt":
from msvcrt import getch
else:
from getch import getch
def connect_database(file):
"""
Create and return Connection object
:param file: database file
"""Get database connection object.
Connect to SQLite database and return a connection object.
:param file: SQLite database
"""
conn = sqlite3.connect(file)
return conn
def get_lower_weekday():
"""
Return current weekday's name as lowercase string
"""
day = time.strftime("%A")
lower_day = day.lower()
return lower_day
def get_data(conn):
"""Get student data.
Request student ID. Return tuple (id, class, other) with valid
student ID, corresponding class number and "other" subject IDs.
def check_id(conn, id):
"""
Return True if existing ID, False is not.
:param conn: Connection object
:param id: ID of student, int
"""
cur = conn.cursor()
cur.execute("SELECT id FROM students")
ids = cur.fetchall()
try:
id = int(input("\nPlease enter student ID: "))
for x in ids:
if id == x[0]:
return True
else:
return False
cur = conn.cursor()
cur.execute("""
SELECT id, student_class, other
FROM students
WHERE id = ?
""", (id,))
data = cur.fetchone()
if data is not None:
data = list(data) # SQLite returns tuples.
data[2] = data[2].split()
else:
raise ValueError
return data
except ValueError:
print("\nInvalid ID, try again.")
return get_data(conn)
def select_final_time(conn, day, id):
"""
Return ending time of final lesson student must attend, or None.
def select_final_time(conn, day, data):
"""Select student finishing time.
Returns ending time (type struct_time) of final lesson student must
attend on given day, or None if no lessons.
:param conn: Connection object
:param day: current weekday, lowercase str
:param id: ID of student, int
:param data: student data tuple returned by get_data
"""
cur = conn.cursor()
# Select finishing time of IB lessons.
cur.execute("""
SELECT end_time
FROM timetable
@ -71,55 +89,110 @@ def select_final_time(conn, day, id):
OR g4 = lesson_id
OR g5 = lesson_id
OR g6 = lesson_id
OR lesson_id = 'gu'
OR lesson_id = 'to'
WHERE id = ? AND day = ?
WHERE id = ?
AND day = ?
AND lesson_class = ?
ORDER BY end_time DESC
LIMIT 1
""", (id, day))
finish = cur.fetchone()
if str(type(finish)) == "<class 'tuple'>":
return finish[0]
""", (data[0], day, data[1])) # Queries return None if no matches.
ib_finish = cur.fetchone()
if ib_finish is not None:
ib_finish = parse_time_string(ib_finish[0])
# Select finishing time of other lessons.
others = []
for subject in data[2]:
cur.execute("""
SELECT end_time
FROM timetable
INNER JOIN students ON ? = lesson_id
WHERE id = ?
AND day = ?
AND lesson_class = ?
ORDER BY end_time DESC
LIMIT 1
""", (subject, data[0], day, data[1]))
subject_finish = cur.fetchone()
if subject_finish is not None:
others.append(parse_time_string(subject_finish[0]))
if not others:
others_finish = None
else:
return finish
others_finish = max(others)
if ib_finish is not None and others_finish is not None:
if ib_finish > others_finish:
finish = ib_finish
else:
finish = others_finish
elif ib_finish is not None:
finish = ib_finish
elif others_finish is not None:
finish = others_finish
else:
finish = None
return finish
def parse_time_string(timestring):
"""
Parse given 24h time string of format "HH:MM" into time_struct
"""Convert time string to tuple.
Parses given 24h time string of format "HH:MM" into the struct_time
object provided by library time.
:param timestring: time string "HH:MM"
"""
timestruct = time.strptime(timestring, "%H:%M")
return timestruct
structtime = time.strptime(timestring, "%H:%M")
return structtime
def clear(finish_time):
"""Return clearance message.
Compare the current time with finishing time and return relevant
clearance message.
:param finish_time: finishing time, struct_time object
"""
current_time = parse_time_string(time.strftime("%H:%M"))
if finish_time == None:
message = "Student has no lessons today, clear to leave."
elif finish_time < current_time:
message = "Student has finished for today, clear to leave."
else:
message = "Student still has lessons, clearance not granted."
return message
def exit_sequence():
"""Initiate exit sequence.
Asks user to enter character, and exits program if X is pressed.
"""
print("Press X to exit.")
key = getch()
if isinstance(key, bytes):
# msvcrt.getch returns type bytes, decode into str.
key = key.decode()
if key.upper() == "X":
exit()
def main():
db = input(
"Please enter name of database (located in the same folder as the program): ")
print("ib-clearance")
print("Copyright 2018-2019 Abdulkadir Furkan Şanlı")
y = "y"
while y == "y":
conn = connect_database(db)
day = get_lower_weekday()
id = int(input("Please input the student ID number: "))
conn = connect_database("database.db")
if check_id(conn, id):
raw = select_final_time(conn, day, id)
final = parse_time_string(raw) if raw != None else None
while True:
student_data = get_data(conn)
day = time.strftime("%A").lower()
finish_time = select_final_time(conn, day, student_data)
if final != None:
current_time = parse_time_string(time.strftime("%H:%M"))
print("\n" + clear(finish_time) + "\n")
if current_time > final:
print("Clear to leave.")
else:
print("Student does not have clearance.")
elif final == None:
print("Clear to leave.")
else:
print("Student does not exist in the database. Please try again.")
y = input("Press y and enter to run again.")
exit_sequence()
if __name__ == "__main__":

BIN
ib2.db

Binary file not shown.