added push notifications

This commit is contained in:
2026-06-03 19:13:56 +02:00
parent a9278b8269
commit 6559a9cd4b
24 changed files with 1598 additions and 557 deletions
+2 -1
View File
@@ -39,7 +39,8 @@ dependencies {
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.13.0")
implementation("io.jsonwebtoken:jjwt-api:0.13.0")
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.13.0")
implementation("org.projectlombok:lombok:1.18.42")
annotationProcessor 'org.projectlombok:lombok:1.18.42'
implementation 'com.google.firebase:firebase-admin:9.9.0'
}
+1 -1
View File
@@ -37,7 +37,7 @@ CREATE TABLE IF NOT EXISTS public.subjects
CONSTRAINT subjects_pkey PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS public."user-subject"
CREATE TABLE IF NOT EXISTS public."user_subject"
(
user_id uuid NOT NULL,
subject_id uuid NOT NULL,
@@ -1,45 +1,42 @@
package dev.ksan.etfoglasiserver.controller;
import dev.ksan.etfoglasiserver.model.DeviceToken;
import dev.ksan.etfoglasiserver.model.RegisterTokenRequest;
import dev.ksan.etfoglasiserver.model.User;
import dev.ksan.etfoglasiserver.repository.DeviceTokenRepo;
import dev.ksan.etfoglasiserver.repository.UserRepo;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
@RestController
@RequestMapping("/api/device-tokens")
@RequiredArgsConstructor
public class DeviceTokenController {
@Autowired
private DeviceTokenRepo deviceTokenRepo;
@Autowired
private UserRepo userRepo;
private final DeviceTokenRepo deviceTokenRepo;
private final UserRepo userRepo;
@PostMapping("/register")
public ResponseEntity<?> register(
@RequestParam UUID userId,
@RequestParam String token
) {
@RequestBody RegisterTokenRequest request,
@AuthenticationPrincipal UserDetails principal) {
User user = userRepo.findById(userId)
User user = userRepo.findByEmail(principal.getUsername())
.orElseThrow(() -> new RuntimeException("User not found"));
DeviceToken deviceToken = deviceTokenRepo
.findByFcmToken(token)
.findByFcmToken(request.getToken())
.orElse(new DeviceToken());
deviceToken.setUser(user);
deviceToken.setFcmToken(token);
deviceToken.setFcmToken(request.getToken());
deviceTokenRepo.save(deviceToken);
return ResponseEntity.ok("Token saved");
return ResponseEntity.noContent().build();
}
}
@@ -4,8 +4,11 @@ import dev.ksan.etfoglasiserver.dto.JwtResponseDTO;
import dev.ksan.etfoglasiserver.dto.UserCreationDTO;
import dev.ksan.etfoglasiserver.dto.UserDTO;
import dev.ksan.etfoglasiserver.dto.UserLoginDTO;
import dev.ksan.etfoglasiserver.model.NotificationMethod;
import dev.ksan.etfoglasiserver.model.User;
import dev.ksan.etfoglasiserver.service.UserService;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@@ -22,13 +25,11 @@ public class UserController {
@GetMapping("users/me")
public ResponseEntity<UserDTO> getUserById(Authentication authentication) {
String email = authentication.getName();
User user = service.getAccountByEmail(email)
.orElseThrow(() -> new RuntimeException("User not found"));
User user = service.getAccountByEmail(email).orElseThrow(() -> new RuntimeException("User not found"));
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return ResponseEntity.ok(new UserDTO(user));
}
@PutMapping("/users/me")
@@ -43,6 +44,20 @@ public class UserController {
return ResponseEntity.ok(userUpdated);
}
@PostMapping("users/me/notification-type")
public ResponseEntity<?> updateNotificationType(
@RequestBody Map<String, String> request,
Authentication authentication) {
String email = authentication.getName();
NotificationMethod type = NotificationMethod.valueOf(request.get("notificationType"));
service.updateNotificationType(email, type);
return ResponseEntity.ok(Map.of("status", "updated"));
}
@PutMapping("/users/me/subjects/{subjectId}")
public ResponseEntity<UserDTO> addSubject(
@PathVariable UUID subjectId,
@@ -83,6 +98,8 @@ public class UserController {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
@DeleteMapping("/users/me")
public ResponseEntity<Void> deleteUser(Authentication authentication) {
@@ -3,14 +3,25 @@ package dev.ksan.etfoglasiserver.dto;
import dev.ksan.etfoglasiserver.model.NotificationMethod;
import dev.ksan.etfoglasiserver.model.Subject;
import dev.ksan.etfoglasiserver.model.User;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;
import java.util.UUID;
public class UserDTO {
@Setter
@Getter
private UUID id;
@Setter
@Getter
private String email;
@Setter
@Getter
private Set<Subject> subjectSet;
@Getter
@Setter
private NotificationMethod notificationType;
public UserDTO() {}
@@ -19,38 +30,17 @@ public class UserDTO {
this.id = id;
this.email = email;
this.subjectSet = subjectSet;
this.notificationType = notificationMethod2;
}
public UserDTO(User user) {
this.id = user.getId();
this.email = user.getEmail();
this.subjectSet = user.getSubjectSet();
this.notificationType = user.getNotificationMethod();
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<Subject> getSubjectSet() {
return subjectSet;
}
public void setSubjectSet(Set<Subject> subjectSet) {
this.subjectSet = subjectSet;
}
}
@@ -7,6 +7,7 @@ import lombok.Setter;
import java.time.LocalDateTime;
import java.util.UUID;
@Getter // ← add class-level getter
@Entity
@Table(
name = "device_tokens",
@@ -25,7 +26,6 @@ public class DeviceToken {
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Getter
@Setter
@Column(name = "fcm_token", nullable = false)
private String fcmToken;
@@ -38,5 +38,4 @@ public class DeviceToken {
public void touch() {
this.updatedAt = LocalDateTime.now();
}
}
@@ -3,6 +3,5 @@ package dev.ksan.etfoglasiserver.model;
public enum NotificationMethod {
NO_NOTIFICATION,
EMAIL,
PUSH_NOTIFICATION
}
@@ -0,0 +1,8 @@
package dev.ksan.etfoglasiserver.model;
import lombok.Data;
@Data
public class RegisterTokenRequest {
private String token;
}
@@ -1,6 +1,8 @@
package dev.ksan.etfoglasiserver.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;
import java.util.UUID;
@@ -9,13 +11,18 @@ import java.util.UUID;
@Table(name = "subjects")
public class Subject {
@Getter
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(columnDefinition = "uuid")
private UUID id;
@Getter
@Setter
@Column private long code;
@Getter
@Setter
@Column(nullable = false)
private String name;
@@ -26,23 +33,4 @@ public class Subject {
public Subject(){
}
public UUID getId() {
return id;
}
public long getCode() {
return code;
}
public void setCode(long code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -9,6 +9,8 @@ import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Setter;
import java.util.UUID;
@Entity
@@ -18,9 +20,11 @@ public class SubjectAlt {
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@Setter
@Column(nullable = false)
String name;
@Setter
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(nullable = false)
private Subject subject;
@@ -32,22 +36,15 @@ public class SubjectAlt {
}
public UUID getId() {
return id;
return this.id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
return this.name;
}
public Subject getSubject() {
return subject;
return this.subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
@@ -43,6 +43,8 @@ public class EntryService {
Entry newEntry = new Entry(entry);
newEntry.setSubject(subject);
entryRepo.save(newEntry);
subjectService.notifyAsync(newEntry);
}
public void addEntry(Entry entry) {
@@ -4,6 +4,7 @@ import dev.ksan.etfoglasiserver.dto.JwtResponseDTO;
import dev.ksan.etfoglasiserver.dto.UserCreationDTO;
import dev.ksan.etfoglasiserver.dto.UserDTO;
import dev.ksan.etfoglasiserver.dto.UserLoginDTO;
import dev.ksan.etfoglasiserver.model.NotificationMethod;
import dev.ksan.etfoglasiserver.model.Subject;
import dev.ksan.etfoglasiserver.model.User;
import dev.ksan.etfoglasiserver.repository.SubjectRepo;
@@ -204,4 +205,11 @@ public class UserService {
return getUserDTO(user);
}
public void updateNotificationType(String email, NotificationMethod notificationType) {
User user = userRepo.findByEmail(email).orElseThrow(() -> new RuntimeException("User not found"));
user.setNotificationMethod(notificationType);
userRepo.save(user);
}
}