The Elearning Community • Quiz ripetibile infinite volte + .Gif mancante
Page 1 of 1

Quiz ripetibile infinite volte + .Gif mancante

Posted: Wed Nov 05, 2014 3:35 pm
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?

Re: Bug Fix (2)

Posted: Wed Nov 05, 2014 5:36 pm
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.

Re: Bug Fix (2)

Posted: Wed Nov 05, 2014 7:21 pm
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 .

Re: Quiz ripetibile infinite volte + .Gif mancante

Posted: Wed Nov 05, 2014 8:26 pm
by max
Claudio, ottimo suggerimento
ho provveduto a cambiare il titolo del thread per renderlo più significativo

Re: Quiz ripetibile infinite volte + .Gif mancante

Posted: Wed Nov 12, 2014 10:57 am
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

Re: Quiz ripetibile infinite volte + .Gif mancante

Posted: Wed Nov 12, 2014 12:14 pm
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

Re: Quiz ripetibile infinite volte + .Gif mancante

Posted: Tue Aug 04, 2015 4:27 pm
by JudE
Segnalo che nella 1.4 il bug continua a persistere..

Re: Quiz ripetibile infinite volte + .Gif mancante

Posted: Mon Aug 17, 2015 4:24 pm
by canelli
quale bug:
a) azione dopo il back
b) gif mancante
?

This site uses cookies.

Some of the cookies we use are essential for parts of the site to operate and have already been set. We also use Google Analytics scripts, which all use cookies.
You may delete or block all cookies from this site in your browser options.