source: branches/HiveProjectManagement/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs @ 15576

Last change on this file since 15576 was 15576, checked in by jzenisek, 4 years ago

#2839 worked on client side mgmt of project-resource assignments and project-user permissions

File size: 11.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Clients.Access;
28using HeuristicLab.Common.Resources;
29using HeuristicLab.Core.Views;
30using HeuristicLab.MainForm;
31
32namespace HeuristicLab.Clients.Hive.Administrator.Views {
33  [View("ProjectView")]
34  [Content(typeof(Project), IsDefaultView = false)]
35  public partial class ProjectPermissionsView : ItemView {
36    private const int userImageIndex = 0;
37    private const int userGroupImageIndex = 1;
38
39    private readonly HashSet<UserGroupBase> assignedPermissions = new HashSet<UserGroupBase>();
40    private readonly HashSet<UserGroupBase> inheritedPermissions = new HashSet<UserGroupBase>();
41    private readonly HashSet<UserGroupBase> newAssignedPermissions = new HashSet<UserGroupBase>();
42    private readonly HashSet<UserGroupBase> newInheritedPermissions = new HashSet<UserGroupBase>();
43    private readonly Dictionary<Guid, HashSet<UserGroupBase>> userGroupAncestors = new Dictionary<Guid, HashSet<UserGroupBase>>();
44    private readonly Dictionary<Guid, HashSet<UserGroupBase>> userGroupDescendants = new Dictionary<Guid, HashSet<UserGroupBase>>();
45
46    private readonly Color addedAssignmentColor = Color.FromArgb(255, 87, 191, 193); // #57bfc1
47    private readonly Color removedAssignmentColor = Color.FromArgb(255, 236, 159, 72); // #ec9f48
48    private readonly Color addedIncludeColor = Color.FromArgb(25, 169, 221, 221); // #a9dddd
49    private readonly Color removedIncludeColor = Color.FromArgb(25, 249, 210, 145); // #f9d291
50
51    public new Project Content {
52      get { return (Project)base.Content; }
53      set { base.Content = value; }
54    }
55
56    public ProjectPermissionsView() {
57      InitializeComponent();
58
59      treeView.ImageList.Images.Add(VSImageLibrary.User);
60      treeView.ImageList.Images.Add(VSImageLibrary.UserAccounts);
61    }
62
63    #region Overrides
64    protected override void OnContentChanged() {
65      base.OnContentChanged();
66      if (Content == null) {
67        assignedPermissions.Clear();
68        inheritedPermissions.Clear();
69        newAssignedPermissions.Clear();
70        newInheritedPermissions.Clear();
71        treeView.Nodes.Clear();
72        detailsViewHost.Content = null;
73      } else {
74        UpdatePermissionList();
75        detailsViewHost.ActiveView.Locked = true;
76      }
77    }
78    #endregion
79
80    #region Event Handlers
81    private void ProjectPermissionsView_Load(object sender, EventArgs e) {
82
83    }
84
85    private void refreshButton_Click(object sender, EventArgs e) {
86      UpdatePermissionList();
87    }
88
89    private async void inheritButton_Click(object sender, EventArgs e) {
90      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
91        action: () => SetGrantedProjectPermissions(Content.Id, newAssignedPermissions.Select(x => x.Id), false, true, true));
92      UpdatePermissionList();
93    }
94
95    private async void saveButton_Click(object sender, EventArgs e) {
96      await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
97        action: () => SetGrantedProjectPermissions(Content.Id, newAssignedPermissions.Select(x => x.Id), false, false, false));
98      UpdatePermissionList();
99    }
100
101    private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
102      var selectedPermission = (UserGroupBase)e.Node.Tag;
103      detailsViewHost.Content = selectedPermission;
104    }
105
106    private void treeView_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
107      var checkedPermission = (UserGroupBase)e.Node.Tag;
108      if (e.Node.Parent == null || newInheritedPermissions.Contains(checkedPermission) || checkedPermission.Id == Guid.Empty) e.Cancel = true;
109    }
110
111    private void treeView_AfterCheck(object sender, TreeViewEventArgs e) {
112      var checkedPermission = (UserGroupBase)e.Node.Tag;
113      if (e.Node.Checked)
114        newAssignedPermissions.Add(checkedPermission);
115      else
116        newAssignedPermissions.Remove(checkedPermission);
117
118      UpdateNewPermissionList();
119    }
120    #endregion
121
122    #region Helpers
123    private void UpdatePermissionList() {
124      UpdateUserGroupGenealogy();
125      UpdateAssignedPermissions();
126      UpdateInheritedPermissions();
127      var top = BuildPermissionsList(AccessClient.Instance.UsersAndGroups);
128      detailsViewHost.Content = top;
129    }
130
131    private void UpdateNewPermissionList() {
132      UpdateNewAssignedPermissions();
133      UpdateNewInheritedPermissions();
134      var top = BuildPermissionsList(AccessClient.Instance.UsersAndGroups);
135      detailsViewHost.Content = top;
136    }
137
138    private void UpdateAssignedPermissions() {
139      assignedPermissions.Clear();
140      newAssignedPermissions.Clear();
141      var grantedPermissions = GetGrantedPermissionsForProject(Content.Id);
142      foreach (var r in grantedPermissions) {
143        assignedPermissions.Add(r);
144        newAssignedPermissions.Add(r);
145      }
146    }
147
148    private void UpdateNewAssignedPermissions() {
149      for(int i = newAssignedPermissions.Count-1; i >= 0; i--) {
150        if(newAssignedPermissions.Intersect(userGroupAncestors[newAssignedPermissions.ElementAt(i).Id]).Any()) {
151          newAssignedPermissions.Remove(newAssignedPermissions.ElementAt(i));
152        }
153      }
154    }
155
156    private void UpdateInheritedPermissions() {
157      inheritedPermissions.Clear();
158      newInheritedPermissions.Clear();
159      foreach(var item in assignedPermissions) {
160        if(userGroupDescendants.ContainsKey(item.Id)) {
161          foreach(var descendant in userGroupDescendants[item.Id]) {
162            inheritedPermissions.Add(descendant);
163            newInheritedPermissions.Add(descendant);
164          }
165        }
166      }
167    }
168
169    private void UpdateNewInheritedPermissions() {
170      newInheritedPermissions.Clear();
171      foreach(var item in newAssignedPermissions) {
172        if(userGroupDescendants.ContainsKey(item.Id)) {
173          foreach(var descendant in userGroupDescendants[item.Id]) {
174            newInheritedPermissions.Add(descendant);
175          }
176        }
177      }
178    }
179
180    private void UpdateUserGroupGenealogy() {
181      userGroupAncestors.Clear();
182      userGroupDescendants.Clear();
183
184      var usersAndGroups = AccessClient.Instance.UsersAndGroups;
185      foreach (var ug in usersAndGroups) {
186        userGroupAncestors.Add(ug.Id, new HashSet<UserGroupBase>());
187        userGroupDescendants.Add(ug.Id, new HashSet<UserGroupBase>());
188      }
189
190      var userGroupTree = HiveServiceLocator.Instance.CallHiveService(s => s.GetUserGroupTree());
191      foreach(var branch in userGroupTree) {
192        var parent = usersAndGroups.Where(x => x.Id == branch.Key).SingleOrDefault();
193        if(parent != null) {
194          var userGroupsToAdd = usersAndGroups.Where(x => userGroupTree[parent.Id].Contains(x.Id));
195          foreach (var node in userGroupsToAdd) {
196            userGroupDescendants[parent.Id].Add(node);
197            userGroupAncestors[node.Id].Add(parent);
198          }
199        }
200      }
201    }
202
203    private static IEnumerable<UserGroupBase> GetGrantedPermissionsForProject(Guid projectId) {
204      var projectPermissions = HiveServiceLocator.Instance.CallHiveService(s => s.GetProjectPermissions(projectId));
205      var userIds = new HashSet<Guid>(projectPermissions.Select(x => x.GrantedUserId));
206      return AccessClient.Instance.UsersAndGroups.Where(x => userIds.Contains(x.Id));
207    }
208
209    private static void SetGrantedProjectPermissions(Guid projectId, IEnumerable<Guid> userIds, bool reassign, bool cascading, bool reassignCascading) {
210      if (projectId == null || userIds == null) return;
211      HiveServiceLocator.Instance.CallHiveService(s => {
212        s.SaveProjectPermissions(projectId, userIds.ToList(), reassign, cascading, reassignCascading);
213      });
214    }
215
216    private UserGroupBase BuildPermissionsList(IEnumerable<UserGroupBase> usersAndGroups) {
217      treeView.Nodes.Clear();
218      if (!usersAndGroups.Any()) return null;
219
220      treeView.BeforeCheck -= treeView_BeforeCheck;
221      treeView.AfterCheck -= treeView_AfterCheck;
222
223      var userGroups = new HashSet<UserGroup>(usersAndGroups.OfType<UserGroup>());
224      var users = new HashSet<LightweightUser>(usersAndGroups.OfType<LightweightUser>());
225      UserGroupBase first = null;
226
227      var groupsNode = new TreeNode("Groups") { ForeColor = SystemColors.GrayText };
228      groupsNode.ImageIndex = groupsNode.SelectedImageIndex = userGroupImageIndex;
229
230      foreach (var group in userGroups.OrderBy(x => x.Name)) {
231        var node = new TreeNode(group.Name) { Tag = group };
232        node.ImageIndex = userGroupImageIndex;
233        node.SelectedImageIndex = node.ImageIndex;
234        BuildNode(group, node);
235        groupsNode.Nodes.Add(node);
236        if (first == null) first = group;
237      }
238
239      var usersNode = new TreeNode("Users") { ForeColor = SystemColors.GrayText };
240      usersNode.ImageIndex = usersNode.SelectedImageIndex = userImageIndex;
241
242      foreach (var user in users.OrderBy(x => x.ToString())) {
243        var node = new TreeNode(user.ToString()) { Tag = user };
244        node.ImageIndex = userImageIndex;
245        node.SelectedImageIndex = node.ImageIndex;
246        BuildNode(user, node);
247        usersNode.Nodes.Add(node);
248        if (first == null) first = user;
249      }
250
251      treeView.Nodes.Add(groupsNode);
252      treeView.Nodes.Add(usersNode);
253      treeView.BeforeCheck += treeView_BeforeCheck;
254      treeView.AfterCheck += treeView_AfterCheck;
255      treeView.ExpandAll();
256
257      return first;
258    }
259
260    private void BuildNode(UserGroupBase ug, TreeNode node) {
261      var addedPermissions = newAssignedPermissions.Except(assignedPermissions);
262      var removedPermissions = assignedPermissions.Except(newAssignedPermissions);
263      var addedIncludes = newInheritedPermissions.Except(inheritedPermissions);
264      var removedIncludes = inheritedPermissions.Except(newInheritedPermissions);
265
266      if (newAssignedPermissions.Contains(ug)) {
267        node.Checked = true;
268      } else if (newInheritedPermissions.Contains(ug)) {
269        node.Checked = true;
270        node.ForeColor = SystemColors.GrayText;
271      }
272
273      if (inheritedPermissions.Contains(ug) && newInheritedPermissions.Contains(ug)) {
274        node.Text += " [included]";
275      } else if (addedIncludes.Contains(ug)) {
276        node.BackColor = addedIncludeColor;
277        node.ForeColor = SystemColors.GrayText;
278        node.Text += " [added include]";
279      } else if (removedIncludes.Contains(ug)) {
280        node.BackColor = removedIncludeColor;
281        node.ForeColor = SystemColors.GrayText;
282        node.Text += " [removed include]";
283      }
284
285      if (addedPermissions.Contains(ug)) {
286        node.BackColor = addedAssignmentColor;
287        node.ForeColor = SystemColors.ControlText;
288        node.Text += " [added assignment]";
289      } else if (removedPermissions.Contains(ug)) {
290        node.BackColor = removedAssignmentColor;
291        node.ForeColor = SystemColors.ControlText;
292        node.Text += " [removed assignment]";
293      }
294
295    }
296
297    #endregion
298  }
299}
Note: See TracBrowser for help on using the repository browser.