diff options
23 files changed, 244 insertions, 79 deletions
diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd index 6f6fd752..678a7e0e 100644 --- a/docs/04_releases.mkd +++ b/docs/04_releases.mkd @@ -9,8 +9,9 @@ - Can't set reset settings with $ or { characters through Gitblit Manager because they are not properly escaped
#### additions
-
- - Chinese translation (github/dapengme)
+
+ - Implemented multiple repository owners (github/akquinet)
+ - Chinese translation (github/dapengme, github/yin8086)
### Older Releases
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 7f06b35c..6bf75d75 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -939,14 +939,14 @@ public class GitBlit implements ServletContextListener { for (RepositoryModel model : getRepositoryModels(user)) {
if (model.isUsersPersonalRepository(username)) {
// personal repository
- model.owner = user.username;
+ model.addOwner(user.username);
String oldRepositoryName = model.name;
model.name = "~" + user.username + model.name.substring(model.projectPath.length());
model.projectPath = "~" + user.username;
updateRepositoryModel(oldRepositoryName, model, false);
} else if (model.isOwner(username)) {
// common/shared repo
- model.owner = user.username;
+ model.addOwner(user.username);
updateRepositoryModel(model.name, model, false);
}
}
@@ -1665,7 +1665,7 @@ public class GitBlit implements ServletContextListener { if (config != null) {
model.description = getConfig(config, "description", "");
- model.owner = getConfig(config, "owner", "");
+ model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", "")));
model.useTickets = getConfig(config, "useTickets", false);
model.useDocs = getConfig(config, "useDocs", false);
model.allowForks = getConfig(config, "allowForks", true);
@@ -2183,7 +2183,7 @@ public class GitBlit implements ServletContextListener { public void updateConfiguration(Repository r, RepositoryModel repository) {
StoredConfig config = r.getConfig();
config.setString(Constants.CONFIG_GITBLIT, null, "description", repository.description);
- config.setString(Constants.CONFIG_GITBLIT, null, "owner", repository.owner);
+ config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners));
config.setBoolean(Constants.CONFIG_GITBLIT, null, "useTickets", repository.useTickets);
config.setBoolean(Constants.CONFIG_GITBLIT, null, "useDocs", repository.useDocs);
config.setBoolean(Constants.CONFIG_GITBLIT, null, "allowForks", repository.allowForks);
@@ -3320,15 +3320,17 @@ public class GitBlit implements ServletContextListener { // create a Gitblit repository model for the clone
RepositoryModel cloneModel = repository.cloneAs(cloneName);
// owner has REWIND/RW+ permissions
- cloneModel.owner = user.username;
+ cloneModel.addOwner(user.username);
updateRepositoryModel(cloneName, cloneModel, false);
// add the owner of the source repository to the clone's access list
- if (!StringUtils.isEmpty(repository.owner)) {
- UserModel originOwner = getUserModel(repository.owner);
- if (originOwner != null) {
- originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
- updateUserModel(originOwner.username, originOwner, false);
+ if (!ArrayUtils.isEmpty(repository.owners)) {
+ for (String owner : repository.owners) {
+ UserModel originOwner = getUserModel(owner);
+ if (originOwner != null) {
+ originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE);
+ updateUserModel(originOwner.username, originOwner, false);
+ }
}
}
diff --git a/src/com/gitblit/GitFilter.java b/src/com/gitblit/GitFilter.java index 2b769d4b..a0d395b1 100644 --- a/src/com/gitblit/GitFilter.java +++ b/src/com/gitblit/GitFilter.java @@ -222,7 +222,7 @@ public class GitFilter extends AccessRestrictionFilter { // create repository
RepositoryModel model = new RepositoryModel();
model.name = repository;
- model.owner = user.username;
+ model.addOwner(user.username);
model.projectPath = StringUtils.getFirstPathElement(repository);
if (model.isUsersPersonalRepository(user.username)) {
// personal repository, default to private for user
diff --git a/src/com/gitblit/client/EditRepositoryDialog.java b/src/com/gitblit/client/EditRepositoryDialog.java index 6f9ed525..8851de43 100644 --- a/src/com/gitblit/client/EditRepositoryDialog.java +++ b/src/com/gitblit/client/EditRepositoryDialog.java @@ -38,7 +38,6 @@ 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;
@@ -117,7 +116,7 @@ public class EditRepositoryDialog extends JDialog { private JComboBox federationStrategy;
- private JComboBox ownerField;
+ private JPalette<String> ownersPalette;
private JComboBox headRefField;
@@ -126,7 +125,7 @@ public class EditRepositoryDialog extends JDialog { private JTextField gcThreshold;
private JComboBox maxActivityCommits;
-
+
private RegistrantPermissionsPanel usersPalette;
private JPalette<String> setsPalette;
@@ -207,7 +206,7 @@ public class EditRepositoryDialog extends JDialog { gcThreshold = new JTextField(8);
gcThreshold.setText(anRepository.gcThreshold);
- ownerField = new JComboBox();
+ ownersPalette = new JPalette<String>(true);
useTickets = new JCheckBox(Translation.get("gb.useTicketsDescription"),
anRepository.useTickets);
@@ -334,10 +333,10 @@ public class EditRepositoryDialog extends JDialog { usersPalette = new RegistrantPermissionsPanel(RegistrantType.USER);
- JPanel northFieldsPanel = new JPanel(new GridLayout(0, 1, 0, 5));
- northFieldsPanel.add(newFieldPanel(Translation.get("gb.owner"), ownerField));
+ JPanel northFieldsPanel = new JPanel(new BorderLayout(0, 5));
+ northFieldsPanel.add(newFieldPanel(Translation.get("gb.owners"), ownersPalette), BorderLayout.NORTH);
northFieldsPanel.add(newFieldPanel(Translation.get("gb.accessRestriction"),
- accessRestriction), BorderLayout.NORTH);
+ accessRestriction), BorderLayout.CENTER);
JPanel northAccessPanel = new JPanel(new BorderLayout(5, 5));
northAccessPanel.add(northFieldsPanel, BorderLayout.NORTH);
@@ -556,8 +555,8 @@ public class EditRepositoryDialog extends JDialog { repository.name = rname;
repository.description = descriptionField.getText();
- repository.owner = ownerField.getSelectedItem() == null ? null
- : ownerField.getSelectedItem().toString();
+ repository.owners.clear();
+ repository.owners.addAll(ownersPalette.getSelections());
repository.HEAD = headRefField.getSelectedItem() == null ? null
: headRefField.getSelectedItem().toString();
repository.gcPeriod = (Integer) gcPeriod.getSelectedItem();
@@ -629,11 +628,8 @@ public class EditRepositoryDialog extends JDialog { this.allowNamed.setSelected(!authenticated);
}
- public void setUsers(String owner, List<String> all, List<RegistrantAccessPermission> permissions) {
- ownerField.setModel(new DefaultComboBoxModel(all.toArray()));
- if (!StringUtils.isEmpty(owner)) {
- ownerField.setSelectedItem(owner);
- }
+ public void setUsers(List<String> owners, List<String> all, List<RegistrantAccessPermission> permissions) {
+ ownersPalette.setObjects(all, owners);
usersPalette.setObjects(all, permissions);
}
diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java index 1101cd60..cc7d58a6 100644 --- a/src/com/gitblit/client/GitblitClient.java +++ b/src/com/gitblit/client/GitblitClient.java @@ -162,7 +162,7 @@ public class GitblitClient implements Serializable { }
public boolean isOwner(RepositoryModel model) {
- return account != null && account.equalsIgnoreCase(model.owner);
+ return model.isOwner(account);
}
public String getURL(String action, String repository, String objectId) {
diff --git a/src/com/gitblit/client/JPalette.java b/src/com/gitblit/client/JPalette.java index 4ead099e..a0c2b258 100644 --- a/src/com/gitblit/client/JPalette.java +++ b/src/com/gitblit/client/JPalette.java @@ -144,7 +144,7 @@ public class JPalette<T> extends JPanel { table.getColumn(table.getColumnName(0)).setCellRenderer(nameRenderer);
JScrollPane jsp = new JScrollPane(table);
- jsp.setPreferredSize(new Dimension(225, 175));
+ jsp.setPreferredSize(new Dimension(225, 160));
JPanel panel = new JPanel(new BorderLayout());
JLabel jlabel = new JLabel(label);
jlabel.setFont(jlabel.getFont().deriveFont(Font.BOLD));
diff --git a/src/com/gitblit/client/RepositoriesPanel.java b/src/com/gitblit/client/RepositoriesPanel.java index 769d33b8..64bde9b8 100644 --- a/src/com/gitblit/client/RepositoriesPanel.java +++ b/src/com/gitblit/client/RepositoriesPanel.java @@ -49,8 +49,8 @@ import javax.swing.table.TableRowSorter; import com.gitblit.Constants;
import com.gitblit.Constants.RpcRequest;
import com.gitblit.Keys;
-import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.FeedModel;
+import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.StringUtils;
@@ -453,7 +453,7 @@ public abstract class RepositoriesPanel extends JPanel { dialog.setLocationRelativeTo(RepositoriesPanel.this);
List<String> usernames = gitblit.getUsernames();
List<RegistrantAccessPermission> members = gitblit.getUserAccessPermissions(repository);
- dialog.setUsers(repository.owner, usernames, members);
+ dialog.setUsers(new ArrayList<String>(repository.owners), usernames, members);
dialog.setTeams(gitblit.getTeamnames(), gitblit.getTeamAccessPermissions(repository));
dialog.setRepositories(gitblit.getRepositories());
dialog.setFederationSets(gitblit.getFederationSets(), repository.federationSets);
diff --git a/src/com/gitblit/client/RepositoriesTableModel.java b/src/com/gitblit/client/RepositoriesTableModel.java index c3eaf6e5..6b295a4b 100644 --- a/src/com/gitblit/client/RepositoriesTableModel.java +++ b/src/com/gitblit/client/RepositoriesTableModel.java @@ -23,6 +23,7 @@ import java.util.List; import javax.swing.table.AbstractTableModel;
import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.ArrayUtils;
/**
* Table model of a list of repositories.
@@ -111,7 +112,7 @@ public class RepositoriesTableModel extends AbstractTableModel { case Description:
return model.description;
case Owner:
- return model.owner;
+ return ArrayUtils.toString(model.owners);
case Indicators:
return model;
case Last_Change:
diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java index 022fd200..a2dab3c5 100644 --- a/src/com/gitblit/models/RepositoryModel.java +++ b/src/com/gitblit/models/RepositoryModel.java @@ -17,6 +17,7 @@ package com.gitblit.models; import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -43,7 +44,7 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel // field names are reflectively mapped in EditRepository page
public String name;
public String description;
- public String owner;
+ public List<String> owners;
public Date lastChange;
public boolean hasCommits;
public boolean showRemoteBranches;
@@ -91,13 +92,15 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel public RepositoryModel(String name, String description, String owner, Date lastchange) {
this.name = name;
this.description = description;
- this.owner = owner;
this.lastChange = lastchange;
this.accessRestriction = AccessRestrictionType.NONE;
this.authorizationControl = AuthorizationControl.NAMED;
this.federationSets = new ArrayList<String>();
this.federationStrategy = FederationStrategy.FEDERATE_THIS;
this.projectPath = StringUtils.getFirstPathElement(name);
+ this.owners = new ArrayList<String>();
+
+ addOwner(owner);
}
public List<String> getLocalBranches() {
@@ -162,7 +165,10 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel }
public boolean isOwner(String username) {
- return owner != null && username != null && owner.equalsIgnoreCase(username);
+ if (StringUtils.isEmpty(username) || ArrayUtils.isEmpty(owners)) {
+ return false;
+ }
+ return owners.contains(username.toLowerCase());
}
public boolean isPersonalRepository() {
@@ -201,4 +207,37 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel clone.sparkleshareId = sparkleshareId;
return clone;
}
-}
\ No newline at end of file +
+ public void addOwner(String username) {
+ if (!StringUtils.isEmpty(username)) {
+ String name = username.toLowerCase();
+ // a set would be more efficient, but this complicates JSON
+ // deserialization so we enforce uniqueness with an arraylist
+ if (!owners.contains(name)) {
+ owners.add(name);
+ }
+ }
+ }
+
+ public void removeOwner(String username) {
+ if (!StringUtils.isEmpty(username)) {
+ owners.remove(username.toLowerCase());
+ }
+ }
+
+ public void addOwners(Collection<String> usernames) {
+ if (!ArrayUtils.isEmpty(usernames)) {
+ for (String username : usernames) {
+ addOwner(username);
+ }
+ }
+ }
+
+ public void removeOwners(Collection<String> usernames) {
+ if (!ArrayUtils.isEmpty(owners)) {
+ for (String username : usernames) {
+ removeOwner(username);
+ }
+ }
+ }
+} diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java index 54e81cb5..bec011d9 100644 --- a/src/com/gitblit/models/UserModel.java +++ b/src/com/gitblit/models/UserModel.java @@ -108,8 +108,7 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel> @Deprecated
@Unused
public boolean canAccessRepository(RepositoryModel repository) {
- boolean isOwner = !StringUtils.isEmpty(repository.owner)
- && repository.owner.equals(username);
+ boolean isOwner = repository.isOwner(username);
boolean allowAuthenticated = isAuthenticated && AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl);
return canAdmin() || isOwner || repositories.contains(repository.name.toLowerCase())
|| hasTeamAccess(repository.name) || allowAuthenticated;
diff --git a/src/com/gitblit/utils/ArrayUtils.java b/src/com/gitblit/utils/ArrayUtils.java index 41d110a3..65834673 100644 --- a/src/com/gitblit/utils/ArrayUtils.java +++ b/src/com/gitblit/utils/ArrayUtils.java @@ -15,7 +15,9 @@ */
package com.gitblit.utils;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
/**
@@ -41,4 +43,32 @@ public class ArrayUtils { public static boolean isEmpty(Collection<?> collection) {
return collection == null || collection.size() == 0;
}
+
+ public static String toString(Collection<?> collection) {
+ if (isEmpty(collection)) {
+ return "";
+ }
+ StringBuilder sb = new StringBuilder();
+ for (Object o : collection) {
+ sb.append(o.toString()).append(", ");
+ }
+ // trim trailing comma-space
+ sb.setLength(sb.length() - 2);
+ return sb.toString();
+ }
+
+ public static Collection<String> fromString(String value) {
+ if (StringUtils.isEmpty(value)) {
+ value = "";
+ }
+ List<String> list = new ArrayList<String>();
+ String [] values = value.split(",|;");
+ for (String v : values) {
+ String string = v.trim();
+ if (!StringUtils.isEmpty(string)) {
+ list.add(string);
+ }
+ }
+ return list;
+ }
}
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index dfdf70c2..a993f9f1 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -441,4 +441,5 @@ gb.validity = validity gb.siteName = site name
gb.siteNameDescription = short, descriptive name of your server
gb.excludeFromActivity = exclude from activity page
-gb.isSparkleshared = repository is Sparkleshared
\ No newline at end of file +gb.isSparkleshared = repository is Sparkleshared
+gb.owners = owners
\ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html index 60893f44..7fc0de23 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -50,7 +50,7 @@ <div class="tab-pane" id="permissions">
<table class="plain">
<tbody class="settings">
- <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select class="span2" wicket:id="owner" tabindex="15" /> <span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
+ <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="15" /> </td></tr>
<tr><th colspan="2"><hr/></th></tr>
<tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="16" /></td></tr>
<tr><th colspan="2"><hr/></th></tr>
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index a071b69e..d68d6550 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -94,7 +94,7 @@ public class EditRepositoryPage extends RootSubPage { // personal create permissions, inject personal repository path
model.name = user.getPersonalPath() + "/";
model.projectPath = user.getPersonalPath();
- model.owner = user.username;
+ model.addOwner(user.username);
// personal repositories are private by default
model.accessRestriction = AccessRestrictionType.VIEW;
model.authorizationControl = AuthorizationControl.NAMED;
@@ -164,6 +164,12 @@ public class EditRepositoryPage extends RootSubPage { final RegistrantPermissionsPanel teamsPalette = new RegistrantPermissionsPanel("teams",
RegistrantType.TEAM, GitBlit.self().getAllTeamnames(), repositoryTeams, getAccessPermissions());
+ // owners palette
+ List<String> owners = new ArrayList<String>(repositoryModel.owners);
+ List<String> persons = GitBlit.self().getAllUsernames();
+ final Palette<String> ownersPalette = new Palette<String>("owners", new ListModel<String>(owners), new CollectionModel<String>(
+ persons), new StringChoiceRenderer(), 12, true);
+
// indexed local branches palette
List<String> allLocalBranches = new ArrayList<String>();
allLocalBranches.add(Constants.DEFAULT_BRANCH);
@@ -326,6 +332,13 @@ public class EditRepositoryPage extends RootSubPage { }
repositoryModel.indexedBranches = indexedBranches;
+ // owners
+ repositoryModel.owners.clear();
+ Iterator<String> owners = ownersPalette.getSelectedChoices();
+ while (owners.hasNext()) {
+ repositoryModel.addOwner(owners.next());
+ }
+
// pre-receive scripts
List<String> preReceiveScripts = new ArrayList<String>();
Iterator<String> pres = preReceivePalette.getSelectedChoices();
@@ -377,8 +390,7 @@ public class EditRepositoryPage extends RootSubPage { // field names reflective match RepositoryModel fields
form.add(new TextField<String>("name").setEnabled(allowEditName));
form.add(new TextField<String>("description"));
- form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames())
- .setEnabled(GitBlitWebSession.get().canAdmin() && !repositoryModel.isPersonalRepository()));
+ form.add(ownersPalette);
form.add(new CheckBox("allowForks").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays
.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer());
@@ -559,7 +571,7 @@ public class EditRepositoryPage extends RootSubPage { isAdmin = true;
return;
} else {
- if (!model.owner.equalsIgnoreCase(user.username)) {
+ if (!model.isOwner(user.username)) {
// User is not an Admin nor Owner
error(getString("gb.errorOnlyAdminOrOwnerMayEditRepository"), true);
}
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java index 78ffe80d..a477b741 100644 --- a/src/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/com/gitblit/wicket/pages/RepositoryPage.java @@ -184,7 +184,7 @@ public abstract class RepositoryPage extends BasePage { showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
}
isOwner = GitBlitWebSession.get().isLoggedIn()
- && (model.owner != null && model.owner.equalsIgnoreCase(GitBlitWebSession.get()
+ && (model.isOwner(GitBlitWebSession.get()
.getUsername()));
if (showAdmin || isOwner) {
pages.put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class, params));
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.html b/src/com/gitblit/wicket/pages/SummaryPage.html index 45ffddfb..3e85df99 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/com/gitblit/wicket/pages/SummaryPage.html @@ -16,7 +16,7 @@ <div class="hidden-phone" style="padding-bottom: 10px;">
<table class="plain">
<tr><th><wicket:message key="gb.description">[description]</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>
- <tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>
+ <tr><th><wicket:message key="gb.owners">[owner]</wicket:message></th><td><span wicket:id="repositoryOwners"><span wicket:id="owner"></span><span wicket:id="comma"></span></span></td></tr>
<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="branchStats">[branch stats]</span> <span class="link"><a wicket:id="metrics"><wicket:message key="gb.metrics">[metrics]</wicket:message></a></span></td></tr>
<tr><th style="vertical-align:top;"><wicket:message key="gb.repositoryUrl">[URL]</wicket:message> <img style="vertical-align: top;padding-left:3px;" wicket:id="accessRestrictionIcon" /></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span><div wicket:id="otherUrls"></div></td></tr>
@@ -44,7 +44,11 @@ <div style="border:1px solid #ddd;border-radius: 0 0 3px 3px;padding: 20px;">
<div wicket:id="readmeContent" class="markdown"></div>
</div>
- </wicket:fragment>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="ownersFragment">
+
+ </wicket:fragment>
</wicket:extend>
</body>
</html>
\ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/SummaryPage.java b/src/com/gitblit/wicket/pages/SummaryPage.java index 8df2cebc..bd40a1b7 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/com/gitblit/wicket/pages/SummaryPage.java @@ -27,6 +27,9 @@ import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.wicketstuff.googlecharts.Chart;
@@ -82,18 +85,29 @@ public class SummaryPage extends RepositoryPage { // repository description
add(new Label("repositoryDescription", getRepositoryModel().description));
- String owner = getRepositoryModel().owner;
- if (StringUtils.isEmpty(owner)) {
- add(new Label("repositoryOwner").setVisible(false));
- } else {
- UserModel ownerModel = GitBlit.self().getUserModel(owner);
- if (ownerModel != null) {
- add(new LinkPanel("repositoryOwner", null, ownerModel.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(owner)));
- } else {
- add(new Label("repositoryOwner", owner));
+
+ // owner links
+ final List<String> owners = new ArrayList<String>(getRepositoryModel().owners);
+ ListDataProvider<String> ownersDp = new ListDataProvider<String>(owners);
+ DataView<String> ownersView = new DataView<String>("repositoryOwners", ownersDp) {
+ private static final long serialVersionUID = 1L;
+ int counter = 0;
+ public void populateItem(final Item<String> item) {
+ UserModel ownerModel = GitBlit.self().getUserModel(item.getModelObject());
+ if (ownerModel != null) {
+ item.add(new LinkPanel("owner", null, ownerModel.getDisplayName(), UserPage.class,
+ WicketUtils.newUsernameParameter(ownerModel.username)).setRenderBodyOnly(true));
+ } else {
+ item.add(new Label("owner").setVisible(false));
+ }
+ counter++;
+ item.add(new Label("comma", ",").setVisible(counter < owners.size()));
+ item.setRenderBodyOnly(true);
}
- }
-
+ };
+ ownersView.setRenderBodyOnly(true);
+ add(ownersView);
+
add(WicketUtils.createTimestampLabel("repositoryLastChange",
JGitUtils.getLastChange(r), getTimeZone(), getTimeUtils()));
if (metricsTotal == null) {
diff --git a/src/com/gitblit/wicket/panels/ProjectRepositoryPanel.java b/src/com/gitblit/wicket/panels/ProjectRepositoryPanel.java index 3c9bf7f0..7b4ee9f0 100644 --- a/src/com/gitblit/wicket/panels/ProjectRepositoryPanel.java +++ b/src/com/gitblit/wicket/panels/ProjectRepositoryPanel.java @@ -127,16 +127,24 @@ public class ProjectRepositoryPanel extends BasePanel { add(WicketUtils.newBlankImage("accessRestrictionIcon"));
}
- if (StringUtils.isEmpty(entry.owner)) {
+ if (ArrayUtils.isEmpty(entry.owners)) {
add(new Label("repositoryOwner").setVisible(false));
} else {
- UserModel ownerModel = GitBlit.self().getUserModel(entry.owner);
- String owner = entry.owner;
- if (ownerModel != null) {
- owner = ownerModel.getDisplayName();
+ String owner = "";
+ for (String username : entry.owners) {
+ UserModel ownerModel = GitBlit.self().getUserModel(username);
+
+ if (ownerModel != null) {
+ owner = ownerModel.getDisplayName();
+ }
}
- add(new Label("repositoryOwner", owner + " (" +
+ if (entry.owners.size() > 1) {
+ owner += ", ...";
+ }
+ Label ownerLabel = (new Label("repositoryOwner", owner + " (" +
localizer.getString("gb.owner", parent) + ")"));
+ WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));
+ add(ownerLabel);
}
UserModel user = GitBlitWebSession.get().getUser();
diff --git a/src/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/com/gitblit/wicket/panels/RepositoriesPanel.java index ee5edfce..726af61d 100644 --- a/src/com/gitblit/wicket/panels/RepositoriesPanel.java +++ b/src/com/gitblit/wicket/panels/RepositoriesPanel.java @@ -49,6 +49,7 @@ import com.gitblit.SyndicationServlet; import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.WicketUtils;
@@ -294,14 +295,23 @@ public class RepositoriesPanel extends BasePanel { row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
}
- String owner = entry.owner;
- if (!StringUtils.isEmpty(owner)) {
- UserModel ownerModel = GitBlit.self().getUserModel(owner);
- if (ownerModel != null) {
- owner = ownerModel.getDisplayName();
+ String owner = "";
+ if (!ArrayUtils.isEmpty(entry.owners)) {
+ // display first owner
+ for (String username : entry.owners) {
+ UserModel ownerModel = GitBlit.self().getUserModel(username);
+ if (ownerModel != null) {
+ owner = ownerModel.getDisplayName();
+ break;
+ }
+ }
+ if (entry.owners.size() > 1) {
+ owner += ", ...";
}
}
- row.add(new Label("repositoryOwner", owner));
+ Label ownerLabel = new Label("repositoryOwner", owner);
+ WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));
+ row.add(ownerLabel);
String lastChange;
if (entry.lastChange.getTime() == 0) {
@@ -522,10 +532,12 @@ public class RepositoriesPanel extends BasePanel { Collections.sort(list, new Comparator<RepositoryModel>() {
@Override
public int compare(RepositoryModel o1, RepositoryModel o2) {
+ String own1 = ArrayUtils.toString(o1.owners);
+ String own2 = ArrayUtils.toString(o2.owners);
if (asc) {
- return o1.owner.compareTo(o2.owner);
+ return own1.compareTo(own2);
}
- return o2.owner.compareTo(o1.owner);
+ return own2.compareTo(own1);
}
});
} else if (prop.equals(SortBy.description.name())) {
diff --git a/tests/com/gitblit/tests/FederationTests.java b/tests/com/gitblit/tests/FederationTests.java index c8f686ad..ced500a5 100644 --- a/tests/com/gitblit/tests/FederationTests.java +++ b/tests/com/gitblit/tests/FederationTests.java @@ -72,7 +72,7 @@ public class FederationTests { model.accessRestriction = AccessRestrictionType.VIEW;
model.description = "cloneable repository " + i;
model.lastChange = new Date();
- model.owner = "adminuser";
+ model.addOwner("adminuser");
model.name = "repo" + i + ".git";
model.size = "5 MB";
model.hasCommits = true;
diff --git a/tests/com/gitblit/tests/GitServletTest.java b/tests/com/gitblit/tests/GitServletTest.java index 771c4b9a..a05b3650 100644 --- a/tests/com/gitblit/tests/GitServletTest.java +++ b/tests/com/gitblit/tests/GitServletTest.java @@ -40,6 +40,7 @@ import com.gitblit.Keys; import com.gitblit.models.PushLogEntry;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.PushLogUtils;
@@ -725,7 +726,7 @@ public class GitServletTest { // confirm default personal repository permissions
RepositoryModel model = GitBlit.self().getRepositoryModel(MessageFormat.format("~{0}/ticgit.git", user.username));
- assertEquals("Unexpected owner", user.username, model.owner);
+ assertEquals("Unexpected owner", user.username, ArrayUtils.toString(model.owners));
assertEquals("Unexpected authorization control", AuthorizationControl.NAMED, model.authorizationControl);
assertEquals("Unexpected access restriction", AccessRestrictionType.VIEW, model.accessRestriction);
@@ -749,7 +750,7 @@ public class GitServletTest { // confirm default project repository permissions
RepositoryModel model = GitBlit.self().getRepositoryModel("project/ticgit.git");
- assertEquals("Unexpected owner", user.username, model.owner);
+ assertEquals("Unexpected owner", user.username, ArrayUtils.toString(model.owners));
assertEquals("Unexpected authorization control", AuthorizationControl.fromName(GitBlit.getString(Keys.git.defaultAuthorizationControl, "NAMED")), model.authorizationControl);
assertEquals("Unexpected access restriction", AccessRestrictionType.fromName(GitBlit.getString(Keys.git.defaultAccessRestriction, "NONE")), model.accessRestriction);
diff --git a/tests/com/gitblit/tests/PermissionsTest.java b/tests/com/gitblit/tests/PermissionsTest.java index b6ffa626..5a951042 100644 --- a/tests/com/gitblit/tests/PermissionsTest.java +++ b/tests/com/gitblit/tests/PermissionsTest.java @@ -2327,7 +2327,7 @@ public class PermissionsTest extends Assert { repository.accessRestriction = AccessRestrictionType.VIEW; UserModel user = new UserModel("test"); - repository.owner = user.username; + repository.addOwner(user.username); assertFalse("user SHOULD NOT HAVE a repository permission!", user.hasRepositoryPermission(repository.name)); assertTrue("owner CAN NOT view!", user.canView(repository)); @@ -2345,13 +2345,58 @@ public class PermissionsTest extends Assert { } @Test + public void testMultipleOwners() throws Exception { + RepositoryModel repository = new RepositoryModel("myrepo.git", null, null, new Date()); + repository.authorizationControl = AuthorizationControl.NAMED; + repository.accessRestriction = AccessRestrictionType.VIEW; + + UserModel user = new UserModel("test"); + repository.addOwner(user.username); + UserModel user2 = new UserModel("test2"); + repository.addOwner(user2.username); + + // first owner + assertFalse("user SHOULD NOT HAVE a repository permission!", user.hasRepositoryPermission(repository.name)); + assertTrue("owner CAN NOT view!", user.canView(repository)); + assertTrue("owner CAN NOT clone!", user.canClone(repository)); + assertTrue("owner CAN NOT push!", user.canPush(repository)); + + assertTrue("owner CAN NOT create ref!", user.canCreateRef(repository)); + assertTrue("owner CAN NOT delete ref!", user.canDeleteRef(repository)); + assertTrue("owner CAN NOT rewind ref!", user.canRewindRef(repository)); + + assertTrue("owner CAN NOT fork!", user.canFork(repository)); + + assertFalse("owner CAN NOT delete!", user.canDelete(repository)); + assertTrue("owner CAN NOT edit!", user.canEdit(repository)); + + // second owner + assertFalse("user SHOULD NOT HAVE a repository permission!", user2.hasRepositoryPermission(repository.name)); + assertTrue("owner CAN NOT view!", user2.canView(repository)); + assertTrue("owner CAN NOT clone!", user2.canClone(repository)); + assertTrue("owner CAN NOT push!", user2.canPush(repository)); + + assertTrue("owner CAN NOT create ref!", user2.canCreateRef(repository)); + assertTrue("owner CAN NOT delete ref!", user2.canDeleteRef(repository)); + assertTrue("owner CAN NOT rewind ref!", user2.canRewindRef(repository)); + + assertTrue("owner CAN NOT fork!", user2.canFork(repository)); + + assertFalse("owner CAN NOT delete!", user2.canDelete(repository)); + assertTrue("owner CAN NOT edit!", user2.canEdit(repository)); + + assertTrue(repository.isOwner(user.username)); + assertTrue(repository.isOwner(user2.username)); + } + + @Test public void testOwnerPersonalRepository() throws Exception { RepositoryModel repository = new RepositoryModel("~test/myrepo.git", null, null, new Date()); repository.authorizationControl = AuthorizationControl.NAMED; repository.accessRestriction = AccessRestrictionType.VIEW; UserModel user = new UserModel("test"); - repository.owner = user.username; + repository.addOwner(user.username); assertFalse("user SHOULD NOT HAVE a repository permission!", user.hasRepositoryPermission(repository.name)); assertTrue("user CAN NOT view!", user.canView(repository)); @@ -2375,7 +2420,7 @@ public class PermissionsTest extends Assert { repository.accessRestriction = AccessRestrictionType.VIEW; UserModel user = new UserModel("visitor"); - repository.owner = "test"; + repository.addOwner("test"); assertFalse("user HAS a repository permission!", user.hasRepositoryPermission(repository.name)); assertFalse("user CAN view!", user.canView(repository)); diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java index 62d87bf9..3241a8ab 100644 --- a/tests/com/gitblit/tests/RpcTests.java +++ b/tests/com/gitblit/tests/RpcTests.java @@ -167,7 +167,7 @@ public class RpcTests { RepositoryModel model = new RepositoryModel();
model.name = "garbagerepo.git";
model.description = "created by RpcUtils";
- model.owner = "garbage";
+ model.addOwner("garbage");
model.accessRestriction = AccessRestrictionType.VIEW;
model.authorizationControl = AuthorizationControl.AUTHENTICATED;
|