Skip to content

Commit

Permalink
feat(build): added build-push-container-images.yml
Browse files Browse the repository at this point in the history
  • Loading branch information
zZHorizonZz committed Aug 7, 2024
1 parent eca6cb4 commit 443435c
Show file tree
Hide file tree
Showing 40 changed files with 214 additions and 403 deletions.
106 changes: 106 additions & 0 deletions .github/workflows/build-push-container-images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Build and Push Container Images

on:
push:
branches:
- main

permissions:
contents: read

env:
JAVA_VERSION: "21"
DISTRIBUTION: "corretto"
CONTAINER_REGISTRY: "ghcr.io"
CONTAINER_GROUP: "cloudeko/services"

jobs:
build-image:
name: Build Docker Image
environment: development
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.DISTRIBUTION }}
cache: maven

- name: Get Short SHA
id: short_sha
run: echo "short_sha=$(echo $GITHUB_SHA | head -c7)" >> $GITHUB_OUTPUT

- name: Set Maven Version
run: |
mvn versions:set -DnewVersion=${{ steps.short_sha.outputs.short_sha }}
- name: Set IMAGE_NAME env variable
run: |
MODULE_NAME=zenei
TEMP_NAME=$(echo "${MODULE_NAME}")
IMAGE_NAME=$(echo "$TEMP_NAME" | sed -r 's/([a-z])([A-Z])/\1-\2/g' | tr '[:upper:]' '[:lower:]')
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.CONTAINER_REGISTRY }} -u ${{ github.actor }} --password-stdin

- name: Build and push native image
run: |
mvn clean install -DskipTests \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.push=true \
-Dquarkus.container-image.registry=${{ env.CONTAINER_REGISTRY }} \
-Dquarkus.container-image.group=${{ env.CONTAINER_GROUP }} \
-Dquarkus.container-image.name=${{ env.IMAGE_NAME }} \
-Dquarkus.container-image.tag=${{ steps.short_sha.outputs.short_sha }}
build-native-image:
name: Build Native Docker Image
environment: development
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.DISTRIBUTION }}
cache: maven

- name: Get Short SHA
id: short_sha
run: echo "short_sha=$(echo $GITHUB_SHA | head -c7)" >> $GITHUB_OUTPUT

- name: Set Maven Version
run: |
mvn versions:set -DnewVersion=${{ steps.short_sha.outputs.short_sha }}
- name: Set IMAGE_NAME env variable
run: |
MODULE_NAME=zenei
TEMP_NAME=$(echo "${MODULE_NAME}")
IMAGE_NAME=$(echo "$TEMP_NAME" | sed -r 's/([a-z])([A-Z])/\1-\2/g' | tr '[:upper:]' '[:lower:]')
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ${{ env.CONTAINER_REGISTRY }} -u ${{ github.actor }} --password-stdin

- name: Build and push native image
run: |
mvn clean install -DskipTests \
-Dnative \
-Dquarkus.native.container-build=true \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.push=true \
-Dquarkus.container-image.registry=${{ env.CONTAINER_REGISTRY }} \
-Dquarkus.container-image.group=${{ env.CONTAINER_GROUP }}/native \
-Dquarkus.container-image.name=${{ env.IMAGE_NAME }} \
-Dquarkus.container-image.tag=${{ steps.short_sha.outputs.short_sha }}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public class PrivateUserResponse {
@Schema(description = "Username of the user")
private String username;

@Schema(description = "First name of the user")
private String firstName;

@Schema(description = "Last name of the user")
private String lastName;

@Schema(description = "Primary email of the user")
private String primaryEmailAddress;

Expand All @@ -30,6 +36,9 @@ public class PrivateUserResponse {
@Schema(description = "Whether the user is an admin")
private Boolean admin;

@Schema(description = "Whether the user has a password")
private Boolean passwordEnabled;

@Schema(description = "Timestamp when the user was created")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime createdAt;
Expand All @@ -41,10 +50,12 @@ public class PrivateUserResponse {
public PrivateUserResponse(User user) {
this.id = user.getId().toString();
this.username = user.getUsername();
this.email = user.getEmail();
this.emailVerified = user.isEmailVerified();
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
this.primaryEmailAddress = user.getPrimaryEmailAddress().getEmail();
this.image = user.getImage();
this.admin = user.isAdmin();
this.passwordEnabled = user.isPasswordEnabled();
this.createdAt = user.getCreatedAt();
this.updatedAt = user.getUpdatedAt();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class AuthenticationResource {
private final CreateUser createUser;
private final VerifyEmail verifyEmail;
private final RefreshAccessToken refreshAccessToken;
private final CreateEmailAddress createEmailAddress;
private final SendMagicLinkVerifyEmail sendMagicLinkVerifyEmail;
private final LoginUserWithPassword loginUserWithPassword;

@POST
Expand All @@ -37,7 +37,7 @@ public Response signup(@BeanParam @Valid SignupRequest request) {
final var emailAddress = user.getPrimaryEmailAddress();

if (!emailAddress.getEmailVerified() && emailAddress.getEmailVerificationToken() != null) {
createEmailAddress.handle(new EmailAddressInput(emailAddress));
sendMagicLinkVerifyEmail.handle(new EmailAddressInput(emailAddress));
}

if (request.getRedirectTo() != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dev.cloudeko.zenei.domain.exception;

public class EmailNotFoundException extends BusinessException {

public EmailNotFoundException() {
super(3, "email not found");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.cloudeko.zenei.domain.exception;

public class InvalidUserLoginException extends BusinessException {
public InvalidUserLoginException() {
super(4, "invalid user login");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

import dev.cloudeko.zenei.domain.model.email.EmailAddressInput;

public interface CreateEmailAddress {
public interface SendMagicLinkVerifyEmail {
void handle(EmailAddressInput input);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,42 @@
import dev.cloudeko.zenei.domain.model.email.EmailAddress;
import dev.cloudeko.zenei.domain.model.user.*;
import dev.cloudeko.zenei.domain.provider.HashProvider;
import dev.cloudeko.zenei.domain.provider.StringTokenProvider;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@ApplicationScoped
@AllArgsConstructor
public class CreateUserImpl implements CreateUser {

private final HashProvider hashProvider;
private final StringTokenProvider stringTokenProvider;

private final UserRepository userRepository;
private final UserPasswordRepository userPasswordRepository;
private final HashProvider hashProvider;

@Override
@Transactional
public User handle(CreateUserInput createUserInput) {
final var emailAddress = EmailAddress.builder().email(createUserInput.getEmail()).build();
if (true) { //Will be based on configuration
final var token = stringTokenProvider.generateToken("mail", emailAddress.getEmail() + UUID.randomUUID());

emailAddress.setEmailVerificationToken(token);
emailAddress.setEmailVerificationTokenExpiresAt(LocalDateTime.now().plusDays(1));
emailAddress.setEmailVerified(false);
}

final var user = User.builder()
.username(createUserInput.getUsername())
.primaryEmailAddress(emailAddress.getEmail())
.emailAddresses(List.of(emailAddress)).build();
.emailAddresses(new ArrayList<>(List.of(emailAddress))).build();

checkExistingUsername(user.getUsername());
checkExistingEmail(user.getPrimaryEmailAddress().getEmail());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package dev.cloudeko.zenei.domain.feature.impl;

import dev.cloudeko.zenei.domain.exception.InvalidPasswordException;
import dev.cloudeko.zenei.domain.exception.UserNotFoundException;
import dev.cloudeko.zenei.domain.feature.LoginUserWithPassword;
import dev.cloudeko.zenei.domain.feature.util.TokenUtil;
import dev.cloudeko.zenei.domain.model.Token;
import dev.cloudeko.zenei.domain.model.token.LoginPasswordInput;
import dev.cloudeko.zenei.domain.model.token.RefreshTokenRepository;
import dev.cloudeko.zenei.domain.model.user.UserPassword;
import dev.cloudeko.zenei.domain.model.user.UserPasswordRepository;
import dev.cloudeko.zenei.domain.model.user.UserRepository;
import dev.cloudeko.zenei.domain.provider.HashProvider;
Expand Down Expand Up @@ -45,7 +47,7 @@ public Token handle(LoginPasswordInput loginPasswordInput) {

return TokenUtil.createToken(user, accessTokenData, refreshToken);
} else {
throw new UserNotFoundException();
throw new InvalidPasswordException();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package dev.cloudeko.zenei.domain.feature.impl;

import dev.cloudeko.zenei.domain.exception.UserNotFoundException;
import dev.cloudeko.zenei.domain.feature.CreateEmailAddress;
import dev.cloudeko.zenei.domain.model.email.ConfirmationTokenRepository;
import dev.cloudeko.zenei.domain.feature.SendMagicLinkVerifyEmail;
import dev.cloudeko.zenei.domain.model.email.EmailAddressInput;
import dev.cloudeko.zenei.domain.model.email.EmailAddressRepository;
import dev.cloudeko.zenei.domain.model.user.UserRepository;
import dev.cloudeko.zenei.domain.provider.MailTemplateProvider;
import dev.cloudeko.zenei.domain.provider.StringTokenProvider;
Expand All @@ -13,35 +12,24 @@
import lombok.AllArgsConstructor;
import lombok.extern.jbosslog.JBossLog;

import java.util.UUID;

@JBossLog
@ApplicationScoped
@AllArgsConstructor
public class CreateEmailAddressImpl implements CreateEmailAddress {
public class SendMagicLinkVerifyEmailImpl implements SendMagicLinkVerifyEmail {

private final Mailer mailer;
private final StringTokenProvider stringTokenProvider;
private final MailTemplateProvider mailTemplateProvider;

private final UserRepository userRepository;
private final ConfirmationTokenRepository confirmationTokenRepository;
private final EmailAddressRepository emailAddressRepository;

@Override
public void handle(EmailAddressInput input) {
final var user = userRepository.getUserByEmail(input.getEmailAddress());

if (user.isEmpty()) {
throw new UserNotFoundException();
}

final var token = stringTokenProvider.generateToken("mail", input.getEmailAddress() + UUID.randomUUID());


final var content = mailTemplateProvider.defaultCreateConfirmationMailTemplate(
"http://localhost:8080/user/verify-email",
input.getEmailVerificationToken());
final var mail = Mail.withHtml(input.getEmailAddress(), "Welcome to Zenei", content);
input.getEmailAddress().getEmailVerificationToken());
final var mail = Mail.withHtml(input.getEmailAddress().getEmail(), "Welcome to Zenei", content);

mailer.send(mail);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,21 @@
package dev.cloudeko.zenei.domain.feature.impl;

import dev.cloudeko.zenei.domain.exception.InvalidConfirmationTokenException;
import dev.cloudeko.zenei.domain.feature.VerifyEmail;
import dev.cloudeko.zenei.domain.model.email.ConfirmEmailInput;
import dev.cloudeko.zenei.domain.model.email.ConfirmationTokenRepository;
import dev.cloudeko.zenei.domain.model.user.UserRepository;
import dev.cloudeko.zenei.domain.provider.MailTemplateProvider;
import dev.cloudeko.zenei.domain.provider.StringTokenProvider;
import io.quarkus.mailer.Mailer;
import dev.cloudeko.zenei.domain.model.email.EmailAddressRepository;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.AllArgsConstructor;
import lombok.extern.jbosslog.JBossLog;

import java.time.LocalDateTime;

@JBossLog
@ApplicationScoped
@AllArgsConstructor
public class VerifyEmailImpl implements VerifyEmail {

private final Mailer mailer;
private final StringTokenProvider stringTokenProvider;
private final MailTemplateProvider mailTemplateProvider;

private final UserRepository userRepository;
private final ConfirmationTokenRepository confirmationTokenRepository;
private final EmailAddressRepository emailAddressRepository;

@Override
public void handle(ConfirmEmailInput input) {
final var confirmationToken = confirmationTokenRepository.findByToken(input.getToken());

if (confirmationToken.isEmpty()) {
throw new InvalidConfirmationTokenException();
}

if (confirmationToken.get().getExpiresAt().isBefore(LocalDateTime.now())) {
throw new InvalidConfirmationTokenException();
}

final var user = confirmationToken.get().getUser();

userRepository.updateEmailVerified(user.getEmail(), true);
confirmationTokenRepository.deleteConfirmationToken(input.getToken());
emailAddressRepository.confirmEmailAddress(input.getToken());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package dev.cloudeko.zenei.domain.mapping;

import dev.cloudeko.zenei.domain.model.email.ConfirmationToken;
import dev.cloudeko.zenei.domain.model.email.EmailAddress;
import dev.cloudeko.zenei.infrastructure.repository.hibernate.entity.ConfirmationTokenEntity;
import dev.cloudeko.zenei.infrastructure.repository.hibernate.entity.EmailAddressEntity;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
Expand Down
Loading

0 comments on commit 443435c

Please sign in to comment.