feat: Add repository issue feature api.
This commit is contained in:
parent
62ced75815
commit
62d7398035
@ -19,6 +19,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIdentityUser_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc405819100144b0483c14b61d32c5aa215930_003F90_003F4d8e1a86_003FIdentityUser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIdentityUser_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7d382df578ec93391918cfaa4ce7f4b8f35c9aed1241d6556dc9be26df13c_003FIdentityUser_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIdentityUser_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd991417b721d4ddab50a2b715d0ad696b138_003Fa2_003Fdb3874bc_003FIdentityUser_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIdentityUser_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd99404009f8a4a8da97cdbe0d6ecd5dd10800_003F1f_003Fe7cb9bcb_003FIdentityUser_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIReactiveObjectExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F404d064a80dc4960b93f90c9bd69770750810_003F5a_003F1516290d_003FIReactiveObjectExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJwtBearerHandler_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F61447741f88e235f7cd1a276ef5abe648b2dee4b210873893d178b861c9d0_003FJwtBearerHandler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APath_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa6b7f037ba7b44df80b8d3aa7e58eeb2e8e938_003F28_003F6a41ec86_003FPath_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
@ -35,6 +35,10 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Refit" Version="8.0.0" />
|
||||
<PackageReference Include="Refitter.SourceGenerator" Version="1.5.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Semi.Avalonia" Version="11.2.1.6" />
|
||||
<PackageReference Include="Semi.Avalonia.TreeDataGrid" Version="11.0.10.2" />
|
||||
<PackageReference Include="ValueTaskSupplement" Version="1.1.0" />
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using DynamicData.Binding;
|
||||
using Flawless.Client.Remote;
|
||||
using ReactiveUI.SourceGenerators;
|
||||
|
||||
@ -30,10 +31,13 @@ public partial class RepositoryModel : ReactiveModel
|
||||
|
||||
public ObservableCollection<Commit> Commits { get; } = new();
|
||||
|
||||
// todo cache depots?
|
||||
public ObservableCollection<Depot> Depots { get; } = new();
|
||||
|
||||
|
||||
public ObservableCollection<Lock> Locks { get; } = new();
|
||||
|
||||
public ObservableCollection<Issue> Issues { get; } = new();
|
||||
|
||||
public enum RepositoryRole : byte
|
||||
{
|
||||
Guest = 0,
|
||||
@ -42,6 +46,40 @@ public partial class RepositoryModel : ReactiveModel
|
||||
Owner = 3,
|
||||
}
|
||||
|
||||
public partial class Issue : ReactiveModel
|
||||
{
|
||||
[Reactive] private ulong _id;
|
||||
|
||||
[Reactive] private string _title;
|
||||
|
||||
[Reactive] private string? _description;
|
||||
|
||||
[Reactive] private string _author;
|
||||
|
||||
[Reactive] private DateTime _createdAt;
|
||||
|
||||
[Reactive] private DateTime? _lastUpdatedAt;
|
||||
|
||||
[Reactive] private bool _closed;
|
||||
|
||||
public ObservableCollection<string> Tags { get; } = new();
|
||||
|
||||
public ObservableCollection<Comment> Comments { get; } = new();
|
||||
}
|
||||
|
||||
public partial class Comment : ReactiveModel
|
||||
{
|
||||
[Reactive] private ulong _id;
|
||||
|
||||
[Reactive] private string _content;
|
||||
|
||||
[Reactive] private string _author;
|
||||
|
||||
[Reactive] private DateTime _createdAt;
|
||||
|
||||
[Reactive] private ulong? _replyTo;
|
||||
}
|
||||
|
||||
public partial class Member : ReactiveModel
|
||||
{
|
||||
[Reactive] private string _username;
|
||||
|
||||
@ -7,6 +7,7 @@ using Refit;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flawless.Client.Models;
|
||||
|
||||
@ -14,99 +15,148 @@ using Flawless.Client.Models;
|
||||
|
||||
namespace Flawless.Client.Remote
|
||||
{
|
||||
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.5.2.0")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.5.3.0")]
|
||||
public partial interface IFlawlessServer
|
||||
{
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/admin/user/delete/{username}")]
|
||||
Task Delete(string username);
|
||||
Task Delete(string username, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/admin/user/enable/{username}")]
|
||||
Task Enable(string username);
|
||||
Task Enable(string username, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/admin/user/disable/{username}")]
|
||||
Task Disable(string username);
|
||||
Task Disable(string username, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/admin/user/reset_password")]
|
||||
Task ResetPassword([Body] ResetPasswordRequest body);
|
||||
Task ResetPassword([Body] ResetPasswordRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/auth/status")]
|
||||
Task<ServerStatusResponse> Status();
|
||||
Task<ServerStatusResponse> Status(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/auth/register")]
|
||||
Task Register([Body] RegisterRequest body);
|
||||
Task Register([Body] RegisterRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Headers("Accept: text/plain, application/json, text/json", "Content-Type: application/json")]
|
||||
[Post("/api/auth/login")]
|
||||
Task<TokenInfo> Login([Body] LoginRequest body);
|
||||
Task<TokenInfo> Login([Body] LoginRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Headers("Accept: text/plain, application/json, text/json", "Content-Type: application/json")]
|
||||
[Post("/api/auth/refresh")]
|
||||
Task<TokenInfo> Refresh([Body] TokenInfo body);
|
||||
Task<TokenInfo> Refresh([Body] TokenInfo body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/auth/logout_all")]
|
||||
Task LogoutAll();
|
||||
Task LogoutAll(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/auth/renew_password")]
|
||||
Task RenewPassword([Body] ResetPasswordRequest body);
|
||||
Task RenewPassword([Body] ResetPasswordRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Get("/")]
|
||||
Task Index();
|
||||
Task Index(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json", "Content-Type: application/json")]
|
||||
[Post("/api/issue/{userName}/{repositoryName}/create")]
|
||||
Task<IssueInfo> Create(string userName, string repositoryName, [Body] CreateIssueRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/issue/{userName}/{repositoryName}/{issueId}/comment")]
|
||||
Task Comment(string userName, string repositoryName, long issueId, [Body] AddCommentRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/issue/{userName}/{repositoryName}/{issueId}/close")]
|
||||
Task Close(string userName, string repositoryName, long issueId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/issue/{userName}/{repositoryName}/list")]
|
||||
Task<IssueInfoListingResponse> List(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/issue/{userName}/{repositoryName}/{issueId}")]
|
||||
Task<IssueDetailInfo> Issue(string userName, string repositoryName, long issueId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Patch("/api/issue/{userName}/{repositoryName}/{issueId}/edit")]
|
||||
Task Edit(string userName, string repositoryName, long issueId, [Body] UpdateIssueRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/issue/{userName}/{repositoryName}/{issueId}/reopen")]
|
||||
Task Reopen(string userName, string repositoryName, long issueId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/issue/{userName}/{repositoryName}/{issueId}/comments")]
|
||||
Task<CommentResponseListingResponse> Comments(string userName, string repositoryName, long issueId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/repo/{userName}/{repositoryName}/delete_repo")]
|
||||
Task DeleteRepo(string repositoryName, string userName);
|
||||
Task DeleteRepo(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/repo/{userName}/{repositoryName}/get_info")]
|
||||
Task<RepositoryInfoResponse> GetInfo(string repositoryName, string userName);
|
||||
Task<RepositoryInfoResponse> GetInfo(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/repo/{userName}/{repositoryName}/archive_repo")]
|
||||
Task ArchiveRepo(string repositoryName, string userName);
|
||||
Task ArchiveRepo(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/repo/{userName}/{repositoryName}/unarchive_repo")]
|
||||
Task UnarchiveRepo(string repositoryName, string userName);
|
||||
Task UnarchiveRepo(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/repo/{userName}/{repositoryName}/get_users")]
|
||||
Task<RepoUserRoleListingResponse> GetUsers(string repositoryName, string userName);
|
||||
Task<RepoUserRoleListingResponse> GetUsers(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Post("/api/repo/{userName}/{repositoryName}/fetch_manifest")]
|
||||
Task<CommitManifest> FetchManifest(string userName, string repositoryName, [Query] string commitId);
|
||||
Task<CommitManifest> FetchManifest(string userName, string repositoryName, [Query] string commitId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
@ -118,48 +168,48 @@ namespace Flawless.Client.Remote
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Post("/api/repo/{userName}/{repositoryName}/list_commit")]
|
||||
Task<RepositoryCommitResponseListingResponse> ListCommit(string userName, string repositoryName);
|
||||
Task<RepositoryCommitResponseListingResponse> ListCommit(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Post("/api/repo/{userName}/{repositoryName}/list_locked_files")]
|
||||
Task<LockFileInfoListingResponse> ListLockedFiles(string userName, string repositoryName);
|
||||
Task<LockFileInfoListingResponse> ListLockedFiles(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/repo/{userName}/{repositoryName}/peek_commit")]
|
||||
Task<GuidPeekResponse> PeekCommit(string userName, string repositoryName);
|
||||
Task<GuidPeekResponse> PeekCommit(string userName, string repositoryName, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/repo/{userName}/{repositoryName}/lock_file")]
|
||||
Task LockFile(string userName, string repositoryName, [Query] string path);
|
||||
Task LockFile(string userName, string repositoryName, [Query] string path, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/repo/{userName}/{repositoryName}/unlock_file")]
|
||||
Task UnlockFile(string userName, string repositoryName, [Query] string path);
|
||||
Task UnlockFile(string userName, string repositoryName, [Query] string path, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Multipart]
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Headers("Accept: text/plain, application/json, text/json", "Content-Type: multipart/form-data")]
|
||||
[Post("/api/repo/{userName}/{repositoryName}/create_commit")]
|
||||
Task<CommitSuccessResponse> CreateCommit(string userName, string repositoryName, StreamPart depot, string message, IEnumerable<string> workspaceSnapshot, IEnumerable<string> requiredDepots, string mainDepotId);
|
||||
Task<CommitSuccessResponse> CreateCommit(string userName, string repositoryName, StreamPart depot, string message, IEnumerable<string> workspaceSnapshot, IEnumerable<string> requiredDepots, string mainDepotId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/repo_list")]
|
||||
Task<RepositoryInfoResponseListingResponse> RepoList();
|
||||
Task<RepositoryInfoResponseListingResponse> RepoList(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Post("/api/repo_create")]
|
||||
Task<RepositoryInfoResponse> RepoCreate([Query] string repositoryName, [Query] string description);
|
||||
Task<RepositoryInfoResponse> RepoCreate([Query] string repositoryName, [Query] string description, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
@ -169,39 +219,42 @@ namespace Flawless.Client.Remote
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/delete_user")]
|
||||
Task DeleteUser([Query] string repositoryName, [Query] string delUser);
|
||||
Task DeleteUser([Query] string repositoryName, [Query] string delUser, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/user/update_info")]
|
||||
Task UpdateInfo([Body] UserInfoModifyResponse body);
|
||||
Task UpdateInfo([Body] UserInfoModifyResponse body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/user/update_email")]
|
||||
Task UpdateEmail([Body] UserContactModifyResponse body);
|
||||
Task UpdateEmail([Body] UserContactModifyResponse body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/user/update_phone")]
|
||||
Task UpdatePhone([Body] UserContactModifyResponse body);
|
||||
Task UpdatePhone([Body] UserContactModifyResponse body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/user/get_info")]
|
||||
Task<UserInfoResponse> GetInfo([Query] string username);
|
||||
Task<UserInfoResponse> GetInfo([Query] string username, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Get("/api/user/query_info")]
|
||||
Task<UserInfoResponseListingResponse> QueryInfo([Query] string keyword);
|
||||
Task<UserInfoResponseListingResponse> QueryInfo([Query] string keyword, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Get("/api/user/delete")]
|
||||
Task Delete();
|
||||
Task Delete(CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
}
|
||||
@ -210,7 +263,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
//----------------------
|
||||
// <auto-generated>
|
||||
// Generated using the NSwag toolchain v14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
|
||||
// Generated using the NSwag toolchain v14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
|
||||
// </auto-generated>
|
||||
//----------------------
|
||||
|
||||
@ -223,6 +276,8 @@ namespace Flawless.Client.Remote
|
||||
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
|
||||
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
|
||||
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
|
||||
#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type"
|
||||
#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference"
|
||||
#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"
|
||||
#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter"
|
||||
#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type"
|
||||
@ -234,7 +289,49 @@ namespace Flawless.Client.Remote
|
||||
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class AddCommentRequest
|
||||
{
|
||||
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; }
|
||||
|
||||
[JsonPropertyName("replyTo")]
|
||||
public long? ReplyTo { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class CommentResponse
|
||||
{
|
||||
|
||||
[JsonPropertyName("commentId")]
|
||||
public long CommentId { get; set; }
|
||||
|
||||
[JsonPropertyName("author")]
|
||||
public string Author { get; set; }
|
||||
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; }
|
||||
|
||||
[JsonPropertyName("createdAt")]
|
||||
public System.DateTimeOffset CreatedAt { get; set; }
|
||||
|
||||
[JsonPropertyName("replyToId")]
|
||||
public long? ReplyToId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class CommentResponseListingResponse
|
||||
{
|
||||
|
||||
[JsonPropertyName("result")]
|
||||
public ICollection<CommentResponse> Result { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class CommitManifest
|
||||
{
|
||||
|
||||
@ -249,7 +346,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class CommitSuccessResponse
|
||||
{
|
||||
|
||||
@ -264,7 +361,22 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class CreateIssueRequest
|
||||
{
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[JsonPropertyName("tag")]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class DepotLabel
|
||||
{
|
||||
|
||||
@ -276,7 +388,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class GuidPeekResponse
|
||||
{
|
||||
|
||||
@ -285,7 +397,73 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class IssueDetailInfo
|
||||
{
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonPropertyName("author")]
|
||||
public string Author { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[JsonPropertyName("createAt")]
|
||||
public System.DateTimeOffset CreateAt { get; set; }
|
||||
|
||||
[JsonPropertyName("lastUpdate")]
|
||||
public System.DateTimeOffset LastUpdate { get; set; }
|
||||
|
||||
[JsonPropertyName("closed")]
|
||||
public bool Closed { get; set; }
|
||||
|
||||
[JsonPropertyName("tag")]
|
||||
public string Tag { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class IssueInfo
|
||||
{
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonPropertyName("author")]
|
||||
public string Author { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("createAt")]
|
||||
public System.DateTimeOffset CreateAt { get; set; }
|
||||
|
||||
[JsonPropertyName("lastUpdate")]
|
||||
public System.DateTimeOffset LastUpdate { get; set; }
|
||||
|
||||
[JsonPropertyName("closed")]
|
||||
public bool Closed { get; set; }
|
||||
|
||||
[JsonPropertyName("tag")]
|
||||
public string Tag { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class IssueInfoListingResponse
|
||||
{
|
||||
|
||||
[JsonPropertyName("result")]
|
||||
public ICollection<IssueInfo> Result { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class LockFileInfo
|
||||
{
|
||||
|
||||
@ -297,7 +475,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class LockFileInfoListingResponse
|
||||
{
|
||||
|
||||
@ -306,7 +484,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class LoginRequest
|
||||
{
|
||||
|
||||
@ -320,7 +498,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RegisterRequest
|
||||
{
|
||||
|
||||
@ -338,7 +516,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepoUserRole
|
||||
{
|
||||
|
||||
@ -351,7 +529,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepoUserRoleListingResponse
|
||||
{
|
||||
|
||||
@ -360,7 +538,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepositoryCommitResponse
|
||||
{
|
||||
|
||||
@ -381,7 +559,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepositoryCommitResponseListingResponse
|
||||
{
|
||||
|
||||
@ -390,7 +568,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepositoryInfoResponse
|
||||
{
|
||||
|
||||
@ -413,7 +591,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class RepositoryInfoResponseListingResponse
|
||||
{
|
||||
|
||||
@ -422,7 +600,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public enum RepositoryRole
|
||||
{
|
||||
|
||||
@ -436,7 +614,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class ResetPasswordRequest
|
||||
{
|
||||
|
||||
@ -452,7 +630,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class ServerStatusResponse
|
||||
{
|
||||
|
||||
@ -464,7 +642,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class TokenInfo
|
||||
{
|
||||
|
||||
@ -477,7 +655,22 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class UpdateIssueRequest
|
||||
{
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[JsonPropertyName("tag")]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class UserContactModifyResponse
|
||||
{
|
||||
|
||||
@ -489,7 +682,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class UserInfoModifyResponse
|
||||
{
|
||||
|
||||
@ -507,7 +700,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class UserInfoResponse
|
||||
{
|
||||
|
||||
@ -540,7 +733,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class UserInfoResponseListingResponse
|
||||
{
|
||||
|
||||
@ -549,7 +742,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public enum UserSex
|
||||
{
|
||||
|
||||
@ -563,7 +756,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class WorkspaceFile
|
||||
{
|
||||
|
||||
@ -575,7 +768,7 @@ namespace Flawless.Client.Remote
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class FileParameter
|
||||
{
|
||||
public FileParameter(System.IO.Stream data)
|
||||
@ -602,7 +795,7 @@ namespace Flawless.Client.Remote
|
||||
public string ContentType { get; private set; }
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.2.0.0 (NJsonSchema v11.1.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "14.3.0.0 (NJsonSchema v11.2.0.0 (Newtonsoft.Json v13.0.0.0))")]
|
||||
public partial class FileResponse : System.IDisposable
|
||||
{
|
||||
private System.IDisposable _client;
|
||||
@ -650,6 +843,8 @@ namespace Flawless.Client.Remote
|
||||
#pragma warning restore 1591
|
||||
#pragma warning restore 8073
|
||||
#pragma warning restore 3016
|
||||
#pragma warning restore 8600
|
||||
#pragma warning restore 8602
|
||||
#pragma warning restore 8603
|
||||
#pragma warning restore 8604
|
||||
#pragma warning restore 8625
|
||||
@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AvaloniaEdit.Utils;
|
||||
using Flawless.Abstraction;
|
||||
using Flawless.Client.Models;
|
||||
using Flawless.Client.Remote;
|
||||
@ -278,6 +281,293 @@ public class RepositoryService : BaseService<RepositoryService>
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdateIssuesListFromServerAsync(RepositoryModel repo)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
var issues = (await api.Gateway.List(repo.Name, repo.OwnerName))
|
||||
.Result.ToImmutableDictionary(x => (ulong) x.Id);
|
||||
|
||||
for (var i = 0; i < repo.Issues.Count; i++)
|
||||
{
|
||||
if (!issues.ContainsKey(repo.Issues[i].Id))
|
||||
repo.Issues.RemoveAt(i);
|
||||
}
|
||||
|
||||
foreach (var (id, info) in issues)
|
||||
{
|
||||
var i = repo.Issues.FirstOrDefault(x => x.Id == id);
|
||||
var tags = info.Tag.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (i == null)
|
||||
{
|
||||
i = new RepositoryModel.Issue
|
||||
{
|
||||
Author = info.Author,
|
||||
Id = id,
|
||||
Title = info.Title,
|
||||
Description = null,
|
||||
Closed = info.Closed,
|
||||
CreatedAt = info.CreateAt.UtcDateTime,
|
||||
LastUpdatedAt = info.LastUpdate.UtcDateTime
|
||||
};
|
||||
|
||||
i.Tags.AddRange(tags);
|
||||
repo.Issues.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i.Title = info.Title;
|
||||
i.Closed = info.Closed;
|
||||
i.LastUpdatedAt = info.LastUpdate.UtcDateTime;
|
||||
i.Author = info.Author;
|
||||
|
||||
i.Tags.Clear();
|
||||
i.Tags.AddRange(tags);
|
||||
}
|
||||
}
|
||||
|
||||
repo.Issues.Sort((x, y) => (int) ((long) x.Id - (long) y.Id));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdateIssueDetailsFromServerAsync(RepositoryModel repo, ulong issueId)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
var issue = await api.Gateway.Issue(repo.Name, repo.OwnerName, (long)issueId);
|
||||
var details = (await api.Gateway.Comments(repo.Name, repo.OwnerName, (long)issueId))
|
||||
.Result.ToImmutableDictionary(x => x.CommentId);
|
||||
|
||||
var entity = repo.Issues.FirstOrDefault(x => x.Id == issueId);
|
||||
var tags = issue.Tag.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
entity = new RepositoryModel.Issue
|
||||
{
|
||||
Author = issue.Author,
|
||||
Id = (ulong) issue.Id,
|
||||
Title = issue.Title,
|
||||
Description = null,
|
||||
Closed = issue.Closed,
|
||||
CreatedAt = issue.CreateAt.UtcDateTime,
|
||||
LastUpdatedAt = issue.LastUpdate.UtcDateTime
|
||||
};
|
||||
|
||||
entity.Tags.AddRange(tags);
|
||||
repo.Issues.Add(entity);
|
||||
|
||||
entity.Comments.AddRange(details.Select(x => new RepositoryModel.Comment
|
||||
{
|
||||
Id = (ulong) x.Key,
|
||||
Author = x.Value.Author,
|
||||
Content = x.Value.Content,
|
||||
CreatedAt = x.Value.CreatedAt.UtcDateTime,
|
||||
ReplyTo = x.Value.ReplyToId.HasValue ? (ulong) x.Value.ReplyToId.Value : null
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
entity.Title = issue.Title;
|
||||
entity.Closed = issue.Closed;
|
||||
entity.LastUpdatedAt = issue.LastUpdate.UtcDateTime;
|
||||
entity.Author = issue.Author;
|
||||
|
||||
entity.Tags.Clear();
|
||||
entity.Tags.AddRange(tags);
|
||||
|
||||
for (var i = 0; i < entity.Comments.Count; i++)
|
||||
{
|
||||
var c = entity.Comments[i];
|
||||
if (!details.ContainsKey((long) c.Id)) repo.Issues.RemoveAt(i);
|
||||
}
|
||||
|
||||
foreach (var (key, value) in details)
|
||||
{
|
||||
var d = entity.Comments.FirstOrDefault(x => x.Id == (ulong) key);
|
||||
if (d == null)
|
||||
{
|
||||
var c = new RepositoryModel.Comment
|
||||
{
|
||||
Id = (ulong)key,
|
||||
Author = value.Author,
|
||||
Content = value.Content,
|
||||
CreatedAt = value.CreatedAt.UtcDateTime,
|
||||
ReplyTo = value.ReplyToId.HasValue ? (ulong)value.ReplyToId.Value : null
|
||||
};
|
||||
|
||||
entity.Comments.Add(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
d.Author = value.Author;
|
||||
d.Content = value.Content;
|
||||
d.CreatedAt = value.CreatedAt.UtcDateTime;
|
||||
d.ReplyTo = value.ReplyToId.HasValue ? (ulong)value.ReplyToId.Value : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repo.Issues.Sort((x, y) => (int) ((long) x.Id - (long) y.Id));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async ValueTask<IssueInfo?> CreateIssueAsync(RepositoryModel repo, string title, string description, IEnumerable<string>? tags)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder? tagString = null;
|
||||
if (tags != null)
|
||||
{
|
||||
new StringBuilder().AppendJoin(',', tags);
|
||||
}
|
||||
|
||||
return await api.Gateway.Create(
|
||||
repo.OwnerName,
|
||||
repo.Name,
|
||||
new CreateIssueRequest { Title = title, Description = description, Tag = tagString?.ToString()});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> CloseIssueAsync(RepositoryModel repo, long issueId)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
await api.Gateway.Close(repo.OwnerName, repo.Name, issueId);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> ReopenIssueAsync(RepositoryModel repo, long issueId)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
await api.Gateway.Reopen(repo.OwnerName, repo.Name, issueId);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> AddCommentAsync(RepositoryModel repo, ulong issueId, string content, ulong? replyTo)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
await api.Gateway.Comment(repo.OwnerName, repo.Name, (long) issueId,
|
||||
new AddCommentRequest { Content = content, ReplyTo = replyTo.HasValue ? (long) replyTo.Value : null });
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdateIssueAsync(RepositoryModel repo, long issueId, string? title, string? description, IEnumerable<string>? tags)
|
||||
{
|
||||
var api = Api.C;
|
||||
try
|
||||
{
|
||||
if (api.RequireRefreshToken() && !(await api.TryRefreshTokenAsync()))
|
||||
{
|
||||
api.ClearGateway();
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuilder? tagString = null;
|
||||
if (tags != null)
|
||||
{
|
||||
new StringBuilder().AppendJoin(',', tags);
|
||||
}
|
||||
|
||||
await api.Gateway.Edit(repo.OwnerName, repo.Name, issueId,
|
||||
new UpdateIssueRequest { Title = title, Description = description, Tag = tagString?.ToString()});
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UIHelper.NotifyError(e);
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdateMembersFromServerAsync(RepositoryModel repo)
|
||||
{
|
||||
|
||||
3
Flawless.Communication/Request/AddCommentRequest.cs
Normal file
3
Flawless.Communication/Request/AddCommentRequest.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace Flawless.Communication.Request;
|
||||
|
||||
public record AddCommentRequest(string Content, ulong? ReplyTo);
|
||||
3
Flawless.Communication/Request/CreateIssueRequest.cs
Normal file
3
Flawless.Communication/Request/CreateIssueRequest.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace Flawless.Communication.Request;
|
||||
|
||||
public record CreateIssueRequest(string Title, string Description, string? Tag);
|
||||
8
Flawless.Communication/Request/UpdateIssueRequest.cs
Normal file
8
Flawless.Communication/Request/UpdateIssueRequest.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Flawless.Communication.Request;
|
||||
|
||||
public record UpdateIssueRequest
|
||||
(
|
||||
string? Title,
|
||||
string? Description,
|
||||
string? Tag
|
||||
);
|
||||
9
Flawless.Communication/Response/CommentResponse.cs
Normal file
9
Flawless.Communication/Response/CommentResponse.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Flawless.Communication.Response;
|
||||
|
||||
public record CommentResponse(
|
||||
ulong CommentId,
|
||||
string Author,
|
||||
string Content,
|
||||
DateTime CreatedAt,
|
||||
ulong? ReplyToId = null
|
||||
);
|
||||
10
Flawless.Communication/Shared/IssueInfo.cs
Normal file
10
Flawless.Communication/Shared/IssueInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Flawless.Communication.Shared;
|
||||
|
||||
public record IssueInfo(
|
||||
ulong Id, string Author, string Title, DateTime CreateAt, DateTime LastUpdate, bool closed, string? Tag);
|
||||
|
||||
public record IssueDetailInfo(
|
||||
ulong Id, string Author, string Title, string Description, DateTime CreateAt, DateTime LastUpdate, bool closed, string? Tag);
|
||||
|
||||
public record IssueCommentInfo(
|
||||
ulong Id, string Author, string Content, DateTime CreateAt, DateTime LastUpdate, ulong? ReplyTo);
|
||||
240
Flawless.Server/Controllers/IssueController.cs
Normal file
240
Flawless.Server/Controllers/IssueController.cs
Normal file
@ -0,0 +1,240 @@
|
||||
using Flawless.Communication.Request;
|
||||
using Flawless.Communication.Response;
|
||||
using Flawless.Communication.Shared;
|
||||
using Flawless.Server.Models;
|
||||
using Flawless.Server.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Flawless.Server.Controllers;
|
||||
[ApiController, Microsoft.AspNetCore.Authorization.Authorize, Route("api/issue/{userName}/{repositoryName}")]
|
||||
public class IssueController(
|
||||
UserManager<AppUser> userManager,
|
||||
AppDbContext dbContext) : ControllerBase
|
||||
{
|
||||
[HttpPost("create")]
|
||||
public async Task<ActionResult<IssueInfo>> CreateIssueAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
[FromBody] CreateIssueRequest request)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository repository) return (ActionResult)grantIssue;
|
||||
|
||||
var issue = new RepositoryIssue
|
||||
{
|
||||
Repository = repository,
|
||||
Author = user,
|
||||
Title = request.Title,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Descripion = request.Description,
|
||||
Closed = false,
|
||||
Tag = request.Tag
|
||||
};
|
||||
|
||||
dbContext.RepositoryIssues.Add(issue);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Ok(new IssueInfo(
|
||||
issue.Id,
|
||||
issue.Author.UserName!,
|
||||
issue.Title,
|
||||
issue.CreatedAt,
|
||||
issue.CreatedAt,
|
||||
issue.Closed,
|
||||
issue.Tag));
|
||||
}
|
||||
|
||||
[HttpPost("{issueId}/comment")]
|
||||
public async Task<IActionResult> AddCommentAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId,
|
||||
[FromBody] AddCommentRequest request)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository _) return (ActionResult) grantIssue;
|
||||
|
||||
var issue = await dbContext.RepositoryIssues
|
||||
.Include(i => i.Repository)
|
||||
.Include(repositoryIssue => repositoryIssue.Contents)
|
||||
.FirstOrDefaultAsync(i => i.Id == issueId);
|
||||
|
||||
if (issue == null) return NotFound(new FailedResponse("Issue not found"));
|
||||
if (issue.Closed) return BadRequest(new FailedResponse("Issue is closed"));
|
||||
|
||||
var comment = new RepositoryIssueContent
|
||||
{
|
||||
Issue = issue,
|
||||
Author = user,
|
||||
Content = request.Content,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ReplyTo = request.ReplyTo.HasValue
|
||||
? issue.Contents.Find(v => v.Id == request.ReplyTo.Value) : null
|
||||
};
|
||||
|
||||
issue.Contents.Add(comment);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("{issueId}/close")]
|
||||
public async Task<IActionResult> CloseIssueAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Developer);
|
||||
if (grantIssue is not Repository _) return (ActionResult) grantIssue;
|
||||
|
||||
var issue = await dbContext.RepositoryIssues.FindAsync(issueId);
|
||||
if (issue == null) return NotFound(new FailedResponse("Issue not found"));
|
||||
|
||||
issue.Closed = true;
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("list")]
|
||||
public async Task<ActionResult<ListingResponse<IssueInfo>>> GetIssuesAsync(
|
||||
string userName,
|
||||
string repositoryName)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository repository) return (ActionResult)grantIssue;
|
||||
|
||||
var issues = await dbContext.RepositoryIssues
|
||||
.Where(i => i.Repository == repository)
|
||||
.Include(i => i.Author)
|
||||
.ToArrayAsync();
|
||||
|
||||
return Ok(new ListingResponse<RepositoryIssue>(issues));
|
||||
}
|
||||
|
||||
[HttpGet("{issueId}")]
|
||||
public async Task<ActionResult<IssueDetailInfo>> GetIssueDetailsAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository repo) return (ActionResult) grantIssue;
|
||||
|
||||
var issue = await dbContext.RepositoryIssues
|
||||
.Include(i => i.Author)
|
||||
.Include(i => i.Repository)
|
||||
.Include(i => i.Contents)
|
||||
.ThenInclude(c => c.Author)
|
||||
.FirstOrDefaultAsync(x => x.Id == issueId && x.Repository == repo);
|
||||
|
||||
return issue == null
|
||||
? NotFound(new FailedResponse("Issue not found"))
|
||||
: Ok(new IssueDetailInfo(
|
||||
issue.Id,
|
||||
issue.Author.UserName!,
|
||||
issue.Title,
|
||||
issue.Descripion ?? String.Empty,
|
||||
issue.CreatedAt,
|
||||
issue.Contents.MaxBy(x => x.CreatedAt)?.CreatedAt ?? issue.CreatedAt,
|
||||
issue.Closed,
|
||||
issue.Tag));
|
||||
}
|
||||
|
||||
[HttpPatch("{issueId}/edit")]
|
||||
public async Task<IActionResult> UpdateIssueAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId,
|
||||
[FromBody] UpdateIssueRequest request)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository repo) return (ActionResult) grantIssue;
|
||||
|
||||
var issue = await dbContext.RepositoryIssues
|
||||
.Include(x => x.Author)
|
||||
.FirstOrDefaultAsync(x => x.Id == issueId && x.Repository == repo);
|
||||
|
||||
if (issue == null) return NotFound(new FailedResponse("Issue not found"));
|
||||
if (issue.Author != user && repo.Owner != user)
|
||||
return BadRequest(new FailedResponse("You are not allowed to do this operation"));
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Title)) issue.Title = request.Title;
|
||||
if (!string.IsNullOrEmpty(request.Description)) issue.Descripion = request.Description;
|
||||
if (request.Tag != null) issue.Tag = request.Tag;
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("{issueId}/reopen")]
|
||||
public async Task<IActionResult> ReopenIssueAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Developer);
|
||||
if (grantIssue is not Repository _) return (ActionResult) grantIssue;
|
||||
|
||||
var issue = await dbContext.RepositoryIssues.FindAsync(issueId);
|
||||
if (issue == null) return NotFound(new FailedResponse("Issue not found"));
|
||||
|
||||
issue.Closed = false;
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet("{issueId}/comments")]
|
||||
public async Task<ActionResult<ListingResponse<CommentResponse>>> GetIssueCommentsAsync(
|
||||
string userName,
|
||||
string repositoryName,
|
||||
ulong issueId)
|
||||
{
|
||||
var user = (await userManager.GetUserAsync(HttpContext.User))!;
|
||||
var grantIssue = await ValidateRepositoryAsync(userName, repositoryName, user, RepositoryRole.Reporter);
|
||||
if (grantIssue is not Repository repo) return (ActionResult) grantIssue;
|
||||
|
||||
var comments = await dbContext.RepositoryIssues
|
||||
.Where(x => x.Id == issueId && x.Repository == repo)
|
||||
.SelectMany(x => x.Contents)
|
||||
.Include(c => c.Author)
|
||||
.OrderBy(c => c.CreatedAt)
|
||||
.Select(c => new CommentResponse(
|
||||
c.Id,
|
||||
c.Author.UserName!,
|
||||
c.Content,
|
||||
c.CreatedAt,
|
||||
c.ReplyTo != null ? c.ReplyTo.Id : null))
|
||||
.ToArrayAsync();
|
||||
|
||||
return Ok(new ListingResponse<CommentResponse>(comments));
|
||||
}
|
||||
|
||||
|
||||
private async ValueTask<object> ValidateRepositoryAsync(
|
||||
string userName, string repositoryName, AppUser user, RepositoryRole role)
|
||||
{
|
||||
// 复用RepositoryInnieController中的验证逻辑
|
||||
var rp = await dbContext.Repositories
|
||||
.Include(r => r.Members)
|
||||
.ThenInclude(m => m.User)
|
||||
.Include(r => r.Owner)
|
||||
.FirstOrDefaultAsync(r => r.Owner.UserName == userName && r.Name == repositoryName);
|
||||
|
||||
if (rp == null) return NotFound(new FailedResponse($"Could not find repository {userName}:{repositoryName}"));
|
||||
if (rp.Owner != user && !rp.Members.Any(m => m.User == user && m.Role >= role))
|
||||
return Unauthorized(new FailedResponse("You are not allowed to do this operation"));
|
||||
|
||||
return rp;
|
||||
}
|
||||
}
|
||||
50
Flawless.Server/Models/RepositoryIssue.cs
Normal file
50
Flawless.Server/Models/RepositoryIssue.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Flawless.Server.Models;
|
||||
|
||||
public class RepositoryIssue
|
||||
{
|
||||
[Key, Required]
|
||||
public ulong Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public required Repository Repository { get; set; }
|
||||
|
||||
[Required]
|
||||
public required AppUser Author { get; set; }
|
||||
|
||||
[Required]
|
||||
public required string Title { get; set; }
|
||||
|
||||
[Required]
|
||||
public required DateTime CreatedAt { get; set; }
|
||||
|
||||
public string? Descripion { get; set; }
|
||||
|
||||
[Required]
|
||||
public required bool Closed { get; set; }
|
||||
|
||||
public string? Tag { get; set; }
|
||||
|
||||
public List<RepositoryIssueContent> Contents { get; set; } = new();
|
||||
}
|
||||
|
||||
public class RepositoryIssueContent
|
||||
{
|
||||
[Key, Required]
|
||||
public ulong Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public RepositoryIssue Issue { get; set; }
|
||||
|
||||
[Required]
|
||||
public required AppUser Author { get; set; }
|
||||
|
||||
[Required]
|
||||
public required DateTime CreatedAt { get; set; }
|
||||
|
||||
[Required]
|
||||
public required string Content { get; set; }
|
||||
|
||||
public RepositoryIssueContent? ReplyTo { get; set; }
|
||||
}
|
||||
@ -12,6 +12,8 @@ public class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
public DbSet<AppUserRefreshKey> RefreshTokens { get; set; }
|
||||
|
||||
public DbSet<Repository> Repositories { get; set; }
|
||||
|
||||
public DbSet<RepositoryIssue> RepositoryIssues { get; set; }
|
||||
|
||||
public async ValueTask<(bool existed, bool authorized)> CheckRepositoryExistedAuthorizedAsync(
|
||||
AppUser owner, string name, AppUser user, RepositoryRole role)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user