Skip to content

Commit

Permalink
enhancements(project): Add project management functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
zZHorizonZz committed Jul 26, 2023
1 parent 45e1a46 commit af5cfff
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 18 deletions.
4 changes: 4 additions & 0 deletions server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
</dependencyManagement>
<dependencies>
<!-- Quarkus: -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.shiperist.entity.account;

import dev.shiperist.entity.project.ProjectEntity;
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import jakarta.persistence.*;
import lombok.Data;
Expand Down Expand Up @@ -40,6 +41,14 @@ public class UserEntity extends PanacheEntityBase {
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private Set<SessionEntity> sessions;

@ManyToMany
@JoinTable(
name = "project_user",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "project_id")
)
private Set<ProjectEntity> projects;

public UserEntity() {
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
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 = "Account")
@Table(name = "account", schema = "public")
@Entity(name = "Project")
@Table(name = "project", schema = "public")
@EqualsAndHashCode(callSuper = true)
public class ProjectEntity extends PanacheEntityBase {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;

@Column(name = "name")
@Column(name = "name", unique = true)
private String name;

@Column(name = "display_name")
Expand All @@ -26,4 +30,14 @@ public class ProjectEntity extends PanacheEntityBase {

@Column(name = "image")
private String image;

@Column(name = "status")
private String status;

@CreationTimestamp
@Column(name = "created_at", updatable = false)
private String createdAt;

@ManyToMany(mappedBy = "projects")
private Set<UserEntity> users;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.shiperist.mapper.project;

import dev.shiperist.entity.project.ProjectEntity;
import dev.shiperist.mapper.QuarkusMappingConfig;
import dev.shiperist.model.project.Project;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

import java.util.List;

@Mapper(config = QuarkusMappingConfig.class)
public interface ProjectMapper {

List<Project> toDomainList(List<ProjectEntity> entities);

Project toDomain(ProjectEntity entity);

@InheritInverseConfiguration(name = "toDomain")
ProjectEntity toEntity(Project domain);

void updateEntityFromDomain(Project domain, @MappingTarget ProjectEntity entity);

void updateDomainFromEntity(ProjectEntity entity, @MappingTarget Project domain);
}
10 changes: 10 additions & 0 deletions server/src/main/java/dev/shiperist/model/project/Project.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
package dev.shiperist.model.project;

import lombok.Data;

@Data
public class Project {
public Long id;
private String name;
private String displayName;
private String description;
private String image;
private String status;
private String createdAt;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.shiperist.repository;
package dev.shiperist.repository.account;

import dev.shiperist.entity.account.AccountEntity;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.shiperist.repository;
package dev.shiperist.repository.account;

import dev.shiperist.entity.account.SessionEntity;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.shiperist.repository;
package dev.shiperist.repository.account;

import dev.shiperist.entity.account.UserEntity;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.shiperist.repository.project;

import dev.shiperist.entity.project.ProjectEntity;
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 ProjectRepository implements PanacheRepositoryBase<ProjectEntity, Long> {

public Uni<ProjectEntity> findByName(String name) {
return find("name", name).firstResult();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package dev.shiperist.resource;

import dev.shiperist.model.account.User;
import dev.shiperist.service.AccountService;
import dev.shiperist.service.SessionService;
import dev.shiperist.service.UserService;
import dev.shiperist.service.account.AccountService;
import dev.shiperist.service.account.SessionService;
import dev.shiperist.service.account.UserService;
import io.smallrye.mutiny.Uni;
import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
Expand All @@ -17,7 +17,7 @@
@Path("/auth")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AuthService {
public class AuthResource {


@Inject
Expand Down
94 changes: 94 additions & 0 deletions server/src/main/java/dev/shiperist/resource/ProjectResource.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,98 @@
package dev.shiperist.resource;

import dev.shiperist.model.project.Project;
import dev.shiperist.service.project.ProjectService;
import io.smallrye.mutiny.Uni;
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.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
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 org.eclipse.microprofile.openapi.annotations.tags.Tag;

import java.util.List;

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

@Path("/projects")
@Tag(name = "Projects")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProjectResource {

@Inject
ProjectService projectService;

@PUT
@Path("createProject/{name}")
@Operation(summary = "Creates a new project")
@APIResponse(
responseCode = "200",
description = "The created project",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = Project.class, required = true))
)
@APIResponse(
responseCode = "400",
description = "The project already exists"
)
public Uni<Response> createProject(@PathParam("name") String name, @Context SecurityContext securityContext) {
return projectService.createProject(name, securityContext.getUserPrincipal().getName())
.onItem().ifNotNull().transform(project -> Response.ok(project).build())
.onItem().ifNull().continueWith(Response.status(Response.Status.BAD_REQUEST).build());

}

@GET
@Path("{id}")
@Operation(summary = "Returns a project by id")
@APIResponse(
responseCode = "200",
description = "The project",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = Project.class, required = true))
)
@APIResponse(
responseCode = "404",
description = "The project does not exist"
)
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());
}

@PATCH
@Path("{id}")
@Operation(summary = "Updates a project")
@APIResponse(
responseCode = "200",
description = "The project",
content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = Project.class, required = true))
)
@APIResponse(
responseCode = "404",
description = "The project does not exist"
)
public Uni<Response> updateProject(@PathParam("id") Long id, Project project) {
return projectService.updateProject(id, project.getDisplayName(), project.getDescription(), project.getImage())
.onItem().ifNotNull().transform(updated -> Response.ok(updated).build())
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND).build());
}

@GET
@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))
)
public Uni<List<Project>> listProjects() {
return projectService.listProjects();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package dev.shiperist.security;

import dev.shiperist.model.account.User;
import dev.shiperist.service.SessionService;
import dev.shiperist.service.UserService;
import dev.shiperist.service.account.SessionService;
import dev.shiperist.service.account.UserService;
import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.credential.TokenCredential;
import io.quarkus.security.identity.AuthenticationRequestContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package dev.shiperist.service;
package dev.shiperist.service.account;

import dev.shiperist.entity.account.AccountEntity;
import dev.shiperist.mapper.account.AccountMapper;
import dev.shiperist.model.account.Account;
import dev.shiperist.repository.AccountRepository;
import dev.shiperist.repository.account.AccountRepository;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package dev.shiperist.service;
package dev.shiperist.service.account;

import dev.shiperist.entity.account.SessionEntity;
import dev.shiperist.mapper.account.SessionMapper;
import dev.shiperist.model.account.Session;
import dev.shiperist.model.account.User;
import dev.shiperist.repository.SessionRepository;
import dev.shiperist.repository.account.SessionRepository;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package dev.shiperist.service;
package dev.shiperist.service.account;

import at.favre.lib.crypto.bcrypt.BCrypt;
import dev.shiperist.entity.account.UserEntity;
import dev.shiperist.mapper.account.UserMapper;
import dev.shiperist.model.account.User;
import dev.shiperist.repository.UserRepository;
import dev.shiperist.repository.account.UserRepository;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dev.shiperist.service.project;

import dev.shiperist.entity.account.UserEntity;
import dev.shiperist.entity.project.ProjectEntity;
import dev.shiperist.mapper.project.ProjectMapper;
import dev.shiperist.model.project.Project;
import dev.shiperist.repository.account.UserRepository;
import dev.shiperist.repository.project.ProjectRepository;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.util.List;
import java.util.Set;

@ApplicationScoped
public class ProjectService {

@Inject
ProjectRepository projectRepository;

@Inject
UserRepository userRepository;

@Inject
ProjectMapper projectMapper;


@WithTransaction
public Uni<Project> createProject(String name, String owner) {
return userRepository.findById(owner)
.map(user -> {
ProjectEntity projectEntity = new ProjectEntity();
projectEntity.setName(name);
projectEntity.getUsers().add(user);
return projectEntity;
})
.flatMap(projectRepository::persist)
.map(projectMapper::toDomain);
}

public Uni<Project> getProject(Long name) {
return projectRepository.findById(name).map(projectMapper::toDomain);
}

@WithTransaction
public Uni<Project> updateProject(Long id, String displayName, String description, String image) {
return projectRepository.findById(id)
.map(project -> {
project.setDisplayName(displayName);
project.setDescription(description);
project.setImage(image);
return project;
})
.map(projectMapper::toDomain);
}

public Uni<List<Project>> listProjects() {
return projectRepository.listAll().map(projectMapper::toDomainList);
}
}

0 comments on commit af5cfff

Please sign in to comment.