From 188fe4fbcbe30c2723d40a5fe56c1b86e7cde930 Mon Sep 17 00:00:00 2001 From: "Vyacheslav N. Boyko" Date: Tue, 12 Dec 2017 15:59:37 +0300 Subject: [PATCH] improved registration (more stronger validation now). changed comments list for admins: they can see deleted comments entries and are allowed to undelete them --- .../voidforum/controllers/PostController.java | 34 +++++++++++++++---- .../voidforum/controllers/UserController.java | 28 +++++++++++---- .../controllers/admin/PostController.java | 22 ++++-------- .../voidforum/forms/RegistrationForm.java | 15 ++++---- .../repositories/CommentRepository.java | 5 ++- .../voidforum/services/CommentService.java | 9 +++++ .../bvn13/voidforum/services/UserService.java | 18 ++++++---- .../bvn13/voidforum/support/web/Message.java | 8 +++++ .../voidforum/support/web/MessageHelper.java | 19 +++++++++++ src/main/resources/logback.xml | 24 ++++--------- src/main/resources/resources/css/mystyle.css | 8 ++--- .../resources/templates/admin/posts/edit.jade | 4 +-- .../resources/templates/admin/posts/new.jade | 4 +-- .../resources/templates/comments/deleted.jade | 22 ++++++++++++ .../resources/templates/comments/one.jade | 2 +- .../resources/templates/users/register.jade | 11 ++++-- .../resources/templates/users/signin.jade | 2 +- 17 files changed, 161 insertions(+), 74 deletions(-) diff --git a/src/main/java/ru/bvn13/voidforum/controllers/PostController.java b/src/main/java/ru/bvn13/voidforum/controllers/PostController.java index 64f9959..a328a36 100644 --- a/src/main/java/ru/bvn13/voidforum/controllers/PostController.java +++ b/src/main/java/ru/bvn13/voidforum/controllers/PostController.java @@ -65,9 +65,14 @@ public class PostController { } @RequestMapping(value = "{permalink}", method = GET) - public String show(@PathVariable String permalink, Model model, @RequestParam(defaultValue = "0") int page, HttpServletRequest request){ + public String show(@PathVariable String permalink, Model model, @RequestParam(defaultValue = "0") int page, HttpServletRequest request) { Post post = this.postService.findPostByPermalink(permalink); User user = userService.currentUser(); + Boolean isAdmin = userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_ADMIN); + + if (post.getCensored() && !userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_WRITE)) { + throw new AccessDeniedException("You are not allowed here"); + } logger.debug(String.format("ACCESS %s from IP: %s", permalink, this.requestProcessorService.getRealIp(request))); @@ -93,13 +98,26 @@ public class PostController { commentForm.setPostId(post.getId()); Integer commentsPageSize = appSetting.getCommentsPageSize(); - Integer lastPage = commentService.getLastPageCommentsForPost(post, commentsPageSize); + Integer lastPage = null; + if (isAdmin) { + lastPage = commentService.getLastPageCommentsForPostForAdmin(post, commentsPageSize); + } else { + lastPage = commentService.getLastPageCommentsForPost(post, commentsPageSize); + } Page comments = null; if (page > 0) { - comments = commentService.getCommentsForPost(post, page - 1, commentsPageSize); + if (isAdmin) { + comments = commentService.getCommentsForPostForAdmin(post, page - 1, commentsPageSize); + } else { + comments = commentService.getCommentsForPost(post, page - 1, commentsPageSize); + } } else { page = lastPage+1; - comments = commentService.getCommentsForPost(post, lastPage, commentsPageSize); + if (isAdmin) { + comments = commentService.getCommentsForPostForAdmin(post, lastPage, commentsPageSize); + } else { + comments = commentService.getCommentsForPost(post, lastPage, commentsPageSize); + } } model.addAttribute("page", page); @@ -108,7 +126,7 @@ public class PostController { model.addAttribute("comments", comments); model.addAttribute("commentForm", commentForm); model.addAttribute("commentFormats", commentService.getAvailableCommentFormats()); - model.addAttribute("disableCommenting", userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_OWNER) || post.getUser().getId().equals(user.getId()) ? false : post.getDisableCommenting()); + model.addAttribute("disableCommenting", userService.currentUserCanWriteCommentToPost(post)); return "posts/show"; } @@ -118,14 +136,16 @@ public class PostController { public String addComment(@PathVariable String permalink, @Valid CommentForm commentForm, Errors errors, Model model) { User user = userService.currentUser(); - if (!userService.currentUserHasPrivilege(PrivilegeService.PRIVILEGE_WRITE)) { + Post post = postService.getPost(commentForm.getPostId()); + + if (!userService.currentUserCanWrite() || !userService.currentUserCanWriteCommentToPost(post)) { throw new AccessDeniedException("You are not allowed here"); } Comment comment = new Comment(); DTOUtil.mapTo(commentForm, comment); comment.setUser(user); - comment.setPost(postService.getPost(commentForm.getPostId())); + comment.setPost(post); comment.setParentComment(commentService.getCommentById(commentForm.getParentCommentId())); comment.setDepth(commentService.calculateDepth(comment)); diff --git a/src/main/java/ru/bvn13/voidforum/controllers/UserController.java b/src/main/java/ru/bvn13/voidforum/controllers/UserController.java index 58f00de..498f1e3 100644 --- a/src/main/java/ru/bvn13/voidforum/controllers/UserController.java +++ b/src/main/java/ru/bvn13/voidforum/controllers/UserController.java @@ -23,6 +23,8 @@ import ru.bvn13.voidforum.error.NicknameExistsException; import ru.bvn13.voidforum.forms.RegistrationForm; import ru.bvn13.voidforum.models.User; import ru.bvn13.voidforum.services.UserService; +import ru.bvn13.voidforum.support.web.Message; +import ru.bvn13.voidforum.support.web.MessageHelper; import ru.bvn13.voidforum.utils.DTOUtil; import javax.servlet.http.HttpServletRequest; @@ -47,15 +49,26 @@ public class UserController { @GetMapping(value = "register") public String registrationForm(Model model) { - model.addAttribute("form", new RegistrationForm()); + if (!model.containsAttribute("registrationForm")) { + // it contains it after post request when errors occurred and was redirected + model.addAttribute("registrationForm", new RegistrationForm()); + } return "users/register"; } @PostMapping(value = "register") public String register(@Valid RegistrationForm registrationForm, Errors errors, Model model, RedirectAttributes ra) { + + if (errors.hasErrors()) { + MessageHelper.addNamedErrorsAsList(ra, "errors", "Please check errors:", errors); + ra.addFlashAttribute("registrationForm", registrationForm); + return "redirect:/register"; + } + if (!registrationForm.getPassword().equals(registrationForm.getPasswordCheck())) { - ra.addFlashAttribute("error", "Verify your password!"); + MessageHelper.addNamedErrorAttribute(ra, "error", "Verify your password!"); + ra.addFlashAttribute("registrationForm", registrationForm); return "redirect:/register"; } @@ -63,7 +76,8 @@ public class UserController { || registrationForm.getNickname().isEmpty() || registrationForm.getPassword().isEmpty() || registrationForm.getPasswordCheck().isEmpty()) { - ra.addFlashAttribute("error", "Not all necessary fields are specified"); + MessageHelper.addNamedErrorAttribute(ra, "error", "Not all necessary fields are specified"); + ra.addFlashAttribute("registrationForm", registrationForm); return "redirect:/register"; } @@ -76,12 +90,12 @@ public class UserController { try { userService.registerNewUserAccount(user); } catch (EmailExistsException e) { - e.printStackTrace(); - ra.addFlashAttribute("error", "There is an account with specified email and nickname"); + MessageHelper.addNamedErrorAttribute(ra, "error", e.getMessage()); + ra.addFlashAttribute("registrationForm", registrationForm); return "redirect:/register"; } catch (NicknameExistsException e) { - e.printStackTrace(); - ra.addFlashAttribute("error", "There is an account with specified email and nickname"); + MessageHelper.addNamedErrorAttribute(ra, "error", e.getMessage()); + ra.addFlashAttribute("registrationForm", registrationForm); return "redirect:/register"; } diff --git a/src/main/java/ru/bvn13/voidforum/controllers/admin/PostController.java b/src/main/java/ru/bvn13/voidforum/controllers/admin/PostController.java index 2697d7c..8a3f22e 100644 --- a/src/main/java/ru/bvn13/voidforum/controllers/admin/PostController.java +++ b/src/main/java/ru/bvn13/voidforum/controllers/admin/PostController.java @@ -1,5 +1,6 @@ package ru.bvn13.voidforum.controllers.admin; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; import ru.bvn13.voidforum.forms.PostForm; import ru.bvn13.voidforum.models.Post; import ru.bvn13.voidforum.models.User; @@ -10,6 +11,7 @@ import ru.bvn13.voidforum.services.CommentService; import ru.bvn13.voidforum.services.PostService; import ru.bvn13.voidforum.services.PrivilegeService; import ru.bvn13.voidforum.services.UserService; +import ru.bvn13.voidforum.support.web.MessageHelper; import ru.bvn13.voidforum.utils.DTOUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -139,14 +141,9 @@ public class PostController { @RequestMapping(value = "", method = POST) - public String create(Principal principal, @Valid PostForm postForm, Errors errors, Model model){ + public String create(Principal principal, @Valid PostForm postForm, Errors errors, Model model, RedirectAttributes ra){ if (errors.hasErrors()) { - Map webErrors = new HashMap<>(); - errors.getAllErrors().forEach(e -> { - String field = ((FieldError)e).getField(); - webErrors.put(field, new WebError(field, e.getDefaultMessage())); - }); - model.addAttribute("errors", webErrors); + MessageHelper.addNamedErrorsAsList(ra, "errors", "Please check following errors:", errors); return this.makeFormPostCreation(model, postForm); } else { Post post = DTOUtil.map(postForm, Post.class); @@ -161,14 +158,9 @@ public class PostController { } @RequestMapping(value = "{postId:[0-9]+}", method = {PUT, POST}) - public String update(@PathVariable Long postId, @Valid PostForm postForm, Errors errors, Model model){ - if (errors.hasErrors()){ - Map webErrors = new HashMap<>(); - errors.getAllErrors().forEach(e -> { - String field = ((FieldError)e).getField(); - webErrors.put(field, new WebError(field, e.getDefaultMessage())); - }); - model.addAttribute("errors", webErrors); + public String update(@PathVariable Long postId, @Valid PostForm postForm, Errors errors, Model model, RedirectAttributes ra){ + if (errors.hasErrors()) { + MessageHelper.addNamedErrorsAsList(ra, "errors", "Please check following errors:", errors); return this.makeFormPostEdition(postId, model, postForm); } else { Post post = postRepository.findOne(postId); diff --git a/src/main/java/ru/bvn13/voidforum/forms/RegistrationForm.java b/src/main/java/ru/bvn13/voidforum/forms/RegistrationForm.java index 766fecc..b663240 100644 --- a/src/main/java/ru/bvn13/voidforum/forms/RegistrationForm.java +++ b/src/main/java/ru/bvn13/voidforum/forms/RegistrationForm.java @@ -3,24 +3,25 @@ package ru.bvn13.voidforum.forms; import lombok.Data; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.*; +import java.io.Serializable; /** * bvn13 . */ @Data -public class RegistrationForm { +public class RegistrationForm implements Serializable { @Email(message = "Email should be valid") @NotBlank(message = "Specify your email") - private String username; + private String username = ""; + @Min(value = 4, message = "Nickname should be longer than 4 characters") + @Pattern(regexp = "\\w", message = "Nickname must not contain spaces") @NotBlank(message = "Specify your nickname") - private String nickname; + private String nickname = ""; + @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{6,}$", message = "Password should be longer than 6 characters, at least one latin letter and one number") @NotBlank(message = "Specify your password") private String password; diff --git a/src/main/java/ru/bvn13/voidforum/repositories/CommentRepository.java b/src/main/java/ru/bvn13/voidforum/repositories/CommentRepository.java index 0011a78..af6c77a 100644 --- a/src/main/java/ru/bvn13/voidforum/repositories/CommentRepository.java +++ b/src/main/java/ru/bvn13/voidforum/repositories/CommentRepository.java @@ -13,7 +13,7 @@ import java.util.List; @Repository public interface CommentRepository extends JpaRepository { - List findAllByPostOrderById(Post post); + Page findAllByPostOrderById(Post post, Pageable pageable); List findAllByPostAndParentCommentOrderById(Post post, Comment parentComment); Page findAllByPostAndDeletedMarkOrderById(Post post, Boolean deletedMark, Pageable pageable); @@ -21,4 +21,7 @@ public interface CommentRepository extends JpaRepository { @Query("SELECT COUNT(c.id) FROM Comment AS c WHERE c.post = :post AND c.deletedMark = :deletedMark") Integer getCommentsCountByPostAndDeletedMark(@Param("post") Post post, @Param("deletedMark") Boolean deletedMark); + + @Query("SELECT COUNT(c.id) FROM Comment AS c WHERE c.post = :post") + Integer getCommentsCountByPost(@Param("post") Post post); } diff --git a/src/main/java/ru/bvn13/voidforum/services/CommentService.java b/src/main/java/ru/bvn13/voidforum/services/CommentService.java index b8535d2..d35475e 100644 --- a/src/main/java/ru/bvn13/voidforum/services/CommentService.java +++ b/src/main/java/ru/bvn13/voidforum/services/CommentService.java @@ -52,12 +52,21 @@ public class CommentService { Page availableComments = commentRepository.findAllByPostAndDeletedMarkOrderById(post, false, new PageRequest(page, pageSize, Sort.Direction.ASC, "createdAt")); return availableComments; } + public Page getCommentsForPostForAdmin(Post post, int page, int pageSize) { + Page availableComments = commentRepository.findAllByPostOrderById(post, new PageRequest(page, pageSize, Sort.Direction.ASC, "createdAt")); + return availableComments; + } public Integer getLastPageCommentsForPost(Post post, int pageSize) { Integer count = commentRepository.getCommentsCountByPostAndDeletedMark(post, false); return (int) Math.ceil(count.intValue() / pageSize); } + public Integer getLastPageCommentsForPostForAdmin(Post post, int pageSize) { + Integer count = commentRepository.getCommentsCountByPost(post); + return (int) Math.ceil(count.intValue() / pageSize); + } + public List filterListByParentComment(List comments, Comment parent) { List children = new ArrayList<>(); comments.forEach(c -> { diff --git a/src/main/java/ru/bvn13/voidforum/services/UserService.java b/src/main/java/ru/bvn13/voidforum/services/UserService.java index 4a413c4..b9ecb76 100644 --- a/src/main/java/ru/bvn13/voidforum/services/UserService.java +++ b/src/main/java/ru/bvn13/voidforum/services/UserService.java @@ -6,6 +6,7 @@ import org.hibernate.SessionFactory; import org.hibernate.hql.internal.ast.util.SessionFactoryHelper; import ru.bvn13.voidforum.error.EmailExistsException; import ru.bvn13.voidforum.error.NicknameExistsException; +import ru.bvn13.voidforum.models.Post; import ru.bvn13.voidforum.models.Privilege; import ru.bvn13.voidforum.models.User; import ru.bvn13.voidforum.models.Role; @@ -68,13 +69,15 @@ public class UserService implements UserDetailsService { @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + public UserDetails loadUserByUsername(String emailOrNickname) throws UsernameNotFoundException { org.springframework.security.core.userdetails.User springUser = null; - //sessionFactory.openSession(); + User user = userRepository.findByEmail(emailOrNickname); + if (user == null) { + user = userRepository.findByNickname(emailOrNickname); + } - User user = userRepository.findByEmail(email); if (user == null) { springUser = new org.springframework.security.core.userdetails.User( "", "", true, true, true, true, @@ -90,8 +93,6 @@ public class UserService implements UserDetailsService { ); } - //sessionFactory.close(); - return springUser; } @@ -166,9 +167,14 @@ public class UserService implements UserDetailsService { return this.currentUserHasPrivilege(PrivilegeService.PRIVILEGE_WRITE); } + public Boolean currentUserCanWriteCommentToPost(Post post) { + User user = currentUser(); + return hasPrivilege(user, PrivilegeService.PRIVILEGE_OWNER) + || post.getUser().getId().equals(user.getId()) ? false : post.getDisableCommenting(); + } + public User registerNewUserAccount(User user) throws EmailExistsException, NicknameExistsException { - if (emailExist(user.getEmail())) { throw new EmailExistsException("There is an account with that email address: " + user.getEmail()); } diff --git a/src/main/java/ru/bvn13/voidforum/support/web/Message.java b/src/main/java/ru/bvn13/voidforum/support/web/Message.java index f1b4a96..558e8d2 100644 --- a/src/main/java/ru/bvn13/voidforum/support/web/Message.java +++ b/src/main/java/ru/bvn13/voidforum/support/web/Message.java @@ -1,5 +1,9 @@ package ru.bvn13.voidforum.support.web; +import ru.bvn13.voidforum.models.support.WebError; + +import java.util.List; + /** * A message to be displayed in web context. Depending on the type, different style will be applied. */ @@ -43,4 +47,8 @@ public class Message implements java.io.Serializable { public Object[] getArgs() { return args; } + + public List getArgsAsWebErrorList() { + return (List) args[0]; + } } diff --git a/src/main/java/ru/bvn13/voidforum/support/web/MessageHelper.java b/src/main/java/ru/bvn13/voidforum/support/web/MessageHelper.java index 2736cbe..348b6d0 100644 --- a/src/main/java/ru/bvn13/voidforum/support/web/MessageHelper.java +++ b/src/main/java/ru/bvn13/voidforum/support/web/MessageHelper.java @@ -1,7 +1,16 @@ package ru.bvn13.voidforum.support.web; import org.springframework.ui.Model; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import ru.bvn13.voidforum.models.support.WebError; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static ru.bvn13.voidforum.support.web.Message.MESSAGE_ATTRIBUTE; @@ -90,4 +99,14 @@ public final class MessageHelper { private static void addNamedAttribute(Model model, String name, String message, Message.Type type, Object... args) { model.addAttribute(name, new Message(message, type, args)); } + + public static void addNamedErrorsAsList(RedirectAttributes ra, String name, String message, Errors errors) { + List webErrors = new ArrayList<>(); + errors.getAllErrors().forEach(e -> { + String field = ((FieldError)e).getField(); + webErrors.add(new WebError(field, e.getDefaultMessage())); + }); + addNamedErrorAttribute(ra, name, message, webErrors); + } + } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 16b250d..289a9f0 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -12,28 +12,16 @@ - - - + - - - + - - - + - - - + - - - - - - + + diff --git a/src/main/resources/resources/css/mystyle.css b/src/main/resources/resources/css/mystyle.css index 80fe39b..f147442 100644 --- a/src/main/resources/resources/css/mystyle.css +++ b/src/main/resources/resources/css/mystyle.css @@ -45,7 +45,8 @@ img { } .markdown-body img { - width: 100%; + display: block; + max-width: 100%; height: auto; } @@ -199,6 +200,7 @@ body { } .comment-header ul li { + margin-left: -40px; float: left; padding-right: 10px; display: inline; @@ -208,7 +210,3 @@ body { float: right; display: inline; } - -.btn { - color: #fff !important; -} \ No newline at end of file diff --git a/src/main/resources/templates/admin/posts/edit.jade b/src/main/resources/templates/admin/posts/edit.jade index 27951ca..b5594b5 100644 --- a/src/main/resources/templates/admin/posts/edit.jade +++ b/src/main/resources/templates/admin/posts/edit.jade @@ -11,9 +11,9 @@ block content if errors != null .alert.alert-danger - span Check out errors! + = errors.getMessage() ol - for err in errors.values() + for err in errors.getArgsAsWebErrorList() li #{err.getField()} : #{err.getErrorMessage()} form.post-form(method="post", action="/admin/posts/#{post.getId()}") diff --git a/src/main/resources/templates/admin/posts/new.jade b/src/main/resources/templates/admin/posts/new.jade index d7265fb..a14f60a 100644 --- a/src/main/resources/templates/admin/posts/new.jade +++ b/src/main/resources/templates/admin/posts/new.jade @@ -11,9 +11,9 @@ block content if errors != null .alert.alert-danger - span Check out errors! + = errors.getMessage() ol - for err in errors.values() + for err in errors.getArgsAsWebErrorList() li #{err.getField()} : #{err.getErrorMessage()} form.post-form(method="post", action="/admin/posts") diff --git a/src/main/resources/templates/comments/deleted.jade b/src/main/resources/templates/comments/deleted.jade index 490ce78..77fa0c5 100644 --- a/src/main/resources/templates/comments/deleted.jade +++ b/src/main/resources/templates/comments/deleted.jade @@ -1,9 +1,31 @@ .panel.panel-warning + .panel-heading.comment-header + ul + li + b + i + | DELETED: + b #{comment.getUser().getNickname()} + | , #{viewHelper.getFormattedDate(comment.getCreatedAt())} + + li.admin + if userService.isCurrentUserAdmin() + .operations + a.btn.btn-xs.btn-danger.btn-delete(href="javascript:deleteComment(#{post.id}, #{comment.getId()})", postId="#{post.id}") + i.fa.fa-trash-o + + form(id="form-#{post.getId()}-comment-#{comment.getId()}-delete",style="visibility: hidden", method="post", action="/admin/comments/#{comment.getId()}/delete") + input(type="hidden", name='_csrf', value='#{_csrf.token}') + input(type="hidden", name='postId', value='#{post.getId()}') + + div(class="clearfix") + .panel-body | Sometimes there was a comment here... + //if commentService.childrenCount(comments, comment) > 0 // .comment-children(style="padding-left: #{5 * commentService.childrenCount(comments, comment)}px") // include list diff --git a/src/main/resources/templates/comments/one.jade b/src/main/resources/templates/comments/one.jade index bd86766..c5a2629 100644 --- a/src/main/resources/templates/comments/one.jade +++ b/src/main/resources/templates/comments/one.jade @@ -7,7 +7,7 @@ |, #{viewHelper.getFormattedDate(comment.getCreatedAt())} li.admin if userService.isCurrentUserAdmin() - .td + .operations a.btn.btn-xs.btn-danger.btn-delete(href="javascript:deleteComment(#{post.id}, #{comment.getId()})", postId="#{post.id}") i.fa.fa-trash-o diff --git a/src/main/resources/templates/users/register.jade b/src/main/resources/templates/users/register.jade index d6f12b2..cb3d0c4 100644 --- a/src/main/resources/templates/users/register.jade +++ b/src/main/resources/templates/users/register.jade @@ -10,14 +10,21 @@ block content if error != null && !error.isEmpty() div.alert.alert-danger = error + if errors != null + div.alert.alert-danger + = errors.getMessage() + ol + for err in errors.getArgsAsWebErrorList() + li #{err.getErrorMessage()} + .row .col-md-4.col-md-offset-4.login-container .login-panel form.signin-form(method="post",action="/register") input(type="hidden", name='_csrf', value='#{_csrf.token}') - input.form-control(type="text",name="username",placeholder="Email") - input.form-control(type="text",name="nickname",placeholder="Nickname") + input.form-control(type="text",name="username",placeholder="Email", value="#{registrationForm.getUsername()}") + input.form-control(type="text",name="nickname",placeholder="Nickname", value="#{registrationForm.getNickname()}") input.form-control(type="password",name="password",placeholder="Password") input.form-control(type="password",name="passwordCheck",placeholder="Verify password") button.btn.btn-primary.btn-block(type="submit") Register diff --git a/src/main/resources/templates/users/signin.jade b/src/main/resources/templates/users/signin.jade index f527df8..f0f513c 100644 --- a/src/main/resources/templates/users/signin.jade +++ b/src/main/resources/templates/users/signin.jade @@ -9,7 +9,7 @@ block content .login-panel form.signin-form(method="post",action="/authenticate") input(type="hidden", name='_csrf', value='#{_csrf.token}') - input.form-control(type="text",name="username",placeholder="Email") + input.form-control(type="text",name="username",placeholder="Email or Nickname") input.form-control(type="password",name="password",placeholder="Password") div.col-centered(style="padding-top: 10px;") input(type="checkbox",name="remember-me")