Compare commits
16 Commits
5215bf8779
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a26b299f2 | |||
| 6b3585da5e | |||
| e7b6712ad3 | |||
| ca41aee64f | |||
| 2959c68bf3 | |||
| 8b2795d518 | |||
| 8ef605ea2d | |||
|
|
ee1820960e | ||
| 1b55d9ab29 | |||
| 9f5306545e | |||
| ab40e9a497 | |||
| 9ff4b21dd9 | |||
| 7f12034174 | |||
| df24350bd3 | |||
| 5368425c1d | |||
| 1033c96d65 |
9
.env.example
Normal file
9
.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
SPRING_PROFILES_ACTIVE=dev
|
||||
|
||||
APP_ALLOWED_ORIGINS='http://127.0.0.1:3000, http://localhost:3000'
|
||||
|
||||
DB_NAME=EXAMPLE_DB
|
||||
DB_USER=EXAMPLE
|
||||
DB_PASSWORD=SECRET
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
.idea
|
||||
|
||||
target
|
||||
*.toml
|
||||
*.db
|
||||
target
|
||||
.env
|
||||
Icon?
|
||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
# Stage 1: Build
|
||||
FROM maven:3.9-eclipse-temurin-21-alpine AS build
|
||||
WORKDIR /app
|
||||
|
||||
# Copiamos todo el proyecto
|
||||
COPY . .
|
||||
|
||||
# Compilamos todo el proyecto (todos los módulos)
|
||||
RUN mvn clean package -DskipTests
|
||||
|
||||
# Stage 2: Run
|
||||
FROM openjdk:21-jdk
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/bootstrap/target/*.jar app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-Xmx512m", "-Xms256m", "-jar", "app.jar"]
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.pablotj.portfolio.application.certification;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.domain.certification.CertificationId;
|
||||
import com.pablotj.portfolio.domain.certification.port.CertificationRepositoryPort;
|
||||
|
||||
public class CreateCertificationUseCase {
|
||||
|
||||
CertificationRepositoryPort repository;
|
||||
|
||||
public CreateCertificationUseCase(CertificationRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Certification handle(Long profileId, Command cmd) {
|
||||
var certification = Certification.builder()
|
||||
.id(new CertificationId(profileId))
|
||||
.name(cmd.name())
|
||||
.issuer(cmd.issuer())
|
||||
.date(cmd.date())
|
||||
.credentialId(cmd.credentialId())
|
||||
.build();
|
||||
return repository.save(certification);
|
||||
}
|
||||
|
||||
public record Command(
|
||||
String name,
|
||||
String issuer,
|
||||
String date,
|
||||
String credentialId
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pablotj.portfolio.application.certification;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.domain.certification.CertificationId;
|
||||
import com.pablotj.portfolio.domain.certification.port.CertificationRepositoryPort;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetCertificationUseCase {
|
||||
|
||||
private final CertificationRepositoryPort repository;
|
||||
|
||||
public GetCertificationUseCase(CertificationRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<Certification> byId(Long profileId, Long id) {
|
||||
return repository.findById(new CertificationId(profileId, id));
|
||||
}
|
||||
|
||||
public List<Certification> all(Long profileId) {
|
||||
return repository.findAll(profileId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.pablotj.portfolio.application.education;
|
||||
|
||||
import com.pablotj.portfolio.domain.education.Education;
|
||||
import com.pablotj.portfolio.domain.education.EducationId;
|
||||
import com.pablotj.portfolio.domain.education.port.EducationRepositoryPort;
|
||||
|
||||
public class CreateEducationUseCase {
|
||||
|
||||
private final EducationRepositoryPort repository;
|
||||
|
||||
public CreateEducationUseCase(EducationRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Education handle(Long profileId, Command cmd) {
|
||||
var education = Education.builder()
|
||||
.id(new EducationId(profileId))
|
||||
.institution(cmd.institution())
|
||||
.degree(cmd.degree())
|
||||
.period(cmd.period())
|
||||
.grade(cmd.grade())
|
||||
.description(cmd.description())
|
||||
.build();
|
||||
return repository.save(education);
|
||||
}
|
||||
|
||||
public record Command(
|
||||
String institution,
|
||||
String degree,
|
||||
String period,
|
||||
String grade,
|
||||
String description
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pablotj.portfolio.application.education;
|
||||
|
||||
import com.pablotj.portfolio.domain.education.Education;
|
||||
import com.pablotj.portfolio.domain.education.EducationId;
|
||||
import com.pablotj.portfolio.domain.education.port.EducationRepositoryPort;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetEducationUseCase {
|
||||
|
||||
private final EducationRepositoryPort repository;
|
||||
|
||||
public GetEducationUseCase(EducationRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<Education> byId(Long profileId, Long id) {
|
||||
return repository.findById(new EducationId(profileId, id));
|
||||
}
|
||||
|
||||
public List<Education> all(Long profileId) {
|
||||
return repository.findAll(profileId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.pablotj.portfolio.application.experience;
|
||||
|
||||
import com.pablotj.portfolio.domain.experience.Achievement;
|
||||
import com.pablotj.portfolio.domain.experience.Experience;
|
||||
import com.pablotj.portfolio.domain.experience.ExperienceId;
|
||||
import com.pablotj.portfolio.domain.experience.Technology;
|
||||
import com.pablotj.portfolio.domain.experience.port.ExperienceRepositoryPort;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateExperienceUseCase {
|
||||
|
||||
private final ExperienceRepositoryPort repository;
|
||||
|
||||
public CreateExperienceUseCase(ExperienceRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Experience handle(Long profileId, Command cmd) {
|
||||
var experience = Experience.builder()
|
||||
.id(new ExperienceId(profileId))
|
||||
.company(cmd.company())
|
||||
.position(cmd.position())
|
||||
.period(cmd.period())
|
||||
.location(cmd.location())
|
||||
.description(cmd.description())
|
||||
.technologies(new ArrayList<>())
|
||||
.achievements(new ArrayList<>())
|
||||
.build();
|
||||
cmd.technologies.forEach(name -> experience.getTechnologies().add(Technology.builder().id(null).name(name).build()));
|
||||
cmd.achievements.forEach(description -> experience.getAchievements().add(Achievement.builder().id(null).description(description).build()));
|
||||
return repository.save(experience);
|
||||
}
|
||||
|
||||
public record Command(
|
||||
String position,
|
||||
String company,
|
||||
String period,
|
||||
String location,
|
||||
String description,
|
||||
List<String> technologies,
|
||||
List<String> achievements
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pablotj.portfolio.application.experience;
|
||||
|
||||
import com.pablotj.portfolio.domain.experience.Experience;
|
||||
import com.pablotj.portfolio.domain.experience.ExperienceId;
|
||||
import com.pablotj.portfolio.domain.experience.port.ExperienceRepositoryPort;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetExperienceUseCase {
|
||||
|
||||
private final ExperienceRepositoryPort repository;
|
||||
|
||||
public GetExperienceUseCase(ExperienceRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<Experience> byId(Long profileId, Long id) {
|
||||
return repository.findById(new ExperienceId(profileId, id));
|
||||
}
|
||||
|
||||
public List<Experience> all(Long profileId) {
|
||||
return repository.findAll(profileId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.pablotj.portfolio.application.profile;
|
||||
|
||||
import com.pablotj.portfolio.domain.profile.Profile;
|
||||
import com.pablotj.portfolio.domain.profile.ProfileSocialLink;
|
||||
import com.pablotj.portfolio.domain.profile.port.ProfileRepositoryPort;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateProfileUseCase {
|
||||
|
||||
private final ProfileRepositoryPort repository;
|
||||
|
||||
public CreateProfileUseCase(ProfileRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Profile handle(Command cmd) {
|
||||
var personalBuilder = Profile.builder()
|
||||
.id(null)
|
||||
.slug(cmd.slug())
|
||||
.name(cmd.name())
|
||||
.title(cmd.title())
|
||||
.subtitle(cmd.subtitle())
|
||||
.email(cmd.email())
|
||||
.phone(cmd.phone())
|
||||
.location(cmd.location())
|
||||
.avatar(cmd.avatar())
|
||||
.bio(cmd.bio());
|
||||
if (cmd.socialLinks != null) {
|
||||
cmd.socialLinks.forEach(l -> personalBuilder.social(ProfileSocialLink.builder().id(null).platform(l.platform()).url(l.url()).build()));
|
||||
}
|
||||
return repository.save(personalBuilder.build());
|
||||
}
|
||||
|
||||
public record Command(
|
||||
String slug,
|
||||
String name,
|
||||
String title,
|
||||
String subtitle,
|
||||
String email,
|
||||
String phone,
|
||||
String location,
|
||||
String avatar,
|
||||
String bio,
|
||||
List<Link> socialLinks
|
||||
) {
|
||||
}
|
||||
|
||||
public record Link(String platform, String url) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.pablotj.portfolio.application.profile;
|
||||
|
||||
import com.pablotj.portfolio.domain.profile.Profile;
|
||||
import com.pablotj.portfolio.domain.profile.ProfileId;
|
||||
import com.pablotj.portfolio.domain.profile.port.ProfileRepositoryPort;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetProfileUseCase {
|
||||
|
||||
private final ProfileRepositoryPort repository;
|
||||
|
||||
public GetProfileUseCase(ProfileRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<Profile> byId(Long id) {
|
||||
return repository.findById(new ProfileId(id));
|
||||
}
|
||||
|
||||
public Optional<Profile> bySlug(String slug) {
|
||||
return repository.findBySlug(new ProfileId(slug));
|
||||
}
|
||||
|
||||
public List<Profile> all() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,25 +1,44 @@
|
||||
package com.pablotj.portfolio.application.project;
|
||||
|
||||
import com.pablotj.portfolio.domain.project.Project;
|
||||
import com.pablotj.portfolio.domain.project.ProjectFeature;
|
||||
import com.pablotj.portfolio.domain.project.ProjectId;
|
||||
import com.pablotj.portfolio.domain.project.ProjectTechnology;
|
||||
import com.pablotj.portfolio.domain.project.port.ProjectRepositoryPort;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateProjectUseCase {
|
||||
|
||||
private final ProjectRepositoryPort repository;
|
||||
|
||||
public record Command(String title, String description, String url) {}
|
||||
|
||||
public CreateProjectUseCase(ProjectRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Project handle(Command cmd) {
|
||||
public Project handle(Long profileId, Command cmd) {
|
||||
var project = Project.builder()
|
||||
.id(null)
|
||||
.id(new ProjectId(profileId))
|
||||
.title(cmd.title())
|
||||
.description(cmd.description())
|
||||
.url(cmd.url())
|
||||
.image(cmd.image())
|
||||
.technologies(new ArrayList<>())
|
||||
.features(new ArrayList<>())
|
||||
.demo(cmd.demo())
|
||||
.repository(cmd.repository())
|
||||
|
||||
.build();
|
||||
cmd.technologies.forEach(name -> project.getTechnologies().add(ProjectTechnology.builder().id(null).name(name).build()));
|
||||
cmd.features.forEach(description -> project.getFeatures().add(ProjectFeature.builder().id(null).name(description).build()));
|
||||
return repository.save(project);
|
||||
}
|
||||
|
||||
public record Command(String title,
|
||||
String description,
|
||||
String image,
|
||||
List<String> technologies,
|
||||
List<String> features,
|
||||
String demo,
|
||||
String repository) {
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@ public class GetProjectUseCase {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<Project> byId(Long id) {
|
||||
return repository.findById(new ProjectId(id));
|
||||
public Optional<Project> byId(Long profileId, Long id) {
|
||||
return repository.findById(new ProjectId(profileId, id));
|
||||
}
|
||||
|
||||
public List<Project> all() {
|
||||
return repository.findAll();
|
||||
public List<Project> all(Long profileId) {
|
||||
return repository.findAll(profileId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.pablotj.portfolio.application.skill;
|
||||
|
||||
import com.pablotj.portfolio.domain.skill.Skill;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroup;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroupId;
|
||||
import com.pablotj.portfolio.domain.skill.port.SkillRepositoryPort;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateSkillUseCase {
|
||||
|
||||
private final SkillRepositoryPort repository;
|
||||
|
||||
public CreateSkillUseCase(SkillRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public SkillGroup handle(Long profileId, CommandGroup cmd) {
|
||||
var skillGroup = SkillGroup.builder()
|
||||
.id(new SkillGroupId(profileId))
|
||||
.name(cmd.name())
|
||||
.icon(cmd.icon())
|
||||
.skills(new ArrayList<>())
|
||||
.build();
|
||||
cmd.skills.forEach(s -> skillGroup.getSkills().add(
|
||||
Skill.builder().id(null).name(s.name).level(s.level).years(s.years).build()));
|
||||
return repository.save(skillGroup);
|
||||
}
|
||||
|
||||
public record CommandGroup(
|
||||
String name,
|
||||
String icon,
|
||||
List<CommandSkill> skills
|
||||
) {
|
||||
}
|
||||
|
||||
public record CommandSkill(
|
||||
String name,
|
||||
Integer level,
|
||||
Integer years
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pablotj.portfolio.application.skill;
|
||||
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroup;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroupId;
|
||||
import com.pablotj.portfolio.domain.skill.port.SkillRepositoryPort;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetSkillUseCase {
|
||||
|
||||
private final SkillRepositoryPort repository;
|
||||
|
||||
public GetSkillUseCase(SkillRepositoryPort repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Optional<SkillGroup> byId(Long profileId, Long id) {
|
||||
return repository.findById(new SkillGroupId(profileId, id));
|
||||
}
|
||||
|
||||
public List<SkillGroup> all(Long profileId) {
|
||||
return repository.findAll(profileId);
|
||||
}
|
||||
}
|
||||
@@ -51,4 +51,20 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "com.pablotj")
|
||||
@EnableJpaRepositories(basePackages = "com.pablotj.portfolio.infrastructure.persistence.repo")
|
||||
@EntityScan(basePackages = "com.pablotj.portfolio.infrastructure.persistence.entity")
|
||||
@EnableJpaRepositories(basePackages = {"com.pablotj.portfolio.infrastructure.persistence.*.repo"})
|
||||
@EntityScan(basePackages = {"com.pablotj.portfolio.infrastructure.persistence.*.entity"})
|
||||
public class PortfolioApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.pablotj.portfolio.bootstrap.certification;
|
||||
|
||||
import com.pablotj.portfolio.application.certification.CreateCertificationUseCase;
|
||||
import com.pablotj.portfolio.application.certification.GetCertificationUseCase;
|
||||
import com.pablotj.portfolio.domain.certification.port.CertificationRepositoryPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class CertificationApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public GetCertificationUseCase getCertificationUseCase(CertificationRepositoryPort repo) {
|
||||
return new GetCertificationUseCase(repo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateCertificationUseCase createCertificationUseCase(CertificationRepositoryPort repo) {
|
||||
return new CreateCertificationUseCase(repo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.pablotj.portfolio.bootstrap.education;
|
||||
|
||||
import com.pablotj.portfolio.application.education.CreateEducationUseCase;
|
||||
import com.pablotj.portfolio.application.education.GetEducationUseCase;
|
||||
import com.pablotj.portfolio.domain.education.port.EducationRepositoryPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class EducationApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public GetEducationUseCase getEducationUseCase(EducationRepositoryPort repo) {
|
||||
return new GetEducationUseCase(repo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateEducationUseCase createEducationUseCase(EducationRepositoryPort repo) {
|
||||
return new CreateEducationUseCase(repo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.pablotj.portfolio.bootstrap.experience;
|
||||
|
||||
import com.pablotj.portfolio.application.experience.CreateExperienceUseCase;
|
||||
import com.pablotj.portfolio.application.experience.GetExperienceUseCase;
|
||||
import com.pablotj.portfolio.domain.experience.port.ExperienceRepositoryPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ExperienceApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public GetExperienceUseCase getExperienceUseCase(ExperienceRepositoryPort repo) {
|
||||
return new GetExperienceUseCase(repo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateExperienceUseCase createExperienceUseCase(ExperienceRepositoryPort repo) {
|
||||
return new CreateExperienceUseCase(repo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.pablotj.portfolio.bootstrap.profile;
|
||||
|
||||
import com.pablotj.portfolio.application.profile.CreateProfileUseCase;
|
||||
import com.pablotj.portfolio.application.profile.GetProfileUseCase;
|
||||
import com.pablotj.portfolio.domain.profile.port.ProfileRepositoryPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ProfileApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public GetProfileUseCase getHomeUseCase(ProfileRepositoryPort repo) {
|
||||
return new GetProfileUseCase(repo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateProfileUseCase createHomeUseCase(ProfileRepositoryPort repo) {
|
||||
return new CreateProfileUseCase(repo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.pablotj.portfolio.bootstrap.skill;
|
||||
|
||||
import com.pablotj.portfolio.application.skill.CreateSkillUseCase;
|
||||
import com.pablotj.portfolio.application.skill.GetSkillUseCase;
|
||||
import com.pablotj.portfolio.domain.skill.port.SkillRepositoryPort;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SkillApplicationConfig {
|
||||
|
||||
@Bean
|
||||
public GetSkillUseCase getSkillUseCase(SkillRepositoryPort repo) {
|
||||
return new GetSkillUseCase(repo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateSkillUseCase createSkillUseCase(SkillRepositoryPort repo) {
|
||||
return new CreateSkillUseCase(repo);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,54 @@
|
||||
info:
|
||||
app:
|
||||
version: @project.version@
|
||||
app:
|
||||
cors:
|
||||
allowed-origins: ${APP_ALLOWED_ORIGINS:http://localhost:8080}
|
||||
spring:
|
||||
application:
|
||||
name: portfolio-api
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
properties:
|
||||
hibernate.transaction.jta.platform: org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform
|
||||
hibernate:
|
||||
format_sql: true
|
||||
show-sql: true
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
---
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: default
|
||||
|
||||
datasource:
|
||||
url: jdbc:h2:mem:portfolio_db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
username: sa
|
||||
password:
|
||||
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
|
||||
---
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
web:
|
||||
resources:
|
||||
add-mappings: false
|
||||
|
||||
datasource:
|
||||
url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:portfolio}
|
||||
username: ${DB_USER:postgres}
|
||||
password: ${DB_PASSWORD:postgres}
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 3
|
||||
minimum-idle: 1
|
||||
idle-timeout: 30000
|
||||
connection-timeout: 10000
|
||||
leak-detection-threshold: 10000
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: validate
|
||||
ddl-auto: validate
|
||||
properties:
|
||||
hibernate.transaction.jta.platform: org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform
|
||||
hibernate:
|
||||
format_sql: true
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
show-sql: true
|
||||
|
||||
jackson:
|
||||
serialization:
|
||||
INDENT_OUTPUT: true
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
path: /v3/api-docs
|
||||
swagger-ui:
|
||||
path: /swagger-ui
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
context-path: /api
|
||||
forward-headers-strategy: framework
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
38
docker-compose.yml
Normal file
38
docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
networks:
|
||||
network:
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
|
||||
api:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8095:8080"
|
||||
networks:
|
||||
network:
|
||||
environment:
|
||||
DB_NAME: ${DB_NAME}
|
||||
DB_HOST: ${DB_HOST}
|
||||
DB_PORT: ${DB_PORT}
|
||||
DB_USER: ${DB_USER}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
APP_ALLOWED_ORIGINS: ${APP_ALLOWED_ORIGINS}
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
networks:
|
||||
network:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.domain.certification;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Certification {
|
||||
private final CertificationId id;
|
||||
private final String name;
|
||||
private final String issuer;
|
||||
private final String date;
|
||||
private final String credentialId;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.certification;
|
||||
|
||||
public record CertificationId(Long profileId, Long certificationId) {
|
||||
|
||||
public CertificationId(Long profileId) {
|
||||
this(profileId, null);
|
||||
}
|
||||
|
||||
public CertificationId {
|
||||
if (certificationId != null && certificationId < 0) throw new IllegalArgumentException("CertificationId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.domain.certification.port;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.domain.certification.CertificationId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CertificationRepositoryPort {
|
||||
Certification save(Certification p);
|
||||
|
||||
Optional<Certification> findById(CertificationId id);
|
||||
|
||||
List<Certification> findAll(Long profileId);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.pablotj.portfolio.domain.education;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Education {
|
||||
private final EducationId id;
|
||||
private final String institution;
|
||||
private final String degree;
|
||||
private final String period;
|
||||
private final String grade;
|
||||
private final String description;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pablotj.portfolio.domain.education;
|
||||
|
||||
public record EducationId(Long profileId, Long educationId) {
|
||||
public EducationId(Long profileId) {
|
||||
this(profileId, null);
|
||||
}
|
||||
|
||||
public EducationId {
|
||||
if (educationId != null && educationId < 0) throw new IllegalArgumentException("EducationId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.domain.education.port;
|
||||
|
||||
import com.pablotj.portfolio.domain.education.Education;
|
||||
import com.pablotj.portfolio.domain.education.EducationId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface EducationRepositoryPort {
|
||||
Education save(Education p);
|
||||
|
||||
Optional<Education> findById(EducationId id);
|
||||
|
||||
List<Education> findAll(Long profileId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Achievement {
|
||||
private final ArchivementId id;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
public record ArchivementId(Long value) {
|
||||
public ArchivementId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("ArchivementId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Experience {
|
||||
private final ExperienceId id;
|
||||
private final String company;
|
||||
private final String position;
|
||||
private final String period;
|
||||
private final String location;
|
||||
private final String description;
|
||||
private final List<Technology> technologies;
|
||||
private final List<Achievement> achievements;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
public record ExperienceId(Long profileId, Long experienceId) {
|
||||
|
||||
public ExperienceId(Long profileId) {
|
||||
this(profileId, null);
|
||||
}
|
||||
|
||||
public ExperienceId {
|
||||
if (experienceId != null && experienceId < 0) throw new IllegalArgumentException("ProfileSocialLinkId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Technology {
|
||||
private final TechnologyId id;
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.experience;
|
||||
|
||||
public record TechnologyId(Long value) {
|
||||
public TechnologyId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("TechnologyId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.pablotj.portfolio.domain.experience.port;
|
||||
|
||||
import com.pablotj.portfolio.domain.experience.Experience;
|
||||
import com.pablotj.portfolio.domain.experience.ExperienceId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ExperienceRepositoryPort {
|
||||
Experience save(Experience p);
|
||||
|
||||
Optional<Experience> findById(ExperienceId id);
|
||||
|
||||
List<Experience> findAll(Long profileId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.pablotj.portfolio.domain.profile;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Singular;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Profile {
|
||||
private final ProfileId id;
|
||||
private final String slug;
|
||||
private final String name;
|
||||
private final String title;
|
||||
private final String subtitle;
|
||||
private final String email;
|
||||
private final String phone;
|
||||
private final String location;
|
||||
private final String avatar;
|
||||
private final String bio;
|
||||
@Singular("social")
|
||||
private final List<ProfileSocialLink> social;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.pablotj.portfolio.domain.profile;
|
||||
|
||||
public record ProfileId(Long id, String slug) {
|
||||
|
||||
public ProfileId(Long id) {
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
public ProfileId(String slug) {
|
||||
this(null, slug);
|
||||
}
|
||||
|
||||
public ProfileId {
|
||||
if (id != null && id < 0) throw new IllegalArgumentException("ProfileId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.profile;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ProfileSocialLink {
|
||||
private final ProfileSocialLinkId id;
|
||||
private final String url;
|
||||
private final String platform;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.profile;
|
||||
|
||||
public record ProfileSocialLinkId(Long value) {
|
||||
public ProfileSocialLinkId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("ProfileSocialLinkId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.pablotj.portfolio.domain.profile.port;
|
||||
|
||||
import com.pablotj.portfolio.domain.profile.Profile;
|
||||
import com.pablotj.portfolio.domain.profile.ProfileId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProfileRepositoryPort {
|
||||
Profile save(Profile p);
|
||||
|
||||
Optional<Profile> findBySlug(ProfileId id);
|
||||
|
||||
Optional<Profile> findById(ProfileId id);
|
||||
|
||||
List<Profile> findAll();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -9,5 +10,9 @@ public class Project {
|
||||
private final ProjectId id;
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final String url;
|
||||
private final String image;
|
||||
private final List<ProjectTechnology> technologies;
|
||||
private final List<ProjectFeature> features;
|
||||
private final String demo;
|
||||
private final String repository;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ProjectFeature {
|
||||
private final ProjectFeatureId id;
|
||||
private final String name;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
public record ProjectFeatureId(Long value) {
|
||||
public ProjectFeatureId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("ProjectFeatureId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
public record ProjectId(Long value) {
|
||||
public record ProjectId(Long profileId, Long projectId) {
|
||||
|
||||
public ProjectId(Long profileId) {
|
||||
this(profileId, null);
|
||||
}
|
||||
|
||||
public ProjectId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("ProjectId must be positive");
|
||||
if (projectId != null && projectId < 0) throw new IllegalArgumentException("ProjectId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ProjectTechnology {
|
||||
private final ProjectTechnologyId id;
|
||||
private final String name;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.project;
|
||||
|
||||
public record ProjectTechnologyId(Long value) {
|
||||
public ProjectTechnologyId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("ProjectTechnologyId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,5 @@ import java.util.Optional;
|
||||
public interface ProjectRepositoryPort {
|
||||
Project save(Project p);
|
||||
Optional<Project> findById(ProjectId id);
|
||||
List<Project> findAll();
|
||||
List<Project> findAll(Long profileId);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.domain.skill;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Skill {
|
||||
private final SkillId id;
|
||||
private final String name;
|
||||
private final Integer level;
|
||||
private final Integer years;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.domain.skill;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class SkillGroup {
|
||||
private final SkillGroupId id;
|
||||
private final String name;
|
||||
private final String icon;
|
||||
private final List<Skill> skills;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pablotj.portfolio.domain.skill;
|
||||
|
||||
public record SkillGroupId(Long profileId, Long skillGroupId) {
|
||||
|
||||
public SkillGroupId(Long profileId) {
|
||||
this(profileId, null);
|
||||
}
|
||||
|
||||
public SkillGroupId {
|
||||
if (skillGroupId != null && skillGroupId < 0) throw new IllegalArgumentException("SkillId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.pablotj.portfolio.domain.skill;
|
||||
|
||||
public record SkillId(Long value) {
|
||||
public SkillId {
|
||||
if (value != null && value < 0) throw new IllegalArgumentException("SkillId must be positive");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.domain.skill.port;
|
||||
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroup;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroupId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SkillRepositoryPort {
|
||||
SkillGroup save(SkillGroup p);
|
||||
|
||||
Optional<SkillGroup> findById(SkillGroupId id);
|
||||
|
||||
List<SkillGroup> findAll(Long profileId);
|
||||
}
|
||||
@@ -33,6 +33,11 @@
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MapStruct -->
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.pablotj.portfolio.infrastructure.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
@Value("${app.cors.allowed-origins}")
|
||||
private String allowedOriginsString;
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
|
||||
List<String> allowedOrigins = Arrays.asList(allowedOriginsString.split(","));
|
||||
config.setAllowedOriginPatterns(allowedOrigins);
|
||||
|
||||
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
config.setAllowedHeaders(List.of("*"));
|
||||
config.setAllowCredentials(true);
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.pablotj.portfolio.infrastructure.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
private final CorsConfigurationSource corsConfigurationSource;
|
||||
|
||||
public SecurityConfig(CorsConfigurationSource corsConfigurationSource) {
|
||||
this.corsConfigurationSource = corsConfigurationSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.anyRequest().permitAll()
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.certification.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.domain.certification.CertificationId;
|
||||
import com.pablotj.portfolio.domain.certification.port.CertificationRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.entity.CertificationJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.mapper.CertificationJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.repo.SpringDataCertificationRepository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class CertificationRepositoryAdapter implements CertificationRepositoryPort {
|
||||
|
||||
private final SpringDataCertificationRepository repo;
|
||||
private final CertificationJpaMapper mapper;
|
||||
|
||||
public CertificationRepositoryAdapter(SpringDataCertificationRepository repo, CertificationJpaMapper mapper) {
|
||||
this.repo = repo;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certification save(Certification p) {
|
||||
CertificationJpaEntity entity = mapper.toEntity(p);
|
||||
CertificationJpaEntity saved = repo.save(entity);
|
||||
return mapper.toDomain(saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Certification> findById(CertificationId id) {
|
||||
return repo.findByProfileIdAndId(id.profileId(), id.certificationId()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Certification> findAll(Long profileId) {
|
||||
return repo.findAllByProfileId(profileId).stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.certification.entity;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "CERTIFICATION")
|
||||
@Getter
|
||||
@Setter
|
||||
public class CertificationJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String issuer;
|
||||
|
||||
@Column
|
||||
private String date;
|
||||
|
||||
@Column
|
||||
private String credentialId;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.certification.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.domain.certification.CertificationId;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.entity.CertificationJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface CertificationJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "profile.id", source = "id.profileId")
|
||||
CertificationJpaEntity toEntity(Certification domain);
|
||||
|
||||
@Mapping(target = "id", expression = "java(new CertificationId(e.getProfile().getId(), e.getId()))")
|
||||
Certification toDomain(CertificationJpaEntity e);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.certification.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.entity.CertificationJpaEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataCertificationRepository extends JpaRepository<CertificationJpaEntity, Long> {
|
||||
|
||||
Optional<CertificationJpaEntity> findByProfileIdAndId(Long profileId, Long id);
|
||||
|
||||
List<CertificationJpaEntity> findAllByProfileId(Long profileId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.education.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.education.Education;
|
||||
import com.pablotj.portfolio.domain.education.EducationId;
|
||||
import com.pablotj.portfolio.domain.education.port.EducationRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.entity.EducationJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.mapper.EducationJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.repo.SpringDataEducationRepository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class EducationRepositoryAdapter implements EducationRepositoryPort {
|
||||
|
||||
private final SpringDataEducationRepository repo;
|
||||
private final EducationJpaMapper mapper;
|
||||
|
||||
public EducationRepositoryAdapter(SpringDataEducationRepository repo, EducationJpaMapper mapper) {
|
||||
this.repo = repo;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Education save(Education p) {
|
||||
EducationJpaEntity entity = mapper.toEntity(p);
|
||||
EducationJpaEntity saved = repo.save(entity);
|
||||
return mapper.toDomain(saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Education> findById(EducationId id) {
|
||||
return repo.findByProfileIdAndId(id.profileId(), id.educationId()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Education> findAll(Long profileId) {
|
||||
return repo.findAllByProfileId(profileId).stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.education.entity;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "EDUCATION")
|
||||
@Getter
|
||||
@Setter
|
||||
public class EducationJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String institution;
|
||||
|
||||
@Column
|
||||
private String degree;
|
||||
|
||||
@Column
|
||||
private String period;
|
||||
|
||||
@Column
|
||||
private String grade;
|
||||
|
||||
@Column(columnDefinition = "text")
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.education.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.education.Education;
|
||||
import com.pablotj.portfolio.domain.education.EducationId;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.entity.EducationJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface EducationJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "profile.id", source = "id.profileId")
|
||||
EducationJpaEntity toEntity(Education domain);
|
||||
|
||||
@Mapping(target = "id", expression = "java(new EducationId(e.getProfile().getId(), e.getId()))")
|
||||
Education toDomain(EducationJpaEntity e);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.education.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.certification.entity.CertificationJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.entity.EducationJpaEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataEducationRepository extends JpaRepository<EducationJpaEntity, Long> {
|
||||
Optional<EducationJpaEntity> findByProfileIdAndId(Long profileId, Long id);
|
||||
|
||||
List<EducationJpaEntity> findAllByProfileId(Long profileId);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "projects")
|
||||
@Getter @Setter
|
||||
public class ProjectJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(columnDefinition = "text")
|
||||
private String description;
|
||||
|
||||
private String url;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.experience.Experience;
|
||||
import com.pablotj.portfolio.domain.experience.ExperienceId;
|
||||
import com.pablotj.portfolio.domain.experience.port.ExperienceRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.mapper.ExperienceJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.repo.SpringDataExperienceRepository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class ExperienceRepositoryAdapter implements ExperienceRepositoryPort {
|
||||
|
||||
private final SpringDataExperienceRepository repo;
|
||||
private final ExperienceJpaMapper mapper;
|
||||
|
||||
public ExperienceRepositoryAdapter(SpringDataExperienceRepository repo, ExperienceJpaMapper mapper) {
|
||||
this.repo = repo;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Experience save(Experience p) {
|
||||
ExperienceJpaEntity entity = mapper.toEntity(p);
|
||||
ExperienceJpaEntity saved = repo.save(entity);
|
||||
return mapper.toDomain(saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Experience> findById(ExperienceId id) {
|
||||
return repo.findByProfileIdAndId(id.profileId(), id.experienceId()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Experience> findAll(Long profileId) {
|
||||
return repo.findAllByProfileId(profileId).stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "EXPERIENCE_ACHIEVEMENT")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Builder
|
||||
public class ExperienceAchievementJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(columnDefinition = "text")
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.entity;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "EXPERIENCE")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Builder
|
||||
public class ExperienceJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String position;
|
||||
|
||||
@Column
|
||||
private String company;
|
||||
|
||||
@Column
|
||||
private String period;
|
||||
|
||||
@Column
|
||||
private String location;
|
||||
|
||||
@Column(columnDefinition = "text")
|
||||
private String description;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "EXPERIENCE_ID")
|
||||
private List<ExperienceSkillJpaEntity> technologies;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "EXPERIENCE_ID")
|
||||
private List<ExperienceAchievementJpaEntity> achievements;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "EXPERIENCE_SKILL")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Builder
|
||||
public class ExperienceSkillJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.experience.Achievement;
|
||||
import com.pablotj.portfolio.domain.experience.Experience;
|
||||
import com.pablotj.portfolio.domain.experience.Technology;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceAchievementJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceSkillJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface ExperienceJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "profile.id", source = "id.profileId")
|
||||
ExperienceJpaEntity toEntity(Experience domain);
|
||||
|
||||
@Mapping(target = "id", expression = "java(new ExperienceId(entity.getProfile().getId(), entity.getId()))")
|
||||
Experience toDomain(ExperienceJpaEntity entity);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ExperienceAchievementJpaEntity toEntity(Achievement entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
Achievement toDomain(ExperienceAchievementJpaEntity entity);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ExperienceSkillJpaEntity toEntity(Technology entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
Technology toDomain(ExperienceSkillJpaEntity entity);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.experience.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.education.entity.EducationJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceJpaEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataExperienceRepository extends JpaRepository<ExperienceJpaEntity, Long> {
|
||||
Optional<ExperienceJpaEntity> findByProfileIdAndId(Long profileId, Long id);
|
||||
|
||||
List<ExperienceJpaEntity> findAllByProfileId(Long profileId);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.project.Project;
|
||||
import com.pablotj.portfolio.domain.project.ProjectId;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.entity.ProjectJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface ProjectJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ProjectJpaEntity toEntity(Project domain);
|
||||
|
||||
default Project toDomain(ProjectJpaEntity e) {
|
||||
if (e == null) return null;
|
||||
return Project.builder()
|
||||
.id(e.getId() == null ? null : new ProjectId(e.getId()))
|
||||
.title(e.getTitle())
|
||||
.description(e.getDescription())
|
||||
.url(e.getUrl())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.profile.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.profile.Profile;
|
||||
import com.pablotj.portfolio.domain.profile.ProfileId;
|
||||
import com.pablotj.portfolio.domain.profile.port.ProfileRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileSocialLinkJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.mapper.ProfileJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.repo.SpringDataProfileRepository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class ProfileRepositoryAdapter implements ProfileRepositoryPort {
|
||||
|
||||
private final SpringDataProfileRepository repo;
|
||||
private final ProfileJpaMapper mapper;
|
||||
|
||||
public ProfileRepositoryAdapter(SpringDataProfileRepository repo, ProfileJpaMapper mapper) {
|
||||
this.repo = repo;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Profile save(Profile p) {
|
||||
ProfileJpaEntity entity = mapper.toEntity(p);
|
||||
if (entity.getSocial() != null) {
|
||||
for (ProfileSocialLinkJpaEntity socialLinkJpaEntity : entity.getSocial()) {
|
||||
socialLinkJpaEntity.setProfile(entity);
|
||||
}
|
||||
}
|
||||
ProfileJpaEntity saved = repo.save(entity);
|
||||
return mapper.toDomain(saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Profile> findBySlug(ProfileId id) {
|
||||
return repo.findBySlug(id.slug()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Profile> findById(ProfileId id) {
|
||||
return repo.findById(id.id()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Profile> findAll() {
|
||||
return repo.findAll().stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.profile.entity;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "profile")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProfileJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String slug;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String title;
|
||||
|
||||
@Column
|
||||
private String subtitle;
|
||||
|
||||
@Column
|
||||
private String email;
|
||||
|
||||
@Column
|
||||
private String phone;
|
||||
|
||||
@Column
|
||||
private String location;
|
||||
|
||||
@Column
|
||||
private String avatar;
|
||||
|
||||
@Column
|
||||
private String bio;
|
||||
|
||||
@OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<ProfileSocialLinkJpaEntity> social = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.profile.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "profile_social_link")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProfileSocialLinkJpaEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String url;
|
||||
|
||||
@Column
|
||||
private String platform;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.profile.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.profile.Profile;
|
||||
import com.pablotj.portfolio.domain.profile.ProfileSocialLink;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileSocialLinkJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface ProfileJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "social", source = "social")
|
||||
ProfileJpaEntity toEntity(Profile domain);
|
||||
|
||||
@Mapping(target = "id.id", source = "id")
|
||||
@Mapping(target = "social", source = "social")
|
||||
Profile toDomain(ProfileJpaEntity e);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ProfileSocialLinkJpaEntity toEntitySocial(ProfileSocialLink entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
ProfileSocialLink toDomainSocial(ProfileSocialLinkJpaEntity entity);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.profile.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataProfileRepository extends JpaRepository<ProfileJpaEntity, Long> {
|
||||
|
||||
Optional<ProfileJpaEntity> findBySlug(String slug);
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.adapter;
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.project.Project;
|
||||
import com.pablotj.portfolio.domain.project.ProjectId;
|
||||
import com.pablotj.portfolio.domain.project.port.ProjectRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.entity.ProjectJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.mapper.ProjectJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.repo.SpringDataProjectRepository;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.mapper.ProjectJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.repo.SpringDataProjectRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@@ -31,11 +31,11 @@ public class ProjectRepositoryAdapter implements ProjectRepositoryPort {
|
||||
|
||||
@Override
|
||||
public Optional<Project> findById(ProjectId id) {
|
||||
return repo.findById(id.value()).map(mapper::toDomain);
|
||||
return repo.findByProfileIdAndId(id.profileId(), id.projectId()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Project> findAll() {
|
||||
return repo.findAll().stream().map(mapper::toDomain).toList();
|
||||
public List<Project> findAll(Long profileId) {
|
||||
return repo.findAllByProfileId(profileId).stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PROJECT_FEATURE")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProjectFeatureJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.entity;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PROJECT")
|
||||
@Getter @Setter
|
||||
public class ProjectJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String title;
|
||||
|
||||
@Column
|
||||
private String description;
|
||||
|
||||
@Column
|
||||
private String image;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "PROJECT_ID")
|
||||
private List<ProjectTechnologyJpaEntity> technologies;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "PROJECT_ID")
|
||||
private List<ProjectFeatureJpaEntity> features;
|
||||
|
||||
@Column
|
||||
private String demo;
|
||||
|
||||
@Column
|
||||
private String repository;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PROJECT_FEATURE_TECHNOLOGY")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProjectTechnologyJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.project.Project;
|
||||
import com.pablotj.portfolio.domain.project.ProjectFeature;
|
||||
import com.pablotj.portfolio.domain.project.ProjectTechnology;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectFeatureJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectTechnologyJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface ProjectJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "profile.id", source = "id.profileId")
|
||||
ProjectJpaEntity toEntity(Project domain);
|
||||
|
||||
@Mapping(target = "id", expression = "java(new ProjectId(e.getProfile().getId(), e.getId()))")
|
||||
Project toDomain(ProjectJpaEntity e);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ProjectTechnologyJpaEntity toEntity(ProjectTechnology entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
ProjectTechnology toDomain(ProjectTechnologyJpaEntity entity);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
ProjectFeatureJpaEntity toEntity(ProjectFeature entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
ProjectFeature toDomain(ProjectFeatureJpaEntity entity);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.project.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.experience.entity.ExperienceJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectJpaEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataProjectRepository extends JpaRepository<ProjectJpaEntity, Long> {
|
||||
Optional<ProjectJpaEntity> findByProfileIdAndId(Long profileId, Long id);
|
||||
|
||||
List<ProjectJpaEntity> findAllByProfileId(Long profileId);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.entity.ProjectJpaEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataProjectRepository extends JpaRepository<ProjectJpaEntity, Long> {}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.skill.adapter;
|
||||
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroup;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroupId;
|
||||
import com.pablotj.portfolio.domain.skill.port.SkillRepositoryPort;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.entity.SkillGroupJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.mapper.SkillJpaMapper;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.repo.SpringDataSkillRepository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class SkillRepositoryAdapter implements SkillRepositoryPort {
|
||||
|
||||
private final SpringDataSkillRepository repo;
|
||||
private final SkillJpaMapper mapper;
|
||||
|
||||
public SkillRepositoryAdapter(SpringDataSkillRepository repo, SkillJpaMapper mapper) {
|
||||
this.repo = repo;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkillGroup save(SkillGroup p) {
|
||||
SkillGroupJpaEntity entity = mapper.toEntity(p);
|
||||
SkillGroupJpaEntity saved = repo.save(entity);
|
||||
return mapper.toDomain(saved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SkillGroup> findById(SkillGroupId id) {
|
||||
return repo.findByProfileIdAndId(id.profileId(), id.skillGroupId()).map(mapper::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SkillGroup> findAll(Long profileId) {
|
||||
return repo.findAllByProfileId(profileId).stream().map(mapper::toDomain).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.skill.entity;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.profile.entity.ProfileJpaEntity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "SKILL_GROUP")
|
||||
@Getter
|
||||
@Setter
|
||||
public class SkillGroupJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "profile_id", nullable = false)
|
||||
private ProfileJpaEntity profile;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String icon;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "SKILL_ID")
|
||||
private List<SkillJpaEntity> skills;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.skill.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "SKILL")
|
||||
@Getter
|
||||
@Setter
|
||||
public class SkillJpaEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private Integer level;
|
||||
|
||||
@Column
|
||||
private Integer years;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.skill.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.skill.Skill;
|
||||
import com.pablotj.portfolio.domain.skill.SkillGroup;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.entity.SkillGroupJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.entity.SkillJpaEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface SkillJpaMapper {
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "profile.id", source = "id.profileId")
|
||||
SkillGroupJpaEntity toEntity(SkillGroup domain);
|
||||
|
||||
@Mapping(target = "id", expression = "java(new SkillGroupId(entity.getProfile().getId(), entity.getId()))")
|
||||
SkillGroup toDomain(SkillGroupJpaEntity entity);
|
||||
|
||||
@Mapping(target = "id", ignore = true)
|
||||
SkillJpaEntity toEntity(Skill entity);
|
||||
|
||||
@Mapping(target = "id.value", source = "id")
|
||||
Skill toDomain(SkillJpaEntity entity);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.infrastructure.persistence.skill.repo;
|
||||
|
||||
import com.pablotj.portfolio.infrastructure.persistence.project.entity.ProjectJpaEntity;
|
||||
import com.pablotj.portfolio.infrastructure.persistence.skill.entity.SkillGroupJpaEntity;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SpringDataSkillRepository extends JpaRepository<SkillGroupJpaEntity, Long> {
|
||||
Optional<SkillGroupJpaEntity> findByProfileIdAndId(Long profileId, Long id);
|
||||
|
||||
List<SkillGroupJpaEntity> findAllByProfileId(Long profileId);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.api;
|
||||
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
public class ApiErrorController implements ErrorController {
|
||||
|
||||
private final ErrorAttributes errorAttributes;
|
||||
|
||||
public ApiErrorController(ErrorAttributes errorAttributes) {
|
||||
this.errorAttributes = errorAttributes;
|
||||
}
|
||||
|
||||
@RequestMapping("/error")
|
||||
public ResponseEntity<Map<String, Object>> handleError(WebRequest webRequest) {
|
||||
Map<String, Object> attributes = errorAttributes.getErrorAttributes(webRequest,
|
||||
ErrorAttributeOptions.defaults());
|
||||
HttpStatus status = HttpStatus.valueOf((int) attributes.getOrDefault("status", 500));
|
||||
return new ResponseEntity<>(attributes, status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class ApiRootController {
|
||||
|
||||
@Value("${info.app.version}")
|
||||
private String appVersion;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<Map<String, Object>> root() {
|
||||
Map<String, Object> response = Map.of(
|
||||
"api", "Portfolio API",
|
||||
"version", appVersion,
|
||||
"doc", "/v3/api-docs",
|
||||
"swagger", "/swagger-ui",
|
||||
"endpoints", List.of(
|
||||
Map.of("path", "/v1/homes", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/certifications", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/projects", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/contacts", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/educations", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/experiences", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/projects", "description", "Manage projects"),
|
||||
Map.of("path", "/v1/technologies", "description", "ProfileSocialLink entries")
|
||||
)
|
||||
);
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.certification;
|
||||
|
||||
import com.pablotj.portfolio.application.certification.CreateCertificationUseCase;
|
||||
import com.pablotj.portfolio.application.certification.GetCertificationUseCase;
|
||||
import com.pablotj.portfolio.infrastructure.rest.certification.dto.CertificationDto;
|
||||
import com.pablotj.portfolio.infrastructure.rest.certification.dto.CreateCertificationRequest;
|
||||
import com.pablotj.portfolio.infrastructure.rest.certification.mapper.CertificationRestMapper;
|
||||
import jakarta.validation.Valid;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v1/profiles/{profileId}/certifications")
|
||||
public class CertificationController {
|
||||
|
||||
private final CreateCertificationUseCase createUC;
|
||||
private final GetCertificationUseCase getUC;
|
||||
private final CertificationRestMapper mapper;
|
||||
|
||||
public CertificationController(CreateCertificationUseCase createUC, GetCertificationUseCase getUC, CertificationRestMapper mapper) {
|
||||
this.createUC = createUC;
|
||||
this.getUC = getUC;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CertificationDto> all(@PathVariable Long profileId) {
|
||||
return getUC.all(profileId).stream().map(mapper::toDto).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<CertificationDto> byId(@PathVariable Long profileId, @PathVariable Long id) {
|
||||
return getUC.byId(profileId, id)
|
||||
.map(mapper::toDto)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<CertificationDto> create(@PathVariable Long profileId, @Valid @RequestBody CreateCertificationRequest request) {
|
||||
var cmd = new CreateCertificationUseCase.Command(
|
||||
request.name(),
|
||||
request.issuer(),
|
||||
request.date(),
|
||||
request.credentialId()
|
||||
);
|
||||
var created = createUC.handle(profileId, cmd);
|
||||
var body = mapper.toDto(created);
|
||||
return ResponseEntity.created(URI.create("/api/certifications/" + body.id())).body(body);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.certification.dto;
|
||||
|
||||
public record CertificationDto(Long id,
|
||||
String name,
|
||||
String issuer,
|
||||
String date,
|
||||
String credentialId) {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.certification.dto;
|
||||
|
||||
public record CreateCertificationRequest(
|
||||
String name,
|
||||
String issuer,
|
||||
String date,
|
||||
String credentialId
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.certification.mapper;
|
||||
|
||||
import com.pablotj.portfolio.domain.certification.Certification;
|
||||
import com.pablotj.portfolio.infrastructure.rest.certification.dto.CertificationDto;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface CertificationRestMapper {
|
||||
|
||||
@Mapping(target = "id", source = "id.certificationId")
|
||||
CertificationDto toDto(Certification domain);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.controller;
|
||||
|
||||
import com.pablotj.portfolio.application.project.CreateProjectUseCase;
|
||||
import com.pablotj.portfolio.application.project.GetProjectUseCase;
|
||||
import com.pablotj.portfolio.infrastructure.rest.dto.CreateProjectRequest;
|
||||
import com.pablotj.portfolio.infrastructure.rest.dto.ProjectDto;
|
||||
import com.pablotj.portfolio.infrastructure.rest.mapper.ProjectRestMapper;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/projects")
|
||||
public class ProjectController {
|
||||
|
||||
private final CreateProjectUseCase createUC;
|
||||
private final GetProjectUseCase getUC;
|
||||
private final ProjectRestMapper mapper;
|
||||
|
||||
public ProjectController(CreateProjectUseCase createUC, GetProjectUseCase getUC, ProjectRestMapper mapper) {
|
||||
this.createUC = createUC;
|
||||
this.getUC = getUC;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<ProjectDto> all() {
|
||||
return getUC.all().stream().map(mapper::toDto).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ProjectDto> byId(@PathVariable Long id) {
|
||||
return getUC.byId(id)
|
||||
.map(mapper::toDto)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ProjectDto> create(@Valid @RequestBody CreateProjectRequest request) {
|
||||
var cmd = new CreateProjectUseCase.Command(
|
||||
request.title(),
|
||||
request.description(),
|
||||
request.url()
|
||||
);
|
||||
var created = createUC.handle(cmd);
|
||||
var body = mapper.toDto(created);
|
||||
return ResponseEntity.created(URI.create("/api/projects/" + body.id())).body(body);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public record CreateProjectRequest(
|
||||
@NotBlank String title,
|
||||
String description,
|
||||
String url
|
||||
) {}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public record ProjectDto(Long id, @NotBlank String title, String description, String url) {}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.pablotj.portfolio.infrastructure.rest.education;
|
||||
|
||||
import com.pablotj.portfolio.application.education.CreateEducationUseCase;
|
||||
import com.pablotj.portfolio.application.education.GetEducationUseCase;
|
||||
import com.pablotj.portfolio.infrastructure.rest.education.dto.CreateEducationRequest;
|
||||
import com.pablotj.portfolio.infrastructure.rest.education.dto.EducationDto;
|
||||
import com.pablotj.portfolio.infrastructure.rest.education.mapper.EducationRestMapper;
|
||||
import jakarta.validation.Valid;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v1/profiles/{profileId}/education")
|
||||
public class EducationController {
|
||||
|
||||
private final CreateEducationUseCase createUC;
|
||||
private final GetEducationUseCase getUC;
|
||||
private final EducationRestMapper mapper;
|
||||
|
||||
public EducationController(CreateEducationUseCase createUC, GetEducationUseCase getUC, EducationRestMapper mapper) {
|
||||
this.createUC = createUC;
|
||||
this.getUC = getUC;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<EducationDto> all(@PathVariable Long profileId) {
|
||||
return getUC.all(profileId).stream().map(mapper::toDto).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<EducationDto> byId(@PathVariable Long profileId, @PathVariable Long id) {
|
||||
return getUC.byId(profileId, id)
|
||||
.map(mapper::toDto)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<EducationDto> create(@PathVariable Long profileId, @Valid @RequestBody CreateEducationRequest request) {
|
||||
var cmd = new CreateEducationUseCase.Command(
|
||||
request.institution(),
|
||||
request.degree(),
|
||||
request.period(),
|
||||
request.grade(),
|
||||
request.description()
|
||||
);
|
||||
var created = createUC.handle(profileId, cmd);
|
||||
var body = mapper.toDto(created);
|
||||
return ResponseEntity.created(URI.create("/api/educations/" + body.id())).body(body);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user