Commit 315b1747 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '338-asciidoccontroller-v1' into 'master'

Resolve "AsciiDocController v1"

Closes #338

See merge request genesys-pgr/genesys-server!233
parents 628e9c14 cec3f8b8
/*
* Copyright 2018 Global Crop Diversity Trust
*
* 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 org.genesys2.server.api.v1;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.api.ApiBaseController;
import org.genesys2.spring.ResourceNotFoundException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
/**
* AsciiDoc API v1.
*/
@RestController("asciiDocApi1")
@PreAuthorize("isAuthenticated()")
@RequestMapping(AsciiDocController.API_BASE)
@Api(tags = { "asciiDoc" })
public class AsciiDocController {
/** The Constant DOCS_DIR. */
private static final String DOCS_DIR = "docs/";
/** The Constant DOCS_SECTIONS_DIR. */
private static final String DOCS_SECTIONS_DIR = "sections/";
/** The Constant DOCS_IMAGES_DIR. */
private static final String DOCS_IMAGES_DIR = "images/";
/** The Constant HTML_EXTENSION. */
private static final String HTML_EXTENSION = ".html";
/** The Constant API_BASE. */
public static final String API_BASE = ApiBaseController.APIv1_BASE + "/cms/d";
/**
* View doc.
*
* @param documentName the document name
* @return the map
* @throws IOException Signals that an I/O exception has occurred.
*/
@RequestMapping(value = "/{documentName}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public ADoc viewDoc(@PathVariable(value = "documentName") String documentName) throws IOException {
ADoc resultDoc = new ADoc();
ClassLoader classLoader = this.getClass().getClassLoader();
String docPath = new StringBuilder(DOCS_DIR).append(documentName).append(HTML_EXTENSION).toString();
InputStream resourceStream = classLoader.getResourceAsStream(docPath);
if (resourceStream == null) {
throw new ResourceNotFoundException();
}
String html = IOUtils.toString(resourceStream);
Document document = Jsoup.parse(html);
resultDoc.title = StringUtils.stripToNull(document.getElementsByTag("title").html());
Element toc = document.getElementById("toc");
if (toc != null) {
toc.getElementById("toctitle").remove();
toc.removeAttr("id").removeAttr("class");
resultDoc.toc = StringUtils.stripToNull(toc.html());
toc.remove();
}
Element header = document.getElementById("header");
if (header != null) {
Elements headerH1 = header.getElementsByTag("h1");
if (headerH1 != null) {
// Use HTML title if available
resultDoc.title = StringUtils.defaultIfBlank(headerH1.html(), resultDoc.title);
}
resultDoc.header = StringUtils.stripToNull(header.getElementsByClass("details").removeAttr("id").html());
}
Element content = document.getElementById("content");
if (content != null) {
resultDoc.content = StringUtils.stripToNull(content.html());
}
Element footer = document.getElementById("footer-text");
if (footer != null) {
resultDoc.footer = StringUtils.stripToNull(footer.html());
}
return resultDoc;
}
/**
* View section.
*
* @param documentName the document name
* @return the map
* @throws IOException Signals that an I/O exception has occurred.
*/
@RequestMapping(value = "/sections/{documentName}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public ADoc viewSection(@PathVariable(value = "documentName") String documentName) throws IOException {
String docPath = new StringBuilder(DOCS_SECTIONS_DIR).append(documentName).toString();
return viewDoc(docPath);
}
/**
* Gets the image.
*
* @param imageName the image name
* @return the image
* @throws IOException Signals that an I/O exception has occurred.
*/
@RequestMapping(value = "/images/{imageName}", method = RequestMethod.GET, produces = { MediaType.IMAGE_JPEG_VALUE })
@ResponseBody
public byte[] getImage(@PathVariable(value = "imageName") String imageName) throws IOException {
ClassLoader classLoader = this.getClass().getClassLoader();
String imgPath = new StringBuilder(DOCS_DIR).append(DOCS_IMAGES_DIR).append(imageName).toString();
InputStream inputStream = classLoader.getResourceAsStream(imgPath);
if (inputStream == null) {
throw new ResourceNotFoundException();
}
return IOUtils.toByteArray(inputStream);
}
public static class ADoc {
public String title;
public String toc;
public String header;
public String content;
public String footer;
}
}
/*
* Copyright 2018 Global Crop Diversity Trust
*
* 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 org.genesys.test.server.api.v1;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.is;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.genesys.test.base.AbstractApiTest;
import org.genesys2.server.api.v1.AsciiDocController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* The Class AsciiDocControllerTest.
*/
public class AsciiDocControllerTest extends AbstractApiTest {
/** The rest documentation. */
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");
/** The web application context. */
@Autowired
private WebApplicationContext webApplicationContext;
/** The mock mvc. */
MockMvc mockMvc;
/*
* (non-Javadoc)
* @see org.genesys.test.base.AbstractApiTest#beforeTest()
*/
@Before
@Override
public void beforeTest() throws Exception {
super.beforeTest();
/*@formatter:off*/
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(this.restDocumentation)
.uris().withScheme("https").withHost("sandbox.genesys-pgr.org").withPort(443))
.build();
/*@formatter:on*/
// setFinalStatic(AsciiDocController.class.getDeclaredField("DOCS_DIR"),
// "docs/");
}
/**
* View doc test.
*
* @throws Exception the exception
*/
@Test
public void viewDocTest() throws Exception {
/*@formatter:off*/
mockMvc.perform(get(AsciiDocController.API_BASE + "/" + "index" )
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
// .andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.title", is("Genesys API <b>reference</b> manual")))
.andExpect(jsonPath("$.footer", is("Version 2.3")))
.andExpect(jsonPath("$.header", is("<span id=\"author\" class=\"author\">Author</span>\n<br> \n<span id=\"revnumber\">version 2.3</span>")))
.andExpect(jsonPath("$.content", is("Here be \n<b>dragons</b>!")))
;
/*@formatter:on*/
}
/**
* View section test.
*
* @throws Exception the exception
*/
@Test
public void viewSectionTest() throws Exception {
/*@formatter:off*/
mockMvc.perform(get(AsciiDocController.API_BASE + "/sections/" + "apis" )
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
// .andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.title", is("Application")))
.andExpect(jsonPath("$.header", nullValue()))
.andExpect(jsonPath("$.footer", is("Last updated 2017-10-15")))
.andExpect(jsonPath("$.content", is("Here be \n<b>dragons</b>!")))
;
/*@formatter:on*/
}
/**
* Sets the final static.
*
* @param field the field
* @param newValue the new value
* @throws Exception the exception
*/
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
// remove final modifier from field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index test</title>
</head>
<body>
<div id="header">
<h1>Genesys API <b>reference</b> manual</h1>
<div class="details">
<span id="author" class="author">Author</span><br>
<span id="revnumber">version 2.3</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#chSecurity">1. Security</a>
<ul class="sectlevel2">
<li><a href="#obtaining-the-access-token">1.1. Obtaining
the access token</a>
<ul class="sectlevel3">
<li><a href="#authorization-grant">1.1.1. Authorization
grant</a></li>
<li><a href="#username-and-password">1.1.2. Username
and password</a></li>
<li><a href="#client-credentials">1.1.3. Client
credentials</a></li>
<li><a href="#successful-authorization">1.1.4.
Successful authorization</a></li>
</ul></li>
<li><a href="#using-the-refresh-token">1.2. Using the
refresh token</a></li>
</ul></li>
<li><a href="#client-errors">2. Client errors</a>
<ul class="sectlevel2">
<li><a href="#401-unauthorized">2.1. 401 Unauthorized</a></li>
</ul></li>
<li><a href="#chApiAccession">3. Managing passport data</a>
<ul class="sectlevel2">
<li><a href="#accession-identity">3.1. Accession identity</a></li>
<li><a href="#json-data-model">3.2. JSON data model</a></li>
<li><a href="#geographic-data-json-model">3.3. Geographic
data JSON model</a></li>
<li><a href="#collecting-data-json-model">3.4. Collecting
data JSON model</a></li>
<li><a href="#clearing-existing-values">3.5. Clearing
existing values</a></li>
<li><a href="#insert-or-update-accessions">3.6. Insert or
update accessions</a></li>
<li><a href="#deleting-accessions">3.7. Deleting
accessions</a></li>
</ul></li>
<li><a href="#chApiImg">4. Managing accession images</a>
<ul class="sectlevel2">
<li><a href="#listing-existing-galleries">4.1. Listing
existing galleries</a>
<ul class="sectlevel3">
<li><a href="#path-parameters">4.1.1. Path parameters</a></li>
<li><a href="#request-parameters">4.1.2. Request
parameters</a></li>
<li><a href="#server-response">4.1.3. Server response</a></li>
</ul></li>
<li><a href="#accepted-image-formats">4.2. Accepted image
formats</a></li>
<li><a href="#adding-images-to-accessions">4.3. Adding
images to accessions</a>
<ul class="sectlevel3">
<li><a href="#path-parameters-2">4.3.1. Path parameters</a></li>
<li><a href="#request-parameters-2">4.3.2. Request
parameters</a></li>
<li><a href="#server-response-2">4.3.3. Server response</a></li>
</ul></li>
<li><a href="#updating-image-metadata">4.4. Updating
image metadata</a>
<ul class="sectlevel3">
<li><a href="#path-parameters-3">4.4.1. Path parameters</a></li>
<li><a href="#response-fields">4.4.2. Response fields</a></li>
</ul></li>
</ul></li>
<li><a href="#chApiRequests">5. Managing requests</a>
<ul class="sectlevel2">
<li><a href="#listing-requests">5.1. Listing requests</a>
<ul class="sectlevel3">
<li><a href="#path-parameters-4">5.1.1. Path parameters</a></li>
<li><a href="#request-parameters-3">5.1.2. Request
parameters</a></li>
<li><a href="#server-response-3">5.1.3. Server response</a></li>
</ul></li>
<li><a href="#request-details">5.2. Request details</a>
<ul class="sectlevel3">
<li><a href="#path-parameters-5">5.2.1. Path parameters</a></li>
<li><a href="#server-response-4">5.2.2. Server response</a></li>
</ul></li>
</ul></li>
<li><a href="#chApiCrop">6. Managing crop data</a>
<ul class="sectlevel2">
<li><a href="#crop-taxonomic-rules">6.1. Crop taxonomic
rules</a></li>
<li><a href="#listing-all-crops">6.2. Listing all crops</a></li>
<li><a href="#retrieving-crop-data">6.3. Retrieving crop
data</a>
<ul class="sectlevel3">
<li><a href="#taxonomic-rules">6.3.1. Taxonomic rules</a></li>
<li><a href="#exclusion-rule">6.3.2. Exclusion rule</a></li>
</ul></li>
<li><a href="#registering-a-new-crop">6.4. Registering a
new crop</a></li>
<li><a href="#localization-of-crop-title-and-description">6.5.
Localization of crop title and description</a></li>
<li><a href="#updating-taxonomic-rules">6.6. Updating
taxonomic rules</a></li>
<li><a href="#deleting-a-crop">6.7. Deleting a crop</a></li>
</ul></li>
<li><a href="#acknowledgements">7. Acknowledgements</a></li>
</ul>
</div>
</div>
<div id="content">
Here be <b>dragons</b>!
</div>
<div id="footer">
<div id="footer-text">
Version 2.3
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.3">
<title>Application</title>
</head>
<body class="book toc2 toc-left">
<div id="header">
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#chBackup">Application</a></li>
<li><a href="#configuration">Configuration</a></li>
<li><a href="#data">Data</a>
<ul class="sectlevel2">
<li><a href="#database-backup">Database backup</a></li>
<li><a href="#file-backup">File backup</a></li>
<li><a href="#elasticsearch-backup">Elasticsearch backup</a></li>
</ul></li>
<li><a href="#validating-backups">Validating backups</a></li>
</ul>
</div>
</div>
<div id="content">
Here be <b>dragons</b>!
</div>
<div id="footer">
<div id="footer-text">Last updated 2017-10-15</div>
</div>
</body>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment