diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java deleted file mode 100644 index 1582d43958..0000000000 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (C) 2009 The Android Open Source Project -// -// 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.google.gerrit.server.project; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.gerrit.server.permissions.LabelPermission.ForUser.ON_BEHALF_OF; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.gerrit.common.Nullable; -import com.google.gerrit.common.data.LabelFunction; -import com.google.gerrit.common.data.LabelType; -import com.google.gerrit.common.data.PermissionRange; -import com.google.gerrit.extensions.restapi.AuthException; -import com.google.gerrit.reviewdb.client.Account; -import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.client.PatchSetApproval; -import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.ApprovalsUtil; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.PatchSetUtil; -import com.google.gerrit.server.notedb.ChangeNotes; -import com.google.gerrit.server.permissions.ChangePermission; -import com.google.gerrit.server.permissions.ChangePermissionOrLabel; -import com.google.gerrit.server.permissions.LabelPermission; -import com.google.gerrit.server.permissions.PermissionBackend.ForChange; -import com.google.gerrit.server.permissions.PermissionBackendException; -import com.google.gerrit.server.permissions.RefPermission; -import com.google.gerrit.server.query.change.ChangeData; -import com.google.gwtorm.server.OrmException; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; -import java.util.Set; - -/** Access control management for a user accessing a single change. */ -class ChangeControl { - @Singleton - static class Factory { - private final ChangeData.Factory changeDataFactory; - private final ChangeNotes.Factory notesFactory; - private final ApprovalsUtil approvalsUtil; - private final PatchSetUtil patchSetUtil; - - @Inject - Factory( - ChangeData.Factory changeDataFactory, - ChangeNotes.Factory notesFactory, - ApprovalsUtil approvalsUtil, - PatchSetUtil patchSetUtil) { - this.changeDataFactory = changeDataFactory; - this.notesFactory = notesFactory; - this.approvalsUtil = approvalsUtil; - this.patchSetUtil = patchSetUtil; - } - - ChangeControl create( - RefControl refControl, ReviewDb db, Project.NameKey project, Change.Id changeId) - throws OrmException { - return create(refControl, notesFactory.create(db, project, changeId)); - } - - ChangeControl create(RefControl refControl, ChangeNotes notes) { - return new ChangeControl(changeDataFactory, approvalsUtil, refControl, notes, patchSetUtil); - } - } - - private final ChangeData.Factory changeDataFactory; - private final ApprovalsUtil approvalsUtil; - private final RefControl refControl; - private final ChangeNotes notes; - private final PatchSetUtil patchSetUtil; - - ChangeControl( - ChangeData.Factory changeDataFactory, - ApprovalsUtil approvalsUtil, - RefControl refControl, - ChangeNotes notes, - PatchSetUtil patchSetUtil) { - this.changeDataFactory = changeDataFactory; - this.approvalsUtil = approvalsUtil; - this.refControl = refControl; - this.notes = notes; - this.patchSetUtil = patchSetUtil; - } - - ChangeControl forUser(CurrentUser who) { - if (getUser().equals(who)) { - return this; - } - return new ChangeControl( - changeDataFactory, approvalsUtil, getRefControl().forUser(who), notes, patchSetUtil); - } - - private RefControl getRefControl() { - return refControl; - } - - private CurrentUser getUser() { - return getRefControl().getUser(); - } - - private ProjectControl getProjectControl() { - return getRefControl().getProjectControl(); - } - - private Change getChange() { - return notes.getChange(); - } - - private ChangeNotes getNotes() { - return notes; - } - - /** Can this user see this change? */ - private boolean isVisible(ReviewDb db, @Nullable ChangeData cd) throws OrmException { - if (getChange().isPrivate() && !isPrivateVisible(db, cd)) { - return false; - } - return isRefVisible(); - } - - /** Can the user see this change? Does not account for draft status */ - private boolean isRefVisible() { - return getRefControl().isVisible(); - } - - /** Can this user abandon this change? */ - private boolean canAbandon(ReviewDb db) throws OrmException { - return (isOwner() // owner (aka creator) of the change can abandon - || getRefControl().isOwner() // branch owner can abandon - || getProjectControl().isOwner() // project owner can abandon - || getRefControl().canAbandon() // user can abandon a specific ref - || getProjectControl().isAdmin()) - && !isPatchSetLocked(db); - } - - /** Can this user delete this change? */ - private boolean canDelete(Change.Status status) { - switch (status) { - case NEW: - case ABANDONED: - return (getRefControl().canDeleteChanges(isOwner()) || getProjectControl().isAdmin()); - case MERGED: - default: - return false; - } - } - - /** Can this user rebase this change? */ - private boolean canRebase(ReviewDb db) throws OrmException { - return (isOwner() || getRefControl().canSubmit(isOwner()) || getRefControl().canRebase()) - && refControl.asForRef().testOrFalse(RefPermission.CREATE_CHANGE) - && !isPatchSetLocked(db); - } - - /** Can this user restore this change? */ - private boolean canRestore(ReviewDb db) throws OrmException { - // Anyone who can abandon the change can restore it, as long as they can create changes. - return canAbandon(db) && refControl.asForRef().testOrFalse(RefPermission.CREATE_CHANGE); - } - - /** The range of permitted values associated with a label permission. */ - private PermissionRange getRange(String permission) { - return getRefControl().getRange(permission, isOwner()); - } - - /** Can this user add a patch set to this change? */ - private boolean canAddPatchSet(ReviewDb db) throws OrmException { - if (!refControl.asForRef().testOrFalse(RefPermission.CREATE_CHANGE) || isPatchSetLocked(db)) { - return false; - } - if (isOwner()) { - return true; - } - return getRefControl().canAddPatchSet(); - } - - /** Is the current patch set locked against state changes? */ - private boolean isPatchSetLocked(ReviewDb db) throws OrmException { - if (getChange().getStatus() == Change.Status.MERGED) { - return false; - } - - for (PatchSetApproval ap : - approvalsUtil.byPatchSet( - db, getNotes(), getUser(), getChange().currentPatchSetId(), null, null)) { - LabelType type = - getProjectControl() - .getProjectState() - .getLabelTypes(getNotes(), getUser()) - .byLabel(ap.getLabel()); - if (type != null - && ap.getValue() == 1 - && type.getFunction() == LabelFunction.PATCH_SET_LOCK) { - return true; - } - } - return false; - } - - /** Is this user the owner of the change? */ - private boolean isOwner() { - if (getUser().isIdentifiedUser()) { - Account.Id id = getUser().asIdentifiedUser().getAccountId(); - return id.equals(getChange().getOwner()); - } - return false; - } - - /** Is this user assigned to this change? */ - private boolean isAssignee() { - Account.Id currentAssignee = notes.getChange().getAssignee(); - if (currentAssignee != null && getUser().isIdentifiedUser()) { - Account.Id id = getUser().getAccountId(); - return id.equals(currentAssignee); - } - return false; - } - - /** Is this user a reviewer for the change? */ - private boolean isReviewer(ReviewDb db, @Nullable ChangeData cd) throws OrmException { - if (getUser().isIdentifiedUser()) { - Collection<Account.Id> results = changeData(db, cd).reviewers().all(); - return results.contains(getUser().getAccountId()); - } - return false; - } - - /** Can this user edit the topic name? */ - private boolean canEditTopicName() { - if (getChange().getStatus().isOpen()) { - return isOwner() // owner (aka creator) of the change can edit topic - || getRefControl().isOwner() // branch owner can edit topic - || getProjectControl().isOwner() // project owner can edit topic - || getRefControl().canEditTopicName() // user can edit topic on a specific ref - || getProjectControl().isAdmin(); - } - return getRefControl().canForceEditTopicName(); - } - - /** Can this user edit the description? */ - private boolean canEditDescription() { - if (getChange().getStatus().isOpen()) { - return isOwner() // owner (aka creator) of the change can edit desc - || getRefControl().isOwner() // branch owner can edit desc - || getProjectControl().isOwner() // project owner can edit desc - || getProjectControl().isAdmin(); - } - return false; - } - - private boolean canEditAssignee() { - return isOwner() - || getProjectControl().isOwner() - || getRefControl().canEditAssignee() - || isAssignee(); - } - - /** Can this user edit the hashtag name? */ - private boolean canEditHashtags() { - return isOwner() // owner (aka creator) of the change can edit hashtags - || getRefControl().isOwner() // branch owner can edit hashtags - || getProjectControl().isOwner() // project owner can edit hashtags - || getRefControl().canEditHashtags() // user can edit hashtag on a specific ref - || getProjectControl().isAdmin(); - } - - private ChangeData changeData(ReviewDb db, @Nullable ChangeData cd) { - return cd != null ? cd : changeDataFactory.create(db, getNotes()); - } - - private boolean isPrivateVisible(ReviewDb db, ChangeData cd) throws OrmException { - return isOwner() - || isReviewer(db, cd) - || getRefControl().canViewPrivateChanges() - || getUser().isInternalUser(); - } - - ForChange asForChange(@Nullable ChangeData cd, @Nullable Provider<ReviewDb> db) { - return new ForChangeImpl(cd, db); - } - - private class ForChangeImpl extends ForChange { - private ChangeData cd; - private Map<String, PermissionRange> labels; - - ForChangeImpl(@Nullable ChangeData cd, @Nullable Provider<ReviewDb> db) { - this.cd = cd; - this.db = db; - } - - private ReviewDb db() { - if (db != null) { - return db.get(); - } else if (cd != null) { - return cd.db(); - } else { - return null; - } - } - - private ChangeData changeData() { - if (cd == null) { - ReviewDb reviewDb = db(); - checkState(reviewDb != null, "need ReviewDb"); - cd = changeDataFactory.create(reviewDb, getNotes()); - } - return cd; - } - - @Override - public CurrentUser user() { - return getUser(); - } - - @Override - public ForChange user(CurrentUser user) { - return user().equals(user) ? this : forUser(user).asForChange(cd, db); - } - - @Override - public void check(ChangePermissionOrLabel perm) - throws AuthException, PermissionBackendException { - if (!can(perm)) { - throw new AuthException(perm.describeForException() + " not permitted"); - } - } - - @Override - public <T extends ChangePermissionOrLabel> Set<T> test(Collection<T> permSet) - throws PermissionBackendException { - Set<T> ok = newSet(permSet); - for (T perm : permSet) { - if (can(perm)) { - ok.add(perm); - } - } - return ok; - } - - private boolean can(ChangePermissionOrLabel perm) throws PermissionBackendException { - if (perm instanceof ChangePermission) { - return can((ChangePermission) perm); - } else if (perm instanceof LabelPermission) { - return can((LabelPermission) perm); - } else if (perm instanceof LabelPermission.WithValue) { - return can((LabelPermission.WithValue) perm); - } - throw new PermissionBackendException(perm + " unsupported"); - } - - private boolean can(ChangePermission perm) throws PermissionBackendException { - try { - switch (perm) { - case READ: - return isVisible(db(), changeData()); - case ABANDON: - return canAbandon(db()); - case DELETE: - return canDelete(getChange().getStatus()); - case ADD_PATCH_SET: - return canAddPatchSet(db()); - case EDIT_ASSIGNEE: - return canEditAssignee(); - case EDIT_DESCRIPTION: - return canEditDescription(); - case EDIT_HASHTAGS: - return canEditHashtags(); - case EDIT_TOPIC_NAME: - return canEditTopicName(); - case REBASE: - return canRebase(db()); - case RESTORE: - return canRestore(db()); - case SUBMIT: - return getRefControl().canSubmit(isOwner()); - - case REMOVE_REVIEWER: - case SUBMIT_AS: - return getRefControl().canPerform(perm.permissionName().get()); - } - } catch (OrmException e) { - throw new PermissionBackendException("unavailable", e); - } - throw new PermissionBackendException(perm + " unsupported"); - } - - private boolean can(LabelPermission perm) { - return !label(perm.permissionName().get()).isEmpty(); - } - - private boolean can(LabelPermission.WithValue perm) { - PermissionRange r = label(perm.permissionName().get()); - if (perm.forUser() == ON_BEHALF_OF && r.isEmpty()) { - return false; - } - return r.contains(perm.value()); - } - - private PermissionRange label(String permission) { - if (labels == null) { - labels = Maps.newHashMapWithExpectedSize(4); - } - PermissionRange r = labels.get(permission); - if (r == null) { - r = getRange(permission); - labels.put(permission, r); - } - return r; - } - } - - static <T extends ChangePermissionOrLabel> Set<T> newSet(Collection<T> permSet) { - if (permSet instanceof EnumSet) { - @SuppressWarnings({"unchecked", "rawtypes"}) - Set<T> s = ((EnumSet) permSet).clone(); - s.clear(); - return s; - } - return Sets.newHashSetWithExpectedSize(permSet.size()); - } -} |