diff --git a/app/controllers/materialien/files.php b/app/controllers/materialien/files.php
index 6f457677483cb8a83ac6b568c29164884b55a7c9..429a98c5d94b2f01227ad845a74af9725dc7346d 100644
--- a/app/controllers/materialien/files.php
+++ b/app/controllers/materialien/files.php
@@ -362,29 +362,37 @@ class Materialien_FilesController extends MVVController
 
     public function upload_attachment_action()
     {
-        if ($GLOBALS['user']->id === "nobody") {
+        $user = User::findCurrent();
+        if (!$user) {
             throw new AccessDeniedException();
         }
 
-        $file = $_FILES['file'];
-        $output = [
-            'name' => $file['name'],
-            'size' => $file['size']];
-
         $mvvfile_id = Request::option('mvvfile_id');
-        $output['mvvfile_id'] = $mvvfile_id;
-        $range_id = Request::option('range_id', $mvvfile_id);
-        $output['range_id'] = $range_id;
-        $file_language = Request::option('file_language');
+        $document_id = Request::option('document_id');
 
-        $top_folder = $this->getTopFolder($mvvfile_id);
-
-        $user = User::findCurrent();
-
-        $file = StandardFile::create($_FILES['file']);
-        $error = $top_folder->validateUpload($file, $GLOBALS['user']->id);
-        if ($error != null) {
-            $file->delete();
+        $file = $_FILES['file'];
+        $output = [
+            'name'       => $file['name'],
+            'size'       => $file['size'],
+            'mvvfile_id' => $mvvfile_id,
+            'range_id'   => Request::option('range_id', $mvvfile_id),
+        ];
+
+        $top_folder = $this->getTopFolder($output['mvvfile_id']);
+
+        if ($document_id) {
+            $file = File::find($document_id);
+            $file->mime_type = $_FILES['file']['type'] ?? get_mime_type($_FILES['file']['name']);
+            $file->size = $_FILES['file']['size'] ?? filesize($_FILES['file']['tmp_name']);
+            $file->connectWithDataFile($_FILES['file']['tmp_name']);
+        } else {
+            $file = StandardFile::create($_FILES['file']);
+        }
+        $error = $top_folder->validateUpload($file, $user->id);
+        if ($error !== null) {
+            if (!$document_id) {
+                $file->delete();
+            }
             $this->response->set_status(400);
             $this->render_json(compact('error'));
             return;
@@ -399,18 +407,15 @@ class Materialien_FilesController extends MVVController
             return;
         }
 
-        $mvv_file_fileref = new MvvFileFileref([$mvvfile_id, $file_language]);
-        $mvv_file_fileref->fileref_id = $file->getId();
+        $mvv_file_fileref = new MvvFileFileref([
+            $output['mvvfile_id'],
+            Request::option('file_language'),
+        ]);
+        $mvv_file_fileref->fileref_id = $file->id;
         $mvv_file_fileref->store();
 
-        $output['document_id'] = $file->getId();
-
-        $output['icon'] = Icon::create(
-            FileManager::getIconNameForMimeType(
-                $file->getMimeType()
-            ),
-            'clickable'
-        )->asImg(['class' => "text-bottom"]);
+        $output['document_id'] = $file->id;
+        $output['icon'] = $file->getIcon(Icon::ROLE_CLICKABLE)->asImg(['class' => 'text-bottom']);
 
         $this->render_json($output);
     }
diff --git a/app/views/materialien/files/add_dokument.php b/app/views/materialien/files/add_dokument.php
index 3b706e90b473d03664c54dcb639b47b872b3e788..a940e95a24cedb319ebf68b556947666652d151e 100644
--- a/app/views/materialien/files/add_dokument.php
+++ b/app/views/materialien/files/add_dokument.php
@@ -47,7 +47,18 @@
                                 <span class="icon"></span>
                                 <span class="name"></span>
                                 <span class="size"></span>
-                                <a class="remove_attachment"><?= Icon::create('trash')->asImg(['class' => 'text-bottom']) ?></a>
+                                <button class="refresh_attachment as-link" data-language="<?= htmlReady($key) ?>">
+                                    <?= Icon::create('refresh')->asImg([
+                                        'class' => 'text-bottom',
+                                        'title' => _('Datei aktualisieren'),
+                                    ]) ?>
+                                </button>
+                                <button class="remove_attachment as-link">
+                                    <?= Icon::create('trash')->asImg([
+                                        'class' => 'text-bottom',
+                                        'title' => _('Datei löschen'),
+                                    ]) ?>
+                                </button>
                             </li>
                         </ul>
                         <div id="statusbar_container">
@@ -79,7 +90,18 @@
                             <span class="icon"><?= Icon::create('file', Icon::ROLE_INFO, ['class' => 'text-bottom']); ?></span>
                             <span class="name"><?= htmlReady($documents[$key]->filename) ?></span>
                             <span class="size"></span>
-                            <a class="remove_attachment"><?= Icon::create('trash', 'clickable')->asImg(['class' => "text-bottom"]) ?></a>
+                            <button class="refresh_attachment as-link" data-language="<?= htmlReady($key) ?>">
+                                <?= Icon::create('refresh')->asImg([
+                                    'class' => 'text-bottom',
+                                    'title' => _('Datei aktualisieren'),
+                                ]) ?>
+                            </button>
+                            <button class="remove_attachment as-link">
+                                <?= Icon::create('trash')->asImg([
+                                    'class' => 'text-bottom',
+                                    'title' => _('Datei löschen'),
+                                ]) ?>
+                            </button>
                         </li>
                     <? endif; ?>
                     </ul>
diff --git a/lib/filesystem/MVVFolder.php b/lib/filesystem/MVVFolder.php
index c5373b97d514923c7d5a5c425f78d533cc75e2b3..2d153dc8090b75337c725f7fc3062314cbf52d15 100644
--- a/lib/filesystem/MVVFolder.php
+++ b/lib/filesystem/MVVFolder.php
@@ -82,7 +82,7 @@ class MVVFolder extends StandardFolder
         if ($folder) {
             $topfolder = $folder->getTypedFolder();
         }
-        return $topfolder ?: null;
+        return $topfolder ?? null;
     }
 
     /**
diff --git a/lib/filesystem/StandardFolder.php b/lib/filesystem/StandardFolder.php
index bbbb1fcb3935f6e7c3ff210d82cdf7857f036e2b..c387bb9b812d23aa4372679ecd549754c19e519c 100644
--- a/lib/filesystem/StandardFolder.php
+++ b/lib/filesystem/StandardFolder.php
@@ -224,14 +224,13 @@ class StandardFolder implements FolderType
     }
 
     /**
-     * @param FileType $newfile
-     * @param string $user_id
+     * @param string   $user_id
      * @return string
      */
-    public function validateUpload(FileType $newfile, $user_id)
+    public function validateUpload(FileType $file, $user_id)
     {
         $upload_type = FileManager::getUploadTypeConfig($this->range_id, $user_id);
-        return $this->getValidationMessages($upload_type, $newfile);
+        return $this->getValidationMessages($upload_type, $file);
     }
 
     protected function getValidationMessages($upload_type, $newfile)
@@ -256,6 +255,8 @@ class StandardFolder implements FolderType
         if (in_array($ext, $types) && $upload_type['type'] === 'allow') {
             return sprintf(_('Sie dürfen den Dateityp %s nicht hochladen!'), $ext);
         }
+
+        return null;
     }
 
     /**
diff --git a/resources/assets/javascripts/mvv.js b/resources/assets/javascripts/mvv.js
index a339624b60864457817341cf5185f3cfe6c0dbc1..92dcd6878acd96395b8c64a6efa35efbfc00b760 100644
--- a/resources/assets/javascripts/mvv.js
+++ b/resources/assets/javascripts/mvv.js
@@ -67,10 +67,17 @@ jQuery(function ($) {
     });
 
     $(document).on('click', '.stgfile .remove_attachment', function($event) {
-        STUDIP.MVV.Document.remove_attachment($(this));
+        STUDIP.Dialog.confirm($gettext('Soll die Datei wirklich gelöscht werden?')).done(() => {
+            STUDIP.MVV.Document.remove_attachment(this);
+        });
         return false;
     });
 
+    $(document).on('click', '.stgfile .refresh_attachment', (event) => {
+        STUDIP.MVV.Document.refresh_attachment(event.target);
+        event.preventDefault();
+    });
+
     STUDIP.dialogReady(
         function() {
 
@@ -663,27 +670,55 @@ STUDIP.MVV.Document = {
             })
         }, 100);
     },
-    remove_attachment: function(item) {
-        jQuery.ajax({
-            url: STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/materialien/files/delete_attachment',
-            data: {
-                mvvfile_id: jQuery('#mvvfile_id').val(),
-                fileref_id: item.closest('li')
-                                .find('input[name=document_id]')
-                                .val()
-            },
-            type: 'POST'
+    refresh_attachment(item) {
+        const language = item.closest('button').dataset.language;
+        const document_id = item.closest('.stgfile').querySelector('[name="document_id"]').value;
+
+        const input = document.createElement('input');
+        input.type = 'file';
+        input.hidden = true;
+
+        input.addEventListener('cancel', () => {
+            input.remove();
         });
-        item.parents('td').find('.attachments').toggle();
-        item.closest('li')
-            .fadeOut(300, function() {
-                jQuery(this).remove();
+        input.addEventListener('change', () => {
+            const fd = new FormData();
+            fd.append('file', input.files[0], input.files[0].name);
+            fd.append('mvvfile_id', jQuery('#mvvfile_id').val());
+            fd.append('range_id', jQuery('#range_id').val());
+            fd.append('document_id', document_id);
+            fd.append('file_language', language);
+
+            const statusbar = $('#statusbar_container .statusbar')
+                .first()
+                .clone()
+                .show();
+            statusbar.appendTo('#statusbar_container');
+
+            STUDIP.MVV.Document.upload_file(fd, statusbar, true).then(() => {
+                input.remove();
+            });
+        });
+
+        item.parentNode.after(input);
+        input.click();
+    },
+    remove_attachment(item) {
+        const url = STUDIP.URLHelper.getURL('dispatch.php/materialien/files/delete_attachment', {
+            mvvfile_id: document.getElementById('mvvfile_id').value,
+            fileref_id: item.closest('li').querySelector('input[name=document_id]').value,
+        });
+        $.post(url).done(() => {
+            $(item).closest('td').find('.attachments').toggle();
+            $(item).closest('li').fadeOut(300, function () {
+                this.remove();
                 jQuery('#upload_chooser').show();
             });
+        });
     },
-    upload_from_input: function(input, file_language) {
+    upload_from_input(input, file_language) {
         STUDIP.MVV.Document.upload_files(input.files, file_language);
-        jQuery(input).val('');
+        input.value = '';
     },
     fileIDQueue: 1,
     upload_files: function(files, file_language) {
@@ -701,82 +736,94 @@ STUDIP.MVV.Document = {
             STUDIP.MVV.Document.upload_file(fd, statusbar);
         }
     },
-    upload_file: function(formdata, statusbar) {
-        $.ajax({
-            xhr: function() {
-                var xhrobj = $.ajaxSettings.xhr();
-                if (xhrobj.upload) {
-                    xhrobj.upload.addEventListener(
-                        'progress',
-                        function(event) {
-                            var percent = 0;
-                            var position = event.loaded || event.position;
-                            var total = event.total;
-                            if (event.lengthComputable) {
-                                percent = Math.ceil((position / total) * 100);
-                            }
-                            //Set progress
-                            statusbar.find('.progress').css({ 'min-width': percent + '%', 'max-width': percent + '%' });
-                            statusbar
-                                .find('.progresstext')
-                                .text(percent === 100 ? jQuery('#upload_finished').text() : percent + '%');
-                        },
-                        false
-                    );
+    upload_file(formdata, statusbar, update = false) {
+        return new Promise((resolve, reject) => {
+            $.ajax({
+                xhr() {
+                    var xhrobj = $.ajaxSettings.xhr();
+                    if (xhrobj.upload) {
+                        xhrobj.upload.addEventListener(
+                            'progress',
+                            function(event) {
+                                var percent = 0;
+                                var position = event.loaded || event.position;
+                                var total = event.total;
+                                if (event.lengthComputable) {
+                                    percent = Math.ceil((position / total) * 100);
+                                }
+                                //Set progress
+                                statusbar.find('.progress').css({ 'min-width': percent + '%', 'max-width': percent + '%' });
+                                statusbar
+                                    .find('.progresstext')
+                                    .text(percent === 100 ? jQuery('#upload_finished').text() : percent + '%');
+                            },
+                            false
+                        );
+                    }
+                    return xhrobj;
+                },
+                url: STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/materialien/files/upload_attachment',
+                type: 'POST',
+                contentType: false,
+                processData: false,
+                cache: false,
+                data: formdata,
+                dataType: 'json'
+            }).done((data) => {
+                const language = formdata.get('file_language');
+
+                statusbar.find('.progress').css({ 'min-width': '100%', 'max-width': '100%' });
+                var file = jQuery('#fileselector_'+formdata.get('file_language')).find('.stgfiles > .stgfile')
+                    .first()
+                    .clone();
+                file.find('.name').text(data.name);
+                if (data.size < 1024) {
+                    file.find('.size').text(data.size + 'B');
                 }
-                return xhrobj;
-            },
-            url: STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/materialien/files/upload_attachment',
-            type: 'POST',
-            contentType: false,
-            processData: false,
-            cache: false,
-            data: formdata,
-            dataType: 'json'
-        })
-        .done(function(data) {
-            statusbar.find('.progress').css({ 'min-width': '100%', 'max-width': '100%' });
-            var file = jQuery('#fileselector_'+formdata.get('file_language')).find('.stgfiles > .stgfile')
-                .first()
-                .clone();
-            file.find('.name').text(data.name);
-            if (data.size < 1024) {
-                file.find('.size').text(data.size + 'B');
-            }
-            if (data.size > 1024 && data.size < 1024 * 1024) {
-                file.find('.size').text(Math.floor(data.size / 1024) + 'KB');
-            }
-            if (data.size > 1024 * 1024 && data.size < 1024 * 1024 * 1024) {
-                file.find('.size').text(Math.floor(data.size / 1024 / 1024) + 'MB');
-            }
-            if (data.size > 1024 * 1024 * 1024) {
-                file.find('.size').text(Math.floor(data.size / 1024 / 1024 / 1024) + 'GB');
-            }
-            file.find('.icon').html(data.icon);
-            file.find('input[name=document_id]').attr('value', data.document_id);
-            jQuery('#fileviewer_'+formdata.get('file_language')).find('.stgfiles').append(file);
-            jQuery('#fileselector_'+formdata.get('file_language')).toggle();
-            jQuery('#fileselector_'+formdata.get('file_language')).parents('.attachments').toggle();
-            jQuery('#fileselector_'+formdata.get('file_language')).parents('.attachments').find('span').toggle();
-            file.fadeIn(300);
-            statusbar.find('.progresstext').text(jQuery('#upload_received_data').text());
-            statusbar.delay(1000).fadeOut(300, function() {
-                jQuery('#upload_chooser').hide();
-                jQuery(this).remove();
-            });
-        })
-        .fail(function(jqxhr, status, errorThrown) {
-            var error = jqxhr.responseJSON.error;
-
-            statusbar
-                .find('.progress')
-                .addClass('progress-error')
-                .attr('title', error);
-            statusbar.find('.progresstext').html(error);
-            statusbar.on('click', function() {
-                jQuery(this).fadeOut(300, function() {
-                    jQuery(this).remove();
+                if (data.size > 1024 && data.size < 1024 * 1024) {
+                    file.find('.size').text(Math.floor(data.size / 1024) + 'KB');
+                }
+                if (data.size > 1024 * 1024 && data.size < 1024 * 1024 * 1024) {
+                    file.find('.size').text(Math.floor(data.size / 1024 / 1024) + 'MB');
+                }
+                if (data.size > 1024 * 1024 * 1024) {
+                    file.find('.size').text(Math.floor(data.size / 1024 / 1024 / 1024) + 'GB');
+                }
+                file.find('.icon').html(data.icon);
+                file.find('input[name=document_id]').attr('value', data.document_id);
+                if (update) {
+                    $(`#fileviewer_${language} .stgfiles`).empty().append(file);
+                    file.show();
+                } else {
+                    $(`#fileviewer_${language}`).find('.stgfiles').append(file);
+                    $(`#fileselector_${language}`)
+                        .toggle()
+                        .parents('.attachments').toggle()
+                        .find('span').toggle();
+                    file.fadeIn(300);
+                }
+                statusbar.find('.progresstext').text(jQuery('#upload_received_data').text());
+                statusbar.delay(1000).fadeOut(300, function() {
+                    $('#upload_chooser').hide();
+                    this.remove();
                 });
+
+                resolve();
+            }).fail(function(jqxhr, status, errorThrown) {
+                var error = jqxhr.responseJSON.error;
+
+                statusbar
+                    .find('.progress')
+                    .addClass('progress-error')
+                    .attr('title', error);
+                statusbar.find('.progresstext').html(error);
+                statusbar.on('click', function() {
+                    jQuery(this).fadeOut(300, function() {
+                        jQuery(this).remove();
+                    });
+                });
+
+                reject(new Error(error));
             });
         });
     }