@@ -26,6 +26,7 @@ r17: { | |||
- Use standard ServletRequestWrapper instead of custom wrapper (issue 224) | |||
changes: | |||
- Improved the repository url display. This display now indicates your repository access permission, per-protocol. | |||
- Improve Gerrit change ref decoration in the refs panel (issue 206) | |||
- Disable Gson's pretty printing which has a huge performance gain | |||
- Properly set application/json content-type on api calls | |||
@@ -33,7 +34,8 @@ r17: { | |||
- Updated Japanese translation | |||
additions: | |||
- Added GO http/https connector thread pool size setting | |||
- Added 3rd-party app clone links for SourceTree and SparkleShare | |||
- Added GO http/https connector thread pool size setting | |||
- Added a server setting to force a particular translation/Locale for all sessions | |||
- Added smart Git Daemon serving. If enabled, git:// access will be offered for any repository which permits anonymous access. If the repository permits anonymous cloning, anonymous git:// clone will be permitted while anonmymous git:// pushes will be rejected. | |||
- Option to automatically tag branch tips on each push with an incremental revision number | |||
@@ -81,8 +83,9 @@ r17: { | |||
- { name: 'git.daemonBindInterface', defaultValue: 'localhost' } | |||
- { name: 'git.daemonPort', defaultValue: 0 } | |||
- { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' } | |||
- { name: 'web.allowAppCloneLinks', defaultValue: true } | |||
- { name: 'web.forceDefaultLocale', defaultValue: ' ' } | |||
- { name: 'server.nioThreadPoolSize', defaultValue: 50 } | |||
- { name: 'server.nioThreadPoolSize', defaultValue: 50 } | |||
} | |||
# |
@@ -766,6 +766,11 @@ web.forwardSlashCharacter = / | |||
# SINCE 0.5.0 | |||
web.otherUrls = | |||
# Should app-specific clone links be displayed for SourceTree, SparkleShare, etc? | |||
# | |||
# SINCE 1.3.0 | |||
web.allowAppCloneLinks = true | |||
# Choose how to present the repositories list. | |||
# grouped = group nested/subfolder repositories together (no sorting) | |||
# flat = flat list of repositories (sorting allowed) | |||
@@ -1250,13 +1255,13 @@ server.tempFolder = ${baseFolder}/temp | |||
# RESTART REQUIRED | |||
server.useNio = true | |||
# If using Jetty NIO connectors, specify the maximum number of concurrent | |||
# http/https worker threads to allow. | |||
# | |||
# SINCE 1.3.0 | |||
# RESTART REQUIRED | |||
server.nioThreadPoolSize = 50 | |||
# If using Jetty NIO connectors, specify the maximum number of concurrent | |||
# http/https worker threads to allow. | |||
# | |||
# SINCE 1.3.0 | |||
# RESTART REQUIRED | |||
server.nioThreadPoolSize = 50 | |||
# Context path for the GO application. You might want to change the context | |||
# path if running Gitblit behind a proxy layer such as mod_proxy. | |||
# |
@@ -203,7 +203,7 @@ public class GitBlitServer { | |||
// conditionally configure the http connector | |||
if (params.port > 0) { | |||
Connector httpConnector = createConnector(params.useNIO, settings.getInteger(Keys.server.nioThreadPoolSize, 50), params.port); | |||
Connector httpConnector = createConnector(params.useNIO, settings.getInteger(Keys.server.nioThreadPoolSize, 50), params.port); | |||
String bindInterface = settings.getString(Keys.server.httpBindInterface, null); | |||
if (!StringUtils.isEmpty(bindInterface)) { | |||
logger.warn(MessageFormat.format("Binding connector on port {0,number,0} to {1}", | |||
@@ -262,7 +262,7 @@ public class GitBlitServer { | |||
if (serverKeyStore.exists()) { | |||
Connector secureConnector = createSSLConnector(params.alias, serverKeyStore, serverTrustStore, params.storePassword, | |||
caRevocationList, params.useNIO, settings.getInteger(Keys.server.nioThreadPoolSize, 50), params.securePort, params.requireClientCertificates); | |||
caRevocationList, params.useNIO, settings.getInteger(Keys.server.nioThreadPoolSize, 50), params.securePort, params.requireClientCertificates); | |||
String bindInterface = settings.getString(Keys.server.httpsBindInterface, null); | |||
if (!StringUtils.isEmpty(bindInterface)) { | |||
logger.warn(MessageFormat.format( | |||
@@ -410,16 +410,16 @@ public class GitBlitServer { | |||
* | |||
* @param useNIO | |||
* @param port | |||
* @param maxThreads | |||
* @param maxThreads | |||
* @return an http connector | |||
*/ | |||
private Connector createConnector(boolean useNIO, int port, int maxThreads) { | |||
private Connector createConnector(boolean useNIO, int port, int maxThreads) { | |||
Connector connector; | |||
if (useNIO) { | |||
logger.info("Setting up NIO SelectChannelConnector on port " + port); | |||
SelectChannelConnector nioconn = new SelectChannelConnector(); | |||
nioconn.setSoLingerTime(-1); | |||
nioconn.setThreadPool(new QueuedThreadPool(maxThreads)); | |||
nioconn.setThreadPool(new QueuedThreadPool(maxThreads)); | |||
connector = nioconn; | |||
} else { | |||
logger.info("Setting up SocketConnector on port " + port); | |||
@@ -444,13 +444,13 @@ public class GitBlitServer { | |||
* @param storePassword | |||
* @param caRevocationList | |||
* @param useNIO | |||
* @param nioThreadPoolSize | |||
* @param nioThreadPoolSize | |||
* @param port | |||
* @param requireClientCertificates | |||
* @return an https connector | |||
*/ | |||
private Connector createSSLConnector(String certAlias, File keyStore, File clientTrustStore, | |||
String storePassword, File caRevocationList, boolean useNIO, int nioThreadPoolSize, int port, | |||
String storePassword, File caRevocationList, boolean useNIO, int nioThreadPoolSize, int port, | |||
boolean requireClientCertificates) { | |||
GitblitSslContextFactory factory = new GitblitSslContextFactory(certAlias, | |||
keyStore, clientTrustStore, storePassword, caRevocationList); | |||
@@ -464,7 +464,7 @@ public class GitBlitServer { | |||
} else { | |||
factory.setWantClientAuth(true); | |||
} | |||
ssl.setThreadPool(new QueuedThreadPool(nioThreadPoolSize)); | |||
ssl.setThreadPool(new QueuedThreadPool(nioThreadPoolSize)); | |||
connector = ssl; | |||
} else { | |||
logger.info("Setting up NIO SslSocketConnector on port " + port); |
@@ -452,4 +452,7 @@ 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} | |||
gb.sparkleshareInvite = SparkleShare invite | |||
gb.cloneWithSparkleShare = clone with SparkleShare\u2122 | |||
gb.cloneWithSourceTree = clone with SourceTree\u2122 | |||
gb.cloneWithGitHub = clone with GitHub\u2122 for {0} | |||
gb.cloneWithSmartGit = clone with SmartGit\u2122 |
@@ -57,7 +57,6 @@ 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; | |||
@@ -313,32 +312,6 @@ public abstract class BasePage extends SessionPage { | |||
} | |||
} | |||
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<ProjectModel> getProjectModels() { | |||
final UserModel user = GitBlitWebSession.get().getUser(); | |||
List<ProjectModel> projects = GitBlit.self().getProjectModels(user, true); |
@@ -16,22 +16,17 @@ | |||
package com.gitblit.wicket.pages; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.wicket.PageParameters; | |||
import org.apache.wicket.markup.html.basic.Label; | |||
import com.gitblit.Constants.AccessPermission; | |||
import com.gitblit.GitBlit; | |||
import com.gitblit.Keys; | |||
import com.gitblit.models.RepositoryModel; | |||
import com.gitblit.models.UserModel; | |||
import com.gitblit.utils.ArrayUtils; | |||
import com.gitblit.wicket.GitBlitWebSession; | |||
import com.gitblit.wicket.GitblitRedirectException; | |||
import com.gitblit.wicket.WicketUtils; | |||
import com.gitblit.wicket.panels.DetailedRepositoryUrlPanel; | |||
import com.gitblit.wicket.panels.RepositoryUrlPanel; | |||
public class EmptyRepositoryPage extends RootPage { | |||
@@ -53,24 +48,17 @@ public class EmptyRepositoryPage extends RootPage { | |||
setupPage(repositoryName, getString("gb.emptyRepository")); | |||
List<String> repositoryUrls = new ArrayList<String>(); | |||
if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { | |||
// add the Gitblit repository url | |||
repositoryUrls.add(getRepositoryUrl(repository)); | |||
} | |||
UserModel user = GitBlitWebSession.get().getUser(); | |||
if (user == null) { | |||
user = UserModel.ANONYMOUS; | |||
} | |||
repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); | |||
String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.get(0); | |||
AccessPermission accessPermission = user.getRepositoryPermission(repository).permission; | |||
RepositoryUrlPanel urlPanel = new RepositoryUrlPanel("pushurl", false, user, repository, getLocalizer(), this); | |||
String primaryUrl = urlPanel.getPrimaryUrl(); | |||
add(new Label("repository", repositoryName)); | |||
add(new DetailedRepositoryUrlPanel("pushurl", getLocalizer(), this, repository.name, primaryUrl, accessPermission)); | |||
add(new Label("cloneSyntax", MessageFormat.format("git clone {0}", repositoryUrls.get(0)))); | |||
add(urlPanel); | |||
add(new Label("cloneSyntax", MessageFormat.format("git clone {0}", primaryUrl))); | |||
add(new Label("remoteSyntax", MessageFormat.format("git remote add gitblit {0}\ngit push gitblit master", primaryUrl))); | |||
} | |||
} |
@@ -21,12 +21,10 @@ | |||
<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="branchStats">[branch stats]</span> <span class="link"><a wicket:id="metrics"><wicket:message key="gb.metrics">[metrics]</wicket:message></a></span></td></tr> | |||
<tr><th style="vertical-align:top;padding-top:4px;"><wicket:message key="gb.repositoryUrl">[URL]</wicket:message> <img style="vertical-align: top;padding-left:3px;" wicket:id="accessRestrictionIcon" /></th> | |||
<td style="padding-top:4px;"> | |||
<div wicket:id="repositoryPrimaryUrl">[repository primary url]</div> | |||
<div wicket:id="repositoryGitDaemonUrl">[repository git daemon url]</div> | |||
<div wicket:id="repositoryUrlPanel">[repository url panel]</div> | |||
<div wicket:id="otherUrls" > | |||
<div wicket:id="otherUrl" style="padding-top:10px"></div> | |||
</div> | |||
<div wicket:id="repositorySparkleShareInviteUrl">[repository sparkleshare invite url]</div> | |||
</td> | |||
</tr> | |||
</table> |
@@ -42,7 +42,6 @@ import org.wicketstuff.googlecharts.LineStyle; | |||
import org.wicketstuff.googlecharts.MarkerType; | |||
import org.wicketstuff.googlecharts.ShapeMarker; | |||
import com.gitblit.Constants.AccessPermission; | |||
import com.gitblit.Constants.AccessRestrictionType; | |||
import com.gitblit.GitBlit; | |||
import com.gitblit.Keys; | |||
@@ -50,7 +49,6 @@ import com.gitblit.models.Metric; | |||
import com.gitblit.models.PathModel; | |||
import com.gitblit.models.RepositoryModel; | |||
import com.gitblit.models.UserModel; | |||
import com.gitblit.utils.ArrayUtils; | |||
import com.gitblit.utils.JGitUtils; | |||
import com.gitblit.utils.MarkdownUtils; | |||
import com.gitblit.utils.StringUtils; | |||
@@ -60,7 +58,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.RepositoryUrlPanel; | |||
import com.gitblit.wicket.panels.TagsPanel; | |||
public class SummaryPage extends RepositoryPage { | |||
@@ -127,11 +125,7 @@ public class SummaryPage extends RepositoryPage { | |||
add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class, | |||
WicketUtils.newRepositoryParameter(repositoryName))); | |||
List<String> repositoryUrls = new ArrayList<String>(); | |||
AccessPermission accessPermission = null; | |||
if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { | |||
accessPermission = user.getRepositoryPermission(model).permission; | |||
AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction; | |||
switch (accessRestriction) { | |||
case NONE: | |||
@@ -152,32 +146,14 @@ public class SummaryPage extends RepositoryPage { | |||
default: | |||
add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); | |||
} | |||
// add the Gitblit repository url | |||
repositoryUrls.add(getRepositoryUrl(getRepositoryModel())); | |||
} else { | |||
add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); | |||
} | |||
repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); | |||
String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0); | |||
add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl", getLocalizer(), this, model.name, primaryUrl, accessPermission)); | |||
Component gitDaemonUrlPanel = createGitDaemonUrlPanel("repositoryGitDaemonUrl", user, model); | |||
if (!StringUtils.isEmpty(primaryUrl) && gitDaemonUrlPanel instanceof DetailedRepositoryUrlPanel) { | |||
WicketUtils.setCssStyle(gitDaemonUrlPanel, "padding-top: 10px"); | |||
} | |||
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<String> urls = new ListDataProvider<String>(repositoryUrls); | |||
add(new RepositoryUrlPanel("repositoryUrlPanel", false, user, model, getLocalizer(), this)); | |||
List<String> otherUrls = GitBlit.self().getOtherCloneUrls(repositoryName, UserModel.ANONYMOUS.equals(user) ? "" : user.username); | |||
ListDataProvider<String> urls = new ListDataProvider<String>(otherUrls); | |||
DataView<String> otherUrlsView = new DataView<String>("otherUrls", urls) { | |||
private static final long serialVersionUID = 1L; | |||
@@ -22,6 +22,7 @@ import org.apache.wicket.AttributeModifier; | |||
import org.apache.wicket.Component; | |||
import org.apache.wicket.markup.html.panel.Panel; | |||
import org.apache.wicket.model.Model; | |||
import org.apache.wicket.protocol.http.request.WebClientInfo; | |||
import com.gitblit.Constants; | |||
import com.gitblit.GitBlit; | |||
@@ -57,6 +58,19 @@ public abstract class BasePanel extends Panel { | |||
} | |||
return timeUtils; | |||
} | |||
protected boolean isWindows() { | |||
return isPlatform("windows"); | |||
} | |||
protected boolean isMac() { | |||
return isPlatform("macintosh"); | |||
} | |||
protected boolean isPlatform(String platform) { | |||
String ua = ((WebClientInfo) GitBlitWebSession.get().getClientInfo()).getUserAgent(); | |||
return ua.toLowerCase().contains(platform); | |||
} | |||
protected void setPersonSearchTooltip(Component component, String value, Constants.SearchType searchType) { | |||
if (searchType.equals(Constants.SearchType.AUTHOR)) { |
@@ -16,8 +16,6 @@ | |||
package com.gitblit.wicket.panels; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.wicket.Component; | |||
@@ -29,7 +27,6 @@ import org.apache.wicket.markup.html.link.ExternalLink; | |||
import org.apache.wicket.markup.html.link.Link; | |||
import org.apache.wicket.markup.html.panel.Fragment; | |||
import com.gitblit.Constants.AccessPermission; | |||
import com.gitblit.Constants.AccessRestrictionType; | |||
import com.gitblit.GitBlit; | |||
import com.gitblit.Keys; | |||
@@ -40,7 +37,6 @@ import com.gitblit.utils.ArrayUtils; | |||
import com.gitblit.utils.StringUtils; | |||
import com.gitblit.wicket.GitBlitWebSession; | |||
import com.gitblit.wicket.WicketUtils; | |||
import com.gitblit.wicket.pages.BasePage; | |||
import com.gitblit.wicket.pages.DocsPage; | |||
import com.gitblit.wicket.pages.EditRepositoryPage; | |||
import com.gitblit.wicket.pages.LogPage; | |||
@@ -58,7 +54,6 @@ public class ProjectRepositoryPanel extends BasePanel { | |||
super(wicketId); | |||
final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true); | |||
final boolean gitServlet = GitBlit.getBoolean(Keys.git.enableGitServlet, true); | |||
final boolean showSize = GitBlit.getBoolean(Keys.web.showRepositorySizes, true); | |||
// repository swatch | |||
@@ -217,15 +212,6 @@ public class ProjectRepositoryPanel extends BasePanel { | |||
add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0))); | |||
List<String> repositoryUrls = new ArrayList<String>(); | |||
if (gitServlet) { | |||
// add the Gitblit repository url | |||
repositoryUrls.add(BasePage.getRepositoryUrl(entry)); | |||
} | |||
repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(entry.name, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); | |||
AccessPermission ap = user.getRepositoryPermission(entry).permission; | |||
String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0); | |||
add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl",localizer, parent, entry.name, primaryUrl, ap)); | |||
add(new RepositoryUrlPanel("repositoryPrimaryUrl", true, user, entry, localizer, parent)); | |||
} | |||
} |
@@ -5,26 +5,14 @@ | |||
lang="en"> | |||
<wicket:panel> | |||
<span wicket:id="repositoryUrl" style="color: blue;">[repository url]</span><span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span> | |||
<!-- Plain JavaScript manual copy & paste --> | |||
<wicket:fragment wicket:id="jsPanel"> | |||
<span style="vertical-align:baseline;"> | |||
<img wicket:id="copyIcon" wicket:message="title:gb.copyToClipboard"></img> | |||
</span> | |||
</wicket:fragment> | |||
<!-- flash-based button-press copy & paste --> | |||
<wicket:fragment wicket:id="clippyPanel"> | |||
<object wicket:message="title:gb.copyToClipboard" style="vertical-align:middle;" | |||
wicket:id="clippy" | |||
width="14" | |||
height="14" | |||
bgcolor="#ffffff" | |||
quality="high" | |||
wmode="transparent" | |||
scale="noscale" | |||
allowScriptAccess="always"></object> | |||
</wicket:fragment> | |||
<div wicket:id="repositoryPrimaryUrl">[repository primary url]</div> | |||
<div style="padding-top: 2px;"> | |||
<span class="link" wicket:id="appCloneLink"> | |||
<span wicket:id="icon"></span> | |||
<span wicket:id="link"></span> | |||
<span wicket:id="separator" style="padding: 0px 5px 0px 5px;"></span> | |||
</span> | |||
</div> | |||
<div wicket:id="repositoryGitDaemonUrl">[repository git daemon url]</div> | |||
</wicket:panel> | |||
</html> |
@@ -15,37 +15,226 @@ | |||
*/ | |||
package com.gitblit.wicket.panels; | |||
import java.io.Serializable; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.wicket.Component; | |||
import org.apache.wicket.Localizer; | |||
import org.apache.wicket.RequestCycle; | |||
import org.apache.wicket.markup.html.basic.Label; | |||
import org.apache.wicket.markup.html.image.ContextImage; | |||
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.protocol.http.WebRequest; | |||
import com.gitblit.Constants; | |||
import com.gitblit.Constants.AccessPermission; | |||
import com.gitblit.Constants.AccessRestrictionType; | |||
import com.gitblit.GitBlit; | |||
import com.gitblit.Keys; | |||
import com.gitblit.SparkleShareInviteServlet; | |||
import com.gitblit.models.RepositoryModel; | |||
import com.gitblit.models.UserModel; | |||
import com.gitblit.utils.StringUtils; | |||
import com.gitblit.wicket.GitBlitWebSession; | |||
import com.gitblit.wicket.WicketUtils; | |||
/** | |||
* Smart repository url panel which can display multiple Gitblit repository urls | |||
* and also supports 3rd party app clone links. | |||
* | |||
* @author James Moger | |||
* | |||
*/ | |||
public class RepositoryUrlPanel extends BasePanel { | |||
private static final long serialVersionUID = 1L; | |||
private final String primaryUrl; | |||
public RepositoryUrlPanel(String wicketId, String url) { | |||
public RepositoryUrlPanel(String wicketId, boolean onlyPrimary, UserModel user, | |||
RepositoryModel repository, Localizer localizer, Component owner) { | |||
super(wicketId); | |||
add(new Label("repositoryUrl", url)); | |||
if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { | |||
// clippy: flash-based copy & paste | |||
Fragment fragment = new Fragment("copyFunction", "clippyPanel", this); | |||
String baseUrl = WicketUtils.getGitblitURL(getRequest()); | |||
ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf"); | |||
clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(url)); | |||
fragment.add(clippy); | |||
add(fragment); | |||
if (user == null) { | |||
user = UserModel.ANONYMOUS; | |||
} | |||
List<String> repositoryUrls = new ArrayList<String>(); | |||
AccessPermission accessPermission = null; | |||
if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { | |||
accessPermission = user.getRepositoryPermission(repository).permission; | |||
repositoryUrls.add(getRepositoryUrl(repository)); | |||
} | |||
repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repository.name, UserModel.ANONYMOUS.equals(user) ? "" : user.username)); | |||
primaryUrl = repositoryUrls.size() == 0 ? "" : repositoryUrls.remove(0); | |||
add(new DetailedRepositoryUrlPanel("repositoryPrimaryUrl", localizer, owner, repository.name, primaryUrl, accessPermission)); | |||
if (!onlyPrimary) { | |||
Component gitDaemonUrlPanel = createGitDaemonUrlPanel("repositoryGitDaemonUrl", user, repository); | |||
if (!StringUtils.isEmpty(primaryUrl) && gitDaemonUrlPanel instanceof DetailedRepositoryUrlPanel) { | |||
WicketUtils.setCssStyle(gitDaemonUrlPanel, "padding-top: 10px"); | |||
} | |||
add(gitDaemonUrlPanel); | |||
} else { | |||
// javascript: manual copy & paste with modal browser prompt dialog | |||
Fragment fragment = new Fragment("copyFunction", "jsPanel", this); | |||
ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png"); | |||
img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", url)); | |||
fragment.add(img); | |||
add(fragment); | |||
add(new Label("repositoryGitDaemonUrl").setVisible(false)); | |||
} | |||
final List<AppCloneLink> cloneLinks = new ArrayList<AppCloneLink>(); | |||
if (user.canClone(repository) && GitBlit.getBoolean(Keys.web.allowAppCloneLinks, true)) { | |||
// universal app clone urls | |||
// cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSmartGit", owner), | |||
// MessageFormat.format("smartgit://cloneRepo/{0}", primaryUrl), | |||
// "Syntevo SmartGit\u2122")); | |||
if (isWindows()) { | |||
// Windows client app clone urls | |||
cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSourceTree", owner), | |||
MessageFormat.format("sourcetree://cloneRepo/{0}", primaryUrl), | |||
"Atlassian SourceTree\u2122")); | |||
// cloneLinks.add(new AppCloneLink( | |||
// MessageFormat.format(localizer.getString("gb.cloneWithGitHub", owner), "Windows"), | |||
// MessageFormat.format("github-windows://openRepo/{0}", primaryUrl))); | |||
} else if (isMac()) { | |||
// Mac client app clone urls | |||
cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSourceTree", owner), | |||
MessageFormat.format("sourcetree://cloneRepo/{0}", primaryUrl), | |||
"Atlassian SourceTree\u2122")); | |||
// cloneLinks.add(new AppCloneLink( | |||
// MessageFormat.format(localizer.getString("gb.cloneWithGitHub", owner), "Mac"), | |||
// MessageFormat.format("github-mac://openRepo/{0}", primaryUrl))); | |||
} | |||
// sparkleshare invite url | |||
String sparkleshareUrl = getSparkleShareInviteUrl(user, repository); | |||
if (!StringUtils.isEmpty(sparkleshareUrl)) { | |||
cloneLinks.add(new AppCloneLink(localizer.getString("gb.cloneWithSparkleShare", owner), | |||
sparkleshareUrl, "SparkleShare \u2122", "icon-star")); | |||
} | |||
} | |||
// app clone links | |||
ListDataProvider<AppCloneLink> appLinks = new ListDataProvider<AppCloneLink>(cloneLinks); | |||
DataView<AppCloneLink> appCloneLinks = new DataView<AppCloneLink>("appCloneLink", appLinks) { | |||
private static final long serialVersionUID = 1L; | |||
int count; | |||
public void populateItem(final Item<AppCloneLink> item) { | |||
final AppCloneLink appLink = item.getModelObject(); | |||
item.add(new Label("icon", MessageFormat.format("<i class=\"{0}\"></i>", appLink.icon)).setEscapeModelStrings(false)); | |||
LinkPanel linkPanel = new LinkPanel("link", null, appLink.name, appLink.url); | |||
if (!StringUtils.isEmpty(appLink.tooltip)) { | |||
WicketUtils.setHtmlTooltip(linkPanel, appLink.tooltip); | |||
} | |||
item.add(linkPanel); | |||
item.add(new Label("separator", "|").setVisible(count < (cloneLinks.size() - 1))); | |||
count++; | |||
} | |||
}; | |||
add(appCloneLinks); | |||
} | |||
public String getPrimaryUrl() { | |||
return primaryUrl; | |||
} | |||
protected String getRepositoryUrl(RepositoryModel repository) { | |||
StringBuilder sb = new StringBuilder(); | |||
sb.append(WicketUtils.getGitblitURL(RequestCycle.get().getRequest())); | |||
sb.append(Constants.GIT_PATH); | |||
sb.append(repository.name); | |||
// inject username into repository url if authentication is required | |||
if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) | |||
&& GitBlitWebSession.get().isLoggedIn()) { | |||
String username = GitBlitWebSession.get().getUsername(); | |||
sb.insert(sb.indexOf("://") + 3, username + "@"); | |||
} | |||
return sb.toString(); | |||
} | |||
protected Component createGitDaemonUrlPanel(String wicketId, UserModel user, RepositoryModel repository) { | |||
int gitDaemonPort = GitBlit.getInteger(Keys.git.daemonPort, 0); | |||
if (gitDaemonPort > 0 && user.canClone(repository)) { | |||
String servername = ((WebRequest) getRequest()).getHttpServletRequest().getServerName(); | |||
String gitDaemonUrl; | |||
if (gitDaemonPort == 9418) { | |||
// standard port | |||
gitDaemonUrl = MessageFormat.format("git://{0}/{1}", servername, repository.name); | |||
} else { | |||
// non-standard port | |||
gitDaemonUrl = MessageFormat.format("git://{0}:{1,number,0}/{2}", servername, gitDaemonPort, repository.name); | |||
} | |||
AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission;; | |||
if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) { | |||
if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { | |||
// can not authenticate clone via anonymous git protocol | |||
gitDaemonPermission = AccessPermission.NONE; | |||
} else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { | |||
// can not authenticate push via anonymous git protocol | |||
gitDaemonPermission = AccessPermission.CLONE; | |||
} else { | |||
// normal user permission | |||
} | |||
} | |||
if (AccessPermission.NONE.equals(gitDaemonPermission)) { | |||
// repository prohibits all anonymous access | |||
return new Label(wicketId).setVisible(false); | |||
} else { | |||
// repository allows some form of anonymous access | |||
return new DetailedRepositoryUrlPanel(wicketId, getLocalizer(), this, repository.name, gitDaemonUrl, gitDaemonPermission); | |||
} | |||
} else { | |||
// git daemon is not running | |||
return new Label(wicketId).setVisible(false); | |||
} | |||
} | |||
protected String getSparkleShareInviteUrl(UserModel user, RepositoryModel repository) { | |||
if (repository.isBare && repository.isSparkleshared()) { | |||
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; | |||
} | |||
static class AppCloneLink implements Serializable { | |||
private static final long serialVersionUID = 1L; | |||
final String name; | |||
final String url; | |||
final String tooltip; | |||
final String icon; | |||
public AppCloneLink(String name, String url, String tooltip) { | |||
this(name, url, tooltip, "icon-download"); | |||
} | |||
public AppCloneLink(String name, String url, String tooltip, String icon) { | |||
this.name = name; | |||
this.url = url; | |||
this.tooltip = tooltip; | |||
this.icon = icon; | |||
} | |||
} | |||
} |
@@ -1,18 +0,0 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" | |||
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" | |||
xml:lang="en" | |||
lang="en"> | |||
<wicket:panel> | |||
<span class="repositoryUrlContainer"> | |||
<span class="repositoryUrlEndCap"> | |||
<img wicket:id="sparkleshareIcon"></img> | |||
</span> | |||
<span class="repositoryUrl"> | |||
<a wicket:id="inviteUrl"><wicket:message key="gb.sparkleshareInvite"></wicket:message></a> | |||
</span> | |||
<span class="hidden-phone hidden-tablet repositoryUrlEndCap" wicket:id="accessPermission">[access permission]</span> | |||
</span> | |||
</wicket:panel> | |||
</html> |
@@ -1,52 +0,0 @@ | |||
/* | |||
* 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); | |||
} | |||
} |