Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Portals committed Jun 25, 2024
1 parent d2a00bc commit b9ee17e
Show file tree
Hide file tree
Showing 22 changed files with 180 additions and 617 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ public class GammaErrorController implements ErrorController {

@GetMapping("/error")
public ModelAndView handleRuntimeException(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
HttpServletResponse response,
HttpServletRequest request) {
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
HttpServletResponse response,
HttpServletRequest request) {
Object statusCodeString = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
int statusCode = Integer.parseInt(statusCodeString.toString());

System.out.println(statusCode);

String page = switch(HttpStatus.valueOf(statusCode)) {
case NOT_FOUND -> "pages/404";
default -> "pages/500";
};
String page =
switch (HttpStatus.valueOf(statusCode)) {
case NOT_FOUND -> "pages/404";
default -> "pages/error";
};

ModelAndView mv = new ModelAndView();
if (htmxRequest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@

import it.chalmers.gamma.app.common.PrettyName.PrettyNameValidator;
import it.chalmers.gamma.app.group.GroupFacade;
import it.chalmers.gamma.app.group.domain.UnofficialPostName;
import it.chalmers.gamma.app.post.PostFacade;
import it.chalmers.gamma.app.supergroup.SuperGroupFacade;
import it.chalmers.gamma.app.user.UserFacade;
import it.chalmers.gamma.app.user.domain.Name.NameValidator;
import jakarta.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.data.util.Pair;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

Expand All @@ -39,6 +43,11 @@ public GroupsController(
this.postFacade = postFacade;
}

@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}

@GetMapping("/groups")
public ModelAndView getGroups(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest) {
Expand Down Expand Up @@ -108,14 +117,15 @@ public ModelAndView getGroup(
"members",
group.get().groupMembers().stream()
.map(
groupMember ->
new Member(
groupMember.user().nick(),
" - "
+ groupMember.post().enName()
+ " - "
+ Objects.requireNonNullElse(groupMember.unofficialPostName(), ""),
groupMember.user().id()))
groupMember -> {
String post = " - " + groupMember.post().enName();

if (groupMember.unofficialPostName() != null) {
post += " - " + groupMember.unofficialPostName();
}

return new Member(groupMember.user().nick(), post, groupMember.user().id());
})
.toList());
mv.addObject("random", Math.random());

Expand Down Expand Up @@ -263,6 +273,8 @@ public void setMembers(List<Member> members) {
public static final class Member {
private UUID userId;
private UUID postId;

@ValidatedWith(UnofficialPostName.UnofficialPostNameValidator.class)
private String unofficialPostName;

public Member() {}
Expand Down Expand Up @@ -299,12 +311,7 @@ public void setUnofficialPostName(String unofficialPostName) {
}
}

@GetMapping("/groups/{id}/edit")
public ModelAndView getGroupEdit(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("id") UUID id,
GroupForm form,
BindingResult bindingResult) {
private ModelAndView createGetGroupEdit(UUID id, GroupForm form, BindingResult bindingResult) {
Optional<GroupFacade.GroupWithMembersDTO> group = this.groupFacade.getWithMembers(id);

if (group.isEmpty()) {
Expand All @@ -321,7 +328,7 @@ public ModelAndView getGroupEdit(
List<UserFacade.UserDTO> users = this.userFacade.getAll();
List<PostFacade.PostDTO> posts = this.postFacade.getAll();

if (form != null) {
if (form == null) {
form =
new GroupForm(
group.get().version(),
Expand Down Expand Up @@ -362,13 +369,34 @@ public ModelAndView getGroupEdit(
.map(UserFacade.UserDTO::id)
.toList());

if (bindingResult.hasErrors()) {
if (bindingResult != null && bindingResult.hasErrors()) {
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);
}

return mv;
}

private void checkForDuplicateEntries(GroupForm form, BindingResult bindingResult) {
Set<Pair<UUID, UUID>> uniquePairs = new HashSet<>();
for (int i = 0; i < form.getMembers().size(); i++) {
GroupForm.Member member = form.getMembers().get(i);
Pair<UUID, UUID> pair = Pair.of(member.getUserId(), member.getPostId());
if (uniquePairs.contains(pair)) {
bindingResult.addError(
new FieldError("form", "members[" + i + "]", "Duplicate user/post entry"));
} else {
uniquePairs.add(pair);
}
}
}

@GetMapping("/groups/{id}/edit")
public ModelAndView getGroupEdit(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@PathVariable("id") UUID id) {
return createGetGroupEdit(id, null, null);
}

@PutMapping("/groups/{id}")
public ModelAndView updateGroup(
@RequestHeader(value = "HX-Request", required = false) boolean htmxRequest,
Expand All @@ -379,14 +407,16 @@ public ModelAndView updateGroup(

validateObject(form, bindingResult);

checkForDuplicateEntries(form, bindingResult);

if (!bindingResult.hasErrors() && this.groupFacade.groupWithNameAlreadyExists(id, form.name)) {
bindingResult.addError(new FieldError("form", "name", "Group with name already exists"));
}

if (bindingResult.hasErrors()) {
response.addHeader("HX-Reswap", "outerHTML");
response.addHeader("HX-Retarget", "closest <article/>");
return this.getGroupEdit(htmxRequest, id, form, bindingResult);
return createGetGroupEdit(id, form, bindingResult);
} else {
this.groupFacade.update(
new GroupFacade.UpdateGroup(
Expand Down Expand Up @@ -450,8 +480,18 @@ public ModelAndView createGetCreateGroup(
form = new GroupForm();
}

List<UserFacade.UserDTO> users = this.userFacade.getAll();
List<PostFacade.PostDTO> posts = this.postFacade.getAll();

mv.addObject("form", form);
mv.addObject("superGroups", this.superGroupFacade.getAll());
mv.addObject(
"users",
users.stream().collect(Collectors.toMap(UserFacade.UserDTO::id, UserFacade.UserDTO::nick)));
mv.addObject(
"posts",
posts.stream()
.collect(Collectors.toMap(PostFacade.PostDTO::id, PostFacade.PostDTO::enName)));

if (bindingResult != null && bindingResult.hasErrors()) {
mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult);
Expand All @@ -474,6 +514,8 @@ public ModelAndView createGroup(

validateObject(form, bindingResult);

checkForDuplicateEntries(form, bindingResult);

if (bindingResult.hasErrors()) {
return createGetCreateGroup(htmxRequest, form, bindingResult);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,4 @@ public ModelAndView handleMaxSizeException(HttpServletResponse response) {
public void handleAccessDeniedException(HttpServletResponse response) throws IOException {
response.sendRedirect("/");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,61 @@ public class WebValidationHelper {
public static void validateObject(Object obj, BindingResult bindingResult) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
ValidatedWith validatedWith = field.getAnnotation(ValidatedWith.class);
if (validatedWith != null) {
field.setAccessible(true);
try {
Validator<Object> validator =
(Validator<Object>) validatedWith.value().getDeclaredConstructor().newInstance();
Object fieldValue = field.get(obj);
ValidationResult validationResult = validator.validate(fieldValue);
if (validationResult instanceof FailedValidation failedValidation) {
bindingResult.addError(
new FieldError(
"form",
field.getName(),
fieldValue,
true,
null,
null,
failedValidation.message()));
}
} catch (NoSuchMethodException
| InstantiationException
| IllegalAccessException
| InvocationTargetException e) {
throw new RuntimeException(e);
validateField(field, "", obj, bindingResult);
}
}

private static void validateField(
Field field, String prefix, Object obj, BindingResult bindingResult) {
field.setAccessible(true);
Object fieldValue;
try {
fieldValue = field.get(obj);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}

ValidatedWith validatedWith = field.getAnnotation(ValidatedWith.class);
if (validatedWith != null) {
try {
Validator<Object> validator =
(Validator<Object>) validatedWith.value().getDeclaredConstructor().newInstance();
ValidationResult validationResult = validator.validate(fieldValue);
if (validationResult instanceof FailedValidation failedValidation) {
bindingResult.addError(
new FieldError(
"form",
prefix + field.getName(),
fieldValue,
true,
null,
null,
failedValidation.message()));
}
} catch (NoSuchMethodException
| InstantiationException
| IllegalAccessException
| InvocationTargetException e) {
throw new RuntimeException(e);
}
}

if (fieldValue instanceof Iterable<?>) {
int i = 0;
for (Object item : (Iterable<?>) fieldValue) {
if (item != null && !item.getClass().isPrimitive() && !(item instanceof String)) {
String newPrefix = String.format("%s%s[%d].", prefix, field.getName(), i);
validateObject(item, newPrefix, bindingResult);
}
i++;
}
}
}

private static void validateObject(Object obj, String prefix, BindingResult bindingResult) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
validateField(field, prefix, obj, bindingResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ public void setMembers(UUID groupId, List<ShallowMember> newMembers)
this.postRepository
.get(new PostId(shallowMember.postId))
.orElseThrow(PostNotFoundRuntimeException::new),
new UnofficialPostName(
shallowMember.unofficialPostName == null ? "" : shallowMember.unofficialPostName),
new UnofficialPostName(shallowMember.unofficialPostName),
this.userRepository
.get(new UserId(shallowMember.userId))
.orElseThrow(UserNotFoundRuntimeException::new)));
Expand Down
Loading

0 comments on commit b9ee17e

Please sign in to comment.