Hashtag REST API endpoints

This change introduces three endpoints to ADD/DELETE/GET hashtags
from/to a change.

Whenever the hashtags are successfully updated, the reply will
describe the new complete set of hashtags for that change.

Please note that these endpoints will not be available without
enabling the NoteDB (later on this is expected to be enabled
per default).

Examples:

  PUT /a/changes/1/hashtags HTTP/1.1
  { "hashtags" : "tag1,tag2,tag3" }

  Response:
  HTTP/1.1 200 OK
  [
    "tag1",
    "tag2",
    "tag3"
  ]

  DELETE /a/changes/1/hashtags HTTP/1.1
  { "hashtags" : "tag1" }

  Response:
  HTTP/1.1 200 OK
  [
    "tag2",
    "tag3"
  ]

  GET /a/changes/1/hashtags HTTP/1.1

  Response:
  HTTP/1.1 200 OK
  [
    "tag2",
    "tag3"
  ]

Change-Id: I79dce433e79c6d209268fd434b2311aa551ffc09
This commit is contained in:
Gustaf Lundh 2014-09-09 13:43:31 +02:00 committed by David Pursehouse
parent 418936d725
commit 34d0db74ef
5 changed files with 200 additions and 0 deletions

View File

@ -270,6 +270,7 @@ public class ChangeJson {
out.project = in.getProject().get();
out.branch = in.getDest().getShortName();
out.topic = in.getTopic();
out.hashtags = ctl.getNotes().load().getHashtags();
out.changeId = in.getKey().get();
out.mergeable = isMergeable(in);
ChangedLines changedLines = cd.changedLines();
@ -927,6 +928,7 @@ public class ChangeJson {
public String project;
public String branch;
public String topic;
public Collection<String> hashtags;
public String changeId;
public String subject;
public Change.Status status;

View File

@ -0,0 +1,74 @@
// Copyright (C) 2014 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.change;
import com.google.common.base.Strings;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.change.DeleteHashtags.Input;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Singleton
public class DeleteHashtags implements RestModifyView<ChangeResource, Input> {
private final ChangeUpdate.Factory updateFactory;
public static class Input {
@DefaultInput
public String hashtags;
}
@Inject
DeleteHashtags(ChangeUpdate.Factory updateFactory) {
this.updateFactory = updateFactory;
}
@Override
public Response<Set<String>> apply(ChangeResource req, Input input)
throws AuthException, OrmException, IOException, BadRequestException {
if (input == null || Strings.isNullOrEmpty(input.hashtags)) {
throw new BadRequestException("Hashtags are required");
}
ChangeControl control = req.getControl();
if(!control.canEditHashtags()){
throw new AuthException("Editing hashtags not permitted");
}
ChangeUpdate update = updateFactory.create(control);
ChangeNotes notes = control.getNotes().load();
Set<String> hashtags = new HashSet<String>();
Set<String> oldHashtags = notes.getHashtags();
if (oldHashtags != null) {
hashtags.addAll(oldHashtags);
}
hashtags.removeAll(Arrays.asList(input.hashtags.split(",")));
update.setHashtags(hashtags);
update.commit();
return Response.ok(hashtags);
}
}

View File

@ -0,0 +1,44 @@
// Copyright (C) 2014 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.change;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Set;
@Singleton
public class GetHashtags implements RestReadView<ChangeResource> {
@Override
public Response<Set<String>> apply(ChangeResource req)
throws AuthException, OrmException, IOException, BadRequestException {
ChangeControl control = req.getControl();
ChangeNotes notes = control.getNotes().load();
Set<String> hashtags = notes.getHashtags();
if (hashtags == null) {
hashtags = ImmutableSet.of();
}
return Response.ok(hashtags);
}
}

View File

@ -51,9 +51,12 @@ public class Module extends RestApiModule {
get(CHANGE_KIND, "detail").to(GetDetail.class);
get(CHANGE_KIND, "topic").to(GetTopic.class);
get(CHANGE_KIND, "in").to(IncludedIn.class);
get(CHANGE_KIND, "hashtags").to(GetHashtags.class);
put(CHANGE_KIND, "topic").to(PutTopic.class);
put(CHANGE_KIND, "hashtags").to(PutHashtags.class);
delete(CHANGE_KIND, "topic").to(PutTopic.class);
delete(CHANGE_KIND).to(DeleteDraftChange.class);
delete(CHANGE_KIND, "hashtags").to(DeleteHashtags.class);
post(CHANGE_KIND, "abandon").to(Abandon.class);
post(CHANGE_KIND, "publish").to(Publish.CurrentRevision.class);
post(CHANGE_KIND, "restore").to(Restore.class);

View File

@ -0,0 +1,77 @@
// Copyright (C) 2012 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.change;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.change.PutHashtags.Input;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
@Singleton
public class PutHashtags implements RestModifyView<ChangeResource, Input> {
private final ChangeUpdate.Factory updateFactory;
public static class Input {
@DefaultInput
public String hashtags;
}
@Inject
PutHashtags(ChangeUpdate.Factory updateFactory) {
this.updateFactory = updateFactory;
}
@Override
public Response<Set<String>> apply(ChangeResource req, Input input)
throws AuthException, OrmException, IOException, BadRequestException {
if (input == null || Strings.isNullOrEmpty(input.hashtags)) {
throw new BadRequestException("Hashtags are required");
}
ChangeControl control = req.getControl();
if (!control.canEditHashtags()) {
throw new AuthException("Editing hashtags not permitted");
}
ChangeUpdate update = updateFactory.create(control);
ChangeNotes notes = control.getNotes().load();
Set<String> oldHashtags = notes.getHashtags();
Set<String> hashtags = new HashSet<String>();
if (oldHashtags != null) {
hashtags.addAll(oldHashtags);
};
hashtags.addAll(Lists.newArrayList(Splitter.on(CharMatcher.anyOf(",;"))
.trimResults().split(input.hashtags)));
update.setHashtags(hashtags);
update.commit();
return Response.ok(hashtags);
}
}