From 092f0a62302e87f44403ba24fc519c65534dbfff Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 29 Oct 2012 23:22:54 -0400 Subject: [PATCH] Stabilizing and polishing permissions ui. Still in-progress. --- resources/gitblit.css | 6 + src/com/gitblit/Constants.java | 4 + src/com/gitblit/GitBlit.java | 51 +++++-- .../gitblit/client/EditRepositoryDialog.java | 63 ++++++++- src/com/gitblit/client/EditTeamDialog.java | 10 +- src/com/gitblit/client/EditUserDialog.java | 18 ++- src/com/gitblit/client/GitblitClient.java | 64 ++++++++- .../client/RegistrantPermissionsPanel.java | 56 +++++--- .../RegistrantPermissionsTableModel.java | 4 +- src/com/gitblit/client/UsersPanel.java | 17 +++ .../models/RegistrantAccessPermission.java | 36 +++-- src/com/gitblit/models/TeamModel.java | 10 +- src/com/gitblit/models/UserModel.java | 18 ++- .../gitblit/wicket/GitBlitWebApp.properties | 5 +- src/com/gitblit/wicket/pages/BasePage.java | 16 +++ .../wicket/pages/EditRepositoryPage.html | 7 +- .../wicket/pages/EditRepositoryPage.java | 125 +++++++++++++++--- .../gitblit/wicket/pages/EditTeamPage.java | 8 +- .../gitblit/wicket/pages/EditUserPage.java | 20 ++- src/com/gitblit/wicket/pages/RootSubPage.java | 19 ++- .../panels/RegistrantPermissionsPanel.html | 2 +- .../panels/RegistrantPermissionsPanel.java | 69 +++++++--- tests/com/gitblit/tests/RpcTests.java | 5 +- 23 files changed, 519 insertions(+), 114 deletions(-) diff --git a/resources/gitblit.css b/resources/gitblit.css index 5c2d92a8..e5363c85 100644 --- a/resources/gitblit.css +++ b/resources/gitblit.css @@ -188,6 +188,12 @@ div.even { vertical-align: middle; } +span.authorizationControl label { + display: inline; + color: #777; + padding:5px 0px 5px 10px; +} + div.page_footer { clear: both; height: 17px; diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index f74317ea..e7812ee3 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -386,6 +386,10 @@ public class Constants { REPOSITORY, USER, TEAM; } + public static enum PermissionType { + EXPLICIT, OWNER, REGEX; + } + public static enum GCStatus { READY, COLLECTING; diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 402f600d..6e587caa 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -79,6 +79,7 @@ import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationRequest; import com.gitblit.Constants.FederationStrategy; import com.gitblit.Constants.FederationToken; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.models.FederationModel; import com.gitblit.models.FederationProposal; @@ -670,14 +671,35 @@ public class GitBlit implements ServletContextListener { * @return a list of User-AccessPermission tuples */ public List getUserAccessPermissions(RepositoryModel repository) { - List permissions = new ArrayList(); + Set permissions = new LinkedHashSet(); + if (!StringUtils.isEmpty(repository.owner)) { + UserModel owner = userService.getUserModel(repository.owner); + if (owner != null) { + permissions.add(new RegistrantAccessPermission(owner.username, AccessPermission.REWIND, PermissionType.OWNER, RegistrantType.USER, false)); + } + } + if (repository.isPersonalRepository()) { + UserModel owner = userService.getUserModel(repository.projectPath.substring(1)); + if (owner != null) { + permissions.add(new RegistrantAccessPermission(owner.username, AccessPermission.REWIND, PermissionType.OWNER, RegistrantType.USER, false)); + } + } for (String user : userService.getUsernamesForRepositoryRole(repository.name)) { UserModel model = userService.getUserModel(user); AccessPermission ap = model.getRepositoryPermission(repository); - boolean isExplicit = model.hasExplicitRepositoryPermission(repository.name); - permissions.add(new RegistrantAccessPermission(user, ap, isExplicit, RegistrantType.USER)); - } - return permissions; + PermissionType pType = PermissionType.REGEX; + boolean editable = false; + if (repository.isOwner(model.username)) { + pType = PermissionType.OWNER; + } else if (repository.isUsersPersonalRepository(model.username)) { + pType = PermissionType.OWNER; + } else if (model.hasExplicitRepositoryPermission(repository.name)) { + pType = PermissionType.EXPLICIT; + editable = true; + } + permissions.add(new RegistrantAccessPermission(user, ap, pType, RegistrantType.USER, editable)); + } + return new ArrayList(permissions); } /** @@ -690,8 +712,8 @@ public class GitBlit implements ServletContextListener { public boolean setUserAccessPermissions(RepositoryModel repository, Collection permissions) { List users = new ArrayList(); for (RegistrantAccessPermission up : permissions) { - if (up.isExplicit) { - // only set explicitly defined permissions + if (up.isEditable) { + // only set editable defined permissions UserModel user = userService.getUserModel(up.registrant); user.setRepositoryPermission(repository.name, up.permission); users.add(user); @@ -811,8 +833,13 @@ public class GitBlit implements ServletContextListener { for (String team : userService.getTeamnamesForRepositoryRole(repository.name)) { TeamModel model = userService.getTeamModel(team); AccessPermission ap = model.getRepositoryPermission(repository); - boolean isExplicit = model.hasExplicitRepositoryPermission(repository.name); - permissions.add(new RegistrantAccessPermission(team, ap, isExplicit, RegistrantType.TEAM)); + PermissionType pType = PermissionType.REGEX; + boolean editable = false; + if (model.hasExplicitRepositoryPermission(repository.name)) { + pType = PermissionType.EXPLICIT; + editable = true; + } + permissions.add(new RegistrantAccessPermission(team, ap, pType, RegistrantType.TEAM, editable)); } return permissions; } @@ -827,7 +854,7 @@ public class GitBlit implements ServletContextListener { public boolean setTeamAccessPermissions(RepositoryModel repository, Collection permissions) { List teams = new ArrayList(); for (RegistrantAccessPermission tp : permissions) { - if (tp.isExplicit) { + if (tp.isEditable) { // only set explicitly defined access permissions TeamModel team = userService.getTeamModel(tp.registrant); team.setRepositoryPermission(repository.name, tp.permission); @@ -1870,7 +1897,9 @@ public class GitBlit implements ServletContextListener { config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFederated", repository.isFederated); config.setString(Constants.CONFIG_GITBLIT, null, "gcThreshold", repository.gcThreshold); config.setString(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod); - config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC)); + if (repository.lastGC != null) { + config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC)); + } updateList(config, "federationSets", repository.federationSets); updateList(config, "preReceiveScript", repository.preReceiveScripts); diff --git a/src/com/gitblit/client/EditRepositoryDialog.java b/src/com/gitblit/client/EditRepositoryDialog.java index 0adf8a80..06621c21 100644 --- a/src/com/gitblit/client/EditRepositoryDialog.java +++ b/src/com/gitblit/client/EditRepositoryDialog.java @@ -24,6 +24,8 @@ import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.text.MessageFormat; import java.util.ArrayList; @@ -37,6 +39,7 @@ import java.util.Set; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListCellRenderer; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -59,6 +62,7 @@ import javax.swing.ScrollPaneConstants; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationStrategy; +import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; import com.gitblit.utils.ArrayUtils; @@ -218,13 +222,41 @@ public class EditRepositoryDialog extends JDialog { accessRestriction = new JComboBox(AccessRestrictionType.values()); accessRestriction.setRenderer(new AccessRestrictionRenderer()); accessRestriction.setSelectedItem(anRepository.accessRestriction); + accessRestriction.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + AccessRestrictionType art = (AccessRestrictionType) accessRestriction.getSelectedItem(); + EditRepositoryDialog.this.setupAccessPermissions(art); + } + } + }); boolean authenticated = anRepository.authorizationControl != null && AuthorizationControl.AUTHENTICATED.equals(anRepository.authorizationControl); allowAuthenticated = new JRadioButton(Translation.get("gb.allowAuthenticatedDescription")); allowAuthenticated.setSelected(authenticated); + allowAuthenticated.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + usersPalette.setEnabled(false); + teamsPalette.setEnabled(false); + } + } + }); + allowNamed = new JRadioButton(Translation.get("gb.allowNamedDescription")); allowNamed.setSelected(!authenticated); + allowNamed.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + usersPalette.setEnabled(true); + teamsPalette.setEnabled(true); + } + } + }); ButtonGroup group = new ButtonGroup(); group.add(allowAuthenticated); @@ -281,7 +313,7 @@ public class EditRepositoryDialog extends JDialog { clonePushPanel .add(newFieldPanel(Translation.get("gb.verifyCommitter"), verifyCommitter)); - usersPalette = new RegistrantPermissionsPanel(); + usersPalette = new RegistrantPermissionsPanel(RegistrantType.USER); JPanel northAccessPanel = new JPanel(new BorderLayout(5, 5)); northAccessPanel.add(newFieldPanel(Translation.get("gb.accessRestriction"), accessRestriction), BorderLayout.NORTH); @@ -294,7 +326,7 @@ public class EditRepositoryDialog extends JDialog { accessPanel.add(newFieldPanel(Translation.get("gb.userPermissions"), usersPalette), BorderLayout.CENTER); - teamsPalette = new RegistrantPermissionsPanel(); + teamsPalette = new RegistrantPermissionsPanel(RegistrantType.TEAM); JPanel teamsPanel = new JPanel(new BorderLayout(5, 5)); teamsPanel.add( newFieldPanel(Translation.get("gb.teamPermissions"), @@ -349,6 +381,8 @@ public class EditRepositoryDialog extends JDialog { panel.addTab(Translation.get("gb.customFields"), customFieldsScrollPane); + setupAccessPermissions(anRepository.accessRestriction); + JButton createButton = new JButton(Translation.get("gb.save")); createButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { @@ -403,6 +437,25 @@ public class EditRepositoryDialog extends JDialog { panel.add(comp); return panel; } + + private void setupAccessPermissions(AccessRestrictionType art) { + if (AccessRestrictionType.NONE.equals(art)) { + usersPalette.setEnabled(false); + teamsPalette.setEnabled(false); + + allowAuthenticated.setEnabled(false); + allowNamed.setEnabled(false); + } else { + allowAuthenticated.setEnabled(true); + allowNamed.setEnabled(true); + + if (allowNamed.isSelected()) { + usersPalette.setEnabled(true); + teamsPalette.setEnabled(true); + } + } + + } private boolean validateFields() { String rname = nameField.getText(); @@ -538,6 +591,7 @@ public class EditRepositoryDialog extends JDialog { public void setAccessRestriction(AccessRestrictionType restriction) { this.accessRestriction.setSelectedItem(restriction); + setupAccessPermissions(restriction); } public void setAuthorizationControl(AuthorizationControl authorization) { @@ -659,14 +713,15 @@ public class EditRepositoryDialog extends JDialog { * restriction. * */ - private class AccessRestrictionRenderer extends JLabel implements - ListCellRenderer { + private class AccessRestrictionRenderer extends DefaultListCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof AccessRestrictionType) { AccessRestrictionType restriction = (AccessRestrictionType) value; switch (restriction) { diff --git a/src/com/gitblit/client/EditTeamDialog.java b/src/com/gitblit/client/EditTeamDialog.java index 4350310e..4d7af261 100644 --- a/src/com/gitblit/client/EditTeamDialog.java +++ b/src/com/gitblit/client/EditTeamDialog.java @@ -45,11 +45,12 @@ import javax.swing.JTextField; import javax.swing.KeyStroke; import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; import com.gitblit.models.ServerSettings; import com.gitblit.models.TeamModel; -import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; public class EditTeamDialog extends JDialog { @@ -140,7 +141,7 @@ public class EditTeamDialog extends JDialog { fieldsPanel.add(newFieldPanel(Translation.get("gb.mailingLists"), mailingListsField)); final Insets _insets = new Insets(5, 5, 5, 5); - repositoryPalette = new RegistrantPermissionsPanel(); + repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY); userPalette = new JPalette(); userPalette.setEnabled(settings.supportsTeamMembershipChanges); @@ -311,9 +312,10 @@ public class EditTeamDialog extends JDialog { public void setRepositories(List repositories, List permissions) { List restricted = new ArrayList(); for (RepositoryModel repo : repositories) { - if (repo.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + if (repo.accessRestriction.exceeds(AccessRestrictionType.NONE) + && repo.authorizationControl.equals(AuthorizationControl.NAMED)) { restricted.add(repo.name); - } + } } StringUtils.sortRepositorynames(restricted); diff --git a/src/com/gitblit/client/EditUserDialog.java b/src/com/gitblit/client/EditUserDialog.java index e0966933..070926dd 100644 --- a/src/com/gitblit/client/EditUserDialog.java +++ b/src/com/gitblit/client/EditUserDialog.java @@ -46,6 +46,8 @@ import javax.swing.JTextField; import javax.swing.KeyStroke; import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.RegistrantType; import com.gitblit.Keys; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; @@ -158,7 +160,7 @@ public class EditUserDialog extends JDialog { notFederatedCheckbox)); final Insets _insets = new Insets(5, 5, 5, 5); - repositoryPalette = new RegistrantPermissionsPanel(); + repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY); teamsPalette = new JPalette(); teamsPalette.setEnabled(settings.supportsTeamMembershipChanges); @@ -343,8 +345,12 @@ public class EditUserDialog extends JDialog { public void setRepositories(List repositories, List permissions) { List restricted = new ArrayList(); for (RepositoryModel repo : repositories) { - if (repo.accessRestriction.exceeds(AccessRestrictionType.NONE)) { - restricted.add(repo.name); + // exclude Owner or personal repositories + if (!repo.isOwner(username) && !repo.isUsersPersonalRepository(username)) { + if (repo.accessRestriction.exceeds(AccessRestrictionType.NONE) + && repo.authorizationControl.equals(AuthorizationControl.NAMED)) { + restricted.add(repo.name); + } } } StringUtils.sortRepositorynames(restricted); @@ -356,15 +362,15 @@ public class EditUserDialog extends JDialog { list.add("[^~].*"); String lastProject = null; for (String repo : restricted) { - String projectPath = StringUtils.getFirstPathElement(repo); + String projectPath = StringUtils.getFirstPathElement(repo).toLowerCase(); if (lastProject == null || !lastProject.equalsIgnoreCase(projectPath)) { lastProject = projectPath; if (!StringUtils.isEmpty(projectPath)) { // regex for all repositories within a project list.add(projectPath + "/.*"); } - list.add(repo); } + list.add(repo); } // remove repositories for which user already has a permission @@ -372,7 +378,7 @@ public class EditUserDialog extends JDialog { permissions = new ArrayList(); } else { for (RegistrantAccessPermission rp : permissions) { - list.remove(rp.registrant); + list.remove(rp.registrant.toLowerCase()); } } repositoryPalette.setObjects(list, permissions); diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java index 4620fefa..b7047d7f 100644 --- a/src/com/gitblit/client/GitblitClient.java +++ b/src/com/gitblit/client/GitblitClient.java @@ -31,6 +31,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlitException.ForbiddenException; import com.gitblit.GitBlitException.NotAllowedException; @@ -340,6 +341,7 @@ public class GitblitClient implements Serializable { List users = RpcUtils.getUsers(url, account, password); allUsers.clear(); allUsers.addAll(users); + Collections.sort(users); return allUsers; } @@ -347,6 +349,7 @@ public class GitblitClient implements Serializable { List teams = RpcUtils.getTeams(url, account, password); allTeams.clear(); allTeams.addAll(teams); + Collections.sort(teams); return allTeams; } @@ -475,6 +478,15 @@ public class GitblitClient implements Serializable { public List getUsers() { return allUsers; } + + public UserModel getUser(String username) { + for (UserModel user : getUsers()) { + if (user.username.equalsIgnoreCase(username)) { + return user; + } + } + return null; + } public List getUsernames() { List usernames = new ArrayList(); @@ -496,15 +508,38 @@ public class GitblitClient implements Serializable { } public List getUserAccessPermissions(RepositoryModel repository) { - List list = new ArrayList(); - for (UserModel user : allUsers) { + Set list = new LinkedHashSet(); + if (!StringUtils.isEmpty(repository.owner)) { + UserModel owner = getUser(repository.owner); + if (owner != null) { + list.add(new RegistrantAccessPermission(owner.username, AccessPermission.REWIND, PermissionType.OWNER, RegistrantType.USER, false)); + } + } + if (repository.isPersonalRepository()) { + UserModel owner = getUser(repository.projectPath.substring(1)); + if (owner != null) { + list.add(new RegistrantAccessPermission(owner.username, AccessPermission.REWIND, PermissionType.OWNER, RegistrantType.USER, false)); + } + } + for (UserModel user : getUsers()) { if (user.hasRepositoryPermission(repository.name)) { AccessPermission ap = user.getRepositoryPermission(repository); - boolean isExplicit = user.hasExplicitRepositoryPermission(repository.name); - list.add(new RegistrantAccessPermission(user.username, ap, isExplicit, RegistrantType.USER)); + PermissionType pType = PermissionType.REGEX; + boolean editable = false; + if (repository.isOwner(user.username)) { + pType = PermissionType.OWNER; + } else if (repository.isUsersPersonalRepository(user.username)) { + pType = PermissionType.OWNER; + } else if (user.hasExplicitRepositoryPermission(repository.name)) { + pType = PermissionType.EXPLICIT; + editable = true; + } + list.add(new RegistrantAccessPermission(user.username, ap, pType, RegistrantType.USER, editable)); } } - return list; + List raps = new ArrayList(list); + Collections.sort(raps); + return raps; } public boolean setUserAccessPermissions(RepositoryModel repository, List permissions) throws IOException { @@ -539,10 +574,16 @@ public class GitblitClient implements Serializable { for (TeamModel team : allTeams) { if (team.hasRepositoryPermission(repository.name)) { AccessPermission ap = team.getRepositoryPermission(repository); - boolean isExplicit = team.hasExplicitRepositoryPermission(repository.name); - list.add(new RegistrantAccessPermission(team.name, ap, isExplicit, RegistrantType.TEAM)); + PermissionType pType = PermissionType.REGEX; + boolean editable = false; + if (team.hasExplicitRepositoryPermission(repository.name)) { + pType = PermissionType.EXPLICIT; + editable = true; + } + list.add(new RegistrantAccessPermission(team.name, ap, pType, RegistrantType.TEAM, editable)); } } + Collections.sort(list); return list; } @@ -566,6 +607,15 @@ public class GitblitClient implements Serializable { public List getRepositories() { return allRepositories; } + + public RepositoryModel getRepository(String name) { + for (RepositoryModel repository : allRepositories) { + if (repository.name.equalsIgnoreCase(name)) { + return repository; + } + } + return null; + } public boolean createRepository(RepositoryModel repository, List userPermissions) throws IOException { diff --git a/src/com/gitblit/client/RegistrantPermissionsPanel.java b/src/com/gitblit/client/RegistrantPermissionsPanel.java index 4ea173fc..b8ab9399 100644 --- a/src/com/gitblit/client/RegistrantPermissionsPanel.java +++ b/src/com/gitblit/client/RegistrantPermissionsPanel.java @@ -33,7 +33,10 @@ import javax.swing.SwingConstants; import javax.swing.table.DefaultTableCellRenderer; import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; +import com.gitblit.utils.StringUtils; public class RegistrantPermissionsPanel extends JPanel { @@ -53,16 +56,19 @@ public class RegistrantPermissionsPanel extends JPanel { private JPanel addPanel; - public RegistrantPermissionsPanel() { + public RegistrantPermissionsPanel(final RegistrantType registrantType) { super(new BorderLayout(5, 5)); tableModel = new RegistrantPermissionsTableModel(); - permissionsTable = new JTable(tableModel); + permissionsTable = Utils.newTable(tableModel, Utils.DATE_FORMAT); + permissionsTable.setModel(tableModel); permissionsTable.setPreferredScrollableViewportSize(new Dimension(400, 150)); JScrollPane jsp = new JScrollPane(permissionsTable); add(jsp, BorderLayout.CENTER); + permissionsTable.getColumnModel().getColumn(RegistrantPermissionsTableModel.Columns.Registrant.ordinal()) + .setCellRenderer(new NameRenderer()); permissionsTable.getColumnModel().getColumn(RegistrantPermissionsTableModel.Columns.Type.ordinal()) - .setCellRenderer(new RegexRenderer()); + .setCellRenderer(new PermissionTypeRenderer()); permissionsTable.getColumnModel().getColumn(RegistrantPermissionsTableModel.Columns.Permission.ordinal()) .setCellEditor(new AccessPermissionEditor()); @@ -79,9 +85,15 @@ public class RegistrantPermissionsPanel extends JPanel { return; } - RegistrantAccessPermission rp = new RegistrantAccessPermission(); + RegistrantAccessPermission rp = new RegistrantAccessPermission(registrantType); rp.registrant = registrantSelector.getSelectedItem().toString(); rp.permission = (AccessPermission) permissionSelector.getSelectedItem(); + if (StringUtils.findInvalidCharacter(rp.registrant) != null) { + rp.permissionType = PermissionType.REGEX; + } else { + rp.permissionType = PermissionType.EXPLICIT; + } + tableModel.permissions.add(rp); registrantModel.removeElement(rp.registrant); @@ -103,7 +115,10 @@ public class RegistrantPermissionsPanel extends JPanel { @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); - permissionsTable.setEnabled(false); + permissionsTable.setEnabled(enabled); + registrantSelector.setEnabled(enabled); + permissionSelector.setEnabled(enabled); + addButton.setEnabled(enabled); } public void setObjects(List registrants, List permissions) { @@ -117,7 +132,11 @@ public class RegistrantPermissionsPanel extends JPanel { permissions = new ArrayList(); } for (RegistrantAccessPermission rp : permissions) { - filtered.remove(rp.registrant); + if (rp.isEditable) { + // only remove editable duplicates + // this allows for specifying an explicit permission + filtered.remove(rp.registrant); + } } for (String registrant : filtered) { registrantModel.addElement(registrant); @@ -138,30 +157,35 @@ public class RegistrantPermissionsPanel extends JPanel { private static final long serialVersionUID = 1L; public AccessPermissionEditor() { - super(new JComboBox(AccessPermission.values())); + super(new JComboBox(AccessPermission.values())); } } - private class RegexRenderer extends DefaultTableCellRenderer { + private class PermissionTypeRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; - public RegexRenderer() { + public PermissionTypeRenderer() { super(); setHorizontalAlignment(SwingConstants.CENTER); } @Override protected void setValue(Object value) { - boolean isExplicit = (Boolean) value; - if (isExplicit) { - // explicit permission - setText(""); - setToolTipText(null); - } else { - // regex matched permission + PermissionType pType = (PermissionType) value; + switch (pType) { + case OWNER: + setText("owner"); + setToolTipText(Translation.get("gb.ownerPermission")); + break; + case REGEX: setText("regex"); setToolTipText(Translation.get("gb.regexPermission")); + break; + default: + setText(""); + setToolTipText(null); + break; } } } diff --git a/src/com/gitblit/client/RegistrantPermissionsTableModel.java b/src/com/gitblit/client/RegistrantPermissionsTableModel.java index fcd9c8b4..9ed8db4a 100644 --- a/src/com/gitblit/client/RegistrantPermissionsTableModel.java +++ b/src/com/gitblit/client/RegistrantPermissionsTableModel.java @@ -104,7 +104,7 @@ public class RegistrantPermissionsTableModel extends AbstractTableModel { // and therefore can not be directly manipulated unless the current // object is the source of the regex (i.e. a user or team with explicit // regex definition) - return permissions.get(rowIndex).isExplicit; + return permissions.get(rowIndex).isEditable; } return false; } @@ -117,7 +117,7 @@ public class RegistrantPermissionsTableModel extends AbstractTableModel { case Registrant: return rp.registrant; case Type: - return rp.isExplicit; + return rp.permissionType; case Permission: return rp.permission; } diff --git a/src/com/gitblit/client/UsersPanel.java b/src/com/gitblit/client/UsersPanel.java index 9fcad7bc..cd571b26 100644 --- a/src/com/gitblit/client/UsersPanel.java +++ b/src/com/gitblit/client/UsersPanel.java @@ -40,7 +40,9 @@ import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableRowSorter; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RpcRequest; +import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; @@ -309,6 +311,21 @@ public abstract class UsersPanel extends JPanel { gitblit.getSettings()); dialog.setLocationRelativeTo(UsersPanel.this); dialog.setUsers(gitblit.getUsers()); + + List permissions = user.getRepositoryPermissions(); + for (RegistrantAccessPermission permission : permissions) { + if (permission.isEditable && PermissionType.EXPLICIT.equals(permission.permissionType)) { + // Ensure this is NOT an owner permission - which is non-editable + // We don't know this from within the usermodel, ownership is a + // property of a repository. + boolean isOwner = gitblit.getRepository(permission.registrant).isOwner(user.username); + if (isOwner) { + permission.permissionType = PermissionType.OWNER; + permission.isEditable = false; + } + } + } + dialog.setRepositories(gitblit.getRepositories(), user.getRepositoryPermissions()); dialog.setTeams(gitblit.getTeams(), user.teams == null ? null : new ArrayList( user.teams)); diff --git a/src/com/gitblit/models/RegistrantAccessPermission.java b/src/com/gitblit/models/RegistrantAccessPermission.java index 4a560d43..7346d310 100644 --- a/src/com/gitblit/models/RegistrantAccessPermission.java +++ b/src/com/gitblit/models/RegistrantAccessPermission.java @@ -18,6 +18,7 @@ package com.gitblit.models; import java.io.Serializable; import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.utils.StringUtils; @@ -32,23 +33,27 @@ public class RegistrantAccessPermission implements Serializable, Comparable { public List getRepositoryPermissions() { List list = new ArrayList(); for (Map.Entry entry : permissions.entrySet()) { - list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), true, RegistrantType.REPOSITORY)); + String registrant = entry.getKey(); + boolean editable = true; + PermissionType pType = PermissionType.EXPLICIT; + if (StringUtils.findInvalidCharacter(registrant) != null) { + // a regex will have at least 1 invalid character + pType = PermissionType.REGEX; + } + list.add(new RegistrantAccessPermission(registrant, entry.getValue(), pType, RegistrantType.REPOSITORY, editable)); } Collections.sort(list); return list; diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index d7bc2935..22f250cc 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -28,6 +28,7 @@ import java.util.Set; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.Constants.Unused; import com.gitblit.utils.ArrayUtils; @@ -137,7 +138,17 @@ public class UserModel implements Principal, Serializable, Comparable public List getRepositoryPermissions() { List list = new ArrayList(); for (Map.Entry entry : permissions.entrySet()) { - list.add(new RegistrantAccessPermission(entry.getKey(), entry.getValue(), true, RegistrantType.REPOSITORY)); + String registrant = entry.getKey(); + boolean editable = true; + PermissionType pType = PermissionType.EXPLICIT; + if (isMyPersonalRepository(registrant)) { + pType = PermissionType.OWNER; + editable = false; + } else if (StringUtils.findInvalidCharacter(registrant) != null) { + // a regex will have at least 1 invalid character + pType = PermissionType.REGEX; + } + list.add(new RegistrantAccessPermission(registrant, entry.getValue(), pType, RegistrantType.REPOSITORY, editable)); } Collections.sort(list); return list; @@ -494,4 +505,9 @@ public class UserModel implements Principal, Serializable, Comparable // Default UserModel doesn't implement branch-level security. Other Realms (i.e. Gerrit) may override this method. return hasRepositoryPermission(repositoryName); } + + public boolean isMyPersonalRepository(String repository) { + String projectPath = StringUtils.getFirstPathElement(repository); + return !StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase("~" + username); + } } diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index 62e4817f..c6ceb9fd 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -311,8 +311,8 @@ gb.duration.months = {0} months gb.duration.oneYear = 1 year gb.duration.years = {0} years gb.authorizationControl = authorization control -gb.allowAuthenticatedDescription = grant restricted access to all authenticated users -gb.allowNamedDescription = grant restricted access to named users or teams +gb.allowAuthenticatedDescription = grant RW+ permission to all authenticated users +gb.allowNamedDescription = grant fine-grained permissions to named users or teams gb.markdownFailure = Failed to parse Markdown content! gb.clearCache = clear cache gb.projects = projects @@ -364,3 +364,4 @@ gb.gcPeriod = GC period gb.gcPeriodDescription = duration between garbage collections gb.gcThreshold = GC threshold gb.gcThresholdDescription = minimum total size of loose objects to trigger early garbage collection +gb.ownerPermission = repository owner \ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/BasePage.java b/src/com/gitblit/wicket/pages/BasePage.java index dcca3619..ceeb9120 100644 --- a/src/com/gitblit/wicket/pages/BasePage.java +++ b/src/com/gitblit/wicket/pages/BasePage.java @@ -55,6 +55,7 @@ import org.slf4j.LoggerFactory; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit; import com.gitblit.Keys; @@ -255,6 +256,21 @@ public abstract class BasePage extends WebPage { } return map; } + + protected Map getAuthorizationControls() { + Map map = new LinkedHashMap(); + for (AuthorizationControl type : AuthorizationControl.values()) { + switch (type) { + case AUTHENTICATED: + map.put(type, getString("gb.allowAuthenticatedDescription")); + break; + case NAMED: + map.put(type, getString("gb.allowNamedDescription")); + break; + } + } + return map; + } protected TimeZone getTimeZone() { return GitBlit.getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get() diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html index 7bd896cf..638eae90 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -49,12 +49,7 @@   - - - +
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index 1a2e63ce..58fdf66b 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -27,6 +27,9 @@ import java.util.Map; import java.util.Set; import org.apache.wicket.PageParameters; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.behavior.SimpleAttributeModifier; import org.apache.wicket.extensions.markup.html.form.palette.Palette; import org.apache.wicket.markup.html.WebMarkupContainer; @@ -36,8 +39,7 @@ import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.IChoiceRenderer; -import org.apache.wicket.markup.html.form.Radio; -import org.apache.wicket.markup.html.form.RadioGroup; +import org.apache.wicket.markup.html.form.RadioChoice; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; @@ -51,6 +53,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.FederationStrategy; +import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlit; import com.gitblit.GitBlitException; import com.gitblit.Keys; @@ -70,6 +73,8 @@ public class EditRepositoryPage extends RootSubPage { private final boolean isCreate; private boolean isAdmin; + + RepositoryModel repositoryModel; private IModel mailingLists; @@ -97,6 +102,7 @@ public class EditRepositoryPage extends RootSubPage { setupPage(model); setStatelessHint(false); + setOutputMarkupId(true); } public EditRepositoryPage(PageParameters params) { @@ -107,9 +113,12 @@ public class EditRepositoryPage extends RootSubPage { RepositoryModel model = GitBlit.self().getRepositoryModel(name); setupPage(model); setStatelessHint(false); + setOutputMarkupId(true); } - protected void setupPage(final RepositoryModel repositoryModel) { + protected void setupPage(RepositoryModel model) { + this.repositoryModel = model; + // ensure this user can create or edit this repository checkPermissions(repositoryModel); @@ -145,10 +154,10 @@ public class EditRepositoryPage extends RootSubPage { final String oldName = repositoryModel.name; - RegistrantPermissionsPanel usersPalette = new RegistrantPermissionsPanel("users", - GitBlit.self().getAllUsernames(), repositoryUsers, getAccessPermissions()); - RegistrantPermissionsPanel teamsPalette = new RegistrantPermissionsPanel("teams", - GitBlit.self().getAllTeamnames(), repositoryTeams, getAccessPermissions()); + final RegistrantPermissionsPanel usersPalette = new RegistrantPermissionsPanel("users", + RegistrantType.USER, GitBlit.self().getAllUsernames(), repositoryUsers, getAccessPermissions()); + final RegistrantPermissionsPanel teamsPalette = new RegistrantPermissionsPanel("teams", + RegistrantType.TEAM, GitBlit.self().getAllTeamnames(), repositoryTeams, getAccessPermissions()); // indexed local branches palette List allLocalBranches = new ArrayList(); @@ -206,9 +215,9 @@ public class EditRepositoryPage extends RootSubPage { }; customFieldsListView.setReuseItems(true); - CompoundPropertyModel model = new CompoundPropertyModel( + CompoundPropertyModel rModel = new CompoundPropertyModel( repositoryModel); - Form form = new Form("editForm", model) { + Form form = new Form("editForm", rModel) { private static final long serialVersionUID = 1L; @@ -366,8 +375,9 @@ public class EditRepositoryPage extends RootSubPage { form.add(new DropDownChoice("owner", GitBlit.self().getAllUsernames()) .setEnabled(GitBlitWebSession.get().canAdmin())); form.add(new CheckBox("allowForks")); - form.add(new DropDownChoice("accessRestriction", Arrays - .asList(AccessRestrictionType.values()), new AccessRestrictionRenderer())); + DropDownChoice accessRestriction = new DropDownChoice("accessRestriction", Arrays + .asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()); + form.add(accessRestriction); form.add(new CheckBox("isFrozen")); // TODO enable origin definition form.add(new TextField("origin").setEnabled(false/* isCreate */)); @@ -403,12 +413,10 @@ public class EditRepositoryPage extends RootSubPage { form.add(new TextField("mailingLists", mailingLists)); form.add(indexedBranchesPalette); - RadioGroup group = new RadioGroup("authorizationControl"); - Radio allowAuthenticated = new Radio("allowAuthenticated", new Model(AuthorizationControl.AUTHENTICATED)); - Radio allowNamed = new Radio("allowNamed", new Model(AuthorizationControl.NAMED)); - group.add(allowAuthenticated); - group.add(allowNamed); - form.add(group); + List acList = Arrays.asList(AuthorizationControl.values()); + final RadioChoice authorizationControl = new RadioChoice( + "authorizationControl", acList, new AuthorizationControlRenderer()); + form.add(authorizationControl); form.add(new CheckBox("verifyCommitter")); @@ -425,7 +433,69 @@ public class EditRepositoryPage extends RootSubPage { WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection"); customFieldsSection.add(customFieldsListView); form.add(customFieldsSection.setVisible(!GitBlit.getString(Keys.groovy.customFields, "").isEmpty())); + + // initial enable/disable of permission controls + if (repositoryModel.accessRestriction.equals(AccessRestrictionType.NONE)) { + // anonymous everything, disable all controls + usersPalette.setEnabled(false); + teamsPalette.setEnabled(false); + authorizationControl.setEnabled(false); + } else { + // authenticated something + // enable authorization controls + authorizationControl.setEnabled(true); + + boolean allowFineGrainedControls = repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); + usersPalette.setEnabled(allowFineGrainedControls); + teamsPalette.setEnabled(allowFineGrainedControls); + } + + accessRestriction.add(new AjaxFormComponentUpdatingBehavior("onchange") { + + private static final long serialVersionUID = 1L; + + protected void onUpdate(AjaxRequestTarget target) { + // enable/disable permissions panel based on access restriction + boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE); + authorizationControl.setEnabled(allowAuthorizationControl); + + boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); + usersPalette.setEnabled(allowFineGrainedControls); + teamsPalette.setEnabled(allowFineGrainedControls); + + if (allowFineGrainedControls) { + repositoryModel.authorizationControl = AuthorizationControl.NAMED; + } + + target.addComponent(authorizationControl); + target.addComponent(usersPalette); + target.addComponent(teamsPalette); + } + }); + + authorizationControl.add(new AjaxFormChoiceComponentUpdatingBehavior() { + + private static final long serialVersionUID = 1L; + protected void onUpdate(AjaxRequestTarget target) { + // enable/disable permissions panel based on access restriction + boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE); + authorizationControl.setEnabled(allowAuthorizationControl); + + boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); + usersPalette.setEnabled(allowFineGrainedControls); + teamsPalette.setEnabled(allowFineGrainedControls); + + if (allowFineGrainedControls) { + repositoryModel.authorizationControl = AuthorizationControl.NAMED; + } + + target.addComponent(authorizationControl); + target.addComponent(usersPalette); + target.addComponent(teamsPalette); + } + }); + form.add(new Button("save")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; @@ -528,4 +598,25 @@ public class EditRepositoryPage extends RootSubPage { return Integer.toString(index); } } + + private class AuthorizationControlRenderer implements IChoiceRenderer { + + private static final long serialVersionUID = 1L; + + private final Map map; + + public AuthorizationControlRenderer() { + map = getAuthorizationControls(); + } + + @Override + public String getDisplayValue(AuthorizationControl type) { + return map.get(type); + } + + @Override + public String getIdValue(AuthorizationControl type, int index) { + return Integer.toString(index); + } + } } diff --git a/src/com/gitblit/wicket/pages/EditTeamPage.java b/src/com/gitblit/wicket/pages/EditTeamPage.java index 8908676e..8ced03c2 100644 --- a/src/com/gitblit/wicket/pages/EditTeamPage.java +++ b/src/com/gitblit/wicket/pages/EditTeamPage.java @@ -38,6 +38,7 @@ import org.apache.wicket.model.util.ListModel; import com.gitblit.GitBlit; import com.gitblit.GitBlitException; +import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.utils.StringUtils; @@ -60,6 +61,7 @@ public class EditTeamPage extends RootSubPage { isCreate = true; setupPage(new TeamModel("")); setStatelessHint(false); + setOutputMarkupId(true); } public EditTeamPage(PageParameters params) { @@ -70,6 +72,7 @@ public class EditTeamPage extends RootSubPage { TeamModel model = GitBlit.self().getTeamModel(name); setupPage(model); setStatelessHint(false); + setOutputMarkupId(true); } protected void setupPage(final TeamModel teamModel) { @@ -81,7 +84,7 @@ public class EditTeamPage extends RootSubPage { CompoundPropertyModel model = new CompoundPropertyModel(teamModel); - List repos = getAccessRestrictedRepositoryList(true); + List repos = getAccessRestrictedRepositoryList(true, null); List teamUsers = new ArrayList(teamModel.users); Collections.sort(teamUsers); @@ -215,7 +218,8 @@ public class EditTeamPage extends RootSubPage { : StringUtils.flattenStrings(teamModel.mailingLists, " ")); form.add(new TextField("mailingLists", mailingLists)); - form.add(new RegistrantPermissionsPanel("repositories", repos, permissions, getAccessPermissions())); + form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, + repos, permissions, getAccessPermissions())); form.add(preReceivePalette); form.add(new BulletListPanel("inheritedPreReceive", "inherited", GitBlit.self() .getPreReceiveScriptsInherited(null))); diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index a165305d..19d297b1 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -37,6 +37,8 @@ import org.apache.wicket.model.util.ListModel; import com.gitblit.GitBlit; import com.gitblit.GitBlitException; import com.gitblit.Keys; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; @@ -61,6 +63,7 @@ public class EditUserPage extends RootSubPage { isCreate = true; setupPage(new UserModel("")); setStatelessHint(false); + setOutputMarkupId(true); } public EditUserPage(PageParameters params) { @@ -71,6 +74,7 @@ public class EditUserPage extends RootSubPage { UserModel model = GitBlit.self().getUserModel(name); setupPage(model); setStatelessHint(false); + setOutputMarkupId(true); } protected void setupPage(final UserModel userModel) { @@ -85,7 +89,7 @@ public class EditUserPage extends RootSubPage { CompoundPropertyModel model = new CompoundPropertyModel(userModel); // build list of projects including all repositories wildcards - List repos = getAccessRestrictedRepositoryList(true); + List repos = getAccessRestrictedRepositoryList(true, userModel); List userTeams = new ArrayList(); for (TeamModel team : userModel.teams) { @@ -95,6 +99,18 @@ public class EditUserPage extends RootSubPage { final String oldName = userModel.username; final List permissions = userModel.getRepositoryPermissions(); + for (RegistrantAccessPermission permission : permissions) { + if (permission.isEditable && PermissionType.EXPLICIT.equals(permission.permissionType)) { + // Ensure this is NOT an owner permission - which is non-editable + // We don't know this from within the usermodel, ownership is a + // property of a repository. + boolean isOwner = GitBlit.self().getRepositoryModel(permission.registrant).isOwner(oldName); + if (isOwner) { + permission.permissionType = PermissionType.OWNER; + permission.isEditable = false; + } + } + } final Palette teams = new Palette("teams", new ListModel( new ArrayList(userTeams)), new CollectionModel(GitBlit.self() @@ -228,7 +244,7 @@ public class EditUserPage extends RootSubPage { form.add(new CheckBox("canFork")); form.add(new CheckBox("canCreate")); form.add(new CheckBox("excludeFromFederation")); - form.add(new RegistrantPermissionsPanel("repositories", repos, permissions, getAccessPermissions())); + form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions())); form.add(teams.setEnabled(editTeams)); form.add(new Button("save")); diff --git a/src/com/gitblit/wicket/pages/RootSubPage.java b/src/com/gitblit/wicket/pages/RootSubPage.java index 30d296ed..891c892a 100644 --- a/src/com/gitblit/wicket/pages/RootSubPage.java +++ b/src/com/gitblit/wicket/pages/RootSubPage.java @@ -21,9 +21,11 @@ import java.util.List; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; -import com.gitblit.GitBlit; import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.GitBlit; import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; /** @@ -52,7 +54,7 @@ public abstract class RootSubPage extends RootPage { super.setupPage("", pageName); } - protected List getAccessRestrictedRepositoryList(boolean includeWildcards) { + protected List getAccessRestrictedRepositoryList(boolean includeWildcards, UserModel user) { // build list of access-restricted projects String lastProject = null; List repos = new ArrayList(); @@ -62,19 +64,26 @@ public abstract class RootSubPage extends RootPage { // all repositories excluding personal repositories repos.add("[^~].*"); } + for (String repo : GitBlit.self().getRepositoryList()) { RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo); - if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE) + && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED)) { + if (user != null && + (repositoryModel.isOwner(user.username) || repositoryModel.isUsersPersonalRepository(user.username))) { + // exclude Owner or personal repositories + continue; + } if (includeWildcards) { if (lastProject == null || !lastProject.equalsIgnoreCase(repositoryModel.projectPath)) { - lastProject = repositoryModel.projectPath; + lastProject = repositoryModel.projectPath.toLowerCase(); if (!StringUtils.isEmpty(repositoryModel.projectPath)) { // regex for all repositories within a project repos.add(repositoryModel.projectPath + "/.*"); } } } - repos.add(repo); + repos.add(repo.toLowerCase()); } } return repos; diff --git a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html index 4c8c4efd..31f0b6be 100644 --- a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html +++ b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html @@ -9,7 +9,7 @@
-
[regex]
+
[permission type]
diff --git a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java index b6ed890f..27e48fbe 100644 --- a/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java +++ b/src/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java @@ -36,6 +36,7 @@ import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.utils.DeepCopier; @@ -52,8 +53,9 @@ public class RegistrantPermissionsPanel extends BasePanel { private static final long serialVersionUID = 1L; - public RegistrantPermissionsPanel(String wicketId, List allRegistrants, final List permissions, final Map translations) { + public RegistrantPermissionsPanel(String wicketId, RegistrantType registrantType, List allRegistrants, final List permissions, final Map translations) { super(wicketId); + setOutputMarkupId(true); // update existing permissions repeater RefreshingView dataView = new RefreshingView("permissionRow") { @@ -80,22 +82,40 @@ public class RegistrantPermissionsPanel extends BasePanel { public void populateItem(final Item item) { final RegistrantAccessPermission entry = item.getModelObject(); - if (RegistrantType.REPOSITORY.equals(entry.type)) { - // repository, strip .git and show swatch + if (RegistrantType.REPOSITORY.equals(entry.registrantType)) { String repoName = StringUtils.stripDotGit(entry.registrant); - Label registrant = new Label("registrant", repoName); - WicketUtils.setCssClass(registrant, "repositorySwatch"); - WicketUtils.setCssBackground(registrant, repoName); - item.add(registrant); + if (StringUtils.findInvalidCharacter(repoName) == null) { + // repository, strip .git and show swatch + Label registrant = new Label("registrant", repoName); + WicketUtils.setCssClass(registrant, "repositorySwatch"); + WicketUtils.setCssBackground(registrant, repoName); + item.add(registrant); + } else { + // likely a regex + Label label = new Label("registrant", entry.registrant); + WicketUtils.setCssStyle(label, "font-weight: bold;"); + item.add(label); + } } else { - item.add(new Label("registrant", entry.registrant)); + // user or team + Label label = new Label("registrant", entry.registrant); + WicketUtils.setCssStyle(label, "font-weight: bold;"); + item.add(label); } - if (entry.isExplicit) { - item.add(new Label("regex", "").setVisible(false)); - } else { - Label regex = new Label("regex", "regex"); + switch (entry.permissionType) { + case OWNER: + Label owner = new Label("pType", "owner"); + WicketUtils.setHtmlTooltip(owner, getString("gb.ownerPermission")); + item.add(owner); + break; + case REGEX: + Label regex = new Label("pType", "regex"); WicketUtils.setHtmlTooltip(regex, getString("gb.regexPermission")); item.add(regex); + break; + default: + item.add(new Label("pType", "").setVisible(false)); + break; } // use ajax to get immediate update of permission level change @@ -106,8 +126,9 @@ public class RegistrantPermissionsPanel extends BasePanel { // only allow changing an explicitly defined permission // this is designed to prevent changing a regex permission in // a repository - permissionChoice.setEnabled(entry.isExplicit); - if (entry.isExplicit) { + permissionChoice.setEnabled(entry.isEditable); + permissionChoice.setOutputMarkupId(true); + if (entry.isEditable) { permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") { private static final long serialVersionUID = 1L; @@ -127,11 +148,15 @@ public class RegistrantPermissionsPanel extends BasePanel { // filter out registrants we already have permissions for final List registrants = new ArrayList(allRegistrants); for (RegistrantAccessPermission rp : permissions) { - registrants.remove(rp.registrant); + if (rp.isEditable) { + // only remove editable duplicates + // this allows for specifying an explicit permission + registrants.remove(rp.registrant); + } } // add new permission form - IModel addPermissionModel = new CompoundPropertyModel(new RegistrantAccessPermission()); + IModel addPermissionModel = new CompoundPropertyModel(new RegistrantAccessPermission(registrantType)); Form addPermissionForm = new Form("addPermissionForm", addPermissionModel); addPermissionForm.add(new DropDownChoice("registrant", registrants)); addPermissionForm.add(new DropDownChoice("permission", Arrays @@ -144,7 +169,11 @@ public class RegistrantPermissionsPanel extends BasePanel { protected void onSubmit(AjaxRequestTarget target, Form form) { // add permission to our list RegistrantAccessPermission rp = (RegistrantAccessPermission) form.getModel().getObject(); - permissions.add(DeepCopier.copy(rp)); + RegistrantAccessPermission copy = DeepCopier.copy(rp); + if (StringUtils.findInvalidCharacter(copy.registrant) != null) { + copy.permissionType = PermissionType.REGEX; + } + permissions.add(copy); // remove registrant from available choices registrants.remove(rp.registrant); @@ -159,6 +188,12 @@ public class RegistrantPermissionsPanel extends BasePanel { add(addPermissionForm.setVisible(registrants.size() > 0)); } + protected boolean getStatelessHint() + { + return false; + } + + private class AccessPermissionRenderer implements IChoiceRenderer { private static final long serialVersionUID = 1L; diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java index 0be2e02a..3df0ff8e 100644 --- a/tests/com/gitblit/tests/RpcTests.java +++ b/tests/com/gitblit/tests/RpcTests.java @@ -35,6 +35,7 @@ import org.junit.Test; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlitException.UnauthorizedException; import com.gitblit.Keys; @@ -199,7 +200,7 @@ public class RpcTests { List permissions = RpcUtils.getRepositoryMemberPermissions(retrievedRepository, url, account, password.toCharArray()); assertEquals("Membership permissions is not empty!", 0, permissions.size()); - permissions.add(new RegistrantAccessPermission(testMember.username, AccessPermission.PUSH, true, RegistrantType.USER)); + permissions.add(new RegistrantAccessPermission(testMember.username, AccessPermission.PUSH, PermissionType.EXPLICIT, RegistrantType.USER, true)); assertTrue( "Failed to set member permissions!", RpcUtils.setRepositoryMemberPermissions(retrievedRepository, permissions, url, account, @@ -288,7 +289,7 @@ public class RpcTests { // set no teams List permissions = new ArrayList(); for (String team : helloworldTeams) { - permissions.add(new RegistrantAccessPermission(team, AccessPermission.NONE, true, RegistrantType.TEAM)); + permissions.add(new RegistrantAccessPermission(team, AccessPermission.NONE, PermissionType.EXPLICIT, RegistrantType.TEAM, true)); } assertTrue(RpcUtils.setRepositoryTeamPermissions(helloworld, permissions, url, account, password.toCharArray())); -- 2.39.5