mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
Feature: Platform Filter (#562)
Co-authored-by: MiniDigger <admin@benndorf.dev>
This commit is contained in:
parent
c574dc19ad
commit
8a175b56aa
@ -48,8 +48,8 @@
|
||||
<v-row justify="center" align="center" style="position: relative; top: 5px; padding-bottom: 10px">
|
||||
<v-subheader>Platforms</v-subheader>
|
||||
</v-row>
|
||||
<v-list-item-group>
|
||||
<v-list-item v-for="(platform, i) in platforms" :key="i" active-class="">
|
||||
<v-list-item-group v-model="filters.platforms" multiple>
|
||||
<v-list-item v-for="platform in $store.getters.visiblePlatforms" :key="platform.enumName" :value="platform.name">
|
||||
<v-list-item-icon>
|
||||
<v-icon v-text="`$vuetify.icons.${platform.name.toLowerCase()}`" />
|
||||
</v-list-item-icon>
|
||||
@ -140,6 +140,7 @@ export default class Home extends HangarComponent {
|
||||
limit: this.options.itemsPerPage,
|
||||
offset: (this.options.page - 1) * this.options.itemsPerPage,
|
||||
category: this.filters.categories,
|
||||
platform: this.filters.platforms,
|
||||
};
|
||||
if (this.filters.search != null && this.filters.search.length > 0) {
|
||||
requestOptions.q = this.filters.search;
|
||||
|
@ -102,6 +102,7 @@ export const actions: ActionTree<RootState, RootState> = {
|
||||
|
||||
export const getters: GetterTree<RootState, RootState> = {
|
||||
visibleCategories: (state: RootState) => Array.from(state.projectCategories.values()).filter((value) => value.visible),
|
||||
visiblePlatforms: (state: RootState) => Array.from(state.platforms.values()).filter((value) => value.visible),
|
||||
};
|
||||
|
||||
function convertToMap<E, T>(values: T[], toStringFunc: (value: T) => string): Map<E, T> {
|
||||
|
1
frontend/types/internal/data.d.ts
vendored
1
frontend/types/internal/data.d.ts
vendored
@ -30,6 +30,7 @@ declare module 'hangar-internal' {
|
||||
url: string;
|
||||
tagColor: TagColor;
|
||||
possibleVersions: string[];
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
interface IVisibility {
|
||||
|
@ -3,10 +3,7 @@ package io.papermc.hangar.controller.api.v1;
|
||||
import io.papermc.hangar.HangarComponent;
|
||||
import io.papermc.hangar.controller.api.v1.interfaces.IProjectsController;
|
||||
import io.papermc.hangar.controller.extras.pagination.annotations.ApplicableFilters;
|
||||
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectAuthorFilter;
|
||||
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectCategoryFilter;
|
||||
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectQueryFilter;
|
||||
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectTagFilter;
|
||||
import io.papermc.hangar.controller.extras.pagination.filters.projects.*;
|
||||
import io.papermc.hangar.model.api.PaginatedResult;
|
||||
import io.papermc.hangar.model.api.User;
|
||||
import io.papermc.hangar.model.api.project.DayProjectStats;
|
||||
@ -53,7 +50,7 @@ public class ProjectsController extends HangarComponent implements IProjectsCont
|
||||
}
|
||||
|
||||
@Override
|
||||
@ApplicableFilters({ProjectCategoryFilter.class, ProjectAuthorFilter.class, ProjectQueryFilter.class, ProjectTagFilter.class})
|
||||
@ApplicableFilters({ProjectCategoryFilter.class, ProjectPlatformFilter.class, ProjectAuthorFilter.class, ProjectQueryFilter.class, ProjectTagFilter.class})
|
||||
public ResponseEntity<PaginatedResult<Project>> getProjects(String q, ProjectSortingStrategy sort, boolean orderWithRelevance, @NotNull RequestPagination pagination) {
|
||||
return ResponseEntity.ok(projectsApiService.getProjects(q, sort, orderWithRelevance, pagination));
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
package io.papermc.hangar.controller.extras.pagination.filters.projects;
|
||||
|
||||
import io.papermc.hangar.controller.extras.pagination.Filter;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import org.jdbi.v3.core.statement.SqlStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
public class ProjectPlatformFilter implements Filter<ProjectPlatformFilter.ProjectPlatformFilterInstance> {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
@Autowired
|
||||
public ProjectPlatformFilter(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getQueryParamNames() {
|
||||
return Set.of("platform");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "A platform to filter for";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ProjectPlatformFilterInstance create(NativeWebRequest webRequest) {
|
||||
return new ProjectPlatformFilterInstance(conversionService.convert(webRequest.getParameterValues(getSingleQueryParam()), Platform[].class));
|
||||
}
|
||||
|
||||
static class ProjectPlatformFilterInstance implements FilterInstance {
|
||||
|
||||
private final Platform[] platforms;
|
||||
|
||||
public ProjectPlatformFilterInstance(Platform[] platforms) {
|
||||
this.platforms = platforms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSql(StringBuilder sb, SqlStatement<?> q) {
|
||||
sb.append("AND v.platform").append(" IN (");
|
||||
for (int i = 0; i < platforms.length; i++) {
|
||||
sb.append(":__platform__").append(i);
|
||||
if (i + 1 != platforms.length) {
|
||||
sb.append(",");
|
||||
}
|
||||
q.bind("__platform__" + i, platforms[i]);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectCategoryFilterInstance{" +
|
||||
"platforms=" + Arrays.toString(platforms) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
@ -69,7 +69,7 @@ public interface ProjectsApiDAO {
|
||||
Project getProject(String author, String slug, @Define boolean canSeeHidden, @Define @Bind Long requesterId);
|
||||
|
||||
@UseStringTemplateEngine
|
||||
@SqlQuery("SELECT hp.id," +
|
||||
@SqlQuery("SELECT DISTINCT (hp.id)," +
|
||||
" hp.created_at," +
|
||||
" hp.name," +
|
||||
" hp.owner_name \"owner\"," +
|
||||
@ -83,6 +83,7 @@ public interface ProjectsApiDAO {
|
||||
" hp.watchers," +
|
||||
" hp.category," +
|
||||
" hp.description," +
|
||||
" hp.last_updated AS dum," + // need to add this so we can use it in order by, special constraint on distinct queries
|
||||
" COALESCE(hp.last_updated, hp.created_at) AS last_updated," +
|
||||
" hp.visibility, " +
|
||||
" exists(SELECT * FROM project_stars s WHERE s.project_id = p.id AND s.user_id = :requesterId) AS starred, " +
|
||||
@ -104,7 +105,10 @@ public interface ProjectsApiDAO {
|
||||
" p.donation_onetime_amounts," +
|
||||
" p.donation_monthly_amounts" +
|
||||
" FROM home_projects hp" +
|
||||
" JOIN projects p ON hp.id = p.id" +
|
||||
" JOIN projects p on hp.id = p.id" +
|
||||
" LEFT JOIN project_versions pv on p.id = pv.project_id " +
|
||||
" LEFT JOIN project_version_platform_dependencies pvpd on pv.id = pvpd.version_id " +
|
||||
" LEFT JOIN platform_versions v on pvpd.platform_version_id = v.id " +
|
||||
" WHERE true <filters>" + // Not sure how else to get here a single Where
|
||||
" <if(!seeHidden)> AND (hp.visibility = 0 <if(requesterId)>OR (:requesterId = ANY(hp.project_members) AND hp.visibility != 4)<endif>) <endif> " +
|
||||
" ORDER BY <orderBy> " +
|
||||
@ -119,6 +123,9 @@ public interface ProjectsApiDAO {
|
||||
@SqlQuery("SELECT count(DISTINCT hp.id) " +
|
||||
" FROM home_projects hp" +
|
||||
" JOIN projects p ON hp.id = p.id" +
|
||||
" LEFT JOIN project_versions pv on p.id = pv.project_id " +
|
||||
" LEFT JOIN project_version_platform_dependencies pvpd on pv.id = pvpd.version_id " +
|
||||
" LEFT JOIN platform_versions v on pvpd.platform_version_id = v.id " +
|
||||
" WHERE true <filters>" + // Not sure how else to get here a single Where
|
||||
" <if(!seeHidden)> AND (hp.visibility = 0 <if(requesterId)>OR (<requesterId> = ANY(hp.project_members) AND hp.visibility != 4)<endif>) <endif> ")
|
||||
long countProjects(@Define boolean seeHidden, @Define Long requesterId,
|
||||
|
@ -13,22 +13,24 @@ import java.util.stream.Collectors;
|
||||
public enum Platform {
|
||||
|
||||
// NOTE: The order here should always be the order they are displayed whenever there is a list somewhere on the frontend
|
||||
PAPER("Paper", Category.SERVER, TagColor.PAPER, "https://papermc.io/downloads"),
|
||||
WATERFALL("Waterfall", Category.PROXY, TagColor.WATERFALL, "https://papermc.io/downloads#Waterfall"),
|
||||
VELOCITY("Velocity", Category.PROXY, TagColor.VELOCITY, "https://www.velocitypowered.com/downloads");
|
||||
PAPER("Paper", Category.SERVER, TagColor.PAPER, "https://papermc.io/downloads", true),
|
||||
WATERFALL("Waterfall", Category.PROXY, TagColor.WATERFALL, "https://papermc.io/downloads#Waterfall", true),
|
||||
VELOCITY("Velocity", Category.PROXY, TagColor.VELOCITY, "https://www.velocitypowered.com/downloads", true);
|
||||
|
||||
private static final Platform[] VALUES = values();
|
||||
|
||||
private final String name;
|
||||
private final Category category;
|
||||
private final TagColor tagColor;
|
||||
private final boolean isVisible;
|
||||
private final String url;
|
||||
|
||||
Platform(String name, Category category, TagColor tagColor, String url) {
|
||||
Platform(String name, Category category, TagColor tagColor, String url, boolean isVisible) {
|
||||
this.name = name;
|
||||
this.category = category;
|
||||
this.tagColor = tagColor;
|
||||
this.url = url;
|
||||
this.isVisible = isVisible;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -42,6 +44,10 @@ public enum Platform {
|
||||
return category;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
public TagColor getTagColor() {
|
||||
return tagColor;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -75,7 +76,7 @@ public class ProjectsApiService extends HangarComponent {
|
||||
case RECENT_DOWNLOADS : orderingFirstHalf ="hp.recent_views *"; break;
|
||||
case RECENT_VIEWS: orderingFirstHalf ="hp.recent_downloads *"; break;
|
||||
default:
|
||||
orderingFirstHalf = " "; // Just in case and so that the ide doesnt complain
|
||||
orderingFirstHalf = " "; // Just in case and so that the ide doesn't complain
|
||||
}
|
||||
ordering = orderingFirstHalf + relevance;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user