Skip to content

Commit 2266d82

Browse files
authored
Merge pull request #121 from dbosk/copilot/add-feedback-terminal-grading
Add conditional feedback to terminal grading based on recent activity
2 parents bc9105f + 77b4039 commit 2266d82

File tree

1 file changed

+93
-19
lines changed

1 file changed

+93
-19
lines changed

modules/terminal/grading/grade.sh.nw

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -103,28 +103,87 @@ Now we can check the history files.
103103
We provide a function that takes a list of students, checks the history file of
104104
the student, grades the student (and provides feedback) accordingly.
105105
The feedback is passed through stdout.
106-
(For now, we don't provide the feedback since we don't check if the student has
107-
already gotten the feedback.)
106+
We only provide feedback if the student has made changes to files in the Public
107+
directory since the last grading date. This way we avoid giving feedback for old
108+
attempts.
108109
The grade is indicated by the return value (1 for fail, 0 for pass).
110+
111+
First, we define a helper function to check if there are any recent changes in
112+
the Public directory. The function takes the path to the Public directory and the
113+
grading time as parameters. It returns "yes" if there are files newer than the
114+
grading time, "no" otherwise.
115+
<<function to check if Public has recent changes>>=
116+
has_recent_public_changes() {
117+
local public_path=$1
118+
local grading_time=$2
119+
120+
# If grading_time is empty or all zeros, consider it as no previous grading
121+
if [ -z "$grading_time" ] || [ "$grading_time" = "0000-00-00" ]; then
122+
echo "yes"
123+
return 0
124+
fi
125+
126+
# Find the newest file in Public directory
127+
local newest_file=$(find "$public_path" -type f -printf '%T@ %p\n' 2>/dev/null \
128+
| sort -n | tail -1 | cut -d' ' -f2-)
129+
130+
if [ -z "$newest_file" ]; then
131+
echo "no"
132+
return 0
133+
fi
134+
135+
# Get the modification time of the newest file in ISO 8601 format
136+
local newest_time=$(stat -c %y "$newest_file" 2>/dev/null | cut -d'.' -f1 | sed 's/ /T/')
137+
138+
# Compare times (ISO 8601 format allows lexicographic comparison)
139+
if [[ "$newest_time" > "$grading_time" ]]; then
140+
echo "yes"
141+
else
142+
echo "no"
143+
fi
144+
}
145+
@
146+
147+
Now we can check the history files.
109148
<<function taking a list of students and returning passes>>=
110149
<<function to get home directory>>
150+
<<function to check if Public has recent changes>>
111151

112152
grade_history_file() {
113153
local student=$1
114154
local homedir=$2
155+
local grading_time=$3
115156
local path="/afs/kth.se/$homedir/Public/datintro"
116157
local filepath="$path/history.txt"
158+
local public_path="/afs/kth.se/$homedir/Public"
159+
160+
# Check if there are recent changes in Public directory
161+
local has_recent_changes=$(has_recent_public_changes "$public_path" "$grading_time")
162+
163+
# Only provide feedback if there are recent changes
164+
if [ "$has_recent_changes" != "yes" ]; then
165+
# No recent changes, just return failure without feedback
166+
if ! [ -d $path ] || ! [ -f $filepath ] || ! [ -r $filepath ] || \
167+
! egrep " *[0-9]+.* history *>>? *([^ ]+/)?history.txt" $filepath > /dev/null; then
168+
return 1
169+
fi
170+
return 0
171+
fi
117172

173+
# Provide specific feedback based on the failure mode
118174
if ! [ -d $path ]; then
119-
#echo "Can't find datintro directory in directory Public in your home directory."
175+
echo "Can't find the 'datintro' directory in the 'Public' directory in your home directory. Please ensure you create it in the correct location (~/Public/datintro)."
120176
return 1
121177
elif ! [ -f $filepath ]; then
122-
#echo "Can't find history.txt located in directory Public/datintro in your home directory."
178+
echo "Can't find the file 'history.txt' in the 'Public/datintro' directory in your home directory. Please ensure you create it in the correct location (~/Public/datintro/history.txt)."
179+
return 1
180+
elif ! [ -r $filepath ]; then
181+
echo "The file 'Public/datintro/history.txt' exists but cannot be read. This usually means you created the file outside the 'Public' directory and then moved it there. Files must be created directly in the 'Public' directory to inherit the correct permissions. Please remove the 'datintro' directory and create it again inside 'Public', then create the 'history.txt' file there. Warning: Never remove the 'Public' directory itself."
123182
return 1
124183
elif ! egrep " *[0-9]+.* history *>>? *([^ ]+/)?history.txt" $filepath \
125184
> /dev/null;
126185
then
127-
#echo "Found Public/datintro/history.txt in your home directory, but it seems to have the wrong format."
186+
echo "Found 'Public/datintro/history.txt' in your home directory, but it doesn't have the correct content. Please read the assignment instructions carefully and ensure you redirect the output of the 'history' command to the file."
128187
return 1
129188
fi
130189
}
@@ -138,10 +197,15 @@ the first argument (it's a regex passed to [[canvaslms]]). The remaining
138197
arguments constitutes a list of courses.
139198

140199
To grade, we iterate through the remaining students, given by
141-
[[students_to_grade]] (from [[common.sh]]).
142-
We get the home directories of the students through [[get_home_directory]].
200+
[[students_with_grading_time]] (from [[common.sh]]).
201+
We cache the home directories for all students by calling [[get_home_directory]]
202+
once with all students, rather than calling it once per student.
203+
This is more efficient since [[get_home_directory]] uses SSH and has significant
204+
delays.
143205
Then we can iterate through the student--home directory tuples and grade
144206
them.
207+
We pass the grading time to [[grade_history_file]] so it can check if there
208+
are recent changes in the Public directory before providing feedback.
145209
Depending on the grade we report P or F.
146210
<<grade students>>=
147211
grade_students() {
@@ -151,27 +215,37 @@ grade_students() {
151215
local feedback=$(mktemp)
152216

153217
for course in $*; do
154-
local students=$(mktemp)
155-
students_to_grade "${course}" "${assignment}" > ${students}
156-
157-
for student_home in $(get_home_directory $(cat ${students})); do
158-
local student=$(echo $student_home | cut -f 1 -d:)
159-
local homedir=$(echo $student_home | cut -f 2 -d:)
160-
161-
if grade_history_file $student $homedir > $feedback; then
218+
local students_times=$(mktemp)
219+
students_with_grading_time "${course}" "${assignment}" > ${students_times}
220+
221+
# Get all students from the student_time pairs
222+
local students=$(cut -f 1 ${students_times})
223+
224+
# Cache home directories for all students at once
225+
local home_dirs=$(mktemp)
226+
get_home_directory $students > ${home_dirs}
227+
228+
# Process each student using the cache
229+
while IFS=$'\t' read -r student grading_time; do
230+
# Look up home directory from cache
231+
local student_home=$(grep "^${student}:" ${home_dirs})
232+
local homedir=$(echo "$student_home" | cut -f 2 -d:)
233+
234+
if grade_history_file "$student" "$homedir" "$grading_time" > "$feedback"; then
162235
echo "$student (terminal)"
163236

164237
canvaslms grade -c "${course}" -a "${assignment}" \
165238
166239

167240
sleep 0.2
168-
elif [ -s $feedback ]; then
241+
elif [ -s "$feedback" ]; then
169242
canvaslms grade -c "${course}" -a "${assignment}" \
170-
-u [email protected] -g F -m "$(cat $feedback)" &
243+
-u [email protected] -g F -m "$(cat "$feedback")" &
171244
fi
172-
done
245+
done < ${students_times}
173246

174-
rm ${students}
247+
rm ${students_times}
248+
rm ${home_dirs}
175249
done
176250

177251
wait

0 commit comments

Comments
 (0)