Skip to content

Commit

Permalink
enhancements(test): added test for projects and enhanced database models
Browse files Browse the repository at this point in the history
  • Loading branch information
zZHorizonZz committed Aug 1, 2023
1 parent e4797ad commit 1ae0aa9
Show file tree
Hide file tree
Showing 16 changed files with 200 additions and 96 deletions.
5 changes: 5 additions & 0 deletions server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security-jwt</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package dev.shiperist.entity.account;

import dev.shiperist.entity.project.ProjectEntity;
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Date;
import java.util.Set;

@Data
@Entity(name = "User")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package dev.shiperist.entity.project;

import dev.shiperist.entity.account.UserEntity;
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.CreationTimestamp;

import java.util.Set;

@Data
@Entity(name = "Project")
@Table(name = "project", schema = "public")
Expand Down Expand Up @@ -37,11 +34,4 @@ public class ProjectEntity extends PanacheEntityBase {
@CreationTimestamp
@Column(name = "created_at", updatable = false)
private String createdAt;

@Column(name = "members")
@OneToMany(mappedBy = "project", fetch = FetchType.EAGER)
private Set<ProjectMemberEntity> members;

@OneToMany(mappedBy = "project", fetch = FetchType.EAGER)
private Set<ProjectAppEntity> projectApps;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.shiperist.model.account;

import dev.shiperist.entity.account.UserEntity;
import lombok.Data;

@Data
Expand Down
3 changes: 0 additions & 3 deletions server/src/main/java/dev/shiperist/model/account/User.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package dev.shiperist.model.account;

import dev.shiperist.entity.account.AccountEntity;
import dev.shiperist.entity.account.RefreshTokenEntity;
import lombok.Data;

import java.util.Date;
import java.util.Set;

@Data
public class User {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.shiperist.model.request;

import lombok.Data;


@Data
public class ProjectRequest {
private String name;
private String displayName;
private String description;
private String image;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package dev.shiperist.model.request;

public class UserRequest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;

import java.util.List;

@WithSession
@ApplicationScoped
public class RefreshTokenRepository implements PanacheRepositoryBase<RefreshTokenEntity, Long> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
import dev.shiperist.entity.project.ProjectMemberEntity;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;

@WithSession
@ApplicationScoped
public class ProjectMemberRepository implements PanacheRepositoryBase<ProjectMemberEntity, Long> {

public Uni<Boolean> isMember(Long projectId, Long userId) {
return count("projectId = ?1 and userId = ?2", projectId, userId).map(count -> count > 0);
}
}
43 changes: 0 additions & 43 deletions server/src/main/java/dev/shiperist/resource/AuthResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,49 +145,6 @@ public Uni<Response> getToken(@FormParam("grant_type") String grantType,
};
}

@GET
@Authenticated
@Path("/user/{id}")
@Operation(summary = "Returns user information")
@APIResponse(
responseCode = "200",
description = "The user information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = User.class, required = true))
)
@APIResponse(
responseCode = "403",
description = "Forbidden"
)
public Uni<Response> getUser(@PathParam("id") Long id) {
if (id == null || !id.equals(Long.parseLong(sub))) {
return Uni.createFrom().item(Response.status(Response.Status.FORBIDDEN).build());
}
return userService.getUser(id)
.map(user -> Response.ok(user).build());
}

@PUT
@Authenticated
@Path("/user")
@Operation(summary = "Updates user information")
@APIResponse(
responseCode = "200",
description = "The updated user",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = User.class, required = true))
)
@APIResponse(
responseCode = "403",
description = "Forbidden"
)
public Uni<Response> updateUser(User user) {
if (user.getId() == null || !user.getId().equals(Long.parseLong(sub))) {
return Uni.createFrom().item(Response.status(Response.Status.FORBIDDEN).build());
}

return userService.updateUser(user)
.map(updatedUser -> Response.ok(updatedUser).build());
}

@HEAD
@Authenticated
@Path("/logout")
Expand Down
54 changes: 21 additions & 33 deletions server/src/main/java/dev/shiperist/resource/ProjectResource.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package dev.shiperist.resource;

import dev.shiperist.model.project.Project;
import dev.shiperist.model.request.ProjectRequest;
import dev.shiperist.service.project.ProjectMemberService;
import dev.shiperist.service.project.ProjectService;
import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.openapi.annotations.Operation;
Expand All @@ -25,6 +25,7 @@
import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON;

@RequestScoped
@Authenticated
@Path("/projects")
@Tag(name = "Projects")
@Produces(MediaType.APPLICATION_JSON)
Expand All @@ -34,36 +35,32 @@ public class ProjectResource {
@Inject
ProjectService projectService;

@Inject
ProjectMemberService projectMemberService;

@Inject
@Claim(standard = Claims.sub)
String sub;

@PUT
@Authenticated
@Path("createProject/{name}")
@Operation(summary = "Creates a new project")
@APIResponse(
responseCode = "200",
responseCode = "201",
description = "The created project",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = Project.class, required = true))
)
@APIResponse(
responseCode = "400",
description = "The project already exists"
)
@APIResponse(
responseCode = "401",
description = "The user is not authenticated"
)
public Uni<Response> createProject(@PathParam("name") String name) {
return projectService.createProject(name, Long.parseLong(sub))
.onItem().ifNotNull().transform(project -> Response.ok(project).build())
public Uni<Response> createProject(ProjectRequest request) {
return projectService.createProject(Long.parseLong(sub), request.getName(), request.getDisplayName(), request.getDescription(), request.getImage())
.onItem().ifNotNull().transform(project -> Response.status(Response.Status.CREATED).entity(project).build())
.onItem().ifNull().continueWith(Response.status(Response.Status.BAD_REQUEST).build());

}

@GET
@Authenticated
@Path("{id}")
@Operation(summary = "Returns a project by id")
@APIResponse(
Expand All @@ -75,18 +72,18 @@ public Uni<Response> createProject(@PathParam("name") String name) {
responseCode = "404",
description = "The project does not exist"
)
@APIResponse(
responseCode = "401",
description = "The user is not authenticated"
)
public Uni<Response> getProject(@PathParam("id") Long id, @Context SecurityContext securityContext) {
return projectService.getProject(id)
.onItem().ifNotNull().transform(project -> Response.ok(project).build())
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND).build());
public Uni<Response> getProject(@PathParam("id") Long id) {
return projectMemberService.isMember(id, Long.parseLong(sub))
.flatMap(isMember -> {
if (isMember) {
return projectService.getProject(id).map(project -> project != null ? Response.ok(project).build() : Response.status(Response.Status.NOT_FOUND).build());
} else {
return Uni.createFrom().item(Response.status(Response.Status.NOT_FOUND).build());
}
});
}

@PATCH
@Authenticated
@Path("{id}")
@Operation(summary = "Updates a project")
@APIResponse(
Expand All @@ -98,29 +95,20 @@ public Uni<Response> getProject(@PathParam("id") Long id, @Context SecurityConte
responseCode = "404",
description = "The project does not exist"
)
@APIResponse(
responseCode = "401",
description = "The user is not authenticated"
)
public Uni<Response> updateProject(@PathParam("id") Long id, Project project) {
return projectService.updateProject(id, project.getDisplayName(), project.getDescription(), project.getImage())
public Uni<Response> updateProject(@PathParam("id") Long id, ProjectRequest request) {
return projectService.updateProject(id, request.getDisplayName(), request.getDescription(), request.getImage())
.onItem().ifNotNull().transform(updated -> Response.ok(updated).build())
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND).build());
}

@GET
@Authenticated
@Path("list")
@Operation(summary = "Returns all projects")
@APIResponse(
responseCode = "200",
description = "All projects",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = Project.class, type = SchemaType.ARRAY))
)
@APIResponse(
responseCode = "401",
description = "The user is not authenticated"
)
public Uni<List<Project>> listProjects() {
return projectService.listProjects();
}
Expand Down
76 changes: 76 additions & 0 deletions server/src/main/java/dev/shiperist/resource/UserResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package dev.shiperist.resource;

import dev.shiperist.model.account.User;
import dev.shiperist.service.account.UserService;
import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;

import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON;

@RequestScoped
@Path("/user")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {

@Inject
UserService userService;

@Inject
@Claim(standard = Claims.sub)
String sub;

@GET
@Authenticated
@Path("{id}")
@Operation(summary = "Returns user information")
@APIResponse(
responseCode = "200",
description = "The user information",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = User.class, required = true))
)
@APIResponse(
responseCode = "403",
description = "Forbidden"
)
public Uni<Response> getUser(@PathParam("id") Long id) {
if (id == null || !id.equals(Long.parseLong(sub))) {
return Uni.createFrom().item(Response.status(Response.Status.FORBIDDEN).build());
}
return userService.getUser(id)
.map(user -> Response.ok(user).build());
}

@PATCH
@Authenticated
@Path("{id}")
@Operation(summary = "Updates user information")
@APIResponse(
responseCode = "200",
description = "The updated user",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = User.class, required = true))
)
@APIResponse(
responseCode = "403",
description = "Forbidden"
)
public Uni<Response> updateUser(@PathParam("id") Long id, User user) {
if (user.getId() == null || !id.equals(Long.parseLong(sub))) {
return Uni.createFrom().item(Response.status(Response.Status.FORBIDDEN).build());
}

return userService.updateUser(user)
.map(updatedUser -> Response.ok(updatedUser).build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.shiperist.service.project;

import dev.shiperist.repository.project.ProjectMemberRepository;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class ProjectMemberService {

@Inject
ProjectMemberRepository projectMemberRepository;

public Uni<Boolean> isMember(Long projectId, Long userId) {
return projectMemberRepository.isMember(projectId, userId);
}
}
Loading

0 comments on commit 1ae0aa9

Please sign in to comment.