From 97a71565f6ff5d9722788559ce638863a9e618ab Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 19 Oct 2012 08:32:03 -0400 Subject: [PATCH] New permissions UI for EditRepository (issue 36) --- src/com/gitblit/GitBlit.java | 75 ++++++++- .../gitblit/models/TeamAccessPermission.java | 51 ++++++ .../gitblit/models/UserAccessPermission.java | 51 ++++++ .../wicket/pages/EditRepositoryPage.html | 1 + .../wicket/pages/EditRepositoryPage.java | 50 ++---- .../wicket/panels/TeamPermissionsPanel.html | 24 +++ .../wicket/panels/TeamPermissionsPanel.java | 157 ++++++++++++++++++ .../wicket/panels/UserPermissionsPanel.html | 24 +++ .../wicket/panels/UserPermissionsPanel.java | 157 ++++++++++++++++++ 9 files changed, 552 insertions(+), 38 deletions(-) create mode 100644 src/com/gitblit/models/TeamAccessPermission.java create mode 100644 src/com/gitblit/models/UserAccessPermission.java create mode 100644 src/com/gitblit/wicket/panels/TeamPermissionsPanel.html create mode 100644 src/com/gitblit/wicket/panels/TeamPermissionsPanel.java create mode 100644 src/com/gitblit/wicket/panels/UserPermissionsPanel.html create mode 100644 src/com/gitblit/wicket/panels/UserPermissionsPanel.java diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index a1217038..af13e02d 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -89,7 +89,9 @@ import com.gitblit.models.SearchResult; import com.gitblit.models.ServerSettings; import com.gitblit.models.ServerStatus; import com.gitblit.models.SettingModel; +import com.gitblit.models.TeamAccessPermission; import com.gitblit.models.TeamModel; +import com.gitblit.models.UserAccessPermission; import com.gitblit.models.UserModel; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.ByteFormat; @@ -630,12 +632,44 @@ public class GitBlit implements ServletContextListener { } /** - * Returns the list of all users who are allowed to bypass the access - * restriction placed on the specified repository. + * Returns the list of users and their access permissions for the specified repository. + * + * @param repository + * @return a list of User-AccessPermission tuples + */ + public List getUserAccessPermissions(RepositoryModel repository) { + List permissions = new ArrayList(); + for (String user : userService.getUsernamesForRepositoryRole(repository.name)) { + AccessPermission ap = userService.getUserModel(user).getRepositoryPermission(repository); + permissions.add(new UserAccessPermission(user, ap)); + } + return permissions; + } + + /** + * Sets the access permissions to the specified repository for the specified users. + * + * @param repository + * @param permissions + * @return true if the user models have been updated + */ + public boolean setUserAccessPermissions(RepositoryModel repository, List permissions) { + List users = new ArrayList(); + for (UserAccessPermission up : permissions) { + UserModel user = userService.getUserModel(up.user); + user.setRepositoryPermission(repository.name, up.permission); + users.add(user); + } + return userService.updateUserModels(users); + } + + /** + * Returns the list of all users who have an explicit access permission + * for the specified repository. * * @see IUserService.getUsernamesForRepositoryRole(String) * @param repository - * @return list of all usernames that can bypass the access restriction + * @return list of all usernames that have an access permission for the repository */ public List getRepositoryUsers(RepositoryModel repository) { return userService.getUsernamesForRepositoryRole(repository.name); @@ -726,7 +760,39 @@ public class GitBlit implements ServletContextListener { public TeamModel getTeamModel(String teamname) { return userService.getTeamModel(teamname); } - + + /** + * Returns the list of teams and their access permissions for the specified repository. + * + * @param repository + * @return a list of Team-AccessPermission tuples + */ + public List getTeamAccessPermissions(RepositoryModel repository) { + List permissions = new ArrayList(); + for (String team : userService.getTeamnamesForRepositoryRole(repository.name)) { + AccessPermission ap = userService.getTeamModel(team).getRepositoryPermission(repository); + permissions.add(new TeamAccessPermission(team, ap)); + } + return permissions; + } + + /** + * Sets the access permissions to the specified repository for the specified teams. + * + * @param repository + * @param permissions + * @return true if the team models have been updated + */ + public boolean setTeamAccessPermissions(RepositoryModel repository, List permissions) { + List teams = new ArrayList(); + for (TeamAccessPermission tp : permissions) { + TeamModel team = userService.getTeamModel(tp.team); + team.setRepositoryPermission(repository.name, tp.permission); + teams.add(team); + } + return userService.updateTeamModels(teams); + } + /** * Returns the list of all teams who are allowed to bypass the access * restriction placed on the specified repository. @@ -735,6 +801,7 @@ public class GitBlit implements ServletContextListener { * @param repository * @return list of all teamnames that can bypass the access restriction */ + @Deprecated public List getRepositoryTeams(RepositoryModel repository) { return userService.getTeamnamesForRepositoryRole(repository.name); } diff --git a/src/com/gitblit/models/TeamAccessPermission.java b/src/com/gitblit/models/TeamAccessPermission.java new file mode 100644 index 00000000..23468c6d --- /dev/null +++ b/src/com/gitblit/models/TeamAccessPermission.java @@ -0,0 +1,51 @@ +/* + * 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; + +/** + * Represents a Team-AccessPermission tuple. + * + * @author James Moger + */ +public class TeamAccessPermission implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String team; + public AccessPermission permission; + + public TeamAccessPermission() { + } + + public TeamAccessPermission(String team, AccessPermission permission) { + this.team = team; + this.permission = permission; + } + + @Override + public int compareTo(TeamAccessPermission p) { + return team.compareTo(p.team); + } + + @Override + public String toString() { + return permission.asRole("@" + team); + } +} \ No newline at end of file diff --git a/src/com/gitblit/models/UserAccessPermission.java b/src/com/gitblit/models/UserAccessPermission.java new file mode 100644 index 00000000..a77fff29 --- /dev/null +++ b/src/com/gitblit/models/UserAccessPermission.java @@ -0,0 +1,51 @@ +/* + * 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; + +/** + * Represents a User-AccessPermission tuple. + * + * @author James Moger + */ +public class UserAccessPermission implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String user; + public AccessPermission permission; + + public UserAccessPermission() { + } + + public UserAccessPermission(String user, AccessPermission permission) { + this.user = user; + this.permission = permission; + } + + @Override + public int compareTo(UserAccessPermission p) { + return user.compareTo(p.user); + } + + @Override + public String toString() { + return permission.asRole(user); + } +} \ 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 20b77e52..9a98e165 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -38,6 +38,7 @@
+

 

+ + + +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/src/com/gitblit/wicket/panels/TeamPermissionsPanel.java b/src/com/gitblit/wicket/panels/TeamPermissionsPanel.java new file mode 100644 index 00000000..e51aab47 --- /dev/null +++ b/src/com/gitblit/wicket/panels/TeamPermissionsPanel.java @@ -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.TeamAccessPermission; +import com.gitblit.utils.DeepCopier; + +/** + * Allows user to manipulate user access permissions. + * + * @author James Moger + * + */ +public class TeamPermissionsPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + public TeamPermissionsPanel(String wicketId, final List permissions, final Map translations) { + super(wicketId); + + // update existing permissions repeater + RefreshingView dataView = new RefreshingView("permissionRow") { + private static final long serialVersionUID = 1L; + + @Override + protected Iterator> getItemModels() { + // the iterator returns RepositoryPermission objects, but we need it to + // return models + return new ModelIteratorAdapter(permissions.iterator()) { + @Override + protected IModel model(TeamAccessPermission permission) { + return new CompoundPropertyModel(permission); + } + }; + } + + @Override + protected Item newItem(String id, int index, IModel model) { + // this item sets markup class attribute to either 'odd' or + // 'even' for decoration + return new OddEvenItem(id, index, model); + } + + public void populateItem(final Item item) { + final TeamAccessPermission entry = item.getModelObject(); + item.add(new Label("team", entry.team)); + + // 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 permissionChoice = new DropDownChoice( + "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 teams we already have permissions for + final List teams = GitBlit.self().getAllTeamnames(); + for (TeamAccessPermission tp : permissions) { + teams.remove(tp.team); + } + + // add new permission form + IModel addPermissionModel = new CompoundPropertyModel(new TeamAccessPermission()); + Form addPermissionForm = new Form("addPermissionForm", addPermissionModel); + addPermissionForm.add(new DropDownChoice("team", teams)); + addPermissionForm.add(new DropDownChoice("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 + TeamAccessPermission tp = (TeamAccessPermission) form.getModel().getObject(); + permissions.add(DeepCopier.copy(tp)); + + // remove team from available choices + teams.remove(tp.team); + + // force the panel to refresh + target.addComponent(TeamPermissionsPanel.this); + } + }; + addPermissionForm.add(button); + + // only show add permission form if we have a team choice + add(addPermissionForm.setVisible(teams.size() > 0)); + } + + private class AccessPermissionRenderer implements IChoiceRenderer { + + private static final long serialVersionUID = 1L; + + private final Map map; + + public AccessPermissionRenderer(Map 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); + } + } +} diff --git a/src/com/gitblit/wicket/panels/UserPermissionsPanel.html b/src/com/gitblit/wicket/panels/UserPermissionsPanel.html new file mode 100644 index 00000000..14d43055 --- /dev/null +++ b/src/com/gitblit/wicket/panels/UserPermissionsPanel.html @@ -0,0 +1,24 @@ + + + + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/src/com/gitblit/wicket/panels/UserPermissionsPanel.java b/src/com/gitblit/wicket/panels/UserPermissionsPanel.java new file mode 100644 index 00000000..6d0ae588 --- /dev/null +++ b/src/com/gitblit/wicket/panels/UserPermissionsPanel.java @@ -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.UserAccessPermission; +import com.gitblit.utils.DeepCopier; + +/** + * Allows user to manipulate user access permissions. + * + * @author James Moger + * + */ +public class UserPermissionsPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + public UserPermissionsPanel(String wicketId, final List permissions, final Map translations) { + super(wicketId); + + // update existing permissions repeater + RefreshingView dataView = new RefreshingView("permissionRow") { + private static final long serialVersionUID = 1L; + + @Override + protected Iterator> getItemModels() { + // the iterator returns RepositoryPermission objects, but we need it to + // return models + return new ModelIteratorAdapter(permissions.iterator()) { + @Override + protected IModel model(UserAccessPermission permission) { + return new CompoundPropertyModel(permission); + } + }; + } + + @Override + protected Item newItem(String id, int index, IModel model) { + // this item sets markup class attribute to either 'odd' or + // 'even' for decoration + return new OddEvenItem(id, index, model); + } + + public void populateItem(final Item item) { + final UserAccessPermission entry = item.getModelObject(); + item.add(new Label("user", entry.user)); + + // 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 permissionChoice = new DropDownChoice( + "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 users we already have permissions for + final List users = GitBlit.self().getAllUsernames(); + for (UserAccessPermission up : permissions) { + users.remove(up.user); + } + + // add new permission form + IModel addPermissionModel = new CompoundPropertyModel(new UserAccessPermission()); + Form addPermissionForm = new Form("addPermissionForm", addPermissionModel); + addPermissionForm.add(new DropDownChoice("user", users)); + addPermissionForm.add(new DropDownChoice("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 + UserAccessPermission up = (UserAccessPermission) form.getModel().getObject(); + permissions.add(DeepCopier.copy(up)); + + // remove user from available choices + users.remove(up.user); + + // force the panel to refresh + target.addComponent(UserPermissionsPanel.this); + } + }; + addPermissionForm.add(button); + + // only show add permission form if we have a user choice + add(addPermissionForm.setVisible(users.size() > 0)); + } + + private class AccessPermissionRenderer implements IChoiceRenderer { + + private static final long serialVersionUID = 1L; + + private final Map map; + + public AccessPermissionRenderer(Map 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); + } + } +} -- 2.39.5