2.7.1 Addon Help

2.7.1 Addon Help

by Wendi Daniels -
Number of replies: 35

I added a plugin called "AskQuestion", but the maker will not answer basic questions and help me out, so I am asking you. It is a plugin that asks questions from the "user profile fields". It is set to ask only "text input" questions. I am trying to tweak it so that it asks " drop menu" and "date/time" questions. Following is what it originally was, and here is what I have.


original...

******************************************************************************************

<?php

/**
 * Ask question form
 */
defined('MOODLE_INTERNAL') || die;

require_once($CFG->libdir . '/formslib.php');

class askquestion_edit_form extends moodleform {  

    function definition() {
        global $USER, $CFG, $DB;

        $mform = $this->_form;

        $profile_field_category_id = get_config('local_askquestion', 'security_question_profile_field_category_id');

        if (isset($_SESSION['profileshortname'])) {
            $profileshortname = $_SESSION['profileshortname'];
        } else {
            $profile_fields = $DB->get_records('user_info_field', array('categoryid' => $profile_field_category_id));
            $extraprofilefields = array();

            if ($profile_fields) {
                foreach ($profile_fields as $profile_field) {
                    $extraprofilefields[] = $profile_field->shortname;
                }
                $rand_key = array_rand($extraprofilefields, 1);
                $profileshortname = $extraprofilefields[$rand_key];
                $_SESSION['profileshortname'] = $profileshortname;
            }
        }

        if (!$DB->record_exists('user_info_field', array('shortname' => $profileshortname))) {
            $displayquestion = false;
        } else {
            $profileinfo = $DB->get_record('user_info_field', array('shortname' => $profileshortname));
            $displayquestion = true;
            $securityquestiontext = $profileinfo->name;
        }

        if ($displayquestion) {
            $attributes = array('size' => '40');
            $mform->addElement('text', 'securityquestion', $securityquestiontext, $attributes);
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');
        } else {
            $mform->addElement('static', 'staticinfo', '', get_string('noquestiontext', 'local_askquestion'));
        }

    }

    // Custom validation should be added here
    function validation($data, $files) {
        global $USER, $DB;
        $errors = array();
        $errors = parent::validation($data, $files);

        $profilefieldshortname = $_SESSION['profileshortname'];
        $profilefieldinfo = $DB->get_record('user_info_field', array('shortname' => $profilefieldshortname));

        if ($DB->record_exists('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id))) {
            $datarow = $DB->get_record('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id));

            if ($data['securityquestion'] !== $datarow->data) {
                if (isset($_SESSION['how_many_times_failed_in_answering'])) {
                    $_SESSION['how_many_times_failed_in_answering'] = $_SESSION['how_many_times_failed_in_answering'] + 1;
                } else {
                    $_SESSION['how_many_times_failed_in_answering'] = 1;
                }

                $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');

                if ($_SESSION['how_many_times_failed_in_answering'] == $max_attempt_allowed) {
                    //invalidate user or suspend user
                    $errors['securityquestion'] = get_string('nomore_attempt', 'local_askquestion');
                    $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                    $userobj = new stdClass();
                    $userobj->id = $USER->id;
                    $userobj->suspended = 1;
                    $return = $DB->update_record('user', $userobj);
                    if ($return) {
                        send_account_suspend_email_to_user();
                    }
                    redirect($logouturl);
                } else if ($_SESSION['how_many_times_failed_in_answering'] == ($max_attempt_allowed - 1)) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsgfinal', 'local_askquestion', $remaning_attempt);
                } else if ($_SESSION['how_many_times_failed_in_answering'] < $max_attempt_allowed) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsg', 'local_askquestion', $remaning_attempt);
                }
            }
        } else {
            $errors['securityquestion'] = get_string('incomplete_profiledata', 'local_askquestion');
        }
        return $errors;
    }

}

****************************************************************************************


my hackings (not yet accurate)


******************************************************************************************

<?php

/**
 * Ask question form
 */
defined('MOODLE_INTERNAL') || die;

require_once($CFG->libdir . '/formslib.php');

class askquestion_edit_form extends moodleform {  

    function definition() {
        global $USER, $CFG, $DB;

        $mform = $this->_form;

        $profile_field_category_id = get_config('local_askquestion', 'security_question_profile_field_category_id');

        if (isset($_SESSION['profileshortname'])) {
            $profileshortname = $_SESSION['profileshortname'];
        } else {
            $profile_fields = $DB->get_records('user_info_field', array('categoryid' => $profile_field_category_id));
            $extraprofilefields = array();

            if ($profile_fields) {
                foreach ($profile_fields as $profile_field) {
                    $extraprofilefields[] = $profile_field->shortname;
                }
                $rand_key = array_rand($extraprofilefields, 1);
                $profileshortname = $extraprofilefields[$rand_key];
                $_SESSION['profileshortname'] = $profileshortname;
            }
        }

        if (!$DB->record_exists('user_info_field', array('shortname' => $profileshortname))) {
            $displayquestion = false;
        } else {
            $profileinfo = $DB->get_record('user_info_field', array('shortname' => $profileshortname));
            $displayquestion = true;
            $securityquestiontext = $profileinfo->name;
        }
  if ($displayquestion) {
            $attributes = array('size' => '40');
            $mform->addElement('datetime', 'securityquestion', $securityquestiontext, $attributes);
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');
             
            $mform->addElement('menu', 'securityquestion', $securityquestiontext, $attributes);
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');
       
            $mform->addElement('text', 'securityquestion', $securityquestiontext, $attributes);
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');

        }
    }
    }

    // Custom validation should be added here
    function validation($data, $files) {
        global $USER, $DB;
        $errors = array();
        $errors = parent::validation($data, $files);

        $profilefieldshortname = $_SESSION['profileshortname'];
        $profilefieldinfo = $DB->get_record('user_info_field', array('shortname' => $profilefieldshortname));

        if ($DB->record_exists('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id))) {
            $datarow = $DB->get_record('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id));

            if ($data['securityquestion'] !== $datarow->data) {
                if (isset($_SESSION['how_many_times_failed_in_answering'])) {
                    $_SESSION['how_many_times_failed_in_answering'] = $_SESSION['how_many_times_failed_in_answering'] + 1;
                } else {
                    $_SESSION['how_many_times_failed_in_answering'] = 1;
                }

                $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');

                if ($_SESSION['how_many_times_failed_in_answering'] == $max_attempt_allowed) {
                    //invalidate user or suspend user
                    $errors['securityquestion'] = get_string('nomore_attempt', 'local_askquestion');
                    $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                    $userobj = new stdClass();
                    $userobj->id = $USER->id;
                    $userobj->suspended = 1;
                    $return = $DB->update_record('user', $userobj);
                    if ($return) {
                        send_account_suspend_email_to_user();
                    }
                    redirect($logouturl);
                } else if ($_SESSION['how_many_times_failed_in_answering'] == ($max_attempt_allowed - 1)) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsgfinal', 'local_askquestion', $remaning_attempt);
                } else if ($_SESSION['how_many_times_failed_in_answering'] < $max_attempt_allowed) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsg', 'local_askquestion', $remaning_attempt);
                }
            }
        } else {
            $errors['securityquestion'] = get_string('incomplete_profiledata', 'local_askquestion');
        }
        return $errors;
    }

Average of ratings: -
In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Seriously, does anyone know how to make this code call for the items in user profile fields that would be called "menu" and "datetime"?


I would go back directly to Fernando Acedo, but he made it clear that he will not help me, and his code was faulty, as were his instructions. I had to have someone hack the code for nearly 2 months just to get it to work right. Therefore, I would appreciate it if you would not include in your reply "ask the maker of the addon".

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

This would be the index file, which it calls from.  I simply do not know enough about code to know what to do with this. This program would be so much easier if it were to use the drop menu and the date fields from "user profile fields", as they could enter the information exactly from a drop screen, because if they misspell, or if they somehow enter is "wrong", then it will register as a false answer. It would be great if Fernando Acedo would tell me, but he will not. All I get is silence. I am frustrated...


******************************************************************************



<?php

require_once('../../config.php');
require_once('edit_form.php');
require_once('lib.php');
$site = get_site();
global $DB, $USER, $PAGE;

require_login();

//if already respond to question redirect to site frontpage

$PAGE->set_context(context_system::instance());
$data = array();
$url = new moodle_url('/course/view.php?id=2'); //this takes user back to course page
$PAGE->set_url('/local/askquestion/index.php');

if (isloggedin() && !is_siteadmin($USER->id) && !isguestuser($USER->id)) {
    //if already respond to question redirect to site frontpage
//    if ($DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1))) {
//        redirect($url);
//    }

    $editform = new askquestion_edit_form(NULL);

    if ($fromform = $editform->get_data()) {
        $fromdata = (array) $fromform;
        if (!$errors = $editform->validation($fromdata, null)) {

            // insert a vlaue in the table so that user will not asked a question again if he or she come on this page
            $record = new stdClass();
            $record->userid = $USER->id;
            $record->validated = 1;
            $return = $DB->insert_record('local_askquestion', $record, true);
            redirect($url);
        } else {
            $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');
            if ($_SESSION['how_many_times_failed_in_answering'] >= $max_attempt_allowed) {
                $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                $userobj = new stdClass();
                $userobj->id = $USER->id;
                $userobj->suspended = 1;
                //$return = $DB->update_record('user', $obj);
                redirect($logouturl);
            }
        }
    } else {
        $PAGE->set_pagelayout('base');
        $PAGE->set_url('/local/askquestion/index.php');
        $PAGE->set_context(context_system::instance());

        $heading = get_string('security_ques', 'local_askquestion');
        $title = "$site->shortname: " . $heading;

        $PAGE->navbar->add($heading);
        $PAGE->set_title($title);
        $PAGE->set_heading($heading);

        echo $OUTPUT->header();
        echo $OUTPUT->heading($heading);
        $editform->display();
        echo $OUTPUT->footer();
    }
}
?>

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Is there no one out there who understands how to adjust this code to get it to call the dropdown menu and the date/time questions in the user profile fields?

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I suspect there's quite a lot of people on holiday at the moment, so not likely to be geared up to answering complex questions in the Moodle forms (complex, as you've copied quite a chunk of code into the post and it's not quite clear which bit you are trying to adjust).

Maybe it would be clearer if you attached the relevant files, rather than copying and pasting + explained step-by-step what you currently see (a screenshot would help greatly at this point) and what it is you want to see.

The code for displaying user profile drop-down fields is inside /user/profile/field/menu ( https://github.com/moodle/moodle/tree/master/user/profile/field/menu ) - but that probably needs some modification to make it work how you want it to.

Average of ratings: Useful (2)
In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

Thanks! Yes, it does need some modification, and I don't know enough about code to know what to do with it, and I am desperate for some help. The problem is that it is set to text input only, and it is so easy for a student to mistype an answer, so I want as many questions as possible to be from a scroll of options. I am almost sure the coding is in the files askquestion/local/askquestion/index   and/or   askquestion/local/askquestion/edit_form. I think on the install we had to rearrange the files so that all the files under the second "askquestion" folder was moved up one level. Also, when I try to save the file as a zip, it all gets rearranged. The "index" and "edit_form" files are pasted in above.


I work all the time it seems, so I should have realized others are on holiday and may not answer immediately.  Thank you.


Here is the plugin (attached). It is GNU-public, and the maker said he did not care if I posted it publicly. There are some errors in the instructions, and the organization  of the file itself. It was changed in my ftp files, but not in this pack. I don't seem to be able to open the zip file after it is attached, so I would appreciate it if the rest of you would let me know if you can see it or not. I will attaché each file if I need to. The edit_form and index files are attached, and also pasted above.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I can see what the code is doing.

You will need to make some changes to the file edit_form.php to display different types of form elements, depending on the type of the user profile field (it is the section inside 'if ($displayquestion) {' that you need to change).

The code to correctly display profile fields based on their type can be found in user/profile/lib.php, function profile_definition (look for the section 'foreach ($fields as $field)'). I don't know if this code will work directly as you want it, but it should be possible to make it work with only minor changes.

If your programming ability is not up to integrating the code yourself, then you could try finding a developer to help you via http://moodle.com/partners or http://moodle.org/jobs


In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

I'm almost there, and I think I'm going to try this on my own, as a few developers have harmed my site, and a few have been excellent.


I am trying right now to integrate the dropdown menu questions, and I am almost there. The scroll box shows up, but the options are not there. I have altered the plugin's "edit_form" file, and this is the code that seems to alter the frontend. Here is what I have so far:


 }

        if (!$DB->record_exists('user_info_field', array('shortname' => $profileshortname))) {
            $displayquestion = false;
        } else {
            $profileinfo = $DB->get_record('user_info_field', array('shortname' => $profileshortname));
            $displayquestion = true;
            $securityquestiontext = $profileinfo->name;
        }



        if ($displayquestion) {
            $attributes = array('size' => '40');
            $mform->addElement('textarea', 'securityquestion', $securityquestiontext, $attributes, get_string('profilemenuoptions', 'admin'), array('rows' => 6, 'cols' => 40));
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion', 'profiledataoptions'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');
        } else {
            $mform->addElement('static', 'staticinfo', '', get_string('noquestiontext', 'local_askquestion'));
        }
    }



Do you see what is missing that would call the code from the database? The database file is "user_info_field", and it is in the code, but it is not being called, for whatever reason. All of my alterations are in the second section; I altered nothing in the first section.


Any help is appreciated.





In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

I have tried a number of combinations of the lib file on the plugin, and I cannot figure it out. Here is the code you are suggesting is important in this:


********************************************************

function profile_definition($mform, $userid = 0) {
    global $CFG, $DB;

    // If user is "admin" fields are displayed regardless.
    $update = has_capability('moodle/user:update', context_system::instance());

    if ($categories = $DB->get_records('user_info_category', null, 'sortorder ASC')) {
        foreach ($categories as $category) {
            if ($fields = $DB->get_records('user_info_field', array('categoryid' => $category->id), 'sortorder ASC')) {

                // Check first if *any* fields will be displayed.
                $display = false;
                foreach ($fields as $field) {
                    if ($field->visible != PROFILE_VISIBLE_NONE) {
                        $display = true;

                    }
                }

                // Display the header and the fields.
                if ($display or $update) {
                    $mform->addElement('header', 'category_'.$category->id, format_string($category->name));
                    foreach ($fields as $field) {
                        require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
                        $newfield = 'profile_field_'.$field->datatype;
                        $formfield = new $newfield($field->id, $userid);
                        $formfield->edit_field($mform);

                    }

*******************************************************************************


and I cannot see how much of it to put where...any ideas? I have changed ($field as $fields) to ($profile_fields as $profile_field). Here is the page that needs to be hacked so that the menu options in the dropdown menu show:


************************************************************************************

<?php

/**
 * Ask question form
 */
defined('MOODLE_INTERNAL') || die;

require_once($CFG->libdir . '/formslib.php');

class askquestion_edit_form extends moodleform {  

    function definition() {
        global $USER, $CFG, $DB;

        $mform = $this->_form;

        $profile_field_category_id = get_config('local_askquestion', 'security_question_profile_field_category_id');

        if (isset($_SESSION['profileshortname'])) {
            $profileshortname = $_SESSION['profileshortname'];
        } else {
            $profile_fields = $DB->get_records('user_info_field', array('categoryid' => $profile_field_category_id));
            $extraprofilefields = array();

            if ($profile_fields) {
                foreach ($profile_fields as $profile_field) {
                    $extraprofilefields[] = $profile_field->shortname;
                }
                $rand_key = array_rand($extraprofilefields, 1);
                $profileshortname = $extraprofilefields[$rand_key];
                $_SESSION['profileshortname'] = $profileshortname;
            }
        }

        if (!$DB->record_exists('user_info_field', array('shortname' => $profileshortname))) {
            $displayquestion = false;
        } else {
            $profileinfo = $DB->get_record('user_info_field', array('shortname' => $profileshortname));
            $displayquestion = true;
            $securityquestiontext = $profileinfo->name;
        }
       
        if ($displayquestion) {
            $attributes = array('size' => '40');
            $mform->addElement('textarea', 'securityquestion', $securityquestiontext, $attributes, get_string('profilemenuoptions', 'admin'), array('rows' => 6, 'cols' => 40));
            $mform->addRule('securityquestion', get_string('missingquestionanswer', 'local_askquestion', 'profiledataoptions'), 'required', null, 'client', false, false);
            $mform->setType('securityquestion', PARAM_TEXT);
            $this->add_action_buttons(false, 'Submit');
        } else {
            $mform->addElement('static', 'staticinfo', '', get_string('noquestiontext', 'local_askquestion'));
        }

    }

    // Custom validation should be added here
    function validation($data, $files) {
        global $USER, $DB;
        $errors = array();
        $errors = parent::validation($data, $files);

        $profilefieldshortname = $_SESSION['profileshortname'];
        $profilefieldinfo = $DB->get_record('user_info_field', array('shortname' => $profilefieldshortname));

        if ($DB->record_exists('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id))) {
            $datarow = $DB->get_record('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id));

            if ($data['securityquestion'] !== $datarow->data) {
                if (isset($_SESSION['how_many_times_failed_in_answering'])) {
                    $_SESSION['how_many_times_failed_in_answering'] = $_SESSION['how_many_times_failed_in_answering'] + 1;
                } else {
                    $_SESSION['how_many_times_failed_in_answering'] = 1;
                }

                $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');

                if ($_SESSION['how_many_times_failed_in_answering'] == $max_attempt_allowed) {
                    //invalidate user or suspend user
                    $errors['securityquestion'] = get_string('nomore_attempt', 'local_askquestion');
                    $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                    $userobj = new stdClass();
                    $userobj->id = $USER->id;
                    $userobj->suspended = 1;
                    $return = $DB->update_record('user', $userobj);
                    if ($return) {
                        send_account_suspend_email_to_user();
                    }
                    redirect($logouturl);
                } else if ($_SESSION['how_many_times_failed_in_answering'] == ($max_attempt_allowed - 1)) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsgfinal', 'local_askquestion', $remaning_attempt);
                } else if ($_SESSION['how_many_times_failed_in_answering'] < $max_attempt_allowed) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsg', 'local_askquestion', $remaning_attempt);
                }
            }
        } else {
            $errors['securityquestion'] = get_string('incomplete_profiledata', 'local_askquestion');
        }
        return $errors;
    }

}
***********************************************************************

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Davo or anyone else:


I do not understand coding except what I have learned by trial and error. I need a little guidance: the system does not like


               foreach ($profile_fields as $profile_field) {
                        require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
                        $newfield = 'profile_field_'.$field->datatype;
                        $formfield = new $newfield($field->id, $userid);
                        $formfield->edit_field($mform);


added before


     } else {


Do you have any idea how I add this code and satisfy the system? It seems adding the code after '} else {' does nothing.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -
Davo, are you SURE your advice is correct? I am thinking it may be incorrect, as nothing seems to work. How do you know it is correct? What makes you believe your advice is true?
In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Why do I believe my advice about Moodle coding is true? Well, in several years of Moodle development, I've reused the user profile field display code several times and, as long as you know enough programming to be able to adapt them, it's always worked the times I've needed it.

However, to address the specific code you are asking about, the following should do what you are wanting:

I can confirm that replacing the contents of the 'if ($displayquestion) {' code with the following (adapted, as I previously mentioned, from the function profile_definition):

require_once($CFG->dirroot.'/user/profile/lib.php');
require_once($CFG->dirroot.'/user/profile/field/'.$profileinfo->datatype.'/field.class.php');
$newfield = 'profile_field_'.$profileinfo->datatype;
$formfield = new $newfield($profileinfo->id, $USER->id);
$formfield->edit_field($mform);
$this->add_action_buttons(false, 'Submit');

Then a drop-down menu is displayed, for questions where this is appropriate.

This does, however, change the name of the submitted value, so you'll have to change the validation function so that instead of:

if ($data['securityquestion'] !== $datarow->data) 

it reads something like:

if ($data['profile_field_'.$profilefieldshortname] !== $datarow->data)

Unfortunately that won't quite work either, as the form submission will give you the index of the answer, not the actual value, so you'll need to do some additional work to retrieve the list of possible answers and then convert the index into the answer (i.e. if the answers were 'Answer A', 'Answer B', 'Answer C', then selecting 'Answer B', will return 1, as the entries are numbered 0, 1, 2; rather than returning 'Answer B').

Overall, the code in this plugin looks pretty messy (those bits of it I've seen - you only posted some of the code in the forum) and I would certainly advise any client that wanted to install it on their site to have a Moodle developer spend a few hours tidying the code and checking it for security flaws, before deploying it.

Average of ratings: Useful (3)
In reply to Davo Smith

Re: 2.7.1 Addon Help

by David Mudrák -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers Picture of Plugins guardians Picture of Testers Picture of Translators
Davo, you're a star.
Average of ratings: Useful (1)
In reply to David Mudrák

Re: 2.7.1 Addon Help

by Wendi Daniels -

Yes, he is!


Thank you, Davo, for the help you have already given me. I am grateful...and feeling a bit silly that your first instruction somehow could not take me there. I'm not as dumb as I look right now...I'm just not a programmer!  smile

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Alright folks, I passed this information onto another programmer who responded to something on Moodle, and I am waiting for her reply, but can someone explain this in plain English...


I understand that "$" denotes a variable. In the line: 

  if ($data['securityquestion'] !== $datarow->data) {    

the term "securityquestion" will not work, and that is the latest setback. If we replace it with 

 if ($data['profile_field_'.$profilefieldshortname] !== $datarow->data) {  

as Davo suggested, then the system cannot find the database in the table.


How do we overcome this? Is there a way to keep the original or must it be changed? I really know nothing about this, and still I am trying things by trial and error. Sarah, the lady I am working with, seems to understand the code, and I am waiting for her reply. I am really trying to learn, and would love novice-level teaching from anyone who gets this. Thank you!

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I certainly don't think anyone who isn't a programmer is dumb ... I've been programming for nearly 30 years (starting as a child with a ZX Spectrum) and programming Moodle for about 8, so most of it just comes naturally to me now - but there's an infinite number of other areas of human ability which I'm completely useless at (don't ever ask me to hold a conversation in German, to pick a random example).

To reply to your other post, the zip file you attached the other day was incomplete - it has the two core files to override, but the local/askquestion folder in it was empty (unless it was somehow incompatible with the software I used to unzip it). Maybe it would help if you checked again and re-attached the files?

The bit I posted about checking for $data['profile_field_'.$profileldshortname] is correct (I was able to test that much locally), but you would also need to do some sort of check, so that if $profilefieldinfo->type == 'menu' then you need to extract the menu options from the $profilefieldinfo variable (I don't have it in front of me now, so I can't remember where inside they are stored) and then use the submitted data from the form as the index to look up the value in the menu options. Once that has been done, the comparison should work. Hopefully the programmer you are working with can use that information.

In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

Thank you, Davo, for all of your help.


I saved the file as a Zip file, and I did it a few times as it was changing the files. I may have to upload them all separately, and I will do that in just a moment.


I don't understand the code you just sent, but I bet my programmer will. The menu options are extracted and they show up, but the "submit" button for the security question just loops me right back to this same page. If I have your programming in place ('profile_field_'.$profileldshortname) then I get the error code

Notice: Undefined variable: profileldshortname in /home/(my login name)/public_html/(my site)/local/askquestion/edit_form.php on line 90 Notice: Undefined index: profile_field_ in /home/(my login name)/public_html/(my site)/local/askquestion/edit_form.php on line 90


If I change the code back to " 'securityquestion' " then I get this error, which is the same statement, except that above the variable is undefined, and now the index is undefined, and in the original coding ("securityquestion") it is stated only once rather than twice. I don't know the significance. :

Notice: Undefined index: securityquestion in /home/(my login name)/public_html/(my site)/local/askquestion/edit_form.php on line 90


And since I cannot seem to send the files as I want, here is the index code:


<?php

require_once('../../config.php');
require_once('edit_form.php');
require_once('lib.php');
$site = get_site();
global $DB, $USER, $PAGE;

require_login();

//if already respond to question redirect to site frontpage

$PAGE->set_context(context_system::instance());
$data = array();
$url = new moodle_url('/course/view.php?id=2'); //this takes user back to course page
$PAGE->set_url('/local/askquestion/index.php');

if (isloggedin() && !is_siteadmin($USER->id) && !isguestuser($USER->id)) {
    //if already respond to question redirect to site frontpage
//    if ($DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1))) {
//        redirect($url);
//    }

    $editform = new askquestion_edit_form(NULL);

    if ($fromform = $editform->get_data()) {
        $fromdata = (array) $fromform;
        if (!$errors = $editform->validation($fromdata, null)) {

            // insert a vlaue in the table so that user will not asked a question again if he or she come on this page
            $record = new stdClass();
            $record->userid = $USER->id;
            $record->validated = 1;
            $return = $DB->insert_record('local_askquestion', $record, true);
            redirect($url);
        } else {
            $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');
            if ($_SESSION['how_many_times_failed_in_answering'] >= $max_attempt_allowed) {
                $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                $userobj = new stdClass();
                $userobj->id = $USER->id;
                $userobj->suspended = 1;
                //$return = $DB->update_record('user', $obj);
                redirect($logouturl);
            }
        }
    } else {
        $PAGE->set_pagelayout('base');
        $PAGE->set_url('/local/askquestion/index.php');
        $PAGE->set_context(context_system::instance());

        $heading = get_string('security_ques', 'local_askquestion');
        $title = "$site->shortname: " . $heading;

        $PAGE->navbar->add($heading);
        $PAGE->set_title($title);
        $PAGE->set_heading($heading);

        echo $OUTPUT->header();
        echo $OUTPUT->heading($heading);
        $editform->display();
        echo $OUTPUT->footer();
    }
}
?>


I will be able to log back on in 15 minutes and I will give you the rest.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

The file keeps getting rearranged when I try to save it as a zip, so here is the organization of it. It will need to be arranged manually in a folder.

**********************************************************

Main AskQuestion folder:

1) Local folder

     a) db folder

          1) "install" file

     b) Lang folder

          1) en

               (a) local_askquestion.php

     c) blockeduser.php

     d) edit_form.php

     e) Index.php

     f) lib.php

     g) redirect.php

     h) settings.php

     I) version.php


2) Login folder

3) Theme folder

     a) standard folder

          1) config.php

4) ReadMe file


****************************************************************


To those concerned about the sharing of this file, as that has come up before, I have 2 things to say:

1) It is GNU-Public, so it is sharable.

2) The creator did not want to help me fix the problems, and I said I would have to allow others to see this if I am going to get this resolved, as I am not a programmer. He told me that I may show it publicly.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Issue resolved!


It was a typo I didn't notice: your suggestion of 'profile_field_'.$profileldshortname was exactly what it needed, but it was slightly misspelled...'profile_field_'.$profilefieldshortname

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

I spoke too soon...the code keeps redirecting the student right back to the same page. The page is "/local/askquestion/index.php", and if they answer the question correctly, I need them to be redirected to "course/view.php?id=2". Nothing seems to work - the student never leaves "local/askquestion/index.php". This is maddening.



Here is the redirect code...any ideas are appreciated.



/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
global $DB, $USER, $PAGE;
$filname = basename($_SERVER['PHP_SELF']);
$dirs = explode('/', dirname($_SERVER['PHP_SELF']));
$pluginname = $dirs[count($dirs) - 1];
$fullnametomatch = $pluginname . '/' . $filname;
$askquestionurl = new moodle_url('/local/askquestion/index.php');
$feature_enabled = get_config('local_askquestion', 'ask_security_question_after_login');

$redirectcondition = !is_siteadmin() && isloggedin() && !isguestuser() && $feature_enabled;

$currentpageurl = $PAGE->url;
$currentpageurl = rtrim($currentpageurl, '/');
$siteurl = $CFG->wwwroot . '/course/view.php?id=2'; //this takes user back to course page
//add check for course home page to see if that is the current page, and if so, redirect to ask question page for user enrollment validation -- by Sarah Ashley, added 9/24/2014
$currentpageurlprefix = substr($currentpageurl,0,52);
$courseurlprefix = $CFG->wwwroot . '/course/view.php';
//echo $currentpageurlprefix . ' / ' . $courseurlprefix;


$timestamp = time() % 2;

if ($redirectcondition && !$DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1)) && $fullnametomatch !== 'askquestion/index.php') {
    redirect($askquestionurl);
} elseif ($redirectcondition && ($currentpageurl == $siteurl) && $timestamp == 0 && $fullnametomatch !== '/course/view.php?id=2') {
    if (isset($_SESSION['profilefieldshortname'])) {
        unset($_SESSION['profilefieldshortname']);
    }
    $DB->delete_records('local_askquestion', array('userid' => $USER->id, 'validated' => 1));
    redirect($askquestionurl);
}
//add check for when current page prefix is the same as the course url prefix -- by Sarah Ashley, added 9/24/2014
/* elseif ($redirectcondition && ($currentpageurlprefix == $courseurlprefix) && $timestamp == 0 && $fullnametomatch !== 'askquestion/index.php') {
    if (isset($_SESSION['profileshortname'])) {
        unset($_SESSION['profileshortname']);
    }
    $DB->delete_records('local_askquestion', array('userid' => $USER->id, 'validated' => 1));
    redirect($askquestionurl);
}*/

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by ryan sanders -

it is your "if, elseif"  there is no "else"  as in "if, elseif, else"  the conditional statements are not matchingup... and as a result you are never getting a redirect... or you are getting redirected right back to your askquestionurl from looks of it.

=========================

if ($redirectcondition && !$DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1)) && $fullnametomatch !== 'askquestion/index.php') {
    redirect($askquestionurl);
} elseif ($redirectcondition && ($currentpageurl == $siteurl) && $timestamp == 0 && $fullnametomatch !== '/course/view.php?id=2') {
    if (isset($_SESSION['profilefieldshortname'])) {
        unset($_SESSION['profilefieldshortname']);
    }
    $DB->delete_records('local_askquestion', array('userid' => $USER->id, 'validated' => 1));
    redirect($askquestionurl);
}
//add check for when current page prefix is the same as the course url prefix -- by Sarah Ashley, added 9/24/2014
/* elseif ($redirectcondition && ($currentpageurlprefix == $courseurlprefix) && $timestamp == 0 && $fullnametomatch !== 'askquestion/index.php') {
    if (isset($_SESSION['profileshortname'])) {
        unset($_SESSION['profileshortname']);
    }
    $DB->delete_records('local_askquestion', array('userid' => $USER->id, 'validated' => 1));
    redirect($askquestionurl);
}*/

In reply to ryan sanders

Re: 2.7.1 Addon Help

by Wendi Daniels -

So I read on conditional statements and isset/unset, and this is what makes sense to me (no training, I am ignorant) but it still is not working.

I have tried so many things, and nothing seems to work. Should isset/unset be there?


Note: we want to go to $siteurl if they answer the question correctly, and we want to go back to $askquestionurl if they answer incorrectly. It seems there are only 2 options, not 3...so maybe just if/else?

***********************************************************************************



if ($redirectcondition && !$DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1)) && $fullnametomatch !== 'askquestion/index.php') {
    redirect($askquestionurl);
} elseif ($redirectcondition && ($currentpageurl == $siteurl) && $timestamp == 0 && $fullnametomatch !== '/course/view.php?id=2') {
        (isset($_SESSION['profilefieldshortname']))
        unset($_SESSION['profilefieldshortname'])}?>;
       
} else {$DB->delete_records('local_askquestion', array('userid' => $USER->id, 'validated' => 1));
    redirect($askquestionurl);
}



*************************

I also tried

if ($redirectcondition && !$DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1)) && $fullnametomatch !== 'askquestion/index.php')
   { redirect($siteurl);
       
} else {redirect($askquestionurl);
}


************************************************************************

...but these did not work either. Do you see a small tweak in  the code that I left out? Please advise. I have been working on this so long, and so has a very nice lady who responded to my call - Thank you Sarah

 
Average of ratings: - Rate...UsefulScales


 
Average of ratings: - Rate...UsefulScales


In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by ryan sanders -

i do not know what these conditions are / variables are. and why they need to be checked.  is the answer being checked if correct or wrong within these if/else  statements? or is it done before this code is ran?  what is each condition checking? what are the variables? not sure if you can use echo or not,   example:   echo $redirection

======================

$redirectcondition && 

!$DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1)) && 

$fullnametomatch !== 'askquestion/index.php'


$redirectcondition && 

($currentpageurl == $siteurl) && 

$timestamp == 0 && 

$fullnametomatch !== '/course/view.php?id=2'



In reply to ryan sanders

Re: 2.7.1 Addon Help

by Wendi Daniels -

The answer is being checked to determine if it is correct or if it is incorrect.


If it is correct, they go on to $siteurl.


It if it incorrect, they stay at $askquestionurl.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by ryan sanders -

find out what is in the variables of the conditions of the "if statements"

see if you can do something like below (copy paste) into your code just before the if statement begins.

echo '1234567890';

echo $redirectcondition;

echo '1234567890';

echo $fullnametomatch;

echo '1234567890';

echo $timestamp;

echo '1234567890';

echo$currentpageurl;

echo '1234567890';

echo$siteurl;

===============

clear caches

reload page / askquestion...

then look in browser page source code and search for... 1234567890.  

the echo statements above...what are in the variables will hopefully show up, between 1234567890.  if you can get an idea of what is showing up in the variables. then you can more determine what is happening.

instead of echo, you might try htmloutput = $variable;   but do not quote me on that. i am not yet familiar with moodle there maybe a better way of doing above and finding out what is in the variables

===================

you may need to check the database table to find out what the 

DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1))

it will be in the 'local_askquestion' table, most likely the very last row / entry in the table.



In reply to ryan sanders

Re: 2.7.1 Addon Help

by Wendi Daniels -

I'm not clear on what you are saying, but I will pass it on to someone who might. Thank you for your help!

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

OK, so we were looking at the wrong code. This is the code that determines what happens after they answer the question. We need the code to tell the system to   redirect($siteurl)  with a correct answer, and    redirect($askquestionurl) with an incorrect answer.  We're working on it, and I'm bringing in another programmer, but so far no luck. Kindly advise on anything you see.



   // Custom validation should be added here
    function validation($data, $files) {
        global $USER, $DB;
        $errors = array();
        $errors = parent::validation($data, $files);

        $profilefieldshortname = $_SESSION['profileshortname'];
        $profilefieldinfo = $DB->get_record('user_info_field', array('shortname' => $profilefieldshortname));

        if ($DB->record_exists('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id))) {
            $datarow = $DB->get_record('user_info_data', array('userid' => $USER->id, 'fieldid' => $profilefieldinfo->id));

            if ($data['profile_field_' . $profilefieldshortname] !== $datarow->data) {
                if (isset($_SESSION['how_many_times_failed_in_answering'])) {
                    $_SESSION['how_many_times_failed_in_answering'] = $_SESSION['how_many_times_failed_in_answering'] + 1;
                } else {
                    $_SESSION['how_many_times_failed_in_answering'] = 1;
                }

                $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');

                if ($_SESSION['how_many_times_failed_in_answering'] == $max_attempt_allowed) {
                    //invalidate user or suspend user
                    $errors['securityquestion'] = get_string('nomore_attempt', 'local_askquestion');
                    $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                    $userobj = new stdClass();
                    $userobj->id = $USER->id;
                    $userobj->suspended = 1;
                    $return = $DB->update_record('user', $userobj);
                    if ($return) {
                        send_account_suspend_email_to_user();
                    }
                    redirect($logouturl);
                } else if ($_SESSION['how_many_times_failed_in_answering'] == ($max_attempt_allowed - 1)) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsgfinal', 'local_askquestion', $remaning_attempt);
                } else if ($_SESSION['how_many_times_failed_in_answering'] < $max_attempt_allowed) {
                    $remaning_attempt = $max_attempt_allowed - $_SESSION['how_many_times_failed_in_answering'];
                    $errors['securityquestion'] = get_string('errormsg', 'local_askquestion', $remaning_attempt);
                }
            }
        } else {
            $errors['securityquestion'] = get_string('incomplete_profiledata', 'local_askquestion');
        }
        return $errors;
    }

}

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

The programmer I am working with suggested the following:


********************************************************

His code is probably trying to read text from a text box. Now it is a drop down menu which does not supply text but rather a number (the index position in the menu list).

We need to either: (1) make the dropdown supply text instead of the index number, or (2) make his code read an index number rather than text.
**********************************************************

How would this be done?
In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I did state exactly this in my reply on the 8th January.

The $profilefieldinfo variable will include a value 'param1' which contains the list of items in the list.

So, you will need to do something like this (completely untested, may contain many typos):

if ($profilefieldinfo->type == 'menu') {
    $options = explode("\n", $profilefieldinfo->param1);
    $selectedindex = $data['profile_field_'.$profilefieldshortname];
    $submittedvalue = $options[$selectedindex];
} else {
    $submittedvalue = $data['profile_field_'.$profilefieldshortname];
}
if ($submittedvalue == $datarow->data) {
 ...



In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

Thanks, Davo. I seriously am a novice. I passed this on to the programmer, and I have played with it as well. Hopefully, it will work. It is somehow not seeing the answers, and hopefully, this will help.

In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

I am confused, as I thought the format was:


If (this condition exists)

     {then proceed with path "A";  }

Else {then proceed with path "B" instead;   }


   -or-


If (this conditions exists)

     {then proceed with path "A";  }

ElseIf (this other condition exists instead)

     {then proceed with path "B" instead;  }


Else {otherwise, proceed with path "C";  }



I thought there was no such things a (If...Else...If). Am I wrong?

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

We still have the same problem. The answers that the students select are being recorded in user_info_data, so we are thinking that the system cannot see the answers. When it was textinput, it worked just fine, but the problem is that people are going to misspell and forget things, and if I don't make it dropmenu, then people will be kicked out of the system all the time, and they will leave my site because of it. Please advise. This is a weird puzzle.

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

Here is the code for the index page, which may be the problem. If you have the inclination, do you see anything that would cause the system to work with a user profile question that is text input? We need to locate it, and change it to dropdown menu.



<?php

require_once('../../config.php');
require_once('edit_form.php');
require_once('lib.php');
$site = get_site();
global $DB, $USER, $PAGE;

require_login();

//if already respond to question redirect to site frontpage

$PAGE->set_context(context_system::instance());
$data = array();
$url = new moodle_url('/course/view.php?id=2'); //this takes user back to course page
$PAGE->set_url('/local/askquestion/index.php');

if (isloggedin() && !is_siteadmin($USER->id) && !isguestuser($USER->id)) {
    //if already respond to question redirect to site frontpage
   if ($DB->record_exists('local_askquestion', array('userid' => $USER->id, 'validated' => 1))) {
      redirect($url);
}

    $editform = new askquestion_edit_form(NULL);

    if ($fromform = $editform->get_data()) {
        $fromdata = (array) $fromform;
        if (!$errors = $editform->validation($fromdata, null)) {

            // insert a vlaue in the table so that user will be not asked a question again if he or she come on this page
            $record = new stdClass();
            $record->userid = $USER->id;
            $record->validated = 1;
            $return = $DB->insert_record('user_info_data', 'local_askquestion', $record, true);
            redirect($url);
        } else {
            $max_attempt_allowed = get_config('local_askquestion', 'max_attempt_allowed_in_security_question');
            if ($_SESSION['how_many_times_failed_in_answering'] >= $max_attempt_allowed) {
                $logouturl = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
                $userobj = new stdClass();
                $userobj->id = $USER->id;
                $userobj->suspended = 1;
                //$return = $DB->update_record('user', $obj);
                redirect($logouturl);
            }
        }
    } else {
        $PAGE->set_pagelayout('base');
        $PAGE->set_url('/local/askquestion/index.php');
        $PAGE->set_context(context_system::instance());

        $heading = get_string('security_ques', 'local_askquestion');
        $title = "$site->shortname: " . $heading;

        $PAGE->navbar->add($heading);
        $PAGE->set_title($title);
        $PAGE->set_heading($heading);

        echo $OUTPUT->header();
        echo $OUTPUT->heading($heading);
        $editform->display();
        echo $OUTPUT->footer();
    }
}
?>

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

GREAT NEWS!  My programmer got the plugin to work on her moodle.


BAD NEWS: I transferred the plugin to my ftp files and I get this error when I try to use the plugin:

Notice: Undefined variable: CFG in /home/nlineceo/public_html/(my site)/local/askquestion/edit_form.php on line 76 Notice: Trying to get property of non-object in /home/nlineceo/public_html/(my site)/local/askquestion/edit_form.php on line 76


The code on line 76 is this:    redirect($CFG->wwwroot . '/course/view.php?id=2'); 


This code is for the course page, and it worked before with this plugin. We upgraded the plugin to include dropmenu questions, but when it was strictly text input, this all worked.


Any ideas?

In reply to Wendi Daniels

Re: 2.7.1 Addon Help

by Wendi Daniels -

My programmer advised me to silence that line, and that fixed it!


Case closed.

In reply to Davo Smith

Re: 2.7.1 Addon Help

by Wendi Daniels -

I posted the whole plugin - it is attached. Yeah, it's messy, and I have someone working on it. Thank you for showing me how to get the dropdown menu to work. If I may ask, and I realize you may not have the time or inclination, but would you know how to make the rest of it work right? I'm working with a programmer, and her time right now is limited.