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/panels/RepositoryUrlPanel.java | 252 ++++++++++++++++++++++++++++++-------------------- 1 files changed, 151 insertions(+), 101 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java index 942f8d5..207f125 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java @@ -36,21 +36,20 @@ 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.GitClientApplication; import com.gitblit.models.RepositoryModel; import com.gitblit.models.RepositoryUrl; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.ExternalImage; 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 * */ @@ -61,12 +60,12 @@ private final String externalPermission = "?"; private boolean onlyUrls; - private UserModel user; + private UserModel user; private RepositoryModel repository; private RepositoryUrl primaryUrl; private Map<String, String> urlPermissionsMap; private Map<AccessRestrictionType, String> accessRestrictionsMap; - + public RepositoryUrlPanel(String wicketId, boolean onlyUrls, UserModel user, RepositoryModel repository) { super(wicketId); this.onlyUrls = onlyUrls; @@ -74,30 +73,37 @@ this.repository = repository; this.urlPermissionsMap = new HashMap<String, String>(); } - + @Override protected void onInitialize() { super.onInitialize(); HttpServletRequest req = ((WebRequest) getRequest()).getHttpServletRequest(); - List<RepositoryUrl> repositoryUrls = GitBlit.self().getRepositoryUrls(req, user, repository); + List<RepositoryUrl> repositoryUrls = app().services().getRepositoryUrls(req, user, repository); // grab primary url from the top of the list primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0); - boolean canClone = ((primaryUrl.permission == null) || primaryUrl.permission.atLeast(AccessPermission.CLONE)); + boolean canClone = primaryUrl != null && (!primaryUrl.hasPermission() || primaryUrl.permission.atLeast(AccessPermission.CLONE)); if (repositoryUrls.size() == 0 || !canClone) { // no urls, nothing to show. add(new Label("repositoryUrlPanel").setVisible(false)); add(new Label("applicationMenusPanel").setVisible(false)); + add(new Label("repositoryIndicators").setVisible(false)); return; } - + // display primary url add(createPrimaryUrlPanel("repositoryUrlPanel", repository, repositoryUrls)); - boolean allowAppLinks = GitBlit.getBoolean(Keys.web.allowAppCloneLinks, true); + if (onlyUrls) { + add(new Label("repositoryIndicators").setVisible(false)); + } else { + add(createRepositoryIndicators(repository)); + } + + boolean allowAppLinks = app().settings().getBoolean(Keys.web.allowAppCloneLinks, true); if (onlyUrls || !canClone || !allowAppLinks) { // only display the url(s) add(new Label("applicationMenusPanel").setVisible(false)); @@ -115,7 +121,7 @@ Fragment urlPanel = new Fragment(wicketId, "repositoryUrlFragment", this); urlPanel.setRenderBodyOnly(true); - + if (repositoryUrls.size() == 1) { // // Single repository url, no dropdown menu @@ -129,16 +135,17 @@ DataView<RepositoryUrl> repoUrlMenuItems = new DataView<RepositoryUrl>("repoUrls", urlsDp) { private static final long serialVersionUID = 1L; + @Override public void populateItem(final Item<RepositoryUrl> item) { RepositoryUrl repoUrl = item.getModelObject(); // repository url - Fragment fragment = new Fragment("repoUrl", "actionFragment", this); + Fragment fragment = new Fragment("repoUrl", "actionFragment", this); Component content = new Label("content", repoUrl.url).setRenderBodyOnly(true); WicketUtils.setCssClass(content, "commandMenuItem"); fragment.add(content); item.add(fragment); - - Label permissionLabel = new Label("permission", repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString()); + + Label permissionLabel = new Label("permission", repoUrl.hasPermission() ? repoUrl.permission.toString() : externalPermission); WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission); String tooltip = getProtocolPermissionDescription(repository, repoUrl); WicketUtils.setHtmlTooltip(permissionLabel, tooltip); @@ -155,7 +162,10 @@ } // access restriction icon and tooltip - if (isGitblitServingRepositories()) { + if (repository.isMirror) { + urlPanel.add(WicketUtils.newImage("accessRestrictionIcon", "mirror_16x16.png", + getString("gb.isMirror"))); + } else if (app().services().isServingRepositories()) { switch (repository.accessRestriction) { case NONE: urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); @@ -188,165 +198,156 @@ urlPanel.add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false)); } } - + urlPanel.add(new Label("primaryUrl", primaryUrl.url).setRenderBodyOnly(true)); - Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.isExternal() ? externalPermission : primaryUrl.permission.toString()); + Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.hasPermission() ? primaryUrl.permission.toString() : externalPermission); String tooltip = getProtocolPermissionDescription(repository, primaryUrl); WicketUtils.setHtmlTooltip(permissionLabel, tooltip); urlPanel.add(permissionLabel); urlPanel.add(createCopyFragment(primaryUrl.url)); - + return urlPanel; } - - protected Fragment createApplicationMenus(String wicketId, UserModel user, final RepositoryModel repository, List<RepositoryUrl> repositoryUrls) { + + protected Fragment createApplicationMenus(String wicketId, final UserModel user, final RepositoryModel repository, final List<RepositoryUrl> repositoryUrls) { final List<GitClientApplication> displayedApps = new ArrayList<GitClientApplication>(); final String userAgent = ((WebClientInfo) GitBlitWebSession.get().getClientInfo()).getUserAgent(); - + if (user.canClone(repository)) { - for (GitClientApplication app : GitBlit.self().getClientApplications()) { + for (GitClientApplication app : app().gitblit().getClientApplications()) { if (app.isActive && app.allowsPlatform(userAgent)) { displayedApps.add(app); } } - - GitClientApplication sparkleshare = getSparkleShareAppMenu(user, repository); - if (sparkleshare != null) { - displayedApps.add(sparkleshare); - } } - final ListDataProvider<RepositoryUrl> urlsDp = new ListDataProvider<RepositoryUrl>(repositoryUrls); + final String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); ListDataProvider<GitClientApplication> displayedAppsDp = new ListDataProvider<GitClientApplication>(displayedApps); DataView<GitClientApplication> appMenus = new DataView<GitClientApplication>("appMenus", displayedAppsDp) { private static final long serialVersionUID = 1L; + @Override public void populateItem(final Item<GitClientApplication> item) { final GitClientApplication clientApp = item.getModelObject(); + // filter the urls for the client app + List<RepositoryUrl> urls = new ArrayList<RepositoryUrl>(); + for (RepositoryUrl repoUrl : repositoryUrls) { + if (clientApp.minimumPermission == null || !repoUrl.hasPermission()) { + // no minimum permission or untracked permissions, assume it is satisfactory + if (clientApp.supportsTransport(repoUrl.url)) { + urls.add(repoUrl); + } + } else if (repoUrl.permission.atLeast(clientApp.minimumPermission)) { + // repo url meets minimum permission requirement + if (clientApp.supportsTransport(repoUrl.url)) { + urls.add(repoUrl); + } + } + } + + if (urls.size() == 0) { + // do not show this app menu because there are no urls + item.add(new Label("appMenu").setVisible(false)); + return; + } + + Fragment appMenu = new Fragment("appMenu", "appMenuFragment", this); + appMenu.setRenderBodyOnly(true); + item.add(appMenu); + // menu button - item.add(new Label("applicationName", clientApp.name)); - + appMenu.add(new Label("applicationName", clientApp.name)); + // application icon Component img; if (StringUtils.isEmpty(clientApp.icon)) { - img = WicketUtils.newClearPixel("applicationIcon").setVisible(false); + img = WicketUtils.newClearPixel("applicationIcon").setVisible(false); } else { - img = WicketUtils.newImage("applicationIcon", clientApp.icon); - } - item.add(img); - + if (clientApp.icon.contains("://")) { + // external image + img = new ExternalImage("applicationIcon", clientApp.icon); + } else { + // context image + img = WicketUtils.newImage("applicationIcon", clientApp.icon); + } + } + appMenu.add(img); + // application menu title, may be a link if (StringUtils.isEmpty(clientApp.productUrl)) { - item.add(new Label("applicationTitle", clientApp.toString())); + appMenu.add(new Label("applicationTitle", clientApp.toString())); } else { - item.add(new LinkPanel("applicationTitle", null, clientApp.toString(), clientApp.productUrl, true)); + appMenu.add(new LinkPanel("applicationTitle", null, clientApp.toString(), clientApp.productUrl, true)); } - + // brief application description if (StringUtils.isEmpty(clientApp.description)) { - item.add(new Label("applicationDescription").setVisible(false)); + appMenu.add(new Label("applicationDescription").setVisible(false)); } else { - item.add(new Label("applicationDescription", clientApp.description)); + appMenu.add(new Label("applicationDescription", clientApp.description)); } - + // brief application legal info, copyright, license, etc if (StringUtils.isEmpty(clientApp.legal)) { - item.add(new Label("applicationLegal").setVisible(false)); + appMenu.add(new Label("applicationLegal").setVisible(false)); } else { - item.add(new Label("applicationLegal", clientApp.legal)); + appMenu.add(new Label("applicationLegal", clientApp.legal)); } - + // a nested repeater for all action items + ListDataProvider<RepositoryUrl> urlsDp = new ListDataProvider<RepositoryUrl>(urls); DataView<RepositoryUrl> actionItems = new DataView<RepositoryUrl>("actionItems", urlsDp) { private static final long serialVersionUID = 1L; + @Override public void populateItem(final Item<RepositoryUrl> repoLinkItem) { RepositoryUrl repoUrl = repoLinkItem.getModelObject(); - Fragment fragment = new Fragment("actionItem", "actionFragment", this); fragment.add(createPermissionBadge("permission", repoUrl)); if (!StringUtils.isEmpty(clientApp.cloneUrl)) { // custom registered url - String url = MessageFormat.format(clientApp.cloneUrl, repoUrl); + String url = substitute(clientApp.cloneUrl, repoUrl.url, baseURL, user.username, repository.name); fragment.add(new LinkPanel("content", "applicationMenuItem", getString("gb.clone") + " " + repoUrl.url, url)); repoLinkItem.add(fragment); fragment.add(new Label("copyFunction").setVisible(false)); } else if (!StringUtils.isEmpty(clientApp.command)) { // command-line - String command = MessageFormat.format(clientApp.command, repoUrl); + String command = substitute(clientApp.command, repoUrl.url, baseURL, user.username, repository.name); Label content = new Label("content", command); WicketUtils.setCssClass(content, "commandMenuItem"); fragment.add(content); repoLinkItem.add(fragment); - + // copy function for command fragment.add(createCopyFragment(command)); } }}; - item.add(actionItems); + appMenu.add(actionItems); } }; - + Fragment applicationMenus = new Fragment(wicketId, "applicationMenusFragment", this); applicationMenus.add(appMenus); return applicationMenus; } - - protected GitClientApplication getSparkleShareAppMenu(UserModel user, RepositoryModel repository) { - String url = null; - if (repository.isBare && repository.isSparkleshared()) { - String username = null; - if (UserModel.ANONYMOUS != user) { - username = user.username; - } - if (isGitblitServingRepositories()) { - // Gitblit as server - // ensure user can rewind - if (user.canRewindRef(repository)) { - String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); - url = SparkleShareInviteServlet.asLink(baseURL, repository.name, username); - } - } else { - // Gitblit as viewer, assume RW+ permission - String baseURL = WicketUtils.getGitblitURL(RequestCycle.get().getRequest()); - url = SparkleShareInviteServlet.asLink(baseURL, repository.name, username); - } - } - // sparkleshare invite url - if (!StringUtils.isEmpty(url)) { - GitClientApplication app = new GitClientApplication(); - app.name = "SparkleShare"; - app.title = "SparkleShare\u2122"; - app.description = "an open source collaboration and sharing tool"; - app.legal = "released under the GPLv3 open source license"; - app.cloneUrl = url; - app.platforms = new String [] { "windows", "macintosh", "linux" }; - app.productUrl = "http://sparkleshare.org"; - app.icon = "sparkleshare_32x32.png"; - app.isActive = true; - return app; - } - return null; + protected String substitute(String pattern, String repoUrl, String baseUrl, String username, String repository) { + return pattern.replace("${repoUrl}", repoUrl).replace("${baseUrl}", baseUrl).replace("${username}", username).replace("${repository}", repository); } - - protected boolean isGitblitServingRepositories() { - return GitBlit.getBoolean(Keys.git.enableGitServlet, true) || (GitBlit.getInteger(Keys.git.daemonPort, 0) > 0); - } - + protected Label createPermissionBadge(String wicketId, RepositoryUrl repoUrl) { - Label permissionLabel = new Label(wicketId, repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString()); + Label permissionLabel = new Label(wicketId, repoUrl.hasPermission() ? repoUrl.permission.toString() : externalPermission); WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission); String tooltip = getProtocolPermissionDescription(repository, repoUrl); WicketUtils.setHtmlTooltip(permissionLabel, tooltip); return permissionLabel; } - + protected Fragment createCopyFragment(String text) { - if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { + if (app().settings().getBoolean(Keys.web.allowFlashCopyToClipboard, true)) { // clippy: flash-based copy & paste Fragment copyFragment = new Fragment("copyFunction", "clippyPanel", this); String baseUrl = WicketUtils.getGitblitURL(getRequest()); @@ -363,16 +364,13 @@ return copyFragment; } } - + protected String getProtocolPermissionDescription(RepositoryModel repository, RepositoryUrl repoUrl) { if (!urlPermissionsMap.containsKey(repoUrl.url)) { String note; - if (repoUrl.isExternal()) { - String protocol = repoUrl.url.substring(0, repoUrl.url.indexOf("://")); - note = MessageFormat.format(getString("gb.externalPermissions"), protocol); - } else { - note = null; + if (repoUrl.hasPermission()) { + note = null; String key; switch (repoUrl.permission) { case OWNER: @@ -402,12 +400,23 @@ String description = MessageFormat.format(pattern, repoUrl.permission.toString()); note = description; } + } else { + String protocol; + int protocolIndex = repoUrl.url.indexOf("://"); + if (protocolIndex > -1) { + // explicit protocol specified + protocol = repoUrl.url.substring(0, protocolIndex); + } else { + // implicit SSH url + protocol = "ssh"; + } + note = MessageFormat.format(getString("gb.externalPermissions"), protocol); } urlPermissionsMap.put(repoUrl.url, note); } return urlPermissionsMap.get(repoUrl.url); } - + protected Map<AccessRestrictionType, String> getAccessRestrictions() { if (accessRestrictionsMap == null) { accessRestrictionsMap = new HashMap<AccessRestrictionType, String>(); @@ -430,4 +439,45 @@ } return accessRestrictionsMap; } + + protected Component createRepositoryIndicators(RepositoryModel repository) { + Fragment fragment = new Fragment("repositoryIndicators", "indicatorsFragment", this); + if (repository.isBare) { + fragment.add(new Label("workingCopyIndicator").setVisible(false)); + } else { + Fragment wc = new Fragment("workingCopyIndicator", "workingCopyFragment", this); + Label lbl = new Label("workingCopy", getString("gb.workingCopy")); + WicketUtils.setHtmlTooltip(lbl, getString("gb.workingCopyWarning")); + wc.add(lbl); + fragment.add(wc); + } + + boolean allowForking = app().settings().getBoolean(Keys.web.allowForking, true); + if (!allowForking || user == null || !user.isAuthenticated) { + // must be logged-in to fork, hide all fork controls + fragment.add(new Label("forksProhibitedIndicator").setVisible(false)); + } else { + String fork = app().repositories().getFork(user.username, repository.name); + boolean hasFork = fork != null; + boolean canFork = user.canFork(repository); + + if (hasFork || !canFork) { + if (user.canFork() && !repository.allowForks) { + // show forks prohibited indicator + Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this); + Label lbl = new Label("forksProhibited", getString("gb.forksProhibited")); + WicketUtils.setHtmlTooltip(lbl, getString("gb.forksProhibitedWarning")); + wc.add(lbl); + fragment.add(wc); + } else { + // can not fork, no need for forks prohibited indicator + fragment.add(new Label("forksProhibitedIndicator").setVisible(false)); + } + } else if (canFork) { + // can fork and we do not have one + fragment.add(new Label("forksProhibitedIndicator").setVisible(false)); + } + } + return fragment; + } } -- Gitblit v1.9.1