resources/gitblit.css
@@ -180,6 +180,15 @@ vertical-align: middle; } div.odd { } div.even { background-color: whiteSmoke; vertical-align: middle; } div.page_footer { clear: both; height: 17px; src/com/gitblit/Constants.java
@@ -320,6 +320,8 @@ public static enum AccessPermission { NONE("N"), VIEW("V"), CLONE("R"), PUSH("RW"), CREATE("RWC"), DELETE("RWD"), REWIND("RW+"); public static final AccessPermission [] NEWPERMISSIONS = { VIEW, CLONE, PUSH, CREATE, DELETE, REWIND }; public static AccessPermission LEGACY = REWIND; public final String code; src/com/gitblit/models/RepositoryAccessPermission.java
New file @@ -0,0 +1,52 @@ /* * Copyright 2012 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.models; import java.io.Serializable; import com.gitblit.Constants.AccessPermission; import com.gitblit.utils.StringUtils; /** * Represents a Repository-AccessPermission tuple. * * @author James Moger */ public class RepositoryAccessPermission implements Serializable, Comparable<RepositoryAccessPermission> { private static final long serialVersionUID = 1L; public String repository; public AccessPermission permission; public RepositoryAccessPermission() { } public RepositoryAccessPermission(String repository, AccessPermission permission) { this.repository = repository; this.permission = permission; } @Override public int compareTo(RepositoryAccessPermission p) { return StringUtils.compareRepositoryNames(repository, p.repository); } @Override public String toString() { return permission.asRole(repository); } } src/com/gitblit/models/TeamModel.java
@@ -18,6 +18,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -86,6 +87,21 @@ removeRepositoryPermission(name); } /** * Returns a list of repository permissions for this team. * * @return the team's list of permissions */ public List<RepositoryAccessPermission> getRepositoryPermissions() { List<RepositoryAccessPermission> list = new ArrayList<RepositoryAccessPermission>(); for (Map.Entry<String, AccessPermission> entry : permissions.entrySet()) { list.add(new RepositoryAccessPermission(entry.getKey(), entry.getValue())); } Collections.sort(list); return list; } /** * Returns true if the team has any type of specified access permission for * this repository. src/com/gitblit/models/UserModel.java
@@ -17,8 +17,11 @@ import java.io.Serializable; import java.security.Principal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -125,6 +128,21 @@ } /** * Returns a list of repository permissions for this user exclusive of * permissions inherited from team memberships. * * @return the user's list of permissions */ public List<RepositoryAccessPermission> getRepositoryPermissions() { List<RepositoryAccessPermission> list = new ArrayList<RepositoryAccessPermission>(); for (Map.Entry<String, AccessPermission> entry : permissions.entrySet()) { list.add(new RepositoryAccessPermission(entry.getKey(), entry.getValue())); } Collections.sort(list); return list; } /** * Returns true if the user has any type of specified access permission for * this repository. * src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -346,3 +346,11 @@ gb.repositoryPermissions = repository permissions gb.userPermissions = user permissions gb.teamPermissions = team permissions gb.add = add gb.noPermission = NO ACCESS gb.viewPermission = {0} (view) gb.clonePermission = {0} (clone) gb.pushPermission = {0} (push) gb.createPermission = {0} (push, ref creation) gb.deletePermission = {0} (push, ref creation+deletion) gb.rewindPermission = {0} (push, ref creation+deletion+rewind) src/com/gitblit/wicket/pages/BasePage.java
@@ -15,6 +15,7 @@ */ package com.gitblit.wicket.pages; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; @@ -52,6 +53,7 @@ import org.slf4j.LoggerFactory; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.FederationStrategy; import com.gitblit.GitBlit; @@ -203,6 +205,36 @@ return map; } protected Map<AccessPermission, String> getAccessPermissions() { Map<AccessPermission, String> map = new LinkedHashMap<AccessPermission, String>(); for (AccessPermission type : AccessPermission.values()) { switch (type) { case NONE: map.put(type, MessageFormat.format(getString("gb.noPermission"), type.code)); break; case VIEW: map.put(type, MessageFormat.format(getString("gb.viewPermission"), type.code)); break; case CLONE: map.put(type, MessageFormat.format(getString("gb.clonePermission"), type.code)); break; case PUSH: map.put(type, MessageFormat.format(getString("gb.pushPermission"), type.code)); break; case CREATE: map.put(type, MessageFormat.format(getString("gb.createPermission"), type.code)); break; case DELETE: map.put(type, MessageFormat.format(getString("gb.deletePermission"), type.code)); break; case REWIND: map.put(type, MessageFormat.format(getString("gb.rewindPermission"), type.code)); break; } } return map; } protected Map<FederationStrategy, String> getFederationTypes() { Map<FederationStrategy, String> map = new LinkedHashMap<FederationStrategy, String>(); for (FederationStrategy type : FederationStrategy.values()) { src/com/gitblit/wicket/pages/EditTeamPage.html
@@ -19,7 +19,7 @@ <tr><td colspan="2" style="padding-top:15px;"><h3><wicket:message key="gb.accessPermissions"></wicket:message> <small><wicket:message key="gb.accessPermissionsForTeamDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.teamMembers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr> <tr><td colspan="2"><hr></hr></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.restrictedRepositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.repositoryPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr> <tr><td colspan="2" style="padding-top:10px;"><h3><wicket:message key="gb.hookScripts"></wicket:message> <small><wicket:message key="gb.hookScriptsDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.preReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPreReceive"></span></th><td style="padding:2px;"><span wicket:id="preReceiveScripts"></span></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.postReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPostReceive"></span></th><td style="padding:2px;"><span wicket:id="postReceiveScripts"></span></td></tr> src/com/gitblit/wicket/pages/EditTeamPage.java
@@ -40,12 +40,14 @@ import com.gitblit.GitBlit; import com.gitblit.GitBlitException; import com.gitblit.models.RepositoryModel; import com.gitblit.models.RepositoryAccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.RequiresAdminRole; import com.gitblit.wicket.StringChoiceRenderer; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.BulletListPanel; import com.gitblit.wicket.panels.RepositoryPermissionsPanel; @RequiresAdminRole public class EditTeamPage extends RootSubPage { @@ -59,6 +61,7 @@ super(); isCreate = true; setupPage(new TeamModel("")); setStatelessHint(false); } public EditTeamPage(PageParameters params) { @@ -68,6 +71,7 @@ String name = WicketUtils.getTeamname(params); TeamModel model = GitBlit.self().getTeamModel(name); setupPage(model); setStatelessHint(false); } protected void setupPage(final TeamModel teamModel) { @@ -94,11 +98,7 @@ List<String> postReceiveScripts = new ArrayList<String>(); final String oldName = teamModel.name; // repositories palette final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(new ArrayList<String>(teamModel.repositories)), new CollectionModel<String>(repos), new StringChoiceRenderer(), 10, false); final List<RepositoryAccessPermission> permissions = teamModel.getRepositoryPermissions(); // users palette final Palette<String> users = new Palette<String>("users", new ListModel<String>( @@ -146,17 +146,10 @@ return; } } Iterator<String> selectedRepositories = repositories.getSelectedChoices(); List<String> repos = new ArrayList<String>(); while (selectedRepositories.hasNext()) { repos.add(selectedRepositories.next().toLowerCase()); // update team permissions for (RepositoryAccessPermission repositoryPermission : permissions) { teamModel.setRepositoryPermission(repositoryPermission.repository, repositoryPermission.permission); } if (repos.size() == 0) { error(getString("gb.teamMustSpecifyRepository")); return; } teamModel.repositories.clear(); teamModel.repositories.addAll(repos); Iterator<String> selectedUsers = users.getSelectedChoices(); List<String> members = new ArrayList<String>(); @@ -231,7 +224,7 @@ : StringUtils.flattenStrings(teamModel.mailingLists, " ")); form.add(new TextField<String>("mailingLists", mailingLists)); form.add(repositories); form.add(new RepositoryPermissionsPanel("repositories", permissions, getAccessPermissions())); form.add(preReceivePalette); form.add(new BulletListPanel("inheritedPreReceive", "inherited", GitBlit.self() .getPreReceiveScriptsInherited(null))); src/com/gitblit/wicket/pages/EditUserPage.html
@@ -23,11 +23,16 @@ <tr><td colspan="2" style="padding-top:15px;"><h3><wicket:message key="gb.accessPermissions"></wicket:message> <small><wicket:message key="gb.accessPermissionsForUserDescription"></wicket:message></small></h3></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.teamMemberships"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr> <tr><td colspan="2"><hr></hr></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.restrictedRepositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr> <tr><th style="vertical-align: top;"><wicket:message key="gb.repositoryPermissions"></wicket:message></th> <td style="padding:2px;"> <div wicket:id="repositories"></div> </td> </tr> <tr><td colspan='2'><div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="9" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="10" /></div></td></tr> </tbody> </table> </form> </body> </wicket:extend> </html> src/com/gitblit/wicket/pages/EditUserPage.java
@@ -39,12 +39,14 @@ import com.gitblit.GitBlitException; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.RepositoryAccessPermission; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.RequiresAdminRole; import com.gitblit.wicket.StringChoiceRenderer; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.RepositoryPermissionsPanel; @RequiresAdminRole public class EditUserPage extends RootSubPage { @@ -60,6 +62,7 @@ } isCreate = true; setupPage(new UserModel("")); setStatelessHint(false); } public EditUserPage(PageParameters params) { @@ -69,6 +72,7 @@ String name = WicketUtils.getUsername(params); UserModel model = GitBlit.self().getUserModel(name); setupPage(model); setStatelessHint(false); } protected void setupPage(final UserModel userModel) { @@ -96,9 +100,8 @@ Collections.sort(userTeams); final String oldName = userModel.username; final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(new ArrayList<String>(userModel.repositories)), new CollectionModel<String>(repos), new StringChoiceRenderer(), 10, false); final List<RepositoryAccessPermission> permissions = userModel.getRepositoryPermissions(); final Palette<String> teams = new Palette<String>("teams", new ListModel<String>( new ArrayList<String>(userTeams)), new CollectionModel<String>(GitBlit.self() .getAllTeamnames()), new StringChoiceRenderer(), 10, false); @@ -167,13 +170,10 @@ } } Iterator<String> selectedRepositories = repositories.getSelectedChoices(); List<String> repos = new ArrayList<String>(); while (selectedRepositories.hasNext()) { repos.add(selectedRepositories.next().toLowerCase()); // update user permissions for (RepositoryAccessPermission repositoryPermission : permissions) { userModel.setRepositoryPermission(repositoryPermission.repository, repositoryPermission.permission); } userModel.repositories.clear(); userModel.repositories.addAll(repos); Iterator<String> selectedTeams = teams.getSelectedChoices(); userModel.teams.clear(); @@ -234,7 +234,7 @@ form.add(new CheckBox("canFork")); form.add(new CheckBox("canCreate")); form.add(new CheckBox("excludeFromFederation")); form.add(repositories); form.add(new RepositoryPermissionsPanel("repositories", permissions, getAccessPermissions())); form.add(teams.setEnabled(editTeams)); form.add(new Button("save")); src/com/gitblit/wicket/panels/RepositoryPermissionsPanel.html
New file @@ -0,0 +1,24 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" xml:lang="en" lang="en"> <body> <wicket:panel> <div wicket:id="permissionRow"> <div style="padding-top:10px" class="row-fluid"> <span class="span8" wicket:id="repository"></span> <select class="input-medium" wicket:id="permission"></select> </div> </div> <div style="padding-top:15px;" class="row-fluid"> <form class="well form-inline" wicket:id="addPermissionForm"> <select class="input-large" wicket:id="repository"></select> <select class="input-medium" wicket:id="permission"></select> <input class="btn btn-success" type="submit" value="Add" wicket:message="value:gb.add" wicket:id="addPermissionButton"/> </form> </div> </wicket:panel> </body> </html> src/com/gitblit/wicket/panels/RepositoryPermissionsPanel.java
New file @@ -0,0 +1,157 @@ /* * Copyright 2012 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.wicket.panels; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.markup.html.basic.Label; 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.repeater.Item; import org.apache.wicket.markup.repeater.OddEvenItem; import org.apache.wicket.markup.repeater.RefreshingView; import org.apache.wicket.markup.repeater.util.ModelIteratorAdapter; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import com.gitblit.Constants.AccessPermission; import com.gitblit.GitBlit; import com.gitblit.models.RepositoryAccessPermission; import com.gitblit.utils.DeepCopier; /** * Allows user to manipulate repository access permissions. * * @author James Moger * */ public class RepositoryPermissionsPanel extends BasePanel { private static final long serialVersionUID = 1L; public RepositoryPermissionsPanel(String wicketId, final List<RepositoryAccessPermission> permissions, final Map<AccessPermission, String> translations) { super(wicketId); // update existing permissions repeater RefreshingView<RepositoryAccessPermission> dataView = new RefreshingView<RepositoryAccessPermission>("permissionRow") { private static final long serialVersionUID = 1L; @Override protected Iterator<IModel<RepositoryAccessPermission>> getItemModels() { // the iterator returns RepositoryPermission objects, but we need it to // return models return new ModelIteratorAdapter<RepositoryAccessPermission>(permissions.iterator()) { @Override protected IModel<RepositoryAccessPermission> model(RepositoryAccessPermission permission) { return new CompoundPropertyModel<RepositoryAccessPermission>(permission); } }; } @Override protected Item<RepositoryAccessPermission> newItem(String id, int index, IModel<RepositoryAccessPermission> model) { // this item sets markup class attribute to either 'odd' or // 'even' for decoration return new OddEvenItem<RepositoryAccessPermission>(id, index, model); } public void populateItem(final Item<RepositoryAccessPermission> item) { final RepositoryAccessPermission entry = item.getModelObject(); item.add(new Label("repository", entry.repository)); // use ajax to get immediate update of permission level change // otherwise we can lose it if they change levels and then add // a new repository permission final DropDownChoice<AccessPermission> permissionChoice = new DropDownChoice<AccessPermission>( "permission", Arrays.asList(AccessPermission.values()), new AccessPermissionRenderer(translations)); permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") { private static final long serialVersionUID = 1L; protected void onUpdate(AjaxRequestTarget target) { target.addComponent(permissionChoice); } }); item.add(permissionChoice); } }; add(dataView); setOutputMarkupId(true); // filter out repositories we already have permissions for final List<String> repositories = GitBlit.self().getRepositoryList(); for (RepositoryAccessPermission rp : permissions) { repositories.remove(rp.repository); } // add new permission form IModel<RepositoryAccessPermission> addPermissionModel = new CompoundPropertyModel<RepositoryAccessPermission>(new RepositoryAccessPermission()); Form<RepositoryAccessPermission> addPermissionForm = new Form<RepositoryAccessPermission>("addPermissionForm", addPermissionModel); addPermissionForm.add(new DropDownChoice<String>("repository", repositories)); addPermissionForm.add(new DropDownChoice<AccessPermission>("permission", Arrays .asList(AccessPermission.NEWPERMISSIONS), new AccessPermissionRenderer(translations))); AjaxButton button = new AjaxButton("addPermissionButton", addPermissionForm) { private static final long serialVersionUID = 1L; @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { // add permission to our list RepositoryAccessPermission rp = (RepositoryAccessPermission) form.getModel().getObject(); permissions.add(DeepCopier.copy(rp)); // remove repository from available choices repositories.remove(rp.repository); // force the panel to refresh target.addComponent(RepositoryPermissionsPanel.this); } }; addPermissionForm.add(button); // only show add permission form if we have a repository choice add(addPermissionForm.setVisible(repositories.size() > 0)); } private class AccessPermissionRenderer implements IChoiceRenderer<AccessPermission> { private static final long serialVersionUID = 1L; private final Map<AccessPermission, String> map; public AccessPermissionRenderer(Map<AccessPermission, String> map) { this.map = map; } @Override public String getDisplayValue(AccessPermission type) { return map.get(type); } @Override public String getIdValue(AccessPermission type, int index) { return Integer.toString(index); } } }