commit before i break things
This commit is contained in:
@@ -30,6 +30,9 @@ backend/.db/
|
|||||||
backend/init/*
|
backend/init/*
|
||||||
backend/**/*temp.java
|
backend/**/*temp.java
|
||||||
|
|
||||||
|
backend/google-services.json
|
||||||
|
backend/etf-oglasi-firebase.json
|
||||||
|
|
||||||
# Java / Eclipse / STS
|
# Java / Eclipse / STS
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ dependencies {
|
|||||||
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.13.0")
|
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.13.0")
|
||||||
implementation("io.jsonwebtoken:jjwt-api:0.13.0")
|
implementation("io.jsonwebtoken:jjwt-api:0.13.0")
|
||||||
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.13.0")
|
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.13.0")
|
||||||
|
|
||||||
|
implementation 'com.google.firebase:firebase-admin:9.9.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
generateJava {
|
generateJava {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package dev.ksan.etfoglasiserver.config;
|
||||||
|
|
||||||
|
import com.google.auth.oauth2.GoogleCredentials;
|
||||||
|
import com.google.firebase.FirebaseApp;
|
||||||
|
import com.google.firebase.FirebaseOptions;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class FirebaseConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FirebaseApp firebaseApp() throws IOException {
|
||||||
|
GoogleCredentials credentials = GoogleCredentials
|
||||||
|
.fromStream(new ClassPathResource("etf-oglasi-firebase.json").getInputStream())
|
||||||
|
.createScoped(List.of("https://www.googleapis.com/auth/firebase.messaging"));
|
||||||
|
|
||||||
|
FirebaseOptions options = FirebaseOptions.builder()
|
||||||
|
.setCredentials(credentials)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (FirebaseApp.getApps().isEmpty()) {
|
||||||
|
return FirebaseApp.initializeApp(options);
|
||||||
|
}
|
||||||
|
return FirebaseApp.getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,13 +23,13 @@ public class SubjectAltController {
|
|||||||
return service.getSubjectAlt(subjectId);
|
return service.getSubjectAlt(subjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/subjectalt")
|
// @PostMapping("/subjectalt")
|
||||||
public void addSubject(@RequestBody SubjectAlt subject) {
|
// public void addSubject(@RequestBody SubjectAlt subject) {
|
||||||
service.addSubjectAlt(subject);
|
// service.addSubjectAlt(subject);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@DeleteMapping("/subjectalt/{subjectId}")
|
// @DeleteMapping("/subjectalt/{subjectId}")
|
||||||
public void deleteSubject(@PathVariable UUID subjectId) {
|
// public void deleteSubject(@PathVariable UUID subjectId) {
|
||||||
service.deleteSubjectAlt(subjectId);
|
// service.deleteSubjectAlt(subjectId);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,18 +22,21 @@ public class SubjectController {
|
|||||||
return service.getSubject(subjectId);
|
return service.getSubject(subjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/subjects")
|
@PostMapping("/subjects")
|
||||||
public void addSubject(@RequestBody Subject subject) {
|
public void addSubject(@RequestBody Subject subject) {
|
||||||
service.addSubject(subject);
|
service.addSubject(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/subjects")
|
//TODO uncomment this if ever roles are added so only admin should modify this (didnt really feel like doing it rn)
|
||||||
public void updateSubject(@RequestBody Subject subject) {
|
//
|
||||||
service.updateSubject(subject);
|
// @PutMapping("/subjects")
|
||||||
}
|
// public void updateSubject(@RequestBody Subject subject) {
|
||||||
|
// service.updateSubject(subject);
|
||||||
|
// }
|
||||||
|
|
||||||
@DeleteMapping("/subjects/{subjectId}")
|
// @DeleteMapping("/subjects/{subjectId}")
|
||||||
public void deleteSubject(@PathVariable UUID subjectId) {
|
// public void deleteSubject(@PathVariable UUID subjectId) {
|
||||||
service.deleteSubject(subjectId);
|
// service.deleteSubject(subjectId);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import dev.ksan.etfoglasiserver.dto.JwtResponseDTO;
|
|||||||
import dev.ksan.etfoglasiserver.dto.UserCreationDTO;
|
import dev.ksan.etfoglasiserver.dto.UserCreationDTO;
|
||||||
import dev.ksan.etfoglasiserver.dto.UserDTO;
|
import dev.ksan.etfoglasiserver.dto.UserDTO;
|
||||||
import dev.ksan.etfoglasiserver.dto.UserLoginDTO;
|
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 dev.ksan.etfoglasiserver.service.UserService;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -20,48 +20,52 @@ public class UserController {
|
|||||||
@Autowired UserService service;
|
@Autowired UserService service;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("users/{userId}")
|
@GetMapping("users/me")
|
||||||
public ResponseEntity<UserDTO> getUserById(@PathVariable UUID userId) {
|
public ResponseEntity<UserDTO> getUserById(Authentication authentication) {
|
||||||
|
|
||||||
UserDTO user = service.getUserById(userId);
|
String email = authentication.getName();
|
||||||
|
|
||||||
|
|
||||||
|
User user = service.getAccountByEmail(email).orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
if (user != null) {
|
|
||||||
return new ResponseEntity<>(user, HttpStatus.OK);
|
|
||||||
}
|
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/users")
|
@PutMapping("/users/me")
|
||||||
public ResponseEntity<UserDTO> updateUser(@RequestBody UserCreationDTO user) {
|
public ResponseEntity<UserDTO> updateUser(
|
||||||
|
@RequestBody UserCreationDTO user,
|
||||||
|
Authentication authentication) {
|
||||||
|
|
||||||
UserDTO userUpdated = service.updateUser(user);
|
String email = authentication.getName();
|
||||||
if (userUpdated != null) {
|
|
||||||
return new ResponseEntity<>(userUpdated, HttpStatus.OK);
|
UserDTO userUpdated = service.updateUser(email, user);
|
||||||
}
|
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return ResponseEntity.ok(userUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/users/{userId}/subjects/{subjectId}")
|
@PutMapping("/users/me/subjects/{subjectId}")
|
||||||
public ResponseEntity<UserDTO> addSubject(
|
public ResponseEntity<UserDTO> addSubject(
|
||||||
@PathVariable UUID userId,
|
@PathVariable UUID subjectId,
|
||||||
@PathVariable UUID subjectId
|
Authentication authentication) {
|
||||||
) {
|
|
||||||
|
|
||||||
UserDTO updatedUser = service.addSubject(userId, subjectId);
|
String email = authentication.getName();
|
||||||
|
|
||||||
return ResponseEntity.ok(updatedUser);
|
UserDTO updatedUser = service.addSubject(email, subjectId);
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/users/{userId}/subjects/{subjectId}")
|
return ResponseEntity.ok(updatedUser);
|
||||||
public ResponseEntity<UserDTO> removeSubject(
|
}
|
||||||
@PathVariable UUID userId,
|
|
||||||
@PathVariable UUID subjectId
|
|
||||||
) {
|
|
||||||
|
|
||||||
UserDTO updatedUser = service.removeSubject(userId, subjectId);
|
@DeleteMapping("/users/me/subjects/{subjectId}")
|
||||||
|
public ResponseEntity<UserDTO> removeSubject(
|
||||||
|
@PathVariable UUID subjectId,
|
||||||
|
Authentication authentication) {
|
||||||
|
|
||||||
return ResponseEntity.ok(updatedUser);
|
String email = authentication.getName();
|
||||||
}
|
|
||||||
|
UserDTO updatedUser = service.removeSubject(email, subjectId);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(updatedUser);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<JwtResponseDTO> login(@RequestBody UserLoginDTO user) {
|
public ResponseEntity<JwtResponseDTO> login(@RequestBody UserLoginDTO user) {
|
||||||
@@ -78,18 +82,14 @@ public class UserController {
|
|||||||
if (newUser != null) return new ResponseEntity<>(newUser, HttpStatus.CREATED);
|
if (newUser != null) return new ResponseEntity<>(newUser, HttpStatus.CREATED);
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// @DeleteMapping("/users/{userId}")
|
|
||||||
// public void deleteUser(@PathVariable UUID userId) {
|
|
||||||
// service.deleteUser(userId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
@DeleteMapping("/users/me")
|
||||||
@PostMapping("/users")
|
public ResponseEntity<Void> deleteUser(Authentication authentication) {
|
||||||
public void addUser(@RequestBody UserCreationDTO user) {
|
|
||||||
NotificationMethod method = NotificationMethod.valueOf(user.getNotification());
|
String email = authentication.getName();
|
||||||
user.setNotificationMethod(method);
|
|
||||||
service.addUser(user);
|
service.deleteUser(email);
|
||||||
|
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package dev.ksan.etfoglasiserver.dto;
|
|||||||
|
|
||||||
import dev.ksan.etfoglasiserver.model.NotificationMethod;
|
import dev.ksan.etfoglasiserver.model.NotificationMethod;
|
||||||
import dev.ksan.etfoglasiserver.model.Subject;
|
import dev.ksan.etfoglasiserver.model.Subject;
|
||||||
|
import dev.ksan.etfoglasiserver.model.User;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -19,7 +21,14 @@ public class UserDTO {
|
|||||||
this.subjectSet = subjectSet;
|
this.subjectSet = subjectSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getId() {
|
public UserDTO(User user) {
|
||||||
|
this.id = user.getId();
|
||||||
|
this.email = user.getEmail();
|
||||||
|
this.subjectSet = user.getSubjectSet();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDTO updateUser(UserCreationDTO user) {
|
public UserDTO updateUser(String email, UserCreationDTO user) {
|
||||||
Optional<User> existingUserOpt = userRepo.findByEmail(user.getEmail());
|
Optional<User> existingUserOpt = userRepo.findByEmail(email);
|
||||||
|
|
||||||
if (userRepo.findByEmail(user.getNewEmail()).isPresent()) {
|
if (userRepo.findByEmail(user.getNewEmail()).isPresent()) {
|
||||||
throw new RuntimeException("Email taken");
|
throw new RuntimeException("Email taken");
|
||||||
@@ -96,8 +96,12 @@ public class UserService {
|
|||||||
} else throw new RuntimeException("User not found");
|
} else throw new RuntimeException("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUser(UUID userId) {
|
public void deleteUser(String email) {
|
||||||
userRepo.deleteById(userId);
|
User user = userRepo.findByEmail(email).orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
|
user.getSubjectSet().clear();
|
||||||
|
userRepo.save(user);
|
||||||
|
userRepo.delete(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDTO register(UserCreationDTO user) {
|
public UserDTO register(UserCreationDTO user) {
|
||||||
@@ -170,9 +174,9 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public UserDTO addSubject(UUID userId, UUID subjectId) {
|
public UserDTO addSubject(String email, UUID subjectId) {
|
||||||
|
|
||||||
User user = userRepo.findById(userId)
|
User user = userRepo.findByEmail(email)
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
Subject subject = subjectRepo.findById(subjectId)
|
Subject subject = subjectRepo.findById(subjectId)
|
||||||
@@ -185,9 +189,9 @@ public class UserService {
|
|||||||
return getUserDTO(user);
|
return getUserDTO(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDTO removeSubject(UUID userId, UUID subjectId) {
|
public UserDTO removeSubject(String email, UUID subjectId) {
|
||||||
|
|
||||||
User user = userRepo.findById(userId)
|
User user = userRepo.findByEmail(email)
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||||
|
|
||||||
Subject subject = subjectRepo.findById(subjectId)
|
Subject subject = subjectRepo.findById(subjectId)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
let subscribedSubjectIds: string[] = [];
|
let subscribedSubjectIds: string[] = [];
|
||||||
if (res.userId) {
|
if (res.userId) {
|
||||||
try {
|
try {
|
||||||
const dto = await authApi.getUser(res.userId, res.token);
|
const dto = await authApi.getUser( res.token);
|
||||||
subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? [];
|
subscribedSubjectIds = dto.subjectSet?.map((s) => s.id) ?? [];
|
||||||
} catch {
|
} catch {
|
||||||
// aaaa
|
// aaaa
|
||||||
@@ -67,7 +67,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
const register = async (payload: RegisterPayload) => {
|
const register = async (payload: RegisterPayload) => {
|
||||||
await authApi.register(payload);
|
await authApi.register(payload);
|
||||||
await login({ email: payload.email, password: payload.password });
|
await login({
|
||||||
|
email: payload.email.trim(),
|
||||||
|
password: payload.password.trim(),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateUser = async (newEmail?: string, newPassword?: string) => {
|
const updateUser = async (newEmail?: string, newPassword?: string) => {
|
||||||
@@ -91,7 +94,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
const subscribe = async (subjectId: string) => {
|
const subscribe = async (subjectId: string) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
const dto = await subscriptionsApi.subscribe(user.id, subjectId, user.token);
|
const dto = await subscriptionsApi.subscribe( subjectId, user.token);
|
||||||
const updated = {
|
const updated = {
|
||||||
...user,
|
...user,
|
||||||
subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? [...user.subscribedSubjectIds, subjectId],
|
subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? [...user.subscribedSubjectIds, subjectId],
|
||||||
@@ -101,7 +104,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
const unsubscribe = async (subjectId: string) => {
|
const unsubscribe = async (subjectId: string) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
const dto = await subscriptionsApi.unsubscribe(user.id, subjectId, user.token);
|
const dto = await subscriptionsApi.unsubscribe( subjectId, user.token);
|
||||||
const updated = {
|
const updated = {
|
||||||
...user,
|
...user,
|
||||||
subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? user.subscribedSubjectIds.filter((id) => id !== subjectId),
|
subscribedSubjectIds: dto.subjectSet?.map((s) => s.id) ?? user.subscribedSubjectIds.filter((id) => id !== subjectId),
|
||||||
|
|||||||
@@ -25,13 +25,19 @@ export default function AuthGate({ onSuccess }: { onSuccess?: () => void }) {
|
|||||||
const accent = dark ? "#E07B45" : "#C4622D";
|
const accent = dark ? "#E07B45" : "#C4622D";
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
|
|
||||||
|
const trimmedEmail = email.trim();
|
||||||
|
const trimmedPassword = password.trim();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setError("");
|
setError("");
|
||||||
if (!email || !password) { setError("Please fill in all fields."); return; }
|
if (!trimmedEmail || !trimmedPassword) { setError("Please fill in all fields."); return; }
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
if (mode === "login") await login({ email, password });
|
if (mode === "login") await login({ email:trimmedEmail, password:trimmedPassword});
|
||||||
else await register({ email, password, name });
|
else await register({ email: trimmedEmail,password:trimmedPassword , name });
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
setError(e.message ?? "Something went wrong.");
|
setError(e.message ?? "Something went wrong.");
|
||||||
|
|||||||
@@ -103,8 +103,15 @@ export type RegisterPayload = { email: string; password: string; name?: string }
|
|||||||
export const authApi = {
|
export const authApi = {
|
||||||
login: (p: LoginPayload) => post<JwtResponse>("/login", p),
|
login: (p: LoginPayload) => post<JwtResponse>("/login", p),
|
||||||
register: (p: RegisterPayload) => post<UserDTO>("/register", p),
|
register: (p: RegisterPayload) => post<UserDTO>("/register", p),
|
||||||
getUser: (userId: string, token: string) => get<UserDTO>(`/users/${userId}`, token),
|
|
||||||
updateUser: (body: UserUpdateDTO, token: string) => request<UserDTO>("PUT", "/users", token, body),
|
getUser: (token: string) =>
|
||||||
|
get<UserDTO>("/users/me", token),
|
||||||
|
|
||||||
|
updateUser: (body: UserUpdateDTO, token: string) =>
|
||||||
|
request<UserDTO>("PUT", "/users/me", token, body),
|
||||||
|
|
||||||
|
deleteUser: (token: string) =>
|
||||||
|
del<void>("/users/me", token),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -114,19 +121,20 @@ export const subjectsApi = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const subscriptionsApi = {
|
export const subscriptionsApi = {
|
||||||
subscribe: (userId: string, subjectId: string, token: string) =>
|
subscribe: (subjectId: string, token: string) =>
|
||||||
put<UserDTO>(
|
put<UserDTO>(
|
||||||
`/users/${userId}/subjects/${subjectId}`,
|
`/users/me/subjects/${subjectId}`,
|
||||||
{}, // body placeholder
|
{},
|
||||||
token
|
token
|
||||||
),
|
),
|
||||||
|
|
||||||
unsubscribe: (userId: string, subjectId: string, token: string) =>
|
unsubscribe: (subjectId: string, token: string) =>
|
||||||
del<UserDTO>(
|
del<UserDTO>(
|
||||||
`/users/${userId}/subjects/${subjectId}`,
|
`/users/me/subjects/${subjectId}`,
|
||||||
token
|
token
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const entriesApi = {
|
export const entriesApi = {
|
||||||
getEntries: (params: { subjectId?: string; groupName?: string; page?: number }) =>
|
getEntries: (params: { subjectId?: string; groupName?: string; page?: number }) =>
|
||||||
get<SpringPage<Entry>>("/entries", undefined, params),
|
get<SpringPage<Entry>>("/entries", undefined, params),
|
||||||
|
|||||||
Reference in New Issue
Block a user