Add some API, update few pages

This commit is contained in:
Dmitry Isaenko 2024-03-05 18:46:51 +03:00
parent 762bb8b97f
commit 67eb755b2b
8 changed files with 93 additions and 16 deletions

View file

@ -2,6 +2,7 @@ package ru.redrise.marinesco.data;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -12,4 +13,5 @@ import java.util.List;
public interface AuthorRepository extends JpaRepository<Author, Long>{ public interface AuthorRepository extends JpaRepository<Author, Long>{
Optional<Author> findByAuthorName(String authorName); Optional<Author> findByAuthorName(String authorName);
List<Author> findByAuthorNameContainingIgnoreCase(String authorName); List<Author> findByAuthorNameContainingIgnoreCase(String authorName);
List<Author> findByAuthorNameContainingIgnoreCase(String authorName, PageRequest pageRequest);
} }

View file

@ -2,6 +2,7 @@ package ru.redrise.marinesco.data;
import java.util.List; import java.util.List;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -10,5 +11,7 @@ import ru.redrise.marinesco.library.Book;
@Repository @Repository
public interface BookRepository extends JpaRepository<Book, Integer>{ public interface BookRepository extends JpaRepository<Book, Integer>{
List<Book> findBySeriesContainingIgnoreCase(String title); List<Book> findBySeriesContainingIgnoreCase(String title);
List<Book> findBySeriesContainingIgnoreCase(String title, PageRequest page);
List<Book> findByTitleContainingIgnoreCase(String title); List<Book> findByTitleContainingIgnoreCase(String title);
List<Book> findByTitleContainingIgnoreCase(String title, PageRequest page);
} }

View file

@ -3,6 +3,7 @@ package ru.redrise.marinesco.library.api;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -29,4 +30,20 @@ public class AuthorsApiController {
return authorRepository.findAll(pageRequest).getContent(); return authorRepository.findAll(pageRequest).getContent();
} }
@GetMapping("/by/name/{name}")
public Iterable<Author> getAuthorId(
@PathVariable("name") String authorName,
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page){
PageRequest pageRequest = PageRequest.of(page, 10);
return authorRepository.findByAuthorNameContainingIgnoreCase(authorName, pageRequest);
}
@GetMapping("/by/id/{id}")
public Author getAuthorId(@PathVariable("id") Long authorId){
return authorRepository.findById(authorId).get();
}
} }

View file

@ -1,8 +1,11 @@
package ru.redrise.marinesco.library.api; package ru.redrise.marinesco.library.api;
import java.util.Optional;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -27,12 +30,38 @@ public class BooksApiController {
} }
@GetMapping(params = "page") @GetMapping(params = "page")
public Iterable<Book> getBooks(@RequestParam(value = "page", required = true) Integer page, public Iterable<Book> getBooks(
@RequestParam(value = "page", required = true) Integer page,
@RequestParam(value = "sort", required = false, defaultValue = "title") String sortBy){ @RequestParam(value = "sort", required = false, defaultValue = "title") String sortBy){
PageRequest pageRequest = PageRequest.of( PageRequest pageRequest = PageRequest.of(
page, 10, Sort.by(sortBy).descending()); page, 10, Sort.by(sortBy).descending());
return bookRepository.findAll(pageRequest).getContent(); return bookRepository.findAll(pageRequest).getContent();
} }
@GetMapping("/by/title/{title}")
public Iterable<Book> getBooksByName(
@PathVariable("title") String title,
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page){
PageRequest pageRequest = PageRequest.of(page, 10);
return bookRepository.findByTitleContainingIgnoreCase(title, pageRequest);
}
@GetMapping("/by/series/{series}")
public Iterable<Book> getBooksBySeries(
@PathVariable("series") String series,
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page){
PageRequest pageRequest = PageRequest.of(page, 10);
return bookRepository.findBySeriesContainingIgnoreCase(series, pageRequest);
}
@GetMapping("/by/id/{id}")
public Book getBooksById(@PathVariable("id") Integer id){
return bookRepository.findById(id).get();
}
} }

View file

@ -1,19 +1,26 @@
package ru.redrise.marinesco.library.api; package ru.redrise.marinesco.library.api;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.data.GenreRepository; import ru.redrise.marinesco.data.GenreRepository;
import ru.redrise.marinesco.library.Author;
import ru.redrise.marinesco.library.Genre; import ru.redrise.marinesco.library.Genre;
@Slf4j
@RestController @RestController
@RequestMapping(path = "/api/genres", produces = "application/json") @RequestMapping(path = "/api/genres", produces = "application/json")
public class GenresApiController { public class GenresApiController {
@ -27,16 +34,36 @@ public class GenresApiController {
public Iterable<Genre> getGenres( public Iterable<Genre> getGenres(
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page, @RequestParam(value = "page", required = false, defaultValue = "0") Integer page,
@RequestParam(value = "sort", required = false, defaultValue = "genreId") String sortBy) { @RequestParam(value = "sort", required = false, defaultValue = "genreId") String sortBy) {
PageRequest pageRequest = PageRequest.of( PageRequest pageRequest = PageRequest.of(page, 10, Sort.by(sortBy).descending());
page, 10, Sort.by(sortBy).descending());
return genreRepository.findAll(pageRequest).getContent(); return genreRepository.findAll(pageRequest).getContent();
} }
@GetMapping("/by/id/{id}")
public Genre getAuthorId(@PathVariable("id") String id){
return genreRepository.findById(id).get();
}
@PostMapping(consumes = "application/json") @PostMapping(consumes = "application/json")
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public Genre postGenre(@RequestBody Genre genre) { public Genre postGenre(@RequestBody Genre genre) {
log.info("{}", genre);
return genreRepository.save(genre); return genreRepository.save(genre);
} }
@PutMapping(path = "/{genreId}", consumes = "application/json")
public Genre putGenre(@PathVariable("genreId") String genreId,
@RequestBody Genre genre){
genre.setGenreId(genreId);
return genreRepository.save(genre);
}
@DeleteMapping("/{genreId}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteGenre(@PathVariable("genreId") String genreId){
try{
genreRepository.deleteById(genreId);
}
catch(EmptyResultDataAccessException ignore){}
}
} }

View file

@ -51,8 +51,7 @@
<span class="header_entry">|</span> <span class="header_entry">|</span>
</li> </li>
<li class="li_header_block"> <li class="li_header_block">
<a class="header_entry header_entry_link" href="/logout">Logout</a> <a id="logout" class="header_entry header_entry_link" href="/logout">Logout</a>
<form style="visibility: hidden" id="form" method="post" action="#" th:action="@{/logout}"></form>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -15,38 +15,38 @@
<div class="container base"> <div class="container base">
<h1>Register</h1> <h1>Register</h1>
<form class="regForm" method="POST" th:action="@{/register}" th:object="${registrationForm}"> <form class="regForm" method="POST" th:action="@{/register}" th:object="${registrationForm}">
<span class="validationError" th:if="${loginOccupied} != null" <span id="duplicate_error" class="validationError" th:if="${loginOccupied} != null"
th:text="${loginOccupied}">pew</span> th:text="${loginOccupied}">pew</span>
<span class="validationError" th:if="${#fields.hasErrors('username')}" <span id="username_error" class="validationError" th:if="${#fields.hasErrors('username')}"
th:errors="*{username}">Error</span> th:errors="*{username}">Error</span>
<br /> <br />
<label for="username">Username: </label> <label for="username">Username: </label>
<br /> <br />
<input type="text" name="username" id="username" size="50%" /><br /> <input type="text" name="username" id="username" size="50%" /><br />
<span class="validationError" th:if="${#fields.hasErrors('password')}" <span id="password_error" class="validationError" th:if="${#fields.hasErrors('password')}"
th:errors="*{password}">Error</span> th:errors="*{password}">Error</span>
<br /> <br />
<label for="password">Password: </label> <label for="password">Password: </label>
<br /> <br />
<input type="password" name="password" id="password" size="50%" /><br /> <input type="password" name="password" id="password" size="50%" /><br />
<span class="validationError" th:if="${passwordsMismatch} != null" <span id="password_dup_error" class="validationError" th:if="${passwordsMismatch} != null"
th:text="${passwordsMismatch}">false</span> th:text="${passwordsMismatch}">false</span>
<br /> <br />
<label for="confirm">Confirm password: </label> <label for="confirm">Confirm password: </label>
<br /> <br />
<input type="password" name="passwordConfirm" id="passwordConfirm" size="50%" /><br /> <input type="password" name="passwordConfirm" id="passwordConfirm" size="50%" /><br />
<span class="validationError" th:if="${#fields.hasErrors('displayname')}" <span id="displayname_error" class="validationError" th:if="${#fields.hasErrors('displayname')}"
th:errors="*{displayname}">Error</span> th:errors="*{displayname}">Error</span>
<br /> <br />
<label for="displayname">Displayed name: </label> <label for="displayname">Displayed name: </label>
<br /> <br />
<input type="text" name="displayname" id="displayname" size="50%" /><br /> <input type="text" name="displayname" id="displayname" size="50%" /><br />
<p> <p>
<button class="sign" type="submit">Register</button> <button id="register_submit" class="sign" type="submit">Register</button>
</p> </p>
</form> </form>
</div> </div>

View file

@ -14,27 +14,27 @@
<div class="container base"> <div class="container base">
<span <span
th:text="${'New users registration is now ' + (allowRegistration ? 'enabled. ' : 'disabled. ' )}"></span> th:text="${'New users registration is now ' + (allowRegistration ? 'enabled. ' : 'disabled. ' )}"></span>
<a th:href="${'/settings/allow_registration/' + !allowRegistration }" <a id="registration" th:href="${'/settings/allow_registration/' + !allowRegistration }"
th:text="${'Click here to ' + (allowRegistration ? 'disable' : 'enable' )}"></a> th:text="${'Click here to ' + (allowRegistration ? 'disable' : 'enable' )}"></a>
<br /> <br />
<br /> <br />
<a href="/settings/manage_users">Manage users</a> <a id="manage_users" href="/settings/manage_users">Manage users</a>
<br /> <br />
<br /> <br />
<span class="validationError" th:if="${rescanError} != null" th:text="${rescanError}"></span> <span class="validationError" th:if="${rescanError} != null" th:text="${rescanError}"></span>
<span class="validationPass" th:if="${rescanOk} != null" th:text="${rescanOk}"></span> <span class="validationPass" th:if="${rescanOk} != null" th:text="${rescanOk}"></span>
<br /> <br />
<a href="/settings/rescan" >Click to rescan library</a> <a id="rescan_library" href="/settings/rescan" >Click to rescan library</a>
<br /> <br />
<br /> <br />
<span class="validationPass" th:if="${repack} != null" th:text="${repack}"></span> <span class="validationPass" th:if="${repack} != null" th:text="${repack}"></span>
<span class="validationPass" th:if="${repack_lastrun} != null" th:text="${repack_lastrun}"></span> <span class="validationPass" th:if="${repack_lastrun} != null" th:text="${repack_lastrun}"></span>
<br /> <br />
<a href="/settings/repack" >Click to repack library zip archives</a> <a id="repack_library" href="/settings/repack" >Click to repack library zip archives</a>
<br /> <br />
<span class="validationError" th:if="${lastScanErrors} != ''" th:text="${lastScanErrors}"></span> <span class="validationError" th:if="${lastScanErrors} != ''" th:text="${lastScanErrors}"></span>
</p> </p>
<a href="/settings/genres">Edit genre descriptions</a> <a id="edit_genres" href="/settings/genres">Edit genre descriptions</a>
</div> </div>
</div> </div>
<div th:replace="~{fragments/footer :: 'footer'}"></div> <div th:replace="~{fragments/footer :: 'footer'}"></div>