Skip to content

Commit

Permalink
Post ordering
Browse files Browse the repository at this point in the history
  • Loading branch information
Portals committed Sep 5, 2024
1 parent 3123030 commit 580cb97
Show file tree
Hide file tree
Showing 20 changed files with 252 additions and 69 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ dependencies {
// web dependencies
"org.webjars.npm:htmx.org:1.9.12",
"org.webjars.npm:hyperscript.org:0.9.12",
"org.webjars.npm:picocss__pico:2.0.6"
"org.webjars.npm:picocss__pico:2.0.6",
"org.webjars.npm:sortablejs:1.15.3"
)
}

Expand Down
43 changes: 22 additions & 21 deletions app/src/main/java/it/chalmers/gamma/ScheduledTasks.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,40 @@

import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository;
import it.chalmers.gamma.app.user.passwordreset.domain.PasswordResetRepository;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ScheduledTasks {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);

private final UserActivationRepository userActivationRepository;
private final PasswordResetRepository passwordResetRepository;
private final UserActivationRepository userActivationRepository;
private final PasswordResetRepository passwordResetRepository;

public ScheduledTasks(UserActivationRepository userActivationRepository, PasswordResetRepository passwordResetRepository) {
this.userActivationRepository = userActivationRepository;
this.passwordResetRepository = passwordResetRepository;
}
public ScheduledTasks(
UserActivationRepository userActivationRepository,
PasswordResetRepository passwordResetRepository) {
this.userActivationRepository = userActivationRepository;
this.passwordResetRepository = passwordResetRepository;
}

@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidActivationCodes() {
int i = userActivationRepository.removeInvalidActivationCodes();
if (i > 0) {
LOGGER.info("Removed {} expired user activation codes", i);
}
@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidActivationCodes() {
int i = userActivationRepository.removeInvalidActivationCodes();
if (i > 0) {
LOGGER.info("Removed {} expired user activation codes", i);
}
}

@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidPasswordResetTokens() {
int i = passwordResetRepository.removeInvalidPasswordResetTokens();
if (i > 0) {
LOGGER.info("Removed {} expired password reset tokens", i);
}
@Scheduled(timeUnit = TimeUnit.MINUTES, fixedRate = 15)
public void clearInvalidPasswordResetTokens() {
int i = passwordResetRepository.removeInvalidPasswordResetTokens();
if (i > 0) {
LOGGER.info("Removed {} expired password reset tokens", i);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package it.chalmers.gamma.adapter.primary.api.info;

import it.chalmers.gamma.adapter.primary.api.NotFoundResponse;
import it.chalmers.gamma.app.group.GroupFacade;
import it.chalmers.gamma.app.post.PostFacade;
import it.chalmers.gamma.app.supergroup.SuperGroupFacade;
import it.chalmers.gamma.app.user.UserFacade;
import java.util.List;
Expand Down Expand Up @@ -33,9 +35,79 @@ public UserFacade.UserWithGroupsDTO getUser(@PathVariable("id") UUID id) {
return this.userFacade.getWithGroups(id).orElseThrow(UserNotFoundResponse::new);
}

public record BlobItem(String type, List<BlobSuperGroupWithMembers> superGroups) {}

public record BlobSuperGroupWithMembers(
BlobSuperGroup superGroup,
boolean hasBanner,
boolean hasAvatar,
List<BlobGroupMember> members) {

public BlobSuperGroupWithMembers(SuperGroupFacade.SuperGroupWithMembersDTO s) {
this(
new BlobSuperGroup(s.superGroup()),
s.hasBanner(),
s.hasAvatar(),
s.members().stream().map(BlobGroupMember::new).toList());
}
}

public record BlobSuperGroup(
UUID id,
String name,
String prettyName,
String type,
String svDescription,
String enDescription) {

public BlobSuperGroup(SuperGroupFacade.SuperGroupDTO superGroup) {
this(
superGroup.id(),
superGroup.name(),
superGroup.prettyName(),
superGroup.type(),
superGroup.svDescription(),
superGroup.enDescription());
}
}

public record BlobGroupMember(BlobUser user, BlobPost post, String unofficialPostName) {
public BlobGroupMember(GroupFacade.GroupMemberDTO groupMember) {
this(
new BlobUser(groupMember.user()),
new BlobPost(groupMember.post()),
groupMember.unofficialPostName());
}
}

public record BlobUser(
String cid, String nick, String firstName, String lastName, UUID id, int acceptanceYear) {
public BlobUser(UserFacade.UserDTO user) {
this(
user.cid(),
user.nick(),
user.firstName(),
user.lastName(),
user.id(),
user.acceptanceYear());
}
}

public record BlobPost(UUID id, String svName, String enName, String emailPrefix) {
public BlobPost(PostFacade.PostDTO post) {
this(post.id(), post.svName(), post.enName(), post.emailPrefix());
}
}

@GetMapping("/blob")
public List<SuperGroupFacade.SuperGroupTypeDTO> getGroups() {
return this.superGroupFacade.getAllTypesWithSuperGroups();
public List<BlobItem> getGroups() {
return this.superGroupFacade.getAllTypesWithSuperGroups().stream()
.map(
item ->
new BlobItem(
item.type(),
item.superGroups().stream().map(BlobSuperGroupWithMembers::new).toList()))
.toList();
}

private static class UserNotFoundResponse extends NotFoundResponse {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ public ModelAndView getPosts(
mv.addObject("page", "posts/page");
}

mv.addObject(
"posts",
posts.stream().sorted(Comparator.comparing(post -> post.enName().toLowerCase())).toList());

mv.addObject("posts", posts);
return mv;
}

Expand Down Expand Up @@ -264,4 +261,13 @@ public ModelAndView createPost(

return new ModelAndView("redirect:/posts/" + postId);
}

@PutMapping("/posts/order")
public ModelAndView updateOrder(
@RequestHeader(value = "HX-Request", required = true) boolean htmxRequest,
@RequestParam("list") List<UUID> list) {
this.postFacade.setOrder(list);

return new ModelAndView("redirect:/posts");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import it.chalmers.gamma.app.image.domain.ImageUri;
import it.chalmers.gamma.app.user.domain.GammaUser;
import it.chalmers.gamma.app.user.domain.Name;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -48,6 +49,7 @@ public Group toDomain(GroupEntity entity) {
user);
})
.filter(Objects::nonNull)
.sorted(Comparator.comparingInt(member -> member.post().order().value()))
.toList();

Optional<ImageUri> avatarUri = Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class PostEntity extends MutableEntity<UUID> {
@Column(name = "email_prefix")
protected String emailPrefix;

@Column(name = "post_order")
protected int order;

protected PostEntity() {}

protected PostEntity(UUID id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package it.chalmers.gamma.adapter.secondary.jpa.group;

import it.chalmers.gamma.app.group.domain.EmailPrefix;
import it.chalmers.gamma.app.post.domain.Order;
import it.chalmers.gamma.app.post.domain.Post;
import it.chalmers.gamma.app.post.domain.PostId;
import org.springframework.stereotype.Service;
Expand All @@ -13,6 +14,7 @@ public Post toDomain(PostEntity postEntity) {
new PostId(postEntity.id),
postEntity.getVersion(),
postEntity.postName.toDomain(),
new EmailPrefix(postEntity.emailPrefix));
new EmailPrefix(postEntity.emailPrefix),
new Order(postEntity.order));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package it.chalmers.gamma.adapter.secondary.jpa.group;

import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PostJpaRepository extends JpaRepository<PostEntity, UUID> {}
public interface PostJpaRepository extends JpaRepository<PostEntity, UUID> {
List<PostEntity> findAllByOrderByOrderAsc();
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public void save(Post post) {
this.repository.saveAndFlush(toEntity(post));
}

@Override
public void saveAll(List<Post> posts) {
this.repository.saveAll(posts.stream().map(this::toEntity).toList());
}

@Override
public void delete(PostId postId) throws PostNotFoundException {
try {
Expand All @@ -37,14 +42,21 @@ public void delete(PostId postId) throws PostNotFoundException {

@Override
public List<Post> getAll() {
return this.repository.findAll().stream().map(this.postEntityConverter::toDomain).toList();
return this.repository.findAllByOrderByOrderAsc().stream()
.map(this.postEntityConverter::toDomain)
.toList();
}

@Override
public Optional<Post> get(PostId postId) {
return this.repository.findById(postId.value()).map(this.postEntityConverter::toDomain);
}

@Override
public int numberOfPosts() {
return Math.toIntExact(this.repository.count());
}

private PostEntity toEntity(Post post) {
PostEntity postEntity = this.repository.findById(post.id().value()).orElse(new PostEntity());

Expand All @@ -59,6 +71,8 @@ private PostEntity toEntity(Post post) {

postEntity.postName.apply(post.name());

postEntity.order = post.order().value();

return postEntity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ public UserId useToken(PasswordResetToken token) {
public int removeInvalidPasswordResetTokens() {
int i = 0;

for (UserPasswordResetEntity userPasswordResetEntity : this.userPasswordResetJpaRepository.findAll()) {
for (UserPasswordResetEntity userPasswordResetEntity :
this.userPasswordResetJpaRepository.findAll()) {
if (!isStillValid(userPasswordResetEntity)) {
this.userPasswordResetJpaRepository.delete(userPasswordResetEntity);
i++;
Expand Down
44 changes: 38 additions & 6 deletions app/src/main/java/it/chalmers/gamma/app/post/PostFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
import it.chalmers.gamma.app.group.GroupFacade;
import it.chalmers.gamma.app.group.domain.EmailPrefix;
import it.chalmers.gamma.app.group.domain.GroupRepository;
import it.chalmers.gamma.app.post.domain.Order;
import it.chalmers.gamma.app.post.domain.Post;
import it.chalmers.gamma.app.post.domain.PostId;
import it.chalmers.gamma.app.post.domain.PostRepository;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import jakarta.transaction.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;

@Service
Expand Down Expand Up @@ -44,7 +46,8 @@ public UUID create(NewPost newPost) {
postId,
0,
new Text(newPost.svText, newPost.enText),
new EmailPrefix(newPost.emailPrefix)));
new EmailPrefix(newPost.emailPrefix),
new Order(this.postRepository.numberOfPosts())));

return postId.value();
}
Expand Down Expand Up @@ -90,19 +93,48 @@ public List<GroupFacade.GroupWithMembersDTO> getPostUsages(UUID postId) {
.toList();
}

@Transactional
public void setOrder(List<UUID> orderedPosts) {
this.accessGuard.require(isAdmin());

Map<PostId, Post> posts =
this.postRepository.getAll().stream()
.collect(Collectors.toMap(Post::id, Function.identity()));

boolean anythingChanged = false;

for (int i = 0; i < orderedPosts.size(); i++) {
UUID orderedPostId = orderedPosts.get(i);
Post post = posts.get(new PostId(orderedPostId));
if (post == null) {
throw new IllegalArgumentException("Unexpected post id");
}

anythingChanged = anythingChanged || post.order().value() != i;

posts.put(post.id(), post.withOrder(new Order(i)));
}

if (anythingChanged) {
this.postRepository.saveAll(new ArrayList<>(posts.values()));
}
}

public record NewPost(String svText, String enText, String emailPrefix) {}

public record UpdatePost(
UUID postId, int version, String svText, String enText, String emailPrefix) {}

public record PostDTO(UUID id, int version, String svName, String enName, String emailPrefix) {
public record PostDTO(
UUID id, int version, String svName, String enName, String emailPrefix, int order) {
public PostDTO(Post post) {
this(
post.id().value(),
post.version(),
post.name().sv().value(),
post.name().en().value(),
post.emailPrefix().value());
post.emailPrefix().value(),
post.order().value());
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/it/chalmers/gamma/app/post/domain/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package it.chalmers.gamma.app.post.domain;

public record Order(int value) {

public Order {
if (value < 0) {
throw new IllegalArgumentException("order must be >= 0");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.Objects;

@RecordBuilder
public record Post(PostId id, int version, Text name, EmailPrefix emailPrefix)
public record Post(PostId id, int version, Text name, EmailPrefix emailPrefix, Order order)
implements PostBuilder.With {

public Post {
Expand Down
Loading

0 comments on commit 580cb97

Please sign in to comment.