- Timestamp:
- 05/13/26 00:35:13 (8 weeks ago)
- Branches:
- master
- Children:
- 447c39f
- Parents:
- a8381b1
- Location:
- backend
- Files:
-
- 3 added
- 2 deleted
- 9 edited
-
docs/Normalization.txt (deleted)
-
docs/P6_Advanced_Reports.txt (deleted)
-
docs/SQL_Injection_Prevention.txt (added)
-
docs/SQL_Injection_Quick_Reference.txt (added)
-
docs/Security_Audit_Report.txt (added)
-
src/main/java/com/trekr/backend/repository/TrainingSessionRepository.java (modified) (1 diff)
-
src/main/java/com/trekr/backend/service/AuthService.java (modified) (1 diff)
-
src/main/java/com/trekr/backend/service/CustomTrackingService.java (modified) (2 diffs)
-
src/main/java/com/trekr/backend/service/DisciplineService.java (modified) (4 diffs)
-
src/main/java/com/trekr/backend/service/FinanceService.java (modified) (2 diffs)
-
src/main/java/com/trekr/backend/service/InvestingService.java (modified) (1 diff)
-
src/main/java/com/trekr/backend/service/TrainingService.java (modified) (4 diffs)
-
src/main/java/com/trekr/backend/service/WeightService.java (modified) (6 diffs)
-
src/main/resources/application.properties (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
backend/src/main/java/com/trekr/backend/repository/TrainingSessionRepository.java
ra8381b1 r42da64d 7 7 import org.springframework.stereotype.Repository; 8 8 9 import java.time.LocalDate; 10 import java.util.Collection; 11 9 12 @Repository 10 13 public interface TrainingSessionRepository extends JpaRepository<TrainingSession, Long> { 11 14 Page<TrainingSession> findByTrainingUser_UserIdOrderByDateDesc(Long userId, Pageable pageable); 12 15 java.util.List<TrainingSession> findByTrainingUser_UserIdAndDate(Long userId, java.time.LocalDate date); 16 17 @SuppressWarnings("unused") 18 java.util.List<TrainingSession> findByTrainingUser_UserIdAndDateIn(Long userId, Collection<LocalDate> dates); 13 19 } -
backend/src/main/java/com/trekr/backend/service/AuthService.java
ra8381b1 r42da64d 43 43 } 44 44 45 @Transactional(readOnly = true) 45 46 public AuthResponse login(LoginRequest request) { 46 47 String usernameOrEmail = request.getUsernameOrEmail().trim(); -
backend/src/main/java/com/trekr/backend/service/CustomTrackingService.java
ra8381b1 r42da64d 36 36 } 37 37 38 @Transactional(readOnly = true) 38 39 public CustomTrackingCategoriesResponse getCustomTrackingCategories(Long userId) { 39 40 List<CustomTrackingCategoryDto> items = customTrackingCategoryRepository … … 72 73 } 73 74 75 @Transactional(readOnly = true) 74 76 public TasksResponse getCustomCategoryTasks(Long userId, Long customTrackingId) { 75 77 requireOwnership(userId, customTrackingId); -
backend/src/main/java/com/trekr/backend/service/DisciplineService.java
ra8381b1 r42da64d 71 71 } 72 72 73 @Transactional(readOnly = true) 73 74 public TasksResponse getTasks(Long userId, int page, int size) { 74 75 if (!disciplineUserRepository.existsById(userId)) { … … 162 163 * Computes the daily completion percentage for the given date: 163 164 * finished_tasks / total_tasks * 100 164 *165 165 * - Persisted once per user+date. If already computed, it is not re-computed. 166 166 * - After computing, all tasks for that user are reset to unfinished. … … 210 210 // (not strictly required for now, but matches schema and enables future analytics) 211 211 if (finished > 0) { 212 List<Task> finishedTasks = taskRepository.findByDisciplineUser_UserIdAndFinishedTrue(userId); 213 for (Task t : finishedTasks) { 214 TaskDailyCompletion link = new TaskDailyCompletion(); 215 link.setTask(t); 216 link.setDailyCompletion(savedCompletion); 217 link.setId(new TaskDailyCompletionId(t.getTaskId(), savedCompletion.getDailyCompletionId())); 218 taskDailyCompletionRepository.save(link); 219 } 212 List<TaskDailyCompletion> links = taskRepository.findByDisciplineUser_UserIdAndFinishedTrue(userId) 213 .stream() 214 .map(t -> { 215 TaskDailyCompletion link = new TaskDailyCompletion(); 216 link.setTask(t); 217 link.setDailyCompletion(savedCompletion); 218 link.setId(new TaskDailyCompletionId(t.getTaskId(), savedCompletion.getDailyCompletionId())); 219 return link; 220 }) 221 .toList(); 222 taskDailyCompletionRepository.saveAll(links); 220 223 } 221 224 … … 228 231 } 229 232 233 @Transactional(readOnly = true) 230 234 public DailyCompletionsResponse getDailyCompletions(Long userId, int page, int size) { 231 235 if (!disciplineUserRepository.existsById(userId)) { -
backend/src/main/java/com/trekr/backend/service/FinanceService.java
ra8381b1 r42da64d 69 69 } 70 70 71 @Transactional(readOnly = true) 71 72 public FinanceProfileResponse getProfile(Long userId) { 72 73 FinanceUser financeUser = financeUserRepository.findById(userId) … … 81 82 } 82 83 84 @Transactional(readOnly = true) 83 85 public IncomesResponse getIncomes(Long userId, int page, int size) { 84 86 if (!financeUserRepository.existsById(userId)) { -
backend/src/main/java/com/trekr/backend/service/InvestingService.java
ra8381b1 r42da64d 53 53 } 54 54 55 @Transactional(readOnly = true) 55 56 public InvestingAssetsResponse getAssets(Long userId, int page, int size) { 56 57 if (!investorUserRepository.existsById(userId)) { -
backend/src/main/java/com/trekr/backend/service/TrainingService.java
ra8381b1 r42da64d 21 21 import java.math.RoundingMode; 22 22 import java.time.LocalDate; 23 import java.util.Arrays; 23 24 import java.util.List; 24 25 import java.util.Locale; … … 108 109 } 109 110 111 @Transactional(readOnly = true) 110 112 public TrainingSessionsResponse getSessions(Long userId, int page, int size) { 111 113 if (!trainingUserRepository.existsById(userId)) { … … 134 136 } 135 137 138 @Transactional(readOnly = true) 136 139 public TrainingProfileResponse getProfile(Long userId) { 137 140 TrainingUser trainingUser = trainingUserRepository.findById(userId) … … 202 205 203 206 String normalized = type.replace('_', '-'); 204 return List.of(normalized.split("-")) 205 .stream() 206 .filter(part -> part != null && !part.isBlank()) 207 return Arrays.stream(normalized.split("-")) 208 .filter(part -> !part.isBlank()) 207 209 .map(part -> Character.toUpperCase(part.charAt(0)) + part.substring(1)) 208 210 .collect(Collectors.joining(" ")); -
backend/src/main/java/com/trekr/backend/service/WeightService.java
ra8381b1 r42da64d 21 21 import java.math.BigDecimal; 22 22 import java.time.LocalDate; 23 import java.util.HashMap; 23 24 import java.util.List; 25 import java.util.Map; 24 26 25 27 @Service … … 73 75 } 74 76 77 @Transactional(readOnly = true) 75 78 public WeightProfileResponse getProfile(Long userId) { 76 79 WeightUser weightUser = weightUserRepository.findById(userId) … … 84 87 } 85 88 89 @Transactional(readOnly = true) 86 90 public WeightDailyIntakesResponse getDailyIntakes(Long userId, int page, int size) { 87 91 if (!weightUserRepository.existsById(userId)) { … … 92 96 .findByWeightUser_UserIdOrderByDateDesc(userId, PageRequest.of(page, size)); 93 97 98 List<LocalDate> dates = result.getContent().stream() 99 .map(DailyIntake::getDate) 100 .distinct() 101 .toList(); 102 103 Map<LocalDate, Integer> trainingCountsByDate = new HashMap<>(); 104 Map<LocalDate, BigDecimal> burnedCaloriesByDate = new HashMap<>(); 105 if (!dates.isEmpty()) { 106 trainingSessionRepository.findByTrainingUser_UserIdAndDateIn(userId, dates).forEach(session -> { 107 LocalDate sessionDate = session.getDate(); 108 trainingCountsByDate.merge(sessionDate, 1, Integer::sum); 109 BigDecimal calories = session.getCalories() != null ? session.getCalories() : BigDecimal.ZERO; 110 burnedCaloriesByDate.merge(sessionDate, calories, BigDecimal::add); 111 }); 112 } 113 94 114 List<WeightDailyIntakeDto> intakes = result.getContent().stream() 95 115 .map(d -> { 96 // Fetch training data for this date 97 var trainingSessions = trainingSessionRepository.findByTrainingUser_UserIdAndDate(userId, d.getDate()); 98 boolean trainedThatDay = !trainingSessions.isEmpty(); 99 BigDecimal burnedCalories = trainingSessions.stream() 100 .map(ts -> ts.getCalories() != null ? ts.getCalories() : BigDecimal.ZERO) 101 .reduce(BigDecimal.ZERO, BigDecimal::add) 116 boolean trainedThatDay = trainingCountsByDate.getOrDefault(d.getDate(), 0) > 0; 117 BigDecimal burnedCalories = burnedCaloriesByDate.getOrDefault(d.getDate(), BigDecimal.ZERO) 102 118 .setScale(2, java.math.RoundingMode.HALF_UP); 103 119 104 120 return new WeightDailyIntakeDto( 105 121 d.getDailyIntakeId(), … … 143 159 } 144 160 145 @Transactional146 161 public WeightProfileResponse updateProfile(Long userId, WeightStartRequest request) { 147 162 WeightUser weightUser = weightUserRepository.findById(userId) … … 163 178 } 164 179 180 @Transactional(readOnly = true) 165 181 public TodayTrainingInfoDto getTodayTrainingInfo(Long userId) { 166 182 // Try to get training user, if doesn't exist just return zeros -
backend/src/main/resources/application.properties
ra8381b1 r42da64d 43 43 spring.datasource.hikari.pool-name=trekrHikariPool 44 44 # Remote PostgreSQL (especially via SSH tunnel) often has a small max_connections. 45 # Use conservative defaults to avoid exhausting connection slots; override via env if needed. 46 spring.datasource.hikari.maximum-pool-size=${SPRING_DATASOURCE_HIKARI_MAX_POOL_SIZE:4} 47 spring.datasource.hikari.minimum-idle=${SPRING_DATASOURCE_HIKARI_MIN_IDLE:0} 45 # Use a slightly larger default so the app can serve more concurrent users without 46 # overloading the database; override via env if your provider has tighter limits. 47 spring.datasource.hikari.maximum-pool-size=${SPRING_DATASOURCE_HIKARI_MAX_POOL_SIZE:20} 48 spring.datasource.hikari.minimum-idle=${SPRING_DATASOURCE_HIKARI_MIN_IDLE:5} 48 49 spring.datasource.hikari.connection-timeout=30000 49 50 spring.datasource.hikari.idle-timeout=600000
Note:
See TracChangeset
for help on using the changeset viewer.
