package io.kaif.web.api; import static java.util.stream.Collectors.*; import java.util.List; import javax.validation.Valid; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.URL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; 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.RestController; import io.kaif.flake.FlakeId; import io.kaif.model.account.AccountAccessToken; import io.kaif.model.article.Article; import io.kaif.model.debate.Debate; import io.kaif.model.zone.Zone; import io.kaif.service.ArticleService; import io.kaif.web.support.SingleWrapper; @RestController @RequestMapping("/api/article") public class ArticleResource { static class CreateExternalLink { @Size(max = Article.URL_MAX) @NotNull @URL(regexp = Article.URL_PATTERN) public String url; @Size(min = Article.TITLE_MIN, max = Article.TITLE_MAX) @NotNull public String title; @NotNull public Zone zone; } static class DeleteArticle { @NotNull public FlakeId articleId; } static class CreateSpeak { @Size(max = Article.CONTENT_MAX, min = Article.CONTENT_MIN) @NotNull public String content; @Size(min = Article.TITLE_MIN, max = Article.TITLE_MAX) @NotNull public String title; @NotNull public Zone zone; } static class CreateDebate { @NotNull public FlakeId articleId; public FlakeId parentDebateId; @Size(min = Debate.CONTENT_MIN, max = Debate.CONTENT_MAX) @NotNull public String content; } static class UpdateDebate { @NotNull public FlakeId debateId; @Size(min = Debate.CONTENT_MIN, max = Debate.CONTENT_MAX) @NotNull public String content; } static class Previewer { @NotNull public String content; } @Autowired private ArticleService articleService; @RequestMapping(value = "/external-link", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE }) public void createExternalLink(AccountAccessToken token, @Valid @RequestBody CreateExternalLink request) { articleService.createExternalLink(token, request.zone, request.title.trim(), request.url.trim()); } @RequestMapping(value = "/", method = RequestMethod.DELETE, consumes = { MediaType.APPLICATION_JSON_VALUE }) public void deleteArticle(AccountAccessToken token, @Valid @RequestBody DeleteArticle request) { articleService.deleteArticle(token, request.articleId); } @RequestMapping(value = "/speak", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE }) public void createSpeak(AccountAccessToken token, @Valid @RequestBody CreateSpeak request) { articleService.createSpeak(token, request.zone, request.title.trim(), request.content.trim()); } @RequestMapping(value = "/debate", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE }) public SingleWrapper<String> create(AccountAccessToken token, @Valid @RequestBody CreateDebate request) { return SingleWrapper.of(articleService.debate(request.articleId, request.parentDebateId, token, request.content.trim()).getDebateId().toString()); } @RequestMapping(value = "/debate/content", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE }) public String editDebateContent(AccountAccessToken token, @Valid @RequestBody UpdateDebate request) { return articleService.updateDebateContent(request.debateId, token, request.content.trim()); } //no need authenticate @RequestMapping(value = "/debate/content/preview", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE }) public String previewDebateContent(@Valid @RequestBody Previewer request) { return Debate.renderContentPreview(request.content); } @RequestMapping(value = "/speak/preview", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE }) public String previewSpeakContent(@Valid @RequestBody Previewer request) { return Article.renderSpeakPreview(request.content); } @RequestMapping(value = "/debate/content", method = RequestMethod.GET) public String loadEditableDebate(AccountAccessToken token, @RequestParam("debateId") FlakeId debateId) { return articleService.loadEditableDebateContent(debateId, token); } @RequestMapping(value = "/can-create", method = RequestMethod.GET) public SingleWrapper<Boolean> canCreateArticle(AccountAccessToken token, @RequestParam("zone") String rawZone) { return SingleWrapper.of(articleService.canCreateArticle(Zone.valueOf(rawZone), token)); } @RequestMapping(value = "/external-link/exist", method = RequestMethod.GET) public SingleWrapper<Boolean> isExternalUrlExist(@RequestParam("zone") String rawZone, @RequestParam("url") String url) { return SingleWrapper.of(articleService.isExternalLinkExist(Zone.valueOf(rawZone), url)); } @RequestMapping(value = "/external-link", method = RequestMethod.GET) public List<FlakeId> listArticleIdsByExternalLink(@RequestParam("zone") String rawZone, @RequestParam("url") String url) { return articleService.listArticlesByExternalLink(Zone.valueOf(rawZone), url) .stream() .map(Article::getArticleId) .collect(toList()); } @RequestMapping(value = "/can-delete", method = RequestMethod.GET) public SingleWrapper<Boolean> canDeleteArticle(AccountAccessToken token, @RequestParam("username") String username, @RequestParam("articleId") FlakeId articleId) { return SingleWrapper.of(articleService.canDeleteArticle(username, articleId)); } }