Quiz ripetibile infinite volte + .Gif mancante

Plugins, funzionalità sviluppate dagli utenti, patch, fix...
Post Reply
JudE
Newbie
Posts: 20
Joined: Tue Jul 22, 2014 11:10 am
Version: forma.lms 1.4

Quiz ripetibile infinite volte + .Gif mancante

Post by JudE »

Ciao a tutti, ho da qualche settimana cominciato a lavorare su Forma LMS.
Posto qui di seguito i bug che ho trovato:

1) Durante un quiz anche se ha impostato dei tentativi massimi è possibile, tramite il pulsante indietro/back, modificare l'ultima domanda e sottomettere le risposte INFINITE volte.

nel file ->appLms\modules\test\do.test.php sostituire l'intera funzione showResult con:

Code: Select all

function showResult( $object_test, $id_param ) {
	if(!checkPerm('view', true, 'organization') && !checkPerm('view', true, 'storage')) die("You can't access");
	##FIX LUCA GIARDINA SU BACK BUTTON E NUOVA SOTTOMISSIONE
	$lang 			=& DoceboLanguage::createInstance('test');
	if(!isset($_POST['page_to_save']) || (($_POST['page_to_save'] == $_POST['previous_page']) && isset($_SESSION['test_date_begin']) && $_SESSION['test_date_begin']))
	{
	require_once(_base_.'/lib/lib.form.php');
	require_once($GLOBALS['where_lms'].'/class.module/track.test.php');
	require_once($GLOBALS['where_lms'].'/lib/lib.param.php' );
	require_once($GLOBALS['where_lms'].'/lib/lib.test.php' );
	
	//$lang 			=& DoceboLanguage::createInstance('test');
	$id_test 		= $object_test->getId();
	$id_reference 	= getLoParam($id_param, 'idReference');
	$url_coded 		= urlencode(serialize($object_test->back_url));
	$id_track 		= retriveTrack($id_reference, $id_test, Docebo::user()->getIdst());
	
	if($id_track === false) {
		
		$GLOBALS['page']->add(getErrorUi($lang->def('_TEST_TRACK_FAILURE')
			.getBackUi(Util::str_replace_once('&', '&', $object_test->back_url), $lang->def('_BACK'))), 'content');
	}
	$test_man 		= new TestManagement($id_test);
	$play_man 		= new PlayTestManagement($id_test, Docebo::user()->getIdst(), $id_track, $test_man);
	$test_info 		= $test_man->getTestAllInfo();
	$track_info 	= $play_man->getTrackAllInfo();
	
	$previous_page = importVar('previous_page', false, false);
	
	$new_info = array(
		'last_page_seen' => $previous_page,
		'score_status' => 'doing' );
	
	if(isset($_POST['page_to_save']) && (($_POST['page_to_save'] > $track_info['last_page_saved']) || $test_info['mod_doanswer'])) {
		
		$play_man->storePage($_POST['page_to_save'], $test_info['mod_doanswer']);
		$play_man->closeTrackPageSession($_POST['page_to_save']);
	}
	
	$now = date('Y-m-d H:i:s');
	
	$point_do 		= 0;
	$max_score 		= 0;
	$num_manual 	= 0;
	$manual_score 	= 0;
	$point_do_cat 	= array();
	
	$re_visu_quest = sql_query("SELECT idQuest 
	FROM ".$GLOBALS['prefix_lms']."_testtrack_quest 
	WHERE idTrack = '".$id_track."' ");
		
	while(list($id_q) = sql_fetch_row($re_visu_quest)) $quest_see[] = $id_q;
	
	$reQuest = sql_query("
	SELECT q.idQuest, q.type_quest, t.type_file, t.type_class, q.idCategory 
	FROM %lms_testquest AS q JOIN ".$GLOBALS['prefix_lms']."_quest_type AS t
	WHERE q.idTest = '".$id_test."' AND q.type_quest = t.type_quest AND q.idQuest IN (".implode($quest_see, ',').") 
	ORDER BY q.sequence");
	
	//#2093: Conto le domande
	$tot_questions=0;
	$tot_answers=0;
	$tot_rightanswers=0;
	$tot_questions= $test_man->getNumberOfQuestion();

	while(list($id_quest, $type_quest, $type_file, $type_class, $id_cat) = sql_fetch_row($reQuest)) {
		
		require_once($GLOBALS['where_lms'].'/modules/question/'.$type_file);
		
		$quest_point_do = 0;
		
		$quest_obj = new $type_class( $id_quest );
		$quest_point_do 	= $quest_obj->userScore($id_track);
		$quest_max_score 	= $quest_obj->getMaxScore();
		if($quest_obj->getScoreSetType() == 'manual') {
			++$num_manual;
			$manual_score = round($manual_score + $quest_max_score, 2);
		}
		
		//#2093: Conto le risposte, conto le risposte corrette
		$tot_answers++;
		if($quest_point_do == $quest_max_score) $tot_rightanswers++;

		$point_do = round($point_do + $quest_point_do, 2);
		$max_score = round($max_score + $quest_max_score, 2);
		if(isset($point_do_cat[$id_cat])) {
			$point_do_cat[$id_cat] = round($quest_point_do + $point_do_cat[$id_cat], 2);
		} else {
			$point_do_cat[$id_cat] = round($quest_point_do, 2);
		}
	}

	if($test_info['point_type'] == '1') { // percentage score (%)
		// x:100=$point_do:$max_score
		//#2093: calcolo effettivo solo se ho tutte le risposte
		if ($tot_questions==$tot_answers){
			$point_do =round(100*$point_do/$max_score);//$max_score$test_info['point_required']
		}
		else{
			$point_do =round(100*$tot_rightanswers/$tot_questions);//$max_score$test_info['point_required']
		}
	}
	$save_score = $point_do;

	// save new status in track
	if($point_do >= $test_info['point_required']) {
		$next_status = 'passed';
		if($test_info['show_only_status']) $score_status = 'passed';
	} else {
		$next_status = 'failed';
		if($test_info['show_only_status']) $score_status = 'not_passed';
	}
	if(!$test_info['show_only_status']) {
		if($num_manual != 0) $score_status = 'not_checked';
		else $score_status = 'valid';
	}
	$test_track = new Track_Test($id_track);
	$test_track->setDate($now);
	$test_track->status = $next_status;
	$test_track->update();
	
	// --
	require_once(_lms_.'/lib/lib.assessment_rule.php');
	$score_arr =array();
	$i =0;
	foreach($point_do_cat as $cat_id=>$score) {
		$score_arr[$i]['score']=$score;
		$score_arr[$i]['category_id']=$cat_id;
		$i++;
	}
	// final score:
	$score_arr[$i]['score']=$point_do;
	$score_arr[$i]['category_id']=0;
	$asrule =new AssessmentRuleManager($id_test);
	$feedback_txt = $asrule->setRulesFromScore($score_arr);
	$asrule->loadJs();
	// --
	
	$GLOBALS['page']->add(
		getTitleArea($lang->def('_TITLE').' : '.$test_info['title'], 'test', $lang->def('_TEST_INFO'))
		.'<div class="std_block">'
		.( $next_status == 'failed' 
			? '<b>'.$lang->def('_TEST_FAILED').'</b>' 
			: $lang->def('_TEST_COMPLETED') )
		.'<br />', 'content');
	
	if($test_info['point_type'] != '1') {
		$save_score = $point_do;
	} else {
		$save_score = $point_do;//round(round($point_do / $max_score, 2) * 100, 2);
	}
	
	$track_info = Track_Test::getTrackInfo( Docebo::user()->getIdst(), $id_test, $id_reference );
	if($score_status == 'valid' || $score_status == 'not_checked' || $score_status == 'passed' || $score_status == 'not_passed') {
		$new_info['date_end_attempt'] 	= $now;
		$new_info['number_of_save'] 	= $track_info['number_of_save'] + 1;
		$new_info['score'] 				= $save_score;
		$new_info['score_status'] 		= $score_status;
		$new_info['number_of_attempt'] 	= $track_info['number_of_attempt'] + 1;
		
		$re_update = Track_Test::updateTrack($id_track, $new_info);
		if (!isset($_POST['show_review'])) {

            $time = fromDatetimeToTimestamp(date('Y-m-d H:i:s')) - fromDatetimeToTimestamp($_SESSION['test_date_begin']);

            sql_query("
            INSERT INTO ".$GLOBALS['prefix_lms']."_testtrack_times
            (idTrack, idReference, idTest, date_attempt, number_time, score, score_status, date_begin, date_end, time) VALUES
            ('".$id_track."', '".$id_reference."', '".$id_test."', now(), '".$new_info['number_of_save']."', '".$new_info['score']."', '".$new_info['score_status']."', '".$_SESSION['test_date_begin']."', '".date('Y-m-d H:i:s')."', '".$time."')");

	        unset($_SESSION['test_date_begin']);
        }
	}

	//--- check suspension conditions ----------------------------------------------

	if ($test_info['use_suspension']) {
		$suspend_info = array();
		if ($next_status == 'failed') {
			$suspend_info['attempts_for_suspension'] = $track_info['attempts_for_suspension'] + 1;
			if ($suspend_info['attempts_for_suspension'] >= $test_info['suspension_num_attempts'] && $test_info['suspension_num_hours'] > 0) {
				//should we reset learning_test.suspension_num_attempts ??
				$suspend_info['attempts_for_suspension'] = 0; //from now on, it uses the suspended_until parameter, so only the date is needed, we can reset the attempts count
				$suspend_info['suspended_until'] = date("Y-m-d H:i:s", time()+$test_info['suspension_num_hours']*3600);
			} //if num_hours is <= 0, never update attempts counter, so user won't never be de-suspended
			$re = Track_Test::updateTrack($id_track, $suspend_info);
		} else {
			if ($next_status == 'completed' || $next_status == 'passed') {
				$suspend_info['attempts_for_suspension'] = 0;
				$re = Track_Test::updateTrack($id_track, $suspend_info);
			}
		}
	}

//--- end suspensions check ----------------------------------------------------

	list($bonus_score, $score_status) = sql_fetch_row( sql_query("
	SELECT bonus_score, score_status
	FROM ".$GLOBALS['prefix_lms']."_testtrack 
	WHERE idTrack = '".(int)$id_track."'"));
	
	if($test_info['show_score'] && $test_info['point_type'] != '1') {
		
		//$GLOBALS['page']->add('<span class="test_score_note">'.$lang->def('_TEST_TOTAL_SCORE').'</span> '.($point_do + $bonus_score).' / '.$max_score.'<br />', 'content');
		$GLOBALS['page']->add('<span class="test_score_note">'.$lang->def('_TEST_TOTAL_SCORE').'</span> '.($point_do + $bonus_score).' / 100<br />', 'content');
		if($num_manual != 0 && $score_status != 'valid') {
			$GLOBALS['page']->add('<br />'
				.'<span class="test_score_note">'.$lang->def('_TEST_MANUAL_SCORE').'</span> '.$manual_score.' '.$lang->def('_TEST_SCORES').'<br />', 'content');
		}
		if($test_info['point_required'] != 0) {
			$GLOBALS['page']->add('<br />'
				.'<span class="test_score_note">'.$lang->def('_TEST_REQUIREDSCORE_RESULT').'</span> '.$test_info['point_required'].'<br />', 'content');
		}
	}
	if($test_info['show_score'] && $test_info['point_type'] == '1') {
		
		$GLOBALS['page']->add('<span class="test_score_note">'.$lang->def('_TEST_TOTAL_SCORE').'</span> '.$save_score.' %'.'<br />', 'content');
		if($num_manual != 0) {
			$GLOBALS['page']->add('<br />'
				.'<span class="test_score_note">'.$lang->def('_TEST_MANUAL_SCORE').'</span> '.$manual_score.' '.$lang->def('_TEST_SCORES').'<br />', 'content');
		}
	}
	if($test_info['show_score_cat']) {
		
		$re_category = sql_query("
		SELECT c.idCategory, c.name, COUNT(q.idQuest)
		FROM ".$GLOBALS['prefix_lms']."_testquest AS q 
			JOIN ".$GLOBALS['prefix_lms']."_quest_category AS c
		WHERE c.idCategory = q.idCategory AND q.idTest = '".$id_test."' AND q.idCategory != 0 
		GROUP BY c.idCategory 
		ORDER BY c.name");
		
		if(sql_num_rows($re_category)) {
			
			$GLOBALS['page']->add('<br />'
				.'<table summary="'.$lang->def('_TEST_CATEGORY_SCORE').'" class="category_score">'
				.'<caption>'.$lang->def('_TEST_CATEGORY_SCORE').'</caption>'
				.'<thead>'
					.'<tr>'
						.'<th>'.$lang->def('_TEST_QUEST_CATEGORY').'</th>'
						.'<th class="number">'.$lang->def('_TEST_QUEST_NUMBER').'</th'
						.'<th class="number">'.$lang->def('_TEST_TOTAL_SCORE').'</th>'
					.'</tr>'
				.'</thead>'
				.'<tbody>', 'content');
			while(list($id_cat, $name_cat, $quest_number) = sql_fetch_row($re_category)) {
				
				$GLOBALS['page']->add('<tr><td>'.$name_cat.'</td>'
					.'<td class="number">'.$quest_number.'</td>'
					.'<td class="number">'.( isset($point_do_cat[$id_cat]) ? $point_do_cat[$id_cat] : 0 ).'</td></tr>'
				, 'content');
			}
			/*
			$GLOBALS['page']->add('<br />'
				.'<span class="test_score_note">'.$lang->def('_TEST_CATEGORY_SCORE').'</span><br />', 'content');
			while(list($id_cat, $name_cat, $quest_number) = sql_fetch_row($re_category)) {
				
				$GLOBALS['page']->add($name_cat.', '.$lang->def('_TEST_SCORES').': '
					.( isset($point_do_cat[$id_cat]) ? $point_do_cat[$id_cat] : 0 ).'<br />', 'content');
			}
			*/
			$GLOBALS['page']->add('</tbody></table>', 'content');
		}
	}
	$GLOBALS['page']->add('<br /><br />', 'content');

	//--- if chart visualization enabled, then show it ---------------------------

	require_once(_base_.'/lib/lib.json.php');
	$json = new Services_JSON();
	if ($test_info['chart_options'] !== "")
		$chart_options = $json->decode($test_info['chart_options']);
	else
		$chart_options = new stdClass();
	if (!property_exists($chart_options, 'use_charts')) $chart_options->use_charts = false;
	if (!property_exists($chart_options, 'selected_chart')) $chart_options->selected_chart = 'column';
	if (!property_exists($chart_options, 'show_chart')) $chart_options->show_chart = 'teacher';

	if ($chart_options->use_charts && $chart_options->show_chart=='course') {
		cout('<div class="align-center">', 'content');
		$chart = new Test_Charts($test_info['idTest'], Docebo::user()->getIdSt());
		$chart->render($chart_options->selected_chart, true);
		cout('</div><br /><br />', 'content');
	}

	//--- end show chart ---------------------------------------------------------

	if($feedback_txt) cout('<p>'.$feedback_txt.'</p><br />', 'content');


	$points = $point_do + $bonus_score;
	if($test_info['show_solution'] == 2 && $points >= $test_info['point_required'])
	{
		$GLOBALS['page']->add(Form::openForm('test_show', 'index.php?modname=test&op=play')
			.Form::getHidden('next_step', 'next_step', 'test_review')
			.Form::getHidden('id_test', 'id_test', $id_test)
			.Form::getHidden('id_param', 'id_param', $id_param)
			.Form::getHidden('back_url', 'back_url', $url_coded)
			.Form::getHidden('idTrack', 'idTrack', $id_track)
			.Form::getButton('review', 'review', $lang->def('_TEST_REVIEW_ANSWER'))
			.Form::closeForm(), 'content');
	}
	elseif($test_info['show_doanswer'] == 2 && $points >= $test_info['point_required'])
	{
		$GLOBALS['page']->add(Form::openForm('test_show', 'index.php?modname=test&op=play')
			.Form::getHidden('next_step', 'next_step', 'test_review')
			.Form::getHidden('id_test', 'id_test', $id_test)
			.Form::getHidden('id_param', 'id_param', $id_param)
			.Form::getHidden('back_url', 'back_url', $url_coded)
			.Form::getHidden('idTrack', 'idTrack', $id_track)
			.Form::getButton('review', 'review', $lang->def('_TEST_REVIEW_ANSWER'))
			.Form::closeForm(), 'content');
	}
	elseif($test_info['show_solution'] != 2 && $test_info['show_doanswer'] != 2)
		if($test_info['show_solution'] || $test_info['show_doanswer'])
		{
			$GLOBALS['page']->add(Form::openForm('test_show', 'index.php?modname=test&op=play')
				.Form::getHidden('next_step', 'next_step', 'test_review')
				.Form::getHidden('id_test', 'id_test', $id_test)
				.Form::getHidden('id_param', 'id_param', $id_param)
				.Form::getHidden('back_url', 'back_url', $url_coded)
				.Form::getHidden('idTrack', 'idTrack', $id_track)
				.Form::getButton('review', 'review', $lang->def('_TEST_REVIEW_ANSWER'))
				.Form::closeForm(), 'content');
		}
	
	$GLOBALS['page']->add(Form::openForm('test_show', Util::str_replace_once('&', '&', $object_test->back_url))
		.'<div class="align_right">'
		.Form::getButton('end_test', 'end_test', $lang->def('_TEST_END_BACKTOLESSON'))
		.'</div>'
		.Form::closeForm(), 'content');
	
	$GLOBALS['page']->add('</div>', 'content');
	}
	else
	{
		$GLOBALS['page']->add($lang->def('_TEST_BUG_BACK'). '<div align="center"><a href="/appLms/"> Torna alla homepage</a></div>', 'content');
	}
}
AGGIUNGERE ALLA LINGUA "_TEST_BUG_BACK" con un testo a scelta/personalizzare la frase alla fine della funzione.

2) Immagine gif che non viene visualizzata perchè manca l'estensione, nel forum (community)
nel file ->appLms\modules\forum\forum.php sostituire alla riga 340

Code: Select all

.'<img src="'.getPathImage().'emoticons/'.$emoticons.'" title="'.$lang->def('_EMOTICONS').'" alt="'.$lang->def('_EMOTICONS').'" />'
con

Code: Select all

.'<img src="'.getPathImage().'emoticons/'.$emoticons.'.gif" title="'.$lang->def('_EMOTICONS').'" alt="'.$lang->def('_EMOTICONS').'" />'
Inoltre ne approfitto per chiedere come mai l'oggetto questionario non risulta "passato" dopo essere stato completato, devo riscaricare forma o è un bug?
User avatar
max
FormaLms Guru
Posts: 2735
Joined: Thu Mar 01, 2012 10:41 am
Version: forma.lms 2.4
Contact:

Re: Bug Fix (2)

Post by max »

Hi Jude,

grazie per i 2 bugfix. In realtà proprio in questi giorni stiamo rilasciando la v. 1.3 e non credo riusciremo a inserirli in questa release. Li mettiamo comunque in lista per testarli e rilasciarli con la prossima.

L'oggetto questionario è un bug annoso, ereditato dalla vecchia docebo, e confermo quello che hai riscontrato. Visto che viene poco usato non ci avevamo mai dedicato molta attenzione, suggerendo anzi a tutti di usare i test anche per fare i sondaggi.
---------------------
Massimiliano Ferrari
Elearnit - Elearning e Knowledge Management
https://www.elearnit.net
https://www.linkedin.com/in/massimilianoferrari
m.ferrari[at]elearnit.net
Skype: m_ferrari_it
User avatar
canelli
FormaLms Guru
Posts: 496
Joined: Thu Nov 08, 2012 12:21 pm
Version: forma.lms 2.0
Contact:

Re: Bug Fix (2)

Post by canelli »

JudE, Grazie per i fix .

Ricordo alcune regole elementari del forum, per essere di aiuto a tutta la comunità:
a) utilizzare un titolo del thread significativo che possa essere di aiuto e comprensione nelle richerche e nelle visualizzazioni
b) utilizzare un thread per uno solo argomento. se occorre aprire un nuovo thread .
Cercate nel forum le riposte prima di chiedere. Check the forum before posting
---------------
Claudio Anelli
Joint Technologies - Sistemi avanzati per l'information technology

http://www.joint-tech.com
---------------
User avatar
max
FormaLms Guru
Posts: 2735
Joined: Thu Mar 01, 2012 10:41 am
Version: forma.lms 2.4
Contact:

Re: Quiz ripetibile infinite volte + .Gif mancante

Post by max »

Claudio, ottimo suggerimento
ho provveduto a cambiare il titolo del thread per renderlo più significativo
---------------------
Massimiliano Ferrari
Elearnit - Elearning e Knowledge Management
https://www.elearnit.net
https://www.linkedin.com/in/massimilianoferrari
m.ferrari[at]elearnit.net
Skype: m_ferrari_it
JudE
Newbie
Posts: 20
Joined: Tue Jul 22, 2014 11:10 am
Version: forma.lms 1.4

Re: Quiz ripetibile infinite volte + .Gif mancante

Post by JudE »

Grazie a voi.. a questo punto aspetterò la nuova versione prima di correggere il questionario.
E' presente una lista di bug da fixare? vorrei dare una mano :)

Luca
User avatar
max
FormaLms Guru
Posts: 2735
Joined: Thu Mar 01, 2012 10:41 am
Version: forma.lms 2.4
Contact:

Re: Quiz ripetibile infinite volte + .Gif mancante

Post by max »

Ciao Luca

lo sviluppo del progetto viene gestito dai 4 partner (www.formalms.org): abbiamo un sistema di ticket, una roadmap, condividiamo strategie su cosa fixare e quando e soprattutto sulla direzione da dare al progetto, comprese le nuove funzionalità da aggiungere (non è che si può solo fixare, si aggiunge). Oltre ai bug, in questo anno e rotti abbiamo anche aggiornato molte cose "sotto il cofano" (librerie, compatibilità con php, icone, motore grafico, motore template...).

Per un membro della community, la maniera migliore e più semplice di dare una mano è esattamente quello che hai fatto tu:
- individuare un bug
- pubblicare la patch o il codice che lo fixa

Le tue due modifiche le abbiamo già inserite nel ns sistema il 5 novembre stesso. Era ormai tardi per questa release, finiranno nella prossima dopo essere state testate e approvate.

In generale le segnalazioni arrivano nei forum "bug", "moduli e patch" e "suggerimenti", sia in ITA che in ENG
---------------------
Massimiliano Ferrari
Elearnit - Elearning e Knowledge Management
https://www.elearnit.net
https://www.linkedin.com/in/massimilianoferrari
m.ferrari[at]elearnit.net
Skype: m_ferrari_it
JudE
Newbie
Posts: 20
Joined: Tue Jul 22, 2014 11:10 am
Version: forma.lms 1.4

Re: Quiz ripetibile infinite volte + .Gif mancante

Post by JudE »

Segnalo che nella 1.4 il bug continua a persistere..
User avatar
canelli
FormaLms Guru
Posts: 496
Joined: Thu Nov 08, 2012 12:21 pm
Version: forma.lms 2.0
Contact:

Re: Quiz ripetibile infinite volte + .Gif mancante

Post by canelli »

quale bug:
a) azione dopo il back
b) gif mancante
?
Cercate nel forum le riposte prima di chiedere. Check the forum before posting
---------------
Claudio Anelli
Joint Technologies - Sistemi avanzati per l'information technology

http://www.joint-tech.com
---------------
Post Reply