Exercise 8 PR #95
1
.github/workflows/build-and-deploy.yml
vendored
1
.github/workflows/build-and-deploy.yml
vendored
|
@ -78,6 +78,7 @@ jobs:
|
|||
cd /home/${{ secrets.SSH_USER }}/
|
||||
touch acme.json
|
||||
sudo chmod 0600 acme.json
|
||||
sudo docker-compose down --remove-orphans
|
||||
sudo echo "PUB_IP=$(wget -qO- http://ipecho.net/plain | xargs echo)" | sed -e 's/\./-/g' > .env
|
||||
sudo docker-compose up -d
|
||||
|
||||
|
|
|
@ -70,3 +70,36 @@ services:
|
|||
- "traefik.http.routers.app.tls=true"
|
||||
- "traefik.http.routers.app.entryPoints=web,websecure"
|
||||
- "traefik.http.routers.app.tls.certresolver=le"
|
||||
|
||||
mongodb:
|
||||
image: mongo
|
||||
container_name: mongodb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: 8nP7s0a # Can not be changed again later on
|
||||
volumes:
|
||||
- database:/data/db
|
||||
|
||||
dbadmin:
|
||||
image: mongo-express
|
||||
container_name: dbadmin
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
ME_CONFIG_BASICAUTH_USERNAME: student # Access to web interface: username
|
||||
ME_CONFIG_BASICAUTH_PASSWORD: studious # Access to web interface: password
|
||||
ME_CONFIG_MONGODB_ADMINUSERNAME: root
|
||||
ME_CONFIG_MONGODB_ADMINPASSWORD: 8nP7s0a # must correspond to the db
|
||||
ME_CONFIG_MONGODB_PORT: 27017 # Default 27017
|
||||
ME_CONFIG_MONGODB_SERVER: mongodb
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dbadmin.rule=Host(`dbadmin.${PUB_IP}.nip.io`)"
|
||||
- "traefik.http.routers.dbadmin.service=dbadmin"
|
||||
- "traefik.http.services.dbadmin.loadbalancer.server.port=8081"
|
||||
- "traefik.http.routers.dbadmin.tls=true"
|
||||
- "traefik.http.routers.dbadmin.entryPoints=web,websecure"
|
||||
- "traefik.http.routers.dbadmin.tls.certresolver=le"
|
||||
|
||||
volumes:
|
||||
database:
|
||||
|
|
|
@ -27,6 +27,15 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>3.2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package ch.unisg.tapastasks;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.adapter.out.persistence.mongodb.TaskRepository;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableMongoRepositories(basePackageClasses = TaskRepository.class)
|
||||
public class TapasTasksApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication tapasTasksApp = new SpringApplication(TapasTasksApplication.class);
|
||||
tapasTasksApp.run(args);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package ch.unisg.tapastasks.tasks.adapter.out.persistence.mongodb;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Data
|
||||
@Document(collection = "tasks")
|
||||
public class MongoTaskDocument {
|
||||
|
||||
@Id
|
||||
public String taskId;
|
||||
|
||||
public String taskName;
|
||||
public String taskType;
|
||||
public String originalTaskUri;
|
||||
public String taskStatus;
|
||||
public String taskListName;
|
||||
|
||||
|
||||
public MongoTaskDocument(String taskId, String taskName, String taskType,
|
||||
String originalTaskUri,
|
||||
String taskStatus, String taskListName) {
|
||||
|
||||
this.taskId = taskId;
|
||||
this.taskName = taskName;
|
||||
this.taskType = taskType;
|
||||
this.originalTaskUri = originalTaskUri;
|
||||
this.taskStatus = taskStatus;
|
||||
this.taskListName = taskListName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ch.unisg.tapastasks.tasks.adapter.out.persistence.mongodb;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
class TaskMapper {
|
||||
|
||||
Task mapToDomainEntity(MongoTaskDocument task) {
|
||||
return Task.withIdNameTypeOriginaluriStatus(
|
||||
new Task.TaskId(task.taskId),
|
||||
new Task.TaskName(task.taskName),
|
||||
new Task.TaskType(task.taskType),
|
||||
new Task.OriginalTaskUri(task.originalTaskUri),
|
||||
new Task.TaskStatus(Task.Status.valueOf(task.taskStatus))
|
||||
);
|
||||
}
|
||||
|
||||
MongoTaskDocument mapToMongoDocument(Task task) {
|
||||
return new MongoTaskDocument(
|
||||
task.getTaskId().getValue(),
|
||||
task.getTaskName().getValue(),
|
||||
task.getTaskType().getValue(),
|
||||
task.getOriginalTaskUri().getValue(),
|
||||
task.getTaskStatus().getValue().toString(),
|
||||
TaskList.getTapasTaskList().getTaskListName().getValue()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package ch.unisg.tapastasks.tasks.adapter.out.persistence.mongodb;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.AddTaskPort;
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.LoadTaskPort;
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TaskPersistenceAdapter implements
|
||||
AddTaskPort,
|
||||
LoadTaskPort {
|
||||
|
||||
@Autowired
|
||||
private final TaskRepository taskRepository;
|
||||
|
||||
private final TaskMapper taskMapper;
|
||||
|
||||
@Override
|
||||
public void addTask(Task task) {
|
||||
MongoTaskDocument mongoTaskDocument = taskMapper.mapToMongoDocument(task);
|
||||
taskRepository.save(mongoTaskDocument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task loadTask(Task.TaskId taskId, TaskList.TaskListName taskListName) {
|
||||
MongoTaskDocument mongoTaskDocument = taskRepository.findByTaskId(taskId.getValue(),taskListName.getValue());
|
||||
Task task = taskMapper.mapToDomainEntity(mongoTaskDocument);
|
||||
return task;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package ch.unisg.tapastasks.tasks.adapter.out.persistence.mongodb;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface TaskRepository extends MongoRepository<MongoTaskDocument,String> {
|
||||
|
||||
public MongoTaskDocument findByTaskId(String taskId, String taskListName);
|
||||
|
||||
public List<MongoTaskDocument> findByTaskListName(String taskListName);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package ch.unisg.tapastasks.tasks.application.port.out;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
|
||||
public interface AddTaskPort {
|
||||
|
||||
void addTask(Task task);
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package ch.unisg.tapastasks.tasks.application.port.out;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
|
||||
public interface LoadTaskPort {
|
||||
|
||||
Task loadTask(Task.TaskId taskId, TaskList.TaskListName taskListName);
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ch.unisg.tapastasks.tasks.application.port.out;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
|
||||
public interface TaskListLock {
|
||||
|
||||
void lockTaskList(TaskList.TaskListName taskListName);
|
||||
|
||||
void releaseTaskList(TaskList.TaskListName taskListName);
|
||||
|
||||
}
|
|
@ -2,7 +2,9 @@ package ch.unisg.tapastasks.tasks.application.service;
|
|||
|
||||
import ch.unisg.tapastasks.tasks.application.port.in.AddNewTaskToTaskListCommand;
|
||||
import ch.unisg.tapastasks.tasks.application.port.in.AddNewTaskToTaskListUseCase;
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.AddTaskPort;
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.NewTaskAddedEventPort;
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.TaskListLock;
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.domain.NewTaskAddedEvent;
|
||||
|
@ -17,11 +19,14 @@ import javax.transaction.Transactional;
|
|||
public class AddNewTaskToTaskListService implements AddNewTaskToTaskListUseCase {
|
||||
|
||||
private final NewTaskAddedEventPort newTaskAddedEventPort;
|
||||
private final AddTaskPort addTaskToRepositoryPort;
|
||||
private final TaskListLock taskListLock;
|
||||
|
||||
@Override
|
||||
public Task addNewTaskToTaskList(AddNewTaskToTaskListCommand command) {
|
||||
TaskList taskList = TaskList.getTapasTaskList();
|
||||
|
||||
taskListLock.lockTaskList(taskList.getTaskListName());
|
||||
Task newTask = (command.getOriginalTaskUri().isPresent()) ?
|
||||
// Create a delegated task that points back to the original task
|
||||
taskList.addNewTaskWithNameAndTypeAndOriginalTaskUri(command.getTaskName(),
|
||||
|
@ -29,6 +34,9 @@ public class AddNewTaskToTaskListService implements AddNewTaskToTaskListUseCase
|
|||
// Create an original task
|
||||
: taskList.addNewTaskWithNameAndType(command.getTaskName(), command.getTaskType());
|
||||
|
||||
addTaskToRepositoryPort.addTask(newTask);
|
||||
taskListLock.releaseTaskList(taskList.getTaskListName());
|
||||
|
||||
//Here we are using the application service to emit the domain event to the outside of the bounded context.
|
||||
//This event should be considered as a light-weight "integration event" to communicate with other services.
|
||||
//Domain events are usually rather "fat". In our implementation we simplify at this point. In general, it is
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package ch.unisg.tapastasks.tasks.application.service;
|
||||
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.TaskListLock;
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class NoOpTaskListLock implements TaskListLock {
|
||||
@Override
|
||||
public void lockTaskList(TaskList.TaskListName taskListName) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseTaskList(TaskList.TaskListName taskListName) {
|
||||
//do nothing
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package ch.unisg.tapastasks.tasks.application.service;
|
|||
|
||||
import ch.unisg.tapastasks.tasks.application.port.in.RetrieveTaskFromTaskListQuery;
|
||||
import ch.unisg.tapastasks.tasks.application.port.in.RetrieveTaskFromTaskListUseCase;
|
||||
import ch.unisg.tapastasks.tasks.application.port.out.LoadTaskPort;
|
||||
import ch.unisg.tapastasks.tasks.domain.Task;
|
||||
import ch.unisg.tapastasks.tasks.domain.TaskList;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -14,9 +15,17 @@ import java.util.Optional;
|
|||
@Component
|
||||
@Transactional
|
||||
public class RetrieveTaskFromTaskListService implements RetrieveTaskFromTaskListUseCase {
|
||||
|
||||
private final LoadTaskPort loadTaskFromRepositoryPort;
|
||||
|
||||
@Override
|
||||
public Optional<Task> retrieveTaskFromTaskList(RetrieveTaskFromTaskListQuery query) {
|
||||
TaskList taskList = TaskList.getTapasTaskList();
|
||||
return taskList.retrieveTaskById(query.getTaskId());
|
||||
|
||||
Optional<Task> task = taskList.retrieveTaskById(query.getTaskId());
|
||||
|
||||
Optional<Task> taskFromRepo = Optional.ofNullable(loadTaskFromRepositoryPort.loadTask(query.getTaskId(), taskList.getTaskListName()));
|
||||
|
||||
return taskFromRepo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,17 +49,39 @@ public class Task {
|
|||
this.outputData = null;
|
||||
}
|
||||
|
||||
protected static Task createTaskWithNameAndType(TaskName name, TaskType type) {
|
||||
//Constructor from repo
|
||||
public Task(TaskId taskId, TaskName taskName, TaskType taskType, OriginalTaskUri taskUri,
|
||||
TaskStatus taskStatus) {
|
||||
this.taskId = taskId;
|
||||
this.taskName = taskName;
|
||||
this.taskType = taskType;
|
||||
this.originalTaskUri = taskUri;
|
||||
this.taskStatus = taskStatus;
|
||||
this.inputData = null;
|
||||
this.outputData = null;
|
||||
}
|
||||
|
||||
|
||||
public static Task createTaskWithNameAndType(TaskName name, TaskType type) {
|
||||
//This is a simple debug message to see that the request has reached the right method in the core
|
||||
System.out.println("New Task: " + name.getValue() + " " + type.getValue());
|
||||
return new Task(name, type, null);
|
||||
}
|
||||
|
||||
protected static Task createTaskWithNameAndTypeAndOriginalTaskUri(TaskName name, TaskType type,
|
||||
public static Task createTaskWithNameAndTypeAndOriginalTaskUri(TaskName name, TaskType type,
|
||||
OriginalTaskUri originalTaskUri) {
|
||||
return new Task(name, type, originalTaskUri);
|
||||
}
|
||||
|
||||
//This is for recreating a task from a repository.
|
||||
public static Task withIdNameTypeOriginaluriStatus(TaskId taskId, TaskName taskName,
|
||||
TaskType taskType,
|
||||
OriginalTaskUri originalTaskUri,
|
||||
TaskStatus taskStatus) {
|
||||
return new Task(taskId, taskName, taskType, originalTaskUri, taskStatus);
|
||||
}
|
||||
|
||||
|
||||
@Value
|
||||
public static class TaskId {
|
||||
String value;
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
server.port=8081
|
||||
//spring.data.mongodb.uri=mongodb://127.0.0.1:27017
|
||||
spring.data.mongodb.uri=mongodb://root:8nP7s0a@mongodb:27017/
|
||||
spring.data.mongodb.database=tapas-tasks
|
||||
baseuri=https://tapas-tasks.86-119-34-23.nip.io/
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user