bstlboard-back/src/main/java/de/bstly/board/controller/EntryController.java

368 lines
12 KiB
Java

/**
*
*/
package de.bstly.board.controller;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.businesslogic.SettingsManager;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.businesslogic.UserPageManager;
import de.bstly.board.businesslogic.VoteManager;
import de.bstly.board.controller.model.EntryFilter;
import de.bstly.board.controller.support.EntityResponseStatusException;
import de.bstly.board.controller.support.RequestBodyErrors;
import de.bstly.board.controller.validation.EntryValidator;
import de.bstly.board.model.Entry;
import de.bstly.board.model.UserPage;
import de.bstly.board.model.Vote;
import de.bstly.board.model.support.EntryStatus;
import de.bstly.board.model.support.EntryType;
import de.bstly.board.model.support.FlaggedStatus;
import de.bstly.board.model.support.Types;
import de.bstly.board.model.support.VoteType;
/**
* The Class EntryController.
*/
@RestController
@RequestMapping("/entries")
public class EntryController extends BaseController {
@Autowired
private EntryManager entryManager;
@Autowired
private UserManager userManager;
@Autowired
private EntryValidator entryValidator;
@Autowired
private VoteManager voteManager;
@Autowired
private SettingsManager settingsManager;
@Autowired
private UserPageManager userPageManager;
/**
* Fetch by user page.
*
* @param name the name
* @param usernameParameter the username parameter
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param ascParameter the asc parameter
* @param ignoreParameter the ignore parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/{name}")
public Page<Entry> fetchByUserPage(@PathVariable("name") String name,
@RequestParam("user") Optional<String> usernameParameter,
@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter,
@RequestParam("date") Optional<Instant> dateParameter,
@RequestParam("tags") Optional<List<String>> tagsParameter,
@RequestParam("excludedTags") Optional<List<String>> excludedTagsParameter,
@RequestParam("type") Optional<EntryType> typeParameter,
@RequestParam("gravity") Optional<Float> gravityParameter,
@RequestParam("asc") Optional<Boolean> ascParameter,
@RequestParam("ignore") Optional<List<String>> ignoreParameter) {
UserPage userPage = userPageManager.get(usernameParameter.orElse(getCurrentUsername()),
name);
if (userPage == null || usernameParameter.isPresent() && !userPage.isPublicPage()) {
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (sizeParameter.isPresent() && sizeParameter.get() > 100) {
sizeParameter = Optional.of(100);
}
EntryFilter filter = buildFilter(dateParameter.orElse(null), FlaggedStatus.NORMAL,
tagsParameter.orElse(null), excludedTagsParameter.orElse(null),
typeParameter.orElse(null));
filter.setFixedTags(userPage.getTags());
filter.setFixedExcludedTags(userPage.getExcludedTags());
Page<Entry> entries = null;
switch (userPage.getSorting()) {
case TOP:
entries = entryManager.fetchByRanking(getCurrentUsername(), filter, getGravity(),
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
ascParameter.orElse(false));
break;
case NEW:
entries = entryManager.fetchByDate(getCurrentUsername(), filter,
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
ascParameter.orElse(false));
break;
case HOT:
entries = entryManager.fetchByComments(getCurrentUsername(), filter, getGravity(),
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
ascParameter.orElse(false));
break;
case LAST:
entries = entryManager.fetchByLastComment(getCurrentUsername(), filter,
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
ascParameter.orElse(false));
break;
}
if (entries == null) {
throw new EntityResponseStatusException(HttpStatus.BAD_REQUEST);
}
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
entries.getContent(), ignore);
return entries;
}
/**
* Fetch by user.
*
* @param username the username
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param dateParameter the date parameter
* @param tagsParameter the tags parameter
* @param excludedTagsParameter the excluded tags parameter
* @param typeParameter the type parameter
* @param ascParameter the asc parameter
* @param ignoreParameter the ignore parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/byuser/{username}")
public Page<Entry> fetchByUser(@PathVariable("username") String username,
@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter,
@RequestParam("date") Optional<Instant> dateParameter,
@RequestParam("tags") Optional<List<String>> tagsParameter,
@RequestParam("excludedTags") Optional<List<String>> excludedTagsParameter,
@RequestParam("type") Optional<EntryType> typeParameter,
@RequestParam("asc") Optional<Boolean> ascParameter,
@RequestParam("ignore") Optional<List<String>> ignoreParameter) {
if (sizeParameter.isPresent() && sizeParameter.get() > 100) {
sizeParameter = Optional.of(100);
}
if (dateParameter.isPresent() && dateParameter.get().isAfter(Instant.now())) {
dateParameter = Optional.of(Instant.now());
}
EntryFilter filter = buildFilter(dateParameter.orElse(null), FlaggedStatus.NORMAL,
tagsParameter.orElse(null), excludedTagsParameter.orElse(null),
typeParameter.orElse(null));
Page<Entry> entries = entryManager.fetchByUser(getCurrentUsername(), username, filter,
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize()),
ascParameter.orElse(false));
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
entries.getContent(), ignore);
return entries;
}
/**
* Builds the filter.
*
* @param date the date
* @param flaggedStatus the flagged status
* @param tags the tags
* @param excludedTags the excluded tags
* @param type the type
* @return the entry filter
*/
protected EntryFilter buildFilter(Instant date, FlaggedStatus flaggedStatus, List<String> tags,
List<String> excludedTags, EntryType type) {
EntryFilter filter = new EntryFilter();
filter.setDate(date);
filter.setFlaggedStatus(flaggedStatus);
filter.setEntryType(type);
filter.setTags(tags);
filter.setExcludedTags(excludedTags);
return filter;
}
/**
* Gets the entry.
*
* @param id the id
* @param ignoreParameter the ignore parameter
* @return the entry
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/entry/{id}")
public Entry getEntry(@PathVariable("id") Long id,
@RequestParam("ignore") Optional<List<String>> ignoreParameter) {
Entry entry = entryManager.get(id);
if (entry == null) {
throw new EntityResponseStatusException(HttpStatus.NOT_FOUND);
}
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
entry, ignore);
return entry;
}
/**
* Creates the entry.
*
* @param entry the entry
* @param ignoreParameter the ignore parameter
* @return the entry
*/
@PreAuthorize("isAuthenticated()")
@PostMapping()
public Entry createEntry(@RequestBody Entry entry,
@RequestParam("ignore") Optional<List<String>> ignoreParameter) {
RequestBodyErrors bindingResult = new RequestBodyErrors(entry);
entryValidator.validate(entry, bindingResult);
if (bindingResult.hasErrors()) {
throw new EntityResponseStatusException(bindingResult.getAllErrors(),
HttpStatus.UNPROCESSABLE_ENTITY);
}
entry.setCreated(Instant.now().plus(getEntryDelay(), ChronoUnit.MINUTES));
entry.setAuthor(getCurrentUsername());
entry.setEntryStatus(EntryStatus.NORMAL);
entry.setFlaggedStatus(FlaggedStatus.NORMAL);
entry.setTitle(entry.getTitle().trim());
entry.setText(entry.getText().trim());
entry = entryManager.save(entry);
Vote vote = new Vote();
vote.setTarget(entry.getId());
vote.setType(VoteType.up);
vote.setTargetType(Types.entry);
vote.setAuthor(getCurrentUsername());
voteManager.save(vote);
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
entry, ignore);
return entry;
}
/**
* Update entry.
*
* @param entry the entry
* @param ignoreParameter the ignore parameter
* @return the entry
*/
@PreAuthorize("isAuthenticated()")
@PatchMapping
public Entry updateEntry(@RequestBody Entry entry,
@RequestParam("ignore") Optional<List<String>> ignoreParameter) {
Entry orgEntry = entryManager.get(entry.getId());
if (orgEntry == null || !orgEntry.getAuthor().equals(getCurrentUsername()) || orgEntry
.getCreated().plus(getEntryDelay(), ChronoUnit.MINUTES).isBefore(Instant.now())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
RequestBodyErrors bindingResult = new RequestBodyErrors(entry);
entryValidator.validate(entry, bindingResult);
if (bindingResult.hasErrors()) {
throw new EntityResponseStatusException(bindingResult.getAllErrors(),
HttpStatus.UNPROCESSABLE_ENTITY);
}
orgEntry.setUrl(entry.getUrl());
orgEntry.setTitle(entry.getTitle().trim());
orgEntry.setText(entry.getText().trim());
orgEntry.setTags(entry.getTags());
orgEntry = entryManager.save(orgEntry);
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
orgEntry, ignore);
return orgEntry;
}
/**
* Detele entry.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("{id}")
public void deteleEntry(@PathVariable("id") Long id) {
Entry orgEntry = entryManager.get(id);
if (orgEntry == null || !orgEntry.getAuthor().equals(getCurrentUsername()) || orgEntry
.getCreated().plus(getEntryDelay(), ChronoUnit.MINUTES).isBefore(Instant.now())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
entryManager.delete(orgEntry);
}
/**
* Gets the title.
*
* @param url the url
* @return the title
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/helper/title")
public String getTitle(@RequestParam("url") String url) {
InputStream response = null;
Scanner scanner = null;
try {
response = new URL(URLDecoder.decode(url, "utf-8")).openStream();
scanner = new Scanner(response);
String responseBody = scanner.useDelimiter("\\A").next();
return responseBody.substring(responseBody.indexOf("<title>") + 7,
responseBody.indexOf("</title>"));
} catch (IOException ex) {
} finally {
try {
if (response != null) {
response.close();
}
if (scanner != null) {
scanner.close();
}
} catch (IOException ex) {
}
}
return "";
}
}