blob: 06f15c22d3fc55e130154e9b8dd904095a1a3652 [file] [log] [blame]
// Copyright (C) 2010 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.httpd.rpc.project;
import com.google.gerrit.common.data.ApprovalType;
import com.google.gerrit.common.data.ApprovalTypes;
import com.google.gerrit.common.data.ProjectDetail;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.RefRight;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.NoSuchGroupException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.NoSuchRefException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import java.util.Collections;
import javax.annotation.Nullable;
class AddRefRight extends Handler<ProjectDetail> {
interface Factory {
AddRefRight create(@Assisted Project.NameKey projectName,
@Assisted ApprovalCategory.Id categoryId,
@Assisted("groupName") String groupName,
@Nullable @Assisted("refPattern") String refPattern,
@Assisted("min") short min, @Assisted("max") short max);
}
private final ProjectDetailFactory.Factory projectDetailFactory;
private final ProjectControl.Factory projectControlFactory;
private final ProjectCache projectCache;
private final GroupCache groupCache;
private final ReviewDb db;
private final ApprovalTypes approvalTypes;
private final Project.NameKey projectName;
private final ApprovalCategory.Id categoryId;
private final AccountGroup.NameKey groupName;
private final String refPattern;
private final short min;
private final short max;
@Inject
AddRefRight(final ProjectDetailFactory.Factory projectDetailFactory,
final ProjectControl.Factory projectControlFactory,
final ProjectCache projectCache, final GroupCache groupCache,
final ReviewDb db, final ApprovalTypes approvalTypes,
@Assisted final Project.NameKey projectName,
@Assisted final ApprovalCategory.Id categoryId,
@Assisted("groupName") final String groupName,
@Nullable @Assisted("refPattern") final String refPattern,
@Assisted("min") final short min, @Assisted("max") final short max) {
this.projectDetailFactory = projectDetailFactory;
this.projectControlFactory = projectControlFactory;
this.projectCache = projectCache;
this.groupCache = groupCache;
this.approvalTypes = approvalTypes;
this.db = db;
this.projectName = projectName;
this.categoryId = categoryId;
this.groupName = new AccountGroup.NameKey(groupName);
this.refPattern = refPattern != null ? refPattern.trim() : null;
if (min <= max) {
this.min = min;
this.max = max;
} else {
this.min = max;
this.max = min;
}
}
@Override
public ProjectDetail call() throws NoSuchProjectException, OrmException,
NoSuchGroupException, InvalidNameException, NoSuchRefException {
final ProjectControl projectControl =
projectControlFactory.controlFor(projectName);
final ApprovalType at = approvalTypes.getApprovalType(categoryId);
if (at == null || at.getValue(min) == null || at.getValue(max) == null) {
throw new IllegalArgumentException("Invalid category " + categoryId
+ " or range " + min + ".." + max);
}
String refPattern = this.refPattern;
if (refPattern == null || refPattern.isEmpty()) {
if (categoryId.equals(ApprovalCategory.SUBMIT)
|| categoryId.equals(ApprovalCategory.PUSH_HEAD)) {
// Explicitly related to a branch head.
refPattern = Constants.R_HEADS + "*";
} else if (!at.getCategory().isAction()) {
// Non actions are approval votes on a change, assume these apply
// to branch heads only.
refPattern = Constants.R_HEADS + "*";
} else if (categoryId.equals(ApprovalCategory.PUSH_TAG)) {
// Explicitly related to the tag namespace.
refPattern = Constants.R_TAGS + "*";
} else if (categoryId.equals(ApprovalCategory.READ)
|| categoryId.equals(ApprovalCategory.OWN)) {
// Currently these are project-wide rights, so apply that way.
refPattern = RefRight.ALL;
} else {
// Assume project wide for the default.
refPattern = RefRight.ALL;
}
}
boolean exclusive = refPattern.startsWith("-");
if (exclusive) {
refPattern = refPattern.substring(1);
}
while (refPattern.startsWith("/")) {
refPattern = refPattern.substring(1);
}
if (!refPattern.startsWith(Constants.R_REFS)) {
refPattern = Constants.R_HEADS + refPattern;
}
if (refPattern.endsWith("/*")) {
final String prefix = refPattern.substring(0, refPattern.length() - 2);
if (!"refs".equals(prefix) && !Repository.isValidRefName(prefix)) {
throw new InvalidNameException();
}
} else {
if (!Repository.isValidRefName(refPattern)) {
throw new InvalidNameException();
}
}
if (exclusive) {
refPattern = "-" + refPattern;
}
if (!controlForRef(projectControl, refPattern).isOwner()) {
throw new NoSuchRefException(refPattern);
}
final AccountGroup group = groupCache.get(groupName);
if (group == null) {
throw new NoSuchGroupException(groupName);
}
final RefRight.Key key =
new RefRight.Key(projectName, new RefRight.RefPattern(refPattern),
categoryId, group.getId());
RefRight rr = db.refRights().get(key);
if (rr == null) {
rr = new RefRight(key);
rr.setMinValue(min);
rr.setMaxValue(max);
db.refRights().insert(Collections.singleton(rr));
} else {
rr.setMinValue(min);
rr.setMaxValue(max);
db.refRights().update(Collections.singleton(rr));
}
projectCache.evictAll();
return projectDetailFactory.create(projectName).call();
}
private RefControl controlForRef(ProjectControl p, String ref) {
if (ref.endsWith("/*")) {
ref = ref.substring(0, ref.length() - 1);
}
return p.controlForRef(ref);
}
}