Перейти к содержанию

Удаление файлов с возможностью восстановления

В системе поддерживается функциональность удаления файла с возможностью его восстановления, если эта опция включена в карточке Настройки сервера. По умолчанию удаление файла в корзину поддерживается только в файловом контроле карточки. Для управления и расширения данной функциональности необходимо написать клиентские и серверные расширения.

Удаление файла

Если файл удаляется из файлового контейнера IFileContainer или IFileUIContainer, то можно воспользоваться методом расширения RemoveWithNotificationAsync, который удалит файл с уведомлением его источника. Например, перед сохранением карточки выполните следующий код на клиенте или сервере:

// Получение файлового контейнера из файлового менеджера или контекста IFileContainer fileContainer = ... // Поиск необходимого файла в контейнере для удаления IFile fileToRemove = fileContainer.Files.FirstOrDefault(x => x.Name == "file.txt"); if (fileToRemove is not null) { // Удаление файла с возможностью восстановления bool removed = await fileContainer.Files.RemoveWithNotificationAsync(fileToRemove, withBackup: true, cancellationToken); }

Код, указанный выше, установит для свойства CardFile.DeletionMode значение CardFileDeletionMode.Backup.

Important

Значение CardFileDeletionMode.Backup учитывается, только если в свойстве CardFile.State установлено CardFileState.Deleted. При сохранении карточки с расширениями на сервере для всех удалённых файлов будет выполнена проверка свойств CardFile.State и CardFile.DeletionMode. Если файл удаляется с возможностью восстановления, а в системе отключена опция удаления файла с возможностью восстановления (см. Настройки сервера), то для свойства CardFile.DeletionMode будет установлено значение CardFileDeletionMode.None. Учитывайте это при написании расширений.

При удалении файла в корзину записи из таблиц Files и FileVersions будут перенесены в таблицы DeletedFiles и DeletedFileVersions. Также записи из всех секций, которые содержатся в метаданных типа файла, будут перенесены в таблицы с префиксом Deleted. Например, таковой таблицей является DeletedFileSignatures.

Important

Если в решении изменялись типовые карточки файлов или были добавлены собственные типы карточек файлов, то для используемых в них секций необходимо добавить соответствующие таблицы с префиксом Deleted для корректного удаления файла с возможностью восстановления.

Если при удалении файла требуется выполнить бэкап, восстановление или полное удаление связанных данных, то необходимо написать расширение на сохранение карточки с проверкой способа удаления файла. Например:

/// <summary> /// Расширение для работы со связанными данными при удалении и восстановлении файла. /// </summary> public sealed class ManageLinkedDataStoreExtension : CardStoreExtension { #region Fields

private readonly ICardFileBackupSettings cardFileBackupSettings;

#endregion

#region Constructors

/// <summary> /// Создаёт экземпляр класса <see cref="ManageLinkedDataStoreExtension"/>. /// </summary> /// <param name="cardFileBackupSettings"><inheritdoc cref="ICardFileBackupSettings" path="/summary"/></param> public BackupCardFileStoreExtension(ICardFileBackupSettings cardFileBackupSettings) => this.cardFileBackupSettings = NotNullOrThrow(cardFileBackupSettings);

#endregion

#region Base Overrides

/// <inheritdoc/> public override async Task BeforeCommitTransaction(ICardStoreExtensionContext context) { if (context.ValidationResult.IsSuccessful() && context.Request.Card.TryGetFiles() is { Count: > 0 } files) { if (await this.cardFileBackupSettings.CanDeleteWithBackupAsync(context.ValidationResult, context.CancellationToken)) { // в системе поддерживается удаление файлов в корзину }

foreach (var file in files) { if (file is { State: CardFileState.Deleted, DeletionMode: not CardFileDeletionMode.Backup }) { // файл удаляется без корзины } else if (file is { State: CardFileState.None, DeletionMode: CardFileDeletionMode.Wipe }) { // файл удаляется из корзины } else if (file is { State: CardFileState.Deleted, DeletionMode: CardFileDeletionMode.Backup }) { // файл удаляется в корзину } else if (file is { State: CardFileState.Inserted, DeletionMode: CardFileDeletionMode.Restore }) { // файл восстанавливается из корзины } } } }

#endregion }

Регистрация такого расширения выглядит следующим образом:

[Registrator] public sealed class Registrator : RegistratorBase { public override void RegisterExtensions(IExtensionContainer extensionContainer) { extensionContainer .RegisterExtension<ICardStoreExtension, CardFileBackupStoreExtension>(x => x .WithOrder(ExtensionStage.AfterPlatform, 1) .WithSingleton() // если расширение использует зависимости, то необходим использовать Unity .WhenAnyStoreMethod() // тут может быть фильтрация по способу сохранения карточки .WhenAnyCardType()); // тут может быть фильтрация по типу карточки } }

Пример такого расширения для переноса аннотаций, добавленных к удаляемому файлу можно посмотреть в Tessa.Extensions.Default.Server.PdfAnnotations.PdfAnnotationsStoreExtension.

Восстановление файла

Для восстановления файла необходимо добавить в карточку новый файл, в котором для свойства CardFile.DeletionMode установлено значение CardFileDeletionMode.Restore.

Important

Значение CardFileDeletionMode.Restore учитывается, только если в свойстве CardFile.State установлено CardFileState.Inserted.

Добавление нового файла выполняет платформенное расширение RestoreCardFileStoreExtension. Оно опирается на ключ CardHelper.FilesToRestoreKey для получения коллекции восстанавливаемых файлов. Чтобы добавить данный ключ при сохранении карточки необходимо написать следующий код:

await using var _ = dbScope.Create();

// получение информации об удалённых файлах

var deletedFiles = await dbScope.Db .SetCommand( dbScope.BuilderFactory .Select().C("f", nameof(CardFileDeletedInfo.RowID), nameof(CardFileDeletedInfo.Deleted), nameof(CardFileDeletedInfo.DeletedByID), nameof(CardFileDeletedInfo.DeletedByName)) .From("DeletedFiles", "f").NoLock() .Where().C("f", "ID").Equals().P("CardID") .Build(), dbScope.Db.Parameter("CardID", cardID, DataType.Guid)) .LogCommand() .ExecuteListAsync<CardFileDeletedInfo>(cancellationToken);

// установка ключа в Info сохраняемой карточки

card.Info = [CardHelper.FilesToRestoreKey] = deletedFiles .Select(f => (object) f.ToSerializedDictionary()) .ToList();

На клиенте можно выполнить запрос на сервер или воспользоваться данными из представления DeletedFiles (см. пример Tessa.Extensions.Default.Client.Files.RestoreFileControlExtension).

Back to top