-
Astor Bizard authoredAstor Bizard authored
similarity_sources.class.php 15.49 KiB
<?php
// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
//
// VPL for Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// VPL for Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with VPL for Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Classes to manage file from difrerent soruces
*
* @package mod_vpl
* @copyright 2015 Juan Carlos Rodríguez-del-Pino
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
*/
defined('MOODLE_INTERNAL') || die();
/**
* @abstract class to represent files from any source
*/
class vpl_file_from_base {
public function show_info() {
}
public function can_access() {
return false;
}
public function get_userid() {
return '';
}
}
/**
* Information of a file from a directory
*/
class vpl_file_from_dir extends vpl_file_from_base {
static protected $usersname = array ();
protected $dirname;
protected $filename;
protected $userid;
// This is for compatibility with GAP 2.x application.
static public function process_gap_userfile($filepath) {
if (strtolower( basename( $filepath ) ) == 'datospersonales.gap') {
$nif = '';
$nombre = '';
$apellidos = '';
$lines = explode( "\n", file_get_contents( $filepath ) );
if (count( $lines ) > 3) {
if (strpos( $lines [1], 'NIF=' ) !== false) {
$nif = substr( $lines [1], 4 );
}
if (strpos( $lines [2], 'Nombre=' ) !== false) {
$nombre = substr( $lines [2], 7 );
}
if (strpos( $lines [3], 'Apellidos=' ) !== false) {
$apellidos = substr( $lines [3], 10 );
}
}
if ($nif > '' && $nombre > '' && $apellidos > '') {
global $CFG;
if ($CFG->fullnamedisplay == 'lastname firstname') {
self::$usersname [$nif] = mb_convert_encoding( $apellidos . ', ' . $nombre, 'utf-8' );
} else {
self::$usersname [$nif] = mb_convert_encoding( $nombre . ' ' . $apellidos, 'utf-8' );
}
}
}
}
// This is for compatibility with GAP 2.x application.
static public function get_user_id_from_file($filename) {
if (count( self::$usersname )) {
$filename = strtolower( $filename );
foreach (self::$usersname as $userid => $userdata) {
if (strpos( $filename, $userid ) !== false) {
return $userid;
}
}
}
return '';
}
public function __construct(&$filename, $vplid, $dirname, $userid = '') {
$this->filename = $filename;
$this->dirname = $dirname;
$this->vplid = $vplid;
$this->userid = self::get_user_id_from_file( $filename );
}
public function get_userid() {
return $this->userid;
}
public function show_info() {
$ret = '';
$ret .= '<a href="' . 'file.php' . '">';
$ret .= s( $this->filename ) . ' ';
$ret .= '</a>';
if ($this->userid != '') {
$ret .= ' ' . self::$usersname [$this->userid];
}
return $ret;
}
public function can_access() {
return $this->filename != vpl_similarity_preprocess::JOINEDFILENAME;
}
public function link_parms($t) {
$res = array (
'type' . $t => 2,
'dirname' . $t => $this->dirname,
'filename' . $t => $this->filename
);
if ($this->userid != '') {
$res ['username' . $t] = self::$usersname [$this->userid];
}
return $res;
}
}
/**
* Information of a file from a zip file
*/
class vpl_file_from_zipfile extends vpl_file_from_dir {
public function show_info() {
$ret = '';
$ret .= s( $this->filename );
if ($this->userid != '') {
$ret .= ' ' . self::$usersname [$this->userid];
}
return $ret;
}
public function can_access() {
return true;
}
public function link_parms($t) {
$res = array (
'type' . $t => 3,
'vplid' . $t => $this->vplid,
'zipfile' . $t => $this->dirname,
'filename' . $t => $this->filename
);
if ($this->userid != '') {
$res ['username' . $t] = self::$usersname [$this->userid];
}
return $res;
}
}
/**
* Information of a file from other vpl activity
*/
class vpl_file_from_activity extends vpl_file_from_base {
static protected $vpls = array ();
protected $vplid;
protected $filename;
protected $subid;
protected $userid;
public function __construct(&$filename, &$vpl, $subinstance) {
$id = $vpl->get_instance()->id;
if (! isset( self::$vpls [$id] )) {
self::$vpls [$id] = $vpl;
}
$this->vplid = $id;
$this->filename = $filename;
$this->userid = $subinstance->userid;
$this->subid = $subinstance->id;
}
public function show_info() {
global $DB;
$vpl = self::$vpls [$this->vplid];
$cmid = $vpl->get_course_module()->id;
$ret = '';
if ($this->userid >= 0) {
$user = $DB->get_record( 'user', array (
'id' => $this->userid
) );
} else {
$user = false;
}
if ($user) {
$ret .= '<a href="' . vpl_mod_href( 'forms/submissionview.php', 'id', $cmid, 'userid', $user->id ) . '">';
}
$ret .= s( $this->filename );
if ($user) {
$ret .= '</a> ';
$sub = new mod_vpl_submission( $vpl, $this->subid );
$ret .= $sub->get_grade_core() . '<br />';
$ret .= $vpl->user_fullname_picture( $user );
$link = vpl_mod_href( 'similarity/user_similarity.php', 'id', $vpl->get_course()->id, 'userid', $user->id );
$ret .= ' (<a href="' . $link . '">';
$ret .= '*</a>)';
}
return $ret;
}
public function get_userid() {
return $this->userid;
}
public function can_access() {
return $this->filename != vpl_similarity_preprocess::JOINEDFILENAME;
}
public function link_parms($t) {
return array (
'type' . $t => 1,
'subid' . $t => $this->subid,
'filename' . $t => $this->filename
);
}
}
/**
* Utility class to get list of preprocessed files
*/
class vpl_similarity_preprocess {
/**
*
* @var const fake file name for files joined
*/
const JOINEDFILENAME = '_joined_files_';
/**
*
* @var minimum number of tokens needed to accept a file to be compared
*/
const MINTOKENS = 10;
/**
* Preprocesses activity, loading activity files into $simil array
*
* @param array $simil of file processed objects
* @param object $vpl of activity to process
* @param array $filesselected if set only files selected
* @param boolean $allfiles preprocess all files
* @param boolean $joinedfiles join files as one
* @param $subinstance
* @param $toremove $toremove with filenames as keys to remove from comparation
* @return void
*/
static public function proccess_files($fgm, $filesselected, $allfiles, $joinedfiles
, $vpl = false, $subinstance = false, $toremove = array()) {
$files = array ();
$filelist = $fgm->getFileList();
$simjf = false;
$from = null;
$joinedfilesdata = '';
foreach ($filelist as $filename) {
if (! isset( $filesselected [ basename($filename) ] ) && ! $allfiles) {
continue;
}
$sim = vpl_similarity_factory::get( $filename );
if ($sim) {
$data = $fgm->getFileData( $filename );
if ($joinedfiles) {
if (! $simjf) {
$simjf = $sim;
}
$joinedfilesdata .= $data . "\n";
} else {
if ($vpl) {
$from = new vpl_file_from_activity( $filename, $vpl, $subinstance );
}
if (isset( $toremove [$filename] )) {
$sim->init( $data, $from, $toremove [$filename] );
} else {
$sim->init( $data, $from );
}
if ($sim->get_size() > self::MINTOKENS) {
$files [$filename] = $sim;
}
}
}
}
if ($simjf) {
$filename = self::JOINEDFILENAME;
if ($vpl) {
$from = new vpl_file_from_activity( $filename, $vpl, $subinstance );
}
if (isset( $toremove [$filename] )) {
$simjf->init( $joinedfilesdata, $from, $toremove [$filename] );
} else {
$simjf->init( $joinedfilesdata, $from );
}
if ($simjf->get_size() > self::MINTOKENS) {
$files [self::JOINEDFILENAME] = $simjf;
}
}
return $files;
}
static public function activity(&$simil, $vpl, $filesselected = array(), $allfiles, $joinedfiles, $spb) {
$vpl->require_capability( VPL_SIMILARITY_CAPABILITY );
$cm = $vpl->get_course_module();
$groupmode = groups_get_activity_groupmode( $cm );
if (! $groupmode) {
$groupmode = groups_get_course_groupmode( $vpl->get_course() );
}
$currentgroup = groups_get_activity_group( $cm, true );
if (! $currentgroup) {
$currentgroup = '';
}
$list = $vpl->get_students($currentgroup);
if (count( $list ) == 0) {
return;
}
$submissions = $vpl->all_last_user_submission();
// Get initial content files.
$reqf = $vpl->get_fgm('required');
$toremove = self::proccess_files( $reqf, $filesselected, $allfiles, $joinedfiles );
$spb->set_max( count( $list ) );
$i = 0;
foreach ($list as $user) {
$i ++;
$spb->set_value( $i );
if (isset( $submissions [$user->id] )) {
$subinstance = $submissions [$user->id];
$submission = new mod_vpl_submission( $vpl, $subinstance );
$subf = $submission->get_submitted_fgm();
$files = self::proccess_files( $subf, $filesselected, $allfiles, $joinedfiles, $vpl, $subinstance, $toremove );
foreach ($files as $file) {
$simil [] = $file;
}
}
}
}
/**
* Preprocesses user activity, loading user activity files into $simil array
*
* @param array $simil of file processed objects
* @param object $vpl activity to process
* @param int $userid id of the user to preprocess
* @return void
*/
static public function user_activity(&$simil, $vpl, $userid) {
$subinstance = $vpl->last_user_submission( $userid );
if (! $subinstance) {
return;
}
$vpl->require_capability( VPL_SIMILARITY_CAPABILITY );
// Get initial content files.
$reqf = $vpl->get_fgm('required');
$filelist = $reqf->getFileList();
$toremove = array ();
foreach ($filelist as $filename) {
$sim = vpl_similarity_factory::get( $filename );
if ($sim) {
$data = $reqf->getFileData( $filename );
$sim->init( $data, null );
$toremove [$filename] = $sim;
}
}
$origin = '';
$submission = new mod_vpl_submission( $vpl, $subinstance );
$subf = $submission->get_submitted_fgm();
$filelist = $subf->getFileList();
foreach ($filelist as $filename) {
$sim = vpl_similarity_factory::get( $filename );
if ($sim) {
$data = $subf->getFileData( $filename );
$from = new vpl_file_from_activity( $filename, $vpl, $subinstance );
if (isset( $toremove [$filename] )) {
$sim->init( $data, $from, $toremove [$filename] );
} else {
$sim->init( $data, $from );
}
if ($sim->get_size() > self::MINTOKENS) {
$simil [] = $sim;
}
}
}
}
static public function get_zip_filepath($vplid, $zipname) {
global $CFG;
$zipname = basename( $zipname );
return $CFG->dataroot . '/temp/vpl_zip/' . $vplid . '_' . $zipname;
}
static public function create_zip_file($vplid, $zipname, $zipdata) {
$filename = self::get_zip_filepath( $vplid, $zipname );
$fp = vpl_fopen( $filename );
fwrite( $fp, $zipdata );
fclose( $fp );
}
/**
* Preprocesses ZIP file, loading processesed files into $simil array
*
* @param array $simil of file processed objects
* @param object $vpl activity to process
* @param array $filesselected if set only files selected
* @param boolean $allfiles preprocess all files
* @param boolean $joinedfiles join files as one
* @param $spb
* @return void
*/
static public function zip(&$simil, $zipname, $zipdata, $vpl, $filesselected = array(), $allfiles, $joinedfiles, $spb) {
global $CFG;
$ext = strtoupper( pathinfo( $zipname, PATHINFO_EXTENSION ) );
if ($ext != 'ZIP') {
print_error( 'nozipfile' );
}
$vplid = $vpl->get_instance()->id;
self::create_zip_file( $vplid, $zipname, $zipdata );
$zip = new ZipArchive();
$zipfilename = self::get_zip_filepath( $vplid, $zipname );
$spb->set_value( get_string( 'unzipping', VPL ) );
if ($zip->open( $zipfilename )) {
$spb->set_max( $zip->numFiles );
$i = 1;
for ($i = 0; $i < $zip->numFiles; $i ++) {
$spb->set_value( $i + 1 );
$filename = $zip->getNameIndex( $i );
if ($filename == false) {
break;
}
$data = $zip->getFromIndex( $i );
if ($data) {
// TODO remove if no GAP file.
vpl_file_from_zipfile::process_gap_userfile( $filename );
if (! isset( $filesselected [basename( $filename )] ) && ! $allfiles) {
continue;
}
$sim = vpl_similarity_factory::get( $filename );
if ($sim) {
$from = new vpl_file_from_zipfile( $filename, $vplid, $zipname );
$sim->init( $data, $from );
if ($sim->get_size() > self::MINTOKENS) {
$simil [] = $sim;
}
}
}
}
}
$spb->set_value( $zip->numFiles );
}
}