James Moger
2013-11-20 8f1c9fd7e0f7ea3d7d0b87788eb92ba2f0f09d59
commit | author | age
fe24a0 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit.models;
17
18 import java.io.Serializable;
d7905a 19 import java.util.ArrayList;
fe24a0 20 import java.util.Collection;
b0e164 21 import java.util.Collections;
fe24a0 22 import java.util.HashSet;
2bfb8a 23 import java.util.LinkedHashMap;
0b9119 24 import java.util.List;
20714a 25 import java.util.Map;
fe24a0 26 import java.util.Set;
20714a 27
JM 28 import com.gitblit.Constants.AccessPermission;
29 import com.gitblit.Constants.AccessRestrictionType;
092f0a 30 import com.gitblit.Constants.PermissionType;
822dfe 31 import com.gitblit.Constants.RegistrantType;
20714a 32 import com.gitblit.Constants.Unused;
e5aaa5 33 import com.gitblit.utils.StringUtils;
fe24a0 34
JM 35 /**
36  * TeamModel is a serializable model class that represents a group of users and
37  * a list of accessible repositories.
699e71 38  *
fe24a0 39  * @author James Moger
699e71 40  *
fe24a0 41  */
JM 42 public class TeamModel implements Serializable, Comparable<TeamModel> {
43
44     private static final long serialVersionUID = 1L;
45
46     // field names are reflectively mapped in EditTeam page
47     public String name;
7f7051 48     public boolean canAdmin;
JM 49     public boolean canFork;
50     public boolean canCreate;
fe24a0 51     public final Set<String> users = new HashSet<String>();
20714a 52     // retained for backwards-compatibility with RPC clients
JM 53     @Deprecated
fe24a0 54     public final Set<String> repositories = new HashSet<String>();
2bfb8a 55     public final Map<String, AccessPermission> permissions = new LinkedHashMap<String, AccessPermission>();
0b9119 56     public final Set<String> mailingLists = new HashSet<String>();
d7905a 57     public final List<String> preReceiveScripts = new ArrayList<String>();
JM 58     public final List<String> postReceiveScripts = new ArrayList<String>();
fe24a0 59
JM 60     public TeamModel(String name) {
61         this.name = name;
62     }
63
20714a 64     /**
JM 65      * @use hasRepositoryPermission
66      * @param name
67      * @return
68      */
69     @Deprecated
70     @Unused
fe24a0 71     public boolean hasRepository(String name) {
20714a 72         return hasRepositoryPermission(name);
fe24a0 73     }
JM 74
20714a 75     @Deprecated
JM 76     @Unused
fe24a0 77     public void addRepository(String name) {
20714a 78         addRepositoryPermission(name);
fe24a0 79     }
699e71 80
20714a 81     @Deprecated
JM 82     @Unused
fe24a0 83     public void addRepositories(Collection<String> names) {
20714a 84         addRepositoryPermissions(names);
JM 85     }
fe24a0 86
20714a 87     @Deprecated
JM 88     @Unused
fe24a0 89     public void removeRepository(String name) {
20714a 90         removeRepositoryPermission(name);
fe24a0 91     }
b0e164 92
699e71 93
b0e164 94     /**
JM 95      * Returns a list of repository permissions for this team.
699e71 96      *
b0e164 97      * @return the team's list of permissions
JM 98      */
822dfe 99     public List<RegistrantAccessPermission> getRepositoryPermissions() {
JM 100         List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
b701ed 101         if (canAdmin) {
JM 102             // team has REWIND access to all repositories
103             return list;
104         }
b0e164 105         for (Map.Entry<String, AccessPermission> entry : permissions.entrySet()) {
092f0a 106             String registrant = entry.getKey();
644bdd 107             String source = null;
092f0a 108             boolean editable = true;
JM 109             PermissionType pType = PermissionType.EXPLICIT;
110             if (StringUtils.findInvalidCharacter(registrant) != null) {
111                 // a regex will have at least 1 invalid character
112                 pType = PermissionType.REGEX;
644bdd 113                 source = registrant;
092f0a 114             }
644bdd 115             list.add(new RegistrantAccessPermission(registrant, entry.getValue(), pType, RegistrantType.REPOSITORY, source, editable));
b0e164 116         }
JM 117         Collections.sort(list);
118         return list;
119     }
699e71 120
20714a 121     /**
JM 122      * Returns true if the team has any type of specified access permission for
123      * this repository.
699e71 124      *
20714a 125      * @param name
JM 126      * @return true if team has a specified access permission for the repository
127      */
128     public boolean hasRepositoryPermission(String name) {
129         String repository = AccessPermission.repositoryFromRole(name).toLowerCase();
58e7ec 130         if (permissions.containsKey(repository)) {
JM 131             // exact repository permission specified
132             return true;
133         } else {
134             // search for regex permission match
135             for (String key : permissions.keySet()) {
136                 if (name.matches(key)) {
137                     AccessPermission p = permissions.get(key);
138                     if (p != null) {
139                         return true;
140                     }
141                 }
142             }
143         }
144         return false;
20714a 145     }
699e71 146
20714a 147     /**
87f6c3 148      * Returns true if the team has an explicitly specified access permission for
JM 149      * this repository.
699e71 150      *
87f6c3 151      * @param name
JM 152      * @return if the team has an explicitly specified access permission
153      */
154     public boolean hasExplicitRepositoryPermission(String name) {
155         String repository = AccessPermission.repositoryFromRole(name).toLowerCase();
156         return permissions.containsKey(repository);
157     }
699e71 158
87f6c3 159     /**
20714a 160      * Adds a repository permission to the team.
JM 161      * <p>
162      * Role may be formatted as:
163      * <ul>
164      * <li> myrepo.git <i>(this is implicitly RW+)</i>
165      * <li> RW+:myrepo.git
166      * </ul>
167      * @param role
168      */
169     public void addRepositoryPermission(String role) {
170         AccessPermission permission = AccessPermission.permissionFromRole(role);
171         String repository = AccessPermission.repositoryFromRole(role).toLowerCase();
172         repositories.add(repository);
173         permissions.put(repository, permission);
174     }
175
176     public void addRepositoryPermissions(Collection<String> roles) {
177         for (String role:roles) {
178             addRepositoryPermission(role);
179         }
180     }
699e71 181
20714a 182     public AccessPermission removeRepositoryPermission(String name) {
JM 183         String repository = AccessPermission.repositoryFromRole(name).toLowerCase();
184         repositories.remove(repository);
185         return permissions.remove(repository);
186     }
699e71 187
20714a 188     public void setRepositoryPermission(String repository, AccessPermission permission) {
139c6d 189         if (permission == null) {
JM 190             // remove the permission
191             permissions.remove(repository.toLowerCase());
192             repositories.remove(repository.toLowerCase());
193         } else {
194             // set the new permission
195             permissions.put(repository.toLowerCase(), permission);
196             repositories.add(repository.toLowerCase());
197         }
20714a 198     }
699e71 199
644bdd 200     public RegistrantAccessPermission getRepositoryPermission(RepositoryModel repository) {
JM 201         RegistrantAccessPermission ap = new RegistrantAccessPermission();
202         ap.registrant = name;
203         ap.registrantType = RegistrantType.TEAM;
204         ap.permission = AccessPermission.NONE;
40b07b 205         ap.mutable = false;
699e71 206
9715e1 207         // determine maximum permission for the repository
699e71 208         final AccessPermission maxPermission =
c44dd0 209                 (repository.isFrozen || !repository.isBare || repository.isMirror) ?
9715e1 210                         AccessPermission.CLONE : AccessPermission.REWIND;
JM 211
9a6a42 212         if (AccessRestrictionType.NONE.equals(repository.accessRestriction)) {
JM 213             // anonymous rewind
214             ap.permissionType = PermissionType.ANONYMOUS;
9715e1 215             if (AccessPermission.REWIND.atMost(maxPermission)) {
JM 216                 ap.permission = AccessPermission.REWIND;
217             } else {
218                 ap.permission = maxPermission;
219             }
9a6a42 220             return ap;
JM 221         }
699e71 222
644bdd 223         if (canAdmin) {
JM 224             ap.permissionType = PermissionType.ADMINISTRATOR;
9715e1 225             if (AccessPermission.REWIND.atMost(maxPermission)) {
JM 226                 ap.permission = AccessPermission.REWIND;
227             } else {
228                 ap.permission = maxPermission;
229             }
644bdd 230             return ap;
JM 231         }
699e71 232
20714a 233         if (permissions.containsKey(repository.name.toLowerCase())) {
5d7545 234             // exact repository permission specified
20714a 235             AccessPermission p = permissions.get(repository.name.toLowerCase());
9a6a42 236             if (p != null && repository.accessRestriction.isValidPermission(p)) {
644bdd 237                 ap.permissionType = PermissionType.EXPLICIT;
9715e1 238                 if (p.atMost(maxPermission)) {
JM 239                     ap.permission = p;
240                 } else {
241                     ap.permission = maxPermission;
242                 }
40b07b 243                 ap.mutable = true;
644bdd 244                 return ap;
20714a 245             }
5d7545 246         } else {
e5aaa5 247             // search for case-insensitive regex permission match
5d7545 248             for (String key : permissions.keySet()) {
e5aaa5 249                 if (StringUtils.matchesIgnoreCase(repository.name, key)) {
5d7545 250                     AccessPermission p = permissions.get(key);
9a6a42 251                     if (p != null && repository.accessRestriction.isValidPermission(p)) {
2bfb8a 252                         // take first match
644bdd 253                         ap.permissionType = PermissionType.REGEX;
9715e1 254                         if (p.atMost(maxPermission)) {
JM 255                             ap.permission = p;
256                         } else {
257                             ap.permission = maxPermission;
258                         }
644bdd 259                         ap.source = key;
JM 260                         return ap;
5d7545 261                     }
JM 262                 }
263             }
20714a 264         }
699e71 265
9a6a42 266         // still no explicit or regex, check for implicit permissions
JM 267         if (AccessPermission.NONE == ap.permission) {
268             switch (repository.accessRestriction) {
269             case VIEW:
270                 // no implicit permissions possible
271                 break;
272             case CLONE:
273                 // implied view permission
274                 ap.permission = AccessPermission.VIEW;
275                 ap.permissionType = PermissionType.ANONYMOUS;
276                 break;
277             case PUSH:
278                 // implied clone permission
279                 ap.permission = AccessPermission.CLONE;
280                 ap.permissionType = PermissionType.ANONYMOUS;
281                 break;
282             case NONE:
9715e1 283                 // implied REWIND or CLONE
JM 284                 ap.permission = maxPermission;
9a6a42 285                 ap.permissionType = PermissionType.ANONYMOUS;
JM 286                 break;
287             }
288         }
289
644bdd 290         return ap;
20714a 291     }
699e71 292
2bfb8a 293     protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) {
20714a 294         if (repository.accessRestriction.atLeast(ifRestriction)) {
644bdd 295             RegistrantAccessPermission ap = getRepositoryPermission(repository);
JM 296             return ap.permission.atLeast(requirePermission);
20714a 297         }
JM 298         return true;
299     }
699e71 300
20714a 301     public boolean canView(RepositoryModel repository) {
JM 302         return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW);
303     }
304
305     public boolean canClone(RepositoryModel repository) {
306         return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE);
307     }
308
309     public boolean canPush(RepositoryModel repository) {
310         if (repository.isFrozen) {
311             return false;
312         }
313         return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH);
314     }
315
316     public boolean canCreateRef(RepositoryModel repository) {
317         if (repository.isFrozen) {
318             return false;
319         }
320         return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE);
321     }
322
323     public boolean canDeleteRef(RepositoryModel repository) {
324         if (repository.isFrozen) {
325             return false;
326         }
327         return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE);
328     }
329
330     public boolean canRewindRef(RepositoryModel repository) {
331         if (repository.isFrozen) {
332             return false;
333         }
334         return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND);
335     }
336
fe24a0 337     public boolean hasUser(String name) {
JM 338         return users.contains(name.toLowerCase());
339     }
340
341     public void addUser(String name) {
342         users.add(name.toLowerCase());
343     }
344
345     public void addUsers(Collection<String> names) {
346         for (String name:names) {
347             users.add(name.toLowerCase());
348         }
349     }
350
351     public void removeUser(String name) {
352         users.remove(name.toLowerCase());
353     }
354
0b9119 355     public void addMailingLists(Collection<String> addresses) {
JM 356         for (String address:addresses) {
357             mailingLists.add(address.toLowerCase());
358         }
359     }
360
fe24a0 361     @Override
JM 362     public String toString() {
363         return name;
364     }
365
366     @Override
367     public int compareTo(TeamModel o) {
368         return name.compareTo(o.name);
369     }
370 }