Basic Recipe entity and models.

This commit is contained in:
JesseBrault0709 2024-06-27 13:06:41 +02:00
parent e205db813a
commit b10451203b
17 changed files with 933 additions and 0 deletions

View File

@ -31,6 +31,14 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
implementation 'org.commonmark:commonmark:0.22.0'
implementation 'org.jsoup:jsoup:1.17.2'
compileOnly 'org.jetbrains:annotations:24.1.0'
// Custom testing
testRuntimeOnly 'com.h2database:h2'
}
tasks.named('test') {

View File

@ -0,0 +1,21 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
import app.mealsmadeeasy.api.user.User;
import org.jetbrains.annotations.Nullable;
import java.time.LocalDateTime;
import java.util.Set;
public interface Recipe {
Long getId();
LocalDateTime getCreated();
@Nullable LocalDateTime getModified();
String getTitle();
String getRawText();
User getOwner();
Set<User> getStarGazers();
boolean isPublic();
Set<User> getViewers();
Set<RecipeComment> getComments();
}

View File

@ -0,0 +1,170 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
import app.mealsmadeeasy.api.recipe.comment.RecipeCommentEntity;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserEntity;
import jakarta.persistence.*;
import org.jetbrains.annotations.Nullable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
@Entity(name = "Recipe")
public final class RecipeEntity implements Recipe {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false, updatable = false)
private Long id;
@Column(nullable = false)
private LocalDateTime created = LocalDateTime.now();
private LocalDateTime modified;
@Column(nullable = false)
private String title;
@Column(nullable = false)
@Lob
@Basic(fetch = FetchType.LAZY)
private String rawText;
@Lob
@Basic(fetch = FetchType.LAZY)
private String cachedRenderedText;
@ManyToOne(optional = false)
@JoinColumn(name = "owner_id", nullable = false)
private UserEntity owner;
@OneToMany
private Set<UserEntity> starGazers = new HashSet<>();
@OneToMany(mappedBy = "recipe")
private Set<RecipeCommentEntity> comments = new HashSet<>();
@Column(nullable = false)
private Boolean isPublic = false;
@ManyToMany
private Set<UserEntity> viewers = new HashSet<>();
@Override
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public LocalDateTime getCreated() {
return this.created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
@Override
public @Nullable LocalDateTime getModified() {
return this.modified;
}
public void setModified(@Nullable LocalDateTime modified) {
this.modified = modified;
}
@Override
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String getRawText() {
return this.rawText;
}
public void setRawText(String rawText) {
this.rawText = rawText;
}
public String getCachedRenderedText() {
return this.cachedRenderedText;
}
public void setCachedRenderedText(String cachedRenderedText) {
this.cachedRenderedText = cachedRenderedText;
}
@Override
public UserEntity getOwner() {
return this.owner;
}
public void setOwner(UserEntity owner) {
this.owner = owner;
}
@Override
public boolean isPublic() {
return this.isPublic;
}
public void setPublic(Boolean isPublic) {
this.isPublic = isPublic;
}
@Override
public Set<User> getViewers() {
return Set.copyOf(this.viewers);
}
public Set<UserEntity> getViewerEntities() {
return this.viewers;
}
public void setViewers(Set<UserEntity> viewers) {
this.viewers = viewers;
}
@Override
public Set<User> getStarGazers() {
return Set.copyOf(this.starGazers);
}
public Set<UserEntity> getStarGazerEntities() {
return this.starGazers;
}
public void setStarGazers(Set<UserEntity> starGazers) {
this.starGazers = starGazers;
}
@Override
public Set<RecipeComment> getComments() {
return Set.copyOf(this.comments);
}
public Set<RecipeCommentEntity> getCommentEntities() {
return this.comments;
}
public void setComments(Set<RecipeCommentEntity> comments) {
this.comments = comments;
}
@Override
public String toString() {
return "RecipeEntity(" + this.id + ", " + this.title + ")";
}
}

View File

@ -0,0 +1,25 @@
package app.mealsmadeeasy.api.recipe;
public class RecipeException extends Exception {
public enum Type {
INVALID_OWNER_USERNAME, INVALID_STAR, INVALID_ID
}
private final Type type;
public RecipeException(Type type, String message, Throwable cause) {
super(message, cause);
this.type = type;
}
public RecipeException(Type type, String message) {
super(message);
this.type = type;
}
public Type getType() {
return this.type;
}
}

View File

@ -0,0 +1,16 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.user.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface RecipeRepository extends JpaRepository<RecipeEntity, Long> {
List<RecipeEntity> findAllByIsPublicIsTrue();
List<RecipeEntity> findAllByViewersContaining(UserEntity viewer);
List<RecipeEntity> findAllByOwner(UserEntity owner);
@Query("SELECT r FROM Recipe r WHERE size(r.starGazers) > ?1")
List<RecipeEntity> findAllByStarGazersGreaterThanEqual(long stars);
}

View File

@ -0,0 +1,45 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
import app.mealsmadeeasy.api.user.User;
import java.util.List;
public interface RecipeService {
Recipe create(String ownerUsername, String title, String rawText) throws RecipeException;
Recipe getById(long id) throws RecipeException;
List<Recipe> getByMinimumStars(long minimumStars);
List<Recipe> getPublicRecipes();
List<Recipe> getRecipesViewableBy(User user);
List<Recipe> getRecipesOwnedBy(User user);
String getRenderedMarkdown(Recipe recipe);
Recipe updateRawText(Recipe recipe, String newRawText);
Recipe updateOwner(Recipe recipe, String newOwnerUsername) throws RecipeException;
RecipeStar addStar(Recipe recipe, User giver);
void deleteStarByUser(Recipe recipe, User giver) throws RecipeException;
void deleteStar(RecipeStar recipeStar);
Recipe setPublic(Recipe recipe, boolean isPublic);
Recipe addViewer(Recipe recipe, User user);
Recipe removeViewer(Recipe recipe, User user);
Recipe clearViewers(Recipe recipe);
RecipeComment getCommentById(long id) throws RecipeException;
RecipeComment addComment(Recipe recipe, String rawCommentText, User commenter);
RecipeComment updateComment(RecipeComment comment, String newRawCommentText);
String getRenderedMarkdown(RecipeComment recipeComment);
void deleteComment(RecipeComment comment);
Recipe clearComments(Recipe recipe);
void deleteRecipe(Recipe recipe);
void deleteById(long id);
}

View File

@ -0,0 +1,236 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
import app.mealsmadeeasy.api.recipe.comment.RecipeCommentEntity;
import app.mealsmadeeasy.api.recipe.comment.RecipeCommentRepository;
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
import app.mealsmadeeasy.api.recipe.star.RecipeStarEntity;
import app.mealsmadeeasy.api.recipe.star.RecipeStarRepository;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserEntity;
import app.mealsmadeeasy.api.user.UserRepository;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Service
public final class RecipeServiceImpl implements RecipeService {
private static String renderAndCleanMarkdown(String rawText) {
final var parser = Parser.builder().build();
final var node = parser.parse(rawText);
final var htmlRenderer = HtmlRenderer.builder().build();
final String unsafeHtml = htmlRenderer.render(node);
return Jsoup.clean(unsafeHtml, Safelist.relaxed());
}
private final RecipeRepository recipeRepository;
private final UserRepository userRepository;
private final RecipeStarRepository recipeStarRepository;
private final RecipeCommentRepository recipeCommentRepository;
public RecipeServiceImpl(
RecipeRepository recipeRepository,
UserRepository userRepository,
RecipeStarRepository recipeStarRepository,
RecipeCommentRepository recipeCommentRepository
) {
this.recipeRepository = recipeRepository;
this.userRepository = userRepository;
this.recipeStarRepository = recipeStarRepository;
this.recipeCommentRepository = recipeCommentRepository;
}
@Override
public Recipe create(String ownerUsername, String title, String rawText) throws RecipeException {
final RecipeEntity draft = new RecipeEntity();
final UserEntity userEntity = this.userRepository.findByUsername(ownerUsername)
.orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_OWNER_USERNAME,
"No such ownerUsername " + ownerUsername
));
draft.setOwner(userEntity);
draft.setTitle(title);
draft.setRawText(rawText);
return this.recipeRepository.save(draft);
}
@Override
public Recipe getById(long id) throws RecipeException {
return this.recipeRepository.findById(id).orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_ID,
"No such recipe for id " + id
));
}
@Override
public List<Recipe> getByMinimumStars(long minimumStars) {
return List.copyOf(this.recipeRepository.findAllByStarGazersGreaterThanEqual(minimumStars));
}
@Override
public List<Recipe> getPublicRecipes() {
return List.copyOf(this.recipeRepository.findAllByIsPublicIsTrue());
}
@Override
public List<Recipe> getRecipesViewableBy(User user) {
return List.copyOf(this.recipeRepository.findAllByViewersContaining((UserEntity) user));
}
@Override
public List<Recipe> getRecipesOwnedBy(User user) {
return List.copyOf(this.recipeRepository.findAllByOwner((UserEntity) user));
}
@Override
public String getRenderedMarkdown(Recipe recipe) {
RecipeEntity entity = (RecipeEntity) recipe;
if (entity.getCachedRenderedText() == null) {
entity.setCachedRenderedText(renderAndCleanMarkdown(entity.getRawText()));
entity = this.recipeRepository.save(entity);
}
return entity.getCachedRenderedText();
}
@Override
public Recipe updateRawText(Recipe recipe, String newRawText) {
final RecipeEntity entity = (RecipeEntity) recipe;
entity.setCachedRenderedText(null);
entity.setRawText(newRawText);
return this.recipeRepository.save(entity);
}
@Override
public Recipe updateOwner(Recipe recipe, String newOwnerUsername) throws RecipeException {
final RecipeEntity entity = (RecipeEntity) recipe;
final UserEntity newOwner = this.userRepository.findByUsername(newOwnerUsername)
.orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_OWNER_USERNAME,
"No such username: " + newOwnerUsername
));
entity.setOwner(newOwner);
return this.recipeRepository.save(entity);
}
@Override
public RecipeStar addStar(Recipe recipe, User giver) {
final RecipeEntity entity = (RecipeEntity) recipe;
final RecipeStarEntity star = new RecipeStarEntity();
star.setOwner((UserEntity) giver);
star.setRecipe(entity);
return this.recipeStarRepository.save(star);
}
@Override
public void deleteStar(RecipeStar recipeStar) {
this.recipeStarRepository.delete((RecipeStarEntity) recipeStar);
}
@Override
public void deleteStarByUser(Recipe recipe, User giver) throws RecipeException {
final RecipeStarEntity star = this.recipeStarRepository.findByOwnerAndRecipe(
(UserEntity) giver,
(RecipeEntity) recipe
).orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_STAR,
"No such star for user " + giver.getUsername() + " and recipe " + recipe.getId()
));
this.recipeStarRepository.delete(star);
}
@Override
public Recipe setPublic(Recipe recipe, boolean isPublic) {
final RecipeEntity entity = (RecipeEntity) recipe;
entity.setPublic(isPublic);
return this.recipeRepository.save(entity);
}
@Override
public Recipe addViewer(Recipe recipe, User user) {
final RecipeEntity entity = (RecipeEntity) recipe;
final Set<UserEntity> viewers = new HashSet<>(entity.getViewerEntities());
viewers.add((UserEntity) user);
entity.setViewers(viewers);
return this.recipeRepository.save(entity);
}
@Override
public Recipe removeViewer(Recipe recipe, User user) {
final RecipeEntity entity = (RecipeEntity) recipe;
final Set<UserEntity> viewers = new HashSet<>(entity.getViewerEntities());
viewers.remove((UserEntity) user);
entity.setViewers(viewers);
return this.recipeRepository.save(entity);
}
@Override
public Recipe clearViewers(Recipe recipe) {
final RecipeEntity entity = (RecipeEntity) recipe;
entity.setViewers(new HashSet<>());
return this.recipeRepository.save(entity);
}
@Override
public RecipeComment getCommentById(long id) throws RecipeException {
return this.recipeCommentRepository.findById(id)
.orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_ID,
"No such RecipeComment for id " + id
));
}
@Override
public RecipeComment addComment(Recipe recipe, String rawCommentText, User commenter) {
final RecipeCommentEntity draft = new RecipeCommentEntity();
draft.setRawText(rawCommentText);
draft.setOwner((UserEntity) commenter);
return this.recipeCommentRepository.save(draft);
}
@Override
public RecipeComment updateComment(RecipeComment comment, String newRawCommentText) {
final RecipeCommentEntity entity = (RecipeCommentEntity) comment;
entity.setCachedRenderedText(null);
entity.setRawText(newRawCommentText);
return this.recipeCommentRepository.save(entity);
}
@Override
public String getRenderedMarkdown(RecipeComment recipeComment) {
RecipeCommentEntity entity = (RecipeCommentEntity) recipeComment;
if (entity.getCachedRenderedText() == null) {
entity.setCachedRenderedText(renderAndCleanMarkdown(entity.getRawText()));
entity = this.recipeCommentRepository.save(entity);
}
return entity.getCachedRenderedText();
}
@Override
public void deleteComment(RecipeComment comment) {
this.recipeCommentRepository.delete((RecipeCommentEntity) comment);
}
@Override
public Recipe clearComments(Recipe recipe) {
this.recipeCommentRepository.deleteAllByRecipe((RecipeEntity) recipe);
return this.recipeRepository.getReferenceById(recipe.getId());
}
@Override
public void deleteRecipe(Recipe recipe) {
this.recipeRepository.delete((RecipeEntity) recipe);
}
@Override
public void deleteById(long id) {
this.recipeRepository.deleteById(id);
}
}

View File

@ -0,0 +1,14 @@
package app.mealsmadeeasy.api.recipe.comment;
import app.mealsmadeeasy.api.recipe.Recipe;
import app.mealsmadeeasy.api.user.User;
import java.time.LocalDateTime;
public interface RecipeComment {
LocalDateTime getCreated();
LocalDateTime getModified();
String getRawText();
User getOwner();
Recipe getRecipe();
}

View File

@ -0,0 +1,99 @@
package app.mealsmadeeasy.api.recipe.comment;
import app.mealsmadeeasy.api.recipe.RecipeEntity;
import app.mealsmadeeasy.api.user.UserEntity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity(name = "RecipeComment")
public final class RecipeCommentEntity implements RecipeComment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private Long id;
@Column(nullable = false, updatable = false)
private LocalDateTime created = LocalDateTime.now();
private LocalDateTime modified;
@Lob
@Basic(fetch = FetchType.LAZY)
private String rawText;
@Lob
@Basic(fetch = FetchType.LAZY)
private String cachedRenderedText;
@ManyToOne
@JoinColumn(name = "owner_id", nullable = false, updatable = false)
private UserEntity owner;
@ManyToOne
@JoinColumn(name = "recipe_id", nullable = false, updatable = false)
private RecipeEntity recipe;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public LocalDateTime getCreated() {
return this.created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
@Override
public LocalDateTime getModified() {
return this.modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
@Override
public String getRawText() {
return this.rawText;
}
public void setRawText(String rawText) {
this.rawText = rawText;
}
public String getCachedRenderedText() {
return this.cachedRenderedText;
}
public void setCachedRenderedText(String cachedRenderedText) {
this.cachedRenderedText = cachedRenderedText;
}
@Override
public UserEntity getOwner() {
return this.owner;
}
public void setOwner(UserEntity owner) {
this.owner = owner;
}
@Override
public RecipeEntity getRecipe() {
return this.recipe;
}
public void setRecipe(RecipeEntity recipe) {
this.recipe = recipe;
}
}

View File

@ -0,0 +1,8 @@
package app.mealsmadeeasy.api.recipe.comment;
import app.mealsmadeeasy.api.recipe.RecipeEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RecipeCommentRepository extends JpaRepository<RecipeCommentEntity, Long> {
void deleteAllByRecipe(RecipeEntity recipe);
}

View File

@ -0,0 +1,12 @@
package app.mealsmadeeasy.api.recipe.star;
import app.mealsmadeeasy.api.recipe.Recipe;
import app.mealsmadeeasy.api.user.User;
import java.time.LocalDateTime;
public interface RecipeStar {
User getOwner();
LocalDateTime getDate();
Recipe getRecipe();
}

View File

@ -0,0 +1,63 @@
package app.mealsmadeeasy.api.recipe.star;
import app.mealsmadeeasy.api.recipe.RecipeEntity;
import app.mealsmadeeasy.api.user.UserEntity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity(name = "RecipeStar")
public final class RecipeStarEntity implements RecipeStar {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private Long id;
@ManyToOne
@JoinColumn(name = "owner_id", nullable = false, updatable = false)
private UserEntity owner;
@Column(nullable = false, updatable = false)
private LocalDateTime date = LocalDateTime.now();
@ManyToOne
@JoinColumn(name = "recipe_id", nullable = false, updatable = false)
private RecipeEntity recipe;
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
@Override
public UserEntity getOwner() {
return this.owner;
}
public void setOwner(UserEntity owner) {
this.owner = owner;
}
@Override
public LocalDateTime getDate() {
return this.date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
@Override
public RecipeEntity getRecipe() {
return this.recipe;
}
public void setRecipe(RecipeEntity recipe) {
this.recipe = recipe;
}
}

View File

@ -0,0 +1,14 @@
package app.mealsmadeeasy.api.recipe.star;
import app.mealsmadeeasy.api.recipe.RecipeEntity;
import app.mealsmadeeasy.api.user.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface RecipeStarRepository extends JpaRepository<RecipeStarEntity, Long> {
List<RecipeStarEntity> findAllByOwner(UserEntity user);
long countAllByOwner(UserEntity user);
Optional<RecipeStarEntity> findByOwnerAndRecipe(UserEntity user, RecipeEntity recipe);
}

View File

@ -5,9 +5,11 @@ import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@Entity(name = "User")
@Table(name = "\"user\"")
public final class UserEntity implements User {
public static UserEntity getDefaultDraft() {
@ -141,4 +143,41 @@ public final class UserEntity implements User {
this.enabled = enabled;
}
@Override
public int hashCode() {
return Objects.hash(
this.id,
this.username,
this.email,
this.password,
this.authorities,
this.enabled,
this.expired,
this.locked,
this.credentialsExpired
);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof User o) {
return Objects.equals(this.id, o.getId())
&& Objects.equals(this.username, o.getUsername())
&& Objects.equals(this.password, o.getPassword())
&& Objects.equals(this.authorities, o.getAuthorities())
&& Objects.equals(this.enabled, o.isEnabled())
&& Objects.equals(this.expired, !o.isAccountNonExpired())
&& Objects.equals(this.locked, !o.isAccountNonLocked())
&& Objects.equals(this.credentialsExpired, !o.isCredentialsNonExpired());
} else {
return false;
}
}
@Override
public String toString() {
return "User(" + this.id + ", " + this.username + ", " + this.email + ")";
}
}

View File

@ -0,0 +1,102 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.user.UserEntity;
import app.mealsmadeeasy.api.user.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
public class RecipeRepositoryTests {
@Autowired
private RecipeRepository recipeRepository;
@Autowired
private UserRepository userRepository;
private UserEntity getOwnerUser() {
final UserEntity recipeUser = UserEntity.getDefaultDraft();
recipeUser.setUsername("recipeUser");
recipeUser.setEmail("recipe@user.com");
recipeUser.setPassword("test");
return this.userRepository.save(recipeUser);
}
private UserEntity getViewerUser() {
final UserEntity viewerUser = UserEntity.getDefaultDraft();
viewerUser.setUsername("recipeViewerUser");
viewerUser.setEmail("recipe-viewer@user.com");
viewerUser.setPassword("test");
return this.userRepository.save(viewerUser);
}
@Test
@DirtiesContext
public void findsAllPublicRecipes() {
final RecipeEntity publicRecipe = new RecipeEntity();
publicRecipe.setPublic(true);
publicRecipe.setOwner(this.getOwnerUser());
publicRecipe.setTitle("Public Recipe");
publicRecipe.setRawText("Hello, World!");
this.recipeRepository.save(publicRecipe);
final List<RecipeEntity> publicRecipes = this.recipeRepository.findAllByIsPublicIsTrue();
assertThat(publicRecipes.size()).isEqualTo(1);
}
@Test
@DirtiesContext
public void doesNotFindNonPublicRecipe() {
final RecipeEntity nonPublicRecipe = new RecipeEntity();
nonPublicRecipe.setOwner(this.getOwnerUser());
nonPublicRecipe.setTitle("Non-Public Recipe");
nonPublicRecipe.setRawText("Hello, World!");
this.recipeRepository.save(nonPublicRecipe);
final List<RecipeEntity> publicRecipes = this.recipeRepository.findAllByIsPublicIsTrue();
assertThat(publicRecipes.size()).isEqualTo(0);
}
@Test
@DirtiesContext
public void findsAllForViewer() {
final RecipeEntity recipe = new RecipeEntity();
recipe.setOwner(this.getOwnerUser());
recipe.setTitle("Test Recipe");
recipe.setRawText("Hello, World!");
final RecipeEntity saved = this.recipeRepository.save(recipe);
final UserEntity viewer = this.getViewerUser();
final Set<UserEntity> viewers = new HashSet<>(recipe.getViewerEntities());
viewers.add(viewer);
saved.setViewers(viewers);
this.recipeRepository.save(saved);
final List<RecipeEntity> viewable = this.recipeRepository.findAllByViewersContaining(viewer);
assertThat(viewable.size()).isEqualTo(1);
}
@Test
@DirtiesContext
public void doesNotIncludeNonViewable() {
final RecipeEntity recipe = new RecipeEntity();
recipe.setOwner(this.getOwnerUser());
recipe.setTitle("Test Recipe");
recipe.setRawText("Hello, World!");
this.recipeRepository.save(recipe);
final UserEntity viewer = this.getViewerUser();
final List<RecipeEntity> viewable = this.recipeRepository.findAllByViewersContaining(viewer);
assertThat(viewable.size()).isEqualTo(0);
}
}

View File

@ -0,0 +1,55 @@
package app.mealsmadeeasy.api.recipe;
import app.mealsmadeeasy.api.user.User;
import app.mealsmadeeasy.api.user.UserEntity;
import app.mealsmadeeasy.api.user.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@SpringBootTest
public class RecipeServiceTests {
@Autowired
private RecipeService recipeService;
@Autowired
private UserRepository userRepository;
private UserEntity createTestUser(String username) {
final UserEntity draft = UserEntity.getDefaultDraft();
draft.setUsername(username);
draft.setEmail(username + "@test.com");
draft.setPassword("test");
return this.userRepository.save(draft);
}
private Recipe createTestRecipe(User owner) throws RecipeException {
return this.recipeService.create(owner.getUsername(), "My Recipe" , "Hello!");
}
@Test
@DirtiesContext
public void simpleCreate() throws RecipeException {
final User user = this.createTestUser("recipeOwner");
final Recipe recipe = this.recipeService.create(user.getUsername(), "My Recipe" , "Hello!");
assertThat(recipe.getOwner(), is(user));
assertThat(recipe.getTitle(), is("My Recipe"));
assertThat(recipe.getRawText(), is("Hello!"));
}
@Test
@DirtiesContext
public void simpleGetById() throws RecipeException {
final Recipe testRecipe = this.createTestRecipe(this.createTestUser("recipeOwner"));
final Recipe byId = this.recipeService.getById(testRecipe.getId());
assertThat(byId.getId(), is(testRecipe.getId()));
assertThat(byId.getTitle(), is("My Recipe"));
assertThat(byId.getRawText(), is("Hello!"));
}
}

View File

@ -0,0 +1,6 @@
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
app.mealsmadeeasy.api.security.access-token-lifetime=60
app.mealsmadeeasy.api.security.refresh-token-lifetime=120