fix: Add type reference info and remove query paged.
This commit is contained in:
parent
d2041ea5e4
commit
621d9f4318
2
Flawless-Version-Control.sln.DotSettings
Normal file
2
Flawless-Version-Control.sln.DotSettings
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeEditing/SuppressUninitializedWarningFix/Enabled/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>
|
||||||
@ -1,17 +0,0 @@
|
|||||||
namespace Flawless.Communication.Request;
|
|
||||||
|
|
||||||
public class QueryPagesRequest<T>
|
|
||||||
{
|
|
||||||
public required int Offset { get; init; }
|
|
||||||
|
|
||||||
public required int Length { get; init; }
|
|
||||||
|
|
||||||
public T? Parameter { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class QueryPagesRequest
|
|
||||||
{
|
|
||||||
public required int Offset { get; init; }
|
|
||||||
|
|
||||||
public required int Length { get; init; }
|
|
||||||
}
|
|
||||||
3
Flawless.Communication/Response/CommitSuccessResponse.cs
Normal file
3
Flawless.Communication/Response/CommitSuccessResponse.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Flawless.Communication.Response;
|
||||||
|
|
||||||
|
public record CommitSuccessResponse(DateTime CommittedOn, Guid CommitId);
|
||||||
3
Flawless.Communication/Response/ListingResponse.cs
Normal file
3
Flawless.Communication/Response/ListingResponse.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Flawless.Communication.Response;
|
||||||
|
|
||||||
|
public record ListingResponse<T>(T[] Result);
|
||||||
@ -1,25 +0,0 @@
|
|||||||
namespace Flawless.Communication.Response;
|
|
||||||
|
|
||||||
public record PagedResponse<T>
|
|
||||||
{
|
|
||||||
public required int Offset { get; init; }
|
|
||||||
|
|
||||||
public required int Length { get; init; }
|
|
||||||
|
|
||||||
public int? Total { get; init; }
|
|
||||||
|
|
||||||
public IEnumerable<T>? Data { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public record PagedResponse<TData, TMetadata>
|
|
||||||
{
|
|
||||||
public required int Offset { get; init; }
|
|
||||||
|
|
||||||
public required int Length { get; init; }
|
|
||||||
|
|
||||||
public int? Total { get; init; }
|
|
||||||
|
|
||||||
public IEnumerable<TData>? Data { get; init; }
|
|
||||||
|
|
||||||
public TMetadata? Metadata { get; init; }
|
|
||||||
}
|
|
||||||
3
Flawless.Communication/Response/PeekResponse.cs
Normal file
3
Flawless.Communication/Response/PeekResponse.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Flawless.Communication.Response;
|
||||||
|
|
||||||
|
public record PeekResponse<T>(T Result);
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
namespace Flawless.Communication.Response;
|
||||||
|
|
||||||
|
public record RepositoryCommitResponse(
|
||||||
|
Guid Id, string Author, DateTime CommitedOn, string Message, Guid MainDepotId);
|
||||||
@ -2,5 +2,7 @@
|
|||||||
|
|
||||||
public record ServerStatusResponse
|
public record ServerStatusResponse
|
||||||
{
|
{
|
||||||
|
public required string? FriendlyName { get; init; }
|
||||||
|
|
||||||
public required bool AllowPublicRegister { get; set; }
|
public required bool AllowPublicRegister { get; set; }
|
||||||
}
|
}
|
||||||
3
Flawless.Communication/Shared/LockFileInfo.cs
Normal file
3
Flawless.Communication/Shared/LockFileInfo.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Flawless.Communication.Shared;
|
||||||
|
|
||||||
|
public record LockFileInfo(string Path, string Owner);
|
||||||
@ -27,7 +27,8 @@ public class AuthenticationController(
|
|||||||
{
|
{
|
||||||
return Task.FromResult<ActionResult<ServerStatusResponse>>(Ok(new ServerStatusResponse()
|
return Task.FromResult<ActionResult<ServerStatusResponse>>(Ok(new ServerStatusResponse()
|
||||||
{
|
{
|
||||||
AllowPublicRegister = true
|
AllowPublicRegister = true,
|
||||||
|
FriendlyName = "Ca2didi Server"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.OpenApi.Validations.Rules;
|
||||||
|
|
||||||
namespace Flawless.Server.Controllers;
|
namespace Flawless.Server.Controllers;
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ public class RepositoryInnieController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("get_users")]
|
[HttpGet("get_users")]
|
||||||
public async Task<IActionResult> GetUsersAsync(string repositoryName, QueryPagesRequest r)
|
public async Task<ActionResult<ListingResponse<RepoUserRole>>> GetUsersAsync(string repositoryName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(repositoryName) || repositoryName.Length <= 3)
|
if (string.IsNullOrWhiteSpace(repositoryName) || repositoryName.Length <= 3)
|
||||||
return BadRequest(new FailedResponse("Repository name is empty or too short!"));
|
return BadRequest(new FailedResponse("Repository name is empty or too short!"));
|
||||||
@ -122,17 +123,11 @@ public class RepositoryInnieController(
|
|||||||
|
|
||||||
if (rp == null) return BadRequest(new FailedResponse("Repository not found!"));
|
if (rp == null) return BadRequest(new FailedResponse("Repository not found!"));
|
||||||
|
|
||||||
return Ok(new PagedResponse<RepoUserRole>
|
return Ok(new ListingResponse<RepoUserRole>(rp.Members.Select(pm => new RepoUserRole
|
||||||
{
|
|
||||||
Length = r.Length,
|
|
||||||
Offset = r.Offset,
|
|
||||||
Total = rp.Members.Count,
|
|
||||||
Data = rp.Members.Select(pm => new RepoUserRole
|
|
||||||
{
|
{
|
||||||
Username = pm.User.UserName!,
|
Username = pm.User.UserName!,
|
||||||
Role = pm.Role
|
Role = pm.Role
|
||||||
})
|
}).ToArray()));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("update_user")]
|
[HttpPost("update_user")]
|
||||||
@ -230,6 +225,7 @@ public class RepositoryInnieController(
|
|||||||
|
|
||||||
|
|
||||||
[HttpGet("fetch_manifest")]
|
[HttpGet("fetch_manifest")]
|
||||||
|
[ProducesResponseType<FileStreamResult>(200)]
|
||||||
public async Task<IActionResult> DownloadManifestAsync(string userName, string repositoryName, [FromQuery] string commitId)
|
public async Task<IActionResult> DownloadManifestAsync(string userName, string repositoryName, [FromQuery] string commitId)
|
||||||
{
|
{
|
||||||
if (!Guid.TryParse(commitId, out var commitGuid)) return BadRequest(new FailedResponse("Invalid commit id"));
|
if (!Guid.TryParse(commitId, out var commitGuid)) return BadRequest(new FailedResponse("Invalid commit id"));
|
||||||
@ -245,6 +241,7 @@ public class RepositoryInnieController(
|
|||||||
|
|
||||||
|
|
||||||
[HttpGet("fetch_depot")]
|
[HttpGet("fetch_depot")]
|
||||||
|
[ProducesResponseType<FileStreamResult>(200)]
|
||||||
public async Task<IActionResult> DownloadDepotAsync(string userName, string repositoryName, [FromQuery] string depotId)
|
public async Task<IActionResult> DownloadDepotAsync(string userName, string repositoryName, [FromQuery] string depotId)
|
||||||
{
|
{
|
||||||
if (!Guid.TryParse(depotId, out var depotGuid)) return BadRequest(new FailedResponse("Invalid depot id"));
|
if (!Guid.TryParse(depotId, out var depotGuid)) return BadRequest(new FailedResponse("Invalid depot id"));
|
||||||
@ -260,50 +257,49 @@ public class RepositoryInnieController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("list_commit")]
|
[HttpGet("list_commit")]
|
||||||
public async Task<IActionResult> ListCommitsAsync(string userName, string repositoryName)
|
public async Task<ActionResult<ListingResponse<RepositoryCommitResponse>>> ListCommitsAsync(string userName, string repositoryName)
|
||||||
{
|
{
|
||||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Guest);
|
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Guest);
|
||||||
if (grantIssue is not Repository) return (IActionResult) grantIssue;
|
if (grantIssue is not Repository) return (ActionResult) grantIssue;
|
||||||
|
|
||||||
var commit = await dbContext.Repositories
|
var commit = dbContext.Repositories
|
||||||
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
||||||
.SelectMany(r => r.Commits)
|
.SelectMany(r => r.Commits)
|
||||||
.Include(r => r.Author)
|
.Include(r => r.Author).Include(repositoryCommit => repositoryCommit.MainDepot)
|
||||||
.OrderByDescending(r => r.CommittedOn)
|
.OrderByDescending(r => r.CommittedOn)
|
||||||
.ToArrayAsync();
|
.AsAsyncEnumerable();
|
||||||
|
|
||||||
return Ok(new
|
List<RepositoryCommitResponse> r = new();
|
||||||
{
|
await foreach (var cm in commit)
|
||||||
Commits = commit
|
r.Add(new RepositoryCommitResponse(
|
||||||
});
|
cm.Id, cm.Author.UserName!, cm.CommittedOn, cm.Message, cm.MainDepot.DepotId));
|
||||||
|
|
||||||
|
return Ok(new ListingResponse<RepositoryCommitResponse>(r.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("list_locked_files")]
|
[HttpGet("list_locked_files")]
|
||||||
public async Task<IActionResult> ListLocksAsync(string userName, string repositoryName)
|
public async Task<ActionResult<ListingResponse<LockFileInfo>>> ListLocksAsync(string userName, string repositoryName)
|
||||||
{
|
{
|
||||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Developer);
|
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Developer);
|
||||||
if (grantIssue is not Repository) return (IActionResult) grantIssue;
|
if (grantIssue is not Repository) return (ActionResult) grantIssue;
|
||||||
|
|
||||||
var lockers = await dbContext.Repositories
|
var lockers = await dbContext.Repositories
|
||||||
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
||||||
.SelectMany(r => r.Locked)
|
.SelectMany(r => r.Locked)
|
||||||
.Select(l => new { Path = l.Path, Owner = l.LockDownUser.UserName})
|
.Select(l => new LockFileInfo(l.Path, l.LockDownUser.UserName))
|
||||||
.ToArrayAsync();
|
.ToArrayAsync();
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new ListingResponse<LockFileInfo>(lockers));
|
||||||
{
|
|
||||||
Lockers = lockers
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("peek_commit")]
|
[HttpGet("peek_commit")]
|
||||||
public async Task<IActionResult> PeekCommitAsync(string userName, string repositoryName)
|
public async Task<ActionResult<PeekResponse<Guid>>> PeekCommitAsync(string userName, string repositoryName)
|
||||||
{
|
{
|
||||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Guest);
|
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Guest);
|
||||||
if (grantIssue is not Repository rp) return (IActionResult) grantIssue;
|
if (grantIssue is not Repository rp) return (ActionResult) grantIssue;
|
||||||
|
|
||||||
var commit = await dbContext.Repositories
|
var commit = await dbContext.Repositories
|
||||||
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
.Where(r => r.Owner.UserName == userName && r.Name == repositoryName)
|
||||||
@ -312,10 +308,7 @@ public class RepositoryInnieController(
|
|||||||
.OrderByDescending(r => r.CommittedOn)
|
.OrderByDescending(r => r.CommittedOn)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new PeekResponse<Guid>(commit?.Id ?? Guid.Empty));
|
||||||
{
|
|
||||||
Commit = commit?.Id.ToString() ?? string.Empty
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -394,6 +387,7 @@ public class RepositoryInnieController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("create_commit")]
|
[HttpPost("create_commit")]
|
||||||
|
[ProducesResponseType<CommitSuccessResponse>(200)]
|
||||||
public async Task<IActionResult> CommitAsync(string userName, string repositoryName, [FromForm] FormCommitRequest req)
|
public async Task<IActionResult> CommitAsync(string userName, string repositoryName, [FromForm] FormCommitRequest req)
|
||||||
{
|
{
|
||||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||||
@ -538,11 +532,7 @@ public class RepositoryInnieController(
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(new
|
return Ok(new CommitSuccessResponse(commit.CommittedOn, commit.Id));
|
||||||
{
|
|
||||||
CreatedAt = commit.CommittedOn,
|
|
||||||
CommitId = commit.Id
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async ValueTask StencilWorkspaceSnapshotAsync(Stream depotStream, HashSet<WorkspaceFile> unresolved)
|
private static async ValueTask StencilWorkspaceSnapshotAsync(Stream depotStream, HashSet<WorkspaceFile> unresolved)
|
||||||
|
|||||||
@ -14,34 +14,30 @@ namespace Flawless.Server.Controllers;
|
|||||||
[ApiController, Authorize, Route("api")]
|
[ApiController, Authorize, Route("api")]
|
||||||
public class RepositoryOutieController(AppDbContext dbContext, UserManager<AppUser> userManager) : ControllerBase
|
public class RepositoryOutieController(AppDbContext dbContext, UserManager<AppUser> userManager) : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
[HttpGet("repo_list")]
|
[HttpGet("repo_list")]
|
||||||
public async Task<IActionResult> ListAllAvailableRepositoriesAsync([FromQuery] QueryPagesRequest r)
|
public async Task<ActionResult<ListingResponse<RepositoryInfoResponse>>> ListAllAvailableRepositoriesAsync()
|
||||||
{
|
{
|
||||||
var u = (await userManager.GetUserAsync(HttpContext.User))!;
|
var u = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||||
var query = await dbContext.Repositories
|
var query = dbContext.Repositories
|
||||||
.Include(repository => repository.Owner)
|
.Include(repository => repository.Owner)
|
||||||
.Include(repository => repository.Commits)
|
.Include(repository => repository.Commits)
|
||||||
.Include(repository => repository.Members)
|
.Include(repository => repository.Members)
|
||||||
.ThenInclude(repositoryMember => repositoryMember.User)
|
.ThenInclude(repositoryMember => repositoryMember.User)
|
||||||
.Where(rp => rp.Members.Any(m => m.User == u))
|
.Where(rp => rp.Members.Any(m => m.User == u))
|
||||||
.Skip(r.Offset)
|
.Select(rp => new RepositoryInfoResponse
|
||||||
.Take(r.Length)
|
|
||||||
.ToArrayAsync();
|
|
||||||
|
|
||||||
return Ok(new PagedResponse<RepositoryInfoResponse>
|
|
||||||
{
|
|
||||||
Length = r.Length,
|
|
||||||
Offset = r.Offset,
|
|
||||||
Data = query.Select(rp => new RepositoryInfoResponse
|
|
||||||
{
|
{
|
||||||
RepositoryName = rp.Name,
|
RepositoryName = rp.Name,
|
||||||
OwnerUsername = rp.Owner.UserName!,
|
OwnerUsername = rp.Owner.UserName!,
|
||||||
LatestCommitId = rp.Commits.OrderByDescending(cm => cm.CommittedOn).FirstOrDefault()?.Id ?? Guid.Empty,
|
LatestCommitId = rp.Commits.OrderByDescending(cm => cm.CommittedOn)
|
||||||
|
.Select(cm => cm.Id).FirstOrDefault(),
|
||||||
Description = rp.Description,
|
Description = rp.Description,
|
||||||
IsArchived = rp.IsArchived,
|
IsArchived = rp.IsArchived,
|
||||||
Role = rp.Members.First(m => m.User == u).Role
|
Role = rp.Members.First(m => m.User == u).Role
|
||||||
}),
|
})
|
||||||
});
|
.ToArray();
|
||||||
|
|
||||||
|
return Ok(new ListingResponse<RepositoryInfoResponse>(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("repo_create")]
|
[HttpPost("repo_create")]
|
||||||
|
|||||||
@ -94,22 +94,15 @@ public class UserController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("query_info")]
|
[HttpGet("query_info")]
|
||||||
public async Task<ActionResult<PagedResponse<UserInfoResponse>>> GetUserInfoAsync(QueryPagesRequest r, [FromQuery] string keyword)
|
public async Task<ActionResult<ListingResponse<UserInfoResponse>>> QueryUserInfoAsync([FromQuery] string keyword)
|
||||||
{
|
{
|
||||||
var payload = await userManager.Users
|
var payload = await userManager.Users
|
||||||
.Where(u => u.UserName!.Contains(keyword) || (u.NickName != null && u.NickName.Contains(keyword)))
|
.Where(u => u.UserName!.Contains(keyword) || (u.NickName != null && u.NickName.Contains(keyword)))
|
||||||
.Skip(r.Offset)
|
|
||||||
.Take(r.Length)
|
|
||||||
.Select(u => GetUserInfoInternal(u, null))
|
.Select(u => GetUserInfoInternal(u, null))
|
||||||
.ToArrayAsync();
|
.ToArrayAsync();
|
||||||
|
|
||||||
// Return self as default
|
// Return self as default
|
||||||
return Ok(new PagedResponse<UserInfoResponse>
|
return Ok(new ListingResponse<UserInfoResponse>(payload));
|
||||||
{
|
|
||||||
Offset = r.Offset,
|
|
||||||
Length = r.Length,
|
|
||||||
Data = payload
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("delete")]
|
[HttpGet("delete")]
|
||||||
|
|||||||
@ -37,4 +37,8 @@
|
|||||||
<Compile Remove="Migrations\20250322194407_InitialCreate.Designer.cs" />
|
<Compile Remove="Migrations\20250322194407_InitialCreate.Designer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Exceptions\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -6,7 +6,10 @@ public class ExceptionTransformMiddleware(RequestDelegate next)
|
|||||||
{
|
{
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
try { await next(context); }
|
try
|
||||||
|
{
|
||||||
|
await next(context);
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = 500;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user