]> source.dussan.org Git - gitblit.git/commitdiff
Show fork links according to user permissions. Improve fork detection.
authorJames Moger <james.moger@gitblit.com>
Tue, 2 Oct 2012 00:45:19 +0000 (20:45 -0400)
committerJames Moger <james.moger@gitblit.com>
Tue, 2 Oct 2012 00:45:19 +0000 (20:45 -0400)
src/com/gitblit/GitBlit.java
src/com/gitblit/models/UserModel.java
src/com/gitblit/wicket/pages/ForksPage.java
src/com/gitblit/wicket/pages/RepositoryPage.java

index 699bbacbad4614a585106ed6d3f2c62e4ffe952a..f86c66a3e16d23e1f57741a686b9a1e4ad3fe408 100644 (file)
@@ -32,6 +32,7 @@ import java.util.Collection;
 import java.util.Collections;\r
 import java.util.Date;\r
 import java.util.HashMap;\r
+import java.util.HashSet;\r
 import java.util.LinkedHashMap;\r
 import java.util.LinkedHashSet;\r
 import java.util.List;\r
@@ -1325,6 +1326,81 @@ public class GitBlit implements ServletContextListener {
                r.close();\r
                return true;\r
        }\r
+       \r
+       /**\r
+        * Determines if the specified user has a fork of the specified origin\r
+        * repository.\r
+        * \r
+        * @param username\r
+        * @param origin\r
+        * @return true the if the user has a fork\r
+        */\r
+       public boolean hasFork(String username, String origin) {\r
+               return getFork(username, origin) != null;\r
+       }\r
+       \r
+       /**\r
+        * Gets the name of a user's fork of the specified origin\r
+        * repository.\r
+        * \r
+        * @param username\r
+        * @param origin\r
+        * @return the name of the user's fork, null otherwise\r
+        */\r
+       public String getFork(String username, String origin) {\r
+               String userProject = "~" + username.toLowerCase();\r
+               if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {\r
+                       String userPath = userProject + "/";\r
+\r
+                       // collect all origin nodes in fork network\r
+                       Set<String> roots = new HashSet<String>();\r
+                       roots.add(origin);\r
+                       RepositoryModel originModel = repositoryListCache.get(origin);\r
+                       while (originModel != null) {\r
+                               if (!ArrayUtils.isEmpty(originModel.forks)) {\r
+                                       for (String fork : originModel.forks) {\r
+                                               if (!fork.startsWith(userPath)) {\r
+                                                       roots.add(fork);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               if (originModel.originRepository != null) {\r
+                                       roots.add(originModel.originRepository);\r
+                                       originModel = repositoryListCache.get(originModel.originRepository);\r
+                               } else {\r
+                                       // break\r
+                                       originModel = null;\r
+                               }\r
+                       }\r
+                       \r
+                       for (String repository : repositoryListCache.keySet()) {\r
+                               if (repository.toLowerCase().startsWith(userPath)) {\r
+                                       RepositoryModel model = repositoryListCache.get(repository);\r
+                                       if (!StringUtils.isEmpty(model.originRepository)) {\r
+                                               if (roots.contains(model.originRepository)) {\r
+                                                       // user has a fork in this graph\r
+                                                       return model.name;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               } else {\r
+                       // not caching\r
+                       ProjectModel project = getProjectModel(userProject);\r
+                       for (String repository : project.repositories) {\r
+                               if (repository.toLowerCase().startsWith(userProject)) {\r
+                                       RepositoryModel model = repositoryListCache.get(repository);\r
+                                       if (model.originRepository.equalsIgnoreCase(origin)) {\r
+                                               // user has a fork\r
+                                               return model.name;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               // user does not have a fork\r
+               return null;\r
+       }\r
 \r
        /**\r
         * Returns the size in bytes of the repository. Gitblit caches the\r
index 0ede878756d82884a4b838e2a7ac4e7d69928f3e..25787a15ae70c4b1defc17001f4bcb5470b94385 100644 (file)
@@ -86,6 +86,16 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
                return false;\r
        }\r
        \r
+       public boolean canViewRepository(RepositoryModel repository) {\r
+               if (canAdmin) {\r
+                       return true;\r
+               }\r
+               if (repository.accessRestriction.atLeast(AccessRestrictionType.VIEW)) {\r
+                       return canAccessRepository(repository);\r
+               }\r
+               return true;\r
+       }\r
+       \r
        public boolean canForkRepository(RepositoryModel repository) {\r
                if (canAdmin) {\r
                        return true;\r
index 7b8235b0aba002f332dccceac83f472ad3db2de7..54c2c82adf43a8a89b0f5d318b809d87431735f3 100644 (file)
@@ -42,26 +42,32 @@ public class ForksPage extends RepositoryPage {
        public ForksPage(PageParameters params) {\r
                super(params);\r
                \r
+               UserModel user = GitBlitWebSession.get().getUser();\r
                RepositoryModel model = getRepositoryModel();\r
-               RepositoryModel origin;\r
+               RepositoryModel origin = model;\r
                List<String> list;\r
                if (ArrayUtils.isEmpty(model.forks)) {\r
-                       // origin repository has forks\r
-                       origin = GitBlit.self().getRepositoryModel(model.originRepository);\r
-                       list = new ArrayList<String>(origin.forks);\r
+                       if (!StringUtils.isEmpty(model.originRepository)) {\r
+                               // try origin repository\r
+                               origin = GitBlit.self().getRepositoryModel(model.originRepository);\r
+                       }\r
+                       if (origin == null || origin.forks == null) {\r
+                               list = new ArrayList<String>();\r
+                       } else {\r
+                               list = new ArrayList<String>(origin.forks);\r
+                       }\r
                } else {\r
                        // this repository has forks\r
-                       origin = model;\r
                        list = new ArrayList<String>(model.forks);\r
                }\r
                \r
                if (origin.isPersonalRepository()) {\r
                        // personal repository\r
-                       UserModel user = GitBlit.self().getUserModel(origin.projectPath.substring(1));\r
-                       PersonIdent ident = new PersonIdent(user.getDisplayName(), user.emailAddress);\r
+                       UserModel originUser = GitBlit.self().getUserModel(origin.projectPath.substring(1));\r
+                       PersonIdent ident = new PersonIdent(originUser.getDisplayName(), originUser.emailAddress);\r
                        add(new GravatarImage("forkSourceAvatar", ident, 20));\r
                        add(new Label("forkSourceSwatch").setVisible(false));\r
-                       add(new LinkPanel("forkSourceProject", null, user.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(user.username)));\r
+                       add(new LinkPanel("forkSourceProject", null, originUser.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(originUser.username)));\r
                } else {\r
                        // standard repository\r
                        add(new GravatarImage("forkSourceAvatar", new PersonIdent("", ""), 20).setVisible(false));\r
@@ -85,10 +91,15 @@ public class ForksPage extends RepositoryPage {
                }\r
                \r
                String source = StringUtils.getLastPathElement(origin.name);\r
-               add(new LinkPanel("forkSource", null, StringUtils.stripDotGit(source), SummaryPage.class, WicketUtils.newRepositoryParameter(origin.name)));\r
+               if (user != null && user.canViewRepository(origin)) {\r
+                       // user can view the origin\r
+                       add(new LinkPanel("forkSource", null, StringUtils.stripDotGit(source), SummaryPage.class, WicketUtils.newRepositoryParameter(origin.name)));\r
+               } else {\r
+                       // user can not view the origin\r
+                       add(new Label("forkSource", StringUtils.stripDotGit(source)));\r
+               }\r
 \r
                // only display user-accessible forks\r
-               UserModel user = GitBlitWebSession.get().getUser();\r
                List<RepositoryModel> forks = new ArrayList<RepositoryModel>();\r
                for (String aFork : list) {\r
                        RepositoryModel fork = GitBlit.self().getRepositoryModel(user, aFork);\r
index a85d21e189dd665bc3e4f55b87d8608d71b25d99..8ca2b335e499325ea08729369e2ef27687b6ec65 100644 (file)
@@ -136,22 +136,12 @@ public abstract class RepositoryPage extends BasePage {
                pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));\r
                pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));\r
                pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));\r
+               pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));\r
 \r
                // conditional links\r
                Repository r = getRepository();\r
                RepositoryModel model = getRepositoryModel();\r
 \r
-               // forks list button\r
-               if (StringUtils.isEmpty(model.originRepository)) {\r
-                       if (!ArrayUtils.isEmpty(model.forks)) {\r
-                               // this origin repository has forks\r
-                               pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));\r
-                       }\r
-               } else {\r
-                       // this is a fork of another repository\r
-                       pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));\r
-               }\r
-               \r
                // per-repository extra page links\r
                if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) {\r
                        pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, params));\r
@@ -204,15 +194,29 @@ public abstract class RepositoryPage extends BasePage {
                                WicketUtils.newRepositoryParameter(repositoryName)));\r
                add(new Label("pageName", pageName).setRenderBodyOnly(true));\r
                \r
+               UserModel user = GitBlitWebSession.get().getUser();\r
+\r
                // indicate origin repository\r
                RepositoryModel model = getRepositoryModel();\r
                if (StringUtils.isEmpty(model.originRepository)) {\r
                        add(new Label("originRepository").setVisible(false));\r
                } else {\r
-                       Fragment forkFrag = new Fragment("originRepository", "originFragment", this);\r
-                       forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository), \r
-                                       SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));\r
-                       add(forkFrag);\r
+                       RepositoryModel origin = GitBlit.self().getRepositoryModel(model.originRepository);\r
+                       if (origin == null) {\r
+                               // no origin repository\r
+                               add(new Label("originRepository").setVisible(false));\r
+                       } else if (!user.canViewRepository(origin)) {\r
+                               // show origin repository without link\r
+                               Fragment forkFrag = new Fragment("originRepository", "originFragment", this);\r
+                               forkFrag.add(new Label("originRepository", StringUtils.stripDotGit(model.originRepository)));\r
+                               add(forkFrag);\r
+                       } else {\r
+                               // link to origin repository\r
+                               Fragment forkFrag = new Fragment("originRepository", "originFragment", this);\r
+                               forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository), \r
+                                               SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));\r
+                               add(forkFrag);\r
+                       }\r
                }\r
                \r
                if (getRepositoryModel().isBare) {\r
@@ -224,33 +228,57 @@ public abstract class RepositoryPage extends BasePage {
                        wc.add(lbl);\r
                        add(wc);\r
                }\r
-               \r
-               if (getRepositoryModel().allowForks) {\r
+\r
+               // fork controls\r
+               if (user == null) {\r
+                       // must be logged-in to fork, hide all fork controls\r
+                       add(new ExternalLink("forkLink", "").setVisible(false));\r
+                       add(new ExternalLink("myForkLink", "").setVisible(false));\r
                        add(new Label("forksProhibitedIndicator").setVisible(false));\r
                } else {\r
-                       Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this);\r
-                       Label lbl = new Label("forksProhibited", getString("gb.forksProhibited"));\r
-                       WicketUtils.setHtmlTooltip(lbl,  getString("gb.forksProhibitedWarning"));\r
-                       wc.add(lbl);\r
-                       add(wc);\r
-               }\r
-               \r
-               UserModel user = GitBlitWebSession.get().getUser();\r
-               \r
-               // fork button\r
-               if (user != null) {                     \r
-                       final String clonedRepo = MessageFormat.format("~{0}/{1}.git", user.username, StringUtils.stripDotGit(StringUtils.getLastPathElement(model.name)));\r
-                       boolean hasClone = GitBlit.self().hasRepository(clonedRepo) && !getRepositoryModel().name.equals(clonedRepo);\r
-                       if (user.canForkRepository(model) && !hasClone) {\r
+                       String fork = GitBlit.self().getFork(user.username, model.name);\r
+                       boolean hasFork = fork != null;\r
+                       boolean canFork = user.canForkRepository(model);\r
+\r
+                       if (hasFork || !canFork) {\r
+                               // user not allowed to fork or fork already exists or repo forbids forking\r
+                               add(new ExternalLink("forkLink", "").setVisible(false));\r
+                               \r
+                               if (user.canFork && !model.allowForks) {\r
+                                       // show forks prohibited indicator\r
+                                       Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this);\r
+                                       Label lbl = new Label("forksProhibited", getString("gb.forksProhibited"));\r
+                                       WicketUtils.setHtmlTooltip(lbl,  getString("gb.forksProhibitedWarning"));\r
+                                       wc.add(lbl);\r
+                                       add(wc);\r
+                               } else {\r
+                                       // can not fork, no need for forks prohibited indicator\r
+                                       add(new Label("forksProhibitedIndicator").setVisible(false));\r
+                               }\r
+                               \r
+                               if (hasFork && !fork.equals(model.name)) {\r
+                                       // user has fork, view my fork link\r
+                                       String url = getRequestCycle().urlFor(SummaryPage.class, WicketUtils.newRepositoryParameter(fork)).toString();\r
+                                       add(new ExternalLink("myForkLink", url));\r
+                               } else {\r
+                                       // no fork, hide view my fork link\r
+                                       add(new ExternalLink("myForkLink", "").setVisible(false));\r
+                               }\r
+                       } else if (canFork) {\r
+                               // can fork and we do not have one\r
+                               add(new Label("forksProhibitedIndicator").setVisible(false));\r
+                               add(new ExternalLink("myForkLink", "").setVisible(false));\r
                                Link<Void> forkLink = new Link<Void>("forkLink") {\r
 \r
                                        private static final long serialVersionUID = 1L;\r
 \r
                                        @Override\r
                                        public void onClick() {\r
+                                               UserModel user = GitBlitWebSession.get().getUser();\r
                                                RepositoryModel model = getRepositoryModel();\r
+                                               String asFork = MessageFormat.format("~{0}/{1}.git", user.username, StringUtils.stripDotGit(StringUtils.getLastPathElement(model.name)));\r
                                                if (GitBlit.self().fork(model, GitBlitWebSession.get().getUser())) {\r
-                                                       throw new RedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(clonedRepo));\r
+                                                       throw new RedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(asFork));\r
                                                } else {\r
                                                        error(MessageFormat.format(getString("gb.repositoryForkFailed"), model));\r
                                                }\r
@@ -259,23 +287,7 @@ public abstract class RepositoryPage extends BasePage {
                                forkLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(\r
                                                getString("gb.forkRepository"), getRepositoryModel())));\r
                                add(forkLink);\r
-                       } else {\r
-                               // user not allowed to fork or fork already exists or repo forbids forking\r
-                               add(new ExternalLink("forkLink", "").setVisible(false));\r
                        }\r
-                       \r
-                       if (hasClone) {\r
-                               // user has clone\r
-                               String url = getRequestCycle().urlFor(SummaryPage.class, WicketUtils.newRepositoryParameter(clonedRepo)).toString();\r
-                               add(new ExternalLink("myForkLink", url));\r
-                       } else {\r
-                               // user does not have clone\r
-                               add(new ExternalLink("myForkLink", "").setVisible(false));\r
-                       }\r
-               } else {\r
-                       // server prohibits forking\r
-                       add(new ExternalLink("forkLink", "").setVisible(false));\r
-                       add(new ExternalLink("myForkLink", "").setVisible(false));\r
                }\r
                \r
                super.setupPage(repositoryName, pageName);\r
@@ -577,4 +589,4 @@ public abstract class RepositoryPage extends BasePage {
                        getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));\r
                }\r
        }\r
-}\r
+}
\ No newline at end of file