From 3ae4fcdfc16d6ca6e695ce564040a5ac90f09ce6 Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 12 Apr 2025 11:36:35 +0300 Subject: [PATCH 01/14] add all planned entities and many_to_one dependencies --- .../java/com/smartcalendar/model/Event.java | 10 ++++-- .../com/smartcalendar/model/GroupChat.java | 30 ++++++++++++++++ .../com/smartcalendar/model/GroupMessage.java | 36 +++++++++++++++++++ .../com/smartcalendar/model/PrivateChat.java | 35 ++++++++++++++++++ .../smartcalendar/model/PrivateMessage.java | 36 +++++++++++++++++++ .../java/com/smartcalendar/model/Tag.java | 21 +++++++++++ .../java/com/smartcalendar/model/Task.java | 6 +++- .../java/com/smartcalendar/model/User.java | 24 +++++++++++++ 8 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/smartcalendar/model/GroupChat.java create mode 100644 src/main/java/com/smartcalendar/model/GroupMessage.java create mode 100644 src/main/java/com/smartcalendar/model/PrivateChat.java create mode 100644 src/main/java/com/smartcalendar/model/PrivateMessage.java create mode 100644 src/main/java/com/smartcalendar/model/Tag.java diff --git a/src/main/java/com/smartcalendar/model/Event.java b/src/main/java/com/smartcalendar/model/Event.java index b6a716d..4ef27fe 100644 --- a/src/main/java/com/smartcalendar/model/Event.java +++ b/src/main/java/com/smartcalendar/model/Event.java @@ -1,5 +1,6 @@ package com.smartcalendar.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -17,17 +18,20 @@ public class Event { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column private String title; - @Column(name = "end_time") - private LocalDateTime end; - @Column(name = "start_time") private LocalDateTime start; + @Column(name = "end_time") + private LocalDateTime end; + + @Column private String location; @ManyToOne @JoinColumn(name = "organizer_id") + @JsonBackReference private User organizer; } \ No newline at end of file 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..1390d8d --- /dev/null +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -0,0 +1,30 @@ +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; + +@Entity +@Data +@Table(name = "group_chats") +@NoArgsConstructor +@AllArgsConstructor +public class GroupChat { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "admin_id") + @JsonBackReference + private User admin; + + @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List messages; +} 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..da2b1ce --- /dev/null +++ b/src/main/java/com/smartcalendar/model/GroupMessage.java @@ -0,0 +1,36 @@ +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; + +@Entity +@Data +@Table(name = "group_messages") +@NoArgsConstructor +@AllArgsConstructor +public class GroupMessage { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column + private String text; + + @Column(name = "time") + private LocalDateTime timeWhenSent; + + @ManyToOne + @JoinColumn(name = "chat_id") + @JsonBackReference + private GroupChat chat; + + @ManyToOne + @JoinColumn(name = "user_id") + @JsonBackReference + 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..432ee26 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/PrivateChat.java @@ -0,0 +1,35 @@ +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; + +@Entity +@Data +@Table(name = "private_chats") +@NoArgsConstructor +@AllArgsConstructor +public class PrivateChat { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "user_id1") + @JsonBackReference + private User user1; + + @ManyToOne + @JoinColumn(name = "user_id2") + @JsonBackReference + private User user2; + + @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + 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..96693e5 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/PrivateMessage.java @@ -0,0 +1,36 @@ +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; + +@Entity +@Data +@Table(name = "private_messages") +@NoArgsConstructor +@AllArgsConstructor +public class PrivateMessage { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column + private String text; + + @Column(name = "time") + private LocalDateTime timeWhenSent; + + @ManyToOne + @JoinColumn(name = "chat_id") + @JsonBackReference + private PrivateChat chat; + + @ManyToOne + @JoinColumn(name = "user_id") + @JsonBackReference + 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..4f19da9 --- /dev/null +++ b/src/main/java/com/smartcalendar/model/Tag.java @@ -0,0 +1,21 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Data +@Table(name = "tags") +@NoArgsConstructor +@AllArgsConstructor +public class Tag { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column + private String title; +} diff --git a/src/main/java/com/smartcalendar/model/Task.java b/src/main/java/com/smartcalendar/model/Task.java index 68ea00c..cb7ffad 100644 --- a/src/main/java/com/smartcalendar/model/Task.java +++ b/src/main/java/com/smartcalendar/model/Task.java @@ -9,6 +9,7 @@ @Entity @Data +@Table(name = "tasks") @NoArgsConstructor @AllArgsConstructor public class Task { @@ -16,9 +17,12 @@ public class Task { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column private String title; + @Column private String description; - private boolean completed; + @Column + private boolean isCompleted; @ManyToOne @JoinColumn(name = "user_id") diff --git a/src/main/java/com/smartcalendar/model/User.java b/src/main/java/com/smartcalendar/model/User.java index c6cd1d7..403fbec 100644 --- a/src/main/java/com/smartcalendar/model/User.java +++ b/src/main/java/com/smartcalendar/model/User.java @@ -37,6 +37,30 @@ public class User implements UserDetails { @JsonManagedReference private List tasks; + @OneToMany(mappedBy = "organizer", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List events; + + @OneToMany(mappedBy = "admin", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List chatsWithAdminRights; + + @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List privateChats1; + + @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List privateChats2; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List groupMessages; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List privateMessages; + @Override public Collection getAuthorities() { return Collections.emptyList(); From fe9e3a35478ffbb6a8fdf6b26e2cd1c80e53c3f9 Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 12 Apr 2025 12:02:52 +0300 Subject: [PATCH 02/14] add trivial many to many dependencies --- .../java/com/smartcalendar/model/Event.java | 15 ++++++++++++++ .../com/smartcalendar/model/GroupChat.java | 4 ++++ .../java/com/smartcalendar/model/Tag.java | 6 ++++++ .../java/com/smartcalendar/model/User.java | 20 ++++++++++++++++++- 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/smartcalendar/model/Event.java b/src/main/java/com/smartcalendar/model/Event.java index 4ef27fe..65a82a1 100644 --- a/src/main/java/com/smartcalendar/model/Event.java +++ b/src/main/java/com/smartcalendar/model/Event.java @@ -1,12 +1,14 @@ 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.time.LocalDateTime; +import java.util.List; @Entity @Table(name = "events") @@ -34,4 +36,17 @@ public class Event { @JoinColumn(name = "organizer_id") @JsonBackReference private User organizer; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "events_tags", + joinColumns = @JoinColumn(name = "event_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id") + ) + @JsonManagedReference + private List tags; + + @ManyToMany(mappedBy = "events", fetch = FetchType.LAZY) + @JsonBackReference + private List users; } \ No newline at end of file diff --git a/src/main/java/com/smartcalendar/model/GroupChat.java b/src/main/java/com/smartcalendar/model/GroupChat.java index 1390d8d..ecc5c37 100644 --- a/src/main/java/com/smartcalendar/model/GroupChat.java +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -27,4 +27,8 @@ public class GroupChat { @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) @JsonManagedReference private List messages; + + @ManyToMany(mappedBy = "group_chats", fetch = FetchType.LAZY) + @JsonBackReference + private List users; } diff --git a/src/main/java/com/smartcalendar/model/Tag.java b/src/main/java/com/smartcalendar/model/Tag.java index 4f19da9..ca240a8 100644 --- a/src/main/java/com/smartcalendar/model/Tag.java +++ b/src/main/java/com/smartcalendar/model/Tag.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Entity @Data @Table(name = "tags") @@ -18,4 +20,8 @@ public class Tag { @Column private String title; + + @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY) + @JsonBackReference + private List events; } diff --git a/src/main/java/com/smartcalendar/model/User.java b/src/main/java/com/smartcalendar/model/User.java index 403fbec..92a9985 100644 --- a/src/main/java/com/smartcalendar/model/User.java +++ b/src/main/java/com/smartcalendar/model/User.java @@ -39,7 +39,7 @@ public class User implements UserDetails { @OneToMany(mappedBy = "organizer", cascade = CascadeType.ALL, orphanRemoval = true) @JsonManagedReference - private List events; + private List organized_events; @OneToMany(mappedBy = "admin", cascade = CascadeType.ALL, orphanRemoval = true) @JsonManagedReference @@ -61,6 +61,24 @@ public class User implements UserDetails { @JsonManagedReference private List privateMessages; + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "users_events", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "event_id") + ) + @JsonManagedReference + private List events; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "users_group_chats", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "chat_id") + ) + @JsonManagedReference + private List groupChats; + @Override public Collection getAuthorities() { return Collections.emptyList(); From bb18a2dd1b5d51e5cfd897de446c210f0f6a9fbc Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 12 Apr 2025 12:04:00 +0300 Subject: [PATCH 03/14] fix --- src/main/java/com/smartcalendar/model/GroupChat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/smartcalendar/model/GroupChat.java b/src/main/java/com/smartcalendar/model/GroupChat.java index ecc5c37..b76831c 100644 --- a/src/main/java/com/smartcalendar/model/GroupChat.java +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -28,7 +28,7 @@ public class GroupChat { @JsonManagedReference private List messages; - @ManyToMany(mappedBy = "group_chats", fetch = FetchType.LAZY) + @ManyToMany(mappedBy = "groupChats", fetch = FetchType.LAZY) @JsonBackReference private List users; } From 7677173e86f9c15c905d2dac67ac579c83d08ee7 Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 12 Apr 2025 12:15:07 +0300 Subject: [PATCH 04/14] add friendships --- .../com/smartcalendar/model/Friendship.java | 28 +++++++++++++++++++ .../java/com/smartcalendar/model/User.java | 8 ++++++ 2 files changed, 36 insertions(+) create mode 100644 src/main/java/com/smartcalendar/model/Friendship.java 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..21842cf --- /dev/null +++ b/src/main/java/com/smartcalendar/model/Friendship.java @@ -0,0 +1,28 @@ +package com.smartcalendar.model; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Data +@Table(name = "friendships") +@NoArgsConstructor +@AllArgsConstructor +public class Friendship { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "user_id1") + @JsonBackReference + private User user1; + + @ManyToOne + @JoinColumn(name = "user_id2") + @JsonBackReference + private User user2; +} diff --git a/src/main/java/com/smartcalendar/model/User.java b/src/main/java/com/smartcalendar/model/User.java index 92a9985..5caed44 100644 --- a/src/main/java/com/smartcalendar/model/User.java +++ b/src/main/java/com/smartcalendar/model/User.java @@ -61,6 +61,14 @@ public class User implements UserDetails { @JsonManagedReference private List privateMessages; + @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List friendships1; + + @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List friendships2; + @ManyToMany(fetch = FetchType.LAZY) @JoinTable( name = "users_events", From e707331917fc8cab1d55858de63e58b07eba0172 Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 12 Apr 2025 13:12:57 +0300 Subject: [PATCH 05/14] add all tables in schema.sql --- .../com/smartcalendar/model/GroupMessage.java | 2 +- .../smartcalendar/model/PrivateMessage.java | 2 +- src/main/resources/schema.sql | 55 +++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/smartcalendar/model/GroupMessage.java b/src/main/java/com/smartcalendar/model/GroupMessage.java index da2b1ce..758717c 100644 --- a/src/main/java/com/smartcalendar/model/GroupMessage.java +++ b/src/main/java/com/smartcalendar/model/GroupMessage.java @@ -21,7 +21,7 @@ public class GroupMessage { @Column private String text; - @Column(name = "time") + @Column(name = "time_sent") private LocalDateTime timeWhenSent; @ManyToOne diff --git a/src/main/java/com/smartcalendar/model/PrivateMessage.java b/src/main/java/com/smartcalendar/model/PrivateMessage.java index 96693e5..c3b1d77 100644 --- a/src/main/java/com/smartcalendar/model/PrivateMessage.java +++ b/src/main/java/com/smartcalendar/model/PrivateMessage.java @@ -21,7 +21,7 @@ public class PrivateMessage { @Column private String text; - @Column(name = "time") + @Column(name = "time_sent") private LocalDateTime timeWhenSent; @ManyToOne diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 0971f93..ee7327c 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -3,4 +3,59 @@ CREATE TABLE IF NOT EXISTS users ( username VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL +); + +CREATE TABLE IF NOT EXISTS events ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + location VARCHAR(255) NOT NULL, + FOREIGN KEY (organizer_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS tasks ( + id BIGINT AUTO_INCREMENT 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL +); + +CREATE TABLE IF NOT EXISTS group_chats ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + FOREIGN KEY (admin_id) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS group_messages ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + FOREIGN KEY (user_id1) REFERENCES users (id), + FOREIGN KEY (user_id2) REFERENCES users (id) +); + +CREATE TABLE IF NOT EXISTS private_messages ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + FOREIGN KEY (user_id1) REFERENCES users (id), + FOREIGN KEY (user_id2) REFERENCES users (id) ); \ No newline at end of file From 4a8e29e77aa45929e7faf4660faf701dff5e0f29 Mon Sep 17 00:00:00 2001 From: minmise Date: Tue, 10 Jun 2025 20:02:01 +0300 Subject: [PATCH 06/14] fix bug with json references --- .../java/com/smartcalendar/model/Event.java | 10 +++++--- .../com/smartcalendar/model/Friendship.java | 4 +-- .../com/smartcalendar/model/GroupChat.java | 8 +++--- .../com/smartcalendar/model/GroupMessage.java | 4 +-- .../com/smartcalendar/model/PrivateChat.java | 6 ++--- .../smartcalendar/model/PrivateMessage.java | 4 +-- .../java/com/smartcalendar/model/Tag.java | 4 ++- .../java/com/smartcalendar/model/Task.java | 2 +- .../java/com/smartcalendar/model/User.java | 25 +++++++++++-------- 9 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/smartcalendar/model/Event.java b/src/main/java/com/smartcalendar/model/Event.java index 65a82a1..aa6569e 100644 --- a/src/main/java/com/smartcalendar/model/Event.java +++ b/src/main/java/com/smartcalendar/model/Event.java @@ -1,7 +1,9 @@ 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; @@ -34,7 +36,7 @@ public class Event { @ManyToOne @JoinColumn(name = "organizer_id") - @JsonBackReference + @JsonBackReference(value = "organized_events") private User organizer; @ManyToMany(fetch = FetchType.LAZY) @@ -43,10 +45,12 @@ public class Event { joinColumns = @JoinColumn(name = "event_id"), inverseJoinColumns = @JoinColumn(name = "tag_id") ) - @JsonManagedReference + //@JsonManagedReference(value = "event_tags") + @JsonProperty("tags") private List tags; @ManyToMany(mappedBy = "events", fetch = FetchType.LAZY) - @JsonBackReference + //@JsonBackReference(value = "personal_events") + @JsonIgnore private List users; } \ 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 index 21842cf..2aefa58 100644 --- a/src/main/java/com/smartcalendar/model/Friendship.java +++ b/src/main/java/com/smartcalendar/model/Friendship.java @@ -18,11 +18,11 @@ public class Friendship { @ManyToOne @JoinColumn(name = "user_id1") - @JsonBackReference + @JsonBackReference(value = "friends1") private User user1; @ManyToOne @JoinColumn(name = "user_id2") - @JsonBackReference + @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 index b76831c..ca3231f 100644 --- a/src/main/java/com/smartcalendar/model/GroupChat.java +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -1,6 +1,7 @@ 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; @@ -21,14 +22,15 @@ public class GroupChat { @ManyToOne @JoinColumn(name = "admin_id") - @JsonBackReference + @JsonBackReference(value = "admin_chats") private User admin; @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "messages_in_group_chat") private List messages; @ManyToMany(mappedBy = "groupChats", fetch = FetchType.LAZY) - @JsonBackReference + //@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 index 758717c..53a31c4 100644 --- a/src/main/java/com/smartcalendar/model/GroupMessage.java +++ b/src/main/java/com/smartcalendar/model/GroupMessage.java @@ -26,11 +26,11 @@ public class GroupMessage { @ManyToOne @JoinColumn(name = "chat_id") - @JsonBackReference + @JsonBackReference(value = "messages_in_group_chat") private GroupChat chat; @ManyToOne @JoinColumn(name = "user_id") - @JsonBackReference + @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 index 432ee26..f026774 100644 --- a/src/main/java/com/smartcalendar/model/PrivateChat.java +++ b/src/main/java/com/smartcalendar/model/PrivateChat.java @@ -21,15 +21,15 @@ public class PrivateChat { @ManyToOne @JoinColumn(name = "user_id1") - @JsonBackReference + @JsonBackReference(value = "chats1") private User user1; @ManyToOne @JoinColumn(name = "user_id2") - @JsonBackReference + @JsonBackReference(value = "chats2") private User user2; @OneToMany(mappedBy = "chat", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @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 index c3b1d77..fea5877 100644 --- a/src/main/java/com/smartcalendar/model/PrivateMessage.java +++ b/src/main/java/com/smartcalendar/model/PrivateMessage.java @@ -26,11 +26,11 @@ public class PrivateMessage { @ManyToOne @JoinColumn(name = "chat_id") - @JsonBackReference + @JsonBackReference(value = "messages_in_private_chat") private PrivateChat chat; @ManyToOne @JoinColumn(name = "user_id") - @JsonBackReference + @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 index ca240a8..c78a58b 100644 --- a/src/main/java/com/smartcalendar/model/Tag.java +++ b/src/main/java/com/smartcalendar/model/Tag.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; @@ -22,6 +23,7 @@ public class Tag { private String title; @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY) - @JsonBackReference + //@JsonBackReference(value = "event_tags") + @JsonIgnore private List events; } diff --git a/src/main/java/com/smartcalendar/model/Task.java b/src/main/java/com/smartcalendar/model/Task.java index cb7ffad..3356a39 100644 --- a/src/main/java/com/smartcalendar/model/Task.java +++ b/src/main/java/com/smartcalendar/model/Task.java @@ -26,6 +26,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 5caed44..647600e 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; @@ -34,39 +35,39 @@ public class User implements UserDetails { private String password; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "user_tasks") private List tasks; @OneToMany(mappedBy = "organizer", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "organized_events") private List organized_events; @OneToMany(mappedBy = "admin", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "admin_chats") private List chatsWithAdminRights; @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "chats1") private List privateChats1; @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "chats2") private List privateChats2; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "group_message_author") private List groupMessages; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "private_message_author") private List privateMessages; @OneToMany(mappedBy = "user1", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "friends1") private List friendships1; @OneToMany(mappedBy = "user2", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference + @JsonManagedReference(value = "friends2") private List friendships2; @ManyToMany(fetch = FetchType.LAZY) @@ -75,7 +76,8 @@ public class User implements UserDetails { joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "event_id") ) - @JsonManagedReference + //@JsonManagedReference(value = "personal_events") + @JsonProperty("events") private List events; @ManyToMany(fetch = FetchType.LAZY) @@ -84,7 +86,8 @@ public class User implements UserDetails { joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "chat_id") ) - @JsonManagedReference + //@JsonManagedReference(value = "common_chats") + @JsonProperty("group_chats") private List groupChats; @Override From dcbcdcafcfe51d71a11e197e69969c7b05d50ac2 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 12:11:10 +0300 Subject: [PATCH 07/14] change sql syntax from H2 to PostgreSQL and add some UUID --- .../com/smartcalendar/model/Friendship.java | 6 ++-- .../com/smartcalendar/model/GroupChat.java | 5 ++-- .../com/smartcalendar/model/GroupMessage.java | 7 +++-- .../com/smartcalendar/model/PrivateChat.java | 5 ++-- .../smartcalendar/model/PrivateMessage.java | 7 +++-- .../java/com/smartcalendar/model/Tag.java | 5 ++-- src/main/resources/application.properties | 19 +++++++----- src/main/resources/schema.sql | 30 +++++++++++-------- 8 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/smartcalendar/model/Friendship.java b/src/main/java/com/smartcalendar/model/Friendship.java index 2aefa58..418ce00 100644 --- a/src/main/java/com/smartcalendar/model/Friendship.java +++ b/src/main/java/com/smartcalendar/model/Friendship.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.UUID; + @Entity @Data @Table(name = "friendships") @@ -13,8 +15,8 @@ @AllArgsConstructor public class Friendship { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @ManyToOne @JoinColumn(name = "user_id1") diff --git a/src/main/java/com/smartcalendar/model/GroupChat.java b/src/main/java/com/smartcalendar/model/GroupChat.java index ca3231f..0b25f86 100644 --- a/src/main/java/com/smartcalendar/model/GroupChat.java +++ b/src/main/java/com/smartcalendar/model/GroupChat.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import java.util.List; +import java.util.UUID; @Entity @Data @@ -17,8 +18,8 @@ @AllArgsConstructor public class GroupChat { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @ManyToOne @JoinColumn(name = "admin_id") diff --git a/src/main/java/com/smartcalendar/model/GroupMessage.java b/src/main/java/com/smartcalendar/model/GroupMessage.java index 53a31c4..4cfd81b 100644 --- a/src/main/java/com/smartcalendar/model/GroupMessage.java +++ b/src/main/java/com/smartcalendar/model/GroupMessage.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.UUID; @Entity @Data @@ -15,11 +16,11 @@ @AllArgsConstructor public class GroupMessage { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @Column - private String text; + private String messageText; @Column(name = "time_sent") private LocalDateTime timeWhenSent; diff --git a/src/main/java/com/smartcalendar/model/PrivateChat.java b/src/main/java/com/smartcalendar/model/PrivateChat.java index f026774..29c9df7 100644 --- a/src/main/java/com/smartcalendar/model/PrivateChat.java +++ b/src/main/java/com/smartcalendar/model/PrivateChat.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import java.util.List; +import java.util.UUID; @Entity @Data @@ -16,8 +17,8 @@ @AllArgsConstructor public class PrivateChat { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @ManyToOne @JoinColumn(name = "user_id1") diff --git a/src/main/java/com/smartcalendar/model/PrivateMessage.java b/src/main/java/com/smartcalendar/model/PrivateMessage.java index fea5877..55933ca 100644 --- a/src/main/java/com/smartcalendar/model/PrivateMessage.java +++ b/src/main/java/com/smartcalendar/model/PrivateMessage.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.UUID; @Entity @Data @@ -15,11 +16,11 @@ @AllArgsConstructor public class PrivateMessage { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @Column - private String text; + private String messageText; @Column(name = "time_sent") private LocalDateTime timeWhenSent; diff --git a/src/main/java/com/smartcalendar/model/Tag.java b/src/main/java/com/smartcalendar/model/Tag.java index c78a58b..7ce4d19 100644 --- a/src/main/java/com/smartcalendar/model/Tag.java +++ b/src/main/java/com/smartcalendar/model/Tag.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import java.util.List; +import java.util.UUID; @Entity @Data @@ -16,8 +17,8 @@ @AllArgsConstructor public class Tag { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; + //@GeneratedValue(strategy = GenerationType.IDENTITY) + private UUID id; @Column private String title; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6f4a937..a8dc487 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=dokhru@gmail.com 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 ee7327c..d5542fb 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,12 +1,13 @@ 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + id BIGSERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, @@ -15,7 +16,7 @@ CREATE TABLE IF NOT EXISTS events ( ); CREATE TABLE IF NOT EXISTS tasks ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, + id BIGSERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, is_completed BOOLEAN, @@ -23,39 +24,44 @@ CREATE TABLE IF NOT EXISTS tasks ( ); CREATE TABLE IF NOT EXISTS tags ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, + id BIGSERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL ); CREATE TABLE IF NOT EXISTS group_chats ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, + id BIGSERIAL PRIMARY KEY, FOREIGN KEY (admin_id) REFERENCES users (id) ); CREATE TABLE IF NOT EXISTS group_messages ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - text VARCHAR(255) NOT NULL, + 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + 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 BIGINT AUTO_INCREMENT PRIMARY KEY, - text VARCHAR(255) NOT NULL, + 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 BIGINT AUTO_INCREMENT PRIMARY KEY, + 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 From 340655237dc598138785ff25c2708e26a985c2aa Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 12:56:04 +0300 Subject: [PATCH 08/14] change test profiles --- .../controller/AudioControllerIntegrationTest.java | 2 ++ .../controller/ChatGPTControllerIntegrationTest.java | 2 ++ .../java/com/smartcalendar/service/ChatGPTServiceTest.java | 3 ++- .../java/com/smartcalendar/service/StatisticsServiceTest.java | 4 +++- src/test/java/com/smartcalendar/service/UserServiceTest.java | 3 ++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java b/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java index aa8d869..b52c3c4 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("test") @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..383de7a 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("test") @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..c9b911e 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("test") 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..296086b 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("test") 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..c7544fd 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("test") class UserServiceTest { @Mock From f91f710c5864cbd9d95c0cd3719075b429e08ae8 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 12:59:22 +0300 Subject: [PATCH 09/14] change test db driver --- src/main/resources/application-test.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 8797063..e9cc23c 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,6 +1,7 @@ spring.main.allow-bean-definition-overriding=true spring.jpa.hibernate.ddl-auto=create-drop spring.datasource.url=jdbc:h2:mem:testdb_test +spring.datasource.driver-class-name=org.h2.Driver chatgpt.api.url=http://dummy-url chatgpt.api.key=dummy-key JWT_SECRET=your_test_secret \ No newline at end of file From 75cb41f75be62b271a55171f1666ae45af4191c3 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 13:45:37 +0300 Subject: [PATCH 10/14] null hibernate dialect in test --- src/main/resources/application-test.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index e9cc23c..b91251a 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -2,6 +2,7 @@ spring.main.allow-bean-definition-overriding=true spring.jpa.hibernate.ddl-auto=create-drop spring.datasource.url=jdbc:h2:mem:testdb_test spring.datasource.driver-class-name=org.h2.Driver +spring.jpa.properties.hibernate.dialect= chatgpt.api.url=http://dummy-url chatgpt.api.key=dummy-key JWT_SECRET=your_test_secret \ No newline at end of file From 1258ca99da21cc25333d829c3ff31380c81b8781 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 13:59:40 +0300 Subject: [PATCH 11/14] add one more profile for properties that can test on h2 database --- src/main/resources/application-test.properties | 13 ++++++++++--- src/main/resources/application.properties | 2 +- .../controller/AudioControllerIntegrationTest.java | 2 +- .../ChatGPTControllerIntegrationTest.java | 2 +- .../smartcalendar/service/ChatGPTServiceTest.java | 2 +- .../service/StatisticsServiceTest.java | 2 +- .../com/smartcalendar/service/UserServiceTest.java | 2 +- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index b91251a..9801217 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,8 +1,15 @@ spring.main.allow-bean-definition-overriding=true spring.jpa.hibernate.ddl-auto=create-drop spring.datasource.url=jdbc:h2:mem:testdb_test -spring.datasource.driver-class-name=org.h2.Driver -spring.jpa.properties.hibernate.dialect= 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 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a8dc487..9acbb95 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -68,7 +68,7 @@ chatgpt.api.key=${CHATGPT_API_KEY} # =============================== spring.mail.host=smtp.gmail.com spring.mail.port=587 -spring.mail.username=dokhru@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/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java b/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java index b52c3c4..99282cd 100644 --- a/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java +++ b/src/test/java/com/smartcalendar/controller/AudioControllerIntegrationTest.java @@ -28,7 +28,7 @@ "chatgpt.api.key=dummy-key", "spring.security.enabled=false" }) -@ActiveProfiles("test") +@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 383de7a..081bc73 100644 --- a/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java +++ b/src/test/java/com/smartcalendar/controller/ChatGPTControllerIntegrationTest.java @@ -26,7 +26,7 @@ "chatgpt.api.key=dummy-key", "spring.security.enabled=false" }) -@ActiveProfiles("test") +@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 c9b911e..28f339e 100644 --- a/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java +++ b/src/test/java/com/smartcalendar/service/ChatGPTServiceTest.java @@ -12,7 +12,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -@ActiveProfiles("test") +@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 296086b..020a23f 100644 --- a/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java +++ b/src/test/java/com/smartcalendar/service/StatisticsServiceTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -@ActiveProfiles("test") +@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 c7544fd..3bea46a 100644 --- a/src/test/java/com/smartcalendar/service/UserServiceTest.java +++ b/src/test/java/com/smartcalendar/service/UserServiceTest.java @@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -@ActiveProfiles("test") +@ActiveProfiles("h2") class UserServiceTest { @Mock From 96edf78ea8359b052b1b8eb6e6bf79a4d38adc39 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 14:04:23 +0300 Subject: [PATCH 12/14] null hibernate dialect in new profile --- src/main/resources/application-test.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 9801217..04ff572 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -12,4 +12,5 @@ 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 \ No newline at end of file +spring.jpa.defer-datasource-initialization=true +spring.jpa.properties.hibernate.dialect= \ No newline at end of file From 4409ae6b15fbe19aa4db374ba7aa94047a4c9556 Mon Sep 17 00:00:00 2001 From: minmise Date: Fri, 20 Jun 2025 14:10:42 +0300 Subject: [PATCH 13/14] change h2.props --- src/main/resources/application-h2.properties | 71 ++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/resources/application-h2.properties 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 From d420f237a78986a285bd88e498792398dff90f87 Mon Sep 17 00:00:00 2001 From: minmise Date: Sat, 21 Jun 2025 15:53:40 +0300 Subject: [PATCH 14/14] add api for getting event lists with relevance by tags --- .../smartcalendar/config/SecurityConfig.java | 1 + .../controller/EventController.java | 35 ++++++++++ .../java/com/smartcalendar/model/Event.java | 21 +++++- .../java/com/smartcalendar/model/Tag.java | 6 +- .../java/com/smartcalendar/model/User.java | 16 +++-- .../repository/EventRepository.java | 6 ++ .../smartcalendar/service/EventService.java | 65 +++++++++++++++++++ src/main/resources/schema.sql | 8 ++- 8 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/smartcalendar/controller/EventController.java create mode 100644 src/main/java/com/smartcalendar/service/EventService.java 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 be18d45..9cf3d4e 100644 --- a/src/main/java/com/smartcalendar/model/Event.java +++ b/src/main/java/com/smartcalendar/model/Event.java @@ -9,9 +9,11 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.time.Instant; import java.time.LocalDateTime; import java.util.List; import java.util.ArrayList; +import java.util.Map; import java.util.UUID; @Entity @@ -21,12 +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") @@ -35,7 +38,7 @@ public class Event { @Column(name = "end_time") private LocalDateTime end; - @Column + @Column(name = "event_location") private String location; @Enumerated(EnumType.STRING) @@ -58,8 +61,10 @@ public class Event { @JsonProperty("tags") private List tags; + @Column private boolean completed = false; + @Column private boolean isShared = false; @ElementCollection @@ -75,4 +80,16 @@ public class Event { ) @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/Tag.java b/src/main/java/com/smartcalendar/model/Tag.java index 7ce4d19..757a45d 100644 --- a/src/main/java/com/smartcalendar/model/Tag.java +++ b/src/main/java/com/smartcalendar/model/Tag.java @@ -18,7 +18,7 @@ public class Tag { @Id //@GeneratedValue(strategy = GenerationType.IDENTITY) - private UUID id; + private Long id; @Column private String title; @@ -27,4 +27,8 @@ public class Tag { //@JsonBackReference(value = "event_tags") @JsonIgnore private List events; + + public Long getId() { + return id; + } } diff --git a/src/main/java/com/smartcalendar/model/User.java b/src/main/java/com/smartcalendar/model/User.java index b6586cc..ea94434 100644 --- a/src/main/java/com/smartcalendar/model/User.java +++ b/src/main/java/com/smartcalendar/model/User.java @@ -10,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 @@ -81,7 +80,7 @@ public class User implements UserDetails { ) //@JsonManagedReference(value = "personal_events") @JsonProperty("events") - private List events; + private List events = new ArrayList<>(); @ManyToMany(fetch = FetchType.LAZY) @JoinTable( @@ -127,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/schema.sql b/src/main/resources/schema.sql index d5542fb..5818795 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -7,11 +7,15 @@ CREATE TABLE IF NOT EXISTS users ( ); CREATE TABLE IF NOT EXISTS events ( - id BIGSERIAL PRIMARY KEY, + id UUID PRIMARY KEY, title VARCHAR(255) NOT NULL, + description VARCHAR(255), start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL, - location VARCHAR(255) 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) );