]> source.dussan.org Git - gitblit.git/commitdiff
Implemented New Repository for personal repositories
authorJames Moger <james.moger@gitblit.com>
Fri, 5 Oct 2012 21:44:53 +0000 (17:44 -0400)
committerJames Moger <james.moger@gitblit.com>
Fri, 5 Oct 2012 21:44:53 +0000 (17:44 -0400)
17 files changed:
docs/04_releases.mkd
src/com/gitblit/ConfigUserService.java
src/com/gitblit/Constants.java
src/com/gitblit/FileUserService.java
src/com/gitblit/client/EditUserDialog.java
src/com/gitblit/models/UserModel.java
src/com/gitblit/wicket/GitBlitWebApp.properties
src/com/gitblit/wicket/pages/EditRepositoryPage.java
src/com/gitblit/wicket/pages/EditUserPage.html
src/com/gitblit/wicket/pages/EditUserPage.java
src/com/gitblit/wicket/pages/RepositoriesPage.java
src/com/gitblit/wicket/pages/ReviewProposalPage.java
src/com/gitblit/wicket/pages/SendProposalPage.java
src/com/gitblit/wicket/pages/UserPage.html
src/com/gitblit/wicket/pages/UserPage.java
src/com/gitblit/wicket/panels/RepositoriesPanel.html
src/com/gitblit/wicket/panels/RepositoriesPanel.java

index 55bdfd71022efa46d90d9b9d87ab9ba18182910b..333623438d090813740f070061877f9ad82d74a6 100644 (file)
@@ -20,10 +20,10 @@ If you are updating from an earlier release AND you have indexed branches with t
 #### additions\r
 \r
 - Added simple project pages.  A project is a subfolder off the *git.repositoriesFolder*.\r
-- Added support for personal repositories.  This builds on the simple project pages.  \r
-Personal repositories are stored in *git.repositoriesFolder*/*~username*.  Each user with personal repositories will have a user page, something like the GitHub profile page.  Personal repositories have all the same features as common repositories.\r
+- Added support for personal repositories.  \r
+Personal repositories can be created by accounts with the *create* permission and are stored in *git.repositoriesFolder/~username*.  Each user with personal repositories will have a user page, something like the GitHub profile page.  Personal repositories have all the same features as common repositories, except personal repositories can be renamed by their owner.\r
 - Added support for server-side forking of a repository to a personal repository (issue 137)  \r
-In order to fork a repository to a personal clone, the user account must have the *fork* permission **and** the repository must *allow forks*.  The clone inherits the access restrictions of its origin.  i.e. if Team A has access to the origin repository, then by default Team A also has access to the fork.  This is to facilitate collaboration.  However, the fork owner may change access to the fork and add/remove users/teams, etc as required.\r
+In order to fork a repository, the user account must have the *fork* permission **and** the repository must *allow forks*.  The clone inherits the access restrictions of its origin.  i.e. if Team A has access to the origin repository, then by default Team A also has access to the fork.  This is to facilitate collaboration.  The fork owner may change access to the fork and add/remove users/teams, etc as required __however__ it should be noted that all personal forks will be enumerated in the fork network regardless of access view restrictions.  If you really must have an invisible fork, the clone it locally, create a new repository for your invisible fork, and push it back.\r
 - Added support for X-Forwarded-Context for Apache subdomain proxy configurations (issue 135)\r
 - Delete branch feature (issue 121, Github/ajermakovics)\r
 - Added line links to blob view at the expense of zebra striping (issue 130)\r
index f526835d77945b1a197e27c958d62fe5eb11ca89..831ede9b15a35b1c138ab39871f35573b46289fb 100644 (file)
@@ -753,6 +753,9 @@ public class ConfigUserService implements IUserService {
                        if (model.canFork) {\r
                                roles.add(Constants.FORK_ROLE);\r
                        }\r
+                       if (model.canCreate) {\r
+                               roles.add(Constants.CREATE_ROLE);\r
+                       }\r
                        if (model.excludeFromFederation) {\r
                                roles.add(Constants.NOT_FEDERATED_ROLE);\r
                        }\r
@@ -862,6 +865,7 @@ public class ConfigUserService implements IUserService {
                                                        USER, username, ROLE)));\r
                                        user.canAdmin = roles.contains(Constants.ADMIN_ROLE);\r
                                        user.canFork = roles.contains(Constants.FORK_ROLE);\r
+                                       user.canCreate = roles.contains(Constants.CREATE_ROLE);\r
                                        user.excludeFromFederation = roles.contains(Constants.NOT_FEDERATED_ROLE);\r
 \r
                                        // repository memberships\r
index c53119b2917c27209949b581397cf26bf812e9a7..c831c42df798ecc916099c143f024a809e95b19a 100644 (file)
@@ -43,6 +43,8 @@ public class Constants {
        public static final String ADMIN_ROLE = "#admin";\r
        \r
        public static final String FORK_ROLE = "#fork";\r
+       \r
+       public static final String CREATE_ROLE = "#create";\r
 \r
        public static final String NOT_FEDERATED_ROLE = "#notfederated";\r
        \r
index 40bc3f60769534e0da1c5722aed2d4e6bc84ecc1..f439469608d3d26718498c63abea4bf9a56daa0f 100644 (file)
@@ -236,6 +236,8 @@ public class FileUserService extends FileSettings implements IUserService {
                                        model.canAdmin = true;\r
                                } else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) {\r
                                        model.canFork = true;\r
+                               } else if (role.equalsIgnoreCase(Constants.CREATE_ROLE)) {\r
+                                       model.canCreate = true;\r
                                } else if (role.equalsIgnoreCase(Constants.NOT_FEDERATED_ROLE)) {\r
                                        model.excludeFromFederation = true;\r
                                }\r
@@ -288,6 +290,9 @@ public class FileUserService extends FileSettings implements IUserService {
                        if (model.canFork) {\r
                                roles.add(Constants.FORK_ROLE);\r
                        }\r
+                       if (model.canCreate) {\r
+                               roles.add(Constants.CREATE_ROLE);\r
+                       }\r
                        if (model.excludeFromFederation) {\r
                                roles.add(Constants.NOT_FEDERATED_ROLE);\r
                        }\r
index 88612b7924cae8f9c37d31af532a1c62f4d63a2b..4ef036e872688ce88465b1f685774f5341bb3bed 100644 (file)
@@ -80,6 +80,8 @@ public class EditUserDialog extends JDialog {
        private JCheckBox canAdminCheckbox;\r
        \r
        private JCheckBox canForkCheckbox;\r
+       \r
+       private JCheckBox canCreateCheckbox;\r
 \r
        private JCheckBox notFederatedCheckbox;\r
 \r
@@ -128,7 +130,8 @@ public class EditUserDialog extends JDialog {
                displayNameField = new JTextField(anUser.displayName == null ? "" : anUser.displayName, 25);\r
                emailAddressField = new JTextField(anUser.emailAddress == null ? "" : anUser.emailAddress, 25);\r
                canAdminCheckbox = new JCheckBox(Translation.get("gb.canAdminDescription"), anUser.canAdmin);           \r
-               canForkCheckbox = new JCheckBox(Translation.get("gb.canForkDescription"), anUser.canFork);              \r
+               canForkCheckbox = new JCheckBox(Translation.get("gb.canForkDescription"), anUser.canFork);\r
+               canCreateCheckbox = new JCheckBox(Translation.get("gb.canCreateDescription"), anUser.canCreate);\r
                notFederatedCheckbox = new JCheckBox(\r
                                Translation.get("gb.excludeFromFederationDescription"),\r
                                anUser.excludeFromFederation);\r
@@ -149,6 +152,7 @@ public class EditUserDialog extends JDialog {
                fieldsPanel.add(newFieldPanel(Translation.get("gb.emailAddress"), emailAddressField));\r
                fieldsPanel.add(newFieldPanel(Translation.get("gb.canAdmin"), canAdminCheckbox));\r
                fieldsPanel.add(newFieldPanel(Translation.get("gb.canFork"), canForkCheckbox));\r
+               fieldsPanel.add(newFieldPanel(Translation.get("gb.canCreate"), canCreateCheckbox));\r
                fieldsPanel.add(newFieldPanel(Translation.get("gb.excludeFromFederation"),\r
                                notFederatedCheckbox));\r
 \r
@@ -311,6 +315,7 @@ public class EditUserDialog extends JDialog {
 \r
                user.canAdmin = canAdminCheckbox.isSelected();\r
                user.canFork = canForkCheckbox.isSelected();\r
+               user.canCreate = canCreateCheckbox.isSelected();\r
                user.excludeFromFederation = notFederatedCheckbox.isSelected();\r
 \r
                user.repositories.clear();\r
index dd41df08ebc23d246102f132a341586242189074..94bd055dba7f845381f3570b4178e064037ba7c8 100644 (file)
@@ -46,6 +46,7 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
        public String emailAddress;\r
        public boolean canAdmin;\r
        public boolean canFork;\r
+       public boolean canCreate;\r
        public boolean excludeFromFederation;\r
        public final Set<String> repositories = new HashSet<String>();\r
        public final Set<TeamModel> teams = new HashSet<TeamModel>();\r
@@ -174,6 +175,23 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
                }\r
                return displayName;\r
        }\r
+       \r
+       public String getPersonalPath() {\r
+               return "~" + username;\r
+       }\r
+       \r
+       @Override\r
+       public int hashCode() {\r
+               return username.hashCode();\r
+       }\r
+       \r
+       @Override\r
+       public boolean equals(Object o) {\r
+               if (o instanceof UserModel) {\r
+                       return username.equals(((UserModel) o).username);\r
+               }\r
+               return false;\r
+       }\r
 \r
        @Override\r
        public String toString() {\r
index 166064279c913a711b0e40c6abfdb00a0a98e0e7..97faf761586c921dfdcfa0d37ae89499a508a1f2 100644 (file)
@@ -337,4 +337,7 @@ gb.noForks = {0} has no forks
 gb.forkNotAuthorized = sorry, you are not authorized to fork {0}\r
 gb.forkInProgress = fork in progress\r
 gb.preparingFork = preparing your fork...\r
-gb.isFork = is fork
\ No newline at end of file
+gb.isFork = is fork\r
+gb.canCreate = can create\r
+gb.canCreateDescription = can create personal repositories\r
+gb.illegalPersonalRepositoryLocation = your personal repository must be located at \"{0}\"
\ No newline at end of file
index 214d0f0d5a1be781f2abbd28420d381af35c76f7..f7427eb587ee9bfdaddfcfa93bd9a1f4326dc4f1 100644 (file)
@@ -80,6 +80,19 @@ public class EditRepositoryPage extends RootSubPage {
                model.accessRestriction = AccessRestrictionType.fromName(restriction);\r
                String authorization = GitBlit.getString(Keys.git.defaultAuthorizationControl, null);\r
                model.authorizationControl = AuthorizationControl.fromName(authorization);\r
+               \r
+               GitBlitWebSession session = GitBlitWebSession.get();\r
+               UserModel user = session.getUser();\r
+               if (user != null && user.canCreate && !user.canAdmin) {\r
+                       // personal create permissions, inject personal repository path\r
+                       model.name = user.getPersonalPath() + "/";\r
+                       model.projectPath = user.getPersonalPath();\r
+                       model.owner = user.username;\r
+                       // personal repositories are private by default\r
+                       model.accessRestriction = AccessRestrictionType.VIEW;\r
+                       model.authorizationControl = AuthorizationControl.NAMED;\r
+               }\r
+               \r
                setupPage(model);\r
        }\r
 \r
@@ -103,8 +116,15 @@ public class EditRepositoryPage extends RootSubPage {
                List<String> preReceiveScripts = new ArrayList<String>();\r
                List<String> postReceiveScripts = new ArrayList<String>();\r
 \r
+               GitBlitWebSession session = GitBlitWebSession.get();\r
+               final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser();\r
+\r
                if (isCreate) {\r
-                       super.setupPage(getString("gb.newRepository"), "");\r
+                       if (user.canAdmin) {\r
+                               super.setupPage(getString("gb.newRepository"), "");\r
+                       } else {\r
+                               super.setupPage(getString("gb.newRepository"), user.getDisplayName());\r
+                       }\r
                } else {\r
                        super.setupPage(getString("gb.edit"), repositoryModel.name);\r
                        if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
@@ -195,11 +215,14 @@ public class EditRepositoryPage extends RootSubPage {
                        protected void onSubmit() {\r
                                try {\r
                                        // confirm a repository name was entered\r
-                                       if (StringUtils.isEmpty(repositoryModel.name)) {\r
+                                       if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) {\r
                                                error(getString("gb.pleaseSetRepositoryName"));\r
                                                return;\r
                                        }\r
-\r
+                                       \r
+                                       // ensure name is trimmed\r
+                                       repositoryModel.name = repositoryModel.name.trim();\r
+                                       \r
                                        // automatically convert backslashes to forward slashes\r
                                        repositoryModel.name = repositoryModel.name.replace('\\', '/');\r
                                        // Automatically replace // with /\r
@@ -229,6 +252,22 @@ public class EditRepositoryPage extends RootSubPage {
                                                                c));\r
                                                return;\r
                                        }\r
+                                       \r
+                                       if (user.canCreate && !user.canAdmin) {\r
+                                               // ensure repository name begins with the user's path\r
+                                               if (!repositoryModel.name.startsWith(user.getPersonalPath())) {\r
+                                                       error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"),\r
+                                                                       user.getPersonalPath()));\r
+                                                       return;\r
+                                               }\r
+                                               \r
+                                               if (repositoryModel.name.equals(user.getPersonalPath())) {\r
+                                                       // reset path prefix and show error\r
+                                                       repositoryModel.name = user.getPersonalPath() + "/";\r
+                                                       error(getString("gb.pleaseSetRepositoryName"));\r
+                                                       return;\r
+                                               }\r
+                                       }\r
 \r
                                        // confirm access restriction selection\r
                                        if (repositoryModel.accessRestriction == null) {\r
@@ -339,7 +378,7 @@ public class EditRepositoryPage extends RootSubPage {
                form.add(new SimpleAttributeModifier("autocomplete", "off"));\r
 \r
                // field names reflective match RepositoryModel fields\r
-               form.add(new TextField<String>("name").setEnabled(isCreate || isAdmin));\r
+               form.add(new TextField<String>("name").setEnabled(isCreate || isAdmin || repositoryModel.isUsersPersonalRepository(user.username)));\r
                form.add(new TextField<String>("description"));\r
                form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames())\r
                                .setEnabled(GitBlitWebSession.get().canAdmin()));\r
@@ -435,8 +474,8 @@ public class EditRepositoryPage extends RootSubPage {
                                }\r
                                if (isCreate) {\r
                                        // Create Repository\r
-                                       if (!user.canAdmin) {\r
-                                               // Only Administrators May Create\r
+                                       if (!user.canCreate && !user.canAdmin) {\r
+                                               // Only administrators or permitted users may create\r
                                                error(getString("gb.errorOnlyAdminMayCreateRepository"), true);\r
                                        }\r
                                } else {\r
index 685eb64f81a8bc80b5afd7fdbf32859dd1c5ca9f..7793207954de401863c59837ee11b4ebc95fc118 100644 (file)
@@ -18,7 +18,8 @@
                                <tr><th><wicket:message key="gb.emailAddress"></wicket:message></th><td class="edit"><input type="text" wicket:id="emailAddress" size="30" tabindex="5" /></td></tr>\r
                                <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> &nbsp;<span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr>                            \r
                                <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr>                               \r
-                               <tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr>                             \r
+                               <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr>                         \r
+                               <tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="9" /> &nbsp;<span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr>                             \r
                                <tr><td colspan="2" style="padding-top:15px;"><h3><wicket:message key="gb.accessPermissions"></wicket:message> &nbsp;<small><wicket:message key="gb.accessPermissionsForUserDescription"></wicket:message></small></h3></td></tr>       \r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.teamMemberships"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr>\r
                                <tr><td colspan="2"><hr></hr></td></tr>\r
index 31f91c1cb3da8a01c22824bf8e8e5576050c1dd4..49515fb97275a47018c472200fb979052ab2ecfe 100644 (file)
@@ -232,6 +232,7 @@ public class EditUserPage extends RootSubPage {
                form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));\r
                form.add(new CheckBox("canAdmin"));\r
                form.add(new CheckBox("canFork"));\r
+               form.add(new CheckBox("canCreate"));\r
                form.add(new CheckBox("excludeFromFederation"));\r
                form.add(repositories);\r
                form.add(teams.setEnabled(editTeams));\r
index 98dade6768b903e9945dc0e6e4394efa52c6048a..36f2c6d533d9baf1ca17ee68c0b7fdaab620c258 100644 (file)
@@ -82,7 +82,7 @@ public class RepositoriesPage extends RootPage {
                List<RepositoryModel> repositories = getRepositories(params);\r
 \r
                RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", showAdmin,\r
-                               repositories, true, getAccessRestrictions());\r
+                               true, repositories, true, getAccessRestrictions());\r
                // push the panel down if we are hiding the admin controls and the\r
                // welcome message\r
                if (!showAdmin && !repositoriesMessage.isVisible()) {\r
index df7b1bc11bc6aa0176b7a18e991d11e258e03177..e1813861f1908cfcb6121153f07cf4c535c5808b 100644 (file)
@@ -92,7 +92,7 @@ public class ReviewProposalPage extends RootSubPage {
                List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(\r
                                proposal.repositories.values());\r
                RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false,\r
-                               repositories, false, getAccessRestrictions());\r
+                               false, repositories, false, getAccessRestrictions());\r
                add(repositoriesPanel);\r
        }\r
 \r
index aa9c03a1c1a65dc267b7db763378e950f16ae481..fc5f95b5f79ea0c88cbae14e3eb39bf50157514d 100644 (file)
@@ -146,7 +146,7 @@ public class SendProposalPage extends RootSubPage {
                List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(\r
                                proposal.repositories.values());\r
                RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false,\r
-                               repositories, false, getAccessRestrictions());\r
+                               false, repositories, false, getAccessRestrictions());\r
                add(repositoriesPanel);\r
        }\r
 }\r
index 5886a3a2cca1c2ace26a38e4465585805739a6f0..c7131c09ced394433e4507b7b5d8c070a4b05bde 100644 (file)
                </div>\r
                \r
                <div class="span8">\r
+                       <div class="pull-right">\r
+                               <a class="btn-small" wicket:id="newRepository" style="padding-right:0px;">\r
+                                       <i class="icon icon-plus-sign"></i>\r
+                                       <wicket:message key="gb.newRepository"></wicket:message>\r
+                               </a>\r
+                       </div>\r
                        <div class="tabbable">\r
                                <!-- tab titles -->\r
                                <ul class="nav nav-tabs">\r
index 28450e94948433100e86c76c96db26598262ea59..e699d03f9df76064fea1d9d064136cbbcd7b910e 100644 (file)
@@ -22,6 +22,7 @@ import java.util.List;
 \r
 import org.apache.wicket.PageParameters;\r
 import org.apache.wicket.markup.html.basic.Label;\r
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
 import org.apache.wicket.markup.repeater.Item;\r
 import org.apache.wicket.markup.repeater.data.DataView;\r
 import org.apache.wicket.markup.repeater.data.ListDataProvider;\r
@@ -99,6 +100,14 @@ public class UserPage extends RootPage {
                PersonIdent person = new PersonIdent(user.getDisplayName(), user.emailAddress);\r
                add(new GravatarImage("gravatar", person, 210));\r
                \r
+               UserModel sessionUser = GitBlitWebSession.get().getUser();\r
+               if (sessionUser != null && user.canCreate && sessionUser.equals(user)) {\r
+                       // user can create personal repositories\r
+                       add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));\r
+               } else {\r
+                       add(new Label("newRepository").setVisible(false));\r
+               }\r
+               \r
                List<RepositoryModel> repositories = getRepositories(params);\r
                \r
                Collections.sort(repositories, new Comparator<RepositoryModel>() {\r
index ddf1656e7e962dd19971681cca049402f5db2888..42f9f1f2a399be68eff1003a756f76b16d507ccd 100644 (file)
@@ -7,7 +7,7 @@
 <body>\r
 <wicket:panel>\r
 \r
-       <div wicket:id="adminPanel">[admin links]</div>\r
+       <div wicket:id="managementPanel">[management links]</div>\r
 \r
        <table class="repositories">\r
                <span wicket:id="headerContent"></span>\r
                </div>  \r
        </wicket:fragment>\r
        \r
+       <wicket:fragment wicket:id="personalLinks">\r
+               <!-- page nav links --> \r
+               <div class="admin_nav">\r
+                       <a class="btn-small" wicket:id="newRepository" style="padding-right:0px;">\r
+                               <i class="icon icon-plus-sign"></i>\r
+                               <wicket:message key="gb.newRepository"></wicket:message>\r
+                       </a>\r
+               </div>  \r
+       </wicket:fragment>\r
+\r
        <wicket:fragment wicket:id="repositoryAdminLinks">\r
                <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="deleteRepository"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>\r
        </wicket:fragment>\r
index 02ebf4f48b1192cc37b14a53135be38c555edfa7..137fae6bd0e02e74ad12fe49e64084f3736c1d9e 100644 (file)
@@ -64,7 +64,7 @@ public class RepositoriesPanel extends BasePanel {
 \r
        private static final long serialVersionUID = 1L;\r
 \r
-       public RepositoriesPanel(String wicketId, final boolean showAdmin,\r
+       public RepositoriesPanel(String wicketId, final boolean showAdmin, final boolean showManagement,\r
                        List<RepositoryModel> models, boolean enableLinks,\r
                        final Map<AccessRestrictionType, String> accessRestrictionTranslations) {\r
                super(wicketId);\r
@@ -76,19 +76,31 @@ public class RepositoriesPanel extends BasePanel {
 \r
                final IDataProvider<RepositoryModel> dp;\r
 \r
-               Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);\r
-               adminLinks.add(new Link<Void>("clearCache") {\r
+               Fragment managementLinks;\r
+               if (showAdmin) {\r
+                       // user is admin\r
+                       managementLinks = new Fragment("managementPanel", "adminLinks", this);\r
+                       managementLinks.add(new Link<Void>("clearCache") {\r
 \r
-                       private static final long serialVersionUID = 1L;\r
+                               private static final long serialVersionUID = 1L;\r
 \r
-                       @Override\r
-                       public void onClick() {\r
-                               GitBlit.self().resetRepositoryListCache();\r
-                               setResponsePage(RepositoriesPage.class);\r
-                       }\r
-               }.setVisible(GitBlit.getBoolean(Keys.git.cacheRepositoryList, true)));\r
-               adminLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));\r
-               add(adminLinks.setVisible(showAdmin));\r
+                               @Override\r
+                               public void onClick() {\r
+                                       GitBlit.self().resetRepositoryListCache();\r
+                                       setResponsePage(RepositoriesPage.class);\r
+                               }\r
+                       }.setVisible(GitBlit.getBoolean(Keys.git.cacheRepositoryList, true)));\r
+                       managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));\r
+                       add(managementLinks);\r
+               } else if (showManagement && user != null && user.canCreate) {\r
+                       // user can create personal repositories\r
+                       managementLinks = new Fragment("managementPanel", "personalLinks", this);\r
+                       managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));\r
+                       add(managementLinks);\r
+               } else {\r
+                       // user has no management permissions\r
+                       add (new Label("managementPanel").setVisible(false));\r
+               }\r
 \r
                if (GitBlit.getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {\r
                        List<RepositoryModel> rootRepositories = new ArrayList<RepositoryModel>();\r
@@ -297,7 +309,7 @@ public class RepositoriesPanel extends BasePanel {
                                row.add(lastChangeLabel);\r
                                WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));\r
 \r
-                               boolean showOwner = user != null && user.username.equalsIgnoreCase(entry.owner);\r
+                               boolean showOwner = user != null && entry.isOwner(user.username);\r
                                boolean myPersonalRepository = showOwner && entry.isUsersPersonalRepository(user.username);\r
                                if (showAdmin || myPersonalRepository) {\r
                                        Fragment repositoryLinks = new Fragment("repositoryLinks",\r