From b5546e34907993f218772453bbb3f286d9de8411 Mon Sep 17 00:00:00 2001 From: gvp Date: Mon, 25 Jun 2018 12:20:22 +0700 Subject: [PATCH 01/14] Add model abstraction and user model --- .../java/org/gvp/boookmanager/model/User.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/main/java/org/gvp/boookmanager/model/User.java diff --git a/src/main/java/org/gvp/boookmanager/model/User.java b/src/main/java/org/gvp/boookmanager/model/User.java new file mode 100644 index 0000000..2076ed5 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/model/User.java @@ -0,0 +1,124 @@ +package org.gvp.boookmanager.model; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.hibernate.annotations.BatchSize; +import org.hibernate.validator.constraints.Email; +import org.hibernate.validator.constraints.NotBlank; +import org.springframework.util.CollectionUtils; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.*; + +@Entity +@Table(name = "users" , uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) +public class User extends AbstractNamedEntity { + + @Column(name = "email") + @Email + @NotBlank + @Size(max = 100) + private String email; + + @Column(name = "password") + @NotBlank + @Size(min = 5, max = 100) + // https://stackoverflow.com/a/12505165/548473 + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String password; + + @Column(name = "enabled") + private boolean enabled = true; + + @Column(name = "registered") + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private Date registered = new Date(); + + @Enumerated(EnumType.STRING) + @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id")) + @Column(name = "role") + @ElementCollection(fetch = FetchType.EAGER) + @BatchSize(size = 200) + private Set roles; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")//, cascade = CascadeType.REMOVE, orphanRemoval = true) + @OrderBy("dateTime DESC") + private List books; + + public User() { + } + + public User(User u) { + this(u.getId(), u.getName(), u.getEmail(), u.getPassword(), u.isEnabled(), u.getRegistered(), u.getRoles()); + } + + public User(Long id, String name, String email, String password, Role role, Role... roles) { + this(id, name, email, password, true, new Date(), EnumSet.of(role, roles)); + } + + public User(Long id, String name, String email, String password, boolean enabled, Date registered, Collection roles) { + super(id, name); + this.email = email; + this.password = password; + this.enabled = enabled; + this.registered = registered; + setRoles(roles); + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPassword(String password) { + this.password = password; + } + + public Date getRegistered() { + return registered; + } + + public void setRegistered(Date registered) { + this.registered = registered; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + public Set getRoles() { + return roles; + } + + public String getPassword() { + return password; + } + + public void setRoles(Collection roles) { + this.roles = CollectionUtils.isEmpty(roles) ? Collections.emptySet() : EnumSet.copyOf(roles); + } + + public List getBooks() { + return books; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", email=" + email + + ", name=" + name + + ", enabled=" + enabled + + ", roles=" + roles + '}'; + } +} From 42e0fc0f7a13beef39045acee4f2bdf4bcd0a0fa Mon Sep 17 00:00:00 2001 From: gvp Date: Mon, 25 Jun 2018 12:24:06 +0700 Subject: [PATCH 02/14] Add model abstraction and user model --- pom.xml | 14 ++++ .../controller/BookController.java | 80 ++++--------------- .../model/AbstractBaseEntity.java | 54 +++++++++++++ .../model/AbstractNamedEntity.java | 37 +++++++++ .../java/org/gvp/boookmanager/model/Book.java | 7 +- .../java/org/gvp/boookmanager/model/Role.java | 13 +++ 6 files changed, 136 insertions(+), 69 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/model/AbstractBaseEntity.java create mode 100644 src/main/java/org/gvp/boookmanager/model/AbstractNamedEntity.java create mode 100644 src/main/java/org/gvp/boookmanager/model/Role.java diff --git a/pom.xml b/pom.xml index 9421357..2e33785 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,7 @@ 5.4.1.Final 5.10.0.Final 5.0.5.RELEASE + 2.9.5 @@ -218,6 +219,19 @@ + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-json.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + ${jackson-json.version} + + + mysql diff --git a/src/main/java/org/gvp/boookmanager/controller/BookController.java b/src/main/java/org/gvp/boookmanager/controller/BookController.java index 0116404..512ead0 100644 --- a/src/main/java/org/gvp/boookmanager/controller/BookController.java +++ b/src/main/java/org/gvp/boookmanager/controller/BookController.java @@ -4,6 +4,7 @@ import org.gvp.boookmanager.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.support.PagedListHolder; +import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -12,35 +13,34 @@ import javax.validation.Valid; import java.util.List; -@Controller() +@RestController +@RequestMapping(value = "/books") public class BookController { private BookService bookService; - private int currentPage = 0; - private String sort = "books"; @Autowired public BookController(BookService bookService) { this.bookService = bookService; } - @GetMapping(value = "/books") - public String listBooks(@RequestParam(required = false) Integer page, Model model) { - sort = "books"; - model.addAttribute("book", new Book()); - List books = bookService.getALL(); - setPaging(page, model, books); - return "books"; + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public List getAll() { + return bookService.getALL(); } - @GetMapping(value = "/addForm") - public String bookAddForm(Model model) { - model.addAttribute("book", new Book()); - return "bookForm"; + @GetMapping("/{id}") + public Book get(@PathVariable("id") Long id) { + return bookService.get(id); } - @PostMapping(value = "/save") - public String saveBook(@Valid @ModelAttribute("book") Book book, BindingResult bindingResult){ + @DeleteMapping(value = "/delete/{id}") + public void delete(@PathVariable("id") Long id){ + bookService.delete(id); + } + + @PostMapping() + public String update(@Valid @ModelAttribute("book") Book book, BindingResult bindingResult){ if(bindingResult.hasErrors()){ return "bookForm"; @@ -48,51 +48,5 @@ public String saveBook(@Valid @ModelAttribute("book") Book book, BindingResult b bookService.save(book); return "redirect:/books"; } - - @RequestMapping(value = "/delete/{id}") - public String removeBook(@PathVariable("id") Long id){ - bookService.delete(id); - return "redirect:/books"; - } - - @GetMapping(value = "editForm") - public String bookEditForm(@RequestParam(name = "id") Long id, Model model){ - model.addAttribute("book", bookService.get(id)); - return "bookForm"; - - } - - @RequestMapping(value = "makeRead/{id}") - public String makeRead(@PathVariable("id") Long id){ - Book book = bookService.get(id); - bookService.makeRead(book); - return "redirect:/books"; - } - - - @GetMapping(value = "books/search") - public String booksSearch(@RequestParam("searchText")String searchText, - Model model) { - List books = bookService.search(searchText); - model.addAttribute("listBooks", books); - return "search"; - } - - private void setPaging(Integer page, Model model, List books) { - PagedListHolder pagedListHolder = new PagedListHolder<>(books); - pagedListHolder.setPageSize(10); - - model.addAttribute("maxPages", pagedListHolder.getPageCount()); - - model.addAttribute("currentSort", sort); - - if (page == null || page < 1 || page > pagedListHolder.getPageCount()) - page = 1; - - model.addAttribute("page", page); - currentPage = page; - - pagedListHolder.setPage(page - 1); - model.addAttribute("listBooks", pagedListHolder.getPageList()); - } + } diff --git a/src/main/java/org/gvp/boookmanager/model/AbstractBaseEntity.java b/src/main/java/org/gvp/boookmanager/model/AbstractBaseEntity.java new file mode 100644 index 0000000..cbc47cc --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/model/AbstractBaseEntity.java @@ -0,0 +1,54 @@ +package org.gvp.boookmanager.model; + +import org.hibernate.Hibernate; + +import javax.persistence.*; + +@MappedSuperclass +public abstract class AbstractBaseEntity { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + protected Long id; + + protected AbstractBaseEntity() { + } + + protected AbstractBaseEntity(Long id) { + this.id = id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + @Override + public String toString() { + return String.format("Entity %s (%s)", getClass().getName(), id); + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || !getClass().equals(Hibernate.getClass(o))) { + return false; + } + AbstractBaseEntity that = (AbstractBaseEntity) o; + return id != null && id.equals(that.id); + } + + @Override + public int hashCode() { + return id == null ? 0 : Long.hashCode(id); + } + + +} diff --git a/src/main/java/org/gvp/boookmanager/model/AbstractNamedEntity.java b/src/main/java/org/gvp/boookmanager/model/AbstractNamedEntity.java new file mode 100644 index 0000000..fcdf7ad --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/model/AbstractNamedEntity.java @@ -0,0 +1,37 @@ +package org.gvp.boookmanager.model; + +import org.hibernate.validator.constraints.NotBlank; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; +import javax.validation.constraints.Size; + +@MappedSuperclass +public abstract class AbstractNamedEntity extends AbstractBaseEntity { + + @NotBlank + @Size(min = 2, max = 100) + @Column(name = "name", nullable = false) + protected String name; + + protected AbstractNamedEntity() { + } + + protected AbstractNamedEntity(Long id, String name) { + super(id); + this.name = name; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return String.format("Entity %s (%s, '%s')", getClass().getName(), id, name); + } +} diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index 8c1c40e..e7c5580 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -27,16 +27,11 @@ @Parameter(name = "language", value = "English") }) }) -public class Book { +public class Book extends AbstractBaseEntity{ public static final String DELETE = "Book.delete"; public static final String GET_ALL = "Book.getAll"; - @Id - @Column(name = "id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - @Column(name = "title") @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, analyzer = @Analyzer(definition = "customAnalyzer")) @NotBlank(message = "Enter a title") diff --git a/src/main/java/org/gvp/boookmanager/model/Role.java b/src/main/java/org/gvp/boookmanager/model/Role.java new file mode 100644 index 0000000..6223164 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/model/Role.java @@ -0,0 +1,13 @@ +package org.gvp.boookmanager.model; + +import org.springframework.security.core.GrantedAuthority; + +public enum Role implements GrantedAuthority { + ROLE_USER, + ROLE_ADMIN; + + @Override + public String getAuthority() { + return name(); + } +} From 21d521b01d1efb6161e7853a9048890c9132e1ce Mon Sep 17 00:00:00 2001 From: gvp Date: Mon, 25 Jun 2018 14:22:26 +0700 Subject: [PATCH 03/14] Divide init and populate DB scripts. --- src/main/resources/db/dataBaseScrpt.sql | 47 ------------------------- src/main/resources/db/initDB.sql | 37 +++++++++++++++++++ src/main/resources/db/populateDB.sql | 40 +++++++++++++++++++++ 3 files changed, 77 insertions(+), 47 deletions(-) delete mode 100644 src/main/resources/db/dataBaseScrpt.sql create mode 100644 src/main/resources/db/initDB.sql create mode 100644 src/main/resources/db/populateDB.sql diff --git a/src/main/resources/db/dataBaseScrpt.sql b/src/main/resources/db/dataBaseScrpt.sql deleted file mode 100644 index 004518c..0000000 --- a/src/main/resources/db/dataBaseScrpt.sql +++ /dev/null @@ -1,47 +0,0 @@ -USE test; - -DROP TABLE IF EXISTS books; - -CREATE TABLE books ( - id INT(10) NOT NULL AUTO_INCREMENT DEFAULT 1, - title VARCHAR(100) NOT NULL, - description VARCHAR(255) NOT NULL, - author VARCHAR(100) NOT NULL, - isbn VARCHAR(20) NOT NULL, - printYear INT(4) NOT NULL, - readAlready BIT(1) NOT NULL DEFAULT 0, - PRIMARY KEY(id)) - -ENGINE = InnoDB DEFAULT CHARSET = utf8; - -INSERT INTO books (title, description, author, isbn, printYear) VALUES - ('A Brief History Of Time', 'description', 'Stephen Hawking', '9780857501004', 2015), - ('The Picture of Dorian Gray', 'description', 'Oscar Wilde', '9781853260155', 1997), - ('Don Quixote', 'description', 'Miguel de Cervantes', '9780099469698', 2005), - ('Frankenstein', 'description', 'Mary Shelley', '9780141198965', 2016), - ('Fahrenheit 451', 'description', 'Ray Bradbury', '9780006546061', 2008), - ('The Little Prince', 'description', 'Antoine de Saint-Exupery', '9780749707231', 1991), - ('The Idiot', 'description', 'Fyodor Dostoyevsky', '9780140447927', 2015), - ('The Call of the Wild', 'description', 'Jack London', '9780141321059', 2008), - ('Robinson Crusoe', 'description', 'Daniel Defoe', '9780199553976', 2009), - ('A Game of Thrones', 'description', 'George Martin', '9780006479888', 2009), - ('The Eye Of The World', 'description', 'Robert Jordan', '9780356503820', 2014), - ('Eragon', 'description', 'Christopher Paolini', '9780552553209', 2008), - ('It', 'description', 'Stephen King', '9781444707861', 2011), - ('Sleeping Beauties', 'description', 'Stephen King', '9781473665194', 2011), - ('The Shining', 'description', 'Stephen King', '9780307743657', 2012), - ('The Stand', 'description', 'Stephen King', '9780307743688', 2011), - ('11.22.63', 'description', 'Stephen King', '9781444727333', 2016), - ('Mr Mercedes', 'description', 'Stephen King', '9781444788648', 2015), - ('Finders Keepers', 'description', 'Stephen King', '9781473698956', 2016), - ('The Dead Zone', 'description', 'Stephen King', '9781444708097', 2011), - ('Revival', 'description', 'Stephen King', '9781444789218', '2015'), - ('The Eyes of the Dragon', 'description', 'Stephen King', '9781444723229', 2015), - ('Carrie', 'description', 'Stephen King', '9780307743664', '2011'), - ('The Great Book of Amber', 'description', 'Roger Zelazny', '9780380809066', 2011), - ('Misery', 'description', 'Stephen King', '9781444720716', 2011), - ('The Dry', 'description', 'Jane Harper', '9780349142111', 2017), - ('The Big Sleep and Other Novels', 'description', 'Raymond Chandler', '9780141182612', 2000), - ('The Maltese Falcon', 'description', 'Dashiell Hammett', '9780752865331', 2008), - ('The Black Dahlia', 'description', 'James Ellroy', '9780099537861', 2011), - ('The Long Goodbye', 'description', 'Raymond Chandler', '9780394757681', 1999); \ No newline at end of file diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql new file mode 100644 index 0000000..71ddeed --- /dev/null +++ b/src/main/resources/db/initDB.sql @@ -0,0 +1,37 @@ +DROP TABLE IF EXISTS test; +CREATE DATABASE test + DEFAULT CHARSET = utf8; + +CREATE TABLE users ( + id INT(10) NOT NULL AUTO_INCREMENT DEFAULT 1, + name VARCHAR(100) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + registered TIMESTAMP DEFAULT now() NOT NULL, + enabled BOOLEAN DEFAULT TRUE NOT NULL +) + ENGINE = InnoDB; + +CREATE TABLE user_roles +( + user_id INT(10) NOT NULL, + role VARCHAR(255), + FOREIGN KEY (user_id) REFERENCES users (id) + ON DELETE CASCADE +) + ENGINE = InnoDB; + +CREATE TABLE books ( + id INT(10) NOT NULL AUTO_INCREMENT DEFAULT 1, + title VARCHAR(100) NOT NULL, + description VARCHAR(255) NOT NULL, + author VARCHAR(100) NOT NULL, + isbn VARCHAR(20) NOT NULL, + printYear INT(4) NOT NULL, + readAlready BOOLEAN NOT NULL DEFAULT FALSE, + user_id INT(10) NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (user_id) REFERENCES users (id) + ON DELETE CASCADE +) + ENGINE = InnoDB; diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql new file mode 100644 index 0000000..92be5bb --- /dev/null +++ b/src/main/resources/db/populateDB.sql @@ -0,0 +1,40 @@ +INSERT INTO users (name, email, password) VALUES + ('User', 'user@yandex.ru', '{noop}password'), + ('Admin', 'admin@gmail.com', '{noop}admin'); + +INSERT INTO user_roles (role, user_id) VALUES + ('ROLE_USER', 1), + ('ROLE_ADMIN', 2); + + +INSERT INTO books (title, description, author, isbn, printYear, user_id) VALUES + ('A Brief History Of Time', 'description', 'Stephen Hawking', '9780857501004', 2015, 1), + ('The Picture of Dorian Gray', 'description', 'Oscar Wilde', '9781853260155', 1997, 1), + ('Don Quixote', 'description', 'Miguel de Cervantes', '9780099469698', 2005, 1), + ('Frankenstein', 'description', 'Mary Shelley', '9780141198965', 2016, 1), + ('Fahrenheit 451', 'description', 'Ray Bradbury', '9780006546061', 2008, 1), + ('The Little Prince', 'description', 'Antoine de Saint-Exupery', '9780749707231', 1991, 1), + ('The Idiot', 'description', 'Fyodor Dostoyevsky', '9780140447927', 2015, 1), + ('The Call of the Wild', 'description', 'Jack London', '9780141321059', 2008, 1), + ('Robinson Crusoe', 'description', 'Daniel Defoe', '9780199553976', 2009, 1), + ('A Game of Thrones', 'description', 'George Martin', '9780006479888', 2009, 1), + ('The Eye Of The World', 'description', 'Robert Jordan', '9780356503820', 2014, 1), + ('Eragon', 'description', 'Christopher Paolini', '9780552553209', 2008, 1), + ('It', 'description', 'Stephen King', '9781444707861', 2011, 1), + ('Sleeping Beauties', 'description', 'Stephen King', '9781473665194', 2011, 1), + ('The Shining', 'description', 'Stephen King', '9780307743657', 2012, 1), + ('The Stand', 'description', 'Stephen King', '9780307743688', 2011, 1), + ('11.22.63', 'description', 'Stephen King', '9781444727333', 2016, 1), + ('Mr Mercedes', 'description', 'Stephen King', '9781444788648', 2015, 1), + ('Finders Keepers', 'description', 'Stephen King', '9781473698956', 2016, 1), + ('The Dead Zone', 'description', 'Stephen King', '9781444708097', 2011, 1), + ('Revival', 'description', 'Stephen King', '9781444789218', 2015, 1), + ('The Eyes of the Dragon', 'description', 'Stephen King', '9781444723229', 2015, 1), + ('Carrie', 'description', 'Stephen King', '9780307743664', 2011, 1), + ('The Great Book of Amber', 'description', 'Roger Zelazny', '9780380809066', 2011, 1), + ('Misery', 'description', 'Stephen King', '9781444720716', 2011, 1), + ('The Dry', 'description', 'Jane Harper', '9780349142111', 2017, 1), + ('The Big Sleep and Other Novels', 'description', 'Raymond Chandler', '9780141182612', 2000, 1), + ('The Maltese Falcon', 'description', 'Dashiell Hammett', '9780752865331', 2008, 1), + ('The Black Dahlia', 'description', 'James Ellroy', '9780099537861', 2011, 1), + ('The Long Goodbye', 'description', 'Raymond Chandler', '9780394757681', 1999, 1); \ No newline at end of file From df5b93c7ba5434b9f94a661147f7332f911725a0 Mon Sep 17 00:00:00 2001 From: gvp Date: Tue, 26 Jun 2018 15:16:02 +0700 Subject: [PATCH 04/14] Add in BookDao and BookService dependency from user --- .../controller/BookController.java | 3 -- .../org/gvp/boookmanager/dao/BookDao.java | 9 +++-- .../org/gvp/boookmanager/dao/BookDaoImpl.java | 18 ++++++--- .../java/org/gvp/boookmanager/model/Book.java | 22 ++++++++++- .../gvp/boookmanager/service/BookService.java | 13 ++++--- .../boookmanager/service/BookServiceImpl.java | 37 +++++++++---------- 6 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/gvp/boookmanager/controller/BookController.java b/src/main/java/org/gvp/boookmanager/controller/BookController.java index 512ead0..5bb49e9 100644 --- a/src/main/java/org/gvp/boookmanager/controller/BookController.java +++ b/src/main/java/org/gvp/boookmanager/controller/BookController.java @@ -3,10 +3,7 @@ import org.gvp.boookmanager.model.Book; import org.gvp.boookmanager.service.BookService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.support.PagedListHolder; 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.annotation.*; diff --git a/src/main/java/org/gvp/boookmanager/dao/BookDao.java b/src/main/java/org/gvp/boookmanager/dao/BookDao.java index 7b7fa4c..7569d88 100644 --- a/src/main/java/org/gvp/boookmanager/dao/BookDao.java +++ b/src/main/java/org/gvp/boookmanager/dao/BookDao.java @@ -5,13 +5,14 @@ import java.util.List; public interface BookDao { - Book save(Book book); - boolean delete(Long id); + Book save(Book book, long userId); - Book get(Long id); + boolean delete(long id, long userId); - List getAll(); + Book get(long id, long userId); + + List getAll(long userId); List search(String searchText); } diff --git a/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java index ceb1a54..b8fcc18 100644 --- a/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java +++ b/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java @@ -3,6 +3,7 @@ import org.apache.lucene.search.Query; import org.gvp.boookmanager.model.Book; +import org.gvp.boookmanager.model.User; import org.gvp.boookmanager.support.search.SearchField; import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.Search; @@ -10,7 +11,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; @@ -28,8 +28,12 @@ public class BookDaoImpl implements BookDao { @Override - public Book save(Book book) { + public Book save(Book book, long userId) { logger.info("Save" + book); + if(book.getId() != null && get(book.getId(), userId) == null) { + return null; + } + book.setUser(em.getReference(User.class, userId)); if (book.getId() == null) { em.persist(book); return book; @@ -40,24 +44,26 @@ public Book save(Book book) { @Override - public boolean delete(Long id) { + public boolean delete(long id, long userId) { /*Book book = em.getReference(Book.class, id); em.remove(book); */ return em.createNamedQuery(Book.DELETE) .setParameter("id", id) + .setParameter("userId", userId) .executeUpdate() != 0; } @Override - public Book get(Long id) { - return em.find(Book.class, id); + public Book get(long id, long userId) { + Book book = em.find(Book.class, id); + return book != null && book.getUser().getId() == userId ? book : null; } @Override - public List getAll() { + public List getAll(long userId) { logger.info("Get all"); return em.createNamedQuery(Book.GET_ALL, Book.class).getResultList(); } diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index e7c5580..284a052 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -4,6 +4,8 @@ import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory; import org.apache.lucene.analysis.standard.StandardTokenizerFactory; import org.gvp.boookmanager.support.validation.Year; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import org.hibernate.search.annotations.*; import org.hibernate.search.annotations.Index; import org.hibernate.search.annotations.Parameter; @@ -14,8 +16,8 @@ @Entity @NamedQueries({ - @NamedQuery(name = Book.DELETE, query = "DELETE FROM Book b WHERE b.id=:id"), - @NamedQuery(name = Book.GET_ALL, query = "SELECT b FROM Book b") + @NamedQuery(name = Book.DELETE, query = "DELETE FROM Book b WHERE b.id=:id AND b.user.id=:userId"), + @NamedQuery(name = Book.GET_ALL, query = "SELECT b FROM Book b ORDER BY b.author ASC") }) @Table(name = "books") @Indexed @@ -59,6 +61,14 @@ public class Book extends AbstractBaseEntity{ @Column(name = "readAlready") private boolean readAlready; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) + //@NotNull(groups = View.Persist.class) + private User user; + + public Book() { + } + public Long getId() { return id; } @@ -115,6 +125,14 @@ public void setReadAlready(boolean readAlready) { this.readAlready = readAlready; } + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + @Override public String toString() { return "Book{" + diff --git a/src/main/java/org/gvp/boookmanager/service/BookService.java b/src/main/java/org/gvp/boookmanager/service/BookService.java index 8b609b5..f2489a5 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookService.java +++ b/src/main/java/org/gvp/boookmanager/service/BookService.java @@ -1,19 +1,20 @@ package org.gvp.boookmanager.service; - import org.gvp.boookmanager.model.Book; import java.util.List; public interface BookService { - Book save(Book book); + Book get(long id, long userId); + + void delete(long id, long userId); - boolean delete(Long id); + Book create(Book book, int userId); - Book get(Long id); + Book update(Book book, int userId); - List getALL(); + List getALL(long userId); List search(String searchText); - void makeRead(Book book); + void makeRead(Book book, long userId); } diff --git a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java index b8e8469..23ef2f2 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java @@ -9,11 +9,11 @@ import java.util.List; @Service -@Transactional +@Transactional(readOnly = true) public class BookServiceImpl implements BookService { - private BookDao bookDao; + private final BookDao bookDao; @Autowired public BookServiceImpl(BookDao bookDao) { @@ -21,40 +21,39 @@ public BookServiceImpl(BookDao bookDao) { } @Override - public void makeRead(Book book) { - book.setReadAlready(true); - bookDao.save(book); + public Book get(long id, long userId) { + return bookDao.get(id, userId); } + @Override @Transactional - public Book save(Book book) { - book.setReadAlready(false); - return bookDao.save(book); + public void delete(long id, long userId) { + bookDao.delete(id, userId); } - @Override - @Transactional - public boolean delete(Long id) { - return bookDao.delete(id); + public Book create(Book book, int userId) { + return bookDao.save(book, userId); } + @Override + public Book update(Book book, int userId) { + return bookDao.save(book, userId); + } @Override - @Transactional - public Book get(Long id) { - return bookDao.get(id); + public List getALL(long userId) { + return bookDao.getAll(userId); } @Override - @Transactional - public List getALL() { - return bookDao.getAll(); + public void makeRead(Book book, long userId) { + book.setReadAlready(true); + bookDao.save(book, userId); } - @Transactional public List search(String searchText) { return bookDao.search(searchText); } From eb9f56a00e47f95249bb9406537037bbb16fefa3 Mon Sep 17 00:00:00 2001 From: gvp Date: Tue, 26 Jun 2018 17:36:10 +0700 Subject: [PATCH 05/14] Add UserDao and Implementation --- .../org/gvp/boookmanager/dao/UserDao.java | 18 +++++++ .../org/gvp/boookmanager/dao/UserDaoImpl.java | 53 +++++++++++++++++++ .../java/org/gvp/boookmanager/model/Book.java | 1 + .../java/org/gvp/boookmanager/model/User.java | 10 ++++ 4 files changed, 82 insertions(+) create mode 100644 src/main/java/org/gvp/boookmanager/dao/UserDao.java create mode 100644 src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDao.java b/src/main/java/org/gvp/boookmanager/dao/UserDao.java new file mode 100644 index 0000000..103a861 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/dao/UserDao.java @@ -0,0 +1,18 @@ +package org.gvp.boookmanager.dao; + +import org.gvp.boookmanager.model.User; + +import java.util.List; + +public interface UserDao { + + User save(User user); + + boolean delete(int id); + + User get(int id); + + User getByEmail(String email); + + List getAll(); +} diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java new file mode 100644 index 0000000..79bd802 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java @@ -0,0 +1,53 @@ +package org.gvp.boookmanager.dao; + +import org.gvp.boookmanager.model.User; +import org.hibernate.jpa.QueryHints; +import org.springframework.dao.support.DataAccessUtils; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; + +public class UserDaoImpl implements UserDao { + + @PersistenceContext + private EntityManager em; + + @Override + public User save(User user) { + if(user.getId() == null) { + em.persist(user); + return user; + } else { + return em.merge(user); + } + } + + @Override + public User get(int id) { + return em.find(User.class, id); + } + + @Override + @Transactional + public boolean delete(int id) { + return em.createNamedQuery(User.DELETE) + .setParameter("id", id) + .executeUpdate() != 0; + } + + @Override + public User getByEmail(String email) { + List users = em.createNamedQuery(User.BY_EMAIL, User.class) + .setParameter("email", email) + .setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false) + .getResultList(); + return DataAccessUtils.singleResult(users); + } + + @Override + public List getAll() { + return em.createNamedQuery(User.ALL_SORTED, User.class).getResultList(); + } +} diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index 284a052..e6d9ed9 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -63,6 +63,7 @@ public class Book extends AbstractBaseEntity{ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) //@NotNull(groups = View.Persist.class) private User user; diff --git a/src/main/java/org/gvp/boookmanager/model/User.java b/src/main/java/org/gvp/boookmanager/model/User.java index 2076ed5..0b51d62 100644 --- a/src/main/java/org/gvp/boookmanager/model/User.java +++ b/src/main/java/org/gvp/boookmanager/model/User.java @@ -12,10 +12,20 @@ import javax.validation.constraints.Size; import java.util.*; +@NamedQueries({ + @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id"), + @NamedQuery(name = User.BY_EMAIL, query = "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=:email"), + @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u ORDER BY u.name"), +}) + @Entity @Table(name = "users" , uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) public class User extends AbstractNamedEntity { + public static final String DELETE = "User.delete"; + public static final String BY_EMAIL = "User.getByEmail"; + public static final String ALL_SORTED = "User.getAllSorted"; + @Column(name = "email") @Email @NotBlank From 86dd9d7a48d3c1955ee5850cc9384f5939667d50 Mon Sep 17 00:00:00 2001 From: gvp Date: Tue, 26 Jun 2018 22:50:07 +0700 Subject: [PATCH 06/14] refactor db scripts --- src/main/resources/db/initDB.sql | 15 +++++++++------ src/main/resources/db/populateDB.sql | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql index 71ddeed..bb48583 100644 --- a/src/main/resources/db/initDB.sql +++ b/src/main/resources/db/initDB.sql @@ -1,20 +1,23 @@ -DROP TABLE IF EXISTS test; +DROP DATABASE IF EXISTS test; CREATE DATABASE test DEFAULT CHARSET = utf8; + USE test; + CREATE TABLE users ( - id INT(10) NOT NULL AUTO_INCREMENT DEFAULT 1, + id BIGINT(10) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, registered TIMESTAMP DEFAULT now() NOT NULL, - enabled BOOLEAN DEFAULT TRUE NOT NULL + enabled BOOLEAN DEFAULT TRUE NOT NULL, + PRIMARY KEY (id) ) ENGINE = InnoDB; CREATE TABLE user_roles ( - user_id INT(10) NOT NULL, + user_id BIGINT(10) NOT NULL, role VARCHAR(255), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE @@ -22,14 +25,14 @@ CREATE TABLE user_roles ENGINE = InnoDB; CREATE TABLE books ( - id INT(10) NOT NULL AUTO_INCREMENT DEFAULT 1, + id BIGINT(10) NOT NULL AUTO_INCREMENT, title VARCHAR(100) NOT NULL, description VARCHAR(255) NOT NULL, author VARCHAR(100) NOT NULL, isbn VARCHAR(20) NOT NULL, printYear INT(4) NOT NULL, readAlready BOOLEAN NOT NULL DEFAULT FALSE, - user_id INT(10) NOT NULL, + user_id BIGINT(10) NOT NULL, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql index 92be5bb..f88e2a9 100644 --- a/src/main/resources/db/populateDB.sql +++ b/src/main/resources/db/populateDB.sql @@ -4,7 +4,8 @@ INSERT INTO users (name, email, password) VALUES INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 1), - ('ROLE_ADMIN', 2); + ('ROLE_ADMIN', 1), + ('ROLE_USER', 2); INSERT INTO books (title, description, author, isbn, printYear, user_id) VALUES From cba0a88a492b92be1cf0a830e384f4fa0dc4332b Mon Sep 17 00:00:00 2001 From: gvp Date: Tue, 26 Jun 2018 22:51:30 +0700 Subject: [PATCH 07/14] Add UserService --- .../controller/BookController.java | 14 ++--- .../java/org/gvp/boookmanager/model/User.java | 2 +- .../boookmanager/service/BookServiceImpl.java | 1 + .../gvp/boookmanager/service/UserService.java | 24 ++++++++ .../boookmanager/service/UserServiceImpl.java | 57 +++++++++++++++++++ 5 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/service/UserService.java create mode 100644 src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java diff --git a/src/main/java/org/gvp/boookmanager/controller/BookController.java b/src/main/java/org/gvp/boookmanager/controller/BookController.java index 5bb49e9..77d90b0 100644 --- a/src/main/java/org/gvp/boookmanager/controller/BookController.java +++ b/src/main/java/org/gvp/boookmanager/controller/BookController.java @@ -23,20 +23,20 @@ public BookController(BookService bookService) { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public List getAll() { - return bookService.getALL(); + return bookService.getALL(1); } @GetMapping("/{id}") - public Book get(@PathVariable("id") Long id) { - return bookService.get(id); + public Book get(@PathVariable("id") long id) { + return bookService.get(id, 1); } @DeleteMapping(value = "/delete/{id}") - public void delete(@PathVariable("id") Long id){ - bookService.delete(id); + public void delete(@PathVariable("id") long id){ + bookService.delete(id, 1); } - @PostMapping() + /* @PostMapping() public String update(@Valid @ModelAttribute("book") Book book, BindingResult bindingResult){ if(bindingResult.hasErrors()){ @@ -44,6 +44,6 @@ public String update(@Valid @ModelAttribute("book") Book book, BindingResult bin } bookService.save(book); return "redirect:/books"; - } + }**/ } diff --git a/src/main/java/org/gvp/boookmanager/model/User.java b/src/main/java/org/gvp/boookmanager/model/User.java index 0b51d62..fa2a7c6 100644 --- a/src/main/java/org/gvp/boookmanager/model/User.java +++ b/src/main/java/org/gvp/boookmanager/model/User.java @@ -19,7 +19,7 @@ }) @Entity -@Table(name = "users" , uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) +@Table(name = "users") public class User extends AbstractNamedEntity { public static final String DELETE = "User.delete"; diff --git a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java index 23ef2f2..c2fe8c9 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java @@ -38,6 +38,7 @@ public Book create(Book book, int userId) { } @Override + @Transactional public Book update(Book book, int userId) { return bookDao.save(book, userId); } diff --git a/src/main/java/org/gvp/boookmanager/service/UserService.java b/src/main/java/org/gvp/boookmanager/service/UserService.java new file mode 100644 index 0000000..4431b04 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/service/UserService.java @@ -0,0 +1,24 @@ +package org.gvp.boookmanager.service; + +import org.gvp.boookmanager.model.User; + +import java.util.List; + +public interface UserService { + + User create(User user); + + void delete(int id); + + User get(int id); + + User getByEmail(String email); + + void update(User user); + + List getAll(); + + void enable(int id, boolean enable); + + User getWithMeals(int id); +} diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java new file mode 100644 index 0000000..279584b --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -0,0 +1,57 @@ +package org.gvp.boookmanager.service; + +import org.gvp.boookmanager.dao.UserDao; +import org.gvp.boookmanager.model.User; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +public class UserServiceImpl implements UserService { + + private final UserDao userDao; + + @Autowired + public UserServiceImpl(UserDao userDao) { + this.userDao = userDao; + } + + @Override + public User create(User user) { + return null; + } + + @Override + public void delete(int id) { + + } + + @Override + public User get(int id) { + return null; + } + + @Override + public User getByEmail(String email) { + return null; + } + + @Override + public void update(User user) { + + } + + @Override + public List getAll() { + return null; + } + + @Override + public void enable(int id, boolean enable) { + + } + + @Override + public User getWithMeals(int id) { + return null; + } +} From 534a93bfc3fb77fd6912469079b6c463190f498e Mon Sep 17 00:00:00 2001 From: gvp Date: Wed, 4 Jul 2018 00:15:22 +0700 Subject: [PATCH 08/14] Add UserServiceImpl and Security --- pom.xml | 10 +-- .../controller/RootController.java | 23 ++++++ .../org/gvp/boookmanager/dao/UserDaoImpl.java | 2 + .../java/org/gvp/boookmanager/model/Book.java | 2 + .../gvp/boookmanager/service/UserService.java | 3 +- .../boookmanager/service/UserServiceImpl.java | 42 ++++++++--- .../support/security/AuthorizedUser.java | 34 +++++++++ .../spring}/appconfig-data.xml | 0 .../spring}/appconfig-mvc.xml | 0 .../spring}/appconfig-root.xml | 2 + .../resources/spring/appconfig-security.xml | 29 +++++++ src/main/webapp/WEB-INF/jsp/login.jsp | 75 +++++++++++++++++++ src/main/webapp/WEB-INF/web.xml | 14 +++- src/main/webapp/index.jsp | 3 - 14 files changed, 216 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/controller/RootController.java create mode 100644 src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java rename src/main/{webapp/WEB-INF => resources/spring}/appconfig-data.xml (100%) rename src/main/{webapp/WEB-INF => resources/spring}/appconfig-mvc.xml (100%) rename src/main/{webapp/WEB-INF => resources/spring}/appconfig-root.xml (93%) create mode 100644 src/main/resources/spring/appconfig-security.xml create mode 100644 src/main/webapp/WEB-INF/jsp/login.jsp delete mode 100644 src/main/webapp/index.jsp diff --git a/pom.xml b/pom.xml index 2e33785..8d46ea0 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ 1.8 - 4.3.12.RELEASE + 5.0.5.RELEASE 1.7.4 1.7.5 5.3.0.Final @@ -73,19 +73,17 @@ org.springframework.security - spring-security-core + spring-security-web ${spring-security.version} - org.springframework.security - spring-security-web + spring-security-config ${spring-security.version} - org.springframework.security - spring-security-config + spring-security-taglibs ${spring-security.version} diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java new file mode 100644 index 0000000..7c96c81 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -0,0 +1,23 @@ +package org.gvp.boookmanager.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class RootController { + + @GetMapping("/") + public String root() { + return "redirect:books"; + } + + @GetMapping("/books") + public String meals() { + return "books"; + } + + @GetMapping(value = "/login") + public String login() { + return "login"; + } +} diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java index 79bd802..6f73fce 100644 --- a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java +++ b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java @@ -3,12 +3,14 @@ import org.gvp.boookmanager.model.User; import org.hibernate.jpa.QueryHints; import org.springframework.dao.support.DataAccessUtils; +import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; +@Repository public class UserDaoImpl implements UserDao { @PersistenceContext diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index e6d9ed9..52f46b6 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -1,5 +1,6 @@ package org.gvp.boookmanager.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.apache.lucene.analysis.core.LowerCaseFilterFactory; import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory; import org.apache.lucene.analysis.standard.StandardTokenizerFactory; @@ -65,6 +66,7 @@ public class Book extends AbstractBaseEntity{ @JoinColumn(name = "user_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) //@NotNull(groups = View.Persist.class) + @JsonIgnore private User user; public Book() { diff --git a/src/main/java/org/gvp/boookmanager/service/UserService.java b/src/main/java/org/gvp/boookmanager/service/UserService.java index 4431b04..598dc77 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserService.java +++ b/src/main/java/org/gvp/boookmanager/service/UserService.java @@ -18,7 +18,6 @@ public interface UserService { List getAll(); - void enable(int id, boolean enable); + void enable(int id, boolean enabled); - User getWithMeals(int id); } diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java index 279584b..46fbbda 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -2,11 +2,20 @@ import org.gvp.boookmanager.dao.UserDao; import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.support.security.AuthorizedUser; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; import java.util.List; -public class UserServiceImpl implements UserService { +@Service +@Transactional(readOnly = true) +public class UserServiceImpl implements UserService, UserDetailsService { private final UserDao userDao; @@ -15,43 +24,54 @@ public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } + @Transactional @Override public User create(User user) { - return null; + Assert.notNull(user, "user must not be null"); + return userDao.save(user); } + @Transactional @Override public void delete(int id) { - + userDao.delete(id); } @Override public User get(int id) { - return null; + return userDao.get(id); } @Override public User getByEmail(String email) { - return null; + return userDao.getByEmail(email); } + @Transactional @Override public void update(User user) { - + userDao.save(user); } @Override public List getAll() { - return null; + return userDao.getAll(); } + @Transactional @Override - public void enable(int id, boolean enable) { - + public void enable(int id, boolean enabled) { + User user = get(id); + user.setEnabled(enabled); + userDao.save(user); } @Override - public User getWithMeals(int id) { - return null; + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + User user = userDao.getByEmail(email.toLowerCase()); + if (user == null) { + throw new UsernameNotFoundException("User " + email + " is not found"); + } + return new AuthorizedUser(user); } } diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java new file mode 100644 index 0000000..075ff9a --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -0,0 +1,34 @@ +package org.gvp.boookmanager.support.security; + + +import org.gvp.boookmanager.model.User; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import static java.util.Objects.requireNonNull; + +public class AuthorizedUser extends org.springframework.security.core.userdetails.User { + + + public AuthorizedUser(User user) { + super(user.getEmail(), user.getPassword(), user.isEnabled(), true, true, true, user.getRoles()); + } + + public static AuthorizedUser safeGet() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null) { + return null; + } + Object principal = auth.getPrincipal(); + return (principal instanceof AuthorizedUser) ? (AuthorizedUser) principal : null; + } + + public static AuthorizedUser get() { + AuthorizedUser user = safeGet(); + requireNonNull(user, "No authorized user found"); + return user; + } + + + +} diff --git a/src/main/webapp/WEB-INF/appconfig-data.xml b/src/main/resources/spring/appconfig-data.xml similarity index 100% rename from src/main/webapp/WEB-INF/appconfig-data.xml rename to src/main/resources/spring/appconfig-data.xml diff --git a/src/main/webapp/WEB-INF/appconfig-mvc.xml b/src/main/resources/spring/appconfig-mvc.xml similarity index 100% rename from src/main/webapp/WEB-INF/appconfig-mvc.xml rename to src/main/resources/spring/appconfig-mvc.xml diff --git a/src/main/webapp/WEB-INF/appconfig-root.xml b/src/main/resources/spring/appconfig-root.xml similarity index 93% rename from src/main/webapp/WEB-INF/appconfig-root.xml rename to src/main/resources/spring/appconfig-root.xml index 70a88ce..ab94093 100644 --- a/src/main/webapp/WEB-INF/appconfig-root.xml +++ b/src/main/resources/spring/appconfig-root.xml @@ -10,6 +10,8 @@ + + diff --git a/src/main/resources/spring/appconfig-security.xml b/src/main/resources/spring/appconfig-security.xml new file mode 100644 index 0000000..b66a240 --- /dev/null +++ b/src/main/resources/spring/appconfig-security.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/login.jsp b/src/main/webapp/WEB-INF/jsp/login.jsp new file mode 100644 index 0000000..b2047ea --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/login.jsp @@ -0,0 +1,75 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> +<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> + + + + + + +
+
+ +
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
+
+ +
+
+
+

+ + +

+
+

Стек технологий: Spring Security, + Spring MVC, + Spring Data JPA, + Spring Security + Test, + Hibernate ORM, + Hibernate Validator, + SLF4J, + Json Jackson, + JSP, + JSTL, + Apache Tomcat, + WebJars, + DataTables plugin, + EHCACHE, + PostgreSQL, + JUnit, + Hamcrest, + jQuery, + jQuery notification, + Bootstrap.

+
+
+
+
+    Java Enterprise проект с + регистрацией/авторизацией и интерфейсом на основе ролей (USER, ADMIN). + Администратор может создавать/редактировать/удалять пользователей, а пользователи - управлять своим + профилем и данными (день, еда, калории) через UI (по AJAX) и по REST интерфейсу с базовой авторизацией. + Возможна фильтрация данных по датам и времени, при этом цвет записи таблицы еды зависит от того, превышает ли + сумма + калорий за день норму (редактируемый параметр в профиле пользователя). + Весь REST интерфейс покрывается JUnit тестами, используя Spring MVC Test и Spring Security Test. +
+
+ + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 72ea58f..82ffece 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -4,6 +4,7 @@ http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> Book Manager + org.springframework.web.context.ContextLoaderListener @@ -13,7 +14,7 @@ contextConfigLocation - /WEB-INF/appconfig-root.xml + classpath:/spring/appconfig-root.xml @@ -37,4 +38,15 @@ *.css + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + springSecurityFilterChain + /* + + + + \ No newline at end of file diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp deleted file mode 100644 index 52e7a99..0000000 --- a/src/main/webapp/index.jsp +++ /dev/null @@ -1,3 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ page contentType="text/html;charset=UTF-8" language="java" %> - \ No newline at end of file From 828f9bc66b1528d0a871339367212cb43523d72d Mon Sep 17 00:00:00 2001 From: gvp Date: Fri, 6 Jul 2018 15:42:32 +0700 Subject: [PATCH 09/14] Implements Controllers --- .../controller/BookController.java | 32 +++++------ .../controller/UserController.java | 53 +++++++++++++++++++ .../org/gvp/boookmanager/dao/UserDao.java | 4 +- .../org/gvp/boookmanager/dao/UserDaoImpl.java | 4 +- .../gvp/boookmanager/service/BookService.java | 4 +- .../boookmanager/service/BookServiceImpl.java | 4 +- .../gvp/boookmanager/service/UserService.java | 8 ++- .../boookmanager/service/UserServiceImpl.java | 10 ++-- .../support/security/AuthorizedUser.java | 17 ++---- .../resources/spring/appconfig-security.xml | 10 ++-- 10 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/controller/UserController.java diff --git a/src/main/java/org/gvp/boookmanager/controller/BookController.java b/src/main/java/org/gvp/boookmanager/controller/BookController.java index 77d90b0..dcfcc35 100644 --- a/src/main/java/org/gvp/boookmanager/controller/BookController.java +++ b/src/main/java/org/gvp/boookmanager/controller/BookController.java @@ -2,9 +2,10 @@ import org.gvp.boookmanager.model.Book; import org.gvp.boookmanager.service.BookService; +import org.gvp.boookmanager.support.security.AuthorizedUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; -import org.springframework.validation.BindingResult; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -22,28 +23,27 @@ public BookController(BookService bookService) { } @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - public List getAll() { - return bookService.getALL(1); + public List getAll(@AuthenticationPrincipal AuthorizedUser authorizedUser) { + return bookService.getALL(authorizedUser.getId()); } - @GetMapping("/{id}") - public Book get(@PathVariable("id") long id) { - return bookService.get(id, 1); + @GetMapping( value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public Book get(@PathVariable("id") long id, @AuthenticationPrincipal AuthorizedUser authorizedUser) { + return bookService.get(id, authorizedUser.getId()); } @DeleteMapping(value = "/delete/{id}") - public void delete(@PathVariable("id") long id){ - bookService.delete(id, 1); + public void delete(@PathVariable("id") long id, @AuthenticationPrincipal AuthorizedUser authorizedUser){ + bookService.delete(id, authorizedUser.getId()); } - /* @PostMapping() - public String update(@Valid @ModelAttribute("book") Book book, BindingResult bindingResult){ - - if(bindingResult.hasErrors()){ - return "bookForm"; + @PostMapping() + public void update(@Valid @ModelAttribute Book book, @AuthenticationPrincipal AuthorizedUser authorizedUser){ + if(book.getId() == null) { + bookService.create(book, authorizedUser.getId()); + } else { + bookService.update(book, authorizedUser.getId()); } - bookService.save(book); - return "redirect:/books"; - }**/ + } } diff --git a/src/main/java/org/gvp/boookmanager/controller/UserController.java b/src/main/java/org/gvp/boookmanager/controller/UserController.java new file mode 100644 index 0000000..29cc888 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/controller/UserController.java @@ -0,0 +1,53 @@ +package org.gvp.boookmanager.controller; + +import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@RestController +public class UserController { + + private final UserService userService; + + @Autowired + public UserController(UserService userService) { + this.userService = userService; + } + + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public List getAll() { + return userService.getAll(); + } + + + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public User get(@PathVariable("id") int id) { + return userService.get(id); + } + + + @DeleteMapping("/{id}") + public void delete(@PathVariable("id") int id) { + userService.delete(id); + } + + @PostMapping + public void createOrUpdate(@Valid @ModelAttribute User user) { + if (user.getId() == null) { + userService.create(user); + } else { + userService.update(user); + } + } + + @PostMapping(value = "/{id}") + public void enable(@PathVariable("id") int id, @RequestParam("enabled") boolean enabled) { + userService.enable(id, enabled); + } +} diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDao.java b/src/main/java/org/gvp/boookmanager/dao/UserDao.java index 103a861..f99bc7a 100644 --- a/src/main/java/org/gvp/boookmanager/dao/UserDao.java +++ b/src/main/java/org/gvp/boookmanager/dao/UserDao.java @@ -8,9 +8,9 @@ public interface UserDao { User save(User user); - boolean delete(int id); + boolean delete(long id); - User get(int id); + User get(long id); User getByEmail(String email); diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java index 6f73fce..f689cce 100644 --- a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java +++ b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java @@ -27,13 +27,13 @@ public User save(User user) { } @Override - public User get(int id) { + public User get(long id) { return em.find(User.class, id); } @Override @Transactional - public boolean delete(int id) { + public boolean delete(long id) { return em.createNamedQuery(User.DELETE) .setParameter("id", id) .executeUpdate() != 0; diff --git a/src/main/java/org/gvp/boookmanager/service/BookService.java b/src/main/java/org/gvp/boookmanager/service/BookService.java index f2489a5..1e1f0f3 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookService.java +++ b/src/main/java/org/gvp/boookmanager/service/BookService.java @@ -8,9 +8,9 @@ public interface BookService { void delete(long id, long userId); - Book create(Book book, int userId); + Book create(Book book, long userId); - Book update(Book book, int userId); + Book update(Book book, long userId); List getALL(long userId); diff --git a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java index c2fe8c9..85d82b7 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java @@ -33,13 +33,13 @@ public void delete(long id, long userId) { } @Override - public Book create(Book book, int userId) { + public Book create(Book book, long userId) { return bookDao.save(book, userId); } @Override @Transactional - public Book update(Book book, int userId) { + public Book update(Book book, long userId) { return bookDao.save(book, userId); } diff --git a/src/main/java/org/gvp/boookmanager/service/UserService.java b/src/main/java/org/gvp/boookmanager/service/UserService.java index 598dc77..b059693 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserService.java +++ b/src/main/java/org/gvp/boookmanager/service/UserService.java @@ -8,16 +8,14 @@ public interface UserService { User create(User user); - void delete(int id); + void delete(long id); - User get(int id); - - User getByEmail(String email); + User get(long id); void update(User user); List getAll(); - void enable(int id, boolean enabled); + void enable(long id, boolean enabled); } diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java index 46fbbda..500245b 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -33,19 +33,15 @@ public User create(User user) { @Transactional @Override - public void delete(int id) { + public void delete(long id) { userDao.delete(id); } @Override - public User get(int id) { + public User get(long id) { return userDao.get(id); } - @Override - public User getByEmail(String email) { - return userDao.getByEmail(email); - } @Transactional @Override @@ -60,7 +56,7 @@ public List getAll() { @Transactional @Override - public void enable(int id, boolean enabled) { + public void enable(long id, boolean enabled) { User user = get(id); user.setEnabled(enabled); userDao.save(user); diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java index 075ff9a..e6bdfe7 100644 --- a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -9,24 +9,15 @@ public class AuthorizedUser extends org.springframework.security.core.userdetails.User { + private User user; public AuthorizedUser(User user) { super(user.getEmail(), user.getPassword(), user.isEnabled(), true, true, true, user.getRoles()); + this.user = user; } - public static AuthorizedUser safeGet() { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null) { - return null; - } - Object principal = auth.getPrincipal(); - return (principal instanceof AuthorizedUser) ? (AuthorizedUser) principal : null; - } - - public static AuthorizedUser get() { - AuthorizedUser user = safeGet(); - requireNonNull(user, "No authorized user found"); - return user; + public long getId() { + return user.getId(); } diff --git a/src/main/resources/spring/appconfig-security.xml b/src/main/resources/spring/appconfig-security.xml index b66a240..9818715 100644 --- a/src/main/resources/spring/appconfig-security.xml +++ b/src/main/resources/spring/appconfig-security.xml @@ -7,6 +7,9 @@ + + @@ -14,16 +17,17 @@ - - - + \ No newline at end of file From 78bebce172c3714a15e49e3e67c14a9b4161e651 Mon Sep 17 00:00:00 2001 From: gvp Date: Wed, 11 Jul 2018 00:14:47 +0700 Subject: [PATCH 10/14] Add profile controller's methods and jsp --- .../controller/RootController.java | 40 ++++++- .../controller/UserController.java | 1 + .../boookmanager/service/UserServiceImpl.java | 1 + .../support/security/AuthorizedUser.java | 13 ++- src/main/resources/db/populateDB.sql | 2 +- src/main/resources/spring/appconfig-mvc.xml | 6 +- .../resources/spring/appconfig-security.xml | 6 +- src/main/webapp/WEB-INF/jsp/bookForm.jsp | 3 - src/main/webapp/WEB-INF/jsp/books.jsp | 105 +++++++++--------- src/main/webapp/WEB-INF/jsp/login.jsp | 87 +++++---------- .../webapp/WEB-INF/jsp/parts/navigation.jsp | 22 ++-- .../webapp/WEB-INF/jsp/parts/pagination.jsp | 39 ------- src/main/webapp/WEB-INF/jsp/profile.jsp | 38 +++++++ src/main/webapp/WEB-INF/jsp/search.jsp | 2 +- 14 files changed, 184 insertions(+), 181 deletions(-) delete mode 100644 src/main/webapp/WEB-INF/jsp/parts/pagination.jsp create mode 100644 src/main/webapp/WEB-INF/jsp/profile.jsp diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java index 7c96c81..eb4fa3b 100644 --- a/src/main/java/org/gvp/boookmanager/controller/RootController.java +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -1,18 +1,39 @@ package org.gvp.boookmanager.controller; +import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.service.UserService; +import org.gvp.boookmanager.support.security.AuthorizedUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.support.SessionStatus; + +import javax.validation.Valid; + @Controller public class RootController { + private final UserService userService; + + @Autowired + public RootController(UserService userService) { + this.userService = userService; + } + @GetMapping("/") public String root() { return "redirect:books"; } @GetMapping("/books") - public String meals() { + public String books() { return "books"; } @@ -20,4 +41,21 @@ public String meals() { public String login() { return "login"; } + + @GetMapping("/profile") + public String profile(Model model, @AuthenticationPrincipal AuthorizedUser authorizedUser) { + model.addAttribute("user", authorizedUser.getUser()); + return "profile"; + } + + @RequestMapping(name = "/profile", method = RequestMethod.POST) + public String updateProfile(@Valid User user, BindingResult result, SessionStatus status, @AuthenticationPrincipal AuthorizedUser authorizedUser) { + if (result.hasErrors()) { + return "profile"; + } + userService.update(user); + authorizedUser.setUser(user); + status.setComplete(); + return "redirect:books"; + } } diff --git a/src/main/java/org/gvp/boookmanager/controller/UserController.java b/src/main/java/org/gvp/boookmanager/controller/UserController.java index 29cc888..3b4d1db 100644 --- a/src/main/java/org/gvp/boookmanager/controller/UserController.java +++ b/src/main/java/org/gvp/boookmanager/controller/UserController.java @@ -10,6 +10,7 @@ import java.util.List; @RestController +@RequestMapping(name = "/users") public class UserController { private final UserService userService; diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java index 500245b..56b3728 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -64,6 +64,7 @@ public void enable(long id, boolean enabled) { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + System.out.println(email + "is email"); User user = userDao.getByEmail(email.toLowerCase()); if (user == null) { throw new UsernameNotFoundException("User " + email + " is not found"); diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java index e6bdfe7..b6cdb62 100644 --- a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -2,17 +2,13 @@ import org.gvp.boookmanager.model.User; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -import static java.util.Objects.requireNonNull; public class AuthorizedUser extends org.springframework.security.core.userdetails.User { private User user; public AuthorizedUser(User user) { - super(user.getEmail(), user.getPassword(), user.isEnabled(), true, true, true, user.getRoles()); + super(user.getEmail(), user.getPassword(), user.getRoles()); this.user = user; } @@ -20,6 +16,11 @@ public long getId() { return user.getId(); } + public User getUser() { + return user; + } - + public void setUser(User user) { + this.user = user; + } } diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql index f88e2a9..e5828be 100644 --- a/src/main/resources/db/populateDB.sql +++ b/src/main/resources/db/populateDB.sql @@ -4,7 +4,7 @@ INSERT INTO users (name, email, password) VALUES INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 1), - ('ROLE_ADMIN', 1), + ('ROLE_ADMIN', 2), ('ROLE_USER', 2); diff --git a/src/main/resources/spring/appconfig-mvc.xml b/src/main/resources/spring/appconfig-mvc.xml index 3471410..f48faea 100644 --- a/src/main/resources/spring/appconfig-mvc.xml +++ b/src/main/resources/spring/appconfig-mvc.xml @@ -4,7 +4,11 @@ xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - + + + + + diff --git a/src/main/resources/spring/appconfig-security.xml b/src/main/resources/spring/appconfig-security.xml index 9818715..779f0d1 100644 --- a/src/main/resources/spring/appconfig-security.xml +++ b/src/main/resources/spring/appconfig-security.xml @@ -7,6 +7,7 @@ + @@ -14,7 +15,7 @@ - + + - + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/bookForm.jsp b/src/main/webapp/WEB-INF/jsp/bookForm.jsp index b612b8d..8faef65 100644 --- a/src/main/webapp/WEB-INF/jsp/bookForm.jsp +++ b/src/main/webapp/WEB-INF/jsp/bookForm.jsp @@ -64,9 +64,6 @@ value=Save> -
- -
diff --git a/src/main/webapp/WEB-INF/jsp/books.jsp b/src/main/webapp/WEB-INF/jsp/books.jsp index 24652e3..8c502dd 100644 --- a/src/main/webapp/WEB-INF/jsp/books.jsp +++ b/src/main/webapp/WEB-INF/jsp/books.jsp @@ -11,62 +11,61 @@ <%@include file="parts/header.jsp" %> -
-
- <%@include file="parts/navigation.jsp" %> -
- - <%@include file="parts/pagination.jsp" %>
+ diff --git a/src/main/webapp/WEB-INF/jsp/login.jsp b/src/main/webapp/WEB-INF/jsp/login.jsp index b2047ea..1516387 100644 --- a/src/main/webapp/WEB-INF/jsp/login.jsp +++ b/src/main/webapp/WEB-INF/jsp/login.jsp @@ -5,71 +5,34 @@ - + Welcome + - -
-
- -
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
-
- -
-
-
-

- - -

-
-

Стек технологий: Spring Security, - Spring MVC, - Spring Data JPA, - Spring Security - Test, - Hibernate ORM, - Hibernate Validator, - SLF4J, - Json Jackson, - JSP, - JSTL, - Apache Tomcat, - WebJars, - DataTables plugin, - EHCACHE, - PostgreSQL, - JUnit, - Hamcrest, - jQuery, - jQuery notification, - Bootstrap.

-
-
+
-
-    Java Enterprise проект с - регистрацией/авторизацией и интерфейсом на основе ролей (USER, ADMIN). - Администратор может создавать/редактировать/удалять пользователей, а пользователи - управлять своим - профилем и данными (день, еда, калории) через UI (по AJAX) и по REST интерфейсу с базовой авторизацией. - Возможна фильтрация данных по датам и времени, при этом цвет записи таблицы еды зависит от того, превышает ли - сумма - калорий за день норму (редактируемый параметр в профиле пользователя). - Весь REST интерфейс покрывается JUnit тестами, используя Spring MVC Test и Spring Security Test. +
+
+
+

Please sign in

+
+
+ + +
+
+ + + + + +
+ +
+
+
- \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp b/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp index 619b9a5..b490267 100644 --- a/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp +++ b/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp @@ -1,24 +1,22 @@ +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %>
\ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/parts/pagination.jsp b/src/main/webapp/WEB-INF/jsp/parts/pagination.jsp deleted file mode 100644 index 3abb1cd..0000000 --- a/src/main/webapp/WEB-INF/jsp/parts/pagination.jsp +++ /dev/null @@ -1,39 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -
-
- -
-
diff --git a/src/main/webapp/WEB-INF/jsp/profile.jsp b/src/main/webapp/WEB-INF/jsp/profile.jsp new file mode 100644 index 0000000..9a77bf4 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/profile.jsp @@ -0,0 +1,38 @@ +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + <sec:authentication property="principal.username"/> + <%@include file="parts/header.jsp" %> + + +
+ <%@include file="parts/navigation.jsp" %> +
+
+
+ +
+ Name + + +
+
+ Email + + +
+
+ Password + + +
+ +
+
+
+
+
+ + diff --git a/src/main/webapp/WEB-INF/jsp/search.jsp b/src/main/webapp/WEB-INF/jsp/search.jsp index c9ea256..383317e 100644 --- a/src/main/webapp/WEB-INF/jsp/search.jsp +++ b/src/main/webapp/WEB-INF/jsp/search.jsp @@ -1,4 +1,4 @@ -<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page session="false" %> From 47820584552f9fa6fbd70839533b1f376ce8c72d Mon Sep 17 00:00:00 2001 From: gvp Date: Wed, 11 Jul 2018 17:48:03 +0700 Subject: [PATCH 11/14] Add UserTo and register form --- .../controller/RootController.java | 49 +++++++++++++--- .../gvp/boookmanager/service/UserService.java | 3 + .../boookmanager/service/UserServiceImpl.java | 10 ++++ .../support/security/AuthorizedUser.java | 16 ++--- .../java/org/gvp/boookmanager/to/BaseTo.java | 24 ++++++++ .../java/org/gvp/boookmanager/to/UserTo.java | 58 +++++++++++++++++++ .../org/gvp/boookmanager/util/UserUtil.java | 33 +++++++++++ src/main/webapp/WEB-INF/jsp/profile.jsp | 4 +- 8 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/to/BaseTo.java create mode 100644 src/main/java/org/gvp/boookmanager/to/UserTo.java create mode 100644 src/main/java/org/gvp/boookmanager/util/UserUtil.java diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java index eb4fa3b..dc696f9 100644 --- a/src/main/java/org/gvp/boookmanager/controller/RootController.java +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -1,12 +1,15 @@ package org.gvp.boookmanager.controller; -import org.gvp.boookmanager.model.User; import org.gvp.boookmanager.service.UserService; import org.gvp.boookmanager.support.security.AuthorizedUser; +import org.gvp.boookmanager.to.UserTo; +import org.gvp.boookmanager.util.UserUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -44,18 +47,50 @@ public String login() { @GetMapping("/profile") public String profile(Model model, @AuthenticationPrincipal AuthorizedUser authorizedUser) { - model.addAttribute("user", authorizedUser.getUser()); + model.addAttribute("userTo", authorizedUser.getUserTo()); return "profile"; } @RequestMapping(name = "/profile", method = RequestMethod.POST) - public String updateProfile(@Valid User user, BindingResult result, SessionStatus status, @AuthenticationPrincipal AuthorizedUser authorizedUser) { + public String updateProfile(@Valid UserTo userTo, BindingResult result, SessionStatus status, @AuthenticationPrincipal AuthorizedUser authorizedUser) { if (result.hasErrors()) { return "profile"; } - userService.update(user); - authorizedUser.setUser(user); - status.setComplete(); - return "redirect:books"; + try { + userService.update(userTo); + authorizedUser.setUserTo(userTo); + status.setComplete(); + return "redirect:books"; + } catch (DataIntegrityViolationException ex) { + result.rejectValue("email", "email already exist"); + return "profile"; + } + + } + + @GetMapping("/register") + public String register(ModelMap model) { + model.addAttribute("userTo", new UserTo()); + model.addAttribute("register", true); + return "profile"; + } + + @PostMapping("/register") + public String saveRegister(@Valid UserTo userTo, BindingResult result, SessionStatus status, Model model) { + if (result.hasErrors()) { + model.addAttribute("register", true); + return "profile"; + } + try { + userService.create(UserUtil.createNewFromTo(userTo)); + status.setComplete(); + return "redirect:login?message=app.registered&username=" + userTo.getEmail(); + } catch (DataIntegrityViolationException ex) { + result.rejectValue("email", "email already exist"); + model.addAttribute("register", true); + return "profile"; + } } + + } diff --git a/src/main/java/org/gvp/boookmanager/service/UserService.java b/src/main/java/org/gvp/boookmanager/service/UserService.java index b059693..2f100bb 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserService.java +++ b/src/main/java/org/gvp/boookmanager/service/UserService.java @@ -1,6 +1,7 @@ package org.gvp.boookmanager.service; import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.to.UserTo; import java.util.List; @@ -14,6 +15,8 @@ public interface UserService { void update(User user); + void update(UserTo userTo); + List getAll(); void enable(long id, boolean enabled); diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java index 56b3728..4dbb24d 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -3,6 +3,8 @@ import org.gvp.boookmanager.dao.UserDao; import org.gvp.boookmanager.model.User; import org.gvp.boookmanager.support.security.AuthorizedUser; +import org.gvp.boookmanager.to.UserTo; +import org.gvp.boookmanager.util.UserUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -49,6 +51,14 @@ public void update(User user) { userDao.save(user); } + + @Transactional + @Override + public void update(UserTo userTo) { + User user = UserUtil.updateFromTo(get(userTo.getId()), userTo); + userDao.save(user); + } + @Override public List getAll() { return userDao.getAll(); diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java index b6cdb62..538f80c 100644 --- a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -2,25 +2,27 @@ import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.to.UserTo; +import org.gvp.boookmanager.util.UserUtil; public class AuthorizedUser extends org.springframework.security.core.userdetails.User { - private User user; + private UserTo userTo; public AuthorizedUser(User user) { super(user.getEmail(), user.getPassword(), user.getRoles()); - this.user = user; + this.userTo = UserUtil.asTo(user); } public long getId() { - return user.getId(); + return userTo.getId(); } - public User getUser() { - return user; + public UserTo getUserTo() { + return userTo; } - public void setUser(User user) { - this.user = user; + public void setUserTo(UserTo userTo) { + this.userTo = userTo; } } diff --git a/src/main/java/org/gvp/boookmanager/to/BaseTo.java b/src/main/java/org/gvp/boookmanager/to/BaseTo.java new file mode 100644 index 0000000..c70035f --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/to/BaseTo.java @@ -0,0 +1,24 @@ +package org.gvp.boookmanager.to; + +public abstract class BaseTo { + + protected Long id; + + public BaseTo() { + } + + public BaseTo(Long id) { + this.id = id; + } + + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/src/main/java/org/gvp/boookmanager/to/UserTo.java b/src/main/java/org/gvp/boookmanager/to/UserTo.java new file mode 100644 index 0000000..cd1a6e3 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/to/UserTo.java @@ -0,0 +1,58 @@ +package org.gvp.boookmanager.to; + +import org.hibernate.validator.constraints.Email; +import org.hibernate.validator.constraints.NotBlank; +import org.hibernate.validator.constraints.SafeHtml; + +import javax.validation.constraints.Size; + +public class UserTo extends BaseTo { + + @NotBlank + @Size(min = 2, max = 100) + @SafeHtml + private String name; + + @Email + @NotBlank + @Size(max = 100) + @SafeHtml + private String email; + + @Size(min = 5, max = 32, message = "length must between 5 and 32 characters") + private String password; + + public UserTo() { + } + + public UserTo(Long id, String name, String email, String password) { + super(id); + this.name = name; + this.email = email; + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/org/gvp/boookmanager/util/UserUtil.java b/src/main/java/org/gvp/boookmanager/util/UserUtil.java new file mode 100644 index 0000000..649bb6e --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/util/UserUtil.java @@ -0,0 +1,33 @@ +package org.gvp.boookmanager.util; + +import org.gvp.boookmanager.model.Role; +import org.gvp.boookmanager.model.User; +import org.gvp.boookmanager.to.UserTo; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.StringUtils; + +public class UserUtil { + + + public static User createNewFromTo(UserTo newUser) { + return new User(null, newUser.getName(), newUser.getEmail().toLowerCase(), newUser.getPassword(), Role.ROLE_USER); + } + + public static UserTo asTo(User user) { + return new UserTo(user.getId(), user.getName(), user.getEmail(), user.getPassword()); + } + + public static User updateFromTo(User user, UserTo userTo) { + user.setName(userTo.getName()); + user.setEmail(userTo.getEmail().toLowerCase()); + user.setPassword(userTo.getPassword()); + return user; + } + + public static User prepareToSave(User user, PasswordEncoder passwordEncoder) { + String password = user.getPassword(); + user.setPassword(StringUtils.isEmpty(password) ? password : passwordEncoder.encode(password)); + user.setEmail(user.getEmail().toLowerCase()); + return user; + } +} diff --git a/src/main/webapp/WEB-INF/jsp/profile.jsp b/src/main/webapp/WEB-INF/jsp/profile.jsp index 9a77bf4..25e0e97 100644 --- a/src/main/webapp/WEB-INF/jsp/profile.jsp +++ b/src/main/webapp/WEB-INF/jsp/profile.jsp @@ -3,7 +3,7 @@ <%@ page contentType="text/html;charset=UTF-8" language="java" %> - <sec:authentication property="principal.username"/> + ${register ? "Registration" : "My profile"} <%@include file="parts/header.jsp" %> @@ -12,7 +12,7 @@
- +
Name From 31445aea2b6dc1331cc31d491a19befc43754207 Mon Sep 17 00:00:00 2001 From: gvp Date: Fri, 13 Jul 2018 01:04:23 +0700 Subject: [PATCH 12/14] Refactoring jsp --- .../controller/RootController.java | 6 +- .../boookmanager/service/UserServiceImpl.java | 10 ++- .../java/org/gvp/boookmanager/to/UserTo.java | 3 +- src/main/webapp/WEB-INF/jsp/books.jsp | 84 ++++++++----------- src/main/webapp/WEB-INF/jsp/login.jsp | 13 ++- src/main/webapp/WEB-INF/jsp/profile.jsp | 16 ++-- 6 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java index dc696f9..d8036ca 100644 --- a/src/main/java/org/gvp/boookmanager/controller/RootController.java +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -51,7 +51,7 @@ public String profile(Model model, @AuthenticationPrincipal AuthorizedUser autho return "profile"; } - @RequestMapping(name = "/profile", method = RequestMethod.POST) + @PostMapping("/profile") public String updateProfile(@Valid UserTo userTo, BindingResult result, SessionStatus status, @AuthenticationPrincipal AuthorizedUser authorizedUser) { if (result.hasErrors()) { return "profile"; @@ -76,7 +76,7 @@ public String register(ModelMap model) { } @PostMapping("/register") - public String saveRegister(@Valid UserTo userTo, BindingResult result, SessionStatus status, Model model) { + public String saveRegister(@Valid UserTo userTo, BindingResult result, SessionStatus status, ModelMap model) { if (result.hasErrors()) { model.addAttribute("register", true); return "profile"; @@ -84,7 +84,7 @@ public String saveRegister(@Valid UserTo userTo, BindingResult result, SessionSt try { userService.create(UserUtil.createNewFromTo(userTo)); status.setComplete(); - return "redirect:login?message=app.registered&username=" + userTo.getEmail(); + return "redirect:login?success=true"; } catch (DataIntegrityViolationException ex) { result.rejectValue("email", "email already exist"); model.addAttribute("register", true); diff --git a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java index 4dbb24d..6462c97 100644 --- a/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/UserServiceImpl.java @@ -9,6 +9,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -20,17 +21,19 @@ public class UserServiceImpl implements UserService, UserDetailsService { private final UserDao userDao; + private final PasswordEncoder passwordEncoder; @Autowired - public UserServiceImpl(UserDao userDao) { + public UserServiceImpl(UserDao userDao, PasswordEncoder passwordEncoder) { this.userDao = userDao; + this.passwordEncoder = passwordEncoder; } @Transactional @Override public User create(User user) { Assert.notNull(user, "user must not be null"); - return userDao.save(user); + return userDao.save(UserUtil.prepareToSave(user, passwordEncoder)); } @Transactional @@ -56,7 +59,7 @@ public void update(User user) { @Override public void update(UserTo userTo) { User user = UserUtil.updateFromTo(get(userTo.getId()), userTo); - userDao.save(user); + userDao.save(UserUtil.prepareToSave(user, passwordEncoder)); } @Override @@ -74,7 +77,6 @@ public void enable(long id, boolean enabled) { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - System.out.println(email + "is email"); User user = userDao.getByEmail(email.toLowerCase()); if (user == null) { throw new UsernameNotFoundException("User " + email + " is not found"); diff --git a/src/main/java/org/gvp/boookmanager/to/UserTo.java b/src/main/java/org/gvp/boookmanager/to/UserTo.java index cd1a6e3..55942b5 100644 --- a/src/main/java/org/gvp/boookmanager/to/UserTo.java +++ b/src/main/java/org/gvp/boookmanager/to/UserTo.java @@ -5,18 +5,17 @@ import org.hibernate.validator.constraints.SafeHtml; import javax.validation.constraints.Size; +import java.io.Serializable; public class UserTo extends BaseTo { @NotBlank @Size(min = 2, max = 100) - @SafeHtml private String name; @Email @NotBlank @Size(max = 100) - @SafeHtml private String email; @Size(min = 5, max = 32, message = "length must between 5 and 32 characters") diff --git a/src/main/webapp/WEB-INF/jsp/books.jsp b/src/main/webapp/WEB-INF/jsp/books.jsp index 8c502dd..1007a0b 100644 --- a/src/main/webapp/WEB-INF/jsp/books.jsp +++ b/src/main/webapp/WEB-INF/jsp/books.jsp @@ -16,56 +16,44 @@ <%@include file="parts/navigation.jsp" %>
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
TitleDescriptionAuthorISBNPrintYearisReadEditDeleteRead
${book.title}${book.description}${book.author}${book.isbn}${book.printYear}${book.readAlready} - - - - - - - - - - - - - -
-
- -

Your bookList is empty. Add a book.

-
-
+ + + + + + + + + + <%-- + + --%> + + +
TitleDescriptionAuthorISBNPrintYearisReadEditDeleteRead
- + diff --git a/src/main/webapp/WEB-INF/jsp/login.jsp b/src/main/webapp/WEB-INF/jsp/login.jsp index 1516387..615a514 100644 --- a/src/main/webapp/WEB-INF/jsp/login.jsp +++ b/src/main/webapp/WEB-INF/jsp/login.jsp @@ -13,7 +13,12 @@
-

Please sign in

+ + + +

Please log in

@@ -24,12 +29,14 @@
- +
+ Register
diff --git a/src/main/webapp/WEB-INF/jsp/profile.jsp b/src/main/webapp/WEB-INF/jsp/profile.jsp index 25e0e97..fe4f94b 100644 --- a/src/main/webapp/WEB-INF/jsp/profile.jsp +++ b/src/main/webapp/WEB-INF/jsp/profile.jsp @@ -1,5 +1,6 @@ <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> @@ -7,12 +8,17 @@ <%@include file="parts/header.jsp" %> -
+
+ <%@include file="parts/navigation.jsp" %> -
-
-
- + +
+
+
+ +
Name From 27e89844a609df0e2279afdaff42e5e49ae5cab5 Mon Sep 17 00:00:00 2001 From: gvp Date: Sun, 22 Jul 2018 23:15:30 +0700 Subject: [PATCH 13/14] add js --- pom.xml | 2 +- .../controller/BookController.java | 26 +++-- .../controller/RootController.java | 10 +- .../controller/UserController.java | 15 +-- .../org/gvp/boookmanager/dao/BookDao.java | 1 - .../org/gvp/boookmanager/dao/BookDaoImpl.java | 31 +----- .../org/gvp/boookmanager/dao/UserDaoImpl.java | 1 - .../java/org/gvp/boookmanager/model/Book.java | 2 +- .../java/org/gvp/boookmanager/model/User.java | 2 + .../gvp/boookmanager/service/BookService.java | 6 +- .../boookmanager/service/BookServiceImpl.java | 15 +-- .../support/security/AuthorizedUser.java | 23 ++++ src/main/resources/spring/appconfig-mvc.xml | 3 + .../resources/spring/appconfig-security.xml | 2 +- src/main/webapp/WEB-INF/jsp/books.jsp | 90 +++++++++++----- src/main/webapp/WEB-INF/jsp/parts/header.jsp | 16 +-- src/main/webapp/WEB-INF/jsp/users.jsp | 86 +++++++++++++++ src/main/webapp/resources/css/style.css | 6 ++ .../webapp/resources/js/booksDatatables.js | 78 ++++++++++++++ .../webapp/resources/js/datatablesUtil.js | 100 ++++++++++++++++++ .../webapp/resources/js/userDatatables.js | 88 +++++++++++++++ 21 files changed, 501 insertions(+), 102 deletions(-) create mode 100644 src/main/webapp/WEB-INF/jsp/users.jsp create mode 100644 src/main/webapp/resources/css/style.css create mode 100644 src/main/webapp/resources/js/booksDatatables.js create mode 100644 src/main/webapp/resources/js/datatablesUtil.js create mode 100644 src/main/webapp/resources/js/userDatatables.js diff --git a/pom.xml b/pom.xml index 8d46ea0..6d0be02 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 1.2 5.1.38 4.1.0 - 3.3.1 + 3.3.1-1 3.1.0 1.10.16 5.4.1.Final diff --git a/src/main/java/org/gvp/boookmanager/controller/BookController.java b/src/main/java/org/gvp/boookmanager/controller/BookController.java index dcfcc35..8e4bcec 100644 --- a/src/main/java/org/gvp/boookmanager/controller/BookController.java +++ b/src/main/java/org/gvp/boookmanager/controller/BookController.java @@ -12,7 +12,7 @@ import java.util.List; @RestController -@RequestMapping(value = "/books") +@RequestMapping(value = "/bookmanager/books") public class BookController { private BookService bookService; @@ -24,26 +24,30 @@ public BookController(BookService bookService) { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public List getAll(@AuthenticationPrincipal AuthorizedUser authorizedUser) { - return bookService.getALL(authorizedUser.getId()); + return bookService.getAll(authorizedUser.getId()); } @GetMapping( value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - public Book get(@PathVariable("id") long id, @AuthenticationPrincipal AuthorizedUser authorizedUser) { - return bookService.get(id, authorizedUser.getId()); + public Book get(@PathVariable("id") long id) { + return bookService.get(id, AuthorizedUser.id()); } - @DeleteMapping(value = "/delete/{id}") - public void delete(@PathVariable("id") long id, @AuthenticationPrincipal AuthorizedUser authorizedUser){ - bookService.delete(id, authorizedUser.getId()); + @DeleteMapping(value = "/{id}") + public void delete(@PathVariable("id") long id){ + bookService.delete(id, AuthorizedUser.id()); } @PostMapping() - public void update(@Valid @ModelAttribute Book book, @AuthenticationPrincipal AuthorizedUser authorizedUser){ + public void update(@Valid @ModelAttribute Book book){ if(book.getId() == null) { - bookService.create(book, authorizedUser.getId()); + bookService.create(book, AuthorizedUser.id()); } else { - bookService.update(book, authorizedUser.getId()); + bookService.update(book, AuthorizedUser.id()); } } - + + @PostMapping(value = "/{id}") + public void makeRead(@PathVariable("id") int id, @RequestParam("readAlready") boolean readAlready) { + bookService.makeRead(id, readAlready, AuthorizedUser.id()); + } } diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java index d8036ca..8273650 100644 --- a/src/main/java/org/gvp/boookmanager/controller/RootController.java +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -6,6 +6,7 @@ import org.gvp.boookmanager.util.UserUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -23,16 +24,17 @@ @Controller public class RootController { - private final UserService userService; + private UserService userService; @Autowired public RootController(UserService userService) { this.userService = userService; } - @GetMapping("/") - public String root() { - return "redirect:books"; + @PreAuthorize("hasRole('ROLE_ADMIN')") + @GetMapping("/users") + public String users() { + return "users"; } @GetMapping("/books") diff --git a/src/main/java/org/gvp/boookmanager/controller/UserController.java b/src/main/java/org/gvp/boookmanager/controller/UserController.java index 3b4d1db..6e6f507 100644 --- a/src/main/java/org/gvp/boookmanager/controller/UserController.java +++ b/src/main/java/org/gvp/boookmanager/controller/UserController.java @@ -2,18 +2,21 @@ import org.gvp.boookmanager.model.User; import org.gvp.boookmanager.service.UserService; +import org.gvp.boookmanager.to.UserTo; +import org.gvp.boookmanager.util.UserUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; @RestController -@RequestMapping(name = "/users") +@RequestMapping(value = "/bookmanager/users") public class UserController { - private final UserService userService; + private UserService userService; @Autowired public UserController(UserService userService) { @@ -39,11 +42,11 @@ public void delete(@PathVariable("id") int id) { } @PostMapping - public void createOrUpdate(@Valid @ModelAttribute User user) { - if (user.getId() == null) { - userService.create(user); + public void createOrUpdate(@Valid @ModelAttribute UserTo userTo) { + if (userTo.getId() == null) { + userService.create(UserUtil.createNewFromTo(userTo)); } else { - userService.update(user); + userService.update(userTo); } } diff --git a/src/main/java/org/gvp/boookmanager/dao/BookDao.java b/src/main/java/org/gvp/boookmanager/dao/BookDao.java index 7569d88..ebc2d65 100644 --- a/src/main/java/org/gvp/boookmanager/dao/BookDao.java +++ b/src/main/java/org/gvp/boookmanager/dao/BookDao.java @@ -14,5 +14,4 @@ public interface BookDao { List getAll(long userId); - List search(String searchText); } diff --git a/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java index b8fcc18..8598be2 100644 --- a/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java +++ b/src/main/java/org/gvp/boookmanager/dao/BookDaoImpl.java @@ -1,13 +1,7 @@ package org.gvp.boookmanager.dao; - -import org.apache.lucene.search.Query; import org.gvp.boookmanager.model.Book; import org.gvp.boookmanager.model.User; -import org.gvp.boookmanager.support.search.SearchField; -import org.hibernate.search.jpa.FullTextEntityManager; -import org.hibernate.search.jpa.Search; -import org.hibernate.search.query.dsl.QueryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; @@ -15,7 +9,6 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import java.util.Collections; import java.util.List; @Repository @@ -65,29 +58,7 @@ public Book get(long id, long userId) { @Override public List getAll(long userId) { logger.info("Get all"); - return em.createNamedQuery(Book.GET_ALL, Book.class).getResultList(); - } - - - @Override - public List search(String searchText) { - if(searchText == null || searchText.isEmpty()) return Collections.emptyList(); - FullTextEntityManager fem = Search.getFullTextEntityManager(em); - try { - fem.createIndexer().startAndWait(); - } catch (InterruptedException e) { - throw new RuntimeException("Indexing db error"); - } - QueryBuilder qb = fem.getSearchFactory() - .buildQueryBuilder().forEntity(Book.class).get(); - Query query = qb.keyword() - .onFields(SearchField.TITLE.toString(), SearchField.AUTHOR.toString()) - .matching(searchText) - .createQuery(); - javax.persistence.Query pq = fem.createFullTextQuery(query, Book.class); - return pq.getResultList(); - - + return em.createNamedQuery(Book.GET_ALL, Book.class).setParameter("userId", userId).getResultList(); } } diff --git a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java index f689cce..a825d33 100644 --- a/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java +++ b/src/main/java/org/gvp/boookmanager/dao/UserDaoImpl.java @@ -32,7 +32,6 @@ public User get(long id) { } @Override - @Transactional public boolean delete(long id) { return em.createNamedQuery(User.DELETE) .setParameter("id", id) diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index 52f46b6..4c021f7 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -18,7 +18,7 @@ @Entity @NamedQueries({ @NamedQuery(name = Book.DELETE, query = "DELETE FROM Book b WHERE b.id=:id AND b.user.id=:userId"), - @NamedQuery(name = Book.GET_ALL, query = "SELECT b FROM Book b ORDER BY b.author ASC") + @NamedQuery(name = Book.GET_ALL, query = "SELECT b FROM Book b WHERE b.user.id=:userId ORDER BY b.author ASC") }) @Table(name = "books") @Indexed diff --git a/src/main/java/org/gvp/boookmanager/model/User.java b/src/main/java/org/gvp/boookmanager/model/User.java index fa2a7c6..6c55caa 100644 --- a/src/main/java/org/gvp/boookmanager/model/User.java +++ b/src/main/java/org/gvp/boookmanager/model/User.java @@ -1,6 +1,7 @@ package org.gvp.boookmanager.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.hibernate.annotations.BatchSize; import org.hibernate.validator.constraints.Email; @@ -56,6 +57,7 @@ public class User extends AbstractNamedEntity { @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")//, cascade = CascadeType.REMOVE, orphanRemoval = true) @OrderBy("dateTime DESC") + @JsonIgnore private List books; public User() { diff --git a/src/main/java/org/gvp/boookmanager/service/BookService.java b/src/main/java/org/gvp/boookmanager/service/BookService.java index 1e1f0f3..1675ec5 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookService.java +++ b/src/main/java/org/gvp/boookmanager/service/BookService.java @@ -12,9 +12,7 @@ public interface BookService { Book update(Book book, long userId); - List getALL(long userId); + List getAll(long userId); - List search(String searchText); - - void makeRead(Book book, long userId); + void makeRead(long id, boolean readAlready, long userId); } diff --git a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java index 85d82b7..6b62243 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java @@ -33,6 +33,7 @@ public void delete(long id, long userId) { } @Override + @Transactional public Book create(Book book, long userId) { return bookDao.save(book, userId); } @@ -40,22 +41,22 @@ public Book create(Book book, long userId) { @Override @Transactional public Book update(Book book, long userId) { + book.setReadAlready(false); return bookDao.save(book, userId); } @Override - public List getALL(long userId) { + public List getAll(long userId) { return bookDao.getAll(userId); } @Override - public void makeRead(Book book, long userId) { - book.setReadAlready(true); + @Transactional + public void makeRead(long id, boolean readAlready, long userId) { + Book book = get(id, userId); + book.setReadAlready(readAlready); + System.out.println("Makeread " + book); bookDao.save(book, userId); } - - public List search(String searchText) { - return bookDao.search(searchText); - } } diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java index 538f80c..5145467 100644 --- a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -4,6 +4,10 @@ import org.gvp.boookmanager.model.User; import org.gvp.boookmanager.to.UserTo; import org.gvp.boookmanager.util.UserUtil; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import static java.util.Objects.requireNonNull; public class AuthorizedUser extends org.springframework.security.core.userdetails.User { @@ -14,6 +18,25 @@ public AuthorizedUser(User user) { this.userTo = UserUtil.asTo(user); } + public static AuthorizedUser safeGet() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null) { + return null; + } + Object principal = auth.getPrincipal(); + return (principal instanceof AuthorizedUser) ? (AuthorizedUser) principal : null; + } + + public static AuthorizedUser get() { + AuthorizedUser user = safeGet(); + requireNonNull(user, "No authorized user found"); + return user; + } + + public static long id() { + return get().userTo.getId(); + } + public long getId() { return userTo.getId(); } diff --git a/src/main/resources/spring/appconfig-mvc.xml b/src/main/resources/spring/appconfig-mvc.xml index f48faea..57e0dd7 100644 --- a/src/main/resources/spring/appconfig-mvc.xml +++ b/src/main/resources/spring/appconfig-mvc.xml @@ -10,7 +10,10 @@ + + + diff --git a/src/main/resources/spring/appconfig-security.xml b/src/main/resources/spring/appconfig-security.xml index 779f0d1..df7e320 100644 --- a/src/main/resources/spring/appconfig-security.xml +++ b/src/main/resources/spring/appconfig-security.xml @@ -15,7 +15,7 @@ - + Book Manager + <%@include file="parts/header.jsp" %> + + -
<%@include file="parts/navigation.jsp" %>
- + +
@@ -24,36 +30,66 @@ - - <%-- - - --%> + + +
TitleAuthor ISBN PrintYearisReadEditDeleteReadReaded
+
- diff --git a/src/main/webapp/WEB-INF/jsp/parts/header.jsp b/src/main/webapp/WEB-INF/jsp/parts/header.jsp index efd4cc7..5a9246c 100644 --- a/src/main/webapp/WEB-INF/jsp/parts/header.jsp +++ b/src/main/webapp/WEB-INF/jsp/parts/header.jsp @@ -1,11 +1,11 @@ <%@ page contentType="text/html;charset=UTF-8" language="java" %> - - - + + + - - - - - + + + + + diff --git a/src/main/webapp/WEB-INF/jsp/users.jsp b/src/main/webapp/WEB-INF/jsp/users.jsp new file mode 100644 index 0000000..da6a5c6 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/users.jsp @@ -0,0 +1,86 @@ +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> +<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> +<%@ taglib prefix="from" uri="http://www.springframework.org/tags/form" %> +<%@ page session="false" %> +<%@ page contentType="text/html;charset=UTF-8" %> + + + + Users + + <%@include file="parts/header.jsp" %> + + + + +
+ <%@include file="parts/navigation.jsp" %> +
+
+ + + + + + + + + + + + + +
NameEmailRolesActiveRegistered
+ +
+
+ +
+ + diff --git a/src/main/webapp/resources/css/style.css b/src/main/webapp/resources/css/style.css new file mode 100644 index 0000000..bf1fa0a --- /dev/null +++ b/src/main/webapp/resources/css/style.css @@ -0,0 +1,6 @@ +tr[book-readAlready="true"] { + color: green; +} +tr[data-userEnabled="false"] { + opacity: 0.3; +} diff --git a/src/main/webapp/resources/js/booksDatatables.js b/src/main/webapp/resources/js/booksDatatables.js new file mode 100644 index 0000000..d943f22 --- /dev/null +++ b/src/main/webapp/resources/js/booksDatatables.js @@ -0,0 +1,78 @@ +var ajaxUrl = "/bookmanager/books/"; +var datatableApi; + +function updateTable() { + $.get(ajaxUrl, updateTableByData); +} + +function makeRead(chkbox, id) { + var readAlready = chkbox.is(":checked"); + $.ajax({ + url: ajaxUrl + id, + type: "POST", + data: "readAlready=" + readAlready + }).done(function () { + chkbox.closest("tr").attr("book-readAlready", readAlready); + if(readAlready) { + successNoty("Readed"); + } + }).fail(function () { + $(chkbox).prop("checked", !readAlready); + }); +} + +$(function () { + datatableApi = $("#bookTable").DataTable({ + "ajax": { + "url": ajaxUrl, + "dataSrc": "" + }, + "info": true, + "columns": [ + { + "data": "title", + }, + { + "data": "description" + }, + { + "data": "author" + }, + { + "data": "isbn" + }, + { + "data": "printYear" + }, + { + "data": "readAlready", + "render": function (data, type, row) { + if (type === "display") { + return ""; + } + return data; + } + }, + { + "render": renderEditBtn, + "defaultContent": "", + "orderable": false + }, + { + "render": renderDeleteBtn, + "defaultContent": "", + "orderable": false + } + ], + "order": [ + [ + 0, + "asc" + ] + ], + "createdRow": function (row, data, dataIndex) { + $(row).attr("book-readAlready", data.readAlready); + }, + "initComplete": makeEditable + }); +}); \ No newline at end of file diff --git a/src/main/webapp/resources/js/datatablesUtil.js b/src/main/webapp/resources/js/datatablesUtil.js new file mode 100644 index 0000000..6c60795 --- /dev/null +++ b/src/main/webapp/resources/js/datatablesUtil.js @@ -0,0 +1,100 @@ +var form; + +function makeEditable() { + form = $('#detailsForm'); + $(document).ajaxError(function (event, jqXHR, options, jsExc) { + failNoty(jqXHR); + }); + + + $.ajaxSetup({cache: false}); +} + +function add() { + $("#modalTitle").html("Add"); + form.find(":input").val(""); + // form.find("input[name='readAlready']").val('false'); + $("#editRow").modal(); +} + + +function updateRow(id) { + $("#modalTitle").html("Edit"); + $.get(ajaxUrl + id, function (data) { + $.each(data, function (key, value) { + if(key === "description"){ + form.find("textarea[name='" + key + "']").val(value); + } + form.find("input[name='" + key + "']").val(value); + }); + $('#editRow').modal(); + }); +} + +function deleteRow(id) { + $.ajax({ + url: ajaxUrl + id, + type: "DELETE" + }).done(function () { + updateTable(); + successNoty("Deleted"); + + }); +} + +function updateTableByData(data) { + datatableApi.clear().rows.add(data).draw(); +} + +function save() { + $.ajax({ + type: "POST", + url: ajaxUrl, + data: form.serialize() + }).done(function () { + $("#editRow").modal("hide"); + updateTable(); + successNoty("Saved"); + }); +} + +var failedNote; + +function closeNoty() { + if (failedNote) { + failedNote.close(); + failedNote = undefined; + } +} + +function successNoty(key) { + closeNoty(); + new Noty({ + text: "  " + [key], + type: 'success', + layout: "bottomRight", + timeout: 1000 + }).show(); +} + +function failNoty(jqXHR) { + closeNoty(); + failedNote = new Noty({ + text: "Error",//"  " + "Error status" + ": " + jqXHR.status + (jqXHR.responseJSON ? "
" + jqXHR.responseJSON : ""), + type: "error", + layout: "bottomRight", + timeout: 1000 + }).show(); +} + +function renderEditBtn(data, type, row) { + if (type === "display") { + return ""; + } +} + +function renderDeleteBtn(data, type, row) { + if (type === "display") { + return ""; + } +} \ No newline at end of file diff --git a/src/main/webapp/resources/js/userDatatables.js b/src/main/webapp/resources/js/userDatatables.js new file mode 100644 index 0000000..efbe001 --- /dev/null +++ b/src/main/webapp/resources/js/userDatatables.js @@ -0,0 +1,88 @@ +var ajaxUrl = "/bookmanager/users/"; +var datatableApi; + +function updateTable() { + $.get(ajaxUrl, updateTableByData); +} + +function enable(chkbox, id) { + var enabled = chkbox.is(":checked"); + $.ajax({ + url: ajaxUrl + id, + type: "POST", + data: "enabled=" + enabled + }).done(function () { + chkbox.closest("tr").attr("data-userEnabled", enabled); + successNoty(enabled ? "Enabled" : "Disabled"); + }).fail(function () { + $(chkbox).prop("checked", !enabled); + }); +} + +// $(document).ready(function () { +$(function () { + datatableApi = $("#userTable").DataTable({ + "ajax": { + "url": ajaxUrl, + "dataSrc": "" + }, + "info": true, + "columns": [ + { + "data": "name" + }, + { + "data": "email", + "render": function (data, type, row) { + if (type === "display") { + return "" + data + ""; + } + return data; + } + }, + { + "data": "roles" + }, + { + "data": "enabled", + "render": function (data, type, row) { + if (type === "display") { + return ""; + } + return data; + } + }, + { + "data": "registered", + "render": function (date, type, row) { + if (type === "display") { + return date.toString().substring(0, 10); + } + return date; + } + }, + { + "orderable": false, + "defaultContent": "", + "render": renderEditBtn + }, + { + "orderable": false, + "defaultContent": "", + "render": renderDeleteBtn + } + ], + "order": [ + [ + 0, + "asc" + ] + ], + "createdRow": function (row, data, dataIndex) { + if (!data.enabled) { + $(row).attr("data-userEnabled", false); + } + }, + "initComplete": makeEditable + }); +}); \ No newline at end of file From 4490e77ff8e640516256196386620489428cb476 Mon Sep 17 00:00:00 2001 From: gvp Date: Tue, 31 Jul 2018 00:10:54 +0700 Subject: [PATCH 14/14] add localization --- pom.xml | 64 +++++------------ .../controller/RootController.java | 1 - .../exception/ApplicationException.java | 42 +++++++++++ .../gvp/boookmanager/exception/ErrorInfo.java | 15 ++++ .../gvp/boookmanager/exception/ErrorType.java | 19 +++++ .../IllegalRequestDataException.java | 15 ++++ .../ModificationRestrictionException.java | 11 +++ .../exception/NotFoundException.java | 12 ++++ .../java/org/gvp/boookmanager/model/Book.java | 17 ----- .../java/org/gvp/boookmanager/model/User.java | 3 +- .../boookmanager/service/BookServiceImpl.java | 1 - .../support/security/AuthorizedUser.java | 2 +- src/main/resources/logback.xml | 28 ++++++++ .../resources/messages/messages_en.properties | 60 ++++++++++++++++ .../resources/messages/messages_ru.properties | 60 ++++++++++++++++ src/main/resources/spring/appconfig-mvc.xml | 25 +++++-- .../resources/spring/appconfig-security.xml | 1 - src/main/webapp/WEB-INF/jsp/bookForm.jsp | 70 ------------------- src/main/webapp/WEB-INF/jsp/books.jsp | 52 ++++++++------ src/main/webapp/WEB-INF/jsp/login.jsp | 23 +++--- src/main/webapp/WEB-INF/jsp/parts/header.jsp | 4 ++ src/main/webapp/WEB-INF/jsp/parts/i18n.jsp | 13 ++++ .../webapp/WEB-INF/jsp/parts/navigation.jsp | 53 +++++++++++--- src/main/webapp/WEB-INF/jsp/profile.jsp | 18 ++--- src/main/webapp/WEB-INF/jsp/search.jsp | 67 ------------------ src/main/webapp/WEB-INF/jsp/users.jsp | 36 +++++----- src/main/webapp/WEB-INF/web.xml | 17 +++++ .../webapp/resources/js/booksDatatables.js | 7 +- .../webapp/resources/js/datatablesUtil.js | 21 +++--- .../webapp/resources/js/userDatatables.js | 8 ++- 30 files changed, 474 insertions(+), 291 deletions(-) create mode 100644 src/main/java/org/gvp/boookmanager/exception/ApplicationException.java create mode 100644 src/main/java/org/gvp/boookmanager/exception/ErrorInfo.java create mode 100644 src/main/java/org/gvp/boookmanager/exception/ErrorType.java create mode 100644 src/main/java/org/gvp/boookmanager/exception/IllegalRequestDataException.java create mode 100644 src/main/java/org/gvp/boookmanager/exception/ModificationRestrictionException.java create mode 100644 src/main/java/org/gvp/boookmanager/exception/NotFoundException.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/resources/messages/messages_en.properties create mode 100644 src/main/resources/messages/messages_ru.properties delete mode 100644 src/main/webapp/WEB-INF/jsp/bookForm.jsp create mode 100644 src/main/webapp/WEB-INF/jsp/parts/i18n.jsp delete mode 100644 src/main/webapp/WEB-INF/jsp/search.jsp diff --git a/pom.xml b/pom.xml index 6d0be02..03a2e74 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,8 @@ 1.8 5.0.5.RELEASE 1.7.4 - 1.7.5 + 1.2.3 + 1.7.5 5.3.0.Final 2.1.1 2.5 @@ -25,6 +26,7 @@ 4.1.0 3.3.1-1 3.1.0 + 2.22.2 1.10.16 5.4.1.Final 5.10.0.Final @@ -107,60 +109,25 @@ ${hibernate-validator.version} - - - org.hibernate - hibernate-search-orm - ${hibernate-search.version} - - - org.hibernate - hibernate-commons-annotations - - - - - org.slf4j slf4j-api - ${org.slf4j-version} - - - org.slf4j - jcl-over-slf4j - ${org.slf4j-version} - runtime + ${slf4j.version} + compile + org.slf4j - slf4j-log4j12 - ${org.slf4j-version} + jul-to-slf4j + ${slf4j.version} runtime + - log4j - log4j - 1.2.15 - - - javax.mail - mail - - - javax.jms - jms - - - com.sun.jdmk - jmxtools - - - com.sun.jmx - jmxri - - + ch.qos.logback + logback-classic + ${logback.version} runtime @@ -188,6 +155,7 @@ jquery ${webjars-jquery.version} + org.webjars bootstrap @@ -216,6 +184,12 @@ ${webjars-noty.version} + + org.webjars.bower + moment + ${webjars-moment.version} + + diff --git a/src/main/java/org/gvp/boookmanager/controller/RootController.java b/src/main/java/org/gvp/boookmanager/controller/RootController.java index 8273650..49241a9 100644 --- a/src/main/java/org/gvp/boookmanager/controller/RootController.java +++ b/src/main/java/org/gvp/boookmanager/controller/RootController.java @@ -31,7 +31,6 @@ public RootController(UserService userService) { this.userService = userService; } - @PreAuthorize("hasRole('ROLE_ADMIN')") @GetMapping("/users") public String users() { return "users"; diff --git a/src/main/java/org/gvp/boookmanager/exception/ApplicationException.java b/src/main/java/org/gvp/boookmanager/exception/ApplicationException.java new file mode 100644 index 0000000..aa6eeae --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/ApplicationException.java @@ -0,0 +1,42 @@ +package org.gvp.boookmanager.exception; + +import org.springframework.http.HttpStatus; + +import java.util.Arrays; + +public class ApplicationException extends RuntimeException { + + private final ErrorType type; + private final String msgCode; + private final HttpStatus httpStatus; + private final String[] args; + + public ApplicationException(String msgCode, HttpStatus httpStatus) { + this(ErrorType.APP_ERROR, msgCode, httpStatus); + } + + public ApplicationException(ErrorType type, String msgCode, HttpStatus httpStatus, String... args) { + super(String.format("type=%s, msgCode=%s, args=%s", type, msgCode, Arrays.toString(args))); + this.type = type; + this.msgCode = msgCode; + this.httpStatus = httpStatus; + this.args = args; + } + + public ErrorType getType() { + return type; + } + + public String getMsgCode() { + return msgCode; + } + + public HttpStatus getHttpStatus() { + return httpStatus; + } + + public String[] getArgs() { + return args; + } + +} diff --git a/src/main/java/org/gvp/boookmanager/exception/ErrorInfo.java b/src/main/java/org/gvp/boookmanager/exception/ErrorInfo.java new file mode 100644 index 0000000..cf835aa --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/ErrorInfo.java @@ -0,0 +1,15 @@ +package org.gvp.boookmanager.exception; + +public class ErrorInfo { + private final String url; + private final ErrorType type; + private final String typeMessage; + private final String[] details; + + public ErrorInfo(CharSequence url, ErrorType type, String typeMessage, String... details) { + this.url = url.toString(); + this.type = type; + this.typeMessage = typeMessage; + this.details = details; + } +} \ No newline at end of file diff --git a/src/main/java/org/gvp/boookmanager/exception/ErrorType.java b/src/main/java/org/gvp/boookmanager/exception/ErrorType.java new file mode 100644 index 0000000..378a2bc --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/ErrorType.java @@ -0,0 +1,19 @@ +package org.gvp.boookmanager.exception; + +public enum ErrorType { + APP_ERROR("Application error"), + DATA_NOT_FOUND("Data not found"), + DATA_ERROR("Data error"), + VALIDATION_ERROR("Validation error"), + WRONG_REQUEST("Wrong request"); + + private final String errorCode; + + ErrorType(String errorCode) { + this.errorCode = errorCode; + } + + public String getErrorCode() { + return errorCode; + } +} diff --git a/src/main/java/org/gvp/boookmanager/exception/IllegalRequestDataException.java b/src/main/java/org/gvp/boookmanager/exception/IllegalRequestDataException.java new file mode 100644 index 0000000..27b8b02 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/IllegalRequestDataException.java @@ -0,0 +1,15 @@ +package org.gvp.boookmanager.exception; + +import org.springframework.lang.NonNull; + +public class IllegalRequestDataException extends RuntimeException { + public IllegalRequestDataException(@NonNull String msg) { + super(msg); + } + + @Override + public String toString() { + return getMessage(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/gvp/boookmanager/exception/ModificationRestrictionException.java b/src/main/java/org/gvp/boookmanager/exception/ModificationRestrictionException.java new file mode 100644 index 0000000..61b01e7 --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/ModificationRestrictionException.java @@ -0,0 +1,11 @@ +package org.gvp.boookmanager.exception; + +import org.springframework.http.HttpStatus; + +public class ModificationRestrictionException extends ApplicationException { + public static final String EXCEPTION_MODIFICATION_RESTRICTION = "Admin/User modification is forbidden"; + + public ModificationRestrictionException() { + super(EXCEPTION_MODIFICATION_RESTRICTION, HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS); + } +} \ No newline at end of file diff --git a/src/main/java/org/gvp/boookmanager/exception/NotFoundException.java b/src/main/java/org/gvp/boookmanager/exception/NotFoundException.java new file mode 100644 index 0000000..4c74ecf --- /dev/null +++ b/src/main/java/org/gvp/boookmanager/exception/NotFoundException.java @@ -0,0 +1,12 @@ +package org.gvp.boookmanager.exception; + +import org.springframework.http.HttpStatus; + +public class NotFoundException extends ApplicationException { + public static final String NOT_FOUND_EXCEPTION = "Not found entity with {0}"; + + // http://stackoverflow.com/a/22358422/548473 + public NotFoundException(String arg) { + super(ErrorType.DATA_NOT_FOUND, NOT_FOUND_EXCEPTION, HttpStatus.UNPROCESSABLE_ENTITY, arg); + } +} \ No newline at end of file diff --git a/src/main/java/org/gvp/boookmanager/model/Book.java b/src/main/java/org/gvp/boookmanager/model/Book.java index 4c021f7..5c5d1de 100644 --- a/src/main/java/org/gvp/boookmanager/model/Book.java +++ b/src/main/java/org/gvp/boookmanager/model/Book.java @@ -1,15 +1,9 @@ package org.gvp.boookmanager.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import org.apache.lucene.analysis.core.LowerCaseFilterFactory; -import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory; -import org.apache.lucene.analysis.standard.StandardTokenizerFactory; import org.gvp.boookmanager.support.validation.Year; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.search.annotations.*; -import org.hibernate.search.annotations.Index; -import org.hibernate.search.annotations.Parameter; import org.hibernate.validator.constraints.NotBlank; import javax.persistence.*; @@ -21,22 +15,12 @@ @NamedQuery(name = Book.GET_ALL, query = "SELECT b FROM Book b WHERE b.user.id=:userId ORDER BY b.author ASC") }) @Table(name = "books") -@Indexed -@AnalyzerDef(name = "customAnalyzer", - tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), - filters = { - @TokenFilterDef(factory = LowerCaseFilterFactory.class), - @TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = { - @Parameter(name = "language", value = "English") - }) - }) public class Book extends AbstractBaseEntity{ public static final String DELETE = "Book.delete"; public static final String GET_ALL = "Book.getAll"; @Column(name = "title") - @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, analyzer = @Analyzer(definition = "customAnalyzer")) @NotBlank(message = "Enter a title") private String title; @@ -46,7 +30,6 @@ public class Book extends AbstractBaseEntity{ private String description; @Column(name = "author") - @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO) @NotBlank(message = "Enter a name of author") private String author; diff --git a/src/main/java/org/gvp/boookmanager/model/User.java b/src/main/java/org/gvp/boookmanager/model/User.java index 6c55caa..847ab0a 100644 --- a/src/main/java/org/gvp/boookmanager/model/User.java +++ b/src/main/java/org/gvp/boookmanager/model/User.java @@ -55,8 +55,7 @@ public class User extends AbstractNamedEntity { @BatchSize(size = 200) private Set roles; - @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")//, cascade = CascadeType.REMOVE, orphanRemoval = true) - @OrderBy("dateTime DESC") + @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true) @JsonIgnore private List books; diff --git a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java index 6b62243..3c136ca 100644 --- a/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java +++ b/src/main/java/org/gvp/boookmanager/service/BookServiceImpl.java @@ -55,7 +55,6 @@ public List getAll(long userId) { public void makeRead(long id, boolean readAlready, long userId) { Book book = get(id, userId); book.setReadAlready(readAlready); - System.out.println("Makeread " + book); bookDao.save(book, userId); } diff --git a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java index 5145467..71d2bcb 100644 --- a/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java +++ b/src/main/java/org/gvp/boookmanager/support/security/AuthorizedUser.java @@ -14,7 +14,7 @@ public class AuthorizedUser extends org.springframework.security.core.userdetail private UserTo userTo; public AuthorizedUser(User user) { - super(user.getEmail(), user.getPassword(), user.getRoles()); + super(user.getEmail(), user.getPassword(), user.isEnabled(), true, true, true, user.getRoles()); this.userTo = UserUtil.asTo(user); } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..d118509 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,28 @@ + + + + + + UTF-8 + %date %-5level %logger{50}.%M:%L - %msg%n + + + + + + UTF-8 + %d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%class{50}.%M:%L) - %msg%n + + + + + + + + + + + + + + diff --git a/src/main/resources/messages/messages_en.properties b/src/main/resources/messages/messages_en.properties new file mode 100644 index 0000000..87328e4 --- /dev/null +++ b/src/main/resources/messages/messages_en.properties @@ -0,0 +1,60 @@ +app.title = Welcome! +app.login=Login as +app.password = Password +app.welcome = Please log in +app.enter = Log in +app.profile=My profile +app.register=Registration +app.registered=You are registered. Please Sign in. +app.logout = Log out +app.main = Main + +user.title=Users +user.edit=Edit user +user.add=Add user +user.name=Name +user.email=Email +user.roles=Roles +user.active=Active +user.registered=Registered +user.password=Password + +books.title=Books +book.title=Title +book.edit=Edit book +book.add=Add book +book.description=Description +book.author = Author +book.isbn = ISBN +book.printYear = PrintYear +book.isRead = Read + +common.add=Add +common.save=Save +common.cancel=Cancel +common.deleted=Record deleted +common.saved=Record saved +common.enabled=Record enabled +common.disabled=Record disabled +common.search=Search +commom.language = Language + +error.appError=Application error +error.dataNotFound=Data not found +error.dataError=Data error +error.validationError=Validation error +error.wrongRequest=Wrong request + +exception.common.notFound=Not found entity with {0} +exception.user.duplicateEmail=User with this email already exists +exception.user.modificationRestriction=Admin/User modification is forbidden + + +NotEmpty="{0}" must not be empty +NotBlank="{0}" must not be empty +NotNull="{0}" must not be empty +Email= Invalid format of "{0}" +Range="{0}" must be between {2} and {1} +Length="{0}" length must be between {2} and {1} +Size="{0}" size must be between {2} and {1} +SafeHtml="{0}" may has unsafe html content diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties new file mode 100644 index 0000000..13037be --- /dev/null +++ b/src/main/resources/messages/messages_ru.properties @@ -0,0 +1,60 @@ +app.title = Добро пожаловать! +app.login=Логин +app.password=Пароль +app.welcome = Пожалуйста войдите +app.enter = Войти +app.profile=Мой профиль +app.register=Регистрация +app.registered=Вы зарегистрированы. Введите ваш логин/пароль. +app.logout = Выйти +app.main = На главную + +user.title=Пользователи +user.edit=Редактирование пользователя +user.add=Добавление пользователя +user.name=Имя +user.email=Почта +user.roles=Роли +user.active=Активный +user.registered=Зарегистрирован +user.password=Пароль + +books.title=Книги +book.title=Название +book.edit=Редактировать книгу +book.add=Добавить книгу +book.description=Описание +book.author = Автор +book.isbn = ISBN +book.printYear = Издано +book.isRead = Прочитано + +common.add=Добавить +common.save=Сохранить +common.cancel=Отменить +common.deleted=Запись удалена +common.saved=Запись сохранена +common.enabled=Запись активирована +common.disabled=Запись деактивирована +common.search=Искать +commom.language = Язык + +error.appError=Ошибка приложения +error.dataNotFound=Данные не найдены +error.dataError=Ошибка в данных +error.validationError=Ошибка проверки данных +error.wrongRequest=Неверный запрос + +exception.common.notFound=Не найдена запись с {0} +exception.user.duplicateEmail=Пользователь с такой почтой уже есть в приложении +exception.user.modificationRestriction=Модификация Admin/User запрещена +exception.meal.duplicateDateTime=У вас уже есть еда с такой датой/временем + +NotEmpty=Поле "{0}" не должно быть пустым +NotBlank=Поле "{0}" не должно быть пустым +NotNull=Поле "{0}" не должно быть пустым +Email=Неверный формат поля "{0}" +Range=Поле "{0}" должно быть между {2} и {1} +Length=Длинна поля "{0}" должена быть между {2} и {1} +Size=Размер поля "{0}" должен быть между {2} и {1} +SafeHtml=Поле "{0}" может содержать небезопасный html контент diff --git a/src/main/resources/spring/appconfig-mvc.xml b/src/main/resources/spring/appconfig-mvc.xml index 57e0dd7..30ac3a3 100644 --- a/src/main/resources/spring/appconfig-mvc.xml +++ b/src/main/resources/spring/appconfig-mvc.xml @@ -1,6 +1,6 @@ @@ -12,12 +12,25 @@ - + - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/spring/appconfig-security.xml b/src/main/resources/spring/appconfig-security.xml index df7e320..ca2f9f0 100644 --- a/src/main/resources/spring/appconfig-security.xml +++ b/src/main/resources/spring/appconfig-security.xml @@ -24,7 +24,6 @@ authentication-failure-url="/login?error=true" login-processing-url="/spring_security_check"/> - diff --git a/src/main/webapp/WEB-INF/jsp/bookForm.jsp b/src/main/webapp/WEB-INF/jsp/bookForm.jsp deleted file mode 100644 index 8faef65..0000000 --- a/src/main/webapp/WEB-INF/jsp/bookForm.jsp +++ /dev/null @@ -1,70 +0,0 @@ -<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> -<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> -<%@ taglib prefix="from" uri="http://www.springframework.org/tags/form" %> -<%@ page session="false" %> -<%@ page contentType="text/html;charset=UTF-8" %> - - - - - Add/Edit book - <%@include file="parts/header.jsp"%> - - - - -
- <%@include file="parts/navigation.jsp"%> -
-
- -
-
-

Add/Edit book

-
- - - - - -
- Title - - -
-
- Description - - -
-
- Author - - - - - - - - - -
-
- ISBN - - -
-
- PrintYear - - -
- -
-
-
-
- - diff --git a/src/main/webapp/WEB-INF/jsp/books.jsp b/src/main/webapp/WEB-INF/jsp/books.jsp index caf0c12..ceb8c1a 100644 --- a/src/main/webapp/WEB-INF/jsp/books.jsp +++ b/src/main/webapp/WEB-INF/jsp/books.jsp @@ -7,7 +7,7 @@ - Book Manager + <spring:message code="books.title"/> <%@include file="parts/header.jsp" %> @@ -20,17 +20,17 @@
- - - - - - + + + + + + @@ -48,27 +48,36 @@
- - + + >
- +
- +
- - + + >
- - + + >
- - + + >
@@ -78,11 +87,11 @@
@@ -92,4 +101,7 @@ + + + diff --git a/src/main/webapp/WEB-INF/jsp/login.jsp b/src/main/webapp/WEB-INF/jsp/login.jsp index 615a514..a3ec40b 100644 --- a/src/main/webapp/WEB-INF/jsp/login.jsp +++ b/src/main/webapp/WEB-INF/jsp/login.jsp @@ -5,38 +5,39 @@ - Welcome + <spring:message code="app.title"/>
+ <%@include file="parts/navigation.jsp" %>
-
+
-

Please log in

-
+

+
- +
- +
- - + +
Register + class="badge badge-pill badge-primary">
diff --git a/src/main/webapp/WEB-INF/jsp/parts/header.jsp b/src/main/webapp/WEB-INF/jsp/parts/header.jsp index 5a9246c..babf07f 100644 --- a/src/main/webapp/WEB-INF/jsp/parts/header.jsp +++ b/src/main/webapp/WEB-INF/jsp/parts/header.jsp @@ -1,4 +1,7 @@ <%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + @@ -9,3 +12,4 @@ + diff --git a/src/main/webapp/WEB-INF/jsp/parts/i18n.jsp b/src/main/webapp/WEB-INF/jsp/parts/i18n.jsp new file mode 100644 index 0000000..c5df986 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/parts/i18n.jsp @@ -0,0 +1,13 @@ +<%@ page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp b/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp index b490267..b35f45e 100644 --- a/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp +++ b/src/main/webapp/WEB-INF/jsp/parts/navigation.jsp @@ -4,19 +4,52 @@
-
\ No newline at end of file +
+ \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/profile.jsp b/src/main/webapp/WEB-INF/jsp/profile.jsp index fe4f94b..6488e85 100644 --- a/src/main/webapp/WEB-INF/jsp/profile.jsp +++ b/src/main/webapp/WEB-INF/jsp/profile.jsp @@ -1,40 +1,40 @@ <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> - ${register ? "Registration" : "My profile"} + <spring:message code="${register ? 'app.register' : 'app.profile'}"/> <%@include file="parts/header.jsp" %>
- - <%@include file="parts/navigation.jsp" %> - + <%@include file="parts/navigation.jsp" %>
-
+
- Name +
- Email +
- Password +
- +
diff --git a/src/main/webapp/WEB-INF/jsp/search.jsp b/src/main/webapp/WEB-INF/jsp/search.jsp deleted file mode 100644 index 383317e..0000000 --- a/src/main/webapp/WEB-INF/jsp/search.jsp +++ /dev/null @@ -1,67 +0,0 @@ -%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> -<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> -<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> -<%@ page session="false" %> -<%@ page contentType="text/html;charset=UTF-8" %> - - - - Search Result - <%@include file="parts/header.jsp" %> - - - -
- <%@include file="parts/navigation.jsp" %> -
-
- - -
TitleDescriptionAuthorISBNPrintYearReaded
- - - - - - - - - - - - - - - - - - - - - - - - -
TitleDescriptionAuthorISBNPrintYearisReadEditDeleteRead
${book.title}${book.description}${book.author}${book.isbn}${book.printYear}${book.readAlready} - - - - - - - - - - - - - -
- - -
-
- <%@include file="parts/pagination.jsp"%> -
- - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/users.jsp b/src/main/webapp/WEB-INF/jsp/users.jsp index da6a5c6..891c137 100644 --- a/src/main/webapp/WEB-INF/jsp/users.jsp +++ b/src/main/webapp/WEB-INF/jsp/users.jsp @@ -7,7 +7,7 @@ - Users + <spring:message code="user.title"/> <%@include file="parts/header.jsp" %> @@ -20,16 +20,16 @@
- - - - - + + + + + @@ -39,7 +39,7 @@ - + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 82ffece..70b3a79 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -38,6 +38,23 @@ *.css + + encodingFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + + + encodingFilter + /* + + springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy diff --git a/src/main/webapp/resources/js/booksDatatables.js b/src/main/webapp/resources/js/booksDatatables.js index d943f22..9173530 100644 --- a/src/main/webapp/resources/js/booksDatatables.js +++ b/src/main/webapp/resources/js/booksDatatables.js @@ -14,7 +14,7 @@ function makeRead(chkbox, id) { }).done(function () { chkbox.closest("tr").attr("book-readAlready", readAlready); if(readAlready) { - successNoty("Readed"); + successNoty(i18n["read"]); } }).fail(function () { $(chkbox).prop("checked", !readAlready); @@ -25,9 +25,12 @@ $(function () { datatableApi = $("#bookTable").DataTable({ "ajax": { "url": ajaxUrl, - "dataSrc": "" + "dataSrc": "", }, "info": true, + "language": { + "search": i18n["common.search"] + }, "columns": [ { "data": "title", diff --git a/src/main/webapp/resources/js/datatablesUtil.js b/src/main/webapp/resources/js/datatablesUtil.js index 6c60795..c210f71 100644 --- a/src/main/webapp/resources/js/datatablesUtil.js +++ b/src/main/webapp/resources/js/datatablesUtil.js @@ -5,24 +5,27 @@ function makeEditable() { $(document).ajaxError(function (event, jqXHR, options, jsExc) { failNoty(jqXHR); }); - - $.ajaxSetup({cache: false}); + var token = $("meta[name='_csrf']").attr("content"); + var header = $("meta[name='_csrf_header']").attr("content"); + $(document).ajaxSend(function (e, xhr, options) { + xhr.setRequestHeader(header, token); + }); } function add() { - $("#modalTitle").html("Add"); + $("#modalTitle").html(i18n["addTitle"]); form.find(":input").val(""); - // form.find("input[name='readAlready']").val('false'); + form.find("input[name='readAlready']").val('false'); $("#editRow").modal(); } function updateRow(id) { - $("#modalTitle").html("Edit"); + $("#modalTitle").html(i18n["editTitle"]); $.get(ajaxUrl + id, function (data) { $.each(data, function (key, value) { - if(key === "description"){ + if (key === "description") { form.find("textarea[name='" + key + "']").val(value); } form.find("input[name='" + key + "']").val(value); @@ -37,7 +40,7 @@ function deleteRow(id) { type: "DELETE" }).done(function () { updateTable(); - successNoty("Deleted"); + successNoty(i18n["common.deleted"]); }); } @@ -54,7 +57,7 @@ function save() { }).done(function () { $("#editRow").modal("hide"); updateTable(); - successNoty("Saved"); + successNoty(i18n["common.saved"]); }); } @@ -80,7 +83,7 @@ function successNoty(key) { function failNoty(jqXHR) { closeNoty(); failedNote = new Noty({ - text: "Error",//"  " + "Error status" + ": " + jqXHR.status + (jqXHR.responseJSON ? "
" + jqXHR.responseJSON : ""), + text: "  " + errorInfo.typeMessage + "
" + errorInfo.details.join("
"), type: "error", layout: "bottomRight", timeout: 1000 diff --git a/src/main/webapp/resources/js/userDatatables.js b/src/main/webapp/resources/js/userDatatables.js index efbe001..daccdc4 100644 --- a/src/main/webapp/resources/js/userDatatables.js +++ b/src/main/webapp/resources/js/userDatatables.js @@ -13,7 +13,7 @@ function enable(chkbox, id) { data: "enabled=" + enabled }).done(function () { chkbox.closest("tr").attr("data-userEnabled", enabled); - successNoty(enabled ? "Enabled" : "Disabled"); + successNoty(enabled ? i18n["common.enabled"] : i18n["common.disabled"]); }).fail(function () { $(chkbox).prop("checked", !enabled); }); @@ -27,6 +27,9 @@ $(function () { "dataSrc": "" }, "info": true, + "language": { + "search": i18n["common.search"] + }, "columns": [ { "data": "name" @@ -56,7 +59,8 @@ $(function () { "data": "registered", "render": function (date, type, row) { if (type === "display") { - return date.toString().substring(0, 10); + var momentDate = moment(date); + return momentDate.format("DD-MM-YYYY"); } return date; }
NameEmailRolesActiveRegistered