Show projects you are a member of on profile

Closes #1380
This commit is contained in:
Nassim Jahnke 2024-07-30 19:52:35 +02:00
parent a7de374eb8
commit 9b94a0261b
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
6 changed files with 62 additions and 4 deletions

View File

@ -9,6 +9,7 @@ import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectAu
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectCategoryFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectLicenseFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectMCVersionFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectMemberFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectPlatformFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectQueryFilter;
import io.papermc.hangar.controller.extras.pagination.filters.projects.ProjectTagFilter;
@ -58,7 +59,7 @@ public class ProjectsController extends HangarComponent implements IProjectsCont
}
@Override
@ApplicableFilters({ProjectCategoryFilter.class, ProjectPlatformFilter.class, ProjectAuthorFilter.class, ProjectQueryFilter.class, ProjectLicenseFilter.class, ProjectMCVersionFilter.class, ProjectTagFilter.class})
@ApplicableFilters({ProjectCategoryFilter.class, ProjectPlatformFilter.class, ProjectAuthorFilter.class, ProjectQueryFilter.class, ProjectLicenseFilter.class, ProjectMCVersionFilter.class, ProjectTagFilter.class, ProjectMemberFilter.class})
@ApplicableSorters({SorterRegistry.VIEWS, SorterRegistry.DOWNLOADS, SorterRegistry.NEWEST, SorterRegistry.STARS, SorterRegistry.UPDATED, SorterRegistry.RECENT_DOWNLOADS, SorterRegistry.RECENT_VIEWS, SorterRegistry.SLUG})
public ResponseEntity<PaginatedResult<Project>> getProjects(final boolean prioritizeExactMatch, final @NotNull RequestPagination pagination) {
final boolean seeHidden = this.getGlobalPermissions().has(Permission.SeeHidden);

View File

@ -0,0 +1,55 @@
package io.papermc.hangar.controller.extras.pagination.filters.projects;
import io.papermc.hangar.controller.extras.pagination.Filter;
import java.util.Locale;
import java.util.Set;
import org.jdbi.v3.core.statement.SqlStatement;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;
@Component
public class ProjectMemberFilter implements Filter<ProjectMemberFilter.ProjectMemberFilterInstance, String> {
@Override
public Set<String> getQueryParamNames() {
return Set.of("member");
}
@Override
public String getDescription() {
return "The member of the project";
}
@Override
public String getValue(final NativeWebRequest webRequest) {
return webRequest.getParameter(this.getSingleQueryParam());
}
@Override
public @NotNull ProjectMemberFilterInstance create(final NativeWebRequest webRequest) {
return new ProjectMemberFilterInstance(this.getValue(webRequest));
}
static class ProjectMemberFilterInstance implements Filter.FilterInstance {
private final String memberName;
ProjectMemberFilterInstance(final String memberName) {
this.memberName = memberName;
}
@Override
public void createSql(final StringBuilder sb, final SqlStatement<?> q) {
sb.append(" AND :memberName = ANY(hp.project_member_names)");
q.bind("memberName", this.memberName.toLowerCase(Locale.ROOT));
}
@Override
public String toString() {
return "ProjectMemberFilterInstance{" +
"memberName='" + this.memberName + '\'' +
'}';
}
}
}

View File

@ -25,6 +25,7 @@ DROP MATERIALIZED VIEW IF EXISTS home_projects CASCADE;
CREATE MATERIALIZED VIEW home_projects AS
SELECT p.id,
array_agg(DISTINCT pm.user_id) AS project_members,
array_agg(DISTINCT lower(u.name)) AS project_member_names,
coalesce(pva.views::bigint, 0::bigint) AS views,
coalesce(pda.downloads::bigint, 0::bigint) AS downloads,
coalesce(pvr.recent_views::bigint, 0::bigint) AS recent_views,
@ -47,6 +48,7 @@ CREATE MATERIALIZED VIEW home_projects AS
FROM projects p
LEFT JOIN project_versions lv ON p.id = lv.project_id
JOIN project_members_all pm ON p.id = pm.id
JOIN users u ON pm.user_id = u.id
LEFT JOIN (SELECT p_1.id,
count(ps_1.user_id) AS stars
FROM projects p_1

View File

@ -189,7 +189,7 @@ export async function useUserData(
useApi<PaginatedResultProjectCompact>(`users/${user}/starred`),
useApi<PaginatedResultProjectCompact>(`users/${user}/watching`),
useApi<PaginatedResultProject>(`projects`, "get", {
owner: user,
member: user,
...projectsParams,
}),
useInternalApi<{ [key: string]: OrganizationRoleTable }>(`organizations/${user}/userOrganizations`),

View File

@ -85,7 +85,7 @@ watchDebounced(
// set the request params
await router.replace({ query: { page: page.value, ...paramsWithoutLimit } });
// do the update
projects.value = await useApi<PaginatedResultProject>("projects", "get", { owner: props.user?.name, ...requestParams.value });
projects.value = await useApi<PaginatedResultProject>("projects", "get", { member: props.user?.name, ...requestParams.value });
},
{ deep: true, debounce: 250 }
);

View File

@ -123,7 +123,7 @@ function updateSelectedNotifications() {
</div>
</template>
</Pagination>
<Button v-if="notifications?.result && selectedTab === 'unread' && notifications.result.length !== 0" size="small" class="mt-2" @click="markAllAsRead">
<Button v-if="notifications?.result?.length && selectedTab === 'unread'" size="small" class="mt-2" @click="markAllAsRead">
{{ i18n.t("notifications.readAll") }}
</Button>
</Card>