1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 02:13:21 +08:00

Move deletion to ArchiveModelImportManager

This commit is contained in:
Dean Herbert 2018-02-15 12:21:11 +09:00
parent d8f84fcca3
commit 6ff63c2f0c
10 changed files with 76 additions and 61 deletions

View File

@ -97,10 +97,10 @@ namespace osu.Game.Beatmaps
b.Metadata = null;
}
protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo beatmapSet)
protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model)
{
// check if this beatmap has already been imported and exit early if so
var existingHashMatch = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == beatmapSet.Hash);
var existingHashMatch = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == model.Hash);
if (existingHashMatch != null)
{
Undelete(existingHashMatch);
@ -108,9 +108,9 @@ namespace osu.Game.Beatmaps
}
// check if a set already exists with the same online id
if (beatmapSet.OnlineBeatmapSetID != null)
if (model.OnlineBeatmapSetID != null)
{
var existingOnlineId = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == beatmapSet.OnlineBeatmapSetID);
var existingOnlineId = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID);
if (existingOnlineId != null)
{
Delete(existingOnlineId);
@ -217,32 +217,6 @@ namespace osu.Game.Beatmaps
/// <param name="beatmapSet">The beatmap set to update.</param>
public void Update(BeatmapSetInfo beatmap) => beatmaps.Update(beatmap);
/// <summary>
/// Delete a beatmap from the manager.
/// Is a no-op for already deleted beatmaps.
/// </summary>
/// <param name="beatmapSet">The beatmap set to delete.</param>
public void Delete(BeatmapSetInfo beatmapSet)
{
using (var usage = ContextFactory.GetForWrite())
{
var context = usage.Context;
context.ChangeTracker.AutoDetectChangesEnabled = false;
// re-fetch the beatmap set on the import context.
beatmapSet = context.BeatmapSetInfo.Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == beatmapSet.ID);
if (beatmaps.Delete(beatmapSet))
{
if (!beatmapSet.Protected)
Files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
}
context.ChangeTracker.AutoDetectChangesEnabled = true;
}
}
/// <summary>
/// Restore all beatmaps that were previously deleted.
/// This will post notifications tracking progress.
@ -351,7 +325,7 @@ namespace osu.Game.Beatmaps
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
/// </summary>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public List<BeatmapSetInfo> GetAllUsableBeatmapSets() => beatmaps.BeatmapSets.Where(s => !s.DeletePending).ToList();
public List<BeatmapSetInfo> GetAllUsableBeatmapSets() => beatmaps.BeatmapSets.Where(s => !s.DeletePending && !s.Protected).ToList();
/// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.

View File

@ -9,7 +9,7 @@ using osu.Game.IO;
namespace osu.Game.Beatmaps
{
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }

View File

@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps
/// <summary>
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
/// </summary>
public class BeatmapStore : DatabaseBackedStore, IAddableStore<BeatmapSetInfo>
public class BeatmapStore : DatabaseBackedStore, IMutableStore<BeatmapSetInfo>
{
public event Action<BeatmapSetInfo> BeatmapSetAdded;
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
@ -79,7 +79,7 @@ namespace osu.Game.Beatmaps
{
Refresh(ref beatmapSet, BeatmapSets);
if (beatmapSet.DeletePending) return false;
if (beatmapSet.Protected || beatmapSet.DeletePending) return false;
beatmapSet.DeletePending = true;
}
@ -178,17 +178,17 @@ namespace osu.Game.Beatmaps
}
public IQueryable<BeatmapSetInfo> BeatmapSets => ContextFactory.Get().BeatmapSetInfo
.Include(s => s.Metadata)
.Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
.Include(s => s.Files).ThenInclude(f => f.FileInfo);
.Include(s => s.Metadata)
.Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
.Include(s => s.Files).ThenInclude(f => f.FileInfo);
public IQueryable<BeatmapInfo> Beatmaps => ContextFactory.Get().BeatmapInfo
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
.Include(b => b.BeatmapSet).ThenInclude(s => s.Files).ThenInclude(f => f.FileInfo)
.Include(b => b.Metadata)
.Include(b => b.Ruleset)
.Include(b => b.BaseDifficulty);
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
.Include(b => b.BeatmapSet).ThenInclude(s => s.Files).ThenInclude(f => f.FileInfo)
.Include(b => b.Metadata)
.Include(b => b.Ruleset)
.Include(b => b.BaseDifficulty);
}
}

View File

@ -1,20 +1,22 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ionic.Zip;
using Microsoft.EntityFrameworkCore;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.IO;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.IPC;
using osu.Game.Overlays.Notifications;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Beatmaps
namespace osu.Game.Database
{
public abstract class ArchiveModelImportManager<TModel, TFileModel> : ICanImportArchives
where TModel : class, IHasFiles<TFileModel>
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
where TFileModel : INamedFileInfo, new()
{
/// <summary>
@ -28,12 +30,12 @@ namespace osu.Game.Beatmaps
protected readonly IDatabaseContextFactory ContextFactory;
protected readonly IAddableStore<TModel> ModelStore;
protected readonly IMutableStore<TModel> ModelStore;
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private ArchiveImportIPCChannel ipc;
protected ArchiveModelImportManager(Storage storage, IDatabaseContextFactory contextFactory, IAddableStore<TModel> modelStore, IIpcHost importHost = null)
protected ArchiveModelImportManager(Storage storage, IDatabaseContextFactory contextFactory, IMutableStore<TModel> modelStore, IIpcHost importHost = null)
{
ContextFactory = contextFactory;
ModelStore = modelStore;
@ -127,6 +129,31 @@ namespace osu.Game.Beatmaps
}
}
/// <summary>
/// Delete a model from the manager.
/// Is a no-op for already deleted models.
/// </summary>
/// <param name="model">The model to delete.</param>
public void Delete(TModel model)
{
using (var usage = ContextFactory.GetForWrite())
{
var context = usage.Context;
context.ChangeTracker.AutoDetectChangesEnabled = false;
// re-fetch the model on the import context.
var foundModel = ContextFactory.Get().Set<TModel>().Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == model.ID);
if (foundModel.DeletePending || !CheckCanDelete(foundModel)) return;
if (ModelStore.Delete(foundModel))
Files.Dereference(foundModel.Files.Select(f => f.FileInfo).ToArray());
context.ChangeTracker.AutoDetectChangesEnabled = true;
}
}
/// <summary>
/// Create all required <see cref="FileInfo"/>s for the provided archive, adding them to the global file store.
/// </summary>
@ -164,13 +191,15 @@ namespace osu.Game.Beatmaps
{
}
protected virtual TModel CheckForExisting(TModel beatmapSet) => null;
protected virtual TModel CheckForExisting(TModel model) => null;
protected virtual bool CheckCanDelete(TModel model) => true;
/// <summary>
/// Creates an <see cref="ArchiveReader"/> from a valid storage path.
/// </summary>
/// <param name="path">A file or folder path resolving the beatmap content.</param>
/// <returns>A reader giving access to the beatmap's content.</returns>
/// <param name="path">A file or folder path resolving the archive content.</param>
/// <returns>A reader giving access to the archive's content.</returns>
private ArchiveReader getReaderFrom(string path)
{
if (ZipFile.IsZipFile(path))

View File

@ -1,4 +1,4 @@
namespace osu.Game.Beatmaps
namespace osu.Game.Database
{
public interface ICanImportArchives
{

View File

@ -0,0 +1,10 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Database
{
public interface ISoftDelete
{
bool DeletePending { get; set; }
}
}

View File

@ -3,12 +3,14 @@
namespace osu.Game.IO
{
public interface IAddableStore<in T>
public interface IMutableStore<in T>
{
/// <summary>
/// Add an object to the store.
/// </summary>
/// <param name="object">The object to add.</param>
void Add(T item);
bool Delete(T item);
}
}

View File

@ -6,7 +6,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Database;
namespace osu.Game.IPC
{

View File

@ -63,7 +63,9 @@ namespace osu.Game.Screens.Menu
{
// we need to import the default menu background beatmap
setInfo = beatmaps.Import(new OszArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz"), "circles.osz"));
setInfo.Protected = true;
beatmaps.Update(setInfo);
}
}
@ -73,9 +75,6 @@ namespace osu.Game.Screens.Menu
welcome = audio.Sample.Get(@"welcome");
seeya = audio.Sample.Get(@"seeya");
if (setInfo.Protected)
beatmaps.Delete(setInfo);
}
protected override void OnEntering(Screen last)

View File

@ -243,7 +243,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Audio\SampleInfo.cs" />
<Compile Include="Beatmaps\ArchiveModelImportManager.cs" />
<Compile Include="Beatmaps\Beatmap.cs" />
<Compile Include="Beatmaps\BeatmapConverter.cs" />
<Compile Include="Beatmaps\BeatmapDifficulty.cs" />
@ -271,20 +270,22 @@
<Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
<Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
<Compile Include="Beatmaps\ICanImportArchives.cs" />
<Compile Include="Configuration\DatabasedSetting.cs" />
<Compile Include="Configuration\SettingsStore.cs" />
<Compile Include="Configuration\DatabasedConfigManager.cs" />
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
<Compile Include="Database\ArchiveModelImportManager.cs" />
<Compile Include="Database\DatabaseContextFactory.cs" />
<Compile Include="Database\DatabaseWriteUsage.cs" />
<Compile Include="Database\ICanImportArchives.cs" />
<Compile Include="Database\IDatabaseContextFactory.cs" />
<Compile Include="Database\IHasPrimaryKey.cs" />
<Compile Include="Database\INamedFileInfo.cs" />
<Compile Include="Database\ISoftDelete.cs" />
<Compile Include="Database\SingletonContextFactory.cs" />
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
<Compile Include="IO\IAddableStore.cs" />
<Compile Include="IO\IMutableStore.cs" />
<Compile Include="IO\IHasFiles.cs" />
<Compile Include="Online\API\APIDownloadRequest.cs" />
<Compile Include="Online\API\Requests\GetUserRequest.cs" />