Skip to content
Snippets Groups Projects
Commit 69be28ce authored by anisa kusumadewi's avatar anisa kusumadewi
Browse files

wip: comments download

parent b06ccf22
No related branches found
No related tags found
No related merge requests found
db/install.xml 100644 → 100755
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/pdfannotator/db" VERSION="20181017" COMMENT="XMLDB file for Moodle mod/pdfannotator"
<XMLDB PATH="mod/pdfannotator/db" VERSION="20221101" COMMENT="XMLDB file for Moodle mod/pdfannotator"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
......@@ -48,9 +48,7 @@
<FIELD NAME="isquestion" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="When the user creates an annotation, the comment he has to write is a question. So this column has to be true, otherwise false."/>
<FIELD NAME="isdeleted" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="ishidden" TYPE="int" LENGTH="2" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Hidden comments can be seen by managers but not participants."/>
<FIELD NAME="solved" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="saves the userid of the user who marked the comment
question: marked as solved
answer: marked as correct answer"/>
<FIELD NAME="solved" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="saves the userid of the user who marked the comment question: marked as solved answer: marked as correct answer"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
......
db/upgrade.php 100644 → 100755
......@@ -603,5 +603,46 @@ function xmldb_pdfannotator_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2021032201, 'pdfannotator');
}
if ($oldversion < 2022102606) {
// Define table pdfannotator_embeddedfiles to be created.
$table = new xmldb_table('pdfannotator_embeddedfiles');
// Adding fields to table pdfannotator_embeddedfiles.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('fileid', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, null, null);
$table->add_field('commentid', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, null, null);
// Adding keys to table pdfannotator_embeddedfiles.
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_key('fileid', XMLDB_KEY_FOREIGN, ['fileid'], 'files', ['id']);
$table->add_key('commentid', XMLDB_KEY_FOREIGN, ['commentid'], 'comments', ['id']);
// Adding indexes to table pdfannotator_embeddedfiles.
$table->add_index('idandcomment', XMLDB_INDEX_NOTUNIQUE, ['id', 'commentid']);
// Conditionally launch create table for pdfannotator_embeddedfiles.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Pdfannotator savepoint reached.
upgrade_mod_savepoint(true, 2022102606, 'pdfannotator');
}
if ($oldversion < 2022110200) {
// Define table pdfannotator_embeddedfiles to be dropped.
$table = new xmldb_table('pdfannotator_embeddedfiles');
// Conditionally launch drop table for pdfannotator_embeddedfiles.
if ($dbman->table_exists($table)) {
$dbman->drop_table($table);
}
// Pdfannotator savepoint reached.
upgrade_mod_savepoint(true, 2022110200, 'pdfannotator');
}
return true;
}
......@@ -113,8 +113,7 @@ $string['error:hideComment'] = "An error has occured while trying to hide the co
$string['error:markasread'] = 'The item could not be marked as read.';
$string['error:markasunread'] = 'The item could not be marked as unread.';
$string['error:markcorrectanswer'] = 'An error has occured while marking the answer as correct.';
$string['error:maximalsizeoffile_created'] = 'Your comment cannot be created, because it exceeds the maximum size of files. You can attach file(s) with at most {$a} to a single comment.';
$string['error:maximalsizeoffile_edited'] = 'Your comment cannot be edited, because it exceeds the maximum size of files. You can attach file(s) with at most {$a} to a single comment.';
$string['error:maximalsizeoffile'] = 'Your file {$a->filename}, because it exceeds {$a->filesize} as the maximum size of files. You can attach file(s) with at most {$a->maxfilesize} to a single comment.';
$string['error:missingAnnotationtype'] = 'Annotationtype does not exists. Possibly the entry in table pdfannotator_annotationtypes is missing.';
$string['error:openingPDF'] = 'An error occurred while opening the PDF file.';
$string['error:openprintview'] = 'An error has occured while trying to open the pdf in Acrobat Reader.';
......
......@@ -211,13 +211,14 @@ function pdfannotator_split_content_image($content, $res, $itemid, $context=null
$tempinfo = [];
foreach($fileinfo as $file) {
$count = substr_count($imgstr, $file['filename']);
$count = substr_count(urldecode($url[0]), $file['filename']);
if($count) {
$tempinfo = $file;
break;
}
}
if($tempinfo) {
$imagedata = 'data:' . $tempinfo['filemimetype'] . ';base64,' . base64_encode($tempinfo['filecontent']);
$data['image'] = $imagedata;
$data['format'] = $tempinfo['filemimetype'];
......@@ -225,6 +226,7 @@ function pdfannotator_split_content_image($content, $res, $itemid, $context=null
$data['filename'] = $tempinfo['filename'];
$data['filepath'] = $tempinfo['filepath'];
$data['filesize'] = $tempinfo['filesize'];
}
preg_match('/height=[0-9]+/', $imgstr, $height);
$data['imageheight'] = str_replace("\"", "", explode('=', $height[0])[1]);
......@@ -263,7 +265,7 @@ function pdfannotator_data_preprocessing($context, $textarea, $draftitemid = 0)
if(!$imagebtn) {
$editor->use_editor($textarea, $options);
} else {
// inilialize Filepicker if image button is active.
// initialize Filepicker if image button is active.
$args = new \stdClass();
// need these three to filter repositories list.
$args->accepted_types = ['web_image'];
......@@ -295,7 +297,7 @@ function pdfannotator_data_preprocessing($context, $textarea, $draftitemid = 0)
/**
* Same function as core, however we need to add files into the existing draft area!
*
* Copied from hsuforum.
*/
function pdfannotator_file_prepare_draft_area(&$draftitemid, $contextid, $component, $filearea, $itemid, array $options=null, $text=null) {
global $CFG, $USER, $CFG, $DB;
......@@ -366,6 +368,233 @@ function pdfannotator_file_prepare_draft_area(&$draftitemid, $contextid, $compon
return file_rewrite_pluginfile_urls($text, 'draftfile.php', $usercontext->id, 'user', 'draft', $draftitemid, $options);
}
/**
* Just like the file_save_draft_area_files core function.
* However, we need to store fileid and commentid in pdfannotator_embeddedfiles
* and add its id into the html code from the corresponding files.
* @return string|null if $text was passed in, the rewritten $text is returned.
* Otherwise NULL.
*/
function pdfannotator_file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options=null, $text=null, $forcehttps=false) {
global $USER, $DB;
// Do not merge files, leave it as it was.
if ($draftitemid === IGNORE_FILE_MERGE) {
// Safely return $text, no need to rewrite pluginfile because this is mostly comming from an external client like the app.
return $text;
}
$usercontext = context_user::instance($USER->id);
$fs = get_file_storage();
$options = (array)$options;
if (!isset($options['subdirs'])) {
$options['subdirs'] = false;
}
if (!isset($options['maxfiles'])) {
$options['maxfiles'] = -1; // unlimited
}
if (!isset($options['maxbytes']) || $options['maxbytes'] == USER_CAN_IGNORE_FILE_SIZE_LIMITS) {
$options['maxbytes'] = 0; // unlimited
}
if (!isset($options['areamaxbytes'])) {
$options['areamaxbytes'] = FILE_AREA_MAX_BYTES_UNLIMITED; // Unlimited.
}
$allowreferences = true;
if (isset($options['return_types']) && !($options['return_types'] & (FILE_REFERENCE | FILE_CONTROLLED_LINK))) {
// we assume that if $options['return_types'] is NOT specified, we DO allow references.
// this is not exactly right. BUT there are many places in code where filemanager options
// are not passed to file_save_draft_area_files()
$allowreferences = false;
}
// Check if the user has copy-pasted from other draft areas. Those files will be located in different draft
// areas and need to be copied into the current draft area.
$text = file_merge_draft_areas($draftitemid, $usercontext->id, $text, $forcehttps);
// Check if the draft area has exceeded the authorised limit. This should never happen as validation
// should have taken place before, unless the user is doing something nauthly. If so, let's just not save
// anything at all in the next area.
if (file_is_draft_area_limit_reached($draftitemid, $options['areamaxbytes'])) {
return null;
}
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
$oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id');
// One file in filearea means it is empty (it has only top-level directory '.').
if (count($draftfiles) > 1 || count($oldfiles) > 1) {
// we have to merge old and new files - we want to keep file ids for files that were not changed
// we change time modified for all new and changed files, we keep time created as is
$newhashes = array();
$filecount = 0;
$context = context::instance_by_id($contextid, MUST_EXIST);
foreach ($draftfiles as $file) {
if (!$options['subdirs'] && $file->get_filepath() !== '/') {
continue;
}
if (!$allowreferences && $file->is_external_file()) {
continue;
}
if (!$file->is_directory()) {
// Check to see if this file was uploaded by someone who can ignore the file size limits.
$fileusermaxbytes = get_user_max_upload_file_size($context, $options['maxbytes'], 0, 0, $file->get_userid());
if ($fileusermaxbytes != USER_CAN_IGNORE_FILE_SIZE_LIMITS
&& ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize())) {
// Oversized file.
continue;
}
if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
// more files - should not get here at all
continue;
}
$filecount++;
}
$newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename());
$newhashes[$newhash] = $file;
}
// Loop through oldfiles and decide which we need to delete and which to update.
// After this cycle the array $newhashes will only contain the files that need to be added.
foreach ($oldfiles as $oldfile) {
$oldhash = $oldfile->get_pathnamehash();
if (!isset($newhashes[$oldhash])) {
// delete files not needed any more - deleted by user
$oldfile->delete();
continue;
}
$newfile = $newhashes[$oldhash];
// Now we know that we have $oldfile and $newfile for the same path.
// Let's check if we can update this file or we need to delete and create.
if ($newfile->is_directory()) {
// Directories are always ok to just update.
} else if (($source = @unserialize($newfile->get_source())) && isset($source->original)) {
// File has the 'original' - we need to update the file (it may even have not been changed at all).
$original = file_storage::unpack_reference($source->original);
if ($original['filename'] !== $oldfile->get_filename() || $original['filepath'] !== $oldfile->get_filepath()) {
// Very odd, original points to another file. Delete and create file.
$oldfile->delete();
continue;
}
} else {
// The same file name but absence of 'original' means that file was deteled and uploaded again.
// By deleting and creating new file we properly manage all existing references.
$oldfile->delete();
continue;
}
// status changed, we delete old file, and create a new one
if ($oldfile->get_status() != $newfile->get_status()) {
// file was changed, use updated with new timemodified data
$oldfile->delete();
// This file will be added later
continue;
}
// Updated author
if ($oldfile->get_author() != $newfile->get_author()) {
$oldfile->set_author($newfile->get_author());
}
// Updated license
if ($oldfile->get_license() != $newfile->get_license()) {
$oldfile->set_license($newfile->get_license());
}
// Updated file source
// Field files.source for draftarea files contains serialised object with source and original information.
// We only store the source part of it for non-draft file area.
$newsource = $newfile->get_source();
if ($source = @unserialize($newfile->get_source())) {
$newsource = $source->source;
}
if ($oldfile->get_source() !== $newsource) {
$oldfile->set_source($newsource);
}
// Updated sort order
if ($oldfile->get_sortorder() != $newfile->get_sortorder()) {
$oldfile->set_sortorder($newfile->get_sortorder());
}
// Update file timemodified
if ($oldfile->get_timemodified() != $newfile->get_timemodified()) {
$oldfile->set_timemodified($newfile->get_timemodified());
}
// Replaced file content
if (!$oldfile->is_directory() &&
($oldfile->get_contenthash() != $newfile->get_contenthash() ||
$oldfile->get_filesize() != $newfile->get_filesize() ||
$oldfile->get_referencefileid() != $newfile->get_referencefileid() ||
$oldfile->get_userid() != $newfile->get_userid())) {
$oldfile->replace_file_with($newfile);
}
// unchanged file or directory - we keep it as is
unset($newhashes[$oldhash]);
}
// Add fresh file or the file which has changed status
// the size and subdirectory tests are extra safety only, the UI should prevent it
foreach ($newhashes as $file) {
$file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'timemodified'=>time());
if ($source = @unserialize($file->get_source())) {
// Field files.source for draftarea files contains serialised object with source and original information.
// We only store the source part of it for non-draft file area.
$file_record['source'] = $source->source;
}
if ($file->is_external_file()) {
$repoid = $file->get_repository_id();
if (!empty($repoid)) {
$context = context::instance_by_id($contextid, MUST_EXIST);
$repo = repository::get_repository_by_id($repoid, $context);
if (!empty($options)) {
$repo->options = $options;
}
$file_record['repositoryid'] = $repoid;
// This hook gives the repo a place to do some house cleaning, and update the $reference before it's saved
// to the file store. E.g. transfer ownership of the file to a system account etc.
$reference = $repo->reference_file_selected($file->get_reference(), $context, $component, $filearea, $itemid);
$file_record['reference'] = $reference;
}
}
// Changes for PDFAnnotator.
$newentry = $fs->create_file_from_storedfile($file_record, $file);
// Checks if the file size exceeds the max size of files in the PDFAnnotator setting.
$maxfilesize = get_config('mod_pdfannotator', 'maxbytes');
if ($maxfilesize != 0 && $maxfilesize < $newentry->get_filesize()) {
$params = new stdClass();
$params->filename = $newentry->get_filename();
$params->filesize = $newentry->get_filesize();
$params->maxfilesize = $maxfilesize;
throw new Error(get_string('error:maxsizeoffiles', 'mod_pdfannotator', $params));
}
// Changes for PDFAnnotator.
$embeddedfile_pdfannotator = new stdClass();
$embeddedfile_pdfannotator->fileid = $newentry->get_id();
$embeddedfile_pdfannotator->commentid = $itemid;
$embeddedfile_pdfannotator->id = $DB->insert_record('pdfannotator_embeddedfiles', $embeddedfile_pdfannotator);
// Set the sortorder for the mapping with pdfannotator_embeddedfiles table.
$newentry->set_sortorder($embeddedfile_pdfannotator->id);
}
}
// note: do not purge the draft area - we clean up areas later in cron,
// the reason is that user might press submit twice and they would loose the files,
// also sometimes we might want to use hacks that save files into two different areas
if (is_null($text)) {
return null;
} else {
return file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps);
}
}
function pdfannotator_get_instance_name($id) {
global $DB;
......
......@@ -6024,11 +6024,13 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
var rectObj;
var _svg=void 0;
var rect=void 0;
/**
* Get the current window selection as rects
*
* @return {Array} An Array of rects
*/function getSelectionRects(){
*/
function getSelectionRects(){
try{
var selection=window.getSelection();
try{
......@@ -6048,11 +6050,13 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
}
return null;
}/**
}
/**
* Handle document.mousedown event
*
* @param {Event} e The DOM event to handle
*/function handleDocumentMousedown(e){
*/
function handleDocumentMousedown(e){
if(!(_svg=(0,_utils.findSVGAtPoint)(e.clientX,e.clientY))|| _type!=='area'){
return;
}
......@@ -6105,12 +6109,12 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
(0,_utils.disableUserSelect)();
}
/**
* Handle document.mousemove event
*
* @param {Event} e The DOM event to handle
*/function handleDocumentMousemove(e){
*/
function handleDocumentMousemove(e){
if(originX+(e.clientX-originX)<rect.right){
overlay.style.width=e.clientX-originX+'px';
}
......@@ -6143,7 +6147,8 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
* Handle document.mouseup event
* concerns area,highlight and strikeout
* @param {Event} e The DOM event to handle
*/function handleDocumentMouseup(e){
*/
function handleDocumentMouseup(e){
//if the cursor is clicked nothing should happen!
if((typeof e.target.getAttribute('className')!='string') && e.target.className.indexOf('cursor') === -1){
document.removeEventListener('mousemove',handleDocumentMousemove);
......@@ -6280,7 +6285,8 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
* Handle document.keyup event
*
* @param {Event} e The DOM event to handle
*/function handleDocumentKeyup(e){// Cancel rect if Esc is pressed
*/
function handleDocumentKeyup(e){// Cancel rect if Esc is pressed
if(e.keyCode===27){var selection=window.getSelection();selection.removeAllRanges();if(overlay&&overlay.parentNode){overlay.parentNode.removeChild(overlay);overlay=null;document.removeEventListener('mousemove',handleDocumentMousemove);}}
}
......@@ -6403,7 +6409,8 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
}
/**
* Enable rect behavior
*/function enableRect(type){
*/
function enableRect(type){
_type=type;
if(_enabled){return;}
......@@ -6422,9 +6429,11 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to
document.addEventListener('touchstart', handleDocumentTouchstart);
document.addEventListener('touchend', handleDocumentTouchend);
}/**
}
/**
* Disable rect behavior
*/function disableRect(){
*/
function disableRect(){
if(!_enabled){return;}
_enabled=false;
if(_type === 'area'){
......
......@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'mod_pdfannotator';
$plugin->version = 2022102602;
$plugin->version = 2022110200;
$plugin->release = 'PDF Annotator v1.4 release 11';
$plugin->requires = 2021051700;
$plugin->maturity = MATURITY_STABLE;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment