From 21ff0a107020e47881e609c5f8222b903e4a7f21 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Fri, 1 Sep 2017 18:06:17 -0600 Subject: [PATCH 1/2] Rename rest controller to be clear this is for the subsonic api Signed-off-by: Andrew DeMaria --- .../{RESTController.java => SubsonicRESTController.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename airsonic-main/src/main/java/org/airsonic/player/controller/{RESTController.java => SubsonicRESTController.java} (100%) diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/RESTController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java similarity index 100% rename from airsonic-main/src/main/java/org/airsonic/player/controller/RESTController.java rename to airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java From 51853e53a1254818edd656ecc61da3ddfd108cec Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Fri, 1 Sep 2017 18:13:50 -0600 Subject: [PATCH 2/2] REST api tweaks - Moved bookmark caching logic into service layer - Removed returning "null" when writing to the response directly - Finish renaming to subsonic rest controller Signed-off-by: Andrew DeMaria --- .../player/controller/AvatarController.java | 6 +- .../player/controller/CoverArtController.java | 8 +-- .../player/controller/DownloadController.java | 7 +- .../player/controller/HLSController.java | 11 ++- .../player/controller/JAXBWriter.java | 2 +- .../player/controller/ProxyController.java | 5 +- .../player/controller/StreamController.java | 13 ++-- .../controller/SubsonicRESTController.java | 69 ++++++++----------- .../airsonic/player/filter/RESTFilter.java | 4 +- .../RESTRequestParameterProcessingFilter.java | 26 +++---- .../player/service/BookmarkService.java | 40 +++++++++++ 11 files changed, 105 insertions(+), 86 deletions(-) create mode 100644 airsonic-main/src/main/java/org/airsonic/player/service/BookmarkService.java diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/AvatarController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/AvatarController.java index b29e99da..72a1ce06 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/AvatarController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/AvatarController.java @@ -28,7 +28,6 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.LastModified; import javax.servlet.http.HttpServletRequest; @@ -60,17 +59,16 @@ public class AvatarController implements LastModified { } @RequestMapping(method = RequestMethod.GET) - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { Avatar avatar = getAvatar(request); if (avatar == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); - return null; + return; } response.setContentType(avatar.getMimeType()); response.getOutputStream().write(avatar.getData()); - return null; } private Avatar getAvatar(HttpServletRequest request) { diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/CoverArtController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/CoverArtController.java index 711d0a50..84673b2a 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/CoverArtController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/CoverArtController.java @@ -35,7 +35,6 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.LastModified; import javax.annotation.PostConstruct; @@ -98,7 +97,7 @@ public class CoverArtController implements LastModified { } @RequestMapping(method = RequestMethod.GET) - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { CoverArtRequest coverArtRequest = createCoverArtRequest(request); // LOG.info("handleRequest - " + coverArtRequest); @@ -107,14 +106,14 @@ public class CoverArtController implements LastModified { // Send fallback image if no ID is given. (No need to cache it, since it will be cached in browser.) if (coverArtRequest == null) { sendFallback(size, response); - return null; + return; } // Optimize if no scaling is required. if (size == null && coverArtRequest.getCoverArt() != null) { // LOG.info("sendUnscaled - " + coverArtRequest); sendUnscaled(coverArtRequest, response); - return null; + return; } // Send cached image, creating it if necessary. @@ -128,7 +127,6 @@ public class CoverArtController implements LastModified { sendFallback(size, response); } - return null; } private CoverArtRequest createCoverArtRequest(HttpServletRequest request) { diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/DownloadController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/DownloadController.java index 22958479..d31aeb50 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/DownloadController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/DownloadController.java @@ -35,7 +35,6 @@ import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.LastModified; import javax.servlet.http.HttpServletRequest; @@ -89,7 +88,7 @@ public class DownloadController implements LastModified { } @RequestMapping(method = RequestMethod.GET) - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { User user = securityService.getCurrentUser(request); TransferStatus status = null; @@ -118,7 +117,7 @@ public class DownloadController implements LastModified { if (!securityService.isFolderAccessAllowed(mediaFile, user.getUsername())) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access to file " + mediaFile.getId() + " is forbidden for user " + user.getUsername()); - return null; + return; } if (mediaFile.isFile()) { @@ -148,8 +147,6 @@ public class DownloadController implements LastModified { securityService.updateUserByteCounts(user, 0L, status.getBytesTransfered(), 0L); } } - - return null; } private MediaFile getMediaFile(HttpServletRequest request) throws ServletRequestBindingException { diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/HLSController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/HLSController.java index de0c2ac6..18ace0cb 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/HLSController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/HLSController.java @@ -33,7 +33,6 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; @@ -68,7 +67,7 @@ public class HLSController { private JWTSecurityService jwtSecurityService; @RequestMapping(method = RequestMethod.GET) - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { response.setHeader("Access-Control-Allow-Origin", "*"); @@ -79,19 +78,19 @@ public class HLSController { if (mediaFile == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND, "Media file not found: " + id); - return null; + return; } if (username != null && !securityService.isFolderAccessAllowed(mediaFile, username)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access to file " + mediaFile.getId() + " is forbidden for user " + username); - return null; + return; } Integer duration = mediaFile.getDurationSeconds(); if (duration == null || duration == 0) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unknown duration for media file: " + id); - return null; + return; } response.setContentType("application/vnd.apple.mpegurl"); @@ -104,7 +103,7 @@ public class HLSController { generateNormalPlaylist(request, id, player, bitRates.size() == 1 ? bitRates.get(0) : null, duration, writer); } - return null; + return; } private List> parseBitRates(HttpServletRequest request) throws IllegalArgumentException { diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/JAXBWriter.java b/airsonic-main/src/main/java/org/airsonic/player/controller/JAXBWriter.java index 585ddd0a..cf7c32fb 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/JAXBWriter.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/JAXBWriter.java @@ -157,7 +157,7 @@ public class JAXBWriter { } public void writeErrorResponse(HttpServletRequest request, HttpServletResponse response, - RESTController.ErrorCode code, String message) throws Exception { + SubsonicRESTController.ErrorCode code, String message) throws Exception { Response res = createResponse(false); Error error = new Error(); res.setError(error); diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/ProxyController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/ProxyController.java index 7081d9bd..ae3bce10 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/ProxyController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/ProxyController.java @@ -20,7 +20,6 @@ package org.airsonic.player.controller; import org.apache.commons.io.IOUtils; -import org.apache.http.HttpStatus; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; @@ -37,6 +36,8 @@ import javax.servlet.http.HttpServletResponse; import java.io.InputStream; +import static org.springframework.http.HttpStatus.*; + /** * A proxy for external HTTP requests. * @@ -61,7 +62,7 @@ public class ProxyController { try (CloseableHttpClient client = HttpClients.createDefault()) { try (CloseableHttpResponse resp = client.execute(method)) { int statusCode = resp.getStatusLine().getStatusCode(); - if (statusCode != HttpStatus.SC_OK) { + if (statusCode != OK.value()) { response.sendError(statusCode); } else { in = resp.getEntity().getContent(); diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java index d42c5a89..51b20919 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java @@ -40,7 +40,6 @@ import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -84,7 +83,7 @@ public class StreamController { private SearchService searchService; @RequestMapping(method = RequestMethod.GET) - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { TransferStatus status = null; PlayQueueInputStream in = null; @@ -96,7 +95,7 @@ public class StreamController { if (!(authentication instanceof JWTAuthenticationToken) && !user.isStreamRole()) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Streaming is forbidden for user " + user.getUsername()); - return null; + return; } // If "playlist" request parameter is set, this is a Podcast request. In that case, create a separate @@ -136,7 +135,7 @@ public class StreamController { if (!(authentication instanceof JWTAuthenticationToken) && !securityService.isFolderAccessAllowed(file, user.getUsername())) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access to file " + file.getId() + " is forbidden for user " + user.getUsername()); - return null; + return; } // Update the index of the currently playing media file. At @@ -189,7 +188,7 @@ public class StreamController { } if (request.getMethod().equals("HEAD")) { - return null; + return; } // Terminate any other streams to this player. @@ -226,7 +225,7 @@ public class StreamController { // Check if stream has been terminated. if (status.terminated()) { - return null; + return; } if (player.getPlayQueue().getStatus() == PlayQueue.Status.STOPPED) { @@ -257,7 +256,7 @@ public class StreamController { } IOUtils.closeQuietly(in); } - return null; + return; } private void setContentDuration(HttpServletResponse response, MediaFile file) { diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java index d4b63dc5..1820035b 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/SubsonicRESTController.java @@ -23,8 +23,12 @@ import org.airsonic.player.ajax.LyricsInfo; import org.airsonic.player.ajax.LyricsService; import org.airsonic.player.ajax.PlayQueueService; import org.airsonic.player.command.UserSettingsCommand; -import org.airsonic.player.dao.*; +import org.airsonic.player.dao.AlbumDao; +import org.airsonic.player.dao.ArtistDao; +import org.airsonic.player.dao.MediaFileDao; +import org.airsonic.player.dao.PlayQueueDao; import org.airsonic.player.domain.*; +import org.airsonic.player.domain.Bookmark; import org.airsonic.player.service.*; import org.airsonic.player.util.Pair; import org.airsonic.player.util.StringUtil; @@ -43,7 +47,6 @@ import org.springframework.web.servlet.ModelAndView; import org.subsonic.restapi.*; import org.subsonic.restapi.PodcastStatus; -import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @@ -65,9 +68,9 @@ import static org.springframework.web.bind.ServletRequestUtils.*; */ @Controller @RequestMapping(value = "/rest", method = {RequestMethod.GET, RequestMethod.POST}) -public class RESTController { +public class SubsonicRESTController { - private static final Logger LOG = LoggerFactory.getLogger(RESTController.class); + private static final Logger LOG = LoggerFactory.getLogger(SubsonicRESTController.class); @Autowired private SettingsService settingsService; @@ -124,7 +127,7 @@ public class RESTController { @Autowired private AlbumDao albumDao; @Autowired - private BookmarkDao bookmarkDao; + private BookmarkService bookmarkService; @Autowired private PlayQueueDao playQueueDao; @Autowired @@ -136,18 +139,6 @@ public class RESTController { private static final String NOT_YET_IMPLEMENTED = "Not yet implemented"; private static final String NO_LONGER_SUPPORTED = "No longer supported"; - @PostConstruct - public void init() { - refreshBookmarkCache(); - } - - private void refreshBookmarkCache() { - bookmarkCache.clear(); - for (org.airsonic.player.domain.Bookmark bookmark : bookmarkDao.getBookmarks()) { - bookmarkCache.put(BookmarkKey.forBookmark(bookmark), bookmark); - } - } - @RequestMapping(value = "/ping") public void ping(HttpServletRequest request, HttpServletResponse response) throws Exception { Response res = createResponse(); @@ -1337,12 +1328,12 @@ public class RESTController { } @RequestMapping(value = "/download") - public ModelAndView download(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void download(HttpServletRequest request, HttpServletResponse response) throws Exception { request = wrapRequest(request); org.airsonic.player.domain.User user = securityService.getCurrentUser(request); if (!user.isDownloadRole()) { error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to download files."); - return null; + return; } long ifModifiedSince = request.getDateHeader("If-Modified-Since"); @@ -1350,49 +1341,47 @@ public class RESTController { if (ifModifiedSince != -1 && lastModified != -1 && lastModified <= ifModifiedSince) { response.sendError(HttpServletResponse.SC_NOT_MODIFIED); - return null; + return; } if (lastModified != -1) { response.setDateHeader("Last-Modified", lastModified); } - return downloadController.handleRequest(request, response); + downloadController.handleRequest(request, response); } @RequestMapping(value = "/stream") - public ModelAndView stream(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void stream(HttpServletRequest request, HttpServletResponse response) throws Exception { request = wrapRequest(request); org.airsonic.player.domain.User user = securityService.getCurrentUser(request); if (!user.isStreamRole()) { error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to play files."); - return null; + return; } streamController.handleRequest(request, response); - return null; } @RequestMapping(value = "/hls") - public ModelAndView hls(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void hls(HttpServletRequest request, HttpServletResponse response) throws Exception { request = wrapRequest(request); org.airsonic.player.domain.User user = securityService.getCurrentUser(request); if (!user.isStreamRole()) { error(request, response, ErrorCode.NOT_AUTHORIZED, user.getUsername() + " is not authorized to play files."); - return null; + return; } int id = getRequiredIntParameter(request, "id"); MediaFile video = mediaFileDao.getMediaFile(id); if (video == null || video.isDirectory()) { error(request, response, ErrorCode.NOT_FOUND, "Video not found."); - return null; + return; } if (!securityService.isFolderAccessAllowed(video, user.getUsername())) { error(request, response, ErrorCode.NOT_AUTHORIZED, "Access denied"); - return null; + return; } hlsController.handleRequest(request, response); - return null; } @RequestMapping(value = "/scrobble") @@ -1702,7 +1691,7 @@ public class RESTController { String username = securityService.getCurrentUsername(request); Bookmarks result = new Bookmarks(); - for (org.airsonic.player.domain.Bookmark bookmark : bookmarkDao.getBookmarks(username)) { + for (Bookmark bookmark : bookmarkService.getBookmarks(username)) { org.subsonic.restapi.Bookmark b = new org.subsonic.restapi.Bookmark(); result.getBookmark().add(b); b.setPosition(bookmark.getPositionMillis()); @@ -1729,9 +1718,8 @@ public class RESTController { String comment = request.getParameter("comment"); Date now = new Date(); - org.airsonic.player.domain.Bookmark bookmark = new org.airsonic.player.domain.Bookmark(0, mediaFileId, position, username, comment, now, now); - bookmarkDao.createOrUpdateBookmark(bookmark); - refreshBookmarkCache(); + Bookmark bookmark = new Bookmark(0, mediaFileId, position, username, comment, now, now); + bookmarkService.createOrUpdateBookmark(bookmark); writeEmptyResponse(request, response); } @@ -1741,8 +1729,7 @@ public class RESTController { String username = securityService.getCurrentUsername(request); int mediaFileId = getRequiredIntParameter(request, "id"); - bookmarkDao.deleteBookmark(username, mediaFileId); - refreshBookmarkCache(); + bookmarkService.deleteBookmark(username, mediaFileId); writeEmptyResponse(request, response); } @@ -1954,15 +1941,15 @@ public class RESTController { } @RequestMapping(value = "/getCoverArt") - public ModelAndView getCoverArt(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void getCoverArt(HttpServletRequest request, HttpServletResponse response) throws Exception { request = wrapRequest(request); - return coverArtController.handleRequest(request, response); + coverArtController.handleRequest(request, response); } @RequestMapping(value = "/getAvatar") - public ModelAndView getAvatar(HttpServletRequest request, HttpServletResponse response) throws Exception { + public void getAvatar(HttpServletRequest request, HttpServletResponse response) throws Exception { request = wrapRequest(request); - return avatarController.handleRequest(request, response); + avatarController.handleRequest(request, response); } @RequestMapping(value = "/changePassword") @@ -2237,7 +2224,7 @@ public class RESTController { MediaFile mediaFile = this.mediaFileService.getMediaFile(id); if (mediaFile == null) { - error(request, response, RESTController.ErrorCode.NOT_FOUND, "Media file not found."); + error(request, response, SubsonicRESTController.ErrorCode.NOT_FOUND, "Media file not found."); return; } AlbumNotes albumNotes = this.lastFmService.getAlbumNotes(mediaFile); @@ -2256,7 +2243,7 @@ public class RESTController { Album album = this.albumDao.getAlbum(id); if (album == null) { - error(request, response, RESTController.ErrorCode.NOT_FOUND, "Album not found."); + error(request, response, SubsonicRESTController.ErrorCode.NOT_FOUND, "Album not found."); return; } AlbumNotes albumNotes = this.lastFmService.getAlbumNotes(album); diff --git a/airsonic-main/src/main/java/org/airsonic/player/filter/RESTFilter.java b/airsonic-main/src/main/java/org/airsonic/player/filter/RESTFilter.java index af3f89d5..53cad862 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/filter/RESTFilter.java +++ b/airsonic-main/src/main/java/org/airsonic/player/filter/RESTFilter.java @@ -20,7 +20,7 @@ package org.airsonic.player.filter; import org.airsonic.player.controller.JAXBWriter; -import org.airsonic.player.controller.RESTController; +import org.airsonic.player.controller.SubsonicRESTController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.ServletRequestBindingException; @@ -61,7 +61,7 @@ public class RESTFilter implements Filter { x = x.getCause(); } - RESTController.ErrorCode code = (x instanceof ServletRequestBindingException) ? RESTController.ErrorCode.MISSING_PARAMETER : RESTController.ErrorCode.GENERIC; + SubsonicRESTController.ErrorCode code = (x instanceof ServletRequestBindingException) ? SubsonicRESTController.ErrorCode.MISSING_PARAMETER : SubsonicRESTController.ErrorCode.GENERIC; String msg = getErrorMessage(x); LOG.warn("Error in REST API: " + msg, x); diff --git a/airsonic-main/src/main/java/org/airsonic/player/security/RESTRequestParameterProcessingFilter.java b/airsonic-main/src/main/java/org/airsonic/player/security/RESTRequestParameterProcessingFilter.java index 229867da..40e7be6f 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/security/RESTRequestParameterProcessingFilter.java +++ b/airsonic-main/src/main/java/org/airsonic/player/security/RESTRequestParameterProcessingFilter.java @@ -20,7 +20,7 @@ package org.airsonic.player.security; import org.airsonic.player.controller.JAXBWriter; -import org.airsonic.player.controller.RESTController; +import org.airsonic.player.controller.SubsonicRESTController; import org.airsonic.player.domain.User; import org.airsonic.player.domain.Version; import org.airsonic.player.service.SecurityService; @@ -100,7 +100,7 @@ public class RESTRequestParameterProcessingFilter implements Filter { String version = StringUtils.trimToNull(httpRequest.getParameter("v")); String client = StringUtils.trimToNull(httpRequest.getParameter("c")); - RESTController.ErrorCode errorCode = null; + SubsonicRESTController.ErrorCode errorCode = null; // The username and credentials parameters are not required if the user // was previously authenticated, for example using Basic Auth. @@ -108,7 +108,7 @@ public class RESTRequestParameterProcessingFilter implements Filter { Authentication previousAuth = SecurityContextHolder.getContext().getAuthentication(); boolean missingCredentials = previousAuth == null && (username == null || !passwordOrTokenPresent); if (missingCredentials || version == null || client == null) { - errorCode = RESTController.ErrorCode.MISSING_PARAMETER; + errorCode = SubsonicRESTController.ErrorCode.MISSING_PARAMETER; } if (errorCode == null) { @@ -127,21 +127,21 @@ public class RESTRequestParameterProcessingFilter implements Filter { } } - private RESTController.ErrorCode checkAPIVersion(String version) { + private SubsonicRESTController.ErrorCode checkAPIVersion(String version) { Version serverVersion = new Version(jaxbWriter.getRestProtocolVersion()); Version clientVersion = new Version(version); if (serverVersion.getMajor() > clientVersion.getMajor()) { - return RESTController.ErrorCode.PROTOCOL_MISMATCH_CLIENT_TOO_OLD; + return SubsonicRESTController.ErrorCode.PROTOCOL_MISMATCH_CLIENT_TOO_OLD; } else if (serverVersion.getMajor() < clientVersion.getMajor()) { - return RESTController.ErrorCode.PROTOCOL_MISMATCH_SERVER_TOO_OLD; + return SubsonicRESTController.ErrorCode.PROTOCOL_MISMATCH_SERVER_TOO_OLD; } else if (serverVersion.getMinor() < clientVersion.getMinor()) { - return RESTController.ErrorCode.PROTOCOL_MISMATCH_SERVER_TOO_OLD; + return SubsonicRESTController.ErrorCode.PROTOCOL_MISMATCH_SERVER_TOO_OLD; } return null; } - private RESTController.ErrorCode authenticate(HttpServletRequest httpRequest, String username, String password, String salt, String token, Authentication previousAuth) { + private SubsonicRESTController.ErrorCode authenticate(HttpServletRequest httpRequest, String username, String password, String salt, String token, Authentication previousAuth) { // Previously authenticated and username not overridden? if (username == null && previousAuth != null) { @@ -151,11 +151,11 @@ public class RESTRequestParameterProcessingFilter implements Filter { if (salt != null && token != null) { User user = securityService.getUserByName(username); if (user == null) { - return RESTController.ErrorCode.NOT_AUTHENTICATED; + return SubsonicRESTController.ErrorCode.NOT_AUTHENTICATED; } String expectedToken = DigestUtils.md5Hex(user.getPassword() + salt); if (!expectedToken.equals(token)) { - return RESTController.ErrorCode.NOT_AUTHENTICATED; + return SubsonicRESTController.ErrorCode.NOT_AUTHENTICATED; } password = user.getPassword(); @@ -170,11 +170,11 @@ public class RESTRequestParameterProcessingFilter implements Filter { return null; } catch (AuthenticationException x) { eventPublisher.publishEvent(new AuthenticationFailureBadCredentialsEvent(authRequest, x)); - return RESTController.ErrorCode.NOT_AUTHENTICATED; + return SubsonicRESTController.ErrorCode.NOT_AUTHENTICATED; } } - return RESTController.ErrorCode.MISSING_PARAMETER; + return SubsonicRESTController.ErrorCode.MISSING_PARAMETER; } public static String decrypt(String s) { @@ -191,7 +191,7 @@ public class RESTRequestParameterProcessingFilter implements Filter { } } - private void sendErrorXml(HttpServletRequest request, HttpServletResponse response, RESTController.ErrorCode errorCode) throws IOException { + private void sendErrorXml(HttpServletRequest request, HttpServletResponse response, SubsonicRESTController.ErrorCode errorCode) throws IOException { try { jaxbWriter.writeErrorResponse(request, response, errorCode, errorCode.getMessage()); } catch (Exception e) { diff --git a/airsonic-main/src/main/java/org/airsonic/player/service/BookmarkService.java b/airsonic-main/src/main/java/org/airsonic/player/service/BookmarkService.java new file mode 100644 index 00000000..39b805d4 --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/service/BookmarkService.java @@ -0,0 +1,40 @@ +package org.airsonic.player.service; + +import org.airsonic.player.dao.BookmarkDao; +import org.airsonic.player.domain.Bookmark; +import org.airsonic.player.domain.MediaFile; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; + +@Service +public class BookmarkService { + + private final BookmarkDao dao; + + @Autowired + public BookmarkService(BookmarkDao dao) { + this.dao = dao; + } + + public Bookmark getBookmarkForUserAndMediaFile(String username, MediaFile mediaFile) { + return dao.getBookmarks(username) + .stream() + .filter(bookmark -> Objects.equals(mediaFile.getId(), bookmark.getMediaFileId())) + .findFirst().orElse(null); + } + + public void createOrUpdateBookmark(Bookmark bookmark) { + dao.createOrUpdateBookmark(bookmark); + } + + public void deleteBookmark(String username, int mediaFileId) { + dao.deleteBookmark(username, mediaFileId); + } + + public List getBookmarks(String username) { + return dao.getBookmarks(username); + } +}