|
|
1 Minggu lalu | |
|---|---|---|
| audio | 1 Minggu lalu | |
| fraction | 2 minggu lalu | |
| images | 2 minggu lalu | |
| obsolete | 1 Minggu lalu | |
| questionGenerators | 1 Minggu lalu | |
| resources | 1 Minggu lalu | |
| templates | 1 Minggu lalu | |
| timekeeperClientServices | 1 Minggu lalu | |
| .gitignore | 1 Minggu lalu | |
| PreHeaderFunctions.php | 1 Minggu lalu | |
| README.md | 1 Minggu lalu | |
| TK2.php | 1 Minggu lalu | |
| TkAnswerStore.php | 1 Minggu lalu | |
| admin_prefs.php | 1 Minggu lalu | |
| answerChecker2.php | 1 Minggu lalu | |
| e_cron.php | 1 Minggu lalu | |
| plugin.xml | 1 Minggu lalu | |
| timekeeper.php | 1 Minggu lalu | |
| timekeeper_menu.php | 1 Minggu lalu | |
| timekeeper_shortcodes.php | 1 Minggu lalu | |
| timekeeper_sql.php | 1 Minggu lalu | |
| tk_stats_page.php | 1 Minggu lalu |
An e107 plugin that makes screen time something students earn. Students answer questions (maths, spelling, anagrams, the periodic table); correct answers earn play minutes. A separate program on each student's computer (TimekeeperEnforcement) asks this server how many minutes are left and closes games when there are none.
/e107_plugins/timekeeper/timekeeper.php.timekeeperClientServices/timer.php.compatibility="2.0" in plugin.xml).htaccess-style blocking described under Securitywkhtmltopdf on the server (PDF reports), a text-to-speech server for spelling audio
(see Spelling audio), e107 mail configured (daily report emails)e107_plugins/timekeeper/ (lower case: the URLs assume it).timekeeper_sql.php.TimeKeeper_Student user class (and any teacher in
TimeKeeper_Teacher). plugin.xml declares both; check Admin → User Classes that they exist.
The code checks them as TIMEKEEPER_STUDENT and TIMEKEEPER_TEACHER.audio/ writable by the web server user. The spelling questions save their spoken
audio there.timekeeper_menu.php) for the sidebar
score box, and Admin → Scheduled Tasks (cron) → enable Send Reports for the daily email.Each student has one row in the timekeeper table. Edit them at Admin → TimeKeeper →
Student Limits: one form with a row per student, plus an Add a student box (the student
needs an e107 account). A row with an invalid value is left unchanged and the problem is
shown; the other rows still save. timer.php also creates the row, with the starting values
below, the first time the enforcement client asks about a student who has an e107 account.
| Column | Default | Meaning |
|---|---|---|
enabled |
1 |
0 = no limit for this student (the server replies 1440) |
freeMins |
10 |
Play minutes every day that don't need earned minutes |
enableTime / disableTime |
10.00 / 22.00 |
Allowed play window as HH.MM (22.30 = 10:30 pm). Write minutes as two digits: 9.5 means 9:50, not 9:30 |
minQuestionCount |
100 |
Questions to answer today before earned minutes can be used |
maxDailyPlayTime |
1440 |
Most minutes of play in a day, free and earned |
usedMinutes, lastDate |
0 |
Counters kept by the server (the screen shows today's usedMinutes for information) |
The window and day boundaries use the time zone set in timekeeperClientServices/timer.php
(Australia/Perth). Change it there if you're elsewhere.
Questions. TK2.php picks a subject from the list in $subjectsList, based on the
student's difficulty (all-time question count × last month's accuracy %), then asks the
generator in questionGenerators/. A subject unlocks at a difficulty threshold:
| Subject | Unlocks at |
|---|---|
| numbers (missing number), spelling | 0 |
| addition | 10,000 |
| subtraction | 20,000 |
| rounding (money to the nearest 5 cents) | 50,000 |
| elements (periodic table) | 150,000 |
| multiplication | 200,000 |
| division | 300,000 |
| anagrams | 4,000,000 |
Worded problems and the geography/history/health subjects exist or are stubbed but are switched
off (the 0 in $subjectsList in TK2.php). To switch one on, change that 0 to a 1; to change
when a subject appears, change its number. Worded problems (word_problems) would unlock at 250,000 and use whole-number
answers only: pillow cases, sponges, an elephant's dinner, sandwiches, marbles, a day at the beach,
cupcakes and sugar bags. The numbers get bigger as the student's accuracy and number of answers grow.
Answers. The expected answer never goes to the browser. The generator stores it in the
tkPendingAnswer table (TkAnswerStore.php) and the form carries a random single-use token
(checkerData). Answering consumes the token, so a changed token, a stale browser tab, a
double submit or an old question gets "That question has expired or was already answered".
Tokens last 2 hours.
Scoring. A correct answer adds round(last month's accuracy % ÷ 10) minutes (at least
1). A wrong answer takes one minute off, never below zero. Every answer is written to
tkReport.
Play time. The enforcement client calls timer.php once a minute while a game is
running. The reply is a number (minutes remaining) or a message explaining why play isn't
allowed. The server uses today's free minutes first, then earned minutes (only if
minQuestionCount questions were answered today).
URL (under /e107_plugins/timekeeper/) |
Who | What |
|---|---|---|
timekeeper.php |
students, teachers | The questions page |
timekeeper.php?mode=Generate%20PDF&user=NAME&output=pdf (or html) &range=today |
logged in: admin, or that student | Report of answered questions. range: today, yesterday, pastWeek, pastMonth, pastQuarter, pastYear |
timekeeper.php?mode=short&user=NAME&range=today |
same, or with &key= |
Question count and accuracy |
tk_stats_page.php?user=NAME&key=KEY |
anyone with the key (anyone at all if no key is set) | Per-subject scores and minutes left; refreshes every minute |
timekeeperClientServices/timer.php?user=NAME&game=PROCESS |
the enforcement client | Minutes remaining; &peek=1 doesn't use a minute |
timekeeperClientServices/games.json |
the enforcement client | Process names to treat as games |
Admin → TimeKeeper (needs the Plugin Manager permission): Student Limits, Score, Report (every answer), Spelling Words (list, add, and a "Spelling Score" summary showing how many words still need a usage sentence), Geography (data only: unused so far), Preferences. Questions, Pending and Report (Old) are screens for tables from an earlier version.
| Table | Holds |
|---|---|
timekeeper |
Per-student limits (above) |
timekeeperScore |
Lifetime counts and earned minutes |
tkReport |
Every answer given |
tkLastQuestion |
The question currently on screen, per student |
tkPendingAnswer |
The expected answer behind it (single use) |
timekeeperStatistics |
Minutes played per student, game and day |
tk_wordList |
Spelling and anagram words |
tk_countries |
Country data for the unfinished geography subject |
timekeeperPending, timekeeperQuestions, timekeeperReport, timekeeperStats |
Earlier versions; still listed in plugin.xml |
Tables from an earlier install: add any that are missing from timekeeper_sql.php and run
SELECT user, COUNT(*) FROM e107_tkLastQuestion GROUP BY user;. If a student has more than one
row, DELETE FROM e107_tkLastQuestion; clears them: the next question regenerates.
questionGenerators/english/spelling2.php asks a text-to-speech server for each word, saves it
to audio/<md5 of the word>.mp3, and reuses it. The server address is the TTS_URL constant at
the top of that file (an OpenAI-style /v1/audio/speech endpoint). It needs allow_url_fopen.
If audio can't be produced, the sentence is shown with the word blanked out instead.
tk_stats_page.php shows any student's
scores to anyone who knows the username.Keep obsolete/ unreachable. It holds old code that no longer ships. If you deploy by copying
the repo, block it in the Apache vhost:
<Directory /path/to/e107_plugins/timekeeper/obsolete>
Require all denied
</Directory>
and check a file in it returns 403. Also consider Options -Indexes for the site root.
Nothing the student types or the URL contains is trusted: user names and game names are validated, SQL is escaped, and output is HTML-escaped.
This repo is readable without signing in. e_cron.php contains the report email addresses
and student account names: don't commit anything private.
e_cron.php emails each student's previous day (questions, accuracy, active study time) to the
parent address and the student. The names and addresses are in one block at the top of the file:
edit them there. The reporting window is "yesterday, midnight to midnight" ($windowStart,
$windowEnd).
PDF reports run wkhtmltopdf; install it and make sure the web server user can run it. The Excel
worksheet generator in PreHeaderFunctions.php needs lib/PHPExcel.phar, which isn't in the repo,
and isn't linked from any page at the moment.
TimekeeperEnforcement runs as root on each student's computer and needs Java 11+. Its README covers its settings file and a systemd unit.
games.json is a list of names (an array, or an object whose values are the names). Each name is
looked for in the full command line of the student's processes: check what a game looks like first
with ps -eo user,args | grep -i NAME. It's a deny-list: anything not listed isn't enforced.
Deploy timer.php before the client. If you run the old PHP client (obsolete/), it still works
against the new timer.php, but it can't update itself any more.
| Symptom | Likely cause |
|---|---|
| "That question has expired or was already answered" | Stale tab, double click, or a question older than 2 hours: answer the new question |
| Spelling shows "Audio is unavailable right now" | audio/ missing or not writable, TTS server unreachable, or allow_url_fopen off |
tk_stats_page.php is blank |
user isn't a plain username, the student has no timekeeper row yet, or the key is wrong (403) |
| Report URL gives "Forbidden" | Not logged in, or logged in as a different student |
| Student always gets "You have not answered enough questions to play" | Questions needed (minQuestionCount) on the Student Limits screen is higher than they answer in a day (default is 100) |
| Games close at exactly 0 minutes | That's intended: free minutes are used first, then earned ones |
| Nothing is closed on the student's machine | Check the client's log, and that the game name in games.json really appears in ps output |