Merge "Reject invalid hashtags with 400 Bad Request"
This commit is contained in:
@@ -30,6 +30,7 @@ import com.google.gerrit.common.data.Permission;
|
|||||||
import com.google.gerrit.extensions.api.changes.HashtagsInput;
|
import com.google.gerrit.extensions.api.changes.HashtagsInput;
|
||||||
import com.google.gerrit.extensions.common.ChangeMessageInfo;
|
import com.google.gerrit.extensions.common.ChangeMessageInfo;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.testutil.TestTimeUtil;
|
import com.google.gerrit.testutil.TestTimeUtil;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -76,6 +77,15 @@ public class HashtagsIT extends AbstractDaemonTest {
|
|||||||
assertMessage(r, "Hashtag added: tag1");
|
assertMessage(r, "Hashtag added: tag1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addInvalidHashtag() throws Exception {
|
||||||
|
PushOneCommit.Result r = createChange();
|
||||||
|
|
||||||
|
exception.expect(BadRequestException.class);
|
||||||
|
exception.expectMessage("hashtags may not contain commas");
|
||||||
|
addHashtags(r, "invalid,hashtag");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addMultipleHashtags() throws Exception {
|
public void addMultipleHashtags() throws Exception {
|
||||||
PushOneCommit.Result r = createChange();
|
PushOneCommit.Result r = createChange();
|
||||||
|
|||||||
@@ -23,6 +23,18 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class HashtagsUtil {
|
public class HashtagsUtil {
|
||||||
|
public static class InvalidHashtagException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
static InvalidHashtagException hashtagsMayNotContainCommas() {
|
||||||
|
return new InvalidHashtagException("hashtags may not contain commas");
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidHashtagException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final CharMatcher LEADER = CharMatcher.whitespace().or(CharMatcher.is('#'));
|
private static final CharMatcher LEADER = CharMatcher.whitespace().or(CharMatcher.is('#'));
|
||||||
private static final String PATTERN = "(?:\\s|\\A)#[\\p{L}[0-9]-_]+";
|
private static final String PATTERN = "(?:\\s|\\A)#[\\p{L}[0-9]-_]+";
|
||||||
|
|
||||||
@@ -43,14 +55,14 @@ public class HashtagsUtil {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Set<String> extractTags(Set<String> input) throws IllegalArgumentException {
|
static Set<String> extractTags(Set<String> input) throws InvalidHashtagException {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
HashSet<String> result = new HashSet<>();
|
HashSet<String> result = new HashSet<>();
|
||||||
for (String hashtag : input) {
|
for (String hashtag : input) {
|
||||||
if (hashtag.contains(",")) {
|
if (hashtag.contains(",")) {
|
||||||
throw new IllegalArgumentException("Hashtags may not contain commas");
|
throw InvalidHashtagException.hashtagsMayNotContainCommas();
|
||||||
}
|
}
|
||||||
hashtag = cleanupHashtag(hashtag);
|
hashtag = cleanupHashtag(hashtag);
|
||||||
if (!hashtag.isEmpty()) {
|
if (!hashtag.isEmpty()) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
|||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
import com.google.gerrit.reviewdb.client.ChangeMessage;
|
||||||
import com.google.gerrit.server.ChangeMessagesUtil;
|
import com.google.gerrit.server.ChangeMessagesUtil;
|
||||||
|
import com.google.gerrit.server.change.HashtagsUtil.InvalidHashtagException;
|
||||||
import com.google.gerrit.server.extensions.events.HashtagsEdited;
|
import com.google.gerrit.server.extensions.events.HashtagsEdited;
|
||||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||||
import com.google.gerrit.server.notedb.ChangeUpdate;
|
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||||
@@ -99,31 +100,31 @@ public class SetHashtagsOp implements BatchUpdateOp {
|
|||||||
ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
|
ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
|
||||||
ChangeNotes notes = update.getNotes().load();
|
ChangeNotes notes = update.getNotes().load();
|
||||||
|
|
||||||
Set<String> existingHashtags = notes.getHashtags();
|
|
||||||
Set<String> updated = new HashSet<>();
|
|
||||||
toAdd = new HashSet<>(extractTags(input.add));
|
|
||||||
toRemove = new HashSet<>(extractTags(input.remove));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Set<String> existingHashtags = notes.getHashtags();
|
||||||
|
Set<String> updated = new HashSet<>();
|
||||||
|
toAdd = new HashSet<>(extractTags(input.add));
|
||||||
|
toRemove = new HashSet<>(extractTags(input.remove));
|
||||||
|
|
||||||
for (HashtagValidationListener validator : validationListeners) {
|
for (HashtagValidationListener validator : validationListeners) {
|
||||||
validator.validateHashtags(update.getChange(), toAdd, toRemove);
|
validator.validateHashtags(update.getChange(), toAdd, toRemove);
|
||||||
}
|
}
|
||||||
} catch (ValidationException e) {
|
|
||||||
|
updated.addAll(existingHashtags);
|
||||||
|
toAdd.removeAll(existingHashtags);
|
||||||
|
toRemove.retainAll(existingHashtags);
|
||||||
|
if (updated()) {
|
||||||
|
updated.addAll(toAdd);
|
||||||
|
updated.removeAll(toRemove);
|
||||||
|
update.setHashtags(updated);
|
||||||
|
addMessage(ctx, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedHashtags = ImmutableSortedSet.copyOf(updated);
|
||||||
|
return true;
|
||||||
|
} catch (ValidationException | InvalidHashtagException e) {
|
||||||
throw new BadRequestException(e.getMessage());
|
throw new BadRequestException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
updated.addAll(existingHashtags);
|
|
||||||
toAdd.removeAll(existingHashtags);
|
|
||||||
toRemove.retainAll(existingHashtags);
|
|
||||||
if (updated()) {
|
|
||||||
updated.addAll(toAdd);
|
|
||||||
updated.removeAll(toRemove);
|
|
||||||
update.setHashtags(updated);
|
|
||||||
addMessage(ctx, update);
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedHashtags = ImmutableSortedSet.copyOf(updated);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMessage(ChangeContext ctx, ChangeUpdate update) throws OrmException {
|
private void addMessage(ChangeContext ctx, ChangeUpdate update) throws OrmException {
|
||||||
|
|||||||
Reference in New Issue
Block a user