Skip to content

Commit 754a7a3

Browse files
author
Vladimir Kotal
committed
implement annotation API endpoint
fixes #3046
1 parent 2387ff1 commit 754a7a3

File tree

12 files changed

+565
-100
lines changed

12 files changed

+565
-100
lines changed

apiary.apib

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@ OpenGrok RESTful API documentation. The following endpoints are accessible under
66

77
Besides `/suggester` and `/search` endpoints, everything is accessible from `localhost` only.
88

9+
## Annotation [/annotation{?path}]
10+
11+
### Get annotation for a file [GET]
12+
13+
+ Parameters
14+
+ path (string) - path of file, relative to source root
15+
16+
+ Response 200 (application/json)
17+
+ Body
18+
19+
[
20+
{
21+
"revision": "c55d5891",
22+
"author": "Adam Hornáček",
23+
"description": "changeset: c55d5891\nsummary: Rewrite README.txt to use markdown syntax\nuser: Adam Hornáček <[email protected]>\ndate: Wed Aug 30 17:42:12 CEST 2017",
24+
"version": "1/15"
25+
},
26+
{
27+
"revision": "5e0c6b22",
28+
"author": "Vladimir Kotal",
29+
"description": "changeset: 5e0c6b22\nsummary: bump year\nuser: Vladimir Kotal <[email protected]>\ndate: Thu Jul 18 14:43:01 CEST 2019",
30+
"version": "14/15"
31+
}
32+
]
33+
934
## Authorization framework reload [/configuration/authorization/reload]
1035

1136
### reloads authorization framework [POST]

opengrok-indexer/src/main/java/org/opengrok/indexer/history/Annotation.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.opengrok.indexer.util.Color;
2929
import org.opengrok.indexer.util.LazilyInstantiate;
3030
import org.opengrok.indexer.util.RainbowColorGenerator;
31-
import org.opengrok.indexer.web.Util;
3231

3332
import java.io.IOException;
3433
import java.io.StringWriter;
@@ -53,7 +52,7 @@ public class Annotation {
5352
private static final Logger LOGGER = LoggerFactory.getLogger(Annotation.class);
5453

5554
private final List<Line> lines = new ArrayList<>();
56-
private final Map<String, String> desc = new HashMap<>();
55+
private final Map<String, String> desc = new HashMap<>(); // revision to description
5756
private final Map<String, Integer> fileVersions = new HashMap<>(); // maps revision to file version
5857
private final LazilyInstantiate<Map<String, String>> colors = LazilyInstantiate.using(this::generateColors);
5958
private int widestRevision;
@@ -163,7 +162,7 @@ void addLine(String revision, String author, boolean enabled) {
163162
}
164163

165164
void addDesc(String revision, String description) {
166-
desc.put(revision, Util.encode(description));
165+
desc.put(revision, description);
167166
}
168167

169168
public String getDesc(String revision) {

opengrok-indexer/src/main/java/org/opengrok/indexer/web/Util.java

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -713,82 +713,88 @@ public static void readableLine(int num, Writer out, Annotation annotation, Stri
713713
out.write(closeQuotedTag);
714714
out.write(snum);
715715
out.write(anchorEnd);
716+
716717
if (annotation != null) {
717-
String r = annotation.getRevision(num);
718-
boolean enabled = annotation.isEnabled(num);
719-
out.write("<span class=\"blame\">");
720-
if (enabled) {
721-
out.write(anchorClassStart);
722-
out.write("r");
723-
out.write("\" style=\"background-color: ");
724-
out.write(annotation.getColors().getOrDefault(r, "inherit"));
725-
out.write("\" href=\"");
726-
out.write(URIEncode(annotation.getFilename()));
727-
out.write("?a=true&amp;r=");
728-
out.write(URIEncode(r));
729-
String msg = annotation.getDesc(r);
730-
out.write("\" title=\"");
731-
if (msg != null) {
732-
out.write(msg);
733-
}
734-
if (annotation.getFileVersion(r) != 0) {
735-
out.write("&lt;br/&gt;version: " + annotation.getFileVersion(r) + "/"
736-
+ annotation.getRevisions().size());
737-
}
738-
out.write(closeQuotedTag);
739-
}
740-
StringBuilder buf = new StringBuilder();
741-
final boolean most_recent_revision = annotation.getFileVersion(r) == annotation.getRevisions().size();
742-
// print an asterisk for the most recent revision
743-
if (most_recent_revision) {
744-
buf.append("<span class=\"most_recent_revision\">");
745-
buf.append('*');
718+
writeAnnotation(num, out, annotation, userPageLink, userPageSuffix, project);
719+
}
720+
}
721+
722+
private static void writeAnnotation(int num, Writer out, Annotation annotation, String userPageLink,
723+
String userPageSuffix, String project) throws IOException {
724+
String r = annotation.getRevision(num);
725+
boolean enabled = annotation.isEnabled(num);
726+
out.write("<span class=\"blame\">");
727+
if (enabled) {
728+
out.write(anchorClassStart);
729+
out.write("r");
730+
out.write("\" style=\"background-color: ");
731+
out.write(annotation.getColors().getOrDefault(r, "inherit"));
732+
out.write("\" href=\"");
733+
out.write(URIEncode(annotation.getFilename()));
734+
out.write("?a=true&amp;r=");
735+
out.write(URIEncode(r));
736+
String msg = annotation.getDesc(r);
737+
out.write("\" title=\"");
738+
if (msg != null) {
739+
out.write(Util.encode(msg));
746740
}
747-
htmlize(r, buf);
748-
if (most_recent_revision) {
749-
buf.append("</span>"); // recent revision span
741+
if (annotation.getFileVersion(r) != 0) {
742+
out.write("&lt;br/&gt;version: " + annotation.getFileVersion(r) + "/"
743+
+ annotation.getRevisions().size());
750744
}
745+
out.write(closeQuotedTag);
746+
}
747+
StringBuilder buf = new StringBuilder();
748+
final boolean most_recent_revision = annotation.getFileVersion(r) == annotation.getRevisions().size();
749+
// print an asterisk for the most recent revision
750+
if (most_recent_revision) {
751+
buf.append("<span class=\"most_recent_revision\">");
752+
buf.append('*');
753+
}
754+
htmlize(r, buf);
755+
if (most_recent_revision) {
756+
buf.append("</span>"); // recent revision span
757+
}
758+
out.write(buf.toString());
759+
buf.setLength(0);
760+
if (enabled) {
761+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
762+
763+
out.write(anchorEnd);
764+
765+
// Write link to search the revision in current project.
766+
out.write(anchorClassStart);
767+
out.write("search\" href=\"" + env.getUrlPrefix());
768+
out.write("defs=&amp;refs=&amp;path=");
769+
out.write(project);
770+
out.write("&amp;hist=&quot;" + URIEncode(r) + "&quot;");
771+
out.write("&amp;type=\" title=\"Search history for this changeset");
772+
out.write(closeQuotedTag);
773+
out.write("S");
774+
out.write(anchorEnd);
775+
}
776+
String a = annotation.getAuthor(num);
777+
if (userPageLink == null) {
778+
out.write(HtmlConsts.SPAN_A);
779+
htmlize(a, buf);
751780
out.write(buf.toString());
781+
out.write(HtmlConsts.ZSPAN);
752782
buf.setLength(0);
753-
if (enabled) {
754-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
755-
756-
out.write(anchorEnd);
757-
758-
// Write link to search the revision in current project.
759-
out.write(anchorClassStart);
760-
out.write("search\" href=\"" + env.getUrlPrefix());
761-
out.write("defs=&amp;refs=&amp;path=");
762-
out.write(project);
763-
out.write("&amp;hist=&quot;" + URIEncode(r) + "&quot;");
764-
out.write("&amp;type=\" title=\"Search history for this changeset");
765-
out.write(closeQuotedTag);
766-
out.write("S");
767-
out.write(anchorEnd);
768-
}
769-
String a = annotation.getAuthor(num);
770-
if (userPageLink == null) {
771-
out.write(HtmlConsts.SPAN_A);
772-
htmlize(a, buf);
773-
out.write(buf.toString());
774-
out.write(HtmlConsts.ZSPAN);
775-
buf.setLength(0);
776-
} else {
777-
out.write(anchorClassStart);
778-
out.write("a\" href=\"");
779-
out.write(userPageLink);
780-
out.write(URIEncode(a));
781-
if (userPageSuffix != null) {
782-
out.write(userPageSuffix);
783-
}
784-
out.write(closeQuotedTag);
785-
htmlize(a, buf);
786-
out.write(buf.toString());
787-
buf.setLength(0);
788-
out.write(anchorEnd);
783+
} else {
784+
out.write(anchorClassStart);
785+
out.write("a\" href=\"");
786+
out.write(userPageLink);
787+
out.write(URIEncode(a));
788+
if (userPageSuffix != null) {
789+
out.write(userPageSuffix);
789790
}
790-
out.write("</span>");
791+
out.write(closeQuotedTag);
792+
htmlize(a, buf);
793+
out.write(buf.toString());
794+
buf.setLength(0);
795+
out.write(anchorEnd);
791796
}
797+
out.write("</span>");
792798
}
793799

794800
/**
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
24+
package org.opengrok.web.api.v1;
25+
26+
import javax.ws.rs.core.Response;
27+
import javax.ws.rs.ext.ExceptionMapper;
28+
import javax.ws.rs.ext.Provider;
29+
import java.io.FileNotFoundException;
30+
31+
@Provider
32+
public class FileNotFoundExceptionMapper implements ExceptionMapper<FileNotFoundException> {
33+
@Override
34+
public Response toResponse(FileNotFoundException e) {
35+
return Response.status(Response.Status.NOT_FOUND).build();
36+
}
37+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
24+
package org.opengrok.web.api.v1;
25+
26+
import org.opengrok.web.util.NoPathParameterException;
27+
28+
import javax.ws.rs.core.Response;
29+
import javax.ws.rs.ext.ExceptionMapper;
30+
import javax.ws.rs.ext.Provider;
31+
32+
@Provider
33+
public class NoPathParameterExceptionMapper implements ExceptionMapper<NoPathParameterException> {
34+
@Override
35+
public Response toResponse(NoPathParameterException e) {
36+
return Response.status(Response.Status.BAD_REQUEST).build();
37+
}
38+
}

0 commit comments

Comments
 (0)