From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001
From: Paul Martin <paul@paulsputer.com>
Date: Sat, 30 Apr 2016 04:19:14 -0400
Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates

---
 src/main/java/com/gitblit/wicket/pages/TicketPage.java |  135 ++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 126 insertions(+), 9 deletions(-)

diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
index 19788f2..b2e63a6 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
@@ -15,6 +15,7 @@
  */
 package com.gitblit.wicket.pages;
 
+import java.io.IOException;
 import java.text.DateFormat;
 import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
@@ -35,6 +36,7 @@
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestCycle;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.behavior.SimpleAttributeModifier;
@@ -42,12 +44,17 @@
 import org.apache.wicket.markup.html.image.ContextImage;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.link.StatelessLink;
+import org.apache.wicket.markup.html.pages.RedirectPage;
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.markup.repeater.data.DataView;
 import org.apache.wicket.markup.repeater.data.ListDataProvider;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.protocol.http.RequestUtils;
 import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.request.target.basic.RedirectRequestTarget;
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
@@ -82,16 +89,19 @@
 import com.gitblit.utils.ArrayUtils;
 import com.gitblit.utils.JGitUtils;
 import com.gitblit.utils.JGitUtils.MergeStatus;
+import com.gitblit.utils.CommitCache;
 import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.RefLogUtils;
 import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.TimeUtils;
 import com.gitblit.wicket.GitBlitWebSession;
 import com.gitblit.wicket.TicketsUI;
 import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.AvatarImage;
+import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;
 import com.gitblit.wicket.panels.BasePanel.JavascriptTextPrompt;
 import com.gitblit.wicket.panels.CommentPanel;
 import com.gitblit.wicket.panels.DiffStatPanel;
-import com.gitblit.wicket.panels.GravatarImage;
 import com.gitblit.wicket.panels.IconAjaxLink;
 import com.gitblit.wicket.panels.LinkPanel;
 import com.gitblit.wicket.panels.ShockWaveComponent;
@@ -312,7 +322,7 @@
 					if (user == null) {
 						user = new UserModel(username);
 					}
-					item.add(new GravatarImage("participant", user.getDisplayName(),
+					item.add(new AvatarImage("participant", user.getDisplayName(),
 							user.emailAddress, null, 25, true));
 				}
 			};
@@ -519,6 +529,10 @@
 		 * TICKET METADATA
 		 */
 		add(new Label("ticketType", ticket.type.toString()));
+
+		add(new Label("priority", ticket.priority.toString()));
+		add(new Label("severity", ticket.severity.toString()));
+
 		if (StringUtils.isEmpty(ticket.topic)) {
 			add(new Label("ticketTopic").setVisible(false));
 		} else {
@@ -527,6 +541,8 @@
 			String safeTopic = app().xssFilter().relaxed(topic);
 			add(new Label("ticketTopic", safeTopic).setEscapeModelStrings(false));
 		}
+
+
 
 
 		/*
@@ -730,7 +746,7 @@
 		} else {
 			// permit user to comment
 			Fragment newComment = new Fragment("newComment", "newCommentFragment", this);
-			GravatarImage img = new GravatarImage("newCommentAvatar", user.username, user.emailAddress,
+			AvatarImage img = new AvatarImage("newCommentAvatar", user.username, user.emailAddress,
 					"gravatar-round", avatarWidth, true);
 			newComment.add(img);
 			CommentPanel commentPanel = new CommentPanel("commentPanel", user, ticket, null, TicketsPage.class);
@@ -746,7 +762,7 @@
 		if (currentPatchset == null) {
 			// no patchset available
 			RepositoryUrl repoUrl = getRepositoryUrl(user, repository);
-			boolean canPropose = repoUrl != null && repoUrl.permission.atLeast(AccessPermission.CLONE) && !UserModel.ANONYMOUS.equals(user);
+			boolean canPropose = repoUrl != null && repoUrl.hasPermission() && repoUrl.permission.atLeast(AccessPermission.CLONE) && !UserModel.ANONYMOUS.equals(user);
 			if (ticket.isOpen() && app().tickets().isAcceptingNewPatchsets(repository) && canPropose) {
 				// ticket & repo will accept a proposal patchset
 				// show the instructions for proposing a patchset
@@ -810,14 +826,14 @@
 				public void populateItem(final Item<RevCommit> item) {
 					RevCommit commit = item.getModelObject();
 					PersonIdent author = commit.getAuthorIdent();
-					item.add(new GravatarImage("authorAvatar", author.getName(), author.getEmailAddress(), null, 16, false));
+					item.add(new AvatarImage("authorAvatar", author.getName(), author.getEmailAddress(), null, 16, false));
 					item.add(new Label("author", commit.getAuthorIdent().getName()));
 					item.add(new LinkPanel("commitId", null, getShortObjectId(commit.getName()),
 							CommitPage.class, WicketUtils.newObjectParameter(repositoryName, commit.getName()), true));
 					item.add(new LinkPanel("diff", "link", getString("gb.diff"), CommitDiffPage.class,
 							WicketUtils.newObjectParameter(repositoryName, commit.getName()), true));
 					item.add(new Label("title", StringUtils.trimString(commit.getShortMessage(), Constants.LEN_SHORTLOG_REFS)));
-					item.add(WicketUtils.createDateLabel("commitDate", JGitUtils.getCommitDate(commit), GitBlitWebSession
+					item.add(WicketUtils.createDateLabel("commitDate", JGitUtils.getAuthorDate(commit), GitBlitWebSession
 							.get().getTimezone(), getTimeUtils(), false));
 					item.add(new DiffStatPanel("commitDiffStat", 0, 0, true));
 				}
@@ -847,6 +863,9 @@
 				if (event.hasPatchset()) {
 					// patchset
 					Patchset patchset = event.patchset;
+					//In the case of using a cached change list
+					item.setVisible(!patchset.isDeleted());
+					
 					String what;
 					if (event.isStatusChange() && (Status.New == event.getStatus())) {
 						what = getString("gb.proposedThisChange");
@@ -874,6 +893,14 @@
 					}
 					item.add(typeLabel);
 
+					Link<Void> deleteLink = createDeletePatchsetLink(repository, patchset);
+					
+					if (user.canDeleteRef(repository)) {
+						item.add(deleteLink.setVisible(patchset.canDelete));
+					} else {
+						item.add(deleteLink.setVisible(false));
+					}
+
 					// show commit diffstat
 					item.add(new DiffStatPanel("patchsetDiffStat", patchset.insertions, patchset.deletions, patchset.rev > 1));
 				} else if (event.hasComment()) {
@@ -881,6 +908,7 @@
 					item.add(new Label("what", getString("gb.commented")));
 					item.add(new Label("patchsetRevision").setVisible(false));
 					item.add(new Label("patchsetType").setVisible(false));
+					item.add(new Label("deleteRevision").setVisible(false));
 					item.add(new Label("patchsetDiffStat").setVisible(false));
 				} else if (event.hasReview()) {
 					// review
@@ -900,11 +928,13 @@
 							.setEscapeModelStrings(false));
 					item.add(new Label("patchsetRevision").setVisible(false));
 					item.add(new Label("patchsetType").setVisible(false));
+					item.add(new Label("deleteRevision").setVisible(false));
 					item.add(new Label("patchsetDiffStat").setVisible(false));
 				} else {
 					// field change
 					item.add(new Label("patchsetRevision").setVisible(false));
 					item.add(new Label("patchsetType").setVisible(false));
+					item.add(new Label("deleteRevision").setVisible(false));
 					item.add(new Label("patchsetDiffStat").setVisible(false));
 
 					String what = "";
@@ -981,12 +1011,12 @@
 		UserModel commenter = app().users().getUserModel(entry.author);
 		if (commenter == null) {
 			// unknown user
-			container.add(new GravatarImage("changeAvatar", entry.author,
+			container.add(new AvatarImage("changeAvatar", entry.author,
 					entry.author, null, avatarSize, false).setVisible(avatarSize > 0));
 			container.add(new Label("changeAuthor", entry.author.toLowerCase()));
 		} else {
 			// known user
-			container.add(new GravatarImage("changeAvatar", commenter.getDisplayName(),
+			container.add(new AvatarImage("changeAvatar", commenter.getDisplayName(),
 					commenter.emailAddress, avatarSize > 24 ? "gravatar-round" : null,
 							avatarSize, true).setVisible(avatarSize > 0));
 			container.add(new LinkPanel("changeAuthor", null, commenter.getDisplayName(),
@@ -1425,6 +1455,12 @@
 				Fragment mergePanel = new Fragment("mergePanel", "alreadyMergedFragment", this);
 				mergePanel.add(new Label("mergeTitle", MessageFormat.format(getString("gb.patchsetAlreadyMerged"), ticket.mergeTo)));
 				return mergePanel;
+			} else if (MergeStatus.MISSING_INTEGRATION_BRANCH == mergeStatus) {
+				// target/integration branch is missing
+				Fragment mergePanel = new Fragment("mergePanel", "notMergeableFragment", this);
+				mergePanel.add(new Label("mergeTitle", MessageFormat.format(getString("gb.patchsetNotMergeable"), ticket.mergeTo)));
+				mergePanel.add(new Label("mergeMore", MessageFormat.format(getString("gb.missingIntegrationBranchMore"), ticket.mergeTo)));
+				return mergePanel;
 			} else {
 				// patchset can not be cleanly merged
 				Fragment mergePanel = new Fragment("mergePanel", "notMergeableFragment", this);
@@ -1503,7 +1539,7 @@
 	 */
 	protected RepositoryUrl getRepositoryUrl(UserModel user, RepositoryModel repository) {
 		HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest();
-		List<RepositoryUrl> urls = app().gitblit().getRepositoryUrls(req, user, repository);
+		List<RepositoryUrl> urls = app().services().getRepositoryUrls(req, user, repository);
 		if (ArrayUtils.isEmpty(urls)) {
 			return null;
 		}
@@ -1588,4 +1624,85 @@
 			return copyFragment;
 		}
 	}
+	
+	private Link<Void> createDeletePatchsetLink(final RepositoryModel repositoryModel, final Patchset patchset)
+	{
+		Link<Void> deleteLink = new Link<Void>("deleteRevision") {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick() {
+				Repository r = app().repositories().getRepository(repositoryModel.name);
+				UserModel user = GitBlitWebSession.get().getUser();
+				
+				if (r == null) {
+					if (app().repositories().isCollectingGarbage(repositoryModel.name)) {
+						error(MessageFormat.format(getString("gb.busyCollectingGarbage"), repositoryModel.name));
+					} else {
+						error(MessageFormat.format("Failed to find repository {0}", repositoryModel.name));
+					}
+					return;
+				}
+				
+				//Construct the ref name based on the patchset
+				String ticketShard = String.format("%02d", ticket.number);
+				ticketShard = ticketShard.substring(ticketShard.length() - 2);
+				final String refName = String.format("%s%s/%d/%d", Constants.R_TICKETS_PATCHSETS, ticketShard, ticket.number, patchset.number);
+
+				Ref ref = null;
+				boolean success = true;
+				
+				try {
+					ref = r.getRef(refName);
+					
+					if (ref != null) {
+						success = JGitUtils.deleteBranchRef(r, ref.getName());
+					} else {
+						success = false;
+					}
+					
+					if (success) {
+						// clear commit cache
+						CommitCache.instance().clear(repositoryModel.name, refName);
+
+						// optionally update reflog
+						if (RefLogUtils.hasRefLogBranch(r)) {
+							RefLogUtils.deleteRef(user, r, ref);
+						}
+
+						TicketModel updatedTicket = app().tickets().deletePatchset(ticket, patchset, user.username);
+												
+						if (updatedTicket == null) {
+							success = false;
+						}
+					}
+				} catch (IOException e) {
+					logger().error("failed to determine ticket from ref", e);
+					success = false;
+				} finally {
+					r.close();
+				}
+
+				if (success) {
+					getSession().info(MessageFormat.format(getString("gb.deletePatchsetSuccess"), patchset.number));
+					logger().info(MessageFormat.format("{0} deleted patchset {1} from ticket {2}", 
+							user.username, patchset.number, ticket.number));
+				} else {
+					getSession().error(MessageFormat.format(getString("gb.deletePatchsetFailure"),patchset.number));
+				}
+				
+				//Force reload of the page to rebuild ticket change cache
+				String relativeUrl = urlFor(TicketsPage.class, getPageParameters()).toString();
+				String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
+				setResponsePage(new RedirectPage(absoluteUrl));
+			}
+		};
+
+		WicketUtils.setHtmlTooltip(deleteLink, MessageFormat.format(getString("gb.deletePatchset"), patchset.number));
+		
+		deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(getString("gb.deletePatchset"), patchset.number)));
+		
+		return deleteLink;
+	}
+	
 }

--
Gitblit v1.9.1