Conditional activities: Quiz Lock Hack for Moodle 1.6.4 (Quiz Module)

Conditional activities: Quiz Lock Hack for Moodle 1.6.4 (Quiz Module)

by Deleted user -
Number of replies: 0

Quiz Lock Hack for Moodle 1.6.4 (Quiz Module)

First, the disclaimer…

This is only a hack! That means it worked for me, and does what I want it to do, but it may not work for you, or it may not work the way you want it to work.

This has only been tested on Moodle 1.6.4, in the file mod/quiz/view.php (version 1.88.2.6 2006/10/05)

Do NOT test on your production server. Check it on a test site first.

Make a copy of your original mod/quiz/view.php and rename it to something like view ORIGINAL.php or view.php.original .

-----------------------------------

Okay, now on to the rest of the story…

I wanted to be able to prevent students from taking a particular exam until they had achieved a certain grade on a previous exam. I read through a lot of posts in the Conditional Activities forum, and it appeared that although Activity Locking was not tested on Moodle 1.6.4, that Score Lock should work. So I downloaded Score Lock, and played around with it, but I could not get it working.

So of course I did what any average-computer-guy-who-has-never-programmed-in-php-before does, and decided to write the code myself! So this hacks constitutes my entire knowledge php programming, including one whole week of php experience.

I guess what I’m trying to say is, that I hope this useful to somebody, but I’m no expert, and won’t be able to give much support to this hack, except maybe explanations of my code, and what it’s doing, and why it’s doing it that way.

WHAT IT DOES:

When your student selects a Quiz, they are presented with a screen that gives them information or instructions about the quiz, and at the bottom of this screen, there is a button (assuming the quiz is open and they still attempts left), that says either “Attempt Now” or “Re-Attempt Now” or “Continue Last Attempt”. This hack will check an array that you setup, to see if this current quiz has to meet a certain grade in a previous quiz. If this previous requirement exists, then it will check the students best grade they achieved on that previous quiz, against a grade you specify, and if there their best grade is equal to or higher than the grade you specified, it will allow the buttons mentioned above to display. If their best grade is below the specified grade, then it will not display the above buttons, but will instead display a message that says: “You cannot attempt this Quiz until you have achieved a grade of 65% on the previous Quiz.”

For our purposes, we have a series of 15 exams (101 thru 115), and you must take them consecutively (starting at 101), and achieve a grade of 85% before you can proceed to the next one. So I wrote it with this “linear” model in mind.

EXAMPLE: You need 60% on 101 before you can take 102. You need 65% on 102 before you can take 103. You need 70% on 103 before you can take 104… etc.

It also is very easy to change the hack, so that several quizzes depend on one particular quiz before they are unlocked. I will call this a “branch” model.

EXAMPLE: You need 65% on 101 before you can take 102, 103, and 104. You need 75% on 102 before you can take 105, 106 and 107. You need 75% on 103 before you can take 108, 109 and 110. You need 75% on 104 before you can take 111, 112 and 113.

WHAT IT WON’T DO:

It does not allow you to have multiple requirements to unlock a quiz. It can only check the grade in ONE previous quiz, to see whether or not it should unlock the current quiz.

EXAMPLE (of what it cannot do): You need 65% on 101 and 70% on 102 before you can take 103.

OTHER NOTES:

There are 4 blocks of code that need to be inserted into the view.php file. I tried to make lots of comments in the code to help explain what it is doing, so make sure you read thru the code blocks before you install it. Each block has a comment telling you where to insert it.

This hack does NOT make any changes or modifications to the database. It simply checks the database to see if the quizzes exist, and to see what the students best grade was.

If student had previously attempted the quizzes, before the hack was installed, all their attempts are still kept, but if they had not achieved the unlock grade, they will now be locked out, and have to return to the previous quiz and pass it before they can continue again.

The one KNOWN ISSUE is this… if the student had previously attempted the quizzes, before the hack was installed, and they had achieved the unlock grade, they will be allowed to continue that attempt, even if they had not achieved the unlock grade on earlier quizzes.

EXAMPLE: Prior to the Quiz Lock Hack being installed, the student could take any quiz in any order, and the student took the following quizzes:

101 and achieved 58% (need 60% to pass)

102 and achieved 62% (need 65% to pass)

103 and achieved 83% (need 70% to pass)

104 and achieved 71% (need 75% to pass)

105 and achieved 69% (need 80% to pass)

After the hack is installed:

102 will now be locked until they achieve 60% on 101

103 will now be locked until they achieve 65% on 102

104 will be UNLOCKED because they achieved 83% on 103, and only needed 70% to pass.

105 will now be locked until they achieve 75% on 104.

HOW TO INSTALL

STEP 1 – Make a copy of your mod/quiz/view.php file, and rename it to something like viewORIGINAL.php or view.php.original.

STEP 2 – Get out a piece of paper and pen (seriously). This is the part where you have to do little bit of work (and why this called a hack). You will need to select each quiz individually (in student mode), and write down the id= number that shows up in your address bar. Here’s what I mean…

You have to first select a course (as a student), and then you will select QUIZZES from the ACTIVITIES block. This should bring up a list of the quizzes for that course. If you hover the mouse over each quiz, it will show you the link (usually along the bottom of your browser) to the quiz, which will look something like this:

http://yousite.com/mod/quiz/view.php?id=63

You need to write down the quiz name and this id number (63 in this case), for each quiz. Each quiz will have a unique id number, and it won’t necessarily be in any specific order.

If you don’t see this information when you hover over the link, you can click on the link, you should see this information appear in the address bar at the top of your browser.

STEP 3 – You now need to write down what grade you want the student to achieve on each quiz, before they can go to the next one. Your list should look something like this:

Exam 101 id=63 need 65% to pass/unlock next quiz

Exam 102 id=66 need 75% to pass/unlock next quiz

Exam 103 id=71 need 80% to pass/unlock next quiz

Exam 104 id=82 need 85% to pass/unlock next quiz

Exam 105 id=67 need 90% to pass/unlock next quiz

STEP 4 – Now open up your text editor, and insert the 4 blocks of code into your mod/quiz/view.php as directed (make sure you make a copy of view.php before you edit it).

STEP 5 – You now need to find the second inserted block (Block 2 of 4), and look for the array. Looks like this:

$QuizName=array('Exam101','Exam102','Exam103','Exam104','Exam105');
$QuizId =array( 63 , 66 , 71 , 82 , 67 ); 
$QuizPass=array( 65 , 75 , 80 , 85 , 90 ); 
$QuizPrev=array( 0 , 0 , 0 , 0 , 0 ); 

STEP 6 – Change the names in the first line of this array ($QuizName) to your quiz names. NOTE: You can change the number of quizzes in the array to more quizzes or less quizzes, you just need to make sure you have the same number of elements for each of the four lines above.

STEP 7 – Change the id number of each quiz in the second line of this array ($QuizID) to the id numbers you wrote down on your piece of paper.

STEP 8 – Change the grade required to pass/unlock the next quiz in the third line of this array ($QuizPass) to the numbers you wrote down on your piece of paper.

STEP 9 – You can leave the zeros in the $QuizPrev line of the array, if you are implementing the “linear” model I talked about above. If you want to implement the “split” model that I talked about above, you need to carefully read ALL the comments in this block, and it will tell you how to do it.

STEP 10 – Save your file, and have fun testing!!!!

I have attached the fully modified view.php file, or here are the four blocks of code:

 

//******************************************************************************************

//*** QUIZ LOCK HACK - Block 1 of 4 - by Jeff Sherk Mar 1, 2007

//******************************************************************************************

//*** WARNING: USE AT YOUR OWN RISK!!!

//***

//*** This hack has only been tested on Moodle 1.6.4 for the Quiz Module file:

//*** /mod/quiz/view.php (view.php version 1.88.2.6 2006/10/05)

//***

//*** WARNING: USE AT YOUR OWN RISK!!!

//******************************************************************************************

//*** Insert this block, immediately AFTER the 1st line of this file.

//******************************************************************************************

//*** NOTE: This hack does NOT modify or change any database records. All grades and

//*** all quizzes and all quiz attempts will still be in the database.

//***

//*** KNOWN ISSUE:

//*** If the student enters a Quiz, and they have already achieved the Unlock Grade in

//*** in the previous Quiz, they will be allowed to attempt it, EVEN if they have not

//*** achieved the the Unlock Grade in the Quiz previous to the previous Quiz...

//*** EXAMPLE: Assume you have 4 quizzes, Quiz 101, Quiz 102, Quiz 103 and Quiz 104, and

//*** each Quiz requires you to achieve 75% on the previous Quiz before you can take the

//*** next one. And let's say, that before you installed the Quiz Lock Hack, the student

//*** had score %80 on 101, 70% on 102, and 85% on 103. They would be locked out of Quiz

//*** 103, until they achieve a 75% on Quiz 102, but they could still take Quiz 104

//*** because they achieved the Unlock Grade already on Quiz 103.

//*** POSSIBLE SOLUTION: Change the database directly. You could change the

//*** mdl_quiz_grade table (grade column), which keeps the highest grade achieved for

//*** each student and for each quiz.

//******************************************************************************************

//*** end Block 1 of 4 - QUIZ LOCK HACK

//******************************************************************************************

 

 

 

 

 

 

 

 

 

//******************************************************************************************

//*** QUIZ LOCK HACK - Block 2 of 4 - by Jeff Sherk Mar 1, 2007

//******************************************************************************************

//*** Insert this block, immediately BEFORE the lines that read:

//*** require_login($course->id, false, $cm);

//*** $isteacher = isteacher($course->id);

//******************************************************************************************

 

//*** If view.php has the $q= parameter passed in (instead of the $id= parameter) then

//*** get the corresponding $id= parameter and set it.

if ($id==0) {

$id = $cm->id;

}

 

//*** Variables explanation:

// $ThisId THIS Quiz ID (this variable is passed into view.php from previous screen).

// You will have to manually write down each ID used for each quiz.

//

// $PrevId PREVIOUS Quiz ID

// From the list of ID's you wrote down above, you will need to decide which

// ID will be the PREVIOUS Quiz ID to THIS Quiz ID.

//

// $UnlockGrade Percentage (between 0 and 100) needed on PREVIOUS Quiz to unlock THIS Quiz

// Default is 0, so that it won't lock a quiz if you enter in a wrong ID.

//

// $BestGrade This is the highest grade achieved in the PREVIOUS Quiz

// Default is 0, so that it won't lock a quiz if you enter in a wrong ID.

//

// $QuizLock 1 = THIS Quiz is locked 0 = THIS Quiz is unlocked

//

// $CantAttempt This is the message that is displayed to the student if the Quiz is locked.

//

// $CantName This will display the name of the previous Quiz the student must pass,

// if the Quiz is locked.

$ThisId = $id;

$PrevId = 0;

$UnlockGrade = 0;

$BestGrade = 0;

$QuizLock = 1;

$CantAttempt = '';

$CantName = 'QUIZ LOCK HACK error';

 

//*** Here's an explanation of the array below:

//***

//*** NOTE: The array can be just about any size, from only two cloumns (two quizzes) all the way up

//*** to whatever the limit is on array size. Just make sure you have the same number of

//*** columns (or quizzes or elements) in each of the four arrays below. The example below

//*** uses 5 columns (or 5 quizzes), but you can change it to anything, just make sure

//*** they all line up...

//***

//*** $QuizName - These are names you assign to your Quizzes. You can call them anything you want.

//*** The only place this is used, is in the message to the student, that tells them

//*** the grade and the name of the previous Quiz they must pass, before they can

//*** complete the current Quiz.

//***

//*** $QuizId - This requires some work... the best place to get these id's, is when you enter

//*** in to do a Quiz. You need to look at the address bar of your browser, and you will

//*** see something like the following line:

//*** http://yourwebsite/mod/quiz/view.php?id=63

//*** You need to mark down the number at the very end (63 in this example). There is

//*** a unique id number for each Quiz, and you will need to enter in to each Quiz,

//*** and mark down what this id is, and then replace the numbers in the $QuizId array

//*** below.

//***

//*** $QuizPass - This is the grade the student must achieve (on their previous Quiz) in order to unlock

//*** the current Quiz. They must achieve this grade (or higher). This should be a number

//*** from 0 to 100. For example, use 50 for 50% or 85 for 85%.

//*** Note also the way it is set up in the array: for example, the number you enter in the

//*** column, say underneath 'Exam 101' in this example, is the grade they must achieve on

//*** 'Exam 101', in order to unlock the next Quiz. This also means that the grade you

//*** place in the last column, under the last quiz ('Exam 105' in this example), is meaningless,

//*** since there are no more quizzes beyond.

//***

//*** $QuizPrev - This is the id of the previous Quiz that it must check to see if the student passed or not.

//*** In this example it is all zeros, because the array is filled in automatically by the lines

//*** code immediately following the arry.

//*** The code below the array will fill in the $QuizPrev array with the id of each previous quiz,

//*** based on the $QuizID array. It assumes that each Quiz listed in your array, is looking to

//*** the previous Quiz listed in your array, for it's unlock grade.

//*** If this is not the case, then you can manually enter the Quiz id into the $QuizPrev array,

//*** and REM out the whole section of code following the array.

//*** Manually entered, it would look like this: $QuizPrev = array(0, 63, 64, 66, 65);

//*** IMPORTANT: The first entry of the $QuizPrev array (underneath the first quiz 'Exam 101'),

//*** should alwaysbe zero(0), otherwise the student might be locked out of the first Quiz.

$QuizName = array('Exam 101','Exam 102','Exam 103','Exam 104','Exam 105');

$QuizId = array( 63 , 66 , 71 , 82 , 67 );

$QuizPass = array( 65 , 75 , 80 , 85 , 90 );

$QuizPrev = array( 0 , 0 , 0 , 0 , 0 );

 

//*** This will fill in $QuizPrev array with the id of each of the previous quizzes, based on the

//*** $QuizID array. It assumes that each Quiz listed in your array is looking to the previous

//*** Quiz listed in your array for it's unlock grade.

//*** If this is not the case, then you can manually enter the Quiz id into the $QuizPrev array

//*** above, and REM out this whole section.

//***

//*** $QuizCount is just a variable used to keep count of where I am in the FOREACH loops.

//***

//*** $QCounter is just a variable used to keep count of where I am in the DO loop.

$QuizCount = 0;

foreach ($QuizId as $QCounter) {

$QuizCount += 1;

}

$QCounter = 0;

do {

$QCounter++;

$QuizPrev[$QCounter] = $QuizId[$QCounter - 1];

}

while ($QCounter < $QuizCount - 1);

 

//*** If the current Quiz id ($ThisId) matches an id in the $QuizId array, then get the id of the

//*** previous Quiz from the $QuizPrev array, the grade required to unlock the current

//*** Quiz from the $QuizPass array, and the name of the previous Quiz from the

//*** $QuizName array.

$QuizCount = 0;

foreach ($QuizId as $QCounter) {

if ($QCounter == $ThisId && $QuizCount > 0) {

$PrevId = $QuizPrev[$QuizCount];

$UnlockGrade = $QuizPass[$QuizCount - 1];

$CantName = $QuizName[$QuizCount - 1];

}

$QuizCount += 1;

}

 

//*** If there is a previous Quiz requirement, then get all the information about that

//*** previous quiz, including the highest grade achieved.

If ($PrevId > 0) {

if ($PrevId) {

if (! $PrevCm = get_coursemodule_from_id('quiz', $PrevId)) {

error("QUIZ LOCK HACK error with Previous Quiz: There is no coursemodule with id $PrevId");

}

if (! $PrevCourse = get_record("course", "id", $PrevCm->course)) {

error("QUIZ LOCK HACK error with Previous Quiz: Course is misconfigured - Course id $PrevCm->course");

}

if (! $PrevQuiz = get_record("quiz", "id", $PrevCm->instance)) {

error("QUIZ LOCK HACK error with Previous Quiz: The quiz with id $PrevCm->instance corresponding to this coursemodule $PrevId is missing");

}

}

if ($UnlockGrade > 0) {

If ($PrevQuiz->sumgrades > 0) {

$BestGrade = (quiz_get_best_grade($PrevQuiz,$USER->id)/$PrevQuiz->sumgrades)*100;

}

}

}

//*** If the highest grade achieved is greater than or equal to the unlock grade requirement,

//*** then unlock the Quiz. If there is no previous Quiz requirement, then since the

//*** defaults for $BestGrade and for $UnlockGrade are equal to zero (and therefore

//*** equal to each other), it will also unlock the current Quiz.

if ($BestGrade >= $UnlockGrade) {

$QuizLock = 0;

}

//******************************************************************************************

//*** end Block 2 of 4 - QUIZ LOCK HACK

//******************************************************************************************

 

 

 

 

 

 

 

 

 

 

//******************************************************************************************

//*** QUIZ LOCK HACK - Block 3 of 4 - by Jeff Sherk Mar 1, 2007

//******************************************************************************************

//*** Insert this block, immediately after the line that reads:

//*** $linktext = get_string('continueattemptquiz', 'quiz');

//******************************************************************************************

//*** What this code does:

//*** If the student had previously made an attempt at this Quiz, and saved it without

//*** submitting, then there is a link that appears in the "show attempts" table, that

//*** says "CONTINUE THE LAST ATTEMPT".

//*** If the Quiz is locked, it removes this link by setting $linktext = ''

//******************************************************************************************

if ($QuizLock == 1) {

$linktext = '';

$CantAttempt = 'Not Blank!!!';

}

//******************************************************************************************

//*** end Block 3 0f 4 - QUIZ LOCK HACK

//******************************************************************************************

 

 

 

 

 

 

 

 

 

 

//******************************************************************************************

//*** QUIZ LOCK HACK - Block 4 of 4 - by Jeff Sherk Mar 1, 2007

//******************************************************************************************

//*** Insert this block, immediately AFTER the line that reads:

//*** echo "<div align=\"center\">";

//***

//*** and immediately BEFORE the line that reads:

//*** if ($quiz->delay1 or $quiz->delay2) {

//***

//*** IMPORTANT: IMPORTANT: IMPORTANT: IMPORTANT: IMPORTANT: IMPORTANT: IMPORTANT:

//*** Make sure you delete the line that reads:

//*** if ($quiz->delay1 or $quiz->delay2) {

//*** which is outside the bottom of this inserted block.

//*** Do NOT delete the similar looking line that is within this block, which reads:

//*** } else if ($quiz->delay1 or $quiz->delay2) {

//********************************************************************************************

//*** What this code does:

//*** If the Quiz is locked, it prevents the display of any START QUIZ buttons,

//*** and puts up a message advising the student that they can't attempt, or re-attempt,

//*** or continue an attempt until they have reached a certain Grade on a previous Quiz.

//********************************************************************************************

if ($QuizLock == 1) {

if ($CantAttempt <> '') {

$CantAttempt = 'You cannot continue your last attempt on this Quiz, until you have achieved a grade of at least <font color="blue">'. $UnlockGrade. '% <font color="red">on the previous Quiz (<font color="blue">'. $CantName. '<font color="red">)!!!';

}

if ($numattempts > 0 && $CantAttempt == '') {

$CantAttempt = 'You cannot re-attempt this Quiz, until you have achieved a grade of at least <font color="blue">'. $UnlockGrade.'% <font color="red">on the previous Quiz (<font color="blue">'. $CantName. '<font color="red">)!!!';

}

if ($CantAttempt == '') {

$CantAttempt = 'You cannot attempt this Quiz, until you have achieved a grade of at least <font color="blue">'. $UnlockGrade.'% <font color="red">on the previous Quiz (<font color="blue">'. $CantName. '<font color="red">)!!!';

}

print_simple_box('<font color="red"><h4><b>'. $CantAttempt. '</b></h4><font color="black">', "center");

} else if ($quiz->delay1 or $quiz->delay2) {

//********************************************************************************************

//*** end Block 4 0f 4 - QUIZ LOCK HACK

//********************************************************************************************

Average of ratings: -