Skip to content

Commit

Permalink
Basic functions and solution for issue mindsmash#34
Browse files Browse the repository at this point in the history
- Add, Update, Delete, and Get Users
- Add, Update, Delete, and Get all user tasks
- Send scheduled email notification for unfinished tasks for every user
  • Loading branch information
ymolla committed Nov 8, 2019
1 parent e646e0f commit dde7dc0
Show file tree
Hide file tree
Showing 38 changed files with 1,080 additions and 92 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

compile group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '2.1.3.RELEASE'
}
13 changes: 13 additions & 0 deletions src/main/java/com/coyoapp/tinytask/ResourceConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.coyoapp.tinytask;

public class ResourceConstants {
public static final String TINY_TASKS_V1 = "/v1/tiny-tasks/";

//Everyday at 8:00 AM
public static final String CRON_EVERYDAY_EXPRESSION = "0 0 8 * * *";

//used only for testing
public static final String CRON_EVERY_TWO_SECONDS_EXPRESSION = "2 * * * * *";

public static final String EMAIL_SUBJECT = "Unfinished Tiny Tasks";
}
84 changes: 84 additions & 0 deletions src/main/java/com/coyoapp/tinytask/batch/SendEmailBatch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.coyoapp.tinytask.batch;

import com.coyoapp.tinytask.ResourceConstants;
import com.coyoapp.tinytask.domain.Task;
import com.coyoapp.tinytask.domain.User;
import com.coyoapp.tinytask.repository.UserRepository;
import com.coyoapp.tinytask.service.EmailService;
import com.coyoapp.tinytask.util.Email;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.mail.MessagingException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

//Scheduled task which sends email to every user their unfinished tasks everyday

@Component
public class SendEmailBatch {

@Autowired
private UserRepository userRepository;

@Autowired
private EmailService emailService;

private static final Logger logger = LoggerFactory.getLogger(SendEmailBatch.class);



@Scheduled(cron = ResourceConstants.CRON_EVERYDAY_EXPRESSION)
public void sendUsersEmail() {
logger.info("Email Schedule started");

List<User> users = (List<User>) userRepository.findAll();
try {
if (null != users) sendEmail(users);
}catch (Exception e) {
e.printStackTrace();
}
}

private void sendEmail(List<User> users) {
for (User user : users) {
if (null != user.getTasks() && !user.getTasks().isEmpty()) {
Set<Task> tasks = user.getTasks();
List<Task> unfinishedTasks = getUnfinishedTasks(tasks);
if(!unfinishedTasks.isEmpty()){
String emailBody = "Here are unfinished Tasks: \n";
for (Task unfinished : unfinishedTasks) {
emailBody = emailBody + " - " + unfinished.getName() + "\n";
}

String subject = ResourceConstants.EMAIL_SUBJECT;
Email email = new Email();
email.setSubject(subject);
email.setBody(emailBody);
email.setToEmail(user.getEmail());

try {
emailService.sendEmail(email);
}catch (MessagingException | UnsupportedEncodingException me){
me.printStackTrace();
}
}
}
}
}

private List<Task> getUnfinishedTasks(Set<Task> tasks) {
List<Task> unfinishedTasks = new ArrayList<>();
for (Task task:tasks) {
if(!task.isDone()){
unfinishedTasks.add(task);
}
}
return unfinishedTasks;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.coyoapp.tinytask.configuration;

import com.coyoapp.tinytask.converter.TaskRequestToTaskConverter;
import com.coyoapp.tinytask.converter.TaskToTaskResponseConverter;
import com.coyoapp.tinytask.converter.UserRequestToUserConverter;
import com.coyoapp.tinytask.converter.UserToUserResponseConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ConversionServiceFactoryBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;

import java.util.HashSet;
import java.util.Set;

@Configuration
public class ConversionConfig {
private Set<Converter> getConverters(){
Set<Converter> converters = new HashSet<Converter>();
converters.add(new TaskRequestToTaskConverter());
converters.add(new TaskToTaskResponseConverter());
converters.add(new UserToUserResponseConverter());
converters.add(new UserRequestToUserConverter());
return converters;
}

@Bean
public ConversionService conversionService(){
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters(this.getConverters());
bean.afterPropertiesSet();

return bean.getObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.coyoapp.tinytask.configuration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@EnableScheduling
@ConditionalOnProperty(name = "scheduling.enable", matchIfMissing = true)
public class SchedulingConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.coyoapp.tinytask.converter;

import com.coyoapp.tinytask.domain.Task;
import com.coyoapp.tinytask.dto.TaskRequest;
import org.springframework.core.convert.converter.Converter;

public class TaskRequestToTaskConverter implements Converter<TaskRequest, Task> {

@Override
public Task convert(TaskRequest source) {
Task task= new Task();

if(null != source.getId()) {
task.setId(source.getId());
}

task.setName(source.getName());
task.setDetail(source.getDetail());
task.setDueDate(source.getDueDate());
task.setDone(source.isDone());

return task;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.coyoapp.tinytask.converter;

import com.coyoapp.tinytask.domain.Task;
import com.coyoapp.tinytask.dto.TaskResponse;
import org.springframework.core.convert.converter.Converter;

public class TaskToTaskResponseConverter implements Converter<Task, TaskResponse> {
@Override
public TaskResponse convert(Task source) {
TaskResponse taskResponse = new TaskResponse();
taskResponse.setId(source.getId());
taskResponse.setName(source.getName());
taskResponse.setCreatedDate(source.getCreated());
taskResponse.setDetail(source.getDetail());
taskResponse.setDueDate(source.getDueDate());
taskResponse.setUser(source.getUser());
taskResponse.setDone(source.isDone());

return taskResponse;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.coyoapp.tinytask.converter;

import com.coyoapp.tinytask.domain.User;
import com.coyoapp.tinytask.dto.UserRequest;
import org.springframework.core.convert.converter.Converter;

public class UserRequestToUserConverter implements Converter<UserRequest, User> {


@Override
public User convert(UserRequest source) {
User user = new User();

if(null != source.getId()){
user.setId(source.getId());
}
user.setEmail(source.getEmail());
user.setUsername(source.getUsername());
user.setPassword(source.getPassword());

return user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.coyoapp.tinytask.converter;

import com.coyoapp.tinytask.domain.User;
import com.coyoapp.tinytask.dto.UserResponse;
import org.springframework.core.convert.converter.Converter;

public class UserToUserResponseConverter implements Converter<User, UserResponse> {
@Override
public UserResponse convert(User source) {
UserResponse userResponse = new UserResponse();
userResponse.setEmail(source.getEmail());
userResponse.setId(source.getId());
userResponse.setName(source.getUsername());
userResponse.setRoles(source.getRoles());
userResponse.setTasks(source.getTasks());

return userResponse;
}
}
38 changes: 38 additions & 0 deletions src/main/java/com/coyoapp/tinytask/domain/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.coyoapp.tinytask.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;

@Table(name = "roles")
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Role {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "id", nullable = false, updatable = false)
private String id;

@Column
private String role;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIgnore
private User user;

}
39 changes: 31 additions & 8 deletions src/main/java/com/coyoapp/tinytask/domain/Task.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package com.coyoapp.tinytask.domain;

import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Table(name = "task")
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.time.Instant;
import java.time.LocalDate;

@Table(name = "tasks")
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@EntityListeners(AuditingEntityListener.class)
public class Task {

Expand All @@ -26,8 +33,24 @@ public class Task {
@Column(name = "id", nullable = false, updatable = false)
private String id;

@NotNull
private String name;

private String detail;

private LocalDate dueDate;

@CreatedDate
private Instant created;

private boolean done;

@NotNull
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false)
@OnDelete(action = OnDeleteAction.NO_ACTION)
@JsonIgnore
private User user;


}
51 changes: 51 additions & 0 deletions src/main/java/com/coyoapp/tinytask/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.coyoapp.tinytask.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.util.HashSet;
import java.util.Set;

@Table(name = "users")
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {

@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "id", nullable = false, updatable = false)
private String id;

@Column(unique = true)
@NotEmpty
private String username;

@Column
@JsonIgnore
@NotEmpty
private String password;

@Column
@NotEmpty
private String email;

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Role> roles = new HashSet<>();

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Task> tasks = new HashSet<>();
}
Loading

0 comments on commit dde7dc0

Please sign in to comment.