diff --git a/src/main/java/me/minidigger/hangar/controller/api/ProjectsApi.java b/src/main/java/me/minidigger/hangar/controller/api/ProjectsApi.java index c4e623f0f..dcd899bb3 100644 --- a/src/main/java/me/minidigger/hangar/controller/api/ProjectsApi.java +++ b/src/main/java/me/minidigger/hangar/controller/api/ProjectsApi.java @@ -42,8 +42,8 @@ public interface ProjectsApi { , @ApiParam(value = "Restrict your search to a list of categories") @Valid @RequestParam(value = "categories", required = false) List categories , @ApiParam(value = "A list of tags all the returned projects should have. Should be formated either as `tagname` or `tagname:tagdata`.") @Valid @RequestParam(value = "tags", required = false) List tags , @ApiParam(value = "Limit the search to a specific user") @Valid @RequestParam(value = "owner", required = false) String owner - , @ApiParam(value = "How to sort the projects") @Valid @RequestParam(value = "sort", required = false) ProjectSortingStrategy sort - , @ApiParam(value = "If how relevant the project is to the given query should be used when sorting the projects") @Valid @RequestParam(value = "relevance", required = false) Boolean relevance + , @ApiParam(value = "How to sort the projects") @Valid @RequestParam(value = "sort", required = false, defaultValue = "updated") ProjectSortingStrategy sort + , @ApiParam(value = "If how relevant the project is to the given query should be used when sorting the projects") @Valid @RequestParam(value = "relevance", required = false, defaultValue = "true") boolean relevance , @ApiParam(value = "The maximum amount of projects to return") @Valid @RequestParam(value = "limit", required = false) Long limit , @ApiParam(value = "Where to start searching", defaultValue = "0") @Valid @RequestParam(value = "offset", required = false, defaultValue = "0") Long offset ); diff --git a/src/main/java/me/minidigger/hangar/controller/api/ProjectsApiController.java b/src/main/java/me/minidigger/hangar/controller/api/ProjectsApiController.java index cfdc72b60..5d5d3f9e3 100644 --- a/src/main/java/me/minidigger/hangar/controller/api/ProjectsApiController.java +++ b/src/main/java/me/minidigger/hangar/controller/api/ProjectsApiController.java @@ -2,9 +2,6 @@ package me.minidigger.hangar.controller.api; import com.fasterxml.jackson.databind.ObjectMapper; -import me.minidigger.hangar.db.dao.HangarDao; -import me.minidigger.hangar.db.dao.ProjectDao; -import me.minidigger.hangar.service.project.ProjectService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,16 +11,27 @@ import org.springframework.stereotype.Controller; import java.io.IOException; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import me.minidigger.hangar.config.hangar.HangarConfig; +import me.minidigger.hangar.db.model.UsersTable; import me.minidigger.hangar.model.Category; +import me.minidigger.hangar.model.Permission; import me.minidigger.hangar.model.generated.PaginatedProjectResult; +import me.minidigger.hangar.model.generated.Pagination; import me.minidigger.hangar.model.generated.Project; import me.minidigger.hangar.model.generated.ProjectMember; import me.minidigger.hangar.model.generated.ProjectSortingStrategy; import me.minidigger.hangar.model.generated.ProjectStatsDay; +import me.minidigger.hangar.model.generated.Tag; +import me.minidigger.hangar.service.PermissionService; +import me.minidigger.hangar.service.UserService; +import me.minidigger.hangar.service.project.ProjectService; + +import static me.minidigger.hangar.util.ApiUtil.limitOrDefault; +import static me.minidigger.hangar.util.ApiUtil.offsetOrZero; @Controller public class ProjectsApiController implements ProjectsApi { @@ -32,28 +40,75 @@ public class ProjectsApiController implements ProjectsApi { private final ObjectMapper objectMapper; private final ProjectService projectService; - - private final HttpServletRequest request; + private final HangarConfig hangarConfig; + private final UserService userService; + private final PermissionService permissionService; @Autowired - public ProjectsApiController(ObjectMapper objectMapper, HttpServletRequest request, ProjectService projectService) { + public ProjectsApiController(ObjectMapper objectMapper, ProjectService projectService, HangarConfig hangarConfig, UserService userService, PermissionService permissionService) { this.objectMapper = objectMapper; - this.request = request; this.projectService = projectService; + this.hangarConfig = hangarConfig; + this.userService = userService; + this.permissionService = permissionService; } @Override - public ResponseEntity listProjects(String q, List categories, List tags, String owner, ProjectSortingStrategy sort, Boolean relevance, Long limit, Long offset) { - try { - return new ResponseEntity<>(objectMapper.readValue("{\n \"result\" : [ {\n \"icon_url\" : \"icon_url\",\n \"plugin_id\" : \"plugin_id\",\n \"settings\" : {\n \"license\" : {\n \"name\" : \"name\",\n \"url\" : \"url\"\n },\n \"sources\" : \"sources\",\n \"forum_sync\" : true,\n \"issues\" : \"issues\",\n \"support\" : \"support\",\n \"homepage\" : \"homepage\"\n },\n \"last_updated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"visibility\" : \"public\",\n \"user_actions\" : {\n \"starred\" : true,\n \"watching\" : true\n },\n \"created_at\" : \"2000-01-23T04:56:07.000+00:00\",\n \"description\" : \"description\",\n \"promoted_versions\" : [ {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n }, {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n } ],\n \"stats\" : {\n \"downloads\" : 5,\n \"recent_downloads\" : 7,\n \"recent_views\" : 2,\n \"watchers\" : 3,\n \"stars\" : 9,\n \"views\" : 5\n },\n \"name\" : \"name\",\n \"namespace\" : {\n \"owner\" : \"owner\",\n \"slug\" : \"slug\"\n },\n \"category\" : \"admin_tools\"\n }, {\n \"icon_url\" : \"icon_url\",\n \"plugin_id\" : \"plugin_id\",\n \"settings\" : {\n \"license\" : {\n \"name\" : \"name\",\n \"url\" : \"url\"\n },\n \"sources\" : \"sources\",\n \"forum_sync\" : true,\n \"issues\" : \"issues\",\n \"support\" : \"support\",\n \"homepage\" : \"homepage\"\n },\n \"last_updated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"visibility\" : \"public\",\n \"user_actions\" : {\n \"starred\" : true,\n \"watching\" : true\n },\n \"created_at\" : \"2000-01-23T04:56:07.000+00:00\",\n \"description\" : \"description\",\n \"promoted_versions\" : [ {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n }, {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n } ],\n \"stats\" : {\n \"downloads\" : 5,\n \"recent_downloads\" : 7,\n \"recent_views\" : 2,\n \"watchers\" : 3,\n \"stars\" : 9,\n \"views\" : 5\n },\n \"name\" : \"name\",\n \"namespace\" : {\n \"owner\" : \"owner\",\n \"slug\" : \"slug\"\n },\n \"category\" : \"admin_tools\"\n } ],\n \"pagination\" : {\n \"offset\" : 6,\n \"limit\" : 0,\n \"count\" : 1\n }\n}", PaginatedProjectResult.class), HttpStatus.OK); - } catch (IOException e) { - log.error("Couldn't serialize response for content type application/json", e); - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + public ResponseEntity listProjects(String q, List categories, List tags, String owner, ProjectSortingStrategy sort, boolean relevance, Long inLimit, Long inOffset) { + // handle input + long limit = limitOrDefault(inLimit, hangarConfig.getProjects().getInitLoad()); + long offset = offsetOrZero(inOffset); + + // parse tags + List parsedTags = new ArrayList<>(); + if (tags == null) { + tags = new ArrayList<>(); } + for (String tag : tags) { + String[] split = tag.split(":", 2); + parsedTags.add(new Tag().name(split[0]).data(split.length > 1 ? split[1] : null)); + } + + UsersTable currentUser = userService.getCurrentUser(); + // TODO this is really meh, we want to save global permissions somewhere + boolean seeHidden = permissionService.getGlobalPermissions(currentUser.getId()).has(Permission.SeeHidden); + + List projects = projectService.getProjects( + null, + categories, + parsedTags, + q, + owner, + seeHidden, + currentUser.getId(), + sort, + relevance, + limit, + offset + ); + + long count = projectService.countProjects( + null, + categories, + parsedTags, + q, + owner, + seeHidden, + currentUser.getId() + ); + + PaginatedProjectResult result = new PaginatedProjectResult(); + result.setPagination(new Pagination().limit(limit).offset(offset).count(count)); + result.setResult(projects); + + return new ResponseEntity<>(result, HttpStatus.OK); } @Override - public ResponseEntity showMembers(String pluginId, Long limit, Long offset) { + public ResponseEntity showMembers(String pluginId, Long inLimit, Long inOffset) { + long limit = limitOrDefault(inLimit, hangarConfig.getProjects().getInitLoad()); + long offset = offsetOrZero(inOffset); + try { return new ResponseEntity<>(objectMapper.readValue("{\n \"roles\" : [ {\n \"color\" : \"color\",\n \"name\" : \"name\",\n \"title\" : \"title\"\n }, {\n \"color\" : \"color\",\n \"name\" : \"name\",\n \"title\" : \"title\"\n } ],\n \"user\" : \"user\"\n}", ProjectMember.class), HttpStatus.OK); // TODO Implement me } catch (IOException e) { @@ -71,12 +126,6 @@ public class ProjectsApiController implements ProjectsApi { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<>(projectService.getProjectApi(pluginId), HttpStatus.OK); -// try { -// return new ResponseEntity<>(objectMapper.readValue("{\n \"icon_url\" : \"icon_url\",\n \"plugin_id\" : \"plugin_id\",\n \"settings\" : {\n \"license\" : {\n \"name\" : \"name\",\n \"url\" : \"url\"\n },\n \"sources\" : \"sources\",\n \"forum_sync\" : true,\n \"issues\" : \"issues\",\n \"support\" : \"support\",\n \"homepage\" : \"homepage\"\n },\n \"last_updated\" : \"2000-01-23T04:56:07.000+00:00\",\n \"visibility\" : \"public\",\n \"user_actions\" : {\n \"starred\" : true,\n \"watching\" : true\n },\n \"created_at\" : \"2000-01-23T04:56:07.000+00:00\",\n \"description\" : \"description\",\n \"promoted_versions\" : [ {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n }, {\n \"version\" : \"version\",\n \"tags\" : [ {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n }, {\n \"data\" : \"data\",\n \"color\" : {\n \"background\" : \"background\",\n \"foreground\" : \"foreground\"\n },\n \"name\" : \"name\",\n \"display_data\" : \"display_data\",\n \"minecraft_version\" : \"minecraft_version\"\n } ]\n } ],\n \"stats\" : {\n \"downloads\" : 5,\n \"recent_downloads\" : 7,\n \"recent_views\" : 2,\n \"watchers\" : 3,\n \"stars\" : 9,\n \"views\" : 5\n },\n \"name\" : \"name\",\n \"namespace\" : {\n \"owner\" : \"owner\",\n \"slug\" : \"slug\"\n },\n \"category\" : \"admin_tools\"\n}", Project.class), HttpStatus.OK); // TODO Implement me -// } catch (IOException e) { -// log.error("Couldn't serialize response for content type application/json", e); -// return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); -// } } diff --git a/src/main/java/me/minidigger/hangar/service/project/ProjectService.java b/src/main/java/me/minidigger/hangar/service/project/ProjectService.java index 3cc721b5e..6b1e2e9d9 100644 --- a/src/main/java/me/minidigger/hangar/service/project/ProjectService.java +++ b/src/main/java/me/minidigger/hangar/service/project/ProjectService.java @@ -10,10 +10,13 @@ import me.minidigger.hangar.db.model.ProjectVisibilityChangesTable; import me.minidigger.hangar.db.model.ProjectsTable; import me.minidigger.hangar.db.model.UserProjectRolesTable; import me.minidigger.hangar.db.model.UsersTable; +import me.minidigger.hangar.model.Category; import me.minidigger.hangar.model.Visibility; import me.minidigger.hangar.model.generated.Project; import me.minidigger.hangar.model.generated.ProjectNamespace; import me.minidigger.hangar.model.generated.ProjectSettings; +import me.minidigger.hangar.model.generated.ProjectSortingStrategy; +import me.minidigger.hangar.model.generated.Tag; import me.minidigger.hangar.model.generated.UserActions; import me.minidigger.hangar.model.viewhelpers.ProjectApprovalData; import me.minidigger.hangar.model.viewhelpers.ProjectData; @@ -189,4 +192,12 @@ public class ProjectService { public List getUnhealthyProjects() { return projectDao.get().getUnhealthyProjects(hangarConfig.projects.getStaleAge().toMillis()); } + + public List getProjects(String pluginId, List categories, List parsedTags, String query, String owner, boolean seeHidden, long requesterId, ProjectSortingStrategy sort, boolean relevance, long limit, long offset) { + return List.of(getProjectApi("test")); // TODO getProjects query + } + + public long countProjects(String pluginId, List categories, List parsedTags, String query, String owner, boolean seeHidden, long requesterId) { + return 1; // TODO count projects query + } } diff --git a/src/main/java/me/minidigger/hangar/util/ApiUtil.java b/src/main/java/me/minidigger/hangar/util/ApiUtil.java new file mode 100644 index 000000000..66f93ab7f --- /dev/null +++ b/src/main/java/me/minidigger/hangar/util/ApiUtil.java @@ -0,0 +1,12 @@ +package me.minidigger.hangar.util; + +public class ApiUtil { + + public static long limitOrDefault(Long limit, long defaultValue) { + return Math.min(limit == null ? defaultValue : limit, defaultValue); + } + + public static long offsetOrZero(Long offset) { + return Math.max(offset == null ? 0 : offset, 0); + } +}