Here you specify how the total Grade will be divided: the percentage for the Automatic grade is on the left, and the Manual grade is on the right.
-
-
The automatic grade is the grade 'given' by the system for simply making a question. So, for example if you require students to make 10 questions, and you assign 100% for Automatic grading, a student that makes 7 questions will get 70% for the activity. On the other hand, if you asign 50% for Automatic grading, a student that creates 7 questions will get 35% for the activity (7/10 x 50% = 35%).
-
-
Note that the automatic grade is no guarantee of quality. The Automatic grade is best used in the following situations:
-
-
1) ...when you want to reward students for simply making the correct number of corrections. In this case, it is probably best to keep the weight for the automatic grade low.
-
-
2) ...when you are confident that the quality of the questioins your students produce is not in doubt. For example, your students if your students are both experienced at creating questions with Moodle, and experienced at writing questions in general then a high weight or even 100% for the autimatic grade may be appropriate.
-
-
-
The Manual grade is the grade that you give for each question. So, if you asign 50% for Automatic grading, the other half of the grade will be your manually assigned grade. So, if a student creates 7 questions, they will get 35% Automatic grade, and if you grade each question as perfect they will get a total of 70% (35% automatic + 35% manual). On the other hand, if the questions have problems and you only give 60% for each question of the 7 questions, the student's total grade will be 56%. Note, it is possible to give different grades to each question. The calculation is as follows:
-Another example:
-Here, students are required to make 5 questions. The Ratio of Automatic
-/ Manual Grading is 20%/80%.
-A student creates all 5 questions, so gets the full 20% for the automatic grade, but the quality of each question is not perfect. As a result the student's grades could look somehting like this:
-
-
-
-
-
-
Automatic grade (20%)
-
Manual grade (80%)
-
-
-
Question 1
-
100%
-
20%
-
-
-
Question 2
-
100%
-
60%
-
-
-
Question 3
-
100%
-
40%
-
-
-
Question 4
-
100%
-
80%
-
-
-
Question 5
-
100%
-
90%
-
-
-
sub-total
-
100%
-
58%
-
-
-
Total
-for activity
-
20%
-
46.4%
-
-
-
= 66.4%
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lang/en/help/qcreate/grade.html b/lang/en/help/qcreate/grade.html
deleted file mode 100644
index c407ff7..0000000
--- a/lang/en/help/qcreate/grade.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
Grade
-
-
This is the total grade for the activity that is reported to the gradebook. It is possible to set 'No grade' so that the the activity is not graded.
\ No newline at end of file
diff --git a/lang/en/help/qcreate/gradedquestiontypes.html b/lang/en/help/qcreate/gradedquestiontypes.html
deleted file mode 100644
index 8f2dea2..0000000
--- a/lang/en/help/qcreate/gradedquestiontypes.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
Graded Question Types
-
-
Here you specify the type of questions that need to be made. If you select "Allow all question types", then students can make any type of question up to the total specified in "Total Questions Graded".
-
-
If your students already know how to make questions, and they know the differences between the question types, it is safe to select "Allow all question types". However, if they are new to question creation, it is probably best to specify here the type of questions you want students to create.
-
-
Example 1:
-
If you select '4' in "Total Questions Graded", and check "Allow all question types" in "Graded Question Types", students will be able to create any type of questions; they could be 4 of the same type or a combination of question types. Note, the "Will Grade Minimum Number of Questions of Type" menus do not need to be set at all.
-
-
Example 2:
-
If you select '4' in "Total Questions Graded", and in "Graded Question Types" you check "Multiple Choice", students will have to create 4 Multiple choice questions. Again, the "Will Grade Minimum Number of Questions of Type" menus do not need to be set at all.
-
-
Example 3:
-
If you select '4' in "Total Questions Graded", and check "Matching" and "Multiple Choice" in "Graded Question Types", students will have to make a total of 4 questions; they could be all Matching, all Multiple Choice, or a combination of the two.
-
-
Note, if you want to to specify exactly what type of questions and how many of each type students should create, you need to indicate these parameters in the "Will Grade Minimum Number of Questions of Type" menus.
-
\ No newline at end of file
diff --git a/lang/en/help/qcreate/index.html b/lang/en/help/qcreate/index.html
deleted file mode 100644
index e07e4ca..0000000
--- a/lang/en/help/qcreate/index.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
In this menu you can specify how many questions of a specific type students should create.
-
-
Example:
-
You want students to create a total of 10 questions, 2 matching, 3 multiple choice, 2 Short Answer, and then any combination of these three types.
-
-
To do this:
-
1) in the "Total Questions Graded" menu select 10
-
2) in "Graded Question Types" check "Matching", "Multiple Choice" and "Short Answer"
-
3) In the first "Will Grade Minimum Number of Questions of Type" area:
-
...in the Question Type menu select "Matching"
-
...and in Minimum Questions menu select 2
-
4) In the second "Will Grade Minimum Number of Questions of Type" area:
-
...in the Question Type menu select "Multiple Choice"
-
...and in Minimum Questions menu select 3
-
5) In the third "Will Grade Minimum Number of Questions of Type" area:
-
...in the Question Type menu select "Short Answer"
-
...and in Minimum Questions menu select 2
-
\ No newline at end of file
diff --git a/lang/en/help/qcreate/mods.html b/lang/en/help/qcreate/mods.html
deleted file mode 100644
index 0d9852b..0000000
--- a/lang/en/help/qcreate/mods.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
Question Creation activity module
-
-
The Question Creation activity module makes it possible for teachers to let or require students to create questions using the Moodle question creation engine. These creations can subsequently be edited by a teacher and added to Moodle quizzes.
-
-
As a non-graded activity, teachers can make it possible for students to make any number of questions. These questions can be imported into quizzes by the teacher. In this way, teachers can encourage students' autonomous learning. Students will create questions about a certain topic or sub-set of knowledge, knowing that their questions will appear in a (graded) quiz.
-
-
As a graded activity, teachers can require students to make specific question types and a specific number of these types. Furthermore, these questions can be graded both automatically or manually or a combination of the two. Automatic grading takes no account of the quality of questions, it simply rewards students for creating questions. Manual grading on the other hand is used to evaluate the content and quality of questions.
In this menu you can specify what type of question students should create.
-
-
Example:
-
You want students to create a total of 5 questions, 2 matching and 3 multiple choice.
-
-
To do this:
-
1) in the "Total Questions Graded" menu select 5
-
2) in "Graded Question Types" check "Matching" and "Multiple Choice"
-
3) In the first "Will Grade Minimum Number of Questions of Type" area:
-
...in the Question Type menu select "Matching"
-
...and in Minimum Questions menu select 2
-
4) In the second "Will Grade Minimum Number of Questions of Type" area:
-
...in the Question Type menu select "Multiple Choice"
-
...and in Minimum Questions menu select 3
-
\ No newline at end of file
diff --git a/lang/en/help/qcreate/studentquestionaccess.html b/lang/en/help/qcreate/studentquestionaccess.html
deleted file mode 100644
index 809c6e4..0000000
--- a/lang/en/help/qcreate/studentquestionaccess.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
Student question access
-
-
Use this menu to define what access rights students have over the questions they create. There are four types:
-
-
1) create only: this is the strictest; once a student clicks on the [Save question] button, they will not be able to edit the question again.
-
-
2) preview: ???
-
-
3) preview and view / save as new: students can do just about everyhing, except edit already created creations. This also means that they can't delete questions they have already made.
-
-
4) preview, view / save as new and edit / delete: this is the higest level access that students can have. For an activity in which you want students to go through an ioterative process of question creation, evaluation, and improvemnt, this is proabably the best setting.
This is the total number of questions that students must create.
-
This number must be equal to or greater than the minimum number of questions required. For example, if you want to specify that students create 2 Matching type questions and 2 Multiple Choice type questions, you will have to select 4 or higher in the Total Questions Graded menu. If you select a number higher than 4, then students will be able to create other questions in excess of the two Matching and two Multiple Choice types. The type of the extra questions created will depend on the types allowed in "Graded Question Types".
\ No newline at end of file
diff --git a/lang/en/qcreate.php b/lang/en/qcreate.php
index 8f4e810..0882c34 100644
--- a/lang/en/qcreate.php
+++ b/lang/en/qcreate.php
@@ -1,103 +1,224 @@
.
+
+/**
+ * English language strings for the qcreate module
+ *
+ * @package mod_qcreate
+ * @copyright 2008 Jamie Pratt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
+ */
$string['activityclosed'] = 'Activity is closed.';
$string['activitygrade'] = 'You have been awarded a total grade of {$a->grade} / {$a->outof} for this activity.';
$string['activityname'] = 'Activity name';
$string['activityopen'] = 'Activity is open.';
-$string['addminimumquestionshdr'] = 'Will Grade Minimum Number of Questions of Type (optional)';
-$string['allowall'] = 'Allow all question types';
+$string['addminimumquestionshdr'] = 'Required Number of Questions of Type (optional)';
+$string['addmorerequireds'] = 'Add more required question types';
$string['allandother'] = 'To allow all question types, check \'{$a}\' and don\'t check anything else.';
-$string['allquestions'] = '0 - (All questions)';
+$string['allowall'] = 'Allow all question types';
$string['allowedqtypes'] = 'Graded Question Types';
+$string['allowedqtypes_help'] = 'Here you specify the type of questions that are allowed. If you select \'Allow all question types\', then students can make any type of question up to the total specified in \'Total Questions Graded\'.';
+$string['allquestions'] = '0 - (All questions)';
$string['alreadydone'] = 'You\'ve done {$a} questions of this type.';
$string['alreadydoneextra'] = 'You\'ve done {$a} extra questions of this type.';
$string['alreadydoneextraone'] = 'You\'ve done one extra question of this type.';
$string['alreadydoneone'] = 'You\'ve done one question of this type.';
$string['and'] = '{$a} AND';
+$string['andmorenewquestions'] = 'and {$a} more new question(s).';
+$string['attemptqcreatenow'] = 'Attempt question creation now';
+$string['availability'] = 'Availability';
$string['automaticgrade'] = 'You have been awarded an automatic grade of {$a->grade} / {$a->outof} for these questions, since you have done {$a->done} of {$a->required} required questions.';
$string['betterthangrade'] = 'Questions with manual grade equal or better than';
$string['clickhere'] = 'Click here to create a question of \'{$a}\' type.';
$string['clickhereanother'] = 'Click here to create another question of \'{$a}\' type.';
$string['close'] = 'Close activity';
+$string['closebeforeopen'] = 'Could not update the question creation activity. You have specified a close date before the open date.';
+$string['closeon'] = 'Close on';
$string['comma'] = '{$a},';
$string['comment'] = 'Comment';
+$string['completionquestions'] = 'Student must create:';
+$string['completionquestionsdesc'] = 'Student must create at least {$a} question/questions';
+$string['completionquestions_help'] = 'If enabled, this activity is considered complete when the student has created that number of questions (graded or not).';
+$string['completionquestionsgroup'] = 'Require questions';
$string['confirmdeletequestion'] = 'Are you sure you want to delete this question?';
$string['creating'] = 'Creating Questions';
+$string['createdquestions'] = 'Created questions';
+$string['deletegrades'] = 'Delete questions created and manual grades';
$string['donequestionno'] = 'You\'ve completed {$a->done} of {$a->no} questions of type \'{$a->qtypestring}\'. These are listed below.';
-$string['exportgood'] = 'Export Good';
+$string['eventeditpageviewed'] = 'Question creation edit page viewed';
+$string['eventoverviewviewed'] = 'Question creation overview viewed';
+$string['eventquestiongraded'] = 'Question graded';
+$string['eventquestionregraded'] = 'Question regraded';
+$string['exportgood'] = 'Export good questions';
$string['exportgoodquestions'] = 'Export Questions Which Have Been Graded Above a Selected Grade';
$string['exportnaming'] = 'Prefix Exported Question Names With';
+$string['exportquestions'] = 'Export questions to file';
$string['exportselection'] = 'Export only these questions';
$string['extraqdone'] = 'You\'ve done one extra question.';
$string['extraqsdone'] = 'You\'ve done {$a->extraquestionsdone} extra questions.';
$string['extraqgraded'] = 'One question of any of the types below will be graded';
$string['extraqsgraded'] = '{$a->extrarequired} questions of any of the types below will be graded';
+$string['finalgrade'] = 'Final grade for {$a}';
$string['fullstop'] = '{$a}.';
+$string['grade'] = 'Grade';
+$string['grade_help'] = 'This is the total grade for the activity that is reported to the gradebook. It is possible to set \'No grade\' so that the the activity is not graded.';
$string['gradeallautomatic'] = 'Grades are completely automatic, no manual grading.';
$string['gradeallmanual'] = 'Grading is completely manual, no automatic grading.';
-$string['grademixed'] = 'Grading is {$a->automatic}%% automatic, {$a->manual}%% manual.';
+$string['gradeavailabletext'] = '{$a->username} has graded your created question \'{$a->questionname}\' for \'{$a->qcreate}\'
+
+You can see it on the activity page:
+
+ {$a->url}';
+$string['gradeavailablehtml'] = '{$a->username} has graded your created question
+\'{$a->questionname}\' for \'{$a->qcreate}\'
+You can see it on the activity page.';
+$string['gradeavailablesmall'] = '{$a->username} has graded your created question for {$a->qcreate}';
+$string['gradecomment'] = 'Comment for question \'{$a->qname}\' created by {$a->user}';
$string['graded'] = 'Graded';
+$string['grademixed'] = 'Grading is {$a->automatic}%% automatic, {$a->manual}%% manual.';
$string['gradequestions'] = 'Grade questions';
$string['grading'] = 'Grading';
$string['graderatio'] = 'Ratio of Automatic / Manual Grading';
+$string['graderatiois'] = 'Ratio of Automatic / Manual Grading: {$a}';
+$string['graderatio_help'] = 'Here you specify how the total Grade will be divided: the percentage for the Automatic grade is on the left, and the Manual grade is on the right. The automatic grade is the grade \'given\' by the system for simply making a question.';
$string['graderatiooptions'] = '{$a->automatic} / {$a->manual}';
+$string['gradesdeleted'] = 'Questions and manual grades removed';
+$string['indicator:cognitivedepth'] = 'Question creation cognitive';
+$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Question creation activity.';
+$string['indicator:socialbreadth'] = 'Question creation social';
+$string['indicator:socialbreadth_help'] = 'This indicator is based on the social breadth reached by the student in a Question creation activity.';
$string['intro'] = 'Introduction';
+$string['invalidqcreatezid'] = 'Invalid question creation ID';
$string['manualgrade'] = 'A teacher has awarded you a grade of {$a->grade} / {$a->outof} for the questions you have done.';
$string['marked'] = 'Marked';
+$string['messageprovider:gradernotification'] = 'Created question notification';
+$string['messageprovider:studentnotification'] = 'Graded question notification';
$string['minimumquestions'] = 'Minimum Questions';
+$string['minimumquestions_help'] = 'In this menu you can specify how many questions of a specific type students should create.';
$string['modulename'] = 'Question Creation';
-$string['modulenameplural'] = 'Question Creation';
+$string['modulenameplural'] = 'Question Creations';
+$string['modulename_help'] = 'The question creation activity enables a teacher to ask students to create questions, number of required quesions, avaiblable question types and number of required questions for each question type can be specified.';
+$string['modulename_link'] = 'mod/qcreate/view';
$string['needtoallowqtype'] = 'You need to allow question type \'{$a}\' if you want to require a minimum no of questions of this type need to be created.';
$string['needtoallowatleastoneqtype'] = 'You need to allow at least one question type';
$string['needsgrading'] = 'Needs grading';
$string['needsregrading'] = 'Needs regrading';
+$string['newquestions'] = 'New questions created';
$string['noofquestionstotal'] = 'Total Questions Graded';
+$string['noofquestionstotal_help'] = 'This is the total number of questions that students must create. This number must be equal to or greater than the minimum number of questions required';
+$string['noquestions'] = 'No questions have been created.';
$string['noquestionsabove'] = 'There are no questions with a manual grade set above {$a->betterthan} in category \'{$a->categoryname}\'.';
$string['notgraded'] = 'Not graded yet';
+$string['nothingtosave'] = 'Nothing to save';
+$string['notifications'] = 'Notifications';
$string['nousers'] = 'No users enrolled in this course / in this group.';
$string['open'] = 'Open activity';
+$string['openafterclose'] = 'Could not update the question creation activity. You have specified an open date after the close date.';
+$string['openclosedatesupdated'] = 'Question creation activity open and close dates updated';
+$string['openon'] = 'Open on';
+$string['open_help'] = 'You can specify times when the question creation activity is accessible for people to make questions. Before the opening time, and after the closing time, students will be unable to create questions.';
$string['openmustbemorethanclose'] = 'Time to open activity must be before time to close activity';
$string['overview'] = 'Overview';
$string['pagesize'] = 'Number of questions to show per page';
+$string['pluginadministration'] = 'Question creation Administration';
+$string['pluginname'] = 'Question creation';
+$string['preview'] = 'Preview';
+$string['previewquestion'] = 'Preview question';
+$string['privacy:graderpath'] = 'questionsgraded';
+$string['privacy:gradepath'] = 'grade';
+$string['privacy:metadata:core_question'] = 'The question creation activity stores created questions information in the core_question subsystem';
+$string['privacy:metadata:qcreate_grades'] = 'Question creation local grades';
+$string['privacy:metadata:qcreate_grades:grade'] = 'Question creation local grade';
+$string['privacy:metadata:qcreate_grades:gradecomment'] = 'Question creation teacher comment';
+$string['privacy:metadata:qcreate_grades:qcreateid'] = 'Question creation instance identifier';
+$string['privacy:metadata:qcreate_grades:questionid'] = 'Question graded identifier';
+$string['privacy:metadata:qcreate_grades:teacher'] = 'Grading teacher identifier';
+$string['privacy:metadata:qcreate_grades:timemodified'] = 'Time when the grade or comment was last modified';
+$string['privacy:studentpath'] = 'questionscreated';
$string['qcreate'] = 'qcreate';
+$string['qcreate:addinstance'] = 'Add a question creation instance';
+$string['qcreate:grade'] = 'Grade question';
+$string['qcreate:receivegradernotifications'] = 'Receive grader notifications';
+$string['qcreate:receivestudentnotifications'] = 'Receive student notifications';
+$string['qcreate:submit'] = 'Submit question';
+$string['qcreate:view'] = 'View question creation activity';
+$string['qcreateeventcloses'] = '{$a} closes';
+$string['qcreateeventopens'] = '{$a} opens';
$string['qcreateopens'] = 'Question creation activity opens';
$string['qcreatecloses'] = 'Question creation activity closes';
$string['qsgraded'] = '{$a} question(s) of any of these types will be graded :';
$string['qtype'] = 'Question Type';
-$string['requiredquestions'] = 'Required Questions to Create';
+$string['qtype_help'] = 'In this menu you can specify what type of question students should create.';
+$string['questiongrade'] = 'Grade for question \'{$a->qname}\' created by {$a->user}';
+$string['questions'] = 'question(s) to complete this activity';
+$string['questionscreated'] = '{$a} question(s) created';
+$string['questiontogradetext'] = '{$a->username} has created a new question \'{$a->questionname}\'
+for \'{$a->qcreate}\' at {$a->timeupdated}
+
+It is available here:
+
+ {$a->url}';
+$string['questiontogradehtml'] = '{$a->username} has created a new question \'{$a->questionname}\'
+for \'{$a->qcreate}\' at {$a->timeupdated}
+It is available on the web site.';
+$string['questiontogradesmall'] = '{$a->username} has created a new question for {$a->qcreate}.';
+$string['requiredquestions'] = 'Required Questions to Create:';
$string['requiredanyplural'] = '{$a->no} questions of any question type are required';
$string['requiredanysingular'] = 'A question of any question type is required';
$string['requiredplural'] = '{$a->no} questions of \'{$a->qtypestring}\' question type are required';
$string['requiredsingular'] = 'A question of \'{$a->qtypestring}\' question type is required';
$string['saveallfeedback'] = 'Save all my feedback';
$string['saveallfeedbackandgrades'] = 'Save all grades & feedback';
+$string['search:activity'] = 'Question creation activities';
$string['selectone'] = 'Select One...';
+$string['sendstudentnotifications'] = 'Notify students';
+$string['sendstudentnotifications_help'] = 'If enabled, students receive a message when one of their questions is graded.';
+$string['sendgradernotifications'] = 'Notify graders';
+$string['sendgradernotifications_help'] = 'If enabled, graders (usually teachers) receive a message whenever a student create a new question. Message methods are configurable.';
$string['show'] = 'Show ';
$string['showgraded'] = 'questions that don\'t need grading';
$string['showneedsregrade'] = 'questions that need regrading';
$string['showungraded'] = 'questions that need grading';
$string['specifictext'] = 'Specific text';
$string['studentqaccess'] = 'To own questions';
+$string['studentqaccess_help'] = 'Use this menu to define what access rights students have over the questions they create.';
$string['studentaccessheader'] = 'Student question access';
$string['studentaccessaddonly'] = 'create only';
$string['studentaccesspreview'] = 'preview';
$string['studentaccesssaveasnew'] = 'preview and view / save as new';
$string['studentaccessedit'] = 'preview, view / save as new and edit / delete';
+$string['studentshavedone'] = 'Students have created {$a} question(s).';
+$string['synchronizeqaccesstask'] = 'Synchronize students questions access capabilities';
$string['timecreated'] = 'Time question created';
$string['timenolimit'] = 'No time limits set.';
$string['timeopen'] = 'Activity opens on {$a->timeopen}';
-$string['timeopened'] = 'Activity opened on $a.';
+$string['timeopened'] = 'Activity opened on {$a}.';
$string['timeclose'] = 'Activity closes on {$a->timeclose}';
-$string['timeclosed'] = 'Activity closed on $a.';
+$string['timeclosed'] = 'Activity closed on {$a}.';
$string['timeopenclose'] = 'Activity is open from {$a->timeopen} to {$a->timeclose}';
-$string['timewillopen'] = 'Activity will open on $a.';
-$string['timewillclose'] = 'Activity will close on $a.';
+$string['timewillopen'] = 'Activity will open on {$a}.';
+$string['timewillclose'] = 'Activity will close on {$a}.';
$string['timing'] = 'Activity timing';
-$string['todoquestionno'] = 'You\'ve still to do $a->stillrequiredno question(s) of type \'{$a->qtypestring}\'.';
+$string['todoquestionno'] = 'You\'ve still to do {$a->stillrequiredno} question(s) of type \'{$a->qtypestring}\'.';
$string['totalgrade'] = 'Total grade';
+$string['totalgradeis'] = 'Total grade: {$a}';
$string['totalrequiredislessthansumoftotalsforeachqtype'] = 'Total required is less than the sum of the totals graded for each question type. It must be equal or more!';
+$string['youhavedone'] = 'You have created {$a} question(s).';
+$string['updategradestask'] = 'Update question creation activity grades';
$string['username'] = 'User name of creator of question';
-$string['youvesetmorethanonemin'] = 'You\'ve set more than one minimum number of questions for question type \'$a\'!';
-?>
+$string['viewgrading'] = 'Grade questions';
+$string['youvesetmorethanonemin'] = 'You\'ve set more than one minimum number of questions for question type \'{$a}\'!';
diff --git a/lang/es/help/qcreate/automaticmanualgrading.html b/lang/es/help/qcreate/automaticmanualgrading.html
deleted file mode 100644
index d378538..0000000
--- a/lang/es/help/qcreate/automaticmanualgrading.html
+++ /dev/null
@@ -1,91 +0,0 @@
-
Ratio calidicación Automática / Manual
-
-
Aquàs edebe especificar cómo se calculará la puntuación total: el porcentaje de puntuación Automática es el primero
-(izquierda), el de la calificación Manual es el segundo (derecha).
-
-
La Puntuación Automática es la nota otorgada por el sistema por simplemente introducir una pregunta.
-Depende del número de preguntas realizadas sobre el total requerido. AsÃ, por ejemplo, si requiere que se generen
-10 preguntas y especifica un 100% de puntuación automática, un estudiante que crea 7 preguntas recibirá
-el 70% de la nota máxima. Por otra parte, si especifica un 50% de puntuación Automática, un estudiante realize las
-7 preguntas obtendrá automáticamente el 35% de la nota máxima (7/10 x 50% = 35%).
-
-
Obviamente, la nota automática no contieen ninguan garantÃa de calidad, sólo el número de preguntas realizadas.
-La puntuación automática es conveniente en algunas situaciones:
2) ...Cuando existe confianza en la calidad media de los textos de los estudiantes..
-
-
En otros casos es probablemente preferible mantener bajo el porcentaje de puntuación Automática.
-
-
La calificación Manual depende de la evaluación que usted, el profesor, realice al revisar explÃcitamente
-cada pregunta introducida, lo que supone una mucho mayor dedicación. Si especifica un 50% de ratio Automática/Manual,
-la mitad de la nota final dependerá de su calificación expresa. Obviamente se puede puntuar diferentemente cada pregunta,
-la calificación final será calculada a partir de la media de las calificaiones manuales, multiplicada por su porcentaje de ratio.
-AsÃ, siguiendo el ejemplo de 10 preguntas requeridas, con una ratio Automática/Manual del 50% y un estudiante que realiza
-7 preguntas, su calificación final será calculada de esta manera:
-Otro ejemplo:
-Aquà lso estudaintes deben crear al menos 5 preguntas. La ratio Automática/Manual es 20%/80%.
-Un estudiante introduce las 5 preguntas, por lo tanto recibe el 20% de la nota final automáticamente. Pero
-la caliad de cada pregunta introducida es dispar. Como resultado la calificación del estudiante podrÃa
-aparecer como algo parecido a esto::
-
-
-
-
-
-
Calificación Automática(20%)
-
Calificación Manual(80%)
-
-
-
Pregunta 1
-
100%
-
20%
-
-
-
Pregunta 2
-
100%
-
60%
-
-
-
Pregunta 3
-
100%
-
40%
-
-
-
Pregunta 4
-
100%
-
80%
-
-
-
Pregunta 5
-
100%
-
90%
-
-
-
sub-total
-
100%
-
58%
-
-
-
Total
-for activity
-
20%
-
46.4%
-
-
-
= 66.4%
-
-
-
-
-
\ No newline at end of file
diff --git a/lang/es/help/qcreate/grade.html b/lang/es/help/qcreate/grade.html
deleted file mode 100644
index 28f0e88..0000000
--- a/lang/es/help/qcreate/grade.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
Calificación
-
-
Esta es la Calificación total que se transladará al libro de notas. Es posible especificar "Sin calificación",
-de forma que la actividad no será evaluable.
\ No newline at end of file
diff --git a/lang/es/help/qcreate/gradedquestiontypes.html b/lang/es/help/qcreate/gradedquestiontypes.html
deleted file mode 100644
index c5da62d..0000000
--- a/lang/es/help/qcreate/gradedquestiontypes.html
+++ /dev/null
@@ -1,28 +0,0 @@
-
Tipos de preguntas requeridos
-
-
Aquà puede especificar los tipos (formatos) de preguntas que deben ser introducidas. Si selecciona "Permitir todos los tipos"
-entonces los estudiantes podrán realizar cualquier tipo hasta el número de preguntas total especificado.
Especifica '4' como "Total de preguntas requeridas" y en "Tipos de preguntas requeridos" marca "Opción múltiple".
-Los estudiantes tendrán que introducir preguntas forzosamente del tipo "opción múltiple", no tendrán posibilidad de
-escoger otro tipo. Los menús de más abajo de "Nº mÃnimo de preguntas a calificar del Tipo" no necesitan ser utilizados.
-
-
Ejemplo 2:
-
Especifica '4' como "Total de preguntas requeridas" y en "Tipos de preguntas requeridos" marca "Opción múltiple"
-y "Emparejamiento". Los estudiantes podrán realizar todas de tipo "Opción múltiple" o todas de tipo "Emparejamiento",
-o una mezcla unas de un tipo y otras del otro tipo. Si desea especificar exactamente cuántas preguntas de cada tipo
-deben ser introducidas debe utilizar los menús "Nº mÃnimo de preguntas a calificar del Tipo" de más abajo.
-Puede añadir más si lo necesita.
-
-
Ejemplo 3:
-
Especifica '4' como "Total de preguntas requeridas" y marca "Permitir todos los tipos de preguntas" en
-"Tipos de preguntas requeridas", los estudiantes podrán crear preguntas de cualquier tipo. Pueden ser todas del mismo
-tipo o cualquier combinación de tipos. Tenga en cuenta que los menús "Nº mÃnimo de preguntas a calificar del Tipo"
-pueden usarse para especificar una combinación mÃnima de tipos de preguntas. O pueden deshabilitarse para no exigir
-ningún tipo en particular.
En eset menú puede especificar cuantas preguntas de un tipo (formato) concreto deberÃa introducir cada estudiante.
-
-
Ejemplo:
-
Usted desea que cada estudiante introduzcan un total de 10 preguntas, 3 de "Opción múltiple", 2 de "Respuesta corta",
-2 de ""Emparejamiento" y además otras 3 de cualquier otra combinación de esso tipos.
-
-
Configurelo de esta forma:
-
1) en el menú "Total de preguntas requeridas" seleccione 10
-
2) en "Tipos de preguntas requeridos" marque las tres casillas "Opción múltiple", "Respuesta corta" y "Emparejamiento"
-
3) En el primer bloque "Nº mÃnimo de preguntas a calificar del Tipo" :
-
...en el menú Tipo de Pregunta seleccione "Opción múltiple"
-
...y en Preguntas mÃnimas seleccione 3
-
4) En el segundo bloque "Nº mÃnimo de preguntas a calificar del Tipo":
-
...en el menú Tipo de Pregunta seleccione "Respuesta corta"
-
...y en Preguntas mÃnimas seleccione 2
-
5) En el tercer bloque "Nº mÃnimo de preguntas a calificar del Tipo" :
-
...en el menú Tipo de Pregunta seleccione "Emparejamiento"
-
...y en Preguntas mÃnimas seleccione 2
-
\ No newline at end of file
diff --git a/lang/es/help/qcreate/mods.html b/lang/es/help/qcreate/mods.html
deleted file mode 100644
index 17b04b7..0000000
--- a/lang/es/help/qcreate/mods.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
Módulo de actividad Crear Preguntas
-
-
El módulo de actividad Crear Preguntas hace posible a los profesores el permitir alos estudiantes que generen
-preguntas de examen usando el interfaz de creación y el motor de almacenamiento de preguntas de Moodle. Las preguntas
-generadas pueden ser evaluadas por el profesor con lo que la actividad se convierte en otra forma de valorar las habilidades
-de los estudiantes.
-
-
Además, si asà se juzga oportuno, las preguntas deseadas pueden transladarse a otras categorÃas y usarse
-en los Cuestionarios de Moodle junto con las generadas por los profesores. Esta adición NO es automática, sino
-que debe ser realizada manualmente por el profesor.
-
-
Usándola como actividad calificable los profesors pueden establecer un Tema y especificar un número
-mÃnimo de preguntas de formatos concretos a ser generadas por los estudiantes. Esta preguntas son evaluadas
-en una combinación de puntuación automática y revisión manual por el profesor considerando asà bien la adquisición
-de conocimientos sobre el tema de las preguntas mostrado por los estudiantes, bien su habilidad en la tarea
-concreta de generar instrumentos para evaluar a otros..
-
-
Usándola como actividad no evaluable los profesores pueden promocionar el aprendizaje autónomo.
-Los estudiantes son "recompensados" por revisar un tema o campo de conocimientos lo suficiente como
-para generar preguntas sobre ese tema con la ventaja de que sus propias preguntas aparezcan en los Cuestionarios usados.
1) Sólo crear:
- Este es el modo más limitado. Una vez que el estudiante termina de editar y guarda el texto
-de una pregunta no podrá verla ni editarla más, queda fuera de su alcance.
-
-
2) Previsualizar:
- Puede ver la pregunta introducida tal y como se mostrarÃa en pantalla en un Cuestionario
-
-
3) Previsualizar / Guardar como nueva:
- Además de ver las preguntas puede "copiar" una para usarla como base para generar una nueva
- pregunta. Sin embargo, el estudiante no puede editar o borrar las preguntas ya generadas y guardadas.
-
-
4) Previsualizar / Guardar como nueva / Editar / Borrar:
- Este es el nivel de acceso más alto que puede otorgar a un estudiante. El estudiante puede editar y cambiar
-las preguntas generadas anteriormente, asà como borrar aquellas que no considere satisfactorias.
-Si usted desea una actividad en la que los estudiantes puedan desarrollar intaractivamente su habilidad
-para crear, valorar y mejorar las preguntas generadas este es el nivel de acceso adecuado.
Abrir y Cerrar la actividad de Creación de Preguntas
-
-
Puede especificar el dÃa y la hora en la que los estudiantes pueden empezar a introducir texto para generar preguntas.
-Igualmente, el momento en el que la actividad terminará
Este es el número totas de preguntas (de cualquier tipo) que desea que cada estudiante genere usando esta actividad.
-Eset numero debe ser igual o mayor que la suma de los números mÃnimos de preguntas de cada tipo especificado
-(si se especifica alguno). El tipo (formato) de preguntas que será posible generar depende las otras opciones.
-
-
El total de preguntas requeridas se emplea para calcular la fracción de calificación automática (si se usa esta opción)
-pero no limita el número de preguntas que los estudiantes pueden introducir y almacenar. Los estudiantes siempre pueden
-generar preguntas "extra" por encima de este número total de preguntas, sin lÃmite alguno.
\ No newline at end of file
diff --git a/lang/es/qcreate.php b/lang/es/qcreate.php
deleted file mode 100644
index 3f3bf0b..0000000
--- a/lang/es/qcreate.php
+++ /dev/null
@@ -1,85 +0,0 @@
-grade} / {$a->outof} por esta actividad.';
-$string['addminimumquestionshdr'] = 'Nº mÃnimo de preguntas a calificar del Tipo :';
-$string['allowall'] = 'Permitir todos los tipos de preguntas';
-$string['allandother'] = 'Para permitir todos los tipos de preguntas, marque \'{$a}\' y nada más.';
-$string['allquestions'] = '0 - (Todas las preguntas)';
-$string['allowedqtypes'] = 'Tipos de preguntas requeridos';
-$string['alreadydone'] = 'Ha introducido {$a} preguntas de este tipo.';
-$string['alreadydoneextra'] = 'Ha introducido {$a} preguntas extra de este tipo.';
-$string['alreadydoneextraone'] = 'Ha introducido una pregunta extra de este tipo.';
-$string['alreadydoneone'] = 'Ha introducido una pregunta de este tipo.';
-$string['and'] = '{$a} y';
-$string['automaticgrade'] = 'Ha recibido una calificación automática de {$a->grade} / {$a->outof} por estas preguntas, ya que ha introducido {$a->done} de {$a->required} preguntas requeridas.';
-$string['betterthangrade'] = 'Preguntas con calificación igual o mayor que';
-$string['clickhere'] = 'Pinche aquà para crear una pregunta del tipo \'{$a}\'.';
-$string['clickhereanother'] = 'Pinche aquà para crear otra pregunta del tipo \'{$a}\'.';
-$string['close'] = 'Cerrar la actividad';
-$string['comma'] = '{$a},';
-$string['comment'] = 'Comentario';
-$string['creating'] = 'Creando Preguntas';
-$string['donequestionno'] = 'Ha completado {$a->done} de {$a->no} preguntas del tipo \'{$a->qtypestring}\'. Se listan debajo.';
-$string['exportgood'] = 'Exportar válidas';
-$string['exportgoodquestions'] = 'Exportar las preguntas con calificación mayor que un valor dado';
-$string['exportselection'] = 'Exportar sólo estas preguntas';
-$string['extraqdone'] = 'Ha introducido una pregunta extra.';
-$string['extraqsdone'] = 'Ha introducido {$a->extraquestionsdone} preguntas extra.';
-$string['extraqgraded'] = 'Una pregunta de estos tipos será evaluada';
-$string['extraqsgraded'] = '{$a->extrarequired} preguntas de estos tipos será evaluada';
-$string['fullstop'] = '{$a}.';
-$string['gradeallautomatic'] = 'Calificaciones completamente automáticas. No hay calificación manual.';
-$string['gradeallmanual'] = 'Calificaciones completamente manuales. No hay calificación automática.';
-$string['grademixed'] = 'Calificaciones {$a->automatic}%% automáticas, {$a->manual}%% manual.';
-$string['graded'] = 'Calificado';
-$string['gradequestions'] = 'Califique las preguntas';
-$string['grading'] = 'Calificar';
-$string['graderatio'] = 'Ratio de calificación Automática / Manual';
-$string['graderatiooptions'] = '{$a->automatic} / {$a->manual}';
-$string['intro'] = 'Introducción';
-$string['manualgrade'] = 'Un profesor ha otrogado una calificación de of {$a->grade} / {$a->outof} por las preguntas introducidas.';
-$string['marked'] = 'Evaluado';
-$string['minimumquestions'] = 'Preguntas mÃnimas';
-$string['modulename'] = 'Crear preguntas';
-$string['modulenameplural'] = 'Actividades Crear preguntas';
-$string['needtoallowqtype'] = 'Debe permitir el tipo de pregunta \'{$a}\' si desea requerir la creación de un número mÃnimo de preguntas de este tipo.';
-$string['needtoallowatleastoneqtype'] = 'Necesita permitir al menos un tipo de pregunta';
-$string['needsgrading'] = 'Necesita calificación';
-$string['needsregrading'] = 'necesita re-calificación';
-$string['noofquestionstotal'] = 'Total de preguntas requeridas';
-$string['notgraded'] = 'Aún no calificada';
-$string['nousers'] = 'No hay usuarios matriculados en este curso o grupo.';
-$string['open'] = 'Abrir la actividad';
-$string['openmustbemorethanclose'] = 'El momento de abrir la actividad debe ser anterior en el tiempo al de cierre';
-$string['overview'] = 'Presentación';
-$string['pagesize'] = 'Número de preguntas a mostrar por página';
-$string['qcreate'] = 'qcreate';
-$string['qsgraded'] = '{$a} pregunta(s) de cualquiera de estos tipos será evaluada:';
-$string['qtype'] = 'Tipo de Pregunta';
-$string['requiredquestions'] = 'Preguntas a crear requeridas';
-$string['requiredanyplural'] = 'Se requieren {$a->no} preguntas de cualquier tipo';
-$string['requiredanysingular'] = 'Se requiere una pregunta de cualquier tipo';
-$string['requiredplural'] = 'Se requieren {$a->no} preguntas del tipo \'{$a->qtypestring}\' ';
-$string['requiredsingular'] = 'Se requiere una pregunta del tipo \'{$a->qtypestring}\' ';
-$string['saveallfeedback'] = 'Guardar comentarios';
-$string['saveallfeedbackandgrades'] = 'Guardar calificaciones y comentarios';
-$string['selectone'] = 'Escoja uno ...';
-$string['show'] = 'Mostrar ';
-$string['showgraded'] = 'preguntas que no requieren evaluación';
-$string['showneedsregrade'] = 'preguntas que requieren re-evaluación';
-$string['showungraded'] = 'preguntas que requieren evaluación';
-$string['studentqaccess'] = 'Con las preguntas propias';
-$string['studentaccessheader'] = 'Accesoa las preguntas por estudiantes';
-$string['studentaccessaddonly'] = 'Sólo crear';
-$string['studentaccesspreview'] = 'Previsualizar';
-$string['studentaccesssaveasnew'] = 'Previsualizar / Guardar como nueva';
-$string['studentaccessedit'] = 'Previsualizar / Guardar como nueva / Editar / Borrar';
-$string['timenolimit'] = 'No hay lÃmite de tiempo definido.';
-$string['timeopen'] = 'La actividad comienza en {$a->timeopen}';
-$string['timeclose'] = 'La actividad termina en {$a->timeclose}';
-$string['timeopenclose'] = 'La actividad está abierta desde el {$a->timeopen} al {$a->timeclose}';
-$string['timing'] = 'Temporalización de la actividad';
-$string['todoquestionno'] = 'TodavÃa debe introducir {$a->stillrequiredno} preguntas(s) del tipo \'{$a->qtypestring}\'.';
-$string['totalgrade'] = 'Calificación total';
-$string['totalrequiredislessthansumoftotalsforeachqtype'] = 'El total requerido es menor que la suma de los mÃnimos especificados para cada tipo de pregunta requerid. ¡Debe ser igual o mayor!';
-$string['youvesetmorethanonemin'] = 'Ha especificado más de un mÃmimo de cuestiones de tipo \'{$a}\'!';
-?>
diff --git a/lib.php b/lib.php
index 11cafd8..f596501 100644
--- a/lib.php
+++ b/lib.php
@@ -1,4 +1,27 @@
-.
+
+/**
+ * @package mod_qcreate
+ * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
/**
* Library of functions and constants for module qcreate
* This file should have two well differenced parts:
@@ -13,336 +36,750 @@
* help to save some memory when Moodle is performing
* actions across all modules.
*/
+
/**
* The options used when popping up a question preview window in Javascript.
*/
define('QCREATE_EDIT_POPUP_OPTIONS', 'scrollbars=yes,resizable=yes,width=800,height=540');
+/** Set QCREATE_PER_PAGE to 0 if you wish to display all questions on the edit page */
+define('QCREATE_PER_PAGE', 10);
+
+define('QCREATE_MAX_PER_PAGE', 100);
+
/**
- * If start and end date for the quiz are more than this many seconds apart
- * they will be represented by two separate events in the calendar
+ * Event types.
*/
-define("QCREATE_MAX_EVENT_LENGTH", 5*24*60*60); // 5 days maximum
-
-require_once(dirname(__FILE__).'/deprecatedlib.php');
+define('QCREATE_EVENT_TYPE_OPEN', 'open');
+define('QCREATE_EVENT_TYPE_CLOSE', 'close');
/**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will create a new instance and return the id number
- * of the new instance.
+ * Returns the information on whether the module supports a feature
*
- * @param object $instance An object from the form in mod.html
- * @return int The id of the newly inserted qcreate record
- **/
-function qcreate_add_instance($qcreate) {
- global $DB;
- $qcreate->timecreated = time();
-
- $qcreate->allowed = join(array_keys($qcreate->allowed), ',');
- if ($qcreate->id = $DB->insert_record("qcreate", $qcreate)){
- $qtypemins = array_filter($qcreate->qtype);
- if (count($qtypemins)){
- foreach ($qtypemins as $key => $qtypemin){
- $toinsert = new stdClass();
- $toinsert->no = $qcreate->minimumquestions[$key];
- $toinsert->qtype = $qtypemin;
- $toinsert->qcreateid = $qcreate->id;
- $toinsert->timemodified = time();
- $DB->insert_record('qcreate_required', $toinsert);
- }
- }
- qcreate_after_add_or_update($qcreate);
+ * @see plugin_supports() in lib/moodlelib.php
+ * @param string $feature FEATURE_xx constant for requested feature
+ * @return mixed true if the feature is supported, null if unknown
+ */
+function qcreate_supports($feature) {
+ switch($feature) {
+ case FEATURE_GROUPS:
+ return true;
+ case FEATURE_GROUPINGS:
+ return true;
+ case FEATURE_MOD_INTRO:
+ return true;
+ case FEATURE_COMPLETION_TRACKS_VIEWS:
+ return true;
+ case FEATURE_COMPLETION_HAS_RULES:
+ return true;
+ case FEATURE_GRADE_HAS_GRADE:
+ return true;
+ case FEATURE_BACKUP_MOODLE2:
+ return true;
+ case FEATURE_GRADE_OUTCOMES:
+ return true;
+ case FEATURE_SHOW_DESCRIPTION:
+ return true;
+ case FEATURE_USES_QUESTIONS:
+ return true;
+
+ default:
+ return null;
}
- return $qcreate->id;
}
+
/**
- * Called from cron and update_instance. Not called from add_instance as the contexts are not set up yet.
+ * Obtains the automatic completion state for this qcreate based on any conditions
+ * in qcreate settings.
+ *
+ * @global object
+ * @global object
+ * @param object $course Course
+ * @param object $cm Course-module
+ * @param int $userid User ID
+ * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
+ * @return bool True if completed, false if not. (If no conditions, then return
+ * value depends on comparison type)
*/
-function qcreate_student_q_access_sync($qcreate, $cmcontext=null, $course=null, $forcesync= false){
- global $DB;
-
- //check if a check is needed
- $timenow = time();
- $activityopen = ($qcreate->timeopen == 0 ||($qcreate->timeopen < $timenow)) &&
- ($qcreate->timeclose == 0 ||($qcreate->timeclose > $timenow));
- $activitywasopen = ($qcreate->timeopen == 0 ||($qcreate->timeopen < $qcreate->timesync)) &&
- ($qcreate->timeclose == 0 ||($qcreate->timeclose > $qcreate->timesync));
- $needsync = (empty($qcreate->timesync) || //no sync has happened yet
- ($activitywasopen != $activityopen));
- if ($forcesync || $needsync){
- if ($cmcontext == null){
- $cm = get_coursemodule_from_instance('qcreate', $qcreate->id);
- $cmcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- }
- if ($course == null){
- $course = get_record('course', 'id', $qcreate->course);
- }
+function qcreate_get_completion_state($course, $cm, $userid, $type) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
- $studentrole = get_archetype_roles('student');
- $studentrole = reset($studentrole);
+ $context = context_module::instance($cm->id);
+ $qcreateobj = new qcreate($context, $cm, $course);
- if ($activityopen){
- $capabilitiestoassign = array (
- 0=> array('moodle/question:add'=> 1, 'moodle/question:usemine'=> -1, 'moodle/question:viewmine'=> -1, 'moodle/question:editmine'=> -1),
- 1=> array('moodle/question:add'=> 1, 'moodle/question:usemine'=> 1, 'moodle/question:viewmine'=> -1, 'moodle/question:editmine'=> -1),
- 2=> array('moodle/question:add'=> 1, 'moodle/question:usemine'=> 1, 'moodle/question:viewmine'=> 1, 'moodle/question:editmine'=> -1),
- 3=> array('moodle/question:add'=> 1, 'moodle/question:usemine'=> 1, 'moodle/question:viewmine'=> 1, 'moodle/question:editmine'=> 1));
- foreach ($capabilitiestoassign[$qcreate->studentqaccess] as $capability => $permission) {
- assign_capability($capability, $permission, $studentrole->id, $cmcontext->id, true);
- }
+ $result = $type; // Default return value.
+
+ if ($qcreateobj->get_instance()->completionquestions) {
+ $value = $qcreateobj->get_instance()->completionquestions <= $qcreateobj->count_user_questions($userid);
+ if ($type == COMPLETION_AND) {
+ $result = $result && $value;
} else {
- $capabilitiestounassign = array (
- 'moodle/question:add', 'moodle/question:usemine', 'moodle/question:viewmine', 'moodle/question:editmine');
- foreach ($capabilitiestounassign as $capability) {
- unassign_capability($capability, $studentrole->id, $cmcontext->id);
- }
+ $result = $result || $value;
}
- $DB->set_field('qcreate', 'timesync', $timenow, array('id'=>$qcreate->id));
-
}
+ return $result;
}
/**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will update an existing instance with new data.
+ * Adds a qcreate instance
*
- * @param object $instance An object from the form in mod.html
- * @return boolean Success/Fail
- **/
-function qcreate_update_instance($qcreate) {
- global $COURSE, $DB;
+ * This is done by calling the add_instance() method of the qcreate type class
+ * @param stdClass $data
+ * @param mod_qcreate_mod_form $form
+ * @return int The instance id of the new qcreate
+ */
+function qcreate_add_instance(stdClass $data, $form = null) {
+ global $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
- $qcreate->timemodified = time();
- $qcreate->id = $qcreate->instance;
+ $qcreateobj = new qcreate(context_module::instance($data->coursemodule), null, null);
+ return $qcreateobj->add_instance($data, true);
+}
- $DB->delete_records('qcreate_required', array('qcreateid'=>$qcreate->id));
+/**
+ * Update an qcreate instance
+ *
+ * This is done by calling the update_instance() method of the qcreate type class
+ * @param stdClass $data he data that came from the form
+ * @param stdClass $form - unused
+ * @return object
+ */
+function qcreate_update_instance(stdClass $data, $form) {
+ global $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
- $qtypemins = array_filter($qcreate->qtype);
- if (count($qtypemins)){
- foreach ($qtypemins as $key => $qtypemin){
- $toinsert = new stdClass();
- $toinsert->no = $qcreate->minimumquestions[$key];
- $toinsert->qtype = $qtypemin;
- $toinsert->qcreateid = $qcreate->id;
- $toinsert->timemodified = time();
- $DB->insert_record('qcreate_required', $toinsert);
- }
- }
- $qcreate->allowed = join(array_keys($qcreate->allowed), ',');
+ $qcreateobj = new qcreate(context_module::instance($data->coursemodule), null, null);
+ return $qcreateobj->update_instance($data);
+}
+
+/**
+ * Given an ID of an instance of this module,
+ * this function will permanently delete the instance
+ * and any data that depends on it.
+ *
+ * @param int $id Id of the module instance
+ * @return boolean Success/Failure
+ **/
+function qcreate_delete_instance($id) {
+ global $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
- $toreturn = $DB->update_record("qcreate", $qcreate);
-
- $qcreate = $DB->get_record('qcreate', array('id'=>$qcreate->id));
+ $cm = get_coursemodule_from_instance('qcreate', $id, 0, false, MUST_EXIST);
+ $context = context_module::instance($cm->id);
- qcreate_student_q_access_sync($qcreate, null, $COURSE, true);
+ $qcreateobj = new qcreate($context, null, null);
+ return $qcreateobj->delete_instance();
+}
- qcreate_after_add_or_update($qcreate);
- return $toreturn;
+/**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * This function will remove all grades from the specified qcreate
+ * and clean up any related data.
+ *
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function qcreate_reset_userdata($data) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ $status = array();
+ $params = array('courseid' => $data->courseid);
+ $sql = "SELECT a.id FROM {qcreate} a WHERE a.course=:courseid";
+ $course = $DB->get_record('course', array('id' => $data->courseid), '*', MUST_EXIST);
+ if ($qcreates = $DB->get_records_sql($sql, $params)) {
+ foreach ($qcreates as $qcreate) {
+ $cm = get_coursemodule_from_instance('qcreate',
+ $qcreate->id,
+ $data->courseid,
+ false,
+ MUST_EXIST);
+ $context = context_module::instance($cm->id);
+ $qcreateobj = new qcreate($context, $cm, $course);
+ $status = array_merge($status, $qcreateobj->reset_userdata($data));
+ }
+ }
+ return $status;
}
+
/**
- * This function is called at the end of qcreate_add_instance
- * and qcreate_update_instance, to do the common processing.
+ * This standard function will check all instances of this module
+ * and make sure there are up-to-date events created for each of them.
+ * If courseid = 0, then every qcreate event in the site is checked, else
+ * only qcreate events belonging to the course specified are checked.
+ * This function is used, in its new format, by restore_refresh_events()
*
- * @param object $qcreate the qcreate object.
+ * @param int $courseid
+ * @param int|stdClass $instance qcreate module instance or ID.
+ * @param int|stdClass $cm Course module object or ID (not used in this module).
+ * @return bool
*/
-function qcreate_after_add_or_update($qcreate) {
- global $COURSE, $DB;
+function qcreate_refresh_events($courseid = 0, $instance = null, $cm = null) {
+ global $DB;
- // Update the events relating to this qcreate.
- // This is slightly inefficient, deleting the old events and creating new ones. However,
- // there are at most two events, and this keeps the code simpler.
- if ($events = $DB->get_records('event', array('modulename' => 'qcreate', 'instance' => $qcreate->id))) {
- foreach($events as $event) {
- delete_event($event->id);
+ // If we have instance information then we can just update the one event instead of updating all events.
+ if (isset($instance)) {
+ if (!is_object($instance)) {
+ $instance = $DB->get_record('qcreate', array('id' => $instance), '*', MUST_EXIST);
}
+ qcreate_update_events($instance);
+ return true;
}
- $event = new stdClass;
- $event->description = $qcreate->intro;
- $event->courseid = $qcreate->course;
- $event->groupid = 0;
- $event->userid = 0;
- $event->modulename = 'qcreate';
- $event->instance = $qcreate->id;
- $event->timestart = $qcreate->timeopen;
- $event->timeduration = $qcreate->timeclose - $qcreate->timeopen;
- $event->visible = instance_is_visible('qcreate', $qcreate);
- $event->eventtype = 'open';
-
- if ($qcreate->timeclose and $qcreate->timeopen and $event->timeduration <= QCREATE_MAX_EVENT_LENGTH) {
- // Single event for the whole qcreate.
- $event->name = $qcreate->name;
- add_event($event);
- } else {
- // Separate start and end events.
- $event->timeduration = 0;
- if ($qcreate->timeopen) {
- $event->name = $qcreate->name.' ('.get_string('qcreateopens', 'qcreate').')';
- add_event($event);
- unset($event->id); // So we can use the same object for the close event.
+ if ($courseid == 0) {
+ if (!$qcreates = $DB->get_records('qcreate')) {
+ return true;
}
- if ($qcreate->timeclose) {
- $event->name = $qcreate->name.' ('.get_string('qcreatecloses', 'qcreate').')';
- $event->timestart = $qcreate->timeclose;
- $event->eventtype = 'close';
- add_event($event);
+ } else {
+ if (!$qcreates = $DB->get_records('qcreate', array('course' => $courseid))) {
+ return true;
}
}
- //update related grade item
- qcreate_grade_item_update($qcreate);
+ foreach ($qcreates as $qcreate) {
+ qcreate_update_events($qcreate);
+ }
+ return true;
}
+
/**
- * Given an ID of an instance of this module,
- * this function will permanently delete the instance
- * and any data that depends on it.
+ * This actually updates the activity calendar events.
*
- * @param int $id Id of the module instance
- * @return boolean Success/Failure
- **/
-function qcreate_delete_instance($id) {
+ * @param stdClass $qcreate qcreate object (from DB).
+ * @param stdClass $course Course object.
+ * @param stdClass $cm Course module object.
+ */
+function qcreate_update_events($qcreate, $course = null, $cm = null) {
+ global $DB, $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
- if (! $qcreate = get_record("qcreate", "id", "$id")) {
- return false;
+ if (!isset($course)) {
+ // Get course and course module for the qcreate.
+ list($course, $cm) = get_course_and_cm_from_instance($qcreate->id, 'qcreate', $qcreate->course);
}
+ // Refresh the qcreate's calendar events.
+ $context = context_module::instance($cm->id);
+ $qcreateobj = new qcreate($context, $cm, $course);
+ $qcreateobj->update_calendar($cm->id);
+}
+/**
+ * Prints qcreate summaries on MyMoodle Page
+ * @param array $courses
+ * @param array $htmlarray
+ */
+function qcreate_print_overview($courses, &$htmlarray) {
+ global $USER, $CFG;
- $result = true;
+ debugging('The function qcreate_print_overview() is now deprecated.', DEBUG_DEVELOPER);
- if (! delete_records("qcreate_grades", "qcreateid", "$qcreate->id")) {
- $result = false;
+ // These next 6 Lines are constant in all modules (just change module name).
+ if (empty($courses) || !is_array($courses) || count($courses) == 0) {
+ return array();
}
- if (! delete_records("qcreate_required", "qcreateid", "$qcreate->id")) {
- $result = false;
+ if (!$qcreates = get_all_instances_in_courses('qcreate', $courses)) {
+ return;
}
- if (! delete_records("qcreate", "id", "$qcreate->id")) {
- $result = false;
+ // Fetch some language strings outside the main loop.
+ $strqcreate = get_string('modulename', 'qcreate');
+
+ // We want to list qcreates that are currently availables.
+ // I know this is different from lesson and quiz. See MDL-10568.
+ $now = time();
+ $strnoquestions = get_string('noquestions', 'qcreate');
+ foreach ($qcreates as $qcreate) {
+ if (($qcreate->timeopen == 0 ||($qcreate->timeopen < $now)) &&
+ ($qcreate->timeclose == 0 ||($qcreate->timeclose > $now))) {
+ // Give a link to the qcreate, and the deadline.
+ $str = '
';
+
+ // Now provide more information depending on the uers's role.
+ $context = context_module::instance($qcreate->coursemodule);
+ if (has_capability('mod/qcreate:grade', $context)) {
+ // For teacher-like people, show a summary of the number questions created.
+ // The $qcreate objects returned by get_all_instances_in_course have the necessary $cm
+ // fields set to make the following call work.
+ $str .= '
';
+ } else if (has_capability('mod/qcreate:view', $context)) { // Student
+ // For student-like people, tell them how many questions they have created.
+ if (isset($USER->id)) {
+ $str .= '
';
+ }
+ } else {
+ // For ayone else, there is no point listing this qcreate, so stop processing.
+ continue;
+ }
+
+ // Add the output for this qcreate to the rest.
+ $str .= '
';
+ if (empty($htmlarray[$qcreate->course]['qcreate'])) {
+ $htmlarray[$qcreate->course]['qcreate'] = $str;
+ } else {
+ $htmlarray[$qcreate->course]['qcreate'] .= $str;
+ }
+ }
}
+}
- return $result;
+/**
+ * Removes all grades from gradebook
+ *
+ * @param int $courseid The ID of the course to reset
+ * @param string $type Optional type of qcreate (not used here)
+ */
+function qcreate_reset_gradebook($courseid, $type='') {
+ global $CFG, $DB;
+
+ $params = array('moduletype' => 'qcreate', 'courseid' => $courseid);
+ $sql = 'SELECT q.*, cm.idnumber as cmidnumber, q.course as courseid
+ FROM {qcreate} q, {course_modules} cm, {modules} m
+ WHERE m.name=:moduletype AND m.id=cm.module AND cm.instance=q.id AND q.course=:courseid';
+
+ if ($qcreates = $DB->get_records_sql($sql, $params)) {
+ foreach ($qcreates as $qcreate) {
+ qcreate_grade_item_update($qcreate, 'reset');
+ }
+ }
}
/**
- * Return a small object with summary information about what a
- * user has done with a given particular instance of this module
- * Used for user activity reports.
- * $return->time = the time they did it
- * $return->info = a short text description
+ * Implementation of the function for printing the form elements that control
+ * whether the course reset functionality affects the qcreate.
*
- * @return null
- * @todo Finish documenting this function
- **/
+ *
+ * @param $mform form passed by reference
+ */
+function qcreate_reset_course_form_definition(&$mform) {
+ $mform->addElement('header', 'qcreateheader', get_string('modulenameplural', 'qcreate'));
+ $mform->addElement('advcheckbox', 'reset_qcreate', get_string('deletegrades', 'qcreate'));
+}
+
+/**
+ * Course reset form defaults.
+ *
+ *
+ * @param stdClass $course
+ * @return array
+ */
+function qcreate_reset_course_form_defaults($course) {
+ return array('reset_qcreate' => 1);
+}
+
+/**
+ * Used by course/user.php to display this module's user activity outline.
+ * @param object $course as this is a standard function this is required but not used here
+ * @param object $user user object
+ * @param object $mod not used here
+ * @param object $qcreate qcreate object
+ * @return object A standard object with 2 variables: info (grade for this user) and
+ * time (last modified)
+ */
function qcreate_user_outline($course, $user, $mod, $qcreate) {
- return null;
+ global $DB, $CFG;
+
+ require_once($CFG->libdir . '/gradelib.php');
+ $result = new stdClass();
+ $result->info = get_string('questionscreated', 'qcreate', qcreate_get_qestions_number($user->id, $qcreate));
+ $grades = grade_get_grades($course->id, 'mod', 'qcreate', $qcreate->id, $user->id);
+
+ if (empty($grades->items[0]->grades)) {
+ return null;
+ } else {
+ $grade = reset($grades->items[0]->grades);
+ $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
+ }
+ $result->time = $grade->dategraded;
+
+ return $result;
}
/**
- * Print a detailed representation of what a user has done with
+ * Print a detailed representation of what a user has done with
* a given particular instance of this module, for user activity reports.
*
- * @return boolean
- * @todo Finish documenting this function
- **/
-function qcreate_user_complete($course, $user, $mod, $qcreate) {
+ * @param object $course
+ * @param object $user
+ * @param object $coursemodule
+ * @param object $qcreate
+ * @return bool
+ */
+function qcreate_user_complete($course, $user, $coursemodule, $qccreate) {
+ global $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ $context = context_module::instance($coursemodule->id);
+ $qcreateobj = new qcreate($context, $coursemodule, $course);
+ echo $qcreateobj->view_student_summary($user, false);
return true;
}
/**
- * Given a course and a time, this module should find recent activity
- * that has occurred in qcreate activities and print it out.
- * Return true if there was output, or false is there was none.
+ * Print recent activity from all qcreates in a given course
*
- * @uses $CFG
- * @return boolean
- * @todo Finish documenting this function
- **/
-function qcreate_print_recent_activity($course, $isteacher, $timestart) {
- global $CFG;
+ * This is used by the recent activity block
+ * @param mixed $course the course to print activity for
+ * @param bool $viewfullnames boolean to determine whether to show full names or not
+ * @param int $timestart the time the rendering started
+ * @return bool true if activity was printed, false otherwise.
+ */
+function qcreate_print_recent_activity($course, $viewfullnames, $timestart) {
+ global $CFG, $DB, $OUTPUT;
+ if (!defined('QCREATE_RECENT_ACTIVITY_LIMIT')) {
+ define('QCREATE_RECENT_ACTIVITY_LIMIT', 20);
+ }
+ $modinfo = get_fast_modinfo($course);
+ $ids = array();
+ $params = array();
+
+ foreach ($modinfo->cms as $cm) {
+ if ($cm->modname != 'qcreate') {
+ continue;
+ }
+ if (!$cm->uservisible) {
+ continue;
+ }
+ $modcontext = context_module::instance($cm->id);
+ $ids[$cm->instance] = $modcontext->id;
+ }
+
+ if (!$ids) {
+ return false;
+ }
+
+ // Generate list of question categories ids for all qcreates in the course.
+ $qcatids = array();
+ foreach ($ids as $qcreateinstanceid => $qcatid) {
+ $qcatids[] = ' qc.contextid = :qccontid'.$qcreateinstanceid.' ';
+ $params['qccontid'.$qcreateinstanceid] = $qcatid;
+ }
- return false; // True if anything was printed, otherwise false
+ if (count($qcatids) > 0) {
+ $qcatsql = 'AND ('. implode($qcatids, ' OR ') .') ';
+ } else {
+ $qcatsql = '';
+ }
+
+ $params['timestart'] = $timestart;
+
+ // Generate list of created questions for all qcreate in the course.
+ $userfields = user_picture::fields('u', null, 'userid');
+ $sql = 'SELECT q.id, q.name AS qname, qc.id as qcat, q.timemodified, g.grade as rawgrade, a.name AS aname, a.id as aid, ' .
+ $userfields .
+ ' FROM {question} q
+ LEFT JOIN {user} u ON u.id = q.createdby
+ LEFT JOIN {question_categories} qc ON qc.id = q.category
+ LEFT JOIN {qcreate_grades} g ON g.questionid = q.id
+ LEFT JOIN {context} c ON c.id = qc.contextid
+ LEFT JOIN {course_modules} cm ON cm.id = c.instanceid
+ LEFT JOIN {qcreate} a ON a.id = cm.instance
+ WHERE q.timecreated > :timestart ' .
+ $qcatsql .
+ ' ORDER BY q.timecreated ASC';
+
+ if ($questions = $DB->get_records_sql($sql, $params)) {
+ echo $OUTPUT->heading(get_string('newquestions', 'qcreate').':', 3);
+ $strftimerecent = get_string('strftimerecent');
+ $questioncount = 0;
+ foreach ($questions as $question) {
+ if ($questioncount < QCREATE_RECENT_ACTIVITY_LIMIT) {
+ $urlparams = array('a' => $question->aid);
+ $link = new moodle_url($CFG->wwwroot.'/mod/qcreate/view.php', $urlparams);
+ print_recent_activity_note($question->timemodified,
+ $question,
+ $question->aname,
+ $link,
+ false,
+ $viewfullnames);
+ $questioncount += 1;
+ } else {
+ $numnewquestions = count($questions);
+ echo '
';
+}
+
+/**
+ * Function to be run periodically according to the scheduled task manager
+ * This function synchronize students access to questions according
+ * to the instance settings and to the open/closed status of the instance.
*
- * @param int $qcreateid ID of an instance of this module
- * @return mixed Null or object with an array of grades and with the maximum grade
**/
-function qcreate_grades($qcreateid) {
- return NULL;
+function qcreate_student_q_access_sync($cmcontext, $qcreate, $forcesync= false) {
+ global $DB;
+
+ // Check if a check is needed.
+ $timenow = time();
+ $activityopen = ($qcreate->timeopen == 0 ||($qcreate->timeopen < $timenow)) &&
+ ($qcreate->timeclose == 0 ||($qcreate->timeclose > $timenow));
+ $activitywasopen = ($qcreate->timeopen == 0 ||($qcreate->timeopen < $qcreate->timesync)) &&
+ ($qcreate->timeclose == 0 ||($qcreate->timeclose > $qcreate->timesync));
+ $needsync = (empty($qcreate->timesync) || // No sync has happened yet.
+ ($activitywasopen != $activityopen));
+
+ if ($forcesync || $needsync) {
+ $studentrole = get_archetype_roles('student');
+ $studentrole = reset($studentrole);
+
+ if ($activityopen) {
+ $capabilitiestoassign = array (
+ 0 => array('moodle/question:add' => CAP_ALLOW, 'moodle/question:usemine' => CAP_PREVENT,
+ 'moodle/question:viewmine' => CAP_PREVENT, 'moodle/question:editmine' => CAP_PREVENT),
+ 1 => array('moodle/question:add' => CAP_ALLOW, 'moodle/question:usemine' => CAP_ALLOW,
+ 'moodle/question:viewmine' => CAP_PREVENT, 'moodle/question:editmine' => CAP_PREVENT),
+ 2 => array('moodle/question:add' => CAP_ALLOW, 'moodle/question:usemine' => CAP_ALLOW,
+ 'moodle/question:viewmine' => CAP_ALLOW, 'moodle/question:editmine' => CAP_PREVENT),
+ 3 => array('moodle/question:add' => CAP_ALLOW, 'moodle/question:usemine' => CAP_ALLOW,
+ 'moodle/question:viewmine' => CAP_ALLOW, 'moodle/question:editmine' => CAP_ALLOW));
+ foreach ($capabilitiestoassign[$qcreate->studentqaccess] as $capability => $permission) {
+ assign_capability($capability, $permission, $studentrole->id, $cmcontext->id, true);
+ }
+ } else {
+ $capabilitiestounassign = array (
+ 'moodle/question:add', 'moodle/question:usemine', 'moodle/question:viewmine', 'moodle/question:editmine');
+ foreach ($capabilitiestounassign as $capability) {
+ unassign_capability($capability, $studentrole->id, $cmcontext->id);
+ }
+ }
+ $DB->set_field('qcreate', 'timesync', $timenow, array('id' => $qcreate->id));
+ }
}
/**
- * Must return an array of user records (all data) who are participants
- * for a given instance of qcreate. Must include every user involved
- * in the instance, independient of his role (student, teacher, admin...)
- * See other modules as example.
+ * Returns all other caps used in the module
*
- * @param int $qcreateid ID of an instance of this module
- * @return mixed boolean/array of students
- **/
-function qcreate_get_participants($qcreateid) {
- return false;
+ * @example return array('moodle/site:accessallgroups');
+ * @return array
+ */
+function qcreate_get_extra_capabilities() {
+ global $CFG;
+ require_once($CFG->libdir . '/questionlib.php');
+ $caps = question_get_all_capabilities();
+ $caps[] = 'moodle/site:accessallgroups';
+ return $caps;
}
/**
* This function returns if a scale is being used by one qcreate
- * it it has support for grading and scales. Commented code should be
+ * if it has support for grading and scales. Commented code should be
* modified if necessary. See forum, glossary or journal modules
* as reference.
*
@@ -350,41 +787,56 @@ function qcreate_get_participants($qcreateid) {
* @return mixed
* @todo Finish documenting this function
**/
-function qcreate_scale_used ($qcreateid,$scaleid) {
+function qcreate_scale_used ($qcreateid, $scaleid) {
+ global $DB;
+
$return = false;
+ $rec = $DB->get_record('qcreate', array('id' => $qcreateid, 'grade' => -$scaleid));
- //$rec = get_record("qcreate","id","$qcreateid","scale","-$scaleid");
- //
- //if (!empty($rec) && !empty($scaleid)) {
- // $return = true;
- //}
+ if (!empty($rec) && !empty($scaleid)) {
+ $return = true;
+ }
return $return;
}
-//////////////////////////////////////////////////////////////////////////////////////
-/// Any other qcreate functions go here. Each of them must have a name that
-/// starts with qcreate_
-/// Remember (see note in first lines) that, if this section grows, it's HIGHLY
-/// recommended to move all funcions below to a new "localib.php" file.
+/**
+ * Checks if scale is being used by any instance of qcreate
+ *
+ * This is used to find out if scale used anywhere
+ * @param int $scaleid
+ * @return boolean True if the scale is used by any qcreate
+ */
+function qcreate_scale_used_anywhere($scaleid) {
+ global $DB;
+
+ if ($scaleid and $DB->record_exists('qcreate', array('grade' => -$scaleid))) {
+ return true;
+ } else {
+ return false;
+ }
+}
/**
- * Create one or all grade items for given qcreate
+ * Create/update grade item for given qcreate
*
- * @param object $qcreate object with extra cmidnumber
- * @return int 0 if ok, error code otherwise
+ * @param stdClass $qcreate qcreate object with extra cmidnumber
+ * @param mixed $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
+ * @return int 0 if ok
*/
-function qcreate_grade_item_update($qcreate) {
+function qcreate_grade_item_update($qcreate, $grades=null) {
global $CFG;
- if (!function_exists('grade_update')) { //workaround for buggy PHP versions
- require_once($CFG->libdir.'/gradelib.php');
- }
+ require_once($CFG->libdir . '/gradelib.php');
if (!isset($qcreate->courseid)) {
$qcreate->courseid = $qcreate->course;
}
- $params = array('itemname'=>$qcreate->name, 'idnumber'=>$qcreate->cmidnumber);
+ if (array_key_exists('cmidnumber', $qcreate)) { // It may not be always present.
+ $params = array('itemname' => $qcreate->name, 'idnumber' => $qcreate->cmidnumber);
+ } else {
+ $params = array('itemname' => $qcreate->name);
+ }
if ($qcreate->grade > 0) {
$params['gradetype'] = GRADE_TYPE_VALUE;
@@ -397,90 +849,106 @@ function qcreate_grade_item_update($qcreate) {
} else {
$params['gradetype'] = GRADE_TYPE_NONE;
}
+
+ if ($grades === 'reset') {
+ $params['reset'] = true;
+ $grades = null;
+ }
$params['itemnumber'] = 0;
- return grade_update('mod/qcreate', $qcreate->courseid, 'mod', 'qcreate', $qcreate->id, 0, NULL, $params);
+ return grade_update('mod/qcreate', $qcreate->courseid, 'mod', 'qcreate', $qcreate->id, 0, $grades, $params);
}
+
/**
* Process submitted grades.
* @param opbject qcreate the qcreate object with cmidnumber set to $cm->id
* @param object cm coursemodule object
* @param array users array of ids of users who can take part in this activity.
*/
-function qcreate_process_grades($qcreate, $cm, $users){
- global $USER, $DB;
- ///do the fast grading stuff
+function qcreate_process_grades($qcreate, $cm, $users) {
+ global $DB, $OUTPUT;
+
+ // Do the fast grading stuff.
$grading = false;
$commenting = false;
$qids = array();
- if (isset($_POST['gradecomment'])) {
+ $submitcomments = optional_param_array('gradecomment', 0, PARAM_RAW);
+ $submittedgrades = optional_param_array('menu', 0, PARAM_INT);
+ if ($submitcomments) {
$commenting = true;
- //process array of submitted comments
- $submitcomments = optional_param_array('gradecomment', 0, PARAM_RAW);
- $qids = array_keys($_POST['gradecomment']);
+ // Process array of submitted comments.
+ $qids = array_keys($submitcomments);
}
- if (isset($_POST['menu'])) {
+ if ($submittedgrades) {
$grading = true;
- //process array of submitted grades
- $submittedgrades = optional_param_array('menu', 0, PARAM_INT);
- $qids = array_unique(array_merge($qids, array_keys($_POST['menu'])));
+ // Process array of submitted grades.
+ $qids = array_unique(array_merge($qids, array_keys($submittedgrades)));
}
if (!$qids) {
- return;
+ $message = $OUTPUT->notification(get_string('nothingtosave', 'qcreate'), 'notifyproblem');
+ return $message;
}
- //get the cleaned keys which are the questions ids
- $qids = clean_param_array($qids, PARAM_INT);
- if ($qids){
+ // Get the cleaned keys which are the questions ids.
+ $qids = clean_param_array($qids, PARAM_INT);
+ if ($qids) {
$toupdates = array();
$questions = $DB->get_records_select('question', 'id IN ('.implode(',', $qids).') AND '.
'createdby IN ('.implode(',', $users).')');
- foreach ($qids as $qid){
- //test that qid is a question created by one of the users we can grade
- if (isset($questions[$qid])){
+ foreach ($qids as $qid) {
+ // Test that qid is a question created by one of the users we can grade.
+ if (isset($questions[$qid])) {
$question = $questions[$qid];
- //TODO fix outcomes
- //qcreate_process_outcomes($qcreate, $id);
+ // TODO fix outcomes,
+ // and call qcreate_process_outcomes.
if ($grading) {
$submittedgrade = $submittedgrades[$qid];
} else {
- $submittedgrade = -1; //not graded
+ $submittedgrade = -1; // Not graded.
}
if ($commenting) {
$submitcomment = $submitcomments[$qid];
} else {
- $submitcomment = ''; //no comment
+ $submitcomment = ''; // No comment.
}
-
- if (qcreate_process_local_grade($qcreate, $question, false, $submittedgrade, $submitcomment)){
+
+ if (qcreate_process_local_grade($qcreate, $question, false, true, $submittedgrade, $submitcomment)) {
$toupdates[] = $question->createdby;
}
}
}
$toupdates = array_unique($toupdates);
- foreach ($toupdates as $toupdate){
+ foreach ($toupdates as $toupdate) {
qcreate_update_grades($qcreate, $toupdate);
}
-
}
- $message = notify(get_string('changessaved'), 'notifysuccess', 'center', true);
+ $message = $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
return $message;
}
-function qcreate_process_local_grade($qcreate, $question, $forcenewgrade = false, $submittedgrade=-1, $submittedcomment=''){
- global $USER, $DB;
- if ($forcenewgrade || !$grade = qcreate_get_grade($qcreate, $question->id)) {
- $grade = qcreate_prepare_new_grade($qcreate, $question);
+/**
+ * Process submitted grades.
+ * @param opbject qcreate the qcreate object with cmidnumber set to $cm->id
+ * @param object question with id and createdby
+ * @param array users array of ids of users who can take part in this activity.
+ */
+function qcreate_process_local_grade($qcreate, $question,
+ $forcenewgrade = false, $notifystudent = false, $submittedgrade = -1, $submittedcomment = '') {
+ global $CFG, $USER, $DB;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ $context = context_module::instance($qcreate->cmidnumber);
+ $qcreateobj = new qcreate($context, null, null);
+ if ($forcenewgrade || !$grade = qcreate_get_local_grade($qcreate, $question->id)) {
+ $grade = qcreate_prepare_new_local_grade($qcreate, $question);
$newgrade = true;
} else {
$newgrade = false;
}
- unset($grade->data1); // Don't need to update this.
- unset($grade->data2); // Don't need to update this.
- //for fast grade, we need to check if any changes take place
+ // For fast grade, we need to check if any changes take place.
$updatedb = false;
$updatedb = $updatedb || ($grade->grade != $submittedgrade);
@@ -492,65 +960,95 @@ function qcreate_process_local_grade($qcreate, $question, $forcenewgrade = false
$grade->userid = $question->createdby;
$grade->teacher = $USER->id;
- if ($grade->grade != -1){
+ if ($grade->grade != -1) {
$grade->timemarked = time();
} else {
$grade->timemarked = 0;
}
- //if it is not an update, we don't change the last modified time etc.
- //this will also not write into database if no gradecomment and grade is entered.
+ // If it is not an update, we don't change the last modified time etc.
+ // This will also not write into database if no gradecomment and grade is entered.
- if ($forcenewgrade || $updatedb){
+ if ($forcenewgrade || $updatedb) {
if ($newgrade) {
if (!$sid = $DB->insert_record('qcreate_grades', $grade)) {
return false;
}
$grade->id = $sid;
+
+ $params = array(
+ 'context' => context_module::instance($qcreate->cmidnumber),
+ 'objectid' => $grade->id,
+ 'relateduserid' => $grade->userid,
+ 'other' => array(
+ 'qcreateid' => $qcreate->id,
+ 'questionid' => $question->id,
+ )
+ );
+ $event = \mod_qcreate\event\question_graded::create($params);
+ $event->add_record_snapshot('qcreate_grades', $grade);
+ $event->trigger();
+
} else {
if (!$DB->update_record('qcreate_grades', $grade)) {
return false;
}
- }
- // triger grade event
- //add to log only if updating
- add_to_log($qcreate->course, 'qcreate', 'update grades',
- 'grades.php?id='.$qcreate->id.'&user='.$grade->userid,
- $grade->userid, $qcreate->cmidnumber);
+ $params = array(
+ 'context' => context_module::instance($qcreate->cmidnumber),
+ 'objectid' => $grade->id,
+ 'relateduserid' => $grade->userid,
+ 'other' => array(
+ 'qcreateid' => $qcreate->id,
+ 'questionid' => $question->id,
+ )
+ );
+ $event = \mod_qcreate\event\question_regraded::create($params);
+ $event->add_record_snapshot('qcreate_grades', $grade);
+ $event->trigger();
+
+ }
+ if ($notifystudent) {
+ $qcreateobj->notify_student_question_graded($question);
+ }
}
return $updatedb;
}
-function qcreate_process_outcomes($qcreate, $userid) {
- global $CFG, $COURSE;
-
- if (empty($CFG->enableoutcomes)) {
- return;
+/**
+ * Return the number of question created by a particular user for a qceate activity
+ *
+ * @param $integer userid id of the user, 0 means all users
+ * @param object $qcreate object
+ * @return integer
+ */
+function qcreate_get_qestions_number($userid, $qcreate) {
+ global $DB;
+
+ $cm = get_coursemodule_from_instance('qcreate', $qcreate->id);
+ $modcontext = context_module::instance($cm->id);
+
+ $params = array();
+ $whereqtype = '';
+ $whereuser = '';
+ if ($qcreate->allowed != 'ALL') {
+ $allowedparts = explode(',', $qcreate->allowed);
+ $allowedlist = "'".join("','", $allowedparts)."'";
+ $whereqtype = 'q.qtype IN ('.$allowedlist.') AND ';
}
- require_once($CFG->libdir.'/gradelib.php');
-
- if (!$formdata = data_submitted()) {
- return;
+ if ($userid) {
+ $params['userid'] = $userid;
+ $whereuser = 'q.createdby = :userid AND ';
}
- $data = array();
- $grading_info = grade_get_grades($COURSE->id, 'mod', 'qcreate', $qcreate->id, $userid);
-
- if (!empty($grading_info->outcomes)) {
- foreach($grading_info->outcomes as $n=>$old) {
- $name = 'outcome_'.$n;
- if (isset($formdata->{$name}[$userid]) and $old->grades[$userid]->grade != $formdata->{$name}[$userid]) {
- $data[$n] = $formdata->{$name}[$userid];
- }
- }
- }
- if (count($data) > 0) {
- grade_update_outcomes('mod/qcreate', $COURSE->id, 'mod', 'qcreate', $qcreate->id, $userid, $data);
- }
+ $params['contextid'] = $modcontext->id;
+ $countsql = 'SELECT COUNT(q.id) FROM {question} q,{question_categories} c '.
+ 'WHERE ' . $whereqtype . $whereuser .
+ 'q.hidden=\'0\' AND q.parent=\'0\' AND q.category = c.id and c.contextid = :contextid';
+ return $DB->count_records_sql($countsql, $params);
}
/**
* Load the local grade object for a particular user
@@ -560,20 +1058,22 @@ function qcreate_process_outcomes($qcreate, $userid) {
* @param $createnew boolean optional Defaults to false. If set to true a new grade object will be created in the database
* @return object The grade
*/
-function qcreate_get_grade($qcreate, $qid, $createnew=false) {
- global $DB;
-
- $grade = $DB->get_record('qcreate_grades', array('qcreateid'=>$qcreate->id, 'questionid'=>$qid));
+function qcreate_get_local_grade($qcreate, $qid, $createnew = false) {
+ global $DB;
+
+ $grade = $DB->get_record_sql(
+ 'SELECT * FROM {qcreate_grades} WHERE qcreateid=? AND questionid=? ORDER BY timemarked DESC LIMIT 1',
+ array($qcreate->id, $qid));
if ($grade || !$createnew) {
return $grade;
}
- $newgrade = qcreate_prepare_new_grade($qcreate, $qid);
- if (!insert_record("qcreate_grades", $newgrade)) {
- error("Could not insert a new empty grade");
+ $newgrade = qcreate_prepare_new_local_grade($qcreate, $qid);
+ if (!$DB->insert_record('qcreate_grades', $newgrade)) {
+ print_error('Could not insert a new empty grade');
}
- return get_record('qcreate_grades', 'qcreate', $qcreate->id, 'questionid', $qid);
+ return $DB->get_record('qcreate_grades', array('qcreateid' => $qcreate->id, 'questionid' => $qid));
}
/**
@@ -583,79 +1083,89 @@ function qcreate_get_grade($qcreate, $qid, $createnew=false) {
* @param $userid int The userid for which we want a grade object
* @return object The grade
*/
-function qcreate_prepare_new_grade($qcreate, $question) {
- $grade = new Object;
+function qcreate_prepare_new_local_grade($qcreate, $question) {
+ $grade = new stdClass();
$grade->qcreateid = $qcreate->id;
$grade->questionid = $question->id;
- $grade->numfiles = 0;
- $grade->data1 = '';
- $grade->data2 = '';
$grade->grade = -1;
$grade->gradecomment = '';
$grade->teacher = 0;
$grade->timemarked = 0;
- $grade->mailed = 0;
return $grade;
}
+
/**
- * Update grades.
+ * Update grades in the gradebook.
*
* @param object $qcreate null means all qcreates
* @param int $userid specific user only, 0 mean all
+ * @param bool $nullifnone If true and the user has no grade then a grade item with rawgrade == null will be inserted
*/
-function qcreate_update_grades($qcreate=null, $userid=0) {
+function qcreate_update_grades($qcreate=null, $userid=0, $nullifnone = true) {
global $CFG, $DB;
- if (!function_exists('grade_update')) { //workaround for buggy PHP versions
- require_once($CFG->libdir.'/gradelib.php');
- }
+ require_once($CFG->libdir . '/gradelib.php');
if ($qcreate != null) {
- if ($gradesbyuserids = qcreate_get_user_grades($qcreate, $userid)) {
- foreach ($gradesbyuserids as $userid => $gradesbyuserid){
- qcreate_grade_item_update($qcreate);
- grade_update('mod/qcreate', $qcreate->courseid, 'mod', 'qcreate', $qcreate->id, 0, $gradesbyuserid);
- }
+ if ($qcreate->grade == 0) {
+ qcreate_grade_item_update($qcreate);
+ } else if ($grades = qcreate_get_user_grades($qcreate, $userid)) {
+ qcreate_grade_item_update($qcreate, $grades);
+
+ } else if ($userid && $nullifnone) {
+ $grade = new stdClass();
+ $grade->userid = $userid;
+ $grade->rawgrade = null;
+ qcreate_grade_item_update($qcreate, $grade);
+
+ } else {
+ qcreate_grade_item_update($qcreate);
}
} else {
- $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
- FROM {$CFG->prefix}qcreate a, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
- WHERE m.name='qcreate' AND m.id=cm.module AND cm.instance=a.id";
+ $sql = "SELECT q.*, cm.id as cmidnumber, q.course as courseid
+ FROM {qcreate} q, {course_modules} cm, {modules} m
+ WHERE m.name='qcreate' AND m.id=cm.module AND cm.instance=q.id";
$rs = $DB->get_recordset_sql($sql);
- foreach ($rs as $qcreate) {
+ foreach ($rs as $qcreate) {
qcreate_grade_item_update($qcreate);
if ($qcreate->grade != 0) {
- qcreate_update_grades($qcreate);
+ qcreate_update_grades($qcreate, $userid);
}
}
$rs->close();
}
}
+
/**
* Return local grades for given user or all users.
*
* @param object $qcreate
- * @param int $userid optional user id, 0 means all users
+ * @param mixed $userid optional user id or array of userids, 0 means all users
* @return array array of grades, false if none
*/
function qcreate_get_user_grades($qcreate, $userid=0) {
- global $CFG, $DB;
- if (is_array($userid)){
- $user = "u.id IN (".implode(',', $userid).") AND";
- } else if ($userid){
- $user = "u.id = $userid AND";
+ global $DB;
+
+ $cm = get_coursemodule_from_instance('qcreate', $qcreate->id, 0, false, MUST_EXIST);
+ $context = context_module::instance($cm->id);
+ if (is_array($userid)) {
+ $user = "u.id IN (".implode(',', $userid).") AND";
+ } else if ($userid) {
+ $user = "u.id = $userid AND";
} else {
- $user = '';
- }
- $modulecontext = get_context_instance(CONTEXT_MODULE, $qcreate->cmidnumber);
- $sql = "SELECT q.id, u.id AS userid, g.grade AS rawgrade, g.gradecomment AS feedback, g.teacher AS usermodified, q.qtype AS qtype
- FROM {$CFG->prefix}user u, {$CFG->prefix}question_categories qc, {$CFG->prefix}question q
- LEFT JOIN {$CFG->prefix}qcreate_grades g ON g.questionid = q.id
- WHERE $user u.id = q.createdby AND qc.id = q. category AND qc.contextid={$modulecontext->id}
- ORDER BY rawgrade DESC";
+ $user = '';
+ }
+
+ $sql = "SELECT q.id, u.id AS userid, g.grade AS rawgrade, g.gradecomment AS feedback,
+ g.teacher AS usermodified, q.qtype AS qtype
+ FROM {user} u, {question_categories} qc, {question} q
+ LEFT JOIN {qcreate_grades} g ON g.questionid = q.id
+ WHERE $user u.id = q.createdby AND qc.id = q. category AND qc.contextid={$context->id}
+ ORDER BY rawgrade DESC";
$localgrades = $DB->get_records_sql($sql);
+
$gradesbyuserids = array();
- foreach($localgrades as $k=>$v) {
- if (!isset($gradesbyuserids[$v->userid])){
+ foreach ($localgrades as $k => $v) {
+ if (!isset($gradesbyuserids[$v->userid])) {
$gradesbyuserids[$v->userid] = array();
}
if ($v->rawgrade == -1) {
@@ -664,7 +1174,7 @@ function qcreate_get_user_grades($qcreate, $userid=0) {
$gradesbyuserids[$v->userid][$k] = $v;
}
$aggregategradebyuserids = array();
- foreach ($gradesbyuserids as $userid => $gradesbyuserid){
+ foreach ($gradesbyuserids as $userid => $gradesbyuserid) {
$aggregategradebyuserids[$userid] = qcreate_grade_aggregate($gradesbyuserid, $qcreate);
}
return $aggregategradebyuserids;
@@ -673,54 +1183,58 @@ function qcreate_get_user_grades($qcreate, $userid=0) {
* @param array gradesforuser an array of objects from local grades tables
* @return aggregated grade
*/
-function qcreate_grade_aggregate($gradesforuser, $qcreate){
+function qcreate_grade_aggregate($gradesforuser, $qcreate) {
$aggregated = new stdClass();
$aggregated->rawgrade = 0;
$aggregated->usermodified = 0;
$requireds = qcreate_required_qtypes($qcreate);
- //need to make sure that we grade required questions and then any extra.
- //grades are sorted for descending raw grade
+
+ // Need to make sure that we grade required questions and then any extra.
+ // Grades are sorted for descending raw grade.
$counttotalrequired = $qcreate->totalrequired;
- if ($requireds){
- foreach ($requireds as $required){
- foreach ($gradesforuser as $key => $gradeforuser){
- if ($gradeforuser->qtype == $required->qtype){
- $aggregated->rawgrade += ($gradeforuser->rawgrade / $qcreate->totalrequired);
- $aggregated->userid = $gradeforuser->userid;
- unset($gradesforuser[$key]);
- $required->no--;
- $counttotalrequired--;
- if ($required->no == 0){
- //go on to the next required type
- break;
- }
- }
- }
- }
- }
- if ($counttotalrequired != 0){
- //now grade the remainder of the questions
- if ($qcreate->allowed != 'ALL'){
+ if ($requireds) {
+ foreach ($requireds as $required) {
+ foreach ($gradesforuser as $key => $gradeforuser) {
+ if ($gradeforuser->qtype == $required->qtype) {
+ $aggregated->rawgrade += ($gradeforuser->rawgrade / $qcreate->totalrequired);
+ $aggregated->userid = $gradeforuser->userid;
+ unset($gradesforuser[$key]);
+ $required->no--;
+ $counttotalrequired--;
+ if ($required->no == 0) {
+ // Go on to the next required type.
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ($counttotalrequired != 0) {
+ // Now grade the remainder of the questions.
+ if ($qcreate->allowed != 'ALL') {
$allowall = false;
$allowed = explode(',', $qcreate->allowed);
} else {
$allowall = true;
}
- foreach ($gradesforuser as $key => $gradeforuser){
- if ($allowall || in_array($gradeforuser->qtype, $allowed)){
+
+ foreach ($gradesforuser as $key => $gradeforuser) {
+ if ($allowall || in_array($gradeforuser->qtype, $allowed)) {
$aggregated->rawgrade += ($gradeforuser->rawgrade / $qcreate->totalrequired);
$aggregated->userid = $gradeforuser->userid;
$counttotalrequired--;
- if ($counttotalrequired == 0){
+ if ($counttotalrequired == 0) {
break;
}
}
}
}
+
$totalrequireddone = $qcreate->totalrequired - $counttotalrequired;
- $aggregated->rawgrade = $aggregated->rawgrade * ((100 - $qcreate->graderatio) / 100) +
- (($totalrequireddone*$qcreate->grade / $qcreate->totalrequired) * ($qcreate->graderatio/ 100));
+ $aggregated->rawgrade = $aggregated->rawgrade * ((100 - $qcreate->graderatio) / 100) + (
+ ($totalrequireddone * $qcreate->grade / $qcreate->totalrequired) * ($qcreate->graderatio / 100));
return $aggregated;
}
@@ -731,17 +1245,282 @@ function qcreate_grade_aggregate($gradesforuser, $qcreate){
* @param object qcreate the qcreate object
* @return array an array of objects
*/
-function qcreate_required_qtypes($qcreate){
- global $DB;
-
+function qcreate_required_qtypes($qcreate) {
+ global $DB;
+
static $requiredcache = array();
- if (!isset($requiredcache[$qcreate->id])){
- $requiredcache[$qcreate->id] = $DB->get_records('qcreate_required', array('qcreateid'=>$qcreate->id), 'qtype', 'qtype, no, id');
+ if (!isset($requiredcache[$qcreate->id])) {
+ $requiredcache[$qcreate->id] = $DB->get_records('qcreate_required',
+ array('qcreateid' => $qcreate->id), 'qtype', 'qtype, no, id');
}
return $requiredcache[$qcreate->id];
}
-function qcreate_time_status($qcreate){
+/**
+ * Extends the settings navigation with the qcreate settings
+ *
+ * This function is called when the context for the page is a qcreate module. This is not called by AJAX
+ * so it is safe to rely on the $PAGE.
+ *
+ * @param settings_navigation $settingsnav {@link settings_navigation}
+ * @param navigation_node $qcreatenode {@link navigation_node}
+ */
+function qcreate_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $qcreatenode=null) {
+ global $PAGE, $CFG;
+ require_once($CFG->libdir . '/questionlib.php');
+
+ $keys = $qcreatenode->get_children_key_list();
+ $beforekey = null;
+ $i = array_search('modedit', $keys);
+ if ($i === false and array_key_exists(0, $keys)) {
+ $beforekey = $keys[0];
+ } else if (array_key_exists($i + 1, $keys)) {
+ $beforekey = $keys[$i + 1];
+ }
+ if (has_capability('mod/qcreate:grade', $PAGE->cm->context)) {
+ $node = navigation_node::create(get_string('grading', 'qcreate'),
+ new moodle_url('/mod/qcreate/edit.php', array('cmid' => $PAGE->cm->id)),
+ navigation_node::TYPE_SETTING, null, 'mod_qcreate_edit');
+ $qcreatenode->add_node($node, $beforekey);
+ $node = navigation_node::create(get_string('exportgood', 'qcreate'),
+ new moodle_url('/mod/qcreate/exportgood.php', array('cmid' => $PAGE->cm->id)),
+ navigation_node::TYPE_SETTING, null, 'mod_qcreate_exportgood');
+ $qcreatenode->add_node($node, $beforekey);
+ question_extend_settings_navigation($settingsnav, $PAGE->cm->context)->trim_if_empty();
+ }
+}
+
+/**
+ * Add a get_coursemodule_info function in case any qcreate type wants to add 'extra' information
+ * for the course (see resource).
+ *
+ * Given a course_module object, this function returns any "extra" information that may be needed
+ * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php.
+ *
+ * @param stdClass $coursemodule The coursemodule object (record).
+ * @return cached_cm_info An object on information that the courses
+ * will know about (most noticeably, an icon).
+ */
+function qcreate_get_coursemodule_info($coursemodule) {
+ global $DB;
+
+ $dbparams = ['id' => $coursemodule->instance];
+ $fields = 'id, name, intro, introformat, completionquestions';
+ if (!$qcreate = $DB->get_record('qcreate', $dbparams, $fields)) {
+ return false;
+ }
+
+ $result = new cached_cm_info();
+ $result->name = $qcreate->name;
+
+ if ($coursemodule->showdescription) {
+ // Convert intro to html. Do not filter cached version, filters run at display time.
+ $result->content = format_module_intro('qcreate', $qcreate, $coursemodule->id, false);
+ }
+
+ // Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'.
+ if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) {
+ $result->customdata['customcompletionrules']['completionquestions'] = $qcreate->completionquestions;
+ }
+
+ return $result;
+}
+/**
+ * Callback which returns human-readable strings describing the active completion custom rules for the module instance.
+ *
+ * @param cm_info|stdClass $cm object with fields ->completion and ->customdata['customcompletionrules']
+ * @return array $descriptions the array of descriptions for the custom rules.
+ */
+function mod_qcreate_get_completion_active_rule_descriptions($cm) {
+ // Values will be present in cm_info, and we assume these are up to date.
+ if (empty($cm->customdata['customcompletionrules'])
+ || $cm->completion != COMPLETION_TRACKING_AUTOMATIC) {
+ return [];
+ }
+
+ $descriptions = [];
+ foreach ($cm->customdata['customcompletionrules'] as $key => $val) {
+ switch ($key) {
+ case 'completionquestions':
+ if (empty($val)) {
+ continue;
+ }
+ $descriptions[] = get_string('completionquestionsdesc', 'qcreate', $val);
+ break;
+ default:
+ break;
+ }
+ }
+ return $descriptions;
+}
+/**
+ * Serves the files from the qcreate file areas
+ *
+ * @package mod_qcreate
+ * @category files
+ *
+ * @param stdClass $course the course object
+ * @param stdClass $cm the course module object
+ * @param stdClass $context the qcreate's context
+ * @param string $filearea the name of the file area
+ * @param array $args extra arguments (itemid, path)
+ * @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
+ */
+function qcreate_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) {
+ global $DB, $CFG;
+ // Special case, sending a question bank export.
+ if ($filearea === 'export') {
+ list($context, $course, $cm) = get_context_info_array($context->id);
+ require_login($course, false, $cm);
+
+ require_once($CFG->dirroot . '/question/editlib.php');
+ $contexts = new question_edit_contexts($context);
+ // Check export capability.
+ $contexts->require_one_edit_tab_cap('export');
+ $categoryid = (int)array_shift($args);
+ $format = array_shift($args);
+ $cattofile = array_shift($args);
+ $contexttofile = array_shift($args);
+ $betterthangrade = (int)array_shift($args);
+ $namingother = (bool)array_shift($args);
+ $namingtext = array_shift($args);
+ $namingfirstname = (bool)array_shift($args);
+ $naminglastname = (bool)array_shift($args);
+ $namingusername = (bool)array_shift($args);
+ $namingactivityname = (bool)array_shift($args);
+ $namingtimecreated = (bool)array_shift($args);
+ $filename = array_shift($args);
+
+ if ($namingactivityname) {
+ $qcreate = $DB->get_record('qcreate', array('id' => $cm->instance));
+ }
+
+ // Load parent class for import/export.
+ require_once($CFG->dirroot . '/question/format.php');
+ require_once($CFG->dirroot . '/question/editlib.php');
+ require_once($CFG->dirroot . '/question/format/' . $format . '/format.php');
+
+ $classname = 'qformat_' . $format;
+ if (!class_exists($classname)) {
+ send_file_not_found();
+ }
+ $qformat = new $classname();
+
+ if (!$category = $DB->get_record('question_categories', array('id' => $categoryid))) {
+ send_file_not_found();
+ }
+
+ $qformat->setContexts($contexts->having_one_edit_tab_cap('export'));
+ $qformat->setCourse($course);
+
+ $questions = get_questions_category($category, true );
+ if ($betterthangrade > 0) {
+ // Filter questions by grade.
+ $qkeys = array();
+ foreach ($questions as $question) {
+ $qkeys[] = $question->id;
+ }
+ $questionlist = join($qkeys, ',');
+ $sql = 'SELECT questionid, grade FROM {qcreate_grades} '.
+ 'WHERE questionid IN ('.$questionlist.') AND grade >= '.$betterthangrade;
+ if ($goodquestions = $DB->get_records_sql($sql)) {
+ foreach ($questions as $zbkey => $question) {
+ if (!array_key_exists($question->id, $goodquestions)) {
+ unset($questions[$zbkey]);
+ }
+ }
+ } else {
+ send_file_not_found();
+ print_error('noquestionsabove', 'qcreate', $thispageurl->out());
+ }
+ }
+
+ if ($namingfirstname||$naminglastname||$namingusername
+ ||$namingother||$namingactivityname||$namingtimecreated) {
+ if ($namingfirstname||$naminglastname||$namingusername) {
+ $useridkeys = array();
+ foreach ($questions as $question) {
+ $useridkeys[] = $question->createdby;
+ }
+ $useridlist = join($useridkeys, ',');
+ if (!$users = $DB->get_records_select('user', "id IN ($useridlist)")) {
+ $users = array();
+ }
+ }
+ foreach ($questions as $question) {
+ $prefixes = array();
+ if ($namingother && !empty($namingtext)) {
+ $prefixes[] = $namingtext;
+ }
+ if ($namingfirstname) {
+ $prefixes[] = isset($users[$question->createdby]) ? $users[$question->createdby]->firstname : '';
+ }
+ if ($naminglastname) {
+ $prefixes[] = isset($users[$question->createdby]) ? $users[$question->createdby]->lastname : '';
+ }
+ if ($namingusername) {
+ $prefixes[] = isset($users[$question->createdby]) ? $users[$question->createdby]->username : '';
+ }
+ if ($namingactivityname) {
+ $prefixes[] = $qcreate->name;
+ }
+ if ($namingtimecreated) {
+ $prefixes[] = userdate($question->timecreated, get_string('strftimedatetimeshort'));
+ }
+ $prefixes[] = $question->name;
+ $question->name = join($prefixes, '-');
+ }
+ }
+ $qformat->setQuestions($questions);
+
+ if ($cattofile == 'withcategories') {
+ $qformat->setCattofile(true);
+ } else {
+ $qformat->setCattofile(false);
+ }
+
+ if ($contexttofile == 'withcontexts') {
+ $qformat->setContexttofile(true);
+ } else {
+ $qformat->setContexttofile(false);
+ }
+
+ if (!$qformat->exportpreprocess()) {
+ send_file_not_found();
+ print_error('exporterror', 'question', $thispageurl->out());
+ }
+
+ // Export data to moodle file pool.
+ if (!$content = $qformat->exportprocess()) {
+ send_file_not_found();
+ }
+
+ send_file($content, $filename, 0, 0, true, true, $qformat->mime_type());
+ }
+
+ if ($context->contextlevel != CONTEXT_MODULE) {
+ send_file_not_found();
+ }
+
+ require_login($course, true, $cm);
+
+ send_file_not_found();
+}
+
+function qcreate_question_pluginfile($course, $context, $component,
+ $filearea, $qubaid, $slot, $args, $forcedownload, array $options=array()) {
+ $fs = get_file_storage();
+ $relativepath = implode('/', $args);
+ $fullpath = "/$context->id/$component/$filearea/$relativepath";
+ if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+ send_file_not_found();
+ }
+
+ send_stored_file($file, 0, 0, $forcedownload, $options);
+}
+
+function qcreate_time_status($qcreate) {
$timenow = time();
$available = ($qcreate->timeopen < $timenow &&
($timenow < $qcreate->timeclose || !$qcreate->timeclose));
@@ -751,19 +1530,19 @@ function qcreate_time_status($qcreate){
$string = get_string("activityclosed", "qcreate");
}
$string = "$string";
- if (!$qcreate->timeopen && !$qcreate->timeclose){
+ if (!$qcreate->timeopen && !$qcreate->timeclose) {
return $string.' '.get_string('timenolimit', 'qcreate');
}
- if ($qcreate->timeopen){
+ if ($qcreate->timeopen) {
if ($timenow < $qcreate->timeopen) {
$string .= ' '.get_string("timewillopen", "qcreate", userdate($qcreate->timeopen));
} else {
- $string .= ' '.get_string("timeopened", "qcreate", userdate($qcreate->timeclose));
+ $string .= ' '.get_string("timeopened", "qcreate", userdate($qcreate->timeopen));
}
}
- if ($qcreate->timeclose){
+ if ($qcreate->timeclose) {
if ($timenow < $qcreate->timeclose) {
- $string .= ' '.get_string("timewillclose", "qcreate", userdate($qcreate->timeopen));
+ $string .= ' '.get_string("timewillclose", "qcreate", userdate($qcreate->timeclose));
} else {
$string .= ' '.get_string("timeclosed", "qcreate", userdate($qcreate->timeclose));
}
@@ -771,4 +1550,248 @@ function qcreate_time_status($qcreate){
return $string;
}
-?>
+/**
+ * Check if the module has any update that affects the current user since a given time.
+ *
+ * @param cm_info $cm course module data
+ * @param int $from the time to check updates from
+ * @param array $filter if we need to check only specific updates
+ * @return stdClass an object with the different type of areas indicating if they were updated or not
+ * @since Moodle 3.2
+ */
+function qcreate_check_updates_since(cm_info $cm, $from, $filter = array()) {
+ global $DB, $USER, $CFG;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ $updates = course_check_module_updates_since($cm, $from, array(), $filter);
+
+ // Check if questions have been modified or added.
+ $context = $cm->context;
+ $updates->questions = (object) array('updated' => false);
+ $qcreateobj = new qcreate($context, null, null);
+ $instance = $qcreateobj->get_instance();
+
+ list($whereqtype, $params) = $qcreateobj->get_allowed_qtypes_where();
+ $params['time1'] = $from;
+ $params['time2'] = $from;
+ if (has_capability('mod/qcreate:grade', $qcreateobj->get_context())) {
+ // Teacher should see questions from all users.
+ $whereuser = '(q.timemodified > :time1 OR q.timecreated > :time2) AND ';
+ } else {
+ $whereuser = 'q.createdby = :userid AND (q.timemodified > :time1 OR q.timecreated > :time2) AND ';
+ $params['userid'] = $USER->id;
+ }
+ $params['contextid'] = $qcreateobj->get_context()->id;
+
+ $questionsql = "SELECT q.*, c.id as cid, c.name as cname, g.grade, g.gradecomment, g.id as gid
+ FROM {question_categories} c, {question} q
+ LEFT JOIN {qcreate_grades} g ON q.id = g.questionid
+ AND g.qcreateid = {$instance->id}
+ WHERE $whereqtype $whereuser c.contextid = :contextid AND c.id = q.category AND q.hidden='0' AND q.parent='0'";
+ $questions = $DB->get_records_sql($questionsql, $params);
+ if (!empty($questions)) {
+ $updates->questions->updated = true;
+ $updates->questions->itemids = array_keys($questions);
+ }
+
+ // Check for new grades.
+ // TODO : what should see teachers here ?
+ $updates->grades = (object) array('updated' => false);
+ $params['userid'] = $USER->id;
+ $params['time1'] = $from;
+ $params['contextid'] = $context->id;
+ $sql = "SELECT g.id, g.grade AS rawgrade, g.gradecomment AS feedback,
+ g.teacher AS usermodified, q.qtype AS qtype
+ FROM {user} u, {question_categories} qc, {question} q
+ LEFT JOIN {qcreate_grades} g ON g.questionid = q.id
+ WHERE u.id = :userid AND u.id = q.createdby AND qc.id = q.category AND qc.contextid= :contextid
+ AND timemarked > :time1
+ ORDER BY rawgrade DESC";
+ $grades = $DB->get_records_sql($sql, $params);
+ if (!empty($grades)) {
+ $updates->grades->updated = true;
+ $updates->grades->itemids = array_keys($grades);
+ }
+
+ return $updates;
+}
+
+/**
+ * This function receives a calendar event and returns the action associated with it, or null if there is none.
+ *
+ * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event
+ * is not displayed on the block.
+ *
+ * @param calendar_event $event
+ * @param \core_calendar\action_factory $factory
+ * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
+ * @return \core_calendar\local\event\entities\action_interface|null
+ */
+function mod_qcreate_core_calendar_provide_event_action(calendar_event $event,
+ \core_calendar\action_factory $factory,
+ $userid = 0) {
+
+ global $CFG, $USER;
+
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ if (empty($userid)) {
+ $userid = $USER->id;
+ }
+
+ $cm = get_fast_modinfo($event->courseid, $userid)->instances['qcreate'][$event->instance];
+ $context = context_module::instance($cm->id);
+ $qcreateobj = new qcreate($context, $cm, null);
+ $instance = $qcreateobj->get_instance();
+
+ // Check they have capabilities allowing them to view the qcreate.
+ if (!has_any_capability(array('mod/qcreate:view', 'mod/qcreate:submit'),
+ $qcreateobj->get_context(), $userid)) {
+ return null;
+ }
+
+ // Check if qcreate is closed, if so don't display it.
+ if (!empty($instance->timeclose) && $instance->timeclose <= time()) {
+ return null;
+ }
+
+ $name = get_string('attemptqcreatenow', 'qcreate');
+ $url = new \moodle_url('/mod/qcreate/view.php', [
+ 'id' => $cm->id
+ ]);
+ $itemcount = 1;
+ $actionable = true;
+
+ // Check if the qcreate is not currently actionable.
+ if (!empty($instance->timeopen) && $instance->timeopen > time()) {
+ $actionable = false;
+ }
+
+ return $factory->create_instance(
+ $name,
+ $url,
+ $itemcount,
+ $actionable
+ );
+}
+
+/**
+ * This function calculates the minimum and maximum cutoff values for the timestart of
+ * the given event.
+ *
+ * It will return an array with two values, the first being the minimum cutoff value and
+ * the second being the maximum cutoff value. Either or both values can be null, which
+ * indicates there is no minimum or maximum, respectively.
+ *
+ * If a cutoff is required then the function must return an array containing the cutoff
+ * timestamp and error string to display to the user if the cutoff value is violated.
+ *
+ * A minimum and maximum cutoff return value will look like:
+ * [
+ * [1505704373, 'The due date must be after the sbumission start date'],
+ * [1506741172, 'The due date must be before the cutoff date']
+ * ]
+ *
+ * If the event does not have a valid timestart range then [false, false] will
+ * be returned.
+ *
+ * @param calendar_event $event The calendar event to get the time range for
+ * @param stdClass $instance The module instance to get the range from
+ * @return array
+ */
+function mod_qcreate_core_calendar_get_valid_event_timestart_range(\calendar_event $event, \stdClass $qcreate) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+
+ $mindate = null;
+ $maxdate = null;
+
+ if ($event->eventtype == QCREATE_EVENT_TYPE_OPEN) {
+ if (!empty($qcreate->timeclose)) {
+ $maxdate = [
+ $qcreate->timeclose,
+ get_string('openafterclose', 'qcreate')
+ ];
+ }
+ } else if ($event->eventtype == QCREATE_EVENT_TYPE_CLOSE) {
+ if (!empty($qcreate->timeopen)) {
+ $mindate = [
+ $qcreate->timeopen,
+ get_string('closebeforeopen', 'qcreate')
+ ];
+ }
+ }
+
+ return [$mindate, $maxdate];
+}
+/**
+ * This function will update the qcreate module according to the
+ * event that has been modified.
+ *
+ * @throws \moodle_exception
+ * @param \calendar_event $event
+ * @param stdClass $instance The module instance to get the range from
+ */
+function mod_qcreate_core_calendar_event_timestart_updated(\calendar_event $event, \stdClass $qcreate) {
+ global $CFG, $DB;
+
+ require_once($CFG->dirroot . '/mod/qcreate/locallib.php');
+ if (!in_array($event->eventtype, [QCREATE_EVENT_TYPE_OPEN, QCREATE_EVENT_TYPE_CLOSE])) {
+ // This isn't an event that we care about so we can ignore it.
+ return;
+ }
+
+ $courseid = $event->courseid;
+ $modulename = $event->modulename;
+ $instanceid = $event->instance;
+ $modified = false;
+ $closedatechanged = false;
+
+ // Something weird going on. The event is for a different module so
+ // we should ignore it.
+ if (empty($event->instance) || $event->modulename != 'qcreate') {
+ return;
+ }
+
+ if ($qcreate->id != $instanceid) {
+ // The provided qcreate instance doesn't match the event so
+ // there is nothing to do here.
+ return;
+ }
+
+ $coursemodule = get_fast_modinfo($courseid)->instances[$modulename][$instanceid];
+ $context = context_module::instance($coursemodule->id);
+
+ // The user does not have the capability to modify this activity.
+ if (!has_capability('moodle/course:manageactivities', $context)) {
+ return;
+ }
+
+ if ($event->eventtype == QCREATE_EVENT_TYPE_OPEN) {
+ // If the event is for the qcreate activity opening then we should
+ // set the start time of the qcreate activity to be the new start
+ // time of the event.
+ if ($qcreate->timeopen != $event->timestart) {
+ $qcreate->timeopen = $event->timestart;
+ $modified = true;
+ }
+ } else if ($event->eventtype == QCREATE_EVENT_TYPE_CLOSE) {
+ // If the event is for the qcreate activity closing then we should
+ // set the end time of the qcreate activity to be the new start
+ // time of the event.
+ if ($qcreate->timeclose != $event->timestart) {
+ $qcreate->timeclose = $event->timestart;
+ $modified = true;
+ $closedatechanged = true;
+ }
+ }
+
+ if ($modified) {
+ $qcreate->timemodified = time();
+ $DB->update_record('qcreate', $qcreate);
+
+ qcreate_update_events($qcreate);
+ $event = \core\event\course_module_updated::create_from_cm($coursemodule, $context);
+ $event->trigger();
+ }
+}
diff --git a/locallib.php b/locallib.php
index 9dda47d..9b23b7e 100644
--- a/locallib.php
+++ b/locallib.php
@@ -1,381 +1,1848 @@
libdir.'/questionlib.php');
-require_once($CFG->libdir.'/gradelib.php');
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->libdir . '/gradelib.php');
+require_once($CFG->dirroot . '/mod/qcreate/renderable.php');
/**
- * Function that can be used in various parts of the quiz code.
- * @param object $quiz
- * @param integer $cmid
- * @param object $question
- * @param string $returnurl url to return to after action is done.
- * @return string html for a number of icons linked to action pages for a
- * question - preview and edit / view icons depending on user capabilities.
+ * Standard base class for mod_qcreate.
+ *
+ * @package mod_qcreate
+ * @copyright 2014 Jean-Michel Vedrine
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-function qcreate_question_action_icons($cmid, $question, $returnurl){
- global $CFG, $COURSE, $OUTPUT;
- static $stredit = null;
- static $strview = null;
- static $strpreview = null;
- static $strdelete = null;
- if ($stredit === null){
- $stredit = get_string('edit');
- $strview = get_string('view');
- $strpreview = get_string('preview', 'quiz');
- $strdelete = get_string("delete");
- }
- $html ='';
- if (($question->qtype != 'random')){
- if (question_has_capability_on($question, 'use', $question->cid)){
- $url = '/question/preview.php?id=' . $question->id . '&courseid=' .$COURSE->id;
- $action = new popup_action('click', $url, 'questionpreview', question_preview_popup_params());
- $html .= $OUTPUT->action_link($url, "pix_url('t/preview')."\" class=\"iconsmall\" alt=\"$strpreview\" />", $action, array('title' => $strpreview));
- }
- }
- $questionparams = array('returnurl' => $returnurl->out_as_local_url(), 'cmid'=>$cmid, 'id' => $question->id);
- $questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
- if (question_has_capability_on($question, 'edit', $question->cid) ||
- question_has_capability_on($question, 'move', $question->cid)) {
- $html .= "out()."\">" .
- "pix_url('t/edit')."\" class=\"iconsmall\" alt=\"$stredit\" />" .
- "";
- } elseif (question_has_capability_on($question, 'view', $question->cid)){
- $html .= "out(false, array('id'=>$question->id))."\">" .
- "pix_url('i/info')."\" alt=\"$strview\" />" .
- "";
- }
- if (question_has_capability_on($question, 'edit', $question->cid)) {
- $html .= "id\">" .
- "pix_url('t/delete')."\" alt=\"$strdelete\" />";
+class qcreate {
+
+ /** @var stdClass the qcreate record that contains the global settings for this qcreate instance */
+ private $instance;
+
+ /** @var stdClass the grade_item record for this qcreate instance's primary grade item. */
+ private $gradeitem;
+
+ /** @var context the context of the course module for this qcreate instance
+ * (or just the course if we are creating a new one)
+ */
+ private $context;
+
+ /** @var stdClass the course this qcreate instance belongs to */
+ private $course;
+
+ /** @var stdClass the admin config for all qcreate instances */
+ private $adminconfig;
+
+ /** @var qcreate_renderer the custom renderer for this module */
+ private $output;
+
+ /** @var stdClass the course module for this qcreate instance */
+ private $coursemodule;
+
+ /** @var array cache for things like the coursemodule name or the scale menu -
+ * only lives for a single request.
+ */
+ private $cache;
+
+ /** @var string modulename prevents excessive calls to get_string */
+ private static $modulename = null;
+
+ /** @var string modulenameplural prevents excessive calls to get_string */
+ private static $modulenameplural = null;
+
+ /**
+ * Constructor for the base qcreate class.
+ *
+ * @param mixed $coursemodulecontext context|null the course module context
+ * (or the course context if the coursemodule has not been
+ * created yet).
+ * @param mixed $coursemodule the current course module if it was already loaded,
+ * otherwise this class will load one from the context as required.
+ * @param mixed $course the current course if it was already loaded,
+ * otherwise this class will load one from the context as required.
+ */
+ public function __construct($coursemodulecontext, $coursemodule, $course) {
+ $this->context = $coursemodulecontext;
+ $this->coursemodule = $coursemodule;
+ $this->course = $course;
+
+ // Temporary cache only lives for a single request - used to reduce db lookups.
+ $this->cache = array();
+ }
+
+ /**
+ * Set the submitted form data.
+ *
+ * @param stdClass $data The form data (instance)
+ */
+ public function set_instance(stdClass $data) {
+ $this->instance = $data;
}
- return $html;
-}
-function qcreate_required_q_list($requireds, $cat, $thisurl, $qcreate, $cm, $modulecontext){
- global $CFG, $DB, $USER, $COURSE, $OUTPUT;
+ /**
+ * Set the context.
+ *
+ * @param context $context The new context
+ */
+ public function set_context(context $context) {
+ $this->context = $context;
+ }
- $qtypemenu = question_type_menu();
+ /**
+ * Set the course data.
+ *
+ * @param stdClass $course The course data
+ */
+ public function set_course(stdClass $course) {
+ $this->course = $course;
+ }
- if ($qcreate->graderatio == 100){
- $showmanualgrades = false;
- } else {
- $showmanualgrades = true;
- }
-
- $questionurl = new moodle_url($CFG->wwwroot.'/question/question.php');
- $questionurl->params(array('cmid'=>$cm->id, 'returnurl'=>$thisurl->out_as_local_url()));
-
-
- $questionsql = "SELECT q.*, c.id as cid, c.name as cname, g.grade, g.gradecomment, g.id as gid
- FROM {$CFG->prefix}question_categories c, {$CFG->prefix}question q
- LEFT JOIN {$CFG->prefix}qcreate_grades g ON q.id = g.questionid
- AND g.qcreateid = {$qcreate->id}
- WHERE c.contextid = {$modulecontext->id} AND c.id = q.category AND q.hidden='0' AND q.parent='0'
- AND q.createdby=".$USER->id;
- if ($qcreate->allowed != 'ALL'){
- //wrap question type names in inverted commas.
- $allowedlistparts = explode(',', $qcreate->allowed);
- $allowedlist = ('\''.join($allowedlistparts, '\', \'').'\'');
- $questionsql .= " AND q.qtype IN ($allowedlist)";
- }
-
- $questions = $DB->get_records_sql($questionsql);
- $activityopen = qcreate_activity_open($qcreate);
-
- echo $OUTPUT->heading(get_string('requiredquestions', 'qcreate'));
- $qtyperequired = 0;
- $qtypedone = 0;
- $qtypeqs = qcreate_questions_of_type($questions);
- $content = "\n\t\t
";
- if ($requireds){
- $i = 1;
- $grammarised = qcreate_proper_grammar($requireds);
- $punctuated = qcreate_proper_punctuation($grammarised);
- foreach ($requireds as $qtype => $required){
- $qtyperequired += $required->no;
- if (!empty($qtypeqs[$qtype])){
- $requireds[$qtype]->done = (count($qtypeqs[$qtype]) > $required->no)
- ? $required->no:count($qtypeqs[$qtype]);
- $requireds[$qtype]->stillrequiredno = $required->no - $requireds[$qtype]->done;
- //sub list of questions done of each question type
- $questionlist = "\n\t\t\t\t
";
+ /**
+ * Update the gradebook information for this qcreate activity.
+ *
+ * @param bool $reset If true, will reset all grades in the gradbook for this qcreate activity
+ * @param int $coursemoduleid This is required because it might not exist in the database yet
+ * @return bool
+ */
+ public function update_gradebook($reset, $coursemoduleid) {
+ global $CFG;
- if ($requireds[$qtype]->stillrequiredno > 0){
- $requirementslist .= "\n\t\t\t\t\t\t\t