2026-05-14 12:31:35 +02:00
|
|
|
using AuthorBuddy.Web.Data;
|
|
|
|
|
using AuthorBuddy.Web.Models;
|
2026-05-20 06:12:54 +02:00
|
|
|
using LiteDB;
|
2026-05-14 12:31:35 +02:00
|
|
|
|
|
|
|
|
namespace AuthorBuddy.Web.Services;
|
|
|
|
|
|
|
|
|
|
public class ProjectService : IProjectService
|
|
|
|
|
{
|
2026-05-20 06:12:54 +02:00
|
|
|
private readonly ILiteDatabase _db;
|
2026-05-14 12:31:35 +02:00
|
|
|
private readonly IFileScannerService _fileScannerService;
|
|
|
|
|
|
2026-05-20 06:12:54 +02:00
|
|
|
public ProjectService(ILiteDatabase db, IFileScannerService fileScannerService)
|
2026-05-14 12:31:35 +02:00
|
|
|
{
|
2026-05-20 06:12:54 +02:00
|
|
|
_db = db;
|
2026-05-14 12:31:35 +02:00
|
|
|
_fileScannerService = fileScannerService;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-20 06:12:54 +02:00
|
|
|
public Task<int> CreateNewProjectAsync(string projectName, string rootPath)
|
2026-05-14 12:31:35 +02:00
|
|
|
{
|
|
|
|
|
string[] subFolders = { "00_Drafts", "01_Fakten", "02_Characters", "03_Archive" };
|
|
|
|
|
foreach (var subFolder in subFolders)
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(Path.Combine(rootPath, subFolder));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string readmePath = Path.Combine(rootPath, "00_Projekt_Info.md");
|
2026-05-20 06:12:54 +02:00
|
|
|
File.WriteAllText(readmePath, $"# Projekt: {projectName}\nErstellt am: {DateTime.Now}");
|
2026-05-14 12:31:35 +02:00
|
|
|
|
2026-05-20 06:12:54 +02:00
|
|
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
2026-05-14 12:31:35 +02:00
|
|
|
var entity = new ProjectEntity
|
|
|
|
|
{
|
|
|
|
|
Name = projectName,
|
|
|
|
|
RootPath = rootPath,
|
|
|
|
|
LastOpened = DateTime.Now
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-20 06:12:54 +02:00
|
|
|
col.Insert(entity);
|
|
|
|
|
return Task.FromResult(entity.Id);
|
2026-05-14 12:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-20 06:12:54 +02:00
|
|
|
public Task<List<Project>> GetAllProjectsAsync()
|
2026-05-14 12:31:35 +02:00
|
|
|
{
|
2026-05-20 06:12:54 +02:00
|
|
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
|
|
|
|
var list = col.FindAll()
|
2026-05-14 12:31:35 +02:00
|
|
|
.OrderByDescending(p => p.LastOpened)
|
|
|
|
|
.Select(p => new Project
|
|
|
|
|
{
|
|
|
|
|
Id = p.Id,
|
|
|
|
|
Name = p.Name,
|
|
|
|
|
RootPath = p.RootPath
|
|
|
|
|
})
|
2026-05-20 06:12:54 +02:00
|
|
|
.ToList();
|
|
|
|
|
return Task.FromResult(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<Project?> GetProjectAsync(int projectId)
|
|
|
|
|
{
|
|
|
|
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
|
|
|
|
var entity = col.FindById(projectId);
|
|
|
|
|
if (entity == null) return Task.FromResult<Project?>(null);
|
|
|
|
|
return Task.FromResult<Project?>(new Project
|
|
|
|
|
{
|
|
|
|
|
Id = entity.Id,
|
|
|
|
|
Name = entity.Name,
|
|
|
|
|
RootPath = entity.RootPath
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<List<FileTreeItem>> GetProjectFileTreeAsync(int projectId)
|
|
|
|
|
{
|
|
|
|
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
|
|
|
|
var entity = col.FindById(projectId);
|
|
|
|
|
if (entity == null || !Directory.Exists(entity.RootPath))
|
|
|
|
|
return Task.FromResult(new List<FileTreeItem>());
|
|
|
|
|
|
|
|
|
|
var result = new List<FileTreeItem>();
|
|
|
|
|
BuildTree(entity.RootPath, result, 0);
|
|
|
|
|
return Task.FromResult(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void BuildTree(string directory, List<FileTreeItem> items, int depth)
|
|
|
|
|
{
|
|
|
|
|
if (depth > 4) return;
|
|
|
|
|
|
|
|
|
|
var dirInfo = new DirectoryInfo(directory);
|
|
|
|
|
if (!dirInfo.Exists) return;
|
|
|
|
|
|
|
|
|
|
foreach (var dir in dirInfo.GetDirectories().OrderBy(d => d.Name))
|
|
|
|
|
{
|
|
|
|
|
var node = new FileTreeItem
|
|
|
|
|
{
|
|
|
|
|
Name = dir.Name,
|
|
|
|
|
FullPath = dir.FullName,
|
|
|
|
|
IsDirectory = true
|
|
|
|
|
};
|
|
|
|
|
BuildTree(dir.FullName, node.Children, depth + 1);
|
|
|
|
|
if (node.Children.Count > 0 || dir.Name.StartsWith("00_") || dir.Name.StartsWith("01_") || dir.Name.StartsWith("02_"))
|
|
|
|
|
items.Add(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var file in dirInfo.GetFiles("*.md").OrderBy(f => f.Name))
|
|
|
|
|
{
|
|
|
|
|
items.Add(new FileTreeItem
|
|
|
|
|
{
|
|
|
|
|
Name = file.Name,
|
|
|
|
|
FullPath = file.FullName,
|
|
|
|
|
IsDirectory = false
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-05-14 12:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress)
|
|
|
|
|
{
|
|
|
|
|
await _fileScannerService.ScanProjectFolderAsync(projectId, directoryPath, progress);
|
|
|
|
|
}
|
2026-05-25 06:38:16 +02:00
|
|
|
|
|
|
|
|
public Task<int> CopyProjectAsync(int sourceProjectId, string newName, string newRootPath, int userId)
|
|
|
|
|
{
|
|
|
|
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
|
|
|
|
var source = col.FindById(sourceProjectId);
|
|
|
|
|
if (source == null)
|
|
|
|
|
throw new InvalidOperationException("Source project not found.");
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory(newRootPath);
|
|
|
|
|
CopyDirectory(source.RootPath, newRootPath);
|
|
|
|
|
|
|
|
|
|
var entity = new ProjectEntity
|
|
|
|
|
{
|
|
|
|
|
Name = newName,
|
|
|
|
|
RootPath = newRootPath,
|
|
|
|
|
LastOpened = DateTime.Now
|
|
|
|
|
};
|
|
|
|
|
col.Insert(entity);
|
|
|
|
|
|
|
|
|
|
var settings = _db.GetCollection<SettingEntity>("settings");
|
|
|
|
|
var projectSettings = settings.Find(s =>
|
|
|
|
|
s.UserId == userId && s.ProjectId == sourceProjectId);
|
|
|
|
|
foreach (var s in projectSettings)
|
|
|
|
|
{
|
|
|
|
|
settings.Insert(new SettingEntity
|
|
|
|
|
{
|
|
|
|
|
Key = s.Key,
|
|
|
|
|
Value = s.Value,
|
|
|
|
|
UserId = userId,
|
|
|
|
|
ProjectId = entity.Id
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(entity.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void CopyDirectory(string sourceDir, string destDir)
|
|
|
|
|
{
|
|
|
|
|
foreach (var dir in Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories))
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(dir.Replace(sourceDir, destDir));
|
|
|
|
|
}
|
|
|
|
|
foreach (var file in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
|
|
|
|
|
{
|
|
|
|
|
var dest = file.Replace(sourceDir, destDir);
|
|
|
|
|
File.Copy(file, dest, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-14 12:31:35 +02:00
|
|
|
}
|