View Javadoc
1   package org.petify.backend.models;
2   
3   import com.fasterxml.jackson.annotation.JsonIgnore;
4   import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5   import com.fasterxml.jackson.annotation.JsonManagedReference;
6   import jakarta.persistence.CascadeType;
7   import jakarta.persistence.Column;
8   import jakarta.persistence.Entity;
9   import jakarta.persistence.EnumType;
10  import jakarta.persistence.Enumerated;
11  import jakarta.persistence.FetchType;
12  import jakarta.persistence.GeneratedValue;
13  import jakarta.persistence.GenerationType;
14  import jakarta.persistence.Id;
15  import jakarta.persistence.JoinColumn;
16  import jakarta.persistence.JoinTable;
17  import jakarta.persistence.Lob;
18  import jakarta.persistence.ManyToMany;
19  import jakarta.persistence.OneToMany;
20  import jakarta.persistence.Table;
21  import jakarta.persistence.Transient;
22  import jakarta.persistence.Version;
23  import lombok.Getter;
24  import lombok.Setter;
25  import org.springframework.security.core.GrantedAuthority;
26  import org.springframework.security.core.userdetails.UserDetails;
27  
28  import java.time.LocalDate;
29  import java.time.LocalDateTime;
30  import java.util.Collection;
31  import java.util.HashSet;
32  import java.util.Set;
33  
34  @Getter
35  @Setter
36  @Entity
37  @Table(name = "users")
38  @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
39  public class ApplicationUser implements UserDetails {
40      @Id
41      @GeneratedValue(strategy = GenerationType.IDENTITY)
42      private Integer userId;
43  
44      @Column(unique = true)
45      private String username;
46  
47      private String password;
48  
49      @Column(name = "first_name")
50      private String firstName;
51  
52      @Column(name = "last_name")
53      private String lastName;
54  
55      @Column(name = "birth_date")
56      private LocalDate birthDate;
57  
58      @Column(name = "gender")
59      private String gender;
60  
61      @Column(name = "phone_number", unique = true)
62      private String phoneNumber;
63  
64      @Column(name = "email", unique = true)
65      private String email;
66  
67      @Enumerated(EnumType.STRING)
68      @Column(name = "volunteer_status")
69      private VolunteerStatus volunteerStatus = VolunteerStatus.NONE;
70  
71      @Column(name = "active")
72      private boolean active = true;
73  
74      @Column(name = "deactivation_reason")
75      private String deactivationReason;
76  
77      @Column(name = "created_at")
78      private LocalDateTime createdAt = LocalDateTime.now();
79  
80      @Column(name = "xp_points")
81      private Integer xpPoints = 0;
82  
83      @Column(name = "level")
84      private Integer level = 1;
85  
86      @Column(name = "likes_count")
87      private Integer likesCount = 0;
88  
89      @Column(name = "support_count")
90      private Integer supportCount = 0;
91  
92      @Column(name = "badges_count")
93      private Integer badgesCount = 0;
94  
95      @Column(name = "adoption_count")
96      private Integer adoptionCount = 0;
97  
98      @Column(name = "city")
99      private String city;
100 
101     @Column(name = "latitude")
102     private Double latitude;
103 
104     @Column(name = "longitude")
105     private Double longitude;
106 
107     @Column(name = "preferred_search_distance_km")
108     private Double preferredSearchDistanceKm = 20.0;
109 
110     @Column(name = "auto_location_enabled")
111     private Boolean autoLocationEnabled = false;
112 
113     @Column(name = "location_updated_at")
114     private LocalDateTime locationUpdatedAt;
115 
116     @Column(name = "profile_image")
117     @Lob
118     @JsonIgnore
119     private byte[] profileImage;
120 
121     @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
122     @JsonManagedReference
123     private Set<UserAchievement> achievements = new HashSet<>();
124 
125     @ManyToMany(fetch = FetchType.EAGER)
126     @JoinTable(
127             name = "user_role_junction",
128             joinColumns = {@JoinColumn(name = "user_id")},
129             inverseJoinColumns = {@JoinColumn(name = "role_id")}
130     )
131     private Set<Role> authorities;
132 
133     @Version
134     private Integer version = 0;
135 
136     @Transient
137     public Integer getXpToNextLevel() {
138         int currentLevel = this.level != null ? this.level : 1;
139         int currentXp = this.xpPoints != null ? this.xpPoints : 0;
140 
141         int xpRequiredForNextLevel = currentLevel * 100;
142 
143         return Math.max(0, xpRequiredForNextLevel - currentXp);
144     }
145 
146     @Transient
147     public boolean hasLocation() {
148         return latitude != null && longitude != null;
149     }
150 
151     @Transient
152     public boolean hasCompleteLocationProfile() {
153         return city != null && !city.trim().isEmpty() && hasLocation();
154     }
155 
156     @Transient
157     @JsonIgnore
158     public boolean hasProfileImage() {
159         try {
160             return profileImage != null && profileImage.length > 0;
161         } catch (Exception e) {
162             return false;
163         }
164     }
165 
166     public void setLocation(String city, Double latitude, Double longitude) {
167         this.city = city;
168         this.latitude = latitude;
169         this.longitude = longitude;
170         this.locationUpdatedAt = LocalDateTime.now();
171     }
172 
173     public void clearLocation() {
174         this.city = null;
175         this.latitude = null;
176         this.longitude = null;
177         this.locationUpdatedAt = null;
178     }
179 
180     public ApplicationUser() {
181         super();
182         authorities = new HashSet<>();
183     }
184 
185     public ApplicationUser(Integer userId, String username, String password,
186                            String firstName, String lastName, LocalDate birthDate,
187                            String gender, String phoneNumber, String email, Set<Role> authorities) {
188         super();
189         this.userId = userId;
190         this.username = username;
191         this.password = password;
192         this.firstName = firstName;
193         this.lastName = lastName;
194         this.birthDate = birthDate;
195         this.gender = gender;
196         this.phoneNumber = phoneNumber;
197         this.email = email;
198         this.authorities = authorities;
199     }
200 
201     @Override
202     public Collection<? extends GrantedAuthority> getAuthorities() {
203         return this.authorities;
204     }
205 
206     @Override
207     public String getPassword() {
208         return this.password;
209     }
210 
211     @Override
212     public String getUsername() {
213         return this.username;
214     }
215 
216     @Override
217     public boolean isAccountNonExpired() {
218         return true;
219     }
220 
221     @Override
222     public boolean isAccountNonLocked() {
223         return true;
224     }
225 
226     @Override
227     public boolean isCredentialsNonExpired() {
228         return true;
229     }
230 
231     @Override
232     public boolean isEnabled() {
233         return true;
234     }
235 }