You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
451 lines
16 KiB
451 lines
16 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Web;
|
|
using System.Web.Mvc;
|
|
using GitCandy.App_GlobalResources;
|
|
using GitCandy.Base;
|
|
using GitCandy.Configuration;
|
|
using GitCandy.Data;
|
|
using GitCandy.Filters;
|
|
using GitCandy.Git;
|
|
using GitCandy.Git.Cache;
|
|
using GitCandy.Models;
|
|
using GitCandy.Ssh;
|
|
using NewLife.Log;
|
|
|
|
namespace GitCandy.Controllers
|
|
{
|
|
public class RepositoryController : CandyControllerBase
|
|
{
|
|
public RepositoryService RepositoryService { get; set; } = new RepositoryService();
|
|
|
|
public ActionResult Index()
|
|
{
|
|
var username = Token == null ? null : Token.Username;
|
|
var p = new NewLife.Web.Pager();
|
|
p.PageSize = 20;
|
|
var model = RepositoryService.GetRepositories(username, Token != null && Token.IsSystemAdministrator, p);
|
|
model.CanCreateRepository = Token != null && (UserConfiguration.Current.AllowRepositoryCreation || Token.IsSystemAdministrator);
|
|
return View(model);
|
|
}
|
|
|
|
[AllowRepositoryCreation]
|
|
public ActionResult Create()
|
|
{
|
|
var model = new RepositoryModel
|
|
{
|
|
IsPrivate = false,
|
|
AllowAnonymousRead = true,
|
|
AllowAnonymousWrite = false,
|
|
};
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
[AllowRepositoryCreation]
|
|
public ActionResult Create(RepositoryModel model)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
bool badName;
|
|
var repo = RepositoryService.Create(model, Token.UserID, out badName);
|
|
if (repo != null)
|
|
{
|
|
var success = GitService.CreateRepository(model.Name);
|
|
if (!success)
|
|
{
|
|
RepositoryService.Delete(model.Name);
|
|
repo = null;
|
|
}
|
|
}
|
|
if (repo != null)
|
|
{
|
|
return RedirectToAction("Detail", "Repository", new { name = repo.Name });
|
|
}
|
|
if (badName)
|
|
ModelState.AddModelError("Name", SR.Repository_AlreadyExists);
|
|
}
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Detail(string name)
|
|
{
|
|
var model = RepositoryService.GetRepositoryModel(name, true, Token == null ? null : Token.Username);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
using (var git = new GitService(name))
|
|
{
|
|
model.DefaultBranch = git.GetHeadBranch();
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public ActionResult Edit(string name)
|
|
{
|
|
var model = RepositoryService.GetRepositoryModel(name, username: Token.Username);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
using (var git = new GitService(name))
|
|
{
|
|
model.DefaultBranch = git.GetHeadBranch();
|
|
model.LocalBranches = git.GetLocalBranches();
|
|
}
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public ActionResult Edit(string name, RepositoryModel model)
|
|
{
|
|
if (string.IsNullOrEmpty(name))
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
if (!RepositoryService.Update(model))
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
using (var git = new GitService(name))
|
|
{
|
|
git.SetHeadBranch(model.DefaultBranch);
|
|
}
|
|
return RedirectToAction("Detail", new { name });
|
|
}
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public ActionResult Coop(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name))
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
|
|
var model = RepositoryService.GetRepositoryCollaborationModel(name);
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public JsonResult ChooseUser(string name, string user, string act, string value)
|
|
{
|
|
string message = null;
|
|
|
|
if (act == "add")
|
|
{
|
|
var role = RepositoryService.RepositoryAddUser(name, user);
|
|
if (role != null)
|
|
return Json(new { role.AllowRead, role.AllowWrite, role.IsOwner });
|
|
}
|
|
else if (act == "del")
|
|
{
|
|
if (!Token.IsSystemAdministrator
|
|
&& string.Equals(user, Token.Username, StringComparison.OrdinalIgnoreCase))
|
|
message = SR.Account_CantRemoveSelf;
|
|
else if (RepositoryService.RepositoryRemoveUser(name, user))
|
|
return Json("success");
|
|
}
|
|
else if (act == "read" || act == "write" || act == "owner")
|
|
{
|
|
var val = string.Equals(bool.TrueString, value, StringComparison.OrdinalIgnoreCase);
|
|
if (!Token.IsSystemAdministrator
|
|
&& (act == "owner" && !val)
|
|
&& string.Equals(user, Token.Username, StringComparison.OrdinalIgnoreCase))
|
|
message = SR.Account_CantRemoveSelf;
|
|
else if (RepositoryService.RepositoryUserSetValue(name, user, act, val))
|
|
return Json("success");
|
|
}
|
|
|
|
Response.StatusCode = 400;
|
|
return Json(message ?? SR.Shared_SomethingWrong);
|
|
}
|
|
|
|
[HttpPost]
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public JsonResult ChooseTeam(string name, string team, string act, string value)
|
|
{
|
|
if (act == "add")
|
|
{
|
|
var role = RepositoryService.RepositoryAddTeam(name, team);
|
|
if (role != null)
|
|
return Json(new { role.AllowRead, role.AllowWrite });
|
|
}
|
|
else if (act == "del")
|
|
{
|
|
if (RepositoryService.RepositoryRemoveTeam(name, team))
|
|
return Json("success");
|
|
}
|
|
else if (act == "read" || act == "write" || act == "owner")
|
|
{
|
|
var val = string.Equals(bool.TrueString, value, StringComparison.OrdinalIgnoreCase);
|
|
if (RepositoryService.RepositoryTeamSetValue(name, team, act, val))
|
|
return Json("success");
|
|
}
|
|
|
|
Response.StatusCode = 400;
|
|
return Json(SR.Shared_SomethingWrong);
|
|
}
|
|
|
|
[RepositoryOwnerOrSystemAdministrator]
|
|
public ActionResult Delete(string name, string conform)
|
|
{
|
|
if (string.Equals(conform, "yes", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
RepositoryService.Delete(name);
|
|
GitService.DeleteRepository(name);
|
|
GitCacheAccessor.Delete(name);
|
|
XTrace.WriteLine("Repository {0} deleted by {1}#{2}", name, Token.Username, Token.UserID);
|
|
return RedirectToAction("Index");
|
|
}
|
|
return View((object)name);
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Tree(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetTree(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
if (model.Entries == null && model.ReferenceName != "HEAD")
|
|
return RedirectToAction("Tree", new { path = model.ReferenceName });
|
|
|
|
model.GitUrls = GetGitUrl(name);
|
|
model.RepositoryName = name;
|
|
if (model.IsRoot)
|
|
{
|
|
var m = RepositoryService.GetRepositoryModel(name);
|
|
model.Description = m.Description;
|
|
}
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Blob(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetBlob(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Blame(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetBlame(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Raw(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetBlob(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
|
|
return model.BlobType == BlobType.Binary
|
|
? new RawResult(model.RawData, FileHelper.BinaryMimeType, model.Name)
|
|
: new RawResult(model.RawData);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Commit(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetCommit(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Compare(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var start = "";
|
|
var end = "";
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
var index = path.IndexOf("...");
|
|
if (index == -1)
|
|
{
|
|
start = path;
|
|
end = "";
|
|
}
|
|
else
|
|
{
|
|
start = path.Substring(0, index);
|
|
end = path.Substring(index + 3);
|
|
}
|
|
}
|
|
var model = git.GetCompare(start.Replace(';', '/'), end.Replace(';', '/'));
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Commits(string name, string path, int? page)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetCommits(path, page ?? 1, UserConfiguration.Current.Commits);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
|
|
ViewBag.Pager = Pager.Items(model.ItemCount)
|
|
.PerPage(UserConfiguration.Current.Commits)
|
|
.Move(model.CurrentPage)
|
|
.Segment(5)
|
|
.Center();
|
|
|
|
model.RepositoryName = name;
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Archive(string name, string path, string eol = null)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
string newline = null;
|
|
switch (eol)
|
|
{
|
|
case "LF":
|
|
newline = "\n";
|
|
break;
|
|
case "CR":
|
|
newline = "\r";
|
|
break;
|
|
case "CRLF":
|
|
newline = "\r\n";
|
|
break;
|
|
default:
|
|
eol = null;
|
|
break;
|
|
}
|
|
|
|
string referenceName;
|
|
var cacheFile = git.GetArchiveFilename(path, newline, out referenceName);
|
|
if (cacheFile == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
|
|
var filename = name + "-" + referenceName;
|
|
if (eol != null)
|
|
filename += "-" + eol;
|
|
return File(cacheFile, "application/zip", filename + ".zip");
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Tags(string name)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetTags();
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
model.CanDelete = Token != null && Token.IsSystemAdministrator
|
|
|| RepositoryService.CanWriteRepository(name, Token == null ? null : Token.Username);
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
[ReadRepository(requireWrite: true)]
|
|
public ActionResult Tags(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
git.DeleteTag(path);
|
|
return Json("success");
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Branches(string name)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetBranches();
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
model.RepositoryName = name;
|
|
model.CanDelete = Token != null && Token.IsSystemAdministrator
|
|
|| RepositoryService.CanWriteRepository(name, Token == null ? null : Token.Username);
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
[ReadRepository(requireWrite: true)]
|
|
public JsonResult Branches(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
git.DeleteBranch(path);
|
|
return Json("success");
|
|
}
|
|
}
|
|
|
|
[ReadRepository]
|
|
public ActionResult Contributors(string name, string path)
|
|
{
|
|
using (var git = new GitService(name))
|
|
{
|
|
var model = git.GetContributors(path);
|
|
if (model == null)
|
|
throw new HttpException((int)HttpStatusCode.NotFound, string.Empty);
|
|
return View(model);
|
|
}
|
|
}
|
|
|
|
private GitUrl[] GetGitUrl(string name)
|
|
{
|
|
var url = Request.Url;
|
|
string path = VirtualPathUtility.ToAbsolute("~/git/" + name + ".git");
|
|
UriBuilder ub = new UriBuilder(url.Scheme, url.Host, url.Port, path);
|
|
var httpUrl = ub.Uri.ToString();
|
|
|
|
var sshPort = UserConfiguration.Current.SshPort;
|
|
var sshUrl = sshPort == StartingInfo.DefaultPort
|
|
? string.Format("git@{0}:git/{1}.git", url.Host, name)
|
|
: string.Format("ssh://git@{0}:{1}/git/{2}.git", url.Host, sshPort, name);
|
|
|
|
var result = new List<GitUrl>(4);
|
|
result.Add(new GitUrl { Type = url.Scheme, Url = httpUrl });
|
|
if (UserConfiguration.Current.EnableSsh)
|
|
result.Add(new GitUrl { Type = "ssh", Url = sshUrl });
|
|
|
|
return result.ToArray();
|
|
}
|
|
|
|
public int sshPort { get; set; }
|
|
}
|
|
}
|