mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-29 08:00:19 +01:00
Oof there's the Update of RepositoryController for ya
This commit is contained in:
@@ -24,7 +24,13 @@ namespace Tgstation.Server.Api.Models
|
||||
/// If the repository was cloned from GitHub.com. If <see langword="true"/> this enables test merge functionality
|
||||
/// </summary>
|
||||
[Permissions(DenyWrite = true)]
|
||||
public bool IsGitHub { get; set; }
|
||||
public bool? IsGitHub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Do the equivalent of a git pull. Will attempt to merge unless <see cref="Reference"/> is also specified
|
||||
/// </summary>
|
||||
[Permissions(WriteRight = RepositoryRights.UpdateBranch)]
|
||||
public bool? UpdateReference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The branch or tag HEAD points to
|
||||
|
||||
@@ -5,10 +5,15 @@ namespace Tgstation.Server.Api.Models
|
||||
/// <inheritdoc />
|
||||
public sealed class RevisionInformation : Internal.RevisionInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="TestMerge"/> that was created with this <see cref="RevisionInformation"/>
|
||||
/// </summary>
|
||||
public TestMerge PrimaryTestMerge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TestMerge"/>s active in the <see cref="RevisionInformation"/>
|
||||
/// </summary>
|
||||
public List<TestMerge> TestMerges { get; set; }
|
||||
public List<TestMerge> ActiveTestMerges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CompileJob"/>s made from the <see cref="RevisionInformation"/>
|
||||
|
||||
@@ -14,6 +14,21 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// </summary>
|
||||
bool IsGitHubRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Octokit.Repository.Owner"/> if this <see cref="IsGitHubRepository"/>
|
||||
/// </summary>
|
||||
string GitHubOwner { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Octokit.Repository.Name"/> if this <see cref="IsGitHubRepository"/>
|
||||
/// </summary>
|
||||
string GitHubRepoName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="Reference"/> tracks an upstream branch
|
||||
/// </summary>
|
||||
bool Tracking { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The SHA of the <see cref="IRepository"/> HEAD
|
||||
/// </summary>
|
||||
@@ -46,9 +61,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="committerEmail">The e-mail of the merge committer</param>
|
||||
/// <param name="accessString">The access string to fetch from the origin repository</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <param name="mergerIdentifier">A string to identify the user that merged</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the SHA of the new HEAD on success, <see langword="null"/> on merge conflict</returns>
|
||||
Task<string> AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, string mergerIdentifier, CancellationToken cancellationToken);
|
||||
Task<string> AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Fetch commits from the origin repository
|
||||
|
||||
@@ -22,6 +22,15 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <inheritdoc />
|
||||
public bool IsGitHubRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GitHubOwner { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GitHubRepoName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Tracking => repository.Head.IsTracking;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Head => repository.Head.Tip.Sha;
|
||||
|
||||
@@ -51,6 +60,19 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// </summary>
|
||||
readonly Action onDispose;
|
||||
|
||||
static void GetRepositoryOwnerName(string remote, out string owner, out string name)
|
||||
{
|
||||
//Assume standard gh format: [(git)|(https)]://github.com/owner/repo(.git)[0-1]
|
||||
//Yes use .git twice in case it was weird
|
||||
var toRemove = new string[] { ".git", "/", ".git" };
|
||||
foreach (string item in toRemove)
|
||||
if (remote.EndsWith(item, StringComparison.OrdinalIgnoreCase))
|
||||
remote = remote.Substring(0, remote.LastIndexOf(item, StringComparison.OrdinalIgnoreCase));
|
||||
var splits = remote.Split('/');
|
||||
name = splits[splits.Length - 1];
|
||||
owner = splits[splits.Length - 2].Split('.')[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="Repository"/>
|
||||
/// </summary>
|
||||
@@ -65,6 +87,12 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
|
||||
this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose));
|
||||
IsGitHubRepository = Origin.ToUpperInvariant().Contains("://GITHUB.COM/");
|
||||
if (IsGitHubRepository)
|
||||
{
|
||||
GetRepositoryOwnerName(Origin, out var owner, out var name);
|
||||
GitHubOwner = owner;
|
||||
GitHubRepoName = name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -106,7 +134,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, string mergerIdentifier, CancellationToken cancellationToken)
|
||||
public async Task<string> AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
if (!IsGitHubRepository)
|
||||
|
||||
@@ -116,14 +116,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
InstanceName = instance.Name,
|
||||
Revision = dmbProvider.CompileJob.RevisionInformation
|
||||
};
|
||||
interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.TestMerges.Select(x => new TestMerge
|
||||
interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).Select(x => new TestMerge
|
||||
{
|
||||
Author = x.Author,
|
||||
Body = x.BodyAtMerge,
|
||||
Comment = x.Comment,
|
||||
CommitSha = x.RevisionInformation.CommitSha,
|
||||
CommitSha = x.PrimaryRevisionInformation.CommitSha,
|
||||
Number = x.Number,
|
||||
OriginCommitSha = x.RevisionInformation.OriginCommitSha,
|
||||
OriginCommitSha = x.PrimaryRevisionInformation.OriginCommitSha,
|
||||
PullRequestCommit = x.PullRequestRevision,
|
||||
TimeMerged = x.MergedAt.Ticks,
|
||||
Title = x.TitleAtMerge,
|
||||
|
||||
@@ -3,7 +3,9 @@ using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Tgstation.Server.Api.Models;
|
||||
@@ -15,7 +17,7 @@ using Tgstation.Server.Host.Security;
|
||||
namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller for managing the <see cref="Api.Models.Repository"/>s
|
||||
/// Controller for managing the <see cref="Repository"/>s
|
||||
/// </summary>
|
||||
[Route("/" + nameof(Repository))]
|
||||
public sealed class RepositoryController : ModelController<Repository>
|
||||
@@ -25,30 +27,32 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// </summary>
|
||||
readonly IInstanceManager instanceManager;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Octokit.IGitHubClient"/> for the <see cref="RepositoryController"/>
|
||||
/// </summary>
|
||||
readonly Octokit.IGitHubClient gitHubClient;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="RepositoryController"/>
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
|
||||
/// <param name="instanceManager">The value of <see cref="instanceManager"/></param>
|
||||
public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory, true)
|
||||
/// <param name="gitHubClient">The value of <see cref="gitHubClient"/></param>
|
||||
public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, Octokit.IGitHubClient gitHubClient) : base(databaseContext, authenticationContextFactory, true)
|
||||
{
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
this.gitHubClient = gitHubClient ?? throw new ArgumentNullException(nameof(gitHubClient));
|
||||
}
|
||||
|
||||
static string GetAccessString(Api.Models.Internal.RepositorySettings repositorySettings) => repositorySettings.AccessUser != null ? String.Concat(repositorySettings.AccessUser, '@', repositorySettings.AccessToken) : null;
|
||||
|
||||
async Task<bool> PopulateApi(Repository model, Components.Repository.IRepository repository, string lastOriginCommitSha, CancellationToken cancellationToken)
|
||||
async Task<bool> LoadRevisionInformation(Components.Repository.IRepository repository, Action<Models.RevisionInformation> revInfoSink, CancellationToken cancellationToken)
|
||||
{
|
||||
model.IsGitHub = repository.IsGitHubRepository;
|
||||
model.Origin = repository.Origin;
|
||||
model.Reference = repository.Reference;
|
||||
model.Sha = repository.Head;
|
||||
|
||||
//rev info stuff
|
||||
var revisionInfo = await DatabaseContext.RevisionInformations.Where(x => x.CommitSha == model.Sha)
|
||||
var repoSha = repository.Head;
|
||||
var revisionInfo = await DatabaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha)
|
||||
.Include(x => x.CompileJobs)
|
||||
.Include(x => x.TestMerges) //minimal info, they can query the rest if they're allowed
|
||||
.Include(x => x.ActiveTestMerges) //minimal info, they can query the rest if they're allowed
|
||||
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); //search every rev info because LOL SHA COLLISIONS
|
||||
|
||||
var needsDbUpdate = revisionInfo == default;
|
||||
@@ -57,16 +61,30 @@ namespace Tgstation.Server.Host.Controllers
|
||||
//needs insertion
|
||||
revisionInfo = new Models.RevisionInformation
|
||||
{
|
||||
CommitSha = model.Sha,
|
||||
CommitSha = repoSha,
|
||||
CompileJobs = new List<Models.CompileJob>(),
|
||||
TestMerges = new List<Models.TestMerge>(), //non null vals for api returns
|
||||
OriginCommitSha = lastOriginCommitSha ?? model.Sha
|
||||
ActiveTestMerges = new List<Models.RevInfoTestMerge>() //non null vals for api returns
|
||||
};
|
||||
|
||||
DatabaseContext.RevisionInformations.Add(revisionInfo);
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
lock (DatabaseContext) //cleaner this way
|
||||
DatabaseContext.RevisionInformations.Add(revisionInfo);
|
||||
}
|
||||
revInfoSink?.Invoke(revisionInfo);
|
||||
return needsDbUpdate;
|
||||
}
|
||||
|
||||
async Task<bool> PopulateApi(Repository model, Components.Repository.IRepository repository, string lastOriginCommitSha, Action<Models.RevisionInformation> revInfoSink, CancellationToken cancellationToken)
|
||||
{
|
||||
model.IsGitHub = repository.IsGitHubRepository;
|
||||
model.Origin = repository.Origin;
|
||||
model.Reference = repository.Reference;
|
||||
model.Sha = repository.Head;
|
||||
|
||||
//rev info stuff
|
||||
Models.RevisionInformation revisionInfo = null;
|
||||
var needsDbUpdate = await LoadRevisionInformation(repository, x => revisionInfo = x, cancellationToken).ConfigureAwait(false);
|
||||
revisionInfo.OriginCommitSha = lastOriginCommitSha ?? model.Sha;
|
||||
revInfoSink?.Invoke(revisionInfo);
|
||||
model.RevisionInformation = revisionInfo.ToApi();
|
||||
return needsDbUpdate;
|
||||
}
|
||||
@@ -102,7 +120,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
//clone conflict
|
||||
return Conflict();
|
||||
var api = currentModel.ToApi();
|
||||
await PopulateApi(api, repo, null, cancellationToken).ConfigureAwait(false);
|
||||
await PopulateApi(api, repo, null, null, cancellationToken).ConfigureAwait(false);
|
||||
currentModel.LastOriginCommitSha = repo.Head;
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
return Json(api);
|
||||
@@ -146,7 +164,164 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, cancellationToken).ConfigureAwait(false))
|
||||
if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, null, cancellationToken).ConfigureAwait(false))
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
return Json(api);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[TgsAuthorize(RepositoryRights.ChangeAutoUpdateSettings | RepositoryRights.ChangeCommitter | RepositoryRights.ChangeCredentials | RepositoryRights.ChangeTestMergeCommits | RepositoryRights.MergePullRequest | RepositoryRights.SetReference | RepositoryRights.SetSha | RepositoryRights.UpdateBranch)]
|
||||
public override async Task<IActionResult> Update([FromBody]Repository model, CancellationToken cancellationToken)
|
||||
{
|
||||
if (model == null)
|
||||
return BadRequest(new { message = "Missing request model!" });
|
||||
|
||||
if (model.AccessUser == null ^ model.AccessToken == null)
|
||||
return BadRequest(new { message = "Either both accessToken and accessUser must be present or neither!" });
|
||||
|
||||
if (model.Sha != null && model.Reference != null)
|
||||
return BadRequest(new { message = "Only one of sha or reference may be specified!" });
|
||||
|
||||
if(model.Sha != null && model.UpdateReference == true)
|
||||
return BadRequest(new { message = "Cannot update a reference when checking out a sha!" });
|
||||
|
||||
if (model.Origin != null)
|
||||
return BadRequest(new { message = "origin cannot be modified without deleting the repository!" });
|
||||
|
||||
var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0;
|
||||
var userRights = (RepositoryRights)AuthenticationContext.GetRight(RightsType.Repository);
|
||||
if (newTestMerges && !userRights.HasFlag(RepositoryRights.MergePullRequest))
|
||||
return Forbid();
|
||||
|
||||
var currentModel = await DatabaseContext.RepositorySettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (currentModel == default)
|
||||
return StatusCode((int)HttpStatusCode.Gone);
|
||||
|
||||
bool CheckModified<T>(Expression<Func<Api.Models.Internal.RepositorySettings, T>> expression, RepositoryRights requiredRight)
|
||||
{
|
||||
var memberSelectorExpression = (MemberExpression)expression.Body;
|
||||
var property = (PropertyInfo)memberSelectorExpression.Member;
|
||||
|
||||
var newVal = property.GetValue(model);
|
||||
if (newVal == null)
|
||||
return false;
|
||||
if (!userRights.HasFlag(requiredRight) && property.GetValue(currentModel) != newVal)
|
||||
return true;
|
||||
|
||||
property.SetValue(currentModel, newVal);
|
||||
return false;
|
||||
};
|
||||
|
||||
if (CheckModified(x => x.AccessToken, RepositoryRights.ChangeCredentials)
|
||||
|| CheckModified(x => x.AccessUser, RepositoryRights.ChangeCredentials)
|
||||
|| CheckModified(x => x.AutoUpdatesKeepTestMerges, RepositoryRights.ChangeAutoUpdateSettings)
|
||||
|| CheckModified(x => x.AutoUpdatesSynchronize, RepositoryRights.ChangeAutoUpdateSettings)
|
||||
|| CheckModified(x => x.CommitterEmail, RepositoryRights.ChangeCommitter)
|
||||
|| CheckModified(x => x.CommitterName, RepositoryRights.ChangeCommitter)
|
||||
|| CheckModified(x => x.PushTestMergeCommits, RepositoryRights.ChangeTestMergeCommits)
|
||||
|| CheckModified(x => x.ShowTestMergeCommitters, RepositoryRights.ChangeTestMergeCommits))
|
||||
return Forbid();
|
||||
|
||||
//so that's the stuff that is just db, the rest is tricky
|
||||
|
||||
using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
if (newTestMerges && !repo.IsGitHubRepository)
|
||||
return Conflict(new { message = "Cannot test merge on a non GitHub based repository!" });
|
||||
|
||||
var committerName = currentModel.ShowTestMergeCommitters.Value ? AuthenticationContext.User.Name : currentModel.CommitterName;
|
||||
var accessString = GetAccessString(currentModel);
|
||||
if (model.UpdateReference == true)
|
||||
{
|
||||
if (!repo.Tracking && model.Reference == null)
|
||||
return Conflict(new { message = "Not on an updatable reference!" });
|
||||
if (!userRights.HasFlag(RepositoryRights.UpdateBranch))
|
||||
return Forbid();
|
||||
await repo.FetchOrigin(accessString, cancellationToken).ConfigureAwait(false);
|
||||
if (model.Sha == null && model.Reference == null)
|
||||
await repo.MergeOrigin(committerName, currentModel.CommitterEmail, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (model.Sha != null || model.Reference != null)
|
||||
{
|
||||
await repo.CheckoutObject(model.Sha ?? model.Reference, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (model.UpdateReference == true && model.Reference != null)
|
||||
{
|
||||
if (!repo.Tracking)
|
||||
return Conflict(new { message = "Checked out reference is does not track an object!" });
|
||||
await repo.ResetToOrigin(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
//now add any testmerges
|
||||
if (newTestMerges)
|
||||
{
|
||||
var repoOwner = repo.GitHubOwner;
|
||||
var repoName = repo.GitHubRepoName;
|
||||
var allAddedTestMerges = new List<Models.TestMerge>();
|
||||
foreach (var I in model.NewTestMerges)
|
||||
{
|
||||
await repo.AddTestMerge(I.Number, I.PullRequestRevision, committerName, currentModel.CommitterEmail, accessString, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Octokit.PullRequest pr = null;
|
||||
string errorMessage = null;
|
||||
|
||||
Models.RevisionInformation revisionInformation = null;
|
||||
var revInfoTask = LoadRevisionInformation(repo, x => revisionInformation = x, cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
pr = await gitHubClient.PullRequest.Get(repoOwner, repoName, I.Number).ConfigureAwait(false);
|
||||
}
|
||||
catch (Octokit.RateLimitExceededException)
|
||||
{
|
||||
//you look at your anonymous access and sigh
|
||||
errorMessage = "PRE RATE LIMITED";
|
||||
}
|
||||
catch (Octokit.NotFoundException)
|
||||
{
|
||||
//you look at your shithub access and sigh
|
||||
errorMessage = "PRE NOT FOUND";
|
||||
}
|
||||
|
||||
var attachedContextUser = new Models.User
|
||||
{
|
||||
Id = AuthenticationContext.User.Id
|
||||
};
|
||||
DatabaseContext.Users.Attach(attachedContextUser);
|
||||
|
||||
var tm = new Models.TestMerge
|
||||
{
|
||||
Author = pr?.User.Login ?? errorMessage,
|
||||
BodyAtMerge = pr?.Body,
|
||||
MergedAt = DateTimeOffset.Now,
|
||||
TitleAtMerge = pr?.Title ?? errorMessage,
|
||||
Comment = I.Comment,
|
||||
Number = I.Number,
|
||||
MergedBy = attachedContextUser,
|
||||
PullRequestRevision = I.PullRequestRevision,
|
||||
Url = pr?.HtmlUrl ?? errorMessage
|
||||
};
|
||||
if (pr == null)
|
||||
tm.BodyAtMerge = errorMessage;
|
||||
|
||||
allAddedTestMerges.Add(tm);
|
||||
|
||||
await revInfoTask.ConfigureAwait(false);
|
||||
|
||||
revisionInformation.PrimaryTestMerge = tm;
|
||||
revisionInformation.ActiveTestMerges.AddRange(allAddedTestMerges.Select(x => new RevInfoTestMerge
|
||||
{
|
||||
TestMerge = x
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
var api = currentModel.ToApi();
|
||||
if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, null, cancellationToken).ConfigureAwait(false) || newTestMerges)
|
||||
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
return Json(api);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace Tgstation.Server.Host.Models
|
||||
/// <inheritdoc />
|
||||
public DbSet<ReattachInformation> ReattachInformations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RevInfoTestMerge"/>s om the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// </summary>
|
||||
public DbSet<RevInfoTestMerge> RevInfoTestMerges { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DbSet<WatchdogReattachInformation> WatchdogReattachInformations { get; set; }
|
||||
|
||||
@@ -96,9 +101,12 @@ namespace Tgstation.Server.Host.Models
|
||||
|
||||
modelBuilder.Entity<InstanceUser>().HasIndex(x => new { x.UserId, x.InstanceId }).IsUnique();
|
||||
|
||||
modelBuilder.Entity<TestMerge>().HasMany(x => x.RevisonInformations).WithOne(x => x.TestMerge).OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
var revInfo = modelBuilder.Entity<RevisionInformation>();
|
||||
revInfo.HasMany(x => x.CompileJobs).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
|
||||
revInfo.HasMany(x => x.TestMerges).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
|
||||
revInfo.HasMany(x => x.ActiveTestMerges).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
|
||||
revInfo.HasOne(x => x.PrimaryTestMerge).WithOne(x => x.PrimaryRevisionInformation).OnDelete(DeleteBehavior.SetNull);
|
||||
revInfo.HasIndex(x => x.CommitSha).IsUnique();
|
||||
|
||||
var chatChannel = modelBuilder.Entity<ChatChannel>();
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Tgstation.Server.Host.Models
|
||||
|
||||
/// <inheritdoc />
|
||||
public Repository ToApi() => new Repository {
|
||||
AccessToken = AccessToken,
|
||||
//AccessToken = AccessToken, //never show this
|
||||
AccessUser = AccessUser,
|
||||
AutoUpdatesKeepTestMerges = AutoUpdatesKeepTestMerges,
|
||||
AutoUpdatesSynchronize = AutoUpdatesSynchronize,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Many to many relationship for <see cref="Models.RevisionInformation"/> and <see cref="Models.TestMerge"/>
|
||||
/// </summary>
|
||||
public sealed class RevInfoTestMerge
|
||||
{
|
||||
/// <summary>
|
||||
/// The row Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.TestMerge"/>
|
||||
/// </summary>
|
||||
[Required]
|
||||
public TestMerge TestMerge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.RevisionInformation"/>
|
||||
/// </summary>
|
||||
[Required]
|
||||
public RevisionInformation RevisionInformation { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,14 @@ namespace Tgstation.Server.Host.Models
|
||||
public Instance Instance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="Api.Models.RevisionInformation.TestMerges"/>
|
||||
/// See <see cref="Api.Models.RevisionInformation.PrimaryTestMerge"/>
|
||||
/// </summary>
|
||||
public List<TestMerge> TestMerges { get; set; }
|
||||
public TestMerge PrimaryTestMerge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="Api.Models.RevisionInformation.ActiveTestMerges"/>
|
||||
/// </summary>
|
||||
public List<RevInfoTestMerge> ActiveTestMerges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="CompileJob"/>s made from this <see cref="RevisionInformation"/>
|
||||
@@ -31,7 +36,8 @@ namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
CommitSha = CommitSha,
|
||||
OriginCommitSha = OriginCommitSha,
|
||||
TestMerges = TestMerges.Select(x => x.ToApi()).ToList(),
|
||||
PrimaryTestMerge = PrimaryTestMerge?.ToApi(),
|
||||
ActiveTestMerges = ActiveTestMerges.Select(x => x.TestMerge.ToApi()).ToList(),
|
||||
CompileJobs = CompileJobs.Select(x => x.ToApi()).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Tgstation.Server.Host.Models
|
||||
{
|
||||
@@ -12,10 +13,19 @@ namespace Tgstation.Server.Host.Models
|
||||
public User MergedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.RevisionInformation"/> for the <see cref="TestMerge"/>
|
||||
/// The initial <see cref="RevisionInformation"/> the <see cref="TestMerge"/> was merged with
|
||||
/// </summary>
|
||||
[Required]
|
||||
public RevisionInformation RevisionInformation { get; set; }
|
||||
public RevisionInformation PrimaryRevisionInformation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Foreign key for <see cref="PrimaryRevisionInformation"/>
|
||||
/// </summary>
|
||||
public long? PrimaryRevisionInformationId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All the <see cref="RevInfoTestMerge"/> for the <see cref="TestMerge"/>
|
||||
/// </summary>
|
||||
public List<RevInfoTestMerge> RevisonInformations { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Api.Models.TestMerge ToApi() => new Api.Models.TestMerge
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.Security
|
||||
|
||||
var res = NativeMethods.LogonUser(splits.Length > 1 ? splits[1] : splits[0], splits.Length > 1 ? splits[0] : null, password, 3 /*LOGON32_LOGON_NETWORK*/, 0 /*LOGON32_PROVIDER_DEFAULT*/, out var token);
|
||||
if (!res)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
return null;
|
||||
|
||||
using (var handle = new SafeAccessTokenHandle(token)) //checked internally, windows identity always duplicates the handle when constructed with a userToken
|
||||
return (ISystemIdentity)new WindowsSystemIdentity(new WindowsIdentity(handle.DangerousGetHandle())); //https://github.com/dotnet/corefx/blob/6ed61acebe3214fcf79b4274f2bb9b55c0604a4d/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs#L271
|
||||
|
||||
Reference in New Issue
Block a user