Skip to content
Snippets Groups Projects
Commit a4e0c78f authored by Richard Githuba's avatar Richard Githuba
Browse files

Merge branch 'release/Sprint-4' into '256-language-options-so-that-i-can-switch-to-polish'

# Conflicts:
#   src/main/java/polish_community_group_11/polish_community/security/WebSecurityConfig.java
#   src/main/resources/schema.sql
parents 5fe5a627 410b3d4e
No related branches found
No related tags found
No related merge requests found
Showing
with 549 additions and 8 deletions
......@@ -59,7 +59,6 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.mockito:mockito-core:4.0.0' // Mocking library
testImplementation 'org.mockito:mockito-junit-jupiter:4.0.0' // JUnit 5 support for Mockito
......
package polish_community_group_11.polish_community.event.controllers;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import polish_community_group_11.polish_community.event.services.EventRepository;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import polish_community_group_11.polish_community.event.models.viewmodel.EventForm;
import org.springframework.web.bind.annotation.*;
import polish_community_group_11.polish_community.event.models.Event;
import polish_community_group_11.polish_community.event.models.EventImpl;
import polish_community_group_11.polish_community.event.services.EventService;
import polish_community_group_11.polish_community.register.services.UserService;
import java.security.Principal;
import java.sql.SQLException;
@Controller
public class EventController {
// Inject the EventRepository service to handle event-related data operations
private EventRepository eventService;
private EventService eventService;
private UserService userService;
@Autowired
// Constructor-based dependency injection for EventRepository
public EventController(EventRepository eventService){
public EventController(EventService eventService, UserService userService) {
this.eventService = eventService;
this.userService = userService;
}
// Controller method to handle GET requests for the "/event" URL
......@@ -50,4 +67,65 @@ public class EventController {
// Return the populated ModelAndView object, which will render the event details view
return modelAndView;
}
//Controller Method to load create new event page
@GetMapping("event/add")
public ModelAndView addEvent() {
ModelAndView modelAndView = new ModelAndView("event/add-event");
//Passing Form object for validation
modelAndView.addObject("event", new EventForm());
/* Form action string to check the type of action to perform and dynamically
use the same form for both create and update */
modelAndView.addObject("formAction", "/event/add");
return modelAndView;
}
@PostMapping("event/add")
public ModelAndView addEvent(@Valid @ModelAttribute("event") EventForm event,
BindingResult bindingResult, Model model,
Principal principal, RedirectAttributes redirectAttributes) throws SQLException {
ModelAndView modelAndView = new ModelAndView("event/add-event");
if(bindingResult.hasErrors()) {
modelAndView.addObject(model.asMap());
/* Form action string to check the type of action to perform and dynamically
use the same form for both create and update */
modelAndView.addObject("formAction", "/event/add");
}
else{
if(event==null){
throw new NullPointerException("New event is empty or null");
}
eventService.addNewEvent(event.processEventForm(),principal.getName());
redirectAttributes.addFlashAttribute("successMessage", "Event created successfully!");
modelAndView.setViewName("redirect:/event");
}
return modelAndView;
}
//Update Events
@GetMapping("event/edit/{id}")
public ModelAndView editEvent(@PathVariable int id) {
EventForm event = eventService.getEventById(id).processEventToEventForm();
ModelAndView modelAndView = new ModelAndView("event/add-event");
modelAndView.addObject("event", event);
modelAndView.addObject("formAction", "/event/edit");
return modelAndView;
}
@PostMapping("/event/edit")
public ModelAndView editEvent(@Valid @ModelAttribute("event") EventForm event,
BindingResult bindingResult, Model model) throws SQLException {
ModelAndView modelAndView = new ModelAndView("event/add-event");
if (bindingResult.hasErrors()) {
modelAndView.addObject(model.asMap());
modelAndView.addObject("formAction", "/event/edit");
} else {
eventService.getEditEvent(event.processEventForm());
modelAndView.setViewName("redirect:/event");
}
return modelAndView;
}
}
package polish_community_group_11.polish_community.event.services;
package polish_community_group_11.polish_community.event.dao;
import polish_community_group_11.polish_community.event.models.Event;
import java.sql.SQLException;
import java.util.List;
public interface EventRepository {
......@@ -8,4 +10,6 @@ public interface EventRepository {
List<Event> getAllEvents();
Event getEventById(int id);
void addNewEvent(Event newEvent) throws SQLException;
Event editEvent(Event event)throws SQLException;
}
package polish_community_group_11.polish_community.event.services;
package polish_community_group_11.polish_community.event.dao;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import polish_community_group_11.polish_community.event.models.Event;
import polish_community_group_11.polish_community.event.models.EventImpl;
import java.sql.SQLException;
import java.util.List;
@Repository // Marks this class as a Spring Data repository for database interaction
public class EventRepositoryImpl implements EventRepository {
// JdbcTemplate instance for executing SQL queries
private JdbcTemplate jdbc;
private final JdbcTemplate jdbc;
// RowMapper to map SQL result set rows to Event objects
private RowMapper<Event> eventItemMapper;
......@@ -74,4 +77,64 @@ public class EventRepositoryImpl implements EventRepository {
return event;
}
public void addNewEvent(Event newEvent) throws SQLException, NullPointerException{
if(newEvent==null){
throw new NullPointerException("Event cannot be null");
}
String dbInsertSql =
"insert into event " +
"(event_title, event_description, location, " +
"event_date, event_time,user_id, event_poster_url,whyJoin,benefits)" +
" values (?,?,?,?,?,?,?,?,?)";
try{
jdbc.update(dbInsertSql,
newEvent.getEvent_title(),
newEvent.getDescription(),
newEvent.getDescription(),
newEvent.getEvent_date(),
newEvent.getEvent_time(),
newEvent.getUser_id(),
newEvent.getImageUrl(),
newEvent.getWhyJoin(),
newEvent.getBenefits()
);
}
catch (DataAccessException e) {
throw new SQLException("Failed to insert new information record", e);
}
}
// Updates selected record with new updated information
public Event editEvent(Event event)throws SQLException {
String updateSql = "UPDATE event " +
"SET event_title = ?, event_description = ?, " +
"event_date = ?, event_time = ?, " +
"location = ?, user_id = ?, event_poster_url = ?, " +
"whyJoin = ?, benefits = ? " +
"WHERE event_id = ?";
try {
// jdbc.update() is a method that will execute the sql query
// replaces the ? with the actual values from the news object
int rowsAffected = jdbc.update(updateSql,
event.getEvent_title(),
event.getDescription(),
event.getEvent_date(),
event.getEvent_time(),
event.getLocation(),
event.getUser_id(),
event.getImageUrl(),
event.getWhyJoin(),
event.getBenefits(),
event.getEvent_id()
);
// error handling
if (rowsAffected == 0) {
throw new SQLException("No event item was updated. Check the ID provided.");
}
} catch (DataAccessException e) {
throw new SQLException("Error updating event with ID: " + event.getEvent_id(), e);
}
return event;
}
}
package polish_community_group_11.polish_community.event.models;
import polish_community_group_11.polish_community.event.models.viewmodel.EventForm;
import java.time.LocalDate;
import java.time.LocalTime;
......@@ -27,4 +29,5 @@ public interface Event {
public String getBenefits();
public void setBenefits(String benefits);
EventForm processEventToEventForm();
}
package polish_community_group_11.polish_community.event.models;
import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import polish_community_group_11.polish_community.event.models.viewmodel.EventForm;
import java.time.LocalDate;
import java.time.LocalTime;
......@@ -20,4 +26,12 @@ public class EventImpl implements Event{
private String whyJoin;
private String benefits;
public EventForm processEventToEventForm(){
EventForm eventForm = new EventForm(
event_id, event_title, description, event_date, event_time,
location, user_id, imageUrl, whyJoin, benefits
);
return eventForm;
}
}
package polish_community_group_11.polish_community.event.models.viewmodel;
import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.URL;
import polish_community_group_11.polish_community.event.models.Event;
import polish_community_group_11.polish_community.event.models.EventImpl;
import java.time.LocalDate;
import java.time.LocalTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EventForm {
private int event_id;
@NotEmpty(message = "Please enter the event title")
private String event_title;
@NotEmpty(message = "Please enter the event description")
private String description;
@FutureOrPresent(message = "The date cannot be in the past")
@NotNull(message = "Please enter the event date")
private LocalDate event_date;
@NotNull(message = "Please enter the time of the event")
private LocalTime event_time;
@NotEmpty(message = "Please provide the location of event")
private String location;
private int user_id;
@NotEmpty(message = "Please provide event image url")
@Pattern(regexp = ".*\\.(png|jpg|jpeg|gif).*", message = "Must be a valid image (png, jpg, jpeg, gif).")
@URL(message = "Not a valid image url")
private String imageUrl;
private String whyJoin;
private String benefits;
public Event processEventForm(){
if (event_title == null || event_title.isEmpty()) {
throw new IllegalArgumentException("Event title is required");
}
if (event_date == null) {
throw new IllegalArgumentException("Event date is required");
}
if (event_time == null) {
throw new IllegalArgumentException("Event time is required");
}
if (location == null || location.isEmpty()) {
throw new IllegalArgumentException("Location is required");
}
Event event = new EventImpl(
event_id, event_title, description, event_date, event_time,
location, user_id, imageUrl, whyJoin, benefits
);
return event;
}
}
package polish_community_group_11.polish_community.event.services;
import polish_community_group_11.polish_community.event.models.Event;
import java.sql.SQLException;
import java.util.List;
public interface EventService {
List<Event> getAllEvents();
Event getEventById(int id);
void addNewEvent(Event newEvent, String email) throws SQLException;
Event getEditEvent(Event event) throws SQLException;
}
\ No newline at end of file
package polish_community_group_11.polish_community.event.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import polish_community_group_11.polish_community.event.dao.EventRepository;
import polish_community_group_11.polish_community.event.models.Event;
import polish_community_group_11.polish_community.register.services.UserService;
import java.sql.SQLException;
import java.util.List;
@Service
public class EventServiceImpl implements EventService {
private final EventRepository eventRepository;
private final UserService userService;
@Autowired
public EventServiceImpl(EventRepository eventRepository, UserService userService) {
this.eventRepository = eventRepository;
this.userService=userService;
}
public List<Event> getAllEvents(){
return eventRepository.getAllEvents();
}
public Event getEventById(int id){
return eventRepository.getEventById(id);
}
public void addNewEvent(Event newEvent, String email) throws SQLException {
newEvent.setUser_id(userService.findUserIdByEmail(email));
eventRepository.addNewEvent(newEvent);
}
public Event getEditEvent(Event event) throws SQLException {
return eventRepository.editEvent(event);
}
}
package polish_community_group_11.polish_community.profile.controllers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import polish_community_group_11.polish_community.profile.models.Profile;
import polish_community_group_11.polish_community.profile.services.ProfileService;
import polish_community_group_11.polish_community.register.models.User;
import polish_community_group_11.polish_community.register.services.UserService;
import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@Controller
public class ProfileController {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Autowired
private UserService userService;
@Autowired
private ProfileService profileService;
@GetMapping("/profile")
public ModelAndView profile(Authentication authentication) {
ModelAndView modelAndView = new ModelAndView("profile/profilePage");
Profile profile = getProfileForAuthenticatedUser(authentication);
modelAndView.addObject("profile", profile);
return modelAndView;
}
@PostMapping("/update")
public String updateProfile(@ModelAttribute Profile profile, Authentication authentication,@RequestParam("newPicture") MultipartFile newPicture)
throws IOException {
String username = authentication.getName();
User user = userService.findByEmail(username);
profile.setUserId(user.getId());
if (!newPicture.isEmpty()) {
String fileName = StringUtils.cleanPath(newPicture.getOriginalFilename());
String uploadDir = "build/resources/main/static/assets/user-photos/" + user.getId();
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = newPicture.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
profile.setProfilePicture("/assets/user-photos/" + user.getId() + "/" + fileName);
}
}
profileService.updateProfile(profile);
return "redirect:/profile";
}
private Profile getProfileForAuthenticatedUser(Authentication authentication) {
LOG.info("getting profile for {} - isAuthenticated: {}", authentication.getName(), authentication.isAuthenticated());
String username = authentication.getName();
User user = userService.findByEmail(username);
Profile profile = profileService.getProfile(user.getId());
return profile;
}
}
package polish_community_group_11.polish_community.profile.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import polish_community_group_11.polish_community.profile.models.Profile;
import polish_community_group_11.polish_community.profile.services.ProfileService;
import polish_community_group_11.polish_community.register.models.User;
import polish_community_group_11.polish_community.register.services.UserService;
@RestController
public class ProfileRestController {
@Autowired
private UserService userService;
@Autowired
private ProfileService profileService;
@GetMapping("/profile-json")
public Profile getProfile(Authentication authentication) {
return getProfileForAuthenticatedUser(authentication);
}
private Profile getProfileForAuthenticatedUser(Authentication authentication) {
String username = authentication.getName();
User user = userService.findByEmail(username);
Profile profile = profileService.getProfile(user.getId());
return profile;
}
}
package polish_community_group_11.polish_community.profile.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile {
private int userId;
private String fullName;
private String email;
private String profilePicture;
private LocalDate dob;
private String bio;
private String phoneNumber;
private String organisation;
private boolean showPhoneNumber;
private boolean showDob;
}
package polish_community_group_11.polish_community.profile.repositories;
import org.springframework.stereotype.Repository;
import polish_community_group_11.polish_community.profile.models.Profile;
import java.util.List;
@Repository
public interface ProfileRepository {
Profile getProfile(Integer id);
void addProfile(Profile profile);
void updateProfile(Profile profile);
}
package polish_community_group_11.polish_community.profile.repositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import polish_community_group_11.polish_community.feed.models.FeedImpl;
import polish_community_group_11.polish_community.profile.models.Profile;
@Repository
public class ProfileRepositoryImpl implements ProfileRepository {
private final JdbcTemplate jdbcTemplate;
private final RowMapper<Profile> rowMapper;
public ProfileRepositoryImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.rowMapper = (rs, rowNum) -> new Profile(
rs.getInt("user_id"),
rs.getString("fullName"),
rs.getString("email"),
rs.getString("profile_picture"),
rs.getDate("dob").toLocalDate(),
rs.getString("bio"),
rs.getString("phone_number"),
rs.getString("organization"),
rs.getBoolean("show_phone_number"),
rs.getBoolean("show_dob")
);
}
@Override
public void addProfile(Profile profile) {
String sql = "INSERT INTO user_profile (user_id) VALUES (?)";
jdbcTemplate.update(sql, profile.getUserId());
}
@Override
public Profile getProfile(Integer id) {
String sql = "SELECT u.id as user_id, " +
"u.fullname, u.email, u.dob, u.organization, " +
"up.profile_picture, up.phone_number, up.bio, up.show_phone_number, up.show_dob " +
"FROM users u LEFT JOIN user_profile up ON " +
"u.id = up.user_id WHERE u.id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}
@Override
public void updateProfile(Profile profile) {
String sql = "UPDATE user_profile SET profile_picture = ?," +
" bio = ?, phone_number = ?, show_phone_number = ?, show_dob = ? WHERE user_id = ?";
jdbcTemplate.update(sql, profile.getProfilePicture(), profile.getBio(), profile.getPhoneNumber(),profile.isShowPhoneNumber(), profile.isShowDob(), profile.getUserId());
}
};
package polish_community_group_11.polish_community.profile.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import polish_community_group_11.polish_community.profile.models.Profile;
import polish_community_group_11.polish_community.profile.repositories.ProfileRepository;
@Service
public class ProfileService {
private ProfileRepository profileRepository;
@Autowired
public ProfileService(ProfileRepository profileRepository) {
this.profileRepository = profileRepository;
}
public void addProfile(Profile profile) {profileRepository.addProfile(profile);}
public Profile getProfile(Integer userId) {
return profileRepository.getProfile(userId);
}
public void updateProfile(Profile profile) {
profileRepository.updateProfile(profile);
}
}
......@@ -4,6 +4,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import polish_community_group_11.polish_community.profile.models.Profile;
import polish_community_group_11.polish_community.profile.services.ProfileService;
import polish_community_group_11.polish_community.register.models.User;
import polish_community_group_11.polish_community.register.models.Role;
import polish_community_group_11.polish_community.register.services.UserService;
......@@ -20,6 +22,9 @@ public class RegisterController {
@Autowired
private RoleService roleService;
@Autowired
private ProfileService profileService;
// displaying the registration form using get request and ModelAndView
@GetMapping("/register")
public ModelAndView showRegistrationForm() {
......@@ -49,6 +54,10 @@ public class RegisterController {
// save user to the database
userService.saveUser(user);
// Profile newProfile = new Profile();
// newProfile.setUserId(user.getId());
// profileService.addProfile(newProfile);
// redirect to the login page
return "redirect:/login";
}
......
......@@ -8,9 +8,11 @@ public interface UserRepository {
int saveUser(User user); // add user into the database
User findByEmail(String email); // find user by email
int findUserIdByEmail(String email);
User findById(int id); // find user by ID
List<User> findAllUsers(); // get all the users
String findUserFullNameByEmail(String email);
}
\ No newline at end of file
......@@ -85,6 +85,22 @@ public class UserRepositoryImpl implements UserRepository {
}
}
public int findUserIdByEmail(String email) {
if(email.trim().equals("")|| email == null){
throw new IllegalArgumentException("Email is null or empty");
}
User user = findByEmail(email);
if(user == null){
throw new NullPointerException("User not found");
}
return user.getId();
}
public String findUserFullNameByEmail(String email) {
User user = findByEmail(email);
return user.getFullname();
}
// function for finding user by id
public User findById(int id) {
......
......@@ -10,6 +10,8 @@ public interface UserService {
User findById(int id);
User findByEmail(String email);
int findUserIdByEmail(String email);
List<User> findAllUsers();
public String findUserFullNameByEmail(String email);
}
\ No newline at end of file
......@@ -37,4 +37,10 @@ public class UserServiceImpl implements UserService {
// Calls findAll method of the UserRepository
return userRepository.findAllUsers();
}
public int findUserIdByEmail(String email){
return userRepository.findUserIdByEmail(email);
}
public String findUserFullNameByEmail(String email){
return userRepository.findUserFullNameByEmail(email);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment