@* This file is part of Utatane. Utatane is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Utatane is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Utatane. If not, see . *@ @page "/api/files" @using System.Diagnostics.CodeAnalysis @layout EmptyLayout @( Path == "/" ? "/" : Path.Split('/').Last() ) @foreach (var row in _rows) { } @* *@
@if (row.IsFile && !row.IsBad) { } @row.Icon @if (row.IsBad) { @(row.Name + row.Trail) } else { @if (row.IsFile) { @row.Name } else { @row.Name/ } } @if (row.IsFile) { @if (row.IsBad) { @Utils.FormatFileSize(row.Size) } else { @Utils.FormatFileSize(row.Size) ; } } @if (row.IsBad) { } else { }
@code { [SupplyParameterFromQuery(Name = "path")] public required String? Path { get; set; } [SupplyParameterFromQuery(Name = "sort-by")] public required String? SortByColumn { get; set; } [SupplyParameterFromQuery(Name = "sort-asc")] public required String SortAsc { get; set; } private DirectoryInfo _realPath; private SortByColumns _sortByColumn; private SortByDirection _sortByDirection; private IEnumerable _rows; protected override Task OnInitializedAsync() { if (String.IsNullOrEmpty(Path)) Path = "/"; else if (Path.EndsWith("/") && Path != "/") Path = Path.TrimEnd('/'); // prechecked in middleware! _realPath = Utils.VerifyPath(Path).Value.AsT1(); _sortByColumn = SortByColumn switch { "name" => SortByColumns.Name, "size" => SortByColumns.Size, "time" => SortByColumns.Time, _ => SortByColumns.Name }; _sortByDirection = SortAsc switch { "on" => SortByDirection.Ascending, _ => SortByDirection.Descending }; _rows = _realPath.EnumerateFileSystemInfos() .Select(fsi => new FileRow(fsi, Path ?? "/")) .OrderByDescending(x => !x.IsFile) .ThenBy(x => x.Name); // Console.WriteLine($"Path <{Path}> | Col <{SortByColumn}> | Dir <{SortAsc}>"); // Console.WriteLine($"RealPath <{_realPath}> | Col <{_sortByColumn}> | Dir <{_sortByDirection}>"); return base.OnInitializedAsync(); } public enum SortByColumns { Name, Size, Time, } public enum SortByDirection { Ascending, Descending, } public class FileRow { public required FileSystemInfo Fsi { get; init; } public required bool IsFile { get; init; } public required bool IsBad { get; init; } public required String TypeString { get; init; } public required MarkupString Icon { get; init; } public required String Name { get; init; } public required bool IsDotFile { get; init; } public required long Size { get; init; } public required String TimeFmt { get; init; } public required String TimeUnix { get; init; } public required String? Href { get; init; } public required char? Trail { get; init; } [SetsRequiredMembers] public FileRow(FileSystemInfo baseFsi, String currentPath) { FileSystemInfo? _fsi; bool _isBad = false; try { _fsi = baseFsi.UnravelLink(); } catch { _isBad = true; _fsi = baseFsi; } Fsi = _fsi; IsFile = Fsi is FileInfo; IsBad = _isBad || !Fsi.IsReadable(); TypeString = IsFile ? "file" : "directory"; Icon = IsBad ? Utils.AbbrIcon($"Server cannot read this {TypeString}", "⚠️") : Utils.GetIconForFileType(Fsi); Name = baseFsi.Name; // specifically want whatever its called in the directory we're looking at IsDotFile = Name.StartsWith('.'); Size = IsBad || !IsFile ? -1 : ((FileInfo)Fsi).Length; TimeFmt = baseFsi.LastWriteTime.ToUniversalTime().ToString("yyyy-MM-dd HH:mm"); TimeUnix = $"{baseFsi.LastWriteTime.ToUniversalTime().Subtract(DateTime.UnixEpoch).TotalSeconds:N0}"; Href = IsBad ? null : String.Join('/', System.IO.Path.Join(currentPath, Name) .Split('/') .Select(Uri.EscapeDataString) ); Trail = IsFile ? null : '/'; } } }