From b7502e5c0666154c7378469fd769b3aeb242e949 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 2 May 2013 21:44:07 -0400 Subject: Added SparkleShare invite url panel This will probably be merged into a refined, single multi-protocol url panel. --- src/main/java/com/gitblit/Constants.java | 4 +- .../com/gitblit/SparkleShareInviteServlet.java | 210 +++++++++++++++++++++ .../com/gitblit/wicket/GitBlitWebApp.properties | 5 +- .../java/com/gitblit/wicket/pages/BasePage.java | 29 ++- .../java/com/gitblit/wicket/pages/SummaryPage.html | 1 + .../java/com/gitblit/wicket/pages/SummaryPage.java | 10 + .../wicket/panels/SparkleShareInvitePanel.html | 18 ++ .../wicket/panels/SparkleShareInvitePanel.java | 52 +++++ 8 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gitblit/SparkleShareInviteServlet.java create mode 100644 src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.java (limited to 'src/main/java/com/gitblit') diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 5bd5b600..f0373464 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -56,7 +56,9 @@ public class Constants { public static final String RPC_PATH = "/rpc/"; - public static final String PAGES= "/pages/"; + public static final String PAGES = "/pages/"; + + public static final String SPARKLESHARE_INVITE_PATH = "/sparkleshare/"; public static final String BORDER = "***********************************************************"; diff --git a/src/main/java/com/gitblit/SparkleShareInviteServlet.java b/src/main/java/com/gitblit/SparkleShareInviteServlet.java new file mode 100644 index 00000000..3cabb411 --- /dev/null +++ b/src/main/java/com/gitblit/SparkleShareInviteServlet.java @@ -0,0 +1,210 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.StringUtils; + +/** + * Handles requests for Sparkleshare Invites + * + * @author James Moger + * + */ +public class SparkleShareInviteServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + public SparkleShareInviteServlet() { + super(); + } + + /** + * Returns an Sparkleshare invite url to this servlet for the repository. + * https://github.com/hbons/SparkleShare/wiki/Invites + * + * @param baseURL + * @param repository + * @param username + * @return an url + */ + public static String asLink(String baseURL, String repository, String username) { + if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') { + baseURL = baseURL.substring(0, baseURL.length() - 1); + } + String url = baseURL + Constants.SPARKLESHARE_INVITE_PATH + + ((StringUtils.isEmpty(username) ? "" : (username + "@"))) + + repository + ".xml"; + url = url.replace("https://", "sparkleshare://"); + url = url.replace("http://", "sparkleshare-unsafe://"); + return url; + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, java.io.IOException { + processRequest(request, response); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + } + + protected void processRequest(javax.servlet.http.HttpServletRequest request, + javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, + java.io.IOException { + + // extract repo name from request + String path = request.getPathInfo(); + if (path != null && path.length() > 1) { + if (path.charAt(0) == '/') { + path = path.substring(1); + } + } + // trim trailing .xml + if (path.endsWith(".xml")) { + path = path.substring(0, path.length() - 4); + } + + String username = null; + int fetch = path.indexOf('@'); + if (fetch > -1) { + username = path.substring(0, fetch); + path = path.substring(fetch + 1); + } + UserModel user; + if (StringUtils.isEmpty(username)) { + user = GitBlit.self().authenticate(request); + } else { + user = GitBlit.self().getUserModel(username); + } + if (user == null) { + user = UserModel.ANONYMOUS; + username = ""; + } + + // ensure that the requested repository exists and is sparkleshared + RepositoryModel model = GitBlit.self().getRepositoryModel(path); + if (model == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + response.getWriter().append(MessageFormat.format("Repository \"{0}\" not found!", path)); + return; + } else if (!model.isSparkleshared()) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.getWriter().append(MessageFormat.format("Repository \"{0}\" is not sparkleshared!", path)); + return; + } + + if (GitBlit.getBoolean(Keys.git.enableGitServlet, true) + || GitBlit.getInteger(Keys.git.daemonPort, 0) > 0) { + // Gitblit as server + // determine username for repository url + if (model.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + if (!user.canRewindRef(model)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.getWriter().append(MessageFormat.format("\"{0}\" does not have RW+ permissions for {1}!", user.username, path)); + return; + } + } + + if (model.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + username = user.username + "@"; + } else { + username = ""; + } + + String serverPort = ""; + if (request.getScheme().equals("https")) { + if (request.getServerPort() != 443) { + serverPort = ":" + request.getServerPort(); + } + } else if (request.getScheme().equals("http")) { + if (request.getServerPort() != 80) { + serverPort = ":" + request.getServerPort(); + } + } + + // assume http/https serving + String scheme = request.getScheme(); + String servletPath = Constants.GIT_PATH; + + // try to switch to git://, if git servlet disabled and repo has no restrictions + if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true) + && (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0) + && AccessRestrictionType.NONE == model.accessRestriction) { + scheme = "git"; + servletPath = "/"; + serverPort = GitBlit.getString(Keys.git.daemonPort, ""); + } + + // construct Sparkleshare invite + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("\n"); + sb.append(MessageFormat.format("
{0}://{1}{2}{3}{4}
\n", scheme, username, request.getServerName(), serverPort, request.getContextPath())); + sb.append(MessageFormat.format("{0}{1}\n", servletPath, model.name)); + if (GitBlit.getInteger(Keys.fanout.port, 0) > 0) { + // Gitblit is running it's own fanout service for pubsub notifications + sb.append(MessageFormat.format("tcp://{0}:{1}\n", request.getServerName(), GitBlit.getString(Keys.fanout.port, ""))); + } + sb.append("
\n"); + + // write invite to client + response.setContentType("application/xml"); + response.setContentLength(sb.length()); + response.getWriter().append(sb.toString()); + } else { + // Gitblit as viewer, repository access handled externally so + // assume RW+ permission + List others = GitBlit.getStrings(Keys.web.otherUrls); + if (others.size() == 0) { + return; + } + + String address = MessageFormat.format(others.get(0), "", username); + + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("\n"); + + sb.append(MessageFormat.format("
{0}
\n", address)); + sb.append(MessageFormat.format("{0}\n", model.name)); + if (GitBlit.getInteger(Keys.fanout.port, 0) > 0) { + // Gitblit is running it's own fanout service for pubsub notifications + sb.append(MessageFormat.format("tcp://{0}:{1}\n", request.getServerName(), GitBlit.getString(Keys.fanout.port, ""))); + } + sb.append("
\n"); + + // write invite to client + response.setContentType("application/xml"); + response.setContentLength(sb.length()); + response.getWriter().append(sb.toString()); + } + } +} diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index aa5a415a..049cc408 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -445,10 +445,11 @@ gb.isSparkleshared = repository is Sparkleshared gb.owners = owners gb.sessionEnded = Session has been closed gb.closeBrowser = Please close the browser to properly end the session. -gb.doesNotExistInTree = {0} does not exist in tree {1} +gb.doesNotExistInTree = {0} does not exist in tree {1} gb.enableIncrementalPushTags = enable incremental push tags gb.useIncrementalPushTagsDescription = on push, automatically tag each branch tip with an incremental revision number gb.incrementalPushTagMessage = Auto-tagged [{0}] branch on push gb.externalPermissions = {0} access permissions for {1} are externally maintained gb.viewAccess = You do not have Gitblit read or write access -gb.yourProtocolPermissionIs = Your {0} access permission for {1} is {2} \ No newline at end of file +gb.yourProtocolPermissionIs = Your {0} access permission for {1} is {2} +gb.sparkleshareInvite = SparkleShare invite \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.java b/src/main/java/com/gitblit/wicket/pages/BasePage.java index b2dcce3f..b3b0767b 100644 --- a/src/main/java/com/gitblit/wicket/pages/BasePage.java +++ b/src/main/java/com/gitblit/wicket/pages/BasePage.java @@ -57,6 +57,7 @@ import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit; import com.gitblit.Keys; +import com.gitblit.SparkleShareInviteServlet; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TeamModel; @@ -311,7 +312,33 @@ public abstract class BasePage extends SessionPage { return new Label(wicketId).setVisible(false); } } - + + protected String getSparkleShareInviteUrl(RepositoryModel repository) { + if (repository.isBare && repository.isSparkleshared()) { + UserModel user = GitBlitWebSession.get().getUser(); + if (user == null) { + user = UserModel.ANONYMOUS; + } + String username = null; + if (UserModel.ANONYMOUS != user) { + username = user.username; + } + if (GitBlit.getBoolean(Keys.git.enableGitServlet, true) || (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0)) { + // Gitblit as server + // ensure user can rewind + if (user.canRewindRef(repository)) { + String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); + return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); + } + } else { + // Gitblit as viewer, assume RW+ permission + String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); + return SparkleShareInviteServlet.asLink(baseURL, repository.name, username); + } + } + return null; + } + protected List getProjectModels() { final UserModel user = GitBlitWebSession.get().getUser(); List projects = GitBlit.self().getProjectModels(user, true); diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html index a751d1f0..c9bce401 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html @@ -26,6 +26,7 @@
+
[repository sparkleshare invite url]
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java index 863974b3..f092a387 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java @@ -60,6 +60,7 @@ import com.gitblit.wicket.panels.BranchesPanel; import com.gitblit.wicket.panels.DetailedRepositoryUrlPanel; import com.gitblit.wicket.panels.LinkPanel; import com.gitblit.wicket.panels.LogPanel; +import com.gitblit.wicket.panels.SparkleShareInvitePanel; import com.gitblit.wicket.panels.TagsPanel; public class SummaryPage extends RepositoryPage { @@ -167,6 +168,15 @@ public class SummaryPage extends RepositoryPage { } add(gitDaemonUrlPanel); + String sparkleshareUrl = getSparkleShareInviteUrl(model); + if (StringUtils.isEmpty(sparkleshareUrl)) { + add(new Label("repositorySparkleShareInviteUrl").setVisible(false)); + } else { + Component sparklesharePanel = new SparkleShareInvitePanel("repositorySparkleShareInviteUrl", getLocalizer(), this, sparkleshareUrl, accessPermission); + WicketUtils.setCssStyle(sparklesharePanel, "padding-top: 10px;"); + add(sparklesharePanel); + } + ListDataProvider urls = new ListDataProvider(repositoryUrls); DataView otherUrlsView = new DataView("otherUrls", urls) { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.html b/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.html new file mode 100644 index 00000000..483050c5 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + [access permission] + + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.java b/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.java new file mode 100644 index 00000000..5d7aa589 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SparkleShareInvitePanel.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import org.apache.wicket.Component; +import org.apache.wicket.Localizer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.image.ContextImage; +import org.apache.wicket.markup.html.link.ExternalLink; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.wicket.WicketUtils; + +public class SparkleShareInvitePanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + public SparkleShareInvitePanel(String wicketId, Localizer localizer, Component parent, String url, AccessPermission ap) { + super(wicketId); + ContextImage star = WicketUtils.newImage("sparkleshareIcon", "star_16x16.png"); + add(star); + add(new ExternalLink("inviteUrl", url)); + String note = localizer.getString("gb.externalAccess", parent); + String permission = ""; + if (ap != null) { + permission = ap.toString(); + if (ap.atLeast(AccessPermission.PUSH)) { + note = localizer.getString("gb.readWriteAccess", parent); + } else if (ap.atLeast(AccessPermission.CLONE)) { + note = localizer.getString("gb.readOnlyAccess", parent); + } else { + note = localizer.getString("gb.viewAccess", parent); + } + } + Label label = new Label("accessPermission", permission); + WicketUtils.setHtmlTooltip(label, note); + add(label); + } +} -- cgit v1.2.3