/* * Copyright 2011 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 java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AccountType; import com.gitblit.Constants.PermissionType; import com.gitblit.Constants.RegistrantType; import com.gitblit.Constants.Unused; import com.gitblit.utils.StringUtils; /** * TeamModel is a serializable model class that represents a group of users and * a list of accessible repositories. * * @author James Moger * */ public class TeamModel implements Serializable, Comparable { private static final long serialVersionUID = 1L; // field names are reflectively mapped in EditTeam page public String name; public boolean canAdmin; public boolean canFork; public boolean canCreate; public AccountType accountType; public final Set users = new HashSet(); // retained for backwards-compatibility with RPC clients @Deprecated public final Set repositories = new HashSet(); public final Map permissions = new LinkedHashMap(); public final Set mailingLists = new HashSet(); public final List preReceiveScripts = new ArrayList(); public final List postReceiveScripts = new ArrayList(); public TeamModel(String name) { this.name = name; this.accountType = AccountType.LOCAL; } /** * @use hasRepositoryPermission * @param name * @return */ @Deprecated @Unused public boolean hasRepository(String name) { return hasRepositoryPermission(name); } @Deprecated @Unused public void addRepository(String name) { addRepositoryPermission(name); } @Deprecated @Unused public void addRepositories(Collection names) { addRepositoryPermissions(names); } @Deprecated @Unused public void removeRepository(String name) { removeRepositoryPermission(name); } /** * Returns a list of repository permissions for this team. * * @return the team's list of permissions */ public List getRepositoryPermissions() { List list = new ArrayList(); if (canAdmin) { // team has REWIND access to all repositories return list; } for (Map.Entry entry : permissions.entrySet()) { String registrant = entry.getKey(); String source = null; boolean editable = true; PermissionType pType = PermissionType.EXPLICIT; if (StringUtils.findInvalidCharacter(registrant) != null) { // a regex will have at least 1 invalid character pType = PermissionType.REGEX; source = registrant; } list.add(new RegistrantAccessPermission(registrant, entry.getValue(), pType, RegistrantType.REPOSITORY, source, editable)); } Collections.sort(list); return list; } /** * Returns true if the team has any type of specified access permission for * this repository. * * @param name * @return true if team has a specified access permission for the repository */ public boolean hasRepositoryPermission(String name) { String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); if (permissions.containsKey(repository)) { // exact repository permission specified return true; } else { // search for regex permission match for (String key : permissions.keySet()) { if (name.matches(key)) { AccessPermission p = permissions.get(key); if (p != null) { return true; } } } } return false; } /** * Returns true if the team has an explicitly specified access permission for * this repository. * * @param name * @return if the team has an explicitly specified access permission */ public boolean hasExplicitRepositoryPermission(String name) { String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); return permissions.containsKey(repository); } /** * Adds a repository permission to the team. *

* Role may be formatted as: *

    *
  • myrepo.git (this is implicitly RW+) *
  • RW+:myrepo.git *
* @param role */ public void addRepositoryPermission(String role) { AccessPermission permission = AccessPermission.permissionFromRole(role); String repository = AccessPermission.repositoryFromRole(role).toLowerCase(); repositories.add(repository); permissions.put(repository, permission); } public void addRepositoryPermissions(Collection roles) { for (String role:roles) { addRepositoryPermission(role); } } public AccessPermission removeRepositoryPermission(String name) { String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); repositories.remove(repository); return permissions.remove(repository); } public void setRepositoryPermission(String repository, AccessPermission permission) { if (permission == null) { // remove the permission permissions.remove(repository.toLowerCase()); repositories.remove(repository.toLowerCase()); } else { // set the new permission permissions.put(repository.toLowerCase(), permission); repositories.add(repository.toLowerCase()); } } public RegistrantAccessPermission getRepositoryPermission(RepositoryModel repository) { RegistrantAccessPermission ap = new RegistrantAccessPermission(); ap.registrant = name; ap.registrantType = RegistrantType.TEAM; ap.permission = AccessPermission.NONE; ap.mutable = false; // determine maximum permission for the repository final AccessPermission maxPermission = (repository.isFrozen || !repository.isBare || repository.isMirror) ? AccessPermission.CLONE : AccessPermission.REWIND; if (AccessRestrictionType.NONE.equals(repository.accessRestriction)) { // anonymous rewind ap.permissionType = PermissionType.ANONYMOUS; if (AccessPermission.REWIND.atMost(maxPermission)) { ap.permission = AccessPermission.REWIND; } else { ap.permission = maxPermission; } return ap; } if (canAdmin) { ap.permissionType = PermissionType.ADMINISTRATOR; if (AccessPermission.REWIND.atMost(maxPermission)) { ap.permission = AccessPermission.REWIND; } else { ap.permission = maxPermission; } return ap; } if (permissions.containsKey(repository.name.toLowerCase())) { // exact repository permission specified AccessPermission p = permissions.get(repository.name.toLowerCase()); if (p != null && repository.accessRestriction.isValidPermission(p)) { ap.permissionType = PermissionType.EXPLICIT; if (p.atMost(maxPermission)) { ap.permission = p; } else { ap.permission = maxPermission; } ap.mutable = true; return ap; } } else { // search for case-insensitive regex permission match for (String key : permissions.keySet()) { if (StringUtils.matchesIgnoreCase(repository.name, key)) { AccessPermission p = permissions.get(key); if (p != null && repository.accessRestriction.isValidPermission(p)) { // take first match ap.permissionType = PermissionType.REGEX; if (p.atMost(maxPermission)) { ap.permission = p; } else { ap.permission = maxPermission; } ap.source = key; return ap; } } } } // still no explicit or regex, check for implicit permissions if (AccessPermission.NONE == ap.permission) { switch (repository.accessRestriction) { case VIEW: // no implicit permissions possible break; case CLONE: // implied view permission ap.permission = AccessPermission.VIEW; ap.permissionType = PermissionType.ANONYMOUS; break; case PUSH: // implied clone permission ap.permission = AccessPermission.CLONE; ap.permissionType = PermissionType.ANONYMOUS; break; case NONE: // implied REWIND or CLONE ap.permission = maxPermission; ap.permissionType = PermissionType.ANONYMOUS; break; } } return ap; } protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) { if (repository.accessRestriction.atLeast(ifRestriction)) { RegistrantAccessPermission ap = getRepositoryPermission(repository); return ap.permission.atLeast(requirePermission); } return true; } public boolean canView(RepositoryModel repository) { return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW); } public boolean canClone(RepositoryModel repository) { return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE); } public boolean canPush(RepositoryModel repository) { if (repository.isFrozen) { return false; } return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH); } public boolean canCreateRef(RepositoryModel repository) { if (repository.isFrozen) { return false; } return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE); } public boolean canDeleteRef(RepositoryModel repository) { if (repository.isFrozen) { return false; } return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE); } public boolean canRewindRef(RepositoryModel repository) { if (repository.isFrozen) { return false; } return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND); } public boolean hasUser(String name) { return users.contains(name.toLowerCase()); } public void addUser(String name) { users.add(name.toLowerCase()); } public void addUsers(Collection names) { for (String name:names) { users.add(name.toLowerCase()); } } public void removeUser(String name) { users.remove(name.toLowerCase()); } public void addMailingLists(Collection addresses) { for (String address:addresses) { mailingLists.add(address.toLowerCase()); } } public boolean isLocalTeam() { return accountType.isLocal(); } @Override public String toString() { return name; } @Override public int compareTo(TeamModel o) { return name.compareTo(o.name); } }