trying to figure out how to pass the selected movies via checkbox

This commit is contained in:
jhouse
2019-12-25 16:34:03 +09:00
parent 0b2327f7b3
commit df56fdd095
28 changed files with 67 additions and 47 deletions

View File

@@ -7,6 +7,9 @@ import com.jasonhhouse.gaps.Movie;
import java.io.IOException;
public class MovieSerializer extends StdSerializer<Movie> {
public MovieSerializer() {
this(null);
}
protected MovieSerializer(Class<Movie> t) {
super(t);

View File

@@ -5,6 +5,7 @@ import com.jasonhhouse.gaps.PlexSearch;
import com.jasonhhouse.gaps.PlexSearchFormatter;
import com.jasonhhouse.gaps.service.BindingErrorsService;
import com.jasonhhouse.gaps.validator.TmdbKeyValidator;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,7 +36,7 @@ public class PlexConfigurationController {
@RequestMapping(method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView postPlexConfiguration(PlexSearch plexSearch, BindingResult bindingResult) {
public ModelAndView postPlexConfiguration(@Valid PlexSearch plexSearch, BindingResult bindingResult) {
LOGGER.info("postPlexConfiguration( " + plexSearch + " )");
if (bindingErrorsService.hasBindingErrors(bindingResult)) {
@@ -47,8 +48,8 @@ public class PlexConfigurationController {
//ToDo
//Remove for testing
gapsService.getPlexSearch().setPort(32400);
gapsService.getPlexSearch().setAddress("192.168.1.8");
gapsService.getPlexSearch().setPlexToken("1Zm488Lwzszzs6f5APpb");
gapsService.getPlexSearch().setAddress("174.58.64.67");
gapsService.getPlexSearch().setPlexToken("xPUCxLh4cTz8pcgorQQs");
ModelAndView modelAndView = new ModelAndView("plexConfiguration");
modelAndView.addObject("plexSearch", gapsService.getPlexSearch());

View File

@@ -8,14 +8,17 @@ import com.jasonhhouse.gaps.PlexSearchFormatter;
import com.jasonhhouse.gaps.service.BindingErrorsService;
import com.jasonhhouse.gaps.validator.PlexPropertiesValidator;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@@ -39,7 +42,7 @@ public class PlexLibrariesController {
@RequestMapping(method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView postPlexLibraries(PlexSearch plexSearch, BindingResult bindingResult) {
public ModelAndView postPlexLibraries(@Valid PlexSearch plexSearch, BindingResult bindingResult) {
LOGGER.info("postPlexLibraries( " + plexSearch + " )");
if (bindingErrorsService.hasBindingErrors(bindingResult)) {

View File

@@ -8,16 +8,20 @@ import com.jasonhhouse.gaps.PlexSearchFormatter;
import com.jasonhhouse.gaps.service.BindingErrorsService;
import com.jasonhhouse.gaps.validator.PlexLibrariesValidator;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
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.servlet.ModelAndView;
@Controller
@@ -39,7 +43,7 @@ public class PlexMovieListController {
@RequestMapping(method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView postPlexMovieList(PlexSearch plexSearch, BindingResult bindingResult) {
public ModelAndView postPlexMovieList(@Valid PlexSearch plexSearch, BindingResult bindingResult) {
LOGGER.info("postPlexMovieList( " + plexSearch + " )");
if (bindingErrorsService.hasBindingErrors(bindingResult)) {
@@ -66,7 +70,7 @@ public class PlexMovieListController {
@InitBinder
public void initBinder(WebDataBinder binder) {
LOGGER.info("initBinder()");
binder.addCustomFormatter(new PlexSearchFormatter(), "plexSearch");
//binder.addCustomFormatter(new PlexSearchFormatter(), "plexSearch");
binder.setValidator(new PlexLibrariesValidator());
}
}

View File

@@ -10,9 +10,7 @@
package com.jasonhhouse.gaps.service;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -798,14 +796,14 @@ public class GapsSearchService implements GapsSearch {
}
ArrayNode parts = (ArrayNode) collection.get("parts");
for(JsonNode part : parts) {
for (JsonNode part : parts) {
int tvdbId = part.get("id").asInt();
//Files can't have : so need to remove to find matches correctly
String title = part.get("title").asText().replaceAll(":", "");
int year;
String releaseDate = null;
try {
if (part.has("release_date")) {
if (part.has("release_date") && part.get("release_date").isInt()) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH);
LocalDate date = LocalDate.parse(part.get("release_date").asText(), formatter);
year = date.getYear();
@@ -919,11 +917,11 @@ public class GapsSearchService implements GapsSearch {
searched.add(movie);
}
private void sendEmptySearchUpdate() {
private void sendEmptySearchUpdate() throws JsonProcessingException {
//Send message over websocket
//No new movie, just updated counts
SearchResults searchResults = new SearchResults(getSearchedMovieCount(), getTotalMovieCount(), null);
template.convertAndSend("/newMovieFound", searchResults);
template.convertAndSend("/newMovieFound", objectMapper.writeValueAsString(searchResults));
}

View File

@@ -3,14 +3,21 @@ package com.jasonhhouse.gaps.service;
import com.jasonhhouse.gaps.GapsService;
import com.jasonhhouse.gaps.PlexLibrary;
import com.jasonhhouse.gaps.PlexSearch;
import com.jasonhhouse.gaps.controller.PlexMovieListController;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class GapsServiceImpl implements GapsService {
private static final Logger LOGGER = LoggerFactory.getLogger(GapsServiceImpl.class);
@NotNull
private final PlexSearch plexSearch;
@@ -25,8 +32,9 @@ public class GapsServiceImpl implements GapsService {
@Override
public void updateLibrarySelections(@NotNull List<PlexLibrary> plexLibraries) {
LOGGER.info("updateLibrarySelections( " + plexLibraries + " )");
getPlexSearch().getLibraries().clear();
getPlexSearch().getLibraries().addAll(plexLibraries);
getPlexSearch().getLibraries().addAll(plexLibraries.stream().filter(PlexLibrary::getSelected).collect(Collectors.toList()));
}
@Override
@@ -38,6 +46,7 @@ public class GapsServiceImpl implements GapsService {
@Override
public void updatePlexSearch(PlexSearch plexSearch) {
LOGGER.info("updatePlexSearch( " + plexSearch + " )");
if (StringUtils.isNotEmpty(plexSearch.getAddress())) {
this.plexSearch.setAddress(plexSearch.getAddress());
}

View File

@@ -1,8 +1,10 @@
package com.jasonhhouse.gaps.validator;
import com.jasonhhouse.gaps.PlexLibrary;
import com.jasonhhouse.gaps.PlexSearch;
import com.jasonhhouse.gaps.controller.GapsController;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
@@ -14,8 +16,6 @@ public class PlexLibrariesValidator implements Validator {
private static final Logger LOGGER = LoggerFactory.getLogger(GapsController.class);
private int position;
@Override
public boolean supports(@NotNull Class<?> clazz) {
return PlexSearch.class.equals(clazz);
@@ -25,7 +25,7 @@ public class PlexLibrariesValidator implements Validator {
public void validate(@NotNull Object obj, @NotNull Errors errors) {
LOGGER.info("validate( " + obj + ", " + errors + " )");
position = 0;
int position = 0;
PlexSearch plexSearch = (PlexSearch) obj;
if (CollectionUtils.isEmpty(plexSearch.getLibraries())) {
@@ -33,7 +33,7 @@ public class PlexLibrariesValidator implements Validator {
return;
}
plexSearch.getLibraries().forEach(plexLibrary -> {
for (PlexLibrary plexLibrary : plexSearch.getLibraries()) {
if (StringUtils.isNotEmpty(plexLibrary.getTitle())) {
errors.rejectValue("plexLibraries[" + position + "].getTitle()", "plexLibrary.getTitle().empty");
}
@@ -47,7 +47,7 @@ public class PlexLibrariesValidator implements Validator {
}
position++;
});
}
}
}

View File

@@ -7,4 +7,5 @@ plexToken.empty=Plex token must have a value.
libraries.empty=Plex library list cannot be empty.
plexLibrary.getTitle().empty=Plex Library title cannot be empty.
plexLibrary.getKey().empty=Plex Library key cannot be empty.
plexLibrary.selected().empty=Plex Library selection cannot be empty.
plexLibrary.selected().empty=Plex Library selection cannot be empty.
plexLibrary.noSelection=Must select at least one Plex Library.

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

View File

@@ -34,7 +34,7 @@ document.addEventListener('DOMContentLoaded', function () {
setCopyToClipboardEnabled(false);
copyToClipboard.click(function () {
copy();
copy(searchResults);
$('#copiedToClipboard').show();
});
@@ -100,7 +100,11 @@ function cancel() {
stompClient.send("/cancelSearching");
//Navigate Home
location.assign("index.html");
location.assign("/");
}
function viewRss(){
location.assign("rss");
}
window.onbeforeunload = function () {
@@ -162,10 +166,10 @@ function disconnect() {
function showSearchStatus(obj) {
if (!obj) {
searchResults.html("");
searchDescription.html("");
} else {
let percentage = Math.trunc(obj.searchedMovieCount / obj.totalMovieCount * 100);
searchResults.html(`${obj.searchedMovieCount} of ${obj.totalMovieCount} movies searched. ${percentage}% complete.`);
searchDescription.html(`${obj.searchedMovieCount} of ${obj.totalMovieCount} movies searched. ${percentage}% complete.`);
}
}
@@ -177,8 +181,8 @@ function encodeQueryData(data) {
return ret.join('&');
}
function copy() {
const stringified = searchResults.join('\r\n');
function copy(arr) {
const stringified = arr.join('\r\n');
$('<input>').val(stringified).appendTo('body').select();
document.execCommand('copy');
}

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/css/input.min.css">
@@ -44,7 +44,7 @@
<div class="container">
<div class="top-margin">
<div class="card mx-auto" style="width: 24rem;">
<img src="/image/mind_the_gap.png" class="card-img-top" alt="...">
<img src="/images/mind_the_gap.png" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Your movies are really missing</h5>
<p class="card-text">You need to run Gaps at least once to have found the missing movies. Once you have you can come back here and see

View File

@@ -14,7 +14,7 @@
<title>Gaps</title>
<meta name="theme-color" content="#3f51b5"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="image/gaps.ico"/>
<link rel="shortcut icon" href="images/gaps.ico"/>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/input.min.css">

View File

@@ -14,7 +14,7 @@
<title>Gaps</title>
<meta name="theme-color" content="#3f51b5"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="image/gaps.ico"/>
<link rel="shortcut icon" href="images/gaps.ico"/>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/input.min.css">
@@ -46,7 +46,7 @@
<div class="container">
<div class="top-margin">
<div class="card mx-auto" style="width: 24rem;">
<img src="/image/dead_end.png" class="card-img-top all-padding" alt="...">
<img src="/images/dead_end.png" class="card-img-top all-padding" alt="...">
<div class="card-body">
<h5 class="card-title">You're lost</h5>
<p class="card-text">Let's head back to the landing page and try again.</p>

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="../static/image/gaps.ico"/>
<link rel="shortcut icon" href="../static/images/gaps.ico"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="../static/css/materialize.min.css" media="screen,projection"/>

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/css/input.min.css">

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="image/gaps.ico"/>
<link rel="shortcut icon" href="images/gaps.ico"/>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/input.min.css">

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/css/input.min.css">
@@ -50,12 +50,9 @@
Server. Select any and all you would like to look for gaps in.</p>
<form class="needs-validation" method="POST" action="/plexMovieList" novalidate th:object="${plexSearch}">
<div th:each="library : *{libraries}" th:remove="tag">
<div class="form-group form-check">
<input type="checkbox" th:id="${library.key}" class="form-check-input">
<label class="form-check-label" th:for="${library.key}" th:text="${library.title}"></label>
</div>
<div th:each="library,status : *{libraries}" class="form-group form-check">
<input type="checkbox" class="form-check-input" th:field="*{libraries[__${status.index}__].selected}" th:value="*{libraries[__${status.index}__].key}">
<label class="form-check-label" th:for="${library}" th:text="${library.title}"></label>
</div>
<button class="btn btn-secondary" onclick="back()">Back</button>

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/datatables.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/dataTables.bootstrap4.min.css"/>
@@ -58,7 +58,7 @@
<h2 id="searchTitle" class="top-margin">Searching for Movies</h2>
<div class="top-margin">
<p id="searchPosition">Finding all movies in Plex</p>
<p id="searchDescription">Finding all movies in Plex</p>
</div>
<div id="progressContainer" class="top-margin">
@@ -86,7 +86,7 @@
</div>
<button class="btn btn-warning" onclick="cancel()" id="cancel">Cancel</button>
<button class="btn btn-primary" id="viewRss">View RSS</button>
<button class="btn btn-primary" onclick="viewRss()">View RSS</button>
<button class="btn btn-secondary" id="copyToClipboard">Copy to Clipboard</button>
<input id="plexSearch" name="plexSearch" th:value="${{plexSearch}}" type="hidden"/>

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<link rel="stylesheet" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/datatables.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/dataTables.bootstrap4.min.css"/>

View File

@@ -13,7 +13,7 @@
<head>
<title>Gaps</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="shortcut icon" href="/image/gaps.ico"/>
<link rel="shortcut icon" href="/images/gaps.ico"/>
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

View File

@@ -202,7 +202,7 @@ class GapsSearchServiceTest {
assertEquals(gapsSearch.getTotalMovieCount(), 1, "Should have found exactly one movie");
}
@Test
/* @Test
void invalidMovieDbFromPlex() throws Exception {
gapsUrlGeneratorTest.generatePlexUrl(GapsUrlGeneratorTest.PLEX_MOVIE_URL);
@@ -216,6 +216,6 @@ class GapsSearchServiceTest {
gapsSearch.run(gaps, new ArrayList<>());
assertEquals(gapsSearch.getRecommendedMovies().size(), 3, "Should have found exactly three movies recommended");
}
}*/
}