diff --git a/src/main/java/com/smartcalendar/config/SecurityConfig.java b/src/main/java/com/smartcalendar/config/SecurityConfig.java index 29faad3..f67a9f0 100644 --- a/src/main/java/com/smartcalendar/config/SecurityConfig.java +++ b/src/main/java/com/smartcalendar/config/SecurityConfig.java @@ -62,6 +62,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/static/**", "/api/auth/login", "/api/auth/signup", + "/api/events", "/h2-console/**" ).permitAll() .requestMatchers( diff --git a/src/main/java/com/smartcalendar/controller/EventController.java b/src/main/java/com/smartcalendar/controller/EventController.java new file mode 100644 index 0000000..c42a12c --- /dev/null +++ b/src/main/java/com/smartcalendar/controller/EventController.java @@ -0,0 +1,35 @@ +package com.smartcalendar.controller; + +import com.smartcalendar.model.Event; +import com.smartcalendar.repository.EventRepository; +import com.smartcalendar.service.EventService; +import org.springframework.beans.factory.annotation.Autowired; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/events") +public class EventController { + + private final EventService eventService; + + @Autowired + public EventController(EventService eventService) { + this.eventService = eventService; + } + + @GetMapping + public ResponseEntity> getEvents(@RequestParam(name = "location") String location, + @RequestParam(name = "userId") Long userId) { + if (location == null || location.isBlank()) { + return ResponseEntity.badRequest().build(); + } + List events = eventService.getPersonalizedEvents(location.trim(), userId); + return ResponseEntity.ok(events); + } +} \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/model/Event.java b/src/main/java/com/smartcalendar/model/Event.java index b7c7b46..9cf3d4e 100644 --- a/src/main/java/com/smartcalendar/model/Event.java +++ b/src/main/java/com/smartcalendar/model/Event.java @@ -1,13 +1,19 @@ package com.smartcalendar.model; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.Instant; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; +import java.util.ArrayList; +import java.util.Map; import java.util.UUID; @Entity @@ -17,11 +23,13 @@ @AllArgsConstructor public class Event { @Id - //@GeneratedValue(strategy = GenerationType.AUTO) + //@GeneratedValue(strategy = GenerationType.UUID) private UUID id; + @Column private String title; + @Column private String description; @Column(name = "start_time") @@ -30,6 +38,7 @@ public class Event { @Column(name = "end_time") private LocalDateTime end; + @Column(name = "event_location") private String location; @Enumerated(EnumType.STRING) @@ -39,10 +48,23 @@ public class Event { @ManyToOne @JoinColumn(name = "organizer_id") + @JsonBackReference(value = "organized_events") private User organizer; + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "events_tags", + joinColumns = @JoinColumn(name = "event_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id") + ) + //@JsonManagedReference(value = "event_tags") + @JsonProperty("tags") + private List tags; + + @Column private boolean completed = false; + @Column private boolean isShared = false; @ElementCollection @@ -56,5 +78,18 @@ public class Event { joinColumns = @JoinColumn(name = "event_id"), inverseJoinColumns = @JoinColumn(name = "user_id") ) + @JsonIgnore private List participants = new ArrayList<>(); + + public LocalDateTime getEnd() { + return end; + } + + public LocalDateTime getStart() { + return start; + } + + public List getTags() { + return tags; + } } \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/model/Friendship.java b/src/main/java/com/smartcalendar/model/Friendship.java new file mode 100644 index 0000000..418ce00 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/Friendship.java @@ -0,0 +1,30 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Entity +@Data +@Table(name = "friendships") +@NoArgsConstructor +@AllArgsConstructor +public class Friendship { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; + + @ManyToOne + @JoinColumn(name = "user_id1") + @JsonBackReference(value = "friends1") + private User user1; + + @ManyToOne + @JoinColumn(name = "user_id2") + @JsonBackReference(value = "friends2") + private User user2; +} diff --git a/src/main/java/com/smartcalendar/model/GroupChat.java b/src/main/java/com/smartcalendar/model/GroupChat.java new file mode 100644 index 0000000..0b25f86 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -0,0 +1,37 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.UUID; + +@Entity +@Data +@Table(name = "group_chats") +@NoArgsConstructor +@AllArgsConstructor +public class GroupChat { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; + + @ManyToOne + @JoinColumn(name = "admin_id") + @JsonBackReference(value = "admin_chats") + private User admin; + + @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "messages_in_group_chat") + private List messages; + + @ManyToMany(mappedBy = "groupChats", fetch = FetchType.LAZY) + //@JsonBackReference(value = "common_chats") + @JsonIgnore + private List users; +} diff --git a/src/main/java/com/smartcalendar/model/GroupMessage.java b/src/main/java/com/smartcalendar/model/GroupMessage.java new file mode 100644 index 0000000..4cfd81b --- /dev/null +++ b/src/main/java/com/smartcalendar/model/GroupMessage.java @@ -0,0 +1,37 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Entity +@Data +@Table(name = "group_messages") +@NoArgsConstructor +@AllArgsConstructor +public class GroupMessage { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; + + @Column + private String messageText; + + @Column(name = "time_sent") + private LocalDateTime timeWhenSent; + + @ManyToOne + @JoinColumn(name = "chat_id") + @JsonBackReference(value = "messages_in_group_chat") + private GroupChat chat; + + @ManyToOne + @JoinColumn(name = "user_id") + @JsonBackReference(value = "group_message_author") + private User user; +} diff --git a/src/main/java/com/smartcalendar/model/PrivateChat.java b/src/main/java/com/smartcalendar/model/PrivateChat.java new file mode 100644 index 0000000..29c9df7 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/PrivateChat.java @@ -0,0 +1,36 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.UUID; + +@Entity +@Data +@Table(name = "private_chats") +@NoArgsConstructor +@AllArgsConstructor +public class PrivateChat { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; + + @ManyToOne + @JoinColumn(name = "user_id1") + @JsonBackReference(value = "chats1") + private User user1; + + @ManyToOne + @JoinColumn(name = "user_id2") + @JsonBackReference(value = "chats2") + private User user2; + + @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "messages_in_private_chat") + private List messages; +} diff --git a/src/main/java/com/smartcalendar/model/PrivateMessage.java b/src/main/java/com/smartcalendar/model/PrivateMessage.java new file mode 100644 index 0000000..55933ca --- /dev/null +++ b/src/main/java/com/smartcalendar/model/PrivateMessage.java @@ -0,0 +1,37 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Entity +@Data +@Table(name = "private_messages") +@NoArgsConstructor +@AllArgsConstructor +public class PrivateMessage { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; + + @Column + private String messageText; + + @Column(name = "time_sent") + private LocalDateTime timeWhenSent; + + @ManyToOne + @JoinColumn(name = "chat_id") + @JsonBackReference(value = "messages_in_private_chat") + private PrivateChat chat; + + @ManyToOne + @JoinColumn(name = "user_id") + @JsonBackReference(value = "private_message_author") + private User user; +} diff --git a/src/main/java/com/smartcalendar/model/Tag.java b/src/main/java/com/smartcalendar/model/Tag.java new file mode 100644 index 0000000..757a45d --- /dev/null +++ b/src/main/java/com/smartcalendar/model/Tag.java @@ -0,0 +1,34 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.UUID; + +@Entity +@Data +@Table(name = "tags") +@NoArgsConstructor +@AllArgsConstructor +public class Tag { + @Id + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column + private String title; + + @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY) + //@JsonBackReference(value = "event_tags") + @JsonIgnore + private List events; + + public Long getId() { + return id; + } +} diff --git a/src/main/java/com/smartcalendar/model/Task.java b/src/main/java/com/smartcalendar/model/Task.java index 2d51341..17c1f77 100644 --- a/src/main/java/com/smartcalendar/model/Task.java +++ b/src/main/java/com/smartcalendar/model/Task.java @@ -1,6 +1,7 @@ package com.smartcalendar.model; import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -12,6 +13,7 @@ @Entity @Data +@Table(name = "tasks") @NoArgsConstructor @AllArgsConstructor public class Task { @@ -19,11 +21,12 @@ public class Task { @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; + @Column private String title; - + @Column private String description; - - private boolean completed; + @Column + private boolean isCompleted; private LocalDateTime dueDateTime; private Boolean allDay = false; @@ -32,6 +35,6 @@ public class Task { @ManyToOne @JoinColumn(name = "user_id") - @JsonBackReference + @JsonBackReference(value = "user_tasks") private User user; } \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/model/User.java b/src/main/java/com/smartcalendar/model/User.java index 89484a5..ea94434 100644 --- a/src/main/java/com/smartcalendar/model/User.java +++ b/src/main/java/com/smartcalendar/model/User.java @@ -1,6 +1,7 @@ package com.smartcalendar.model; import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; import jakarta.validation.constraints.Email; import lombok.Data; @@ -9,9 +10,8 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.time.LocalDateTime; +import java.util.*; @Entity @Data @@ -34,12 +34,64 @@ public class User implements UserDetails { private String password; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "user_tasks") private List tasks; @Column(name = "device_token") private String deviceToken; + @OneToMany(mappedBy = "organizer", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "organized_events") + private List organized_events; + + @OneToMany(mappedBy = "admin", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "admin_chats") + private List chatsWithAdminRights; + + @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "chats1") + private List privateChats1; + + @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "chats2") + private List privateChats2; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "group_message_author") + private List groupMessages; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "private_message_author") + private List privateMessages; + + @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "friends1") + private List friendships1; + + @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference(value = "friends2") + private List friendships2; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "users_events", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "event_id") + ) + //@JsonManagedReference(value = "personal_events") + @JsonProperty("events") + private List events = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "users_group_chats", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "chat_id") + ) + //@JsonManagedReference(value = "common_chats") + @JsonProperty("group_chats") + private List groupChats; + @Override public Collection getAuthorities() { return Collections.emptyList(); @@ -74,4 +126,13 @@ public boolean isCredentialsNonExpired() { public boolean isEnabled() { return true; } + + public Long getId() { + return id; + } + + public List getVisitedEvents() { + return events.stream().filter(event -> event.getStart().isBefore(LocalDateTime.now())).toList(); + } + } \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/repository/EventRepository.java b/src/main/java/com/smartcalendar/repository/EventRepository.java index 7cc86b7..312c2d5 100644 --- a/src/main/java/com/smartcalendar/repository/EventRepository.java +++ b/src/main/java/com/smartcalendar/repository/EventRepository.java @@ -2,6 +2,7 @@ import com.smartcalendar.model.Event; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -10,4 +11,9 @@ @Repository public interface EventRepository extends JpaRepository { List findByOrganizerId(Long organizerId); + @Query("SELECT e FROM Event e WHERE LOWER(e.location) = LOWER(:location) ORDER BY e.end ASC") + List findByLocationIgnoreCase(String location); + @Query("SELECT e FROM Event e WHERE LOWER(e.location) = LOWER(:location) AND :userId IS NOT NULL " + + "AND (e NOT IN (SELECT v FROM User u JOIN u.events v WHERE u.id = :userId))") + List findByLocationForUser(String location, Long userId); } \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/service/EventService.java b/src/main/java/com/smartcalendar/service/EventService.java new file mode 100644 index 0000000..c23f5d9 --- /dev/null +++ b/src/main/java/com/smartcalendar/service/EventService.java @@ -0,0 +1,65 @@ +package com.smartcalendar.service; + +import com.smartcalendar.model.Event; +import com.smartcalendar.model.Tag; +import com.smartcalendar.model.User; +import com.smartcalendar.repository.EventRepository; +import com.smartcalendar.repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class EventService { + + private final UserRepository userRepository; + private final EventRepository eventRepository; + + @Autowired + public EventService(UserRepository userRepository, EventRepository eventRepository) { + this.userRepository = userRepository; + this.eventRepository = eventRepository; + } + + public List getPersonalizedEvents(String location, Long userId) { + List events = new ArrayList<>(); + if (userId != null) { + Optional userOpt = userRepository.findById(userId); + if (userOpt.isPresent()) { + User user = userOpt.get(); + events = calculateRelevance(location, user); + } + } + if (events.isEmpty()) { + events = eventRepository.findByLocationIgnoreCase(location); + } + return filterEventsByTime(events); + } + + private List filterEventsByTime(List events) { + return events.stream().filter(event -> event.getEnd().isAfter(LocalDateTime.now())).toList(); + } + + private List calculateRelevance(String location, User user) { + List locationEvents = eventRepository.findByLocationForUser(location, user.getId()); + Map tagFrequency = new HashMap<>(); + user.getVisitedEvents().forEach(event -> event.getTags().forEach(tag -> + tagFrequency.put(tag.getId(), tagFrequency.getOrDefault(tag.getId(), 0) + 1))); + Map relevanceMap = new HashMap<>(); + for (Event event : locationEvents) { + int score = 0; + for (Long tagId : event.getTags().stream().map(Tag::getId).toList()) { + score += tagFrequency.getOrDefault(tagId, 0); + } + relevanceMap.put(event, score); + } + return locationEvents.stream().sorted((lhs, rhs) -> { + int relevanceCompare = Integer.compare(relevanceMap.get(rhs), relevanceMap.get(lhs)); + if (relevanceCompare != 0) return relevanceCompare; + return lhs.getStart().compareTo(rhs.getStart()); + }).collect(Collectors.toList()); + } +} diff --git a/src/main/resources/application-h2.properties b/src/main/resources/application-h2.properties new file mode 100644 index 0000000..8d25e7c --- /dev/null +++ b/src/main/resources/application-h2.properties @@ -0,0 +1,71 @@ +# =============================== +# DATABASE (H2) +# =============================== +spring.datasource.url=jdbc:h2:mem:smartcalendar;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +# =============================== +# H2 CONSOLE +# =============================== +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console +spring.h2.console.settings.trace=true +spring.h2.console.settings.web-allow-others=true + +# =============================== +# DATA INITIALIZATION +# =============================== +spring.sql.init.mode=always +spring.jpa.defer-datasource-initialization=true +spring.jpa.properties.hibernate.dialect= + +# =============================== +# LOGGING +# =============================== +logging.level.org.springframework=INFO +logging.level.com.smartcalendar=DEBUG +logging.level.org.hibernate.SQL=DEBUG +logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE +logging.level.org.springframework.security=DEBUG + +# =============================== +# JWT +# =============================== +app.jwt.secret=${JWT_SECRET} +app.jwt.expiration-ms=86400000 + +# =============================== +# SWAGGER +# =============================== +springdoc.swagger-ui.enabled=true +springdoc.api-docs.enabled=true +springdoc.api-docs.path=/v3/api-docs +springdoc.swagger-ui.path=/swagger-ui.html +springdoc.swagger-ui.tags-sorter=alpha +springdoc.swagger-ui.operations-sorter=alpha +springdoc.swagger-ui.oauth.client-id=your-client-id +springdoc.swagger-ui.oauth.use-pkce-with-authorization-code-grant=true + +# =============================== +# OTHER SETTINGS +# =============================== +server.port=8080 +server.address=0.0.0.0 +spring.main.banner-mode=off + +chatgpt.api.url=https://api.openai.com/v1/chat/completions +whisper.api.url=https://api.openai.com/v1/audio/transcriptions +chatgpt.api.key=${CHATGPT_API_KEY} + +# =============================== +# SMTP +# =============================== +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=${MAIL_ADDRESS} +spring.mail.password=${MAIL_PASSWORD} +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.from=noreply@ttsc.com \ No newline at end of file diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 8797063..04ff572 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -3,4 +3,14 @@ spring.jpa.hibernate.ddl-auto=create-drop spring.datasource.url=jdbc:h2:mem:testdb_test chatgpt.api.url=http://dummy-url chatgpt.api.key=dummy-key -JWT_SECRET=your_test_secret \ No newline at end of file +JWT_SECRET=your_test_secret +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console +spring.h2.console.settings.trace=true +spring.h2.console.settings.web-allow-others=true +spring.sql.init.mode=always +spring.jpa.defer-datasource-initialization=true +spring.jpa.properties.hibernate.dialect= \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6f4a937..9acbb95 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,10 +1,12 @@ # =============================== -# DATABASE (H2) -# =============================== -spring.datasource.url=jdbc:h2:mem:smartcalendar;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password= +# DATABASE (PostgreSQL) +# =============================== +spring.datasource.url=jdbc:postgresql://localhost:5432/smartcalendar +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +spring.jpa.show-sql=true +spring.jpa.database=postgresql # =============================== # H2 CONSOLE @@ -19,6 +21,9 @@ spring.h2.console.settings.web-allow-others=true # =============================== spring.sql.init.mode=always spring.jpa.defer-datasource-initialization=true +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.generate-ddl=true # =============================== # LOGGING @@ -63,7 +68,7 @@ chatgpt.api.key=${CHATGPT_API_KEY} # =============================== spring.mail.host=smtp.gmail.com spring.mail.port=587 -spring.mail.username=dimarus06122005@gmail.com +spring.mail.username=${MAIL_ADDRESS} spring.mail.password=${MAIL_PASSWORD} spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0971f93..5818795 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,6 +1,71 @@ CREATE TABLE IF NOT EXISTS users ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, + id BIGSERIAL PRIMARY KEY, username VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, - password VARCHAR(255) NOT NULL + password VARCHAR(255) NOT NULL, + device_token VARCHAR(255) +); + +CREATE TABLE IF NOT EXISTS events ( + id UUID PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description VARCHAR(255), + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + event_location VARCHAR(255) NOT NULL, + completed BOOLEAN NOT NULL, + is_shared BOOLEAN NOT NULL, + organizer_id BIGSERIAL NOT NULL, + FOREIGN KEY (organizer_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS tasks ( + id BIGSERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description VARCHAR(255) NOT NULL, + is_completed BOOLEAN, + FOREIGN KEY (user_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS tags ( + id BIGSERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL +); + +CREATE TABLE IF NOT EXISTS group_chats ( + id BIGSERIAL PRIMARY KEY, + FOREIGN KEY (admin_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS group_messages ( + id BIGSERIAL PRIMARY KEY, + message_text VARCHAR(255) NOT NULL, + time_sent TIMESTAMP NOT NULL, + FOREIGN KEY (chat_id) REFERENCES group_chats (id), + FOREIGN KEY (user_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS private_chats ( + id BIGSERIAL PRIMARY KEY, + FOREIGN KEY (user_id1) REFERENCES users (id), + FOREIGN KEY (user_id2) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS private_messages ( + id BIGSERIAL PRIMARY KEY, + message_text VARCHAR(255) NOT NULL, + time_sent TIMESTAMP NOT NULL, + FOREIGN KEY (chat_id) REFERENCES private_chats (id), + FOREIGN KEY (user_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS friendships ( + id BIGSERIAL PRIMARY KEY, + FOREIGN KEY (user_id1) REFERENCES users (id), + FOREIGN KEY (user_id2) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS statistics ( + id BIGSERIAL PRIMARY KEY, + FOREIGN KEY (user_id) REFERENCES users (id) ); \ No newline at end of file diff --git a/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java b/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java index aa8d869..99282cd 100644 --- a/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java +++ b/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java @@ -12,6 +12,7 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import java.util.List; @@ -27,6 +28,7 @@ "chatgpt.api.key=dummy-key", "spring.security.enabled=false" }) +@ActiveProfiles("h2") @AutoConfigureMockMvc class AudioControllerIntegrationTest { diff --git a/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java b/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java index 77fe507..081bc73 100644 --- a/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java +++ b/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java @@ -10,6 +10,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import java.util.List; @@ -25,6 +26,7 @@ "chatgpt.api.key=dummy-key", "spring.security.enabled=false" }) +@ActiveProfiles("h2") @AutoConfigureMockMvc class ChatGPTControllerIntegrationTest { diff --git a/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java b/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java index 8de75c4..28f339e 100644 --- a/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java +++ b/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.*; +import org.springframework.test.context.ActiveProfiles; import org.springframework.web.reactive.function.client.WebClient; import java.util.List; @@ -11,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; - +@ActiveProfiles("h2") class ChatGPTServiceTest { @InjectMocks diff --git a/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java b/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java index 0e0e3c0..020a23f 100644 --- a/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java +++ b/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java @@ -8,13 +8,15 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.*; +import org.springframework.test.context.ActiveProfiles; + import java.time.LocalDate; import java.util.Date; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; - +@ActiveProfiles("h2") class StatisticsServiceTest { @Mock diff --git a/src/test/java/com/smartcalendar/service/UserServiceTest.java b/src/test/java/com/smartcalendar/service/UserServiceTest.java index 1cf23b3..3bea46a 100644 --- a/src/test/java/com/smartcalendar/service/UserServiceTest.java +++ b/src/test/java/com/smartcalendar/service/UserServiceTest.java @@ -8,6 +8,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.context.ActiveProfiles; import java.util.Optional; import java.util.Collections; @@ -15,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; - +@ActiveProfiles("h2") class UserServiceTest { @Mock