Açıklama Yok

Gregory Huxley 8756e92f47 Add flags question generator. 4 gün önce
audio 1686ade99e Update gitignore and More fixes 1 hafta önce
fraction 7fe48d7027 Add fractions.. 6 gün önce
images 3f8bcdaf28 initial commit 2 hafta önce
obsolete ee350c0968 More fixes 1 hafta önce
questionGenerators 8756e92f47 Add flags question generator. 4 gün önce
resources 6df801a403 Make worded questions work again.. 1 hafta önce
templates 1686ade99e Update gitignore and More fixes 1 hafta önce
timekeeperClientServices f3c61fd3f1 Update timer.php to sent 1440 instead of 30 when Timekeeper is disabled. 1 hafta önce
.gitignore 214f331e1d Remove IDE folder.. 1 hafta önce
PreHeaderFunctions.php bb3c17237e More fixes 1 hafta önce
README.md 8756e92f47 Add flags question generator. 4 gün önce
TK2.php 8756e92f47 Add flags question generator. 4 gün önce
TkAnswerStore.php 4c5028103a More fixes 1 hafta önce
admin_prefs.php f9bcfa822a Add Readme. And add Per-student limits to admin section. 1 hafta önce
answerChecker2.php 8756e92f47 Add flags question generator. 4 gün önce
e_cron.php bb3c17237e More fixes 1 hafta önce
flag.php 8756e92f47 Add flags question generator. 4 gün önce
plugin.xml 3b89011b89 More fixes 1 hafta önce
timekeeper.php d0cec6e6c3 More fixes 1 hafta önce
timekeeper_menu.php 3b89011b89 More fixes 1 hafta önce
timekeeper_shortcodes.php 1686ade99e Update gitignore and More fixes 1 hafta önce
timekeeper_sql.php 3b89011b89 More fixes 1 hafta önce
tk_stats_page.php d0cec6e6c3 More fixes 1 hafta önce

README.md

TimeKeeper

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.

  • Students answer questions at /e107_plugins/timekeeper/timekeeper.php.
  • Parents/admins get a daily report email, PDF/HTML reports, a stats page, and admin screens for scores, answers and the spelling word list.
  • The enforcement client talks to timekeeperClientServices/timer.php.

Requirements

  • e107 2.x (compatibility="2.0" in plugin.xml)
  • PHP 7.1 or newer, MySQL/MariaDB
  • Apache, if you want the .htaccess-style blocking described under Security
  • Optional: wkhtmltopdf on the server (PDF reports), a text-to-speech server for spelling audio (see Spelling audio), e107 mail configured (daily report emails)

Install

  1. Put the folder at e107_plugins/timekeeper/ (lower case: the URLs assume it).
  2. Admin → Plugin Manager → install TimeKeeper. This creates the tables from timekeeper_sql.php.
  3. Put each student in the 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.
  4. Admin → TimeKeeper → Preferences: set the Stats / summary key (see Security).
  5. Make audio/ writable by the web server user. The spelling questions save their spoken audio there.
  6. Add words under Admin → TimeKeeper → Spelling Words → Add Words. Each needs a word, a usage sentence and a year level (1–13). Words without a usage sentence are never asked.
  7. Optional: Menu Manager → enable the TimeKeeper menu (timekeeper_menu.php) for the sidebar score box, and Admin → Scheduled Tasks (cron) → enable Send Reports for the daily email.

Per-student limits

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.

How it works

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
flags (switched off until you turn it on) 120,000
elements (periodic table) 150,000
multiplication 200,000
division 300,000
fractions (switched off until you turn it on) 350,000
anagrams 4,000,000

The geography subjects other than flags, and the history/health ones, are stubbed but 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.

Flags (flags, unlocking at 120,000 once switched on) show a flag from resources/flags/ and the student types the country's name. A country is asked only if tk_countries has its isoCode (the 3-letter code that names the flag file, e.g. AUS for AUS.svg) and the flag file exists. The difficulty column (1 easy ... 3 hard in the current data) sets the order: a new student gets the easiest 15% and the list opens up as their accuracy grows. Countries asked least this month come first. The page shows the flag through flag.php, which sends the flag for the student's open question without naming the file, so the answer isn't in the address. Names are checked by questionGenerators/geography/countryNames.php: capitals, accents and punctuation don't matter, alternative names are accepted (USA, Holland, Ivory Coast, Burma, DR Congo ...), one slipped letter in a long name is forgiven, and the name of a different country never is. Two rows with the same isoCode (Bosnia and Herzegovina) are asked once.

Fractions (fractions, unlocking at 350,000 once switched on) use the fraction/ folder, a copy of the open-source phospr/fraction library (MIT licence, lightly modified). The questions are simplifying, adding and subtracting (same denominator, then one a multiple of the other, then unrelated), multiplying, dividing, writing an improper fraction as a mixed number, and "3/4 of 20". The harder kinds appear as the student's accuracy grows. Answers can be typed as 3/4, a mixed number (1 1/2), a whole number, or an exact decimal (0.75), but must be in their simplest form: a right value that could be simplified is marked wrong with a hint, as is an improper fraction when a mixed number was asked for.

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).

Pages and URLs

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
flag.php the student's own browser The flag for their open flags question (logged in only)

Admin area

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.

Database

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.

Spelling audio

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.

Security

  • Stats key. Set it under Preferences. Without one, tk_stats_page.php shows any student's scores to anyone who knows the username.
  • Reports need a login. A student can only see their own.
  • 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.

Daily report email

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 and Excel

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.

The enforcement client

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.

Troubleshooting

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