com.marklogic.samplestack.web.QnADocumentController.java Source code

Java tutorial

Introduction

Here is the source code for com.marklogic.samplestack.web.QnADocumentController.java

Source

/*
 * Copyright 2012-2014 MarkLogic Corporation
 *
 * 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.marklogic.samplestack.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.marklogic.samplestack.domain.ClientRole;
import com.marklogic.samplestack.domain.QnADocument;
import com.marklogic.samplestack.domain.InitialQuestion;
import com.marklogic.samplestack.exception.SampleStackDataIntegrityException;
import com.marklogic.samplestack.service.ContributorService;
import com.marklogic.samplestack.service.QnAService;

/**
 * Controller to handle endpoints related to questions and answers.
 */
@RestController
public class QnADocumentController {

    @SuppressWarnings("unused")
    private final Logger logger = LoggerFactory.getLogger(QnADocumentController.class);

    @Autowired
    private QnAService qnaService;

    @Autowired
    ObjectMapper mapper;

    @Autowired
    private ContributorService contributorService;

    /** 
     * Searches for QnADocuments and returns search results to request body
     * @param q A search string (See Search API docs)
     * @param start The index of the first return result.
     * @return A Search API JSON response containing matches, facets and snippets.
     */
    @RequestMapping(value = "questions", method = RequestMethod.GET)
    public @ResponseBody JsonNode getQnADocuments(@RequestParam(required = false) String q,
            @RequestParam(required = false, defaultValue = "1") long start) {
        if (q == null) {
            q = "sort:active";
        }
        ObjectNode structuredQuery = mapper.createObjectNode();
        ObjectNode qtext = structuredQuery.putObject("query");
        qtext.put("qtext", q);
        return qnaService.rawSearch(ClientRole.securityContextRole(), structuredQuery, start);
    }

    /**
     * Exposes endpoint for asking a question.
     * @param sparseQuestion A POJO constructed from the request body.
     * @return The newly-created QnADocument's JSON node.
     */
    @RequestMapping(value = "questions", method = RequestMethod.POST)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") @ResponseStatus(HttpStatus.CREATED) JsonNode ask(
            @RequestBody InitialQuestion sparseQuestion) {
        QnADocument qnaDoc = new QnADocument(mapper, sparseQuestion.getTitle(), sparseQuestion.getText(),
                sparseQuestion.getTags());
        QnADocument answered = qnaService.ask(ClientRole.securityContextUserName(), qnaDoc);
        return answered.getJson();
    }

    /**
     * Gets a QnADocument based on the ID in the URL path.
     * @param id The id of the document to retrieve.
     * @return The QnADocument's JSON with id= id.
     */
    @RequestMapping(value = "questions/{id}", method = RequestMethod.GET)
    public @ResponseBody JsonNode get(@PathVariable(value = "id") String id) {
        QnADocument qnaDoc = qnaService.get(ClientRole.securityContextRole(), "/questions/" + id);
        return qnaDoc.getJson();
    }

    /**
     * Deletes a QnADocument by id
     * @param id the id of the QnADocument to delete.
     * @return An empty response, 204 HTTP status.
     */
    @RequestMapping(value = "questions/{id}", method = RequestMethod.DELETE)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_ADMINS')") ResponseEntity<?> delete(
            @PathVariable(value = "id") String id) {
        qnaService.delete("/questions/" + id);
        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }

    /**
     * Endpoint to provide an answer to an outstanding question.
     * @param answer The JSON node containing an answer.
     * @param id The id of the question to answer.
     * @return The updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/answers", method = RequestMethod.POST)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") @ResponseStatus(HttpStatus.CREATED) JsonNode answer(
            @RequestBody JsonNode answer, @PathVariable(value = "id") String id) {
        //validate TODO
        String answerId = "/questions/" + id;
        QnADocument answered = qnaService.answer(ClientRole.securityContextUserName(), answerId,
                answer.get("text").asText());
        return answered.getJson();
    }

    /**
     * Exposes endpoint to accept an answer.
     * @param answerIdPart The id of the answer that's deemed suitable to the contributor.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/answers/{answerId}/accept", method = RequestMethod.POST)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode accept(
            @PathVariable(value = "answerId") String answerIdPart) {
        //validate TODO
        String userName = ClientRole.securityContextUserName();
        String answerId = "/answers/" + answerIdPart;
        QnADocument toAccept = qnaService.findOne(ClientRole.SAMPLESTACK_CONTRIBUTOR, "id:" + answerId, 1);
        if (toAccept.getOwnerUserName().equals(userName)) {
            QnADocument accepted = qnaService.accept(answerId);
            return accepted.getJson();
        } else {
            throw new SampleStackDataIntegrityException("Current user does not match owner of question");
        }
    }

    /**
     * Exposes an endpoint to comment on a question.
     * @param comment The JSON payload containing a comment.
     * @param questionId The id of the question on which to comment.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/comments", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode comment(
            @RequestBody JsonNode comment, @PathVariable(value = "id") String questionId) {
        String postId = "/questions/" + questionId;
        QnADocument toCommentOn = qnaService.comment(ClientRole.securityContextUserName(), postId,
                comment.get("text").asText());
        return toCommentOn.getJson();
    }

    /**
     * Exposes an endpoint to give a question an upvote.
     * @param questionId The question's id.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/upvotes", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode voteUp(
            @PathVariable(value = "id") String questionId) {
        String postId = "/questions/" + questionId;
        QnADocument toVoteOn = qnaService.voteUp(ClientRole.securityContextUserName(), postId);
        return toVoteOn.getJson();
    }

    /**
     * Exposes an endpoint to give a question an downvote.
     * @param questionId The question's id.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/downvotes", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode voteDown(
            @PathVariable(value = "id") String questionId) {
        String postId = "/questions/" + questionId;
        QnADocument toVoteOn = qnaService.voteDown(ClientRole.securityContextUserName(), postId);
        return toVoteOn.getJson();
    }

    /**
     * Exposes an endpoint to give an answer an upvote.
     * @param answerIdPart The part of the URL that encodes the answer's id.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/answers/{answerId}/upvotes", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode upVoteAnswer(
            @RequestBody JsonNode comment, @PathVariable(value = "answerId") String answerIdPart) {
        String answerId = "/answers/" + answerIdPart;
        QnADocument toVoteOn = qnaService.voteUp(ClientRole.securityContextUserName(), answerId);
        return toVoteOn.getJson();
    }

    /**
     * Exposes an endpoint to give an answer a downvote.
     * @param answerIdPart The part of the URL that encodes the answer's id.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/answers/{answerId}/downvotes", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode downVoteAnswer(
            @PathVariable(value = "answerId") String answerIdPart) {
        String answerId = "/answers/" + answerIdPart;
        QnADocument toVoteOn = qnaService.voteDown(ClientRole.securityContextUserName(), answerId);
        return toVoteOn.getJson();
    }

    /**
     * Exposes an endpoint to comment on an answer.
     * @param comment The JSON payload containing a comment.
     * @param answerIdPart The part of the URL that encodes the answer's id.
     * @return An updated QnADocument's JSON node.
     */
    @RequestMapping(value = "questions/{id}/answers/{answerId}/comments", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody @PreAuthorize("hasRole('ROLE_CONTRIBUTORS')") JsonNode commentAnswer(
            @RequestBody JsonNode comment, @PathVariable(value = "answerId") String answerIdPart) {
        String answerId = "/answers/" + answerIdPart;
        QnADocument toCommentOn = qnaService.comment(ClientRole.securityContextUserName(), answerId,
                comment.get("text").asText());
        return toCommentOn.getJson();
    }

    /**
     * Exposes an endpoint for searching QnADocuments.
     * @param structuredQuery A JSON structured query.
     * @param start The index of the first result to return.
     * @return A Search Results JSON response.
     */
    @RequestMapping(value = "search", method = RequestMethod.POST)
    public @ResponseBody JsonNode search(@RequestBody ObjectNode structuredQuery,
            @RequestParam(defaultValue = "1", required = false) long start) {

        JsonNode postedStartNode = structuredQuery.get("start");
        if (postedStartNode != null) {
            start = postedStartNode.asLong();
            structuredQuery.remove("start");
        }
        return qnaService.rawSearch(ClientRole.securityContextRole(), structuredQuery, start);
    }

}