Skip to content
64 changes: 47 additions & 17 deletions src/main/java/org/group1/projectbackend/config/DataInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,66 @@

import org.springframework.boot.CommandLineRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class DataInitializer implements CommandLineRunner {

private final JdbcTemplate jdbcTemplate;
private final PasswordEncoder passwordEncoder;

public DataInitializer(JdbcTemplate jdbcTemplate) {
public DataInitializer(JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) {
this.jdbcTemplate = jdbcTemplate;
this.passwordEncoder = passwordEncoder;
}

@Override
public void run(String... args) {
Integer userCount = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM users WHERE id = 1",
Integer.class
);

if (userCount != null && userCount > 0) {
return;
}
// Kryptera lösenord
String userPassword = passwordEncoder.encode("password123");
String adminPassword = passwordEncoder.encode("admin123");

// USER
jdbcTemplate.update("""
INSERT INTO users (id, username, email, password, full_name, enabled, created_at)
VALUES
(1, 'user', 'user@example.com', 'password', 'user', true, CURRENT_TIMESTAMP),
(2, 'adamaj01', 'adamaj@example.com', 'password', 'Adam', true, CURRENT_TIMESTAMP),
(3, 'emmtra01', 'emmtra@example.com', 'password', 'Emma', true, CURRENT_TIMESTAMP),
(4, 'erifa101', 'erifa1@example.com', 'password', 'Erika', true, CURRENT_TIMESTAMP),
(5, 'johjan01', 'johjan@example.com', 'password', 'Johan', true, CURRENT_TIMESTAMP)
""");
INSERT INTO users (id, username, email, password, full_name, enabled, created_at)
VALUES (1, 'testuser', 'testuser@example.com', ?, 'Test User', true, CURRENT_TIMESTAMP)
ON CONFLICT (id) DO NOTHING
""", userPassword);

// ADMIN USER
jdbcTemplate.update("""
INSERT INTO users (id, username, email, password, full_name, enabled, created_at)
VALUES (2, 'admin', 'admin@example.com', ?, 'Admin User', true, CURRENT_TIMESTAMP)
ON CONFLICT (id) DO NOTHING
""", adminPassword);
Comment thread
EmmaTravljanin marked this conversation as resolved.

// ROLLER
jdbcTemplate.update("""
INSERT INTO roles (id, name)
VALUES (1, 'ROLE_USER')
ON CONFLICT (id) DO NOTHING
""");

jdbcTemplate.update("""
INSERT INTO roles (id, name)
VALUES (2, 'ROLE_ADMIN')
ON CONFLICT (id) DO NOTHING
""");

// Koppla USER → ROLE_USER
jdbcTemplate.update("""
INSERT INTO user_roles (user_id, role_id)
VALUES (1, 1)
ON CONFLICT DO NOTHING
""");

// Koppla ADMIN → ROLE_ADMIN
jdbcTemplate.update("""
INSERT INTO user_roles (user_id, role_id)
VALUES (2, 2)
ON CONFLICT DO NOTHING
Comment thread
EmmaTravljanin marked this conversation as resolved.
""");
Comment thread
EmmaTravljanin marked this conversation as resolved.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.validation.Valid;
import org.group1.projectbackend.dto.activitylog.ActivityLogDto;
import org.group1.projectbackend.dto.activitylog.CreateActivityLogDto;
import org.group1.projectbackend.exception.ResourceNotFoundException;
import org.group1.projectbackend.service.ActivityLogService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -19,46 +20,41 @@ public ActivityLogController(ActivityLogService activityLogService) {
this.activityLogService = activityLogService;
}

// Create activity log
@PostMapping
public ResponseEntity<ActivityLogDto> createActivityLog(@Valid @RequestBody CreateActivityLogDto dto) {
ActivityLogDto createdActivityLog = activityLogService.createActivityLog(dto);
return ResponseEntity.status(201).body(createdActivityLog);
return ResponseEntity.status(201).body(activityLogService.createActivityLog(dto));
}

// Get all activity logs
@GetMapping
public ResponseEntity<List<ActivityLogDto>> getAllActivityLogs() {
List<ActivityLogDto> activityLogs = activityLogService.getAllActivityLogs();
return ResponseEntity.ok(activityLogs);
return ResponseEntity.ok(activityLogService.getAllActivityLogs());
}

// Get activity log by id
@GetMapping("/{activityLogId}")
public ResponseEntity<ActivityLogDto> getActivityLogById(@PathVariable Long activityLogId) {
ActivityLogDto activityLog = activityLogService.getActivityLogById(activityLogId);
return ResponseEntity.ok(activityLog);
try {
return ResponseEntity.ok(activityLogService.getActivityLogById(activityLogId));
} catch (ResourceNotFoundException e) {
return ResponseEntity.notFound().build();
}
}

// Get activity logs by support ticket id
@GetMapping("/ticket/{supportTicketId}")
public ResponseEntity<List<ActivityLogDto>> getActivityLogsBySupportTicketId(
public ResponseEntity<List<ActivityLogDto>> getByTicket(
@PathVariable Long supportTicketId,
@RequestParam(defaultValue = "desc") String sortDirection
) {
return ResponseEntity.ok(
activityLogService.getActivityLogsBySupportTicketId(supportTicketId, sortDirection)
);
@RequestParam(defaultValue = "asc") String sortDirection) {
try {
List<ActivityLogDto> logs = activityLogService.getActivityLogsBySupportTicketId(supportTicketId, sortDirection);
return ResponseEntity.ok(logs);
} catch (ResourceNotFoundException e) {
return ResponseEntity.notFound().build();
}
}

// Get activity logs by user id
@GetMapping("/user/{userId}")
public ResponseEntity<List<ActivityLogDto>> getActivityLogsByUserId(
public ResponseEntity<List<ActivityLogDto>> getByUser(
@PathVariable Long userId,
@RequestParam(defaultValue = "asc") String sortDirection
) {
return ResponseEntity.ok(
activityLogService.getActivityLogsByUserId(userId, sortDirection)
);
@RequestParam(defaultValue = "asc") String sortDirection) {
return ResponseEntity.ok(activityLogService.getActivityLogsByUserId(userId, sortDirection));
}
}
}
20 changes: 20 additions & 0 deletions src/main/java/org/group1/projectbackend/dto/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.group1.projectbackend.dto;

import java.time.LocalDateTime;

public class ApiResponse<T> {

private String status;
private T data;
private LocalDateTime timestamp;

public ApiResponse(String status, T data) {
this.status = status;
this.data = data;
this.timestamp = LocalDateTime.now();
}

public String getStatus() { return status; }
public T getData() { return data; }
public LocalDateTime getTimestamp() { return timestamp; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.group1.projectbackend.security;

import org.group1.projectbackend.entity.User;
import org.group1.projectbackend.repository.UserRepository;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository userRepository;

public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));

return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(
user.getRoles().stream()
.map(role -> role.getName().name().replace("ROLE_", ""))
.toArray(String[]::new)
)
.build();
Comment thread
EmmaTravljanin marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,46 @@

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

private final CustomUserDetailsService userDetailsService;

public SecurityConfig(CustomUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.httpBasic(Customizer.withDefaults())

// använd Spring default login
.formLogin(form -> form
.defaultSuccessUrl("/", true)
.permitAll()
)
Comment thread
VonAdamo marked this conversation as resolved.

.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
.requestMatchers("/", "/css/**", "/js/**").permitAll()
.requestMatchers("/activitylogs/**").hasRole("ADMIN")
.requestMatchers("/comments/**").authenticated()
.requestMatchers("/api/tickets/**").authenticated()
.anyRequest().permitAll()
)

.userDetailsService(userDetailsService)

.build();
}

@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build()
);
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ public ActivityLogDto getActivityLogById(Long id) {
return activityLogMapper.toDto(activityLog);
}


public List<ActivityLogDto> getActivityLogsBySupportTicketId(Long supportTicketId, String sortDirection) {

if (!supportTicketRepository.existsById(supportTicketId)) {
throw new ResourceNotFoundException("Support ticket not found with id: " + supportTicketId);
}
Expand All @@ -91,4 +93,4 @@ public List<ActivityLogDto> getActivityLogsByUserId(Long userId, String sortDire
.map(activityLogMapper::toDto)
.toList();
}
}
}
Loading