From 6662e38a4e252b6ed455ca8f11729d0f1440a3b0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 5 Oct 2012 17:44:53 -0400 Subject: [PATCH] Implemented New Repository for personal repositories --- docs/04_releases.mkd | 6 +-- src/com/gitblit/ConfigUserService.java | 4 ++ src/com/gitblit/Constants.java | 2 + src/com/gitblit/FileUserService.java | 5 ++ src/com/gitblit/client/EditUserDialog.java | 7 ++- src/com/gitblit/models/UserModel.java | 18 +++++++ .../gitblit/wicket/GitBlitWebApp.properties | 5 +- .../wicket/pages/EditRepositoryPage.java | 51 ++++++++++++++++--- .../gitblit/wicket/pages/EditUserPage.html | 3 +- .../gitblit/wicket/pages/EditUserPage.java | 1 + .../wicket/pages/RepositoriesPage.java | 2 +- .../wicket/pages/ReviewProposalPage.java | 2 +- .../wicket/pages/SendProposalPage.java | 2 +- src/com/gitblit/wicket/pages/UserPage.html | 6 +++ src/com/gitblit/wicket/pages/UserPage.java | 9 ++++ .../wicket/panels/RepositoriesPanel.html | 12 ++++- .../wicket/panels/RepositoriesPanel.java | 38 +++++++++----- 17 files changed, 144 insertions(+), 29 deletions(-) diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 55bdfd71..33362343 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -20,10 +20,10 @@ If you are updating from an earlier release AND you have indexed branches with t #### additions - Added simple project pages. A project is a subfolder off the *git.repositoriesFolder*. -- Added support for personal repositories. This builds on the simple project pages. -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. +- Added support for personal repositories. +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. - Added support for server-side forking of a repository to a personal repository (issue 137) -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. +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. - Added support for X-Forwarded-Context for Apache subdomain proxy configurations (issue 135) - Delete branch feature (issue 121, Github/ajermakovics) - Added line links to blob view at the expense of zebra striping (issue 130) diff --git a/src/com/gitblit/ConfigUserService.java b/src/com/gitblit/ConfigUserService.java index f526835d..831ede9b 100644 --- a/src/com/gitblit/ConfigUserService.java +++ b/src/com/gitblit/ConfigUserService.java @@ -753,6 +753,9 @@ public class ConfigUserService implements IUserService { if (model.canFork) { roles.add(Constants.FORK_ROLE); } + if (model.canCreate) { + roles.add(Constants.CREATE_ROLE); + } if (model.excludeFromFederation) { roles.add(Constants.NOT_FEDERATED_ROLE); } @@ -862,6 +865,7 @@ public class ConfigUserService implements IUserService { USER, username, ROLE))); user.canAdmin = roles.contains(Constants.ADMIN_ROLE); user.canFork = roles.contains(Constants.FORK_ROLE); + user.canCreate = roles.contains(Constants.CREATE_ROLE); user.excludeFromFederation = roles.contains(Constants.NOT_FEDERATED_ROLE); // repository memberships diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index c53119b2..c831c42d 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -43,6 +43,8 @@ public class Constants { public static final String ADMIN_ROLE = "#admin"; public static final String FORK_ROLE = "#fork"; + + public static final String CREATE_ROLE = "#create"; public static final String NOT_FEDERATED_ROLE = "#notfederated"; diff --git a/src/com/gitblit/FileUserService.java b/src/com/gitblit/FileUserService.java index 40bc3f60..f4394696 100644 --- a/src/com/gitblit/FileUserService.java +++ b/src/com/gitblit/FileUserService.java @@ -236,6 +236,8 @@ public class FileUserService extends FileSettings implements IUserService { model.canAdmin = true; } else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) { model.canFork = true; + } else if (role.equalsIgnoreCase(Constants.CREATE_ROLE)) { + model.canCreate = true; } else if (role.equalsIgnoreCase(Constants.NOT_FEDERATED_ROLE)) { model.excludeFromFederation = true; } @@ -288,6 +290,9 @@ public class FileUserService extends FileSettings implements IUserService { if (model.canFork) { roles.add(Constants.FORK_ROLE); } + if (model.canCreate) { + roles.add(Constants.CREATE_ROLE); + } if (model.excludeFromFederation) { roles.add(Constants.NOT_FEDERATED_ROLE); } diff --git a/src/com/gitblit/client/EditUserDialog.java b/src/com/gitblit/client/EditUserDialog.java index 88612b79..4ef036e8 100644 --- a/src/com/gitblit/client/EditUserDialog.java +++ b/src/com/gitblit/client/EditUserDialog.java @@ -80,6 +80,8 @@ public class EditUserDialog extends JDialog { private JCheckBox canAdminCheckbox; private JCheckBox canForkCheckbox; + + private JCheckBox canCreateCheckbox; private JCheckBox notFederatedCheckbox; @@ -128,7 +130,8 @@ public class EditUserDialog extends JDialog { displayNameField = new JTextField(anUser.displayName == null ? "" : anUser.displayName, 25); emailAddressField = new JTextField(anUser.emailAddress == null ? "" : anUser.emailAddress, 25); canAdminCheckbox = new JCheckBox(Translation.get("gb.canAdminDescription"), anUser.canAdmin); - canForkCheckbox = new JCheckBox(Translation.get("gb.canForkDescription"), anUser.canFork); + canForkCheckbox = new JCheckBox(Translation.get("gb.canForkDescription"), anUser.canFork); + canCreateCheckbox = new JCheckBox(Translation.get("gb.canCreateDescription"), anUser.canCreate); notFederatedCheckbox = new JCheckBox( Translation.get("gb.excludeFromFederationDescription"), anUser.excludeFromFederation); @@ -149,6 +152,7 @@ public class EditUserDialog extends JDialog { fieldsPanel.add(newFieldPanel(Translation.get("gb.emailAddress"), emailAddressField)); fieldsPanel.add(newFieldPanel(Translation.get("gb.canAdmin"), canAdminCheckbox)); fieldsPanel.add(newFieldPanel(Translation.get("gb.canFork"), canForkCheckbox)); + fieldsPanel.add(newFieldPanel(Translation.get("gb.canCreate"), canCreateCheckbox)); fieldsPanel.add(newFieldPanel(Translation.get("gb.excludeFromFederation"), notFederatedCheckbox)); @@ -311,6 +315,7 @@ public class EditUserDialog extends JDialog { user.canAdmin = canAdminCheckbox.isSelected(); user.canFork = canForkCheckbox.isSelected(); + user.canCreate = canCreateCheckbox.isSelected(); user.excludeFromFederation = notFederatedCheckbox.isSelected(); user.repositories.clear(); diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index dd41df08..94bd055d 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -46,6 +46,7 @@ public class UserModel implements Principal, Serializable, Comparable public String emailAddress; public boolean canAdmin; public boolean canFork; + public boolean canCreate; public boolean excludeFromFederation; public final Set repositories = new HashSet(); public final Set teams = new HashSet(); @@ -174,6 +175,23 @@ public class UserModel implements Principal, Serializable, Comparable } return displayName; } + + public String getPersonalPath() { + return "~" + username; + } + + @Override + public int hashCode() { + return username.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof UserModel) { + return username.equals(((UserModel) o).username); + } + return false; + } @Override public String toString() { diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 16606427..97faf761 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -337,4 +337,7 @@ gb.noForks = {0} has no forks gb.forkNotAuthorized = sorry, you are not authorized to fork {0} gb.forkInProgress = fork in progress gb.preparingFork = preparing your fork... -gb.isFork = is fork \ No newline at end of file +gb.isFork = is fork +gb.canCreate = can create +gb.canCreateDescription = can create personal repositories +gb.illegalPersonalRepositoryLocation = your personal repository must be located at \"{0}\" \ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index 214d0f0d..f7427eb5 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -80,6 +80,19 @@ public class EditRepositoryPage extends RootSubPage { model.accessRestriction = AccessRestrictionType.fromName(restriction); String authorization = GitBlit.getString(Keys.git.defaultAuthorizationControl, null); model.authorizationControl = AuthorizationControl.fromName(authorization); + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + if (user != null && user.canCreate && !user.canAdmin) { + // personal create permissions, inject personal repository path + model.name = user.getPersonalPath() + "/"; + model.projectPath = user.getPersonalPath(); + model.owner = user.username; + // personal repositories are private by default + model.accessRestriction = AccessRestrictionType.VIEW; + model.authorizationControl = AuthorizationControl.NAMED; + } + setupPage(model); } @@ -103,8 +116,15 @@ public class EditRepositoryPage extends RootSubPage { List preReceiveScripts = new ArrayList(); List postReceiveScripts = new ArrayList(); + GitBlitWebSession session = GitBlitWebSession.get(); + final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser(); + if (isCreate) { - super.setupPage(getString("gb.newRepository"), ""); + if (user.canAdmin) { + super.setupPage(getString("gb.newRepository"), ""); + } else { + super.setupPage(getString("gb.newRepository"), user.getDisplayName()); + } } else { super.setupPage(getString("gb.edit"), repositoryModel.name); if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { @@ -195,11 +215,14 @@ public class EditRepositoryPage extends RootSubPage { protected void onSubmit() { try { // confirm a repository name was entered - if (StringUtils.isEmpty(repositoryModel.name)) { + if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) { error(getString("gb.pleaseSetRepositoryName")); return; } - + + // ensure name is trimmed + repositoryModel.name = repositoryModel.name.trim(); + // automatically convert backslashes to forward slashes repositoryModel.name = repositoryModel.name.replace('\\', '/'); // Automatically replace // with / @@ -229,6 +252,22 @@ public class EditRepositoryPage extends RootSubPage { c)); return; } + + if (user.canCreate && !user.canAdmin) { + // ensure repository name begins with the user's path + if (!repositoryModel.name.startsWith(user.getPersonalPath())) { + error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"), + user.getPersonalPath())); + return; + } + + if (repositoryModel.name.equals(user.getPersonalPath())) { + // reset path prefix and show error + repositoryModel.name = user.getPersonalPath() + "/"; + error(getString("gb.pleaseSetRepositoryName")); + return; + } + } // confirm access restriction selection if (repositoryModel.accessRestriction == null) { @@ -339,7 +378,7 @@ public class EditRepositoryPage extends RootSubPage { form.add(new SimpleAttributeModifier("autocomplete", "off")); // field names reflective match RepositoryModel fields - form.add(new TextField("name").setEnabled(isCreate || isAdmin)); + form.add(new TextField("name").setEnabled(isCreate || isAdmin || repositoryModel.isUsersPersonalRepository(user.username))); form.add(new TextField("description")); form.add(new DropDownChoice("owner", GitBlit.self().getAllUsernames()) .setEnabled(GitBlitWebSession.get().canAdmin())); @@ -435,8 +474,8 @@ public class EditRepositoryPage extends RootSubPage { } if (isCreate) { // Create Repository - if (!user.canAdmin) { - // Only Administrators May Create + if (!user.canCreate && !user.canAdmin) { + // Only administrators or permitted users may create error(getString("gb.errorOnlyAdminMayCreateRepository"), true); } } else { diff --git a/src/com/gitblit/wicket/pages/EditUserPage.html b/src/com/gitblit/wicket/pages/EditUserPage.html index 685eb64f..77932079 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.html +++ b/src/com/gitblit/wicket/pages/EditUserPage.html @@ -18,7 +18,8 @@ - + +

 


diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index 31f91c1c..49515fb9 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -232,6 +232,7 @@ public class EditUserPage extends RootSubPage { form.add(new TextField("emailAddress").setEnabled(editEmailAddress)); form.add(new CheckBox("canAdmin")); form.add(new CheckBox("canFork")); + form.add(new CheckBox("canCreate")); form.add(new CheckBox("excludeFromFederation")); form.add(repositories); form.add(teams.setEnabled(editTeams)); diff --git a/src/com/gitblit/wicket/pages/RepositoriesPage.java b/src/com/gitblit/wicket/pages/RepositoriesPage.java index 98dade67..36f2c6d5 100644 --- a/src/com/gitblit/wicket/pages/RepositoriesPage.java +++ b/src/com/gitblit/wicket/pages/RepositoriesPage.java @@ -82,7 +82,7 @@ public class RepositoriesPage extends RootPage { List repositories = getRepositories(params); RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", showAdmin, - repositories, true, getAccessRestrictions()); + true, repositories, true, getAccessRestrictions()); // push the panel down if we are hiding the admin controls and the // welcome message if (!showAdmin && !repositoriesMessage.isVisible()) { diff --git a/src/com/gitblit/wicket/pages/ReviewProposalPage.java b/src/com/gitblit/wicket/pages/ReviewProposalPage.java index df7b1bc1..e1813861 100644 --- a/src/com/gitblit/wicket/pages/ReviewProposalPage.java +++ b/src/com/gitblit/wicket/pages/ReviewProposalPage.java @@ -92,7 +92,7 @@ public class ReviewProposalPage extends RootSubPage { List repositories = new ArrayList( proposal.repositories.values()); RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false, - repositories, false, getAccessRestrictions()); + false, repositories, false, getAccessRestrictions()); add(repositoriesPanel); } diff --git a/src/com/gitblit/wicket/pages/SendProposalPage.java b/src/com/gitblit/wicket/pages/SendProposalPage.java index aa9c03a1..fc5f95b5 100644 --- a/src/com/gitblit/wicket/pages/SendProposalPage.java +++ b/src/com/gitblit/wicket/pages/SendProposalPage.java @@ -146,7 +146,7 @@ public class SendProposalPage extends RootSubPage { List repositories = new ArrayList( proposal.repositories.values()); RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false, - repositories, false, getAccessRestrictions()); + false, repositories, false, getAccessRestrictions()); add(repositoriesPanel); } } diff --git a/src/com/gitblit/wicket/pages/UserPage.html b/src/com/gitblit/wicket/pages/UserPage.html index 5886a3a2..c7131c09 100644 --- a/src/com/gitblit/wicket/pages/UserPage.html +++ b/src/com/gitblit/wicket/pages/UserPage.html @@ -18,6 +18,12 @@
+