Example #1
0
/**
 * Saves files from a draft file area to a real one (merging the list of files).
 * Can rewrite URLs in some content at the same time if desired.
 *
 * @category files
 * @global stdClass $USER
 * @param int $draftitemid the id of the draft area to use. Normally obtained
 *      from file_get_submitted_draft_itemid('elementname') or similar.
 * @param int $contextid This parameter and the next two identify the file area to save to.
 * @param string $component
 * @param string $filearea indentifies the file area.
 * @param int $itemid helps identifies the file area.
 * @param array $options area options (subdirs=>false, maxfiles=-1, maxbytes=0)
 * @param string $text some html content that needs to have embedded links rewritten
 *      to the @@PLUGINFILE@@ form for saving in the database.
 * @param bool $forcehttps force https urls.
 * @return string|null if $text was passed in, the rewritten $text is returned. Otherwise NULL.
 */
function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options = null, $text = null, $forcehttps = false)
{
    global $USER;
    $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)) {
        // 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 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;
        foreach ($draftfiles as $file) {
            if (!$options['subdirs'] && $file->get_filepath() !== '/') {
                continue;
            }
            if (!$allowreferences && $file->is_external_file()) {
                continue;
            }
            if (!$file->is_directory()) {
                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
                    // oversized file - should not get here at all
                    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)) {
                    $file_record['repositoryid'] = $repoid;
                    $file_record['reference'] = $file->get_reference();
                }
            }
            $fs->create_file_from_storedfile($file_record, $file);
        }
    }
    // 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);
    }
}
Example #2
0
 /**
  * Update the calendar entries for this assignment.
  *
  * @param int $coursemoduleid - Required to pass this in because it might
  *                              not exist in the database yet.
  * @return bool
  */
 public function update_calendar($coursemoduleid)
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/calendar/lib.php';
     // Special case for add_instance as the coursemodule has not been set yet.
     $instance = $this->get_instance();
     if ($instance->duedate) {
         $event = new stdClass();
         $params = array('modulename' => 'assign', 'instance' => $instance->id);
         $event->id = $DB->get_field('event', 'id', $params);
         $event->name = $instance->name;
         $event->timestart = $instance->duedate;
         // Convert the links to pluginfile. It is a bit hacky but at this stage the files
         // might not have been saved in the module area yet.
         $intro = $instance->intro;
         if ($draftid = file_get_submitted_draft_itemid('introeditor')) {
             $intro = file_rewrite_urls_to_pluginfile($intro, $draftid);
         }
         // We need to remove the links to files as the calendar is not ready
         // to support module events with file areas.
         $intro = strip_pluginfile_content($intro);
         if ($this->show_intro()) {
             $event->description = array('text' => $intro, 'format' => $instance->introformat);
         } else {
             $event->description = array('text' => '', 'format' => $instance->introformat);
         }
         if ($event->id) {
             $calendarevent = calendar_event::load($event->id);
             $calendarevent->update($event);
         } else {
             unset($event->id);
             $event->courseid = $instance->course;
             $event->groupid = 0;
             $event->userid = 0;
             $event->modulename = 'assign';
             $event->instance = $instance->id;
             $event->eventtype = 'due';
             $event->timeduration = 0;
             calendar_event::create($event);
         }
     } else {
         $DB->delete_records('event', array('modulename' => 'assign', 'instance' => $instance->id));
     }
 }
Example #3
0
/**
 * Saves files from a draft file area to a real one (merging the list of files).
 * Can rewrite URLs in some content at the same time if desired.
 *
 * @global object
 * @global object
 * @param integer $draftitemid the id of the draft area to use. Normally obtained
 *      from file_get_submitted_draft_itemid('elementname') or similar.
 * @param integer $contextid This parameter and the next two identify the file area to save to.
 * @param string $component
 * @param string $filearea indentifies the file area.
 * @param integer $itemid helps identifies the file area.
 * @param array $options area options (subdirs=>false, maxfiles=-1, maxbytes=0)
 * @param string $text some html content that needs to have embedded links rewritten
 *      to the @@PLUGINFILE@@ form for saving in the database.
 * @param boolean $forcehttps force https urls.
 * @return string if $text was passed in, the rewritten $text is returned. Otherwise NULL.
 */
function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options = null, $text = null, $forcehttps = false)
{
    global $USER;
    $usercontext = get_context_instance(CONTEXT_USER, $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'] = 0;
        // unlimited
    }
    $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
    $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id');
    if (count($draftfiles) < 2) {
        // means there are no files - one file means root dir only ;-)
        $fs->delete_area_files($contextid, $component, $filearea, $itemid);
    } else {
        if (count($oldfiles) < 2) {
            $filecount = 0;
            // there were no files before - one file means root dir only ;-)
            $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid);
            foreach ($draftfiles as $file) {
                if (!$options['subdirs']) {
                    if ($file->get_filepath() !== '/' or $file->is_directory()) {
                        continue;
                    }
                }
                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
                    // oversized file - should not get here at all
                    continue;
                }
                if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
                    // more files - should not get here at all
                    break;
                }
                if (!$file->is_directory()) {
                    $filecount++;
                }
                $fs->create_file_from_storedfile($file_record, $file);
            }
        } else {
            // 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
            $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid, 'timemodified' => time());
            $newhashes = array();
            foreach ($draftfiles as $file) {
                $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename());
                $newhashes[$newhash] = $file;
            }
            $filecount = 0;
            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];
                if ($oldfile->get_contenthash() != $newfile->get_contenthash() or $oldfile->get_sortorder() != $newfile->get_sortorder() or $oldfile->get_status() != $newfile->get_status() or $oldfile->get_license() != $newfile->get_license() or $oldfile->get_author() != $newfile->get_author() or $oldfile->get_source() != $newfile->get_source()) {
                    // file was changed, use updated with new timemodified data
                    $oldfile->delete();
                    continue;
                }
                // unchanged file or directory - we keep it as is
                unset($newhashes[$oldhash]);
                if (!$oldfile->is_directory()) {
                    $filecount++;
                }
            }
            // now add new/changed files
            // the size and subdirectory tests are extra safety only, the UI should prevent it
            foreach ($newhashes as $file) {
                if (!$options['subdirs']) {
                    if ($file->get_filepath() !== '/' or $file->is_directory()) {
                        continue;
                    }
                }
                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
                    // oversized file - should not get here at all
                    continue;
                }
                if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
                    // more files - should not get here at all
                    break;
                }
                if (!$file->is_directory()) {
                    $filecount++;
                }
                $fs->create_file_from_storedfile($file_record, $file);
            }
        }
    }
    // 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);
    }
}
Example #4
0
 /**
  * Compute the value that should be stored in the question_attempt_step_data
  * table. Contains a hash that (almost) uniquely encodes all the files.
  * @param int $draftitemid the draft file area itemid.
  * @param string $text optional content containing file links.
  */
 protected function compute_value($draftitemid, $text)
 {
     global $USER;
     $fs = get_file_storage();
     $usercontext = context_user::instance($USER->id);
     $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'sortorder, filepath, filename', false);
     $string = '';
     foreach ($files as $file) {
         $string .= $file->get_filepath() . $file->get_filename() . '|' . $file->get_contenthash() . '|';
     }
     $hash = md5($string);
     if (is_null($text)) {
         if ($string) {
             return $hash;
         } else {
             return '';
         }
     }
     // We add the file hash so a simple string comparison will say if the
     // files have been changed. First strip off any existing file hash.
     if ($text !== '') {
         $text = preg_replace('/\\s*<!-- File hash: \\w+ -->\\s*$/', '', $text);
         $text = file_rewrite_urls_to_pluginfile($text, $draftitemid);
         if ($string) {
             $text .= '<!-- File hash: ' . $hash . ' -->';
         }
     }
     return $text;
 }
Example #5
0
/**
 * Saves files from a draft file area to a real one (merging the list of files).
 * Can rewrite URLs in some content at the same time if desired.
 *
 * @category files
 * @global stdClass $USER
 * @param int $draftitemid the id of the draft area to use. Normally obtained
 *      from file_get_submitted_draft_itemid('elementname') or similar.
 * @param int $contextid This parameter and the next two identify the file area to save to.
 * @param string $component
 * @param string $filearea indentifies the file area.
 * @param int $itemid helps identifies the file area.
 * @param array $options area options (subdirs=>false, maxfiles=-1, maxbytes=0)
 * @param string $text some html content that needs to have embedded links rewritten
 *      to the @@PLUGINFILE@@ form for saving in the database.
 * @param bool $forcehttps force https urls.
 * @return string|null if $text was passed in, the rewritten $text is returned. Otherwise NULL.
 */
function file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options = null, $text = null, $forcehttps = false)
{
    global $USER;
    $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
    }
    $allowreferences = true;
    if (isset($options['return_types']) && !($options['return_types'] & FILE_REFERENCE)) {
        // 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;
    }
    $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
    $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id');
    if (count($draftfiles) < 2) {
        // means there are no files - one file means root dir only ;-)
        $fs->delete_area_files($contextid, $component, $filearea, $itemid);
    } else {
        if (count($oldfiles) < 2) {
            $filecount = 0;
            // there were no files before - one file means root dir only ;-)
            foreach ($draftfiles as $file) {
                $file_record = array('contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid);
                if (!$options['subdirs']) {
                    if ($file->get_filepath() !== '/' or $file->is_directory()) {
                        continue;
                    }
                }
                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
                    // oversized file - should not get here at all
                    continue;
                }
                if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
                    // more files - should not get here at all
                    break;
                }
                if (!$file->is_directory()) {
                    $filecount++;
                }
                if ($file->is_external_file()) {
                    if (!$allowreferences) {
                        continue;
                    }
                    $repoid = $file->get_repository_id();
                    if (!empty($repoid)) {
                        $file_record['repositoryid'] = $repoid;
                        $file_record['reference'] = $file->get_reference();
                    }
                }
                file_restore_source_field_from_draft_file($file);
                $fs->create_file_from_storedfile($file_record, $file);
            }
        } else {
            // 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();
            foreach ($draftfiles as $file) {
                $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename());
                file_restore_source_field_from_draft_file($file);
                $newhashes[$newhash] = $file;
            }
            $filecount = 0;
            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];
                // 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
                if ($oldfile->get_source() != $newfile->get_source()) {
                    $oldfile->set_source($newfile->get_source());
                }
                // 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->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) {
                    $oldfile->replace_content_with($newfile);
                    // push changes to all local files that are referencing this file
                    $fs->update_references_to_storedfile($oldfile);
                }
                // unchanged file or directory - we keep it as is
                unset($newhashes[$oldhash]);
                if (!$oldfile->is_directory()) {
                    $filecount++;
                }
            }
            // 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 (!$options['subdirs']) {
                    if ($file->get_filepath() !== '/' or $file->is_directory()) {
                        continue;
                    }
                }
                if ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize()) {
                    // oversized file - should not get here at all
                    continue;
                }
                if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) {
                    // more files - should not get here at all
                    break;
                }
                if (!$file->is_directory()) {
                    $filecount++;
                }
                if ($file->is_external_file()) {
                    if (!$allowreferences) {
                        continue;
                    }
                    $repoid = $file->get_repository_id();
                    if (!empty($repoid)) {
                        $file_record['repositoryid'] = $repoid;
                        $file_record['reference'] = $file->get_reference();
                    }
                }
                $fs->create_file_from_storedfile($file_record, $file);
            }
        }
    }
    // 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);
    }
}
 /**
  * Update the calendar entries for this assignment.
  *
  * @param \stdClass $collaborate- collaborate record
  *
  * @return bool
  */
 public static function update_calendar($collaborate)
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/calendar/lib.php';
     $event = new \stdClass();
     $params = array('modulename' => 'collaborate', 'instance' => $collaborate->id);
     $event->id = $DB->get_field('event', 'id', $params);
     $event->name = $collaborate->name;
     $event->timestart = $collaborate->timestart;
     // Convert the links to pluginfile. It is a bit hacky but at this stage the files
     // might not have been saved in the module area yet.
     $intro = $collaborate->intro;
     if ($draftid = file_get_submitted_draft_itemid('introeditor')) {
         $intro = file_rewrite_urls_to_pluginfile($intro, $draftid);
     }
     // We need to remove the links to files as the calendar is not ready
     // to support module events with file areas.
     $intro = strip_pluginfile_content($intro);
     $event->description = array('text' => $intro, 'format' => $collaborate->introformat);
     if ($event->id) {
         $calendarevent = \calendar_event::load($event->id);
         $calendarevent->update($event);
     } else {
         unset($event->id);
         $event->courseid = $collaborate->course;
         $event->groupid = 0;
         $event->userid = 0;
         $event->modulename = 'collaborate';
         $event->instance = $collaborate->id;
         $event->eventtype = 'due';
         $event->timeend = self::timeend_from_duration($collaborate->timestart, $collaborate->duration);
         if (!empty($event->timeend)) {
             $event->timeduration = $event->timeend - $event->timestart;
         } else {
             $event->timeduration = 0;
         }
         \calendar_event::create($event);
     }
 }
 public function save()
 {
     global $DB, $USER;
     $admin = get_admin();
     // possible cronjob
     if ($USER->id != $admin->id and $USER->id != $this->_authorid) {
         throw new \moodle_exception("This doesn't belong to you!");
     }
     $context = $this->dialogue->context;
     // needed for filelib functions
     $dialogueid = $this->dialogue->dialogueid;
     $conversationid = $this->conversation->conversationid;
     $record = new \stdClass();
     $record->id = $this->_messageid;
     $record->dialogueid = $dialogueid;
     $record->conversationid = $conversationid;
     $record->conversationindex = $this->_conversationindex;
     $record->authorid = $this->_authorid;
     // rewrite body now if has embedded files
     if (dialogue_contains_draft_files($this->_bodydraftid)) {
         $record->body = file_rewrite_urls_to_pluginfile($this->_body, $this->_bodydraftid);
     } else {
         $record->body = $this->_body;
     }
     $record->bodyformat = $this->_bodyformat;
     // mark atttachments now if has them
     if (dialogue_contains_draft_files($this->_attachmentsdraftid)) {
         $record->attachments = 1;
     } else {
         $record->attachments = 0;
     }
     $record->state = $this->_state;
     $record->timecreated = $this->_timecreated;
     $record->timemodified = $this->_timemodified;
     if (is_null($this->_messageid)) {
         // create new record
         $this->_messageid = $DB->insert_record('dialogue_messages', $record);
     } else {
         $record->timemodified = time();
         // update existing record
         $DB->update_record('dialogue_messages', $record);
     }
     // deal with embedded files
     if ($this->_bodydraftid) {
         file_save_draft_area_files($this->_bodydraftid, $context->id, 'mod_dialogue', 'message', $this->_messageid);
     }
     // deal with attached files
     if ($this->_attachmentsdraftid) {
         file_save_draft_area_files($this->_attachmentsdraftid, $context->id, 'mod_dialogue', 'attachment', $this->_messageid);
     }
     return true;
 }