diff --git a/.gitignore b/.gitignore
index 0276604..1176c27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,9 +19,6 @@
*.tar.gz
*.rar
-# Resources
-# src/main/resources
-
# IntelliJ
\.idea
@@ -30,3 +27,4 @@ hs_err_pid*
# ignore any .properties files
*.properties
+/.jpb/
diff --git a/README.md b/README.md
index 4cf1f23..cda6844 100644
--- a/README.md
+++ b/README.md
@@ -6,30 +6,41 @@ Team Vanquish Project 2 Implementation
- [ ] Users are interfacing with an advanced UI built with Angular running in a browser
- [ ] CRUD operations are supported for one or more domain objects via the web application's API endpoints
- [ ] Client/Server communication is done with JSON in HTTP request and response bodies.
-- [ ] Client/Server communication is done with JSON in HTTP request and response bodies.
- [ ] All low-level persistence logic is abstracted away with Hibernate/Spring Data
- [ ] Documentation (all classes and methods have adequate Javadoc comments)
-- [ ] All Exceptions are caught and logged to a file
+- [ ] All VanquishP2.Exceptions are caught and logged to a file/database
- [ ] Data useful to the application is retrieved from a third party API
- [ ] Adequate test coverage for the service-layer
- [ ] DevOps CI/CD pipeline is used to build and deploy project to a publicly available remote location
-## -- App Name Here --
-You will need to write a small paragraph describing your application. It should be 4-6 sentences and briefly cover the important points and features.
+## -- 4TheMusic --
-### Minimum Viable Product
-Your team will need to work with the trainer to come up with a satisfactory list of user stories for MVP as well as bonus stories. They should begin with "As a [stakeholder] I can... and describe what the user should be able to do. Aim for at least 2 different roles, user and administrator. Try to come up with 8 or so user stories for MVP. Carefully consider what your team can accomplish in 3 weeks and try not to set yourselves too great a task.
+"4TheMusic" is a social web service that brings music fans and concert-goers together with their favorite artists,
+while allowing premium users to gain valuable insights from user trends and analytics.
+
+Users can create and share playlists of their favorite songs and artists,
+along with viewing songs by similar artists and genres, and connecting to the social media accounts of their
+favorite artists.
-* As a user, I can see...
-* As a user, I can purchase...
-* As a user, I can check...
-* As an administrator, I can schedule...
-* As an administrator, I can cancel...
-* As an administrator, I can view...
+Premium users (concert organizers, artists, tour managers, etc.) can browse artists and see high-level, real-time analytics on
+the users that like particular artists.
+
+
+### Minimum Viable Product
+* As a user, I can create a playlist.
+* As a user, I can add or remove songs from a playlist.
+* As a user, I can rate a song with a like or dislike.
+* As a user, I can look up an album and see what songs are on it.
+* As a user, I can look up an artist and see a [limited] list of their songs.
+* As a premium user, I can schedule a concert.
+* As a premium user, I can cancel a concert.
+* As a premium user, I can see a list of liked songs for a user.
+* As a premium user, I can see a like/dislike ratio for a particular song.
### Bonus Stories
-* As an administrator, I can...
+* As a user, I can view a list of users who like the same songs.
+* As a premium user, I can see a like/dislike ratio for an entire artist.
## Tech Stack
You should be employing the following technologies in your project.
diff --git a/pom.xml b/pom.xml
index 33fd8cc..804653e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.revature.vanquish
P2
- 0.0.1-SNAPSHOT
+ 0.0.1
war
P2
Project 2 with Spring Boot Implementation
@@ -22,30 +22,114 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
org.springframework.boot
spring-boot-starter-validation
+ 2.5.5
+
org.springframework.boot
spring-boot-starter-web
-
- org.mariadb.jdbc
- mariadb-java-client
- runtime
-
org.springframework.boot
spring-boot-starter-tomcat
+ 2.5.5
provided
+
org.springframework.boot
spring-boot-starter-test
test
+
+
+ com.vaadin.external.google
+ android-json
+ 0.0.20131108.vaadin1
+ compile
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.0
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.13.0
+
+
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ 2.7.3
+ runtime
+
+
+
+
+ org.json
+ json
+ 20210307
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.2
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.2
+ runtime
+
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.2
+ runtime
+
+
+
+
+ org.mockito
+ mockito-core
+ 4.0.0
+
+
+
+
+ com.h2database
+ h2
+ 1.4.200
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.2
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
diff --git a/src/main/java/Application/P2Application.java b/src/main/java/Application/P2Application.java
deleted file mode 100644
index 530bbe9..0000000
--- a/src/main/java/Application/P2Application.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package Application;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class P2Application {
-
- public static void main(String[] args) {
- SpringApplication.run(P2Application.class, args);
- }
-
-}
diff --git a/src/main/java/VanquishP2/Application/Beans/Aspects/LoggerAspect.java b/src/main/java/VanquishP2/Application/Beans/Aspects/LoggerAspect.java
new file mode 100644
index 0000000..04a5a79
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/Aspects/LoggerAspect.java
@@ -0,0 +1,52 @@
+package VanquishP2.Application.Beans.Aspects;
+
+import VanquishP2.Application.Beans.ModelServices.LoggerService;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+/**
+ * LoggerAspect
+ * Logs all method calls and exceptions for all classes except filters.
+ *
+ * @author Kollier Martin
+ */
+
+
+@Aspect
+@Component
+public class LoggerAspect {
+ private final LoggerService loggerService;
+
+ public LoggerAspect(LoggerService loggerService) {
+ this.loggerService = loggerService;
+ }
+
+ @Pointcut("within(VanquishP2.*.*.*.*)")
+ public void logAll() {
+
+ }
+
+ @Around("within(VanquishP2.*.*.*.*)")
+ public void logAroundAll(ProceedingJoinPoint joinPoint) throws Throwable {
+ try {
+ joinPoint.proceed();
+ } catch (Exception ignored){
+
+ }
+ }
+
+ @AfterThrowing(pointcut = "logAll()", throwing = "e")
+ public void logMethodException(JoinPoint jp, Throwable e) {
+ String methodSig = extractMethodSignature(jp);
+ loggerService.writeLog(String.format("%s was thrown in method %s with message: %s", e.getClass().getSimpleName(), methodSig, e.getMessage()), 3);
+ }
+
+ private String extractMethodSignature(JoinPoint jp) {
+ return jp.getTarget().getClass().toString() + "." + jp.getSignature().getName();
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/Filters/AuthenticationFilter.java b/src/main/java/VanquishP2/Application/Beans/Filters/AuthenticationFilter.java
new file mode 100644
index 0000000..2c5fb7d
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/Filters/AuthenticationFilter.java
@@ -0,0 +1,63 @@
+package VanquishP2.Application.Beans.Filters;
+
+import VanquishP2.Application.Beans.Service.JWTUtil;
+import VanquishP2.DTOs.PrincipalDTO;
+import VanquishP2.Exceptions.AuthenticationException;
+import io.jsonwebtoken.Claims;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Authentication Filter
+ * Chains with other filters on every endpoint call to make sure the current request is from a valid source
+ * @author Kollier Martin
+ * @date 11/8/2021
+ */
+
+@Component
+public class AuthenticationFilter implements Filter {
+ private JWTUtil jwtUtil;
+
+ @Override
+ public void init(FilterConfig config) {
+ ApplicationContext container = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
+ this.jwtUtil = container.getBean(JWTUtil.class);
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ HttpServletResponse response = (HttpServletResponse) resp;
+
+ if (!request.getRequestURI().equals("/4TheMusic/login")
+ && !request.getRequestURI().equals("/4TheMusic/register/basic")
+ && !request.getRequestURI().equals("/4TheMusic/register/premium")
+ && !request.getRequestURI().equals("/4TheMusic/user/all")) {
+ parseToken(request);
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ private void parseToken(HttpServletRequest request) throws AuthenticationException {
+ String errMessage = "Unauthorized user tried to barge their way in here! Don't worry, I caught this transgression. Error: %s";
+
+ String header = request.getHeader(jwtUtil.getHeader());
+
+ if (header == null || !header.startsWith(jwtUtil.getPrefix())) {
+ throw new AuthenticationException(errMessage);
+ } else {
+ String token = header.replaceAll(jwtUtil.getPrefix(), "");
+
+ Claims jwtClaims = jwtUtil.parseJWT(token);
+ PrincipalDTO principalDTO = new PrincipalDTO(jwtClaims);
+ request.setAttribute("principal", principalDTO);
+ }
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/Filters/CORSFilter.java b/src/main/java/VanquishP2/Application/Beans/Filters/CORSFilter.java
new file mode 100644
index 0000000..4a68eea
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/Filters/CORSFilter.java
@@ -0,0 +1,22 @@
+package VanquishP2.Application.Beans.Filters;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class CORSFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws ServletException, IOException {
+ resp.setHeader("Access-Control-Allow-Origin", "*");
+ resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, PATCH");
+ resp.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Authentication");
+ chain.doFilter(req, resp);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/AlbumService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/AlbumService.java
new file mode 100644
index 0000000..7137cd9
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/AlbumService.java
@@ -0,0 +1,86 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Album;
+import VanquishP2.Application.Beans.Repos.AlbumRepository;
+import VanquishP2.Exceptions.AlbumDoesNotExistException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * AlbumService
+ * The middle man, or service, that connects to the persistence layer for everything Album related
+ *
+ * @date 10/29/2021
+ * @author Kollier Martin
+ */
+
+@Service
+@Transactional
+public class AlbumService {
+ private final AlbumRepository albumRepository;
+
+ @Autowired
+ public AlbumService(AlbumRepository albumRepository) {
+ this.albumRepository = albumRepository;
+ }
+
+ /**
+ * Get all Albums
+ * @return List of Albums
+ */
+ public List getAll() {
+ return albumRepository.findAll();
+ }
+
+ /**
+ * Fetch Album by its ID
+ * @param id Album ID
+ * @return Album Object
+ * @throws AlbumDoesNotExistException Album does not exist in DB
+ */
+ public Album getByID(int id) throws AlbumDoesNotExistException {
+ return albumRepository.findByAlbumID(id)
+ .orElseThrow(AlbumDoesNotExistException::new);
+ }
+
+ /**
+ * Fetch Album by its Title
+ * @param title Album Title
+ * @return Album Object
+ * @throws AlbumDoesNotExistException Album does not exist in DB
+ */
+ public Album getByTitle(String title) throws AlbumDoesNotExistException {
+ return albumRepository.getAlbumByAlbumTitle(title)
+ .orElseThrow(AlbumDoesNotExistException::new);
+ }
+
+ /**
+ * Delete album by ID
+ * @param id Album ID
+ * @throws AlbumDoesNotExistException Album does not exist in DB
+ */
+ public void delete(int id) throws AlbumDoesNotExistException {
+ albumRepository.delete(getByID(id));
+ }
+
+ /**
+ * Delete album by album
+ * @param album Album object
+ * @throws AlbumDoesNotExistException Album does not exist in DB
+ */
+ public void delete(Optional album) throws AlbumDoesNotExistException {
+ albumRepository.delete(album.get());
+ }
+
+ /**
+ * This method saves an album to the DB
+ * @param album Album object that we'll be saving to the DB
+ */
+ public void save(Album album) {
+ albumRepository.save(album);
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/ArtistService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/ArtistService.java
new file mode 100644
index 0000000..1497cb9
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/ArtistService.java
@@ -0,0 +1,30 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Artist;
+import VanquishP2.Application.Beans.Repos.ArtistRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class ArtistService {
+ private final ArtistRepository artistRepository;
+
+ @Autowired
+ public ArtistService(ArtistRepository artistRepository) {
+ this.artistRepository = artistRepository;
+ }
+
+ public void save(Artist artist){
+ artistRepository.save(artist);
+ }
+
+ public Artist getArtist(Integer id){
+ return artistRepository.getById(id);
+ }
+
+ public Artist getArtistByName(String name){
+ return artistRepository.findByName(name);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/ConcertService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/ConcertService.java
new file mode 100644
index 0000000..d174b99
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/ConcertService.java
@@ -0,0 +1,40 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Concert;
+import VanquishP2.Application.Beans.Repos.ConcertRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+@Transactional
+public class ConcertService {
+ private final ConcertRepository concertRepository;
+
+ @Autowired
+ public ConcertService(ConcertRepository concertRepository) {
+ this.concertRepository = concertRepository;
+ }
+
+ public void save(Concert concert){
+ concertRepository.save(concert);
+ }
+
+ public Concert getConcert(Integer id){
+ return concertRepository.getById(id);
+ }
+
+ public List getConcertList(){
+ return concertRepository.findAll();
+ }
+
+ public void deleteConcert(Concert concert) {
+ concertRepository.delete(concert);
+ }
+
+ public void deleteAllConcerts() {
+ concertRepository.deleteAll();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/GenreService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/GenreService.java
new file mode 100644
index 0000000..3d462d3
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/GenreService.java
@@ -0,0 +1,26 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Genre;
+import VanquishP2.Application.Beans.Repos.GenreRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class GenreService {
+ private final GenreRepository repo;
+
+ @Autowired
+ public GenreService(GenreRepository repo){
+ this.repo = repo;
+ }
+
+ public void save(Genre genre){
+ repo.save(genre);
+ }
+
+ public Genre getGenre(Integer id){
+ return repo.getById(id);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/LikeDislikeService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/LikeDislikeService.java
new file mode 100644
index 0000000..322916c
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/LikeDislikeService.java
@@ -0,0 +1,57 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Track;
+import VanquishP2.Application.Beans.Models.User;
+import VanquishP2.Application.Beans.Models.UserInfo;
+import VanquishP2.Application.Beans.Repos.TrackRepository;
+import VanquishP2.Application.Beans.Repos.UserInfoRepository;
+import VanquishP2.Application.Beans.Repos.UserRepository;
+import VanquishP2.Exceptions.UserDoesNotExistException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Optional;
+
+@Service
+@Transactional
+public class LikeDislikeService {
+ private final TrackRepository trackRepository;
+ private final UserRepository userRepository;
+ private final UserInfoRepository userInfoRepository;
+ private final String exceptionError = "User: %s does not exist.";
+
+ @Autowired
+ public LikeDislikeService(TrackRepository trackRepository, UserRepository userRepository, UserInfoRepository userInfoRepository){
+ this.trackRepository = trackRepository;
+ this.userRepository = userRepository;
+ this.userInfoRepository = userInfoRepository;
+ }
+
+ public void saveTrack(Track track){
+ trackRepository.save(track);
+ }
+
+ public Track getTrack(Integer id){
+ return trackRepository.getById(id);
+ }
+
+ public void saveUser(User user)
+ {
+ userRepository.save(user);
+ }
+
+ public User getUser(Integer id)
+ {
+ return userRepository.getById(id);
+ }
+
+ public Optional getUserByUsername(String username) throws UserDoesNotExistException
+ {
+ Optional optionalUserInfo = userInfoRepository.findByUsername(username);
+ return optionalUserInfo
+ .map(userInfo -> userRepository.findUserByUserInfo(userInfo)
+ .orElseThrow(() -> new UserDoesNotExistException(String.format(exceptionError, username))));
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/LocationService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/LocationService.java
new file mode 100644
index 0000000..f80cae2
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/LocationService.java
@@ -0,0 +1,54 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+
+import VanquishP2.Application.Beans.Models.Location;
+import VanquishP2.Application.Beans.Repos.LocationRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+@Transactional
+public class LocationService {
+ private final LocationRepository locationRepository;
+
+ @Autowired
+ public LocationService(LocationRepository locationRepository){
+ this.locationRepository = locationRepository;
+ }
+
+ public Location saveLocation(Location location){
+ locationRepository.save(location);
+ return locationRepository.getById(location.getLocationID());
+ }
+
+ // Kollier added this
+ public List getAll(){
+ return locationRepository.findAll();
+ }
+
+ public Location getLocationById(Integer id){
+ return locationRepository.getById(id);
+ }
+
+ public void save(Location location) {
+ locationRepository.save(location);
+ }
+
+ public void deleteLocationById(Integer id){
+ locationRepository.delete(locationRepository.getById(id));
+ }
+
+ public void deleteLocation(Location location){
+ locationRepository.delete(location);
+ }
+
+ /**
+ * To reset DB data if necessary
+ */
+ public void deleteAllLocations(){
+ locationRepository.deleteAll();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/LoggerService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/LoggerService.java
new file mode 100644
index 0000000..37756f7
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/LoggerService.java
@@ -0,0 +1,31 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Logger;
+import VanquishP2.Application.Beans.Repos.LoggerRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.text.SimpleDateFormat;
+
+@Service
+@Transactional
+public class LoggerService {
+ private final LoggerRepo repo;
+
+ @Autowired
+ public LoggerService(LoggerRepo repo) {
+ this.repo = repo;
+ }
+
+ public void writeLog(String message, int level) {
+ Logger logger = new Logger(getCurrentDateTime(), message, level);
+
+ repo.save(logger);
+ }
+
+ private String getCurrentDateTime() {
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ return formatter.format(System.currentTimeMillis());
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/PlaylistService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/PlaylistService.java
new file mode 100644
index 0000000..d370473
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/PlaylistService.java
@@ -0,0 +1,24 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Playlist;
+import VanquishP2.Application.Beans.Repos.PlaylistRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class PlaylistService {
+ private PlaylistRepository repo;
+
+ @Autowired
+ public PlaylistService(PlaylistRepository repo){
+ this.repo = repo;
+ }
+ public void save(Playlist playlist){
+ repo.save(playlist);
+ }
+ public Playlist getPlaylist_name (Integer playlist_id){
+ return repo.getById(playlist_id);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/TrackService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/TrackService.java
new file mode 100644
index 0000000..79fcaf0
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/TrackService.java
@@ -0,0 +1,31 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Track;
+import VanquishP2.Application.Beans.Repos.TrackRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class TrackService {
+ private final TrackRepository repo;
+
+ @Autowired
+ public TrackService(TrackRepository repo){
+ this.repo = repo;
+ }
+
+ public void save(Track track){
+ repo.save(track);
+ }
+
+ public Track getTrack(Integer id){
+ return repo.getById(id);
+ }
+
+ public boolean trackExists(Integer id)
+ {
+ return repo.existsById(id);
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/UserInfoService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/UserInfoService.java
new file mode 100644
index 0000000..9441dde
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/UserInfoService.java
@@ -0,0 +1,105 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.UserInfo;
+import VanquishP2.Application.Beans.Repos.UserInfoRepository;
+import VanquishP2.Exceptions.UserDoesNotExistException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Transactional
+public class UserInfoService {
+ private final UserInfoRepository userInfoRepository;
+ private final String exceptionError = "User: %s does not exist.";
+
+ @Autowired
+ public UserInfoService(UserInfoRepository userInfoRepository) {
+ this.userInfoRepository = userInfoRepository;
+ }
+
+ public UserInfo saveUserInfo(UserInfo userInfo){
+ userInfoRepository.save(userInfo);
+ return userInfoRepository.getById(userInfo.getID());
+ }
+
+ public UserInfo getUserInfoById(Integer id){
+ return userInfoRepository.getById(id);
+ }
+
+ public String getEmailById(Integer id){
+ UserInfo info = userInfoRepository.getById(id);
+ return info.getEmail();
+ }
+
+ public String getUsernameById(Integer id){
+ UserInfo info = userInfoRepository.getById(id);
+ return info.getUsername();
+ }
+
+ public String getPasswordById(Integer id){
+ UserInfo info = userInfoRepository.getById(id);
+ return info.getPassword();
+ }
+
+ public List getLoginById(Integer id){
+ UserInfo info = userInfoRepository.getById(id);
+ List login = new LinkedList<>();
+ login.add(info.getUsername());
+ login.add(info.getPassword());
+ return login;
+ }
+
+ public UserInfo getByFirstName(String firstName) {
+ return userInfoRepository.findByFirstName(firstName).get();
+ }
+
+ public void save(UserInfo userInfo) {
+ userInfoRepository.save(userInfo);
+ }
+
+ public void deleteUserInfo(UserInfo info){
+ userInfoRepository.delete(info);
+ }
+
+ /**
+ * To reset DB data if necessary
+ */
+ public void deleteAllInfo(){
+ userInfoRepository.deleteAll();
+ }
+
+ /**
+ * This method fetches all User Info in the DB
+ * @author Kollier Martin
+ * @date 11/8/2021
+ * @return List of users present in DB
+ */
+ public List getAll() {
+ return userInfoRepository.findAll();
+ }
+
+ /**
+ * Authenticate User
+ * @date 11/8/2021
+ * @author Kollier Martin
+ * @param username Username
+ * @param password Password
+ * @return User Info, either null or not null
+ */
+ public Optional authenticate(String username, String password) throws UserDoesNotExistException {
+ Optional userInfo;
+
+ userInfo = userInfoRepository.findByUsernameAndPassword(username, password);
+
+ if (!userInfo.isPresent()) {
+ throw new UserDoesNotExistException(exceptionError);
+ }
+
+ return userInfo;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/VanquishP2/Application/Beans/ModelServices/UserService.java b/src/main/java/VanquishP2/Application/Beans/ModelServices/UserService.java
new file mode 100644
index 0000000..85623ec
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/ModelServices/UserService.java
@@ -0,0 +1,119 @@
+package VanquishP2.Application.Beans.ModelServices;
+
+import VanquishP2.Application.Beans.Models.Location;
+import VanquishP2.Application.Beans.Models.User;
+import VanquishP2.Application.Beans.Models.UserInfo;
+import VanquishP2.Application.Beans.Repos.LocationRepository;
+import VanquishP2.Application.Beans.Repos.UserInfoRepository;
+import VanquishP2.Application.Beans.Repos.UserRepository;
+import VanquishP2.DTOs.UserRegistrationDTO;
+import VanquishP2.Exceptions.UserDoesNotExistException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+/**
+ * This service bean is used to talk to its designated repository and handle data retrieval
+ *
+ * @date 10/29/2021
+ * @author Kollier Martin
+ */
+
+@Service
+@Transactional
+public class UserService {
+ private final UserRepository userRepository;
+ private final UserInfoRepository userInfoRepository;
+ private final LocationRepository locationRepository;
+ private final String exceptionError = "User: %s does not exist.";
+
+ @Autowired
+ public UserService(UserRepository userRepository,
+ UserInfoRepository userInfoRepository,
+ LocationRepository locationRepository) {
+ this.userRepository = userRepository;
+ this.userInfoRepository = userInfoRepository;
+ this.locationRepository = locationRepository;
+ }
+
+ /**
+ * This method fetches all Users in the DB
+ * @return List of users present in DB
+ */
+ public List getAllUsers(){
+ return userRepository.findAll();
+ }
+
+ /**
+ * This method fetches User by ID
+ * @param ID User ID
+ * @return User object
+ */
+ public User getByID(int ID) throws UserDoesNotExistException {
+ User user;
+
+ user = userRepository.findByID(ID)
+ .orElseThrow(() -> new UserDoesNotExistException(String.format(exceptionError, ID)));
+
+
+ return user;
+ }
+
+ /**
+ * This method fetches a User based on UserInfo
+ * @param userInfo UserInfo object
+ * @return User object
+ */
+ public User getByUserInfo(UserInfo userInfo) {
+ User user;
+
+ user = userRepository.findUserByUserInfo(userInfo)
+ .orElseThrow(() -> new UserDoesNotExistException(String.format(exceptionError, userInfo)));
+
+ return user;
+ }
+
+ /**
+ * Persist User to DB
+ * @param user User Object
+ * @return Persisted User Object
+ */
+ public void save(User user) {
+ userRepository.save(user);
+ }
+
+ /**
+ * Delete User by ID
+ * @param id User ID
+ * @return User of the specific ID
+ */
+ public void delete(int id) throws UserDoesNotExistException {
+ userRepository.deleteByID(id);
+ }
+
+ /**
+ * Register New User
+ * @param data UserRegistration data to persist
+ * @return The new persisted Object
+ */
+ public User registerUser(UserRegistrationDTO data, User.Role role) {
+ User newUser;
+ UserInfo newUserInfo;
+ Location location;
+
+ location = new Location(data.getCity(), data.getState());
+ newUserInfo = new UserInfo(data);
+ newUser = new User(role, newUserInfo);
+
+ locationRepository.save(location);
+ userRepository.save(newUser);
+
+ newUserInfo.setLocation(location);
+ newUserInfo.setUser(newUser);
+ userInfoRepository.save(newUserInfo);
+
+ return newUser;
+ }
+}
diff --git a/src/main/java/VanquishP2/Application/Beans/Models/Album.java b/src/main/java/VanquishP2/Application/Beans/Models/Album.java
new file mode 100644
index 0000000..e0a992c
--- /dev/null
+++ b/src/main/java/VanquishP2/Application/Beans/Models/Album.java
@@ -0,0 +1,90 @@
+package VanquishP2.Application.Beans.Models;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used to declare the POJO, Album
+ * @date 10/29/2021
+ * @author Kollier Martin
+ */
+
+@Table(name = "ALBUMS")
+@Entity
+@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"}, ignoreUnknown = true)
+public class Album implements Serializable {
+ public Album() {
+ tracks = new ArrayList<>();
+ }
+
+ @Id
+ @Column(name = "AlbumID")
+ private Integer albumID;
+ public Integer getAlbumID() {
+ return albumID;
+ }
+ public void setAlbumID(Integer ID) {
+ this.albumID = ID;
+ }
+
+ @Column(name = "AlbumTitle")
+ private String albumTitle;
+ public String getAlbumTitle() {
+ return albumTitle;
+ }
+ public void setAlbumTitle(String albumTitle) {
+ this.albumTitle = albumTitle;
+ }
+
+ @Column(name = "ReleaseDate")
+ private String date;
+ public String getDate() {
+ return date;
+ }
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ @ManyToOne
+ private Artist artist;
+ public Artist getArtist() {
+ return artist;
+ }
+ public void setArtist(Artist artist) {
+ this.artist = artist;
+ }
+
+ @OneToMany
+ private List