mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-12-21 06:51:19 +08:00
implemented project stargazing and watching and the userGrid view (#54)
Co-authored-by: MiniDigger <admin@minidigger.me>
This commit is contained in:
parent
c26110afa3
commit
1ed562d952
@ -27,10 +27,12 @@ import me.minidigger.hangar.util.AlertUtil.AlertType;
|
||||
import me.minidigger.hangar.util.HangarException;
|
||||
import me.minidigger.hangar.util.RouteHelper;
|
||||
import me.minidigger.hangar.util.StringUtils;
|
||||
import me.minidigger.hangar.util.TriFunction;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.core.parameters.P;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@ -40,9 +42,10 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import java.util.Collection;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Controller
|
||||
@ -323,15 +326,22 @@ public class ProjectsController extends HangarController {
|
||||
return null; // TODO implement addMessage request controller
|
||||
}
|
||||
|
||||
@RequestMapping("/{author}/{slug}/stars")
|
||||
public Object showStargazers(@PathVariable Object author, @PathVariable Object slug, @RequestParam Object page) {
|
||||
return null; // TODO implement showStargazers request controller
|
||||
@GetMapping("/{author}/{slug}/stars")
|
||||
public ModelAndView showStargazers(@PathVariable String author, @PathVariable String slug, @RequestParam(required = false, defaultValue = "1") Integer page) {
|
||||
return showUserGrid(author, slug, page, "Stargazers", projectService::getProjectStargazers);
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@RequestMapping("/{author}/{slug}/stars/toggle")
|
||||
public Object toggleStarred(@PathVariable Object author, @PathVariable Object slug) {
|
||||
return null; // TODO implement toggleStarred request controller
|
||||
@PostMapping("/{author}/{slug}/stars/toggle")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public void toggleStarred(@PathVariable String author, @PathVariable String slug) {
|
||||
ProjectData projectData = projectService.getProjectData(author, slug);
|
||||
ScopedProjectData scopedProjectData = projectService.getScopedProjectData(projectData.getProject().getId());
|
||||
if (scopedProjectData.isStarred()) {
|
||||
userDao.get().removeStargazing(projectData.getProject().getId(), userService.getCurrentUser().getId());
|
||||
} else {
|
||||
userDao.get().setStargazing(projectData.getProject().getId(), userService.getCurrentUser().getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@ -346,15 +356,40 @@ public class ProjectsController extends HangarController {
|
||||
// TODO user action logging
|
||||
}
|
||||
|
||||
@RequestMapping("/{author}/{slug}/watchers")
|
||||
public Object showWatchers(@PathVariable Object author, @PathVariable Object slug, @RequestParam Object page) {
|
||||
return null; // TODO implement showWatchers request controller
|
||||
@GetMapping("/{author}/{slug}/watchers")
|
||||
public ModelAndView showWatchers(@PathVariable String author, @PathVariable String slug, @RequestParam(required = false, defaultValue = "1") Integer page) {
|
||||
return showUserGrid(author, slug, page, "Watchers", projectService::getProjectWatchers);
|
||||
}
|
||||
|
||||
@Secured("ROLE_USER")
|
||||
@RequestMapping("/{author}/{slug}/watchers/{watching}")
|
||||
public Object setWatching(@PathVariable Object author, @PathVariable Object slug, @PathVariable Object watching) {
|
||||
return null; // TODO implement setWatching request controller
|
||||
@PostMapping("/{author}/{slug}/watchers/{watching}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public void setWatching(@PathVariable String author, @PathVariable String slug, @PathVariable boolean watching) {
|
||||
ProjectData projectData = projectService.getProjectData(author, slug);
|
||||
ScopedProjectData scopedProjectData = projectService.getScopedProjectData(projectData.getProject().getId());
|
||||
if (scopedProjectData.isWatching() == watching) return; // No change
|
||||
if (watching) {
|
||||
userDao.get().setWatching(projectData.getProject().getId(), userService.getCurrentUser().getId());
|
||||
} else {
|
||||
userDao.get().removeWatching(projectData.getProject().getId(), userService.getCurrentUser().getId());
|
||||
}
|
||||
}
|
||||
|
||||
private ModelAndView showUserGrid(String author, String slug, Integer page, String title, TriFunction<Long, Integer, Integer, Collection<UsersTable>> getUsers) {
|
||||
ProjectData projectData = projectService.getProjectData(author, slug);
|
||||
ScopedProjectData scopedProjectData = projectService.getScopedProjectData(projectData.getProject().getId());
|
||||
|
||||
int pageSize = hangarConfig.projects.getUserGridPageSize();
|
||||
int offset = (page - 1) * pageSize;
|
||||
|
||||
ModelAndView mav = new ModelAndView("projects/userGrid");
|
||||
mav.addObject("title", title);
|
||||
mav.addObject("p", projectData);
|
||||
mav.addObject("sp", scopedProjectData);
|
||||
mav.addObject("users", getUsers.apply(projectData.getProject().getId(), offset, pageSize));
|
||||
mav.addObject("page", page);
|
||||
mav.addObject("pageSize", pageSize);
|
||||
return fillModel(mav);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,4 +82,22 @@ public interface UserDao {
|
||||
@UseStringTemplateEngine
|
||||
@RegisterBeanMapper(Staff.class)
|
||||
List<Staff> getStaff(long offset, long pageSize, @Define String sort);
|
||||
|
||||
@SqlQuery("SELECT u.* FROM project_watchers pw JOIN users u ON pw.user_id = u.id WHERE project_id = :projectId OFFSET :offset LIMIT :limit")
|
||||
List<UsersTable> getProjectWatchers(long projectId, int offset, Integer limit);
|
||||
|
||||
@SqlUpdate("INSERT INTO project_watchers (project_id, user_id) VALUES (:projectId, :userId)")
|
||||
void setWatching(long projectId, long userId);
|
||||
|
||||
@SqlUpdate("DELETE FROM project_watchers WHERE project_id = :projectId AND user_id = :userId")
|
||||
void removeWatching(long projectId, long userId);
|
||||
|
||||
@SqlQuery("SELECT u.* FROM project_stars ps JOIN users u ON ps.user_id = u.id WHERE project_id = :projectId OFFSET :offset LIMIT :limit")
|
||||
List<UsersTable> getProjectStargazers(long projectId, int offset, Integer limit);
|
||||
|
||||
@SqlUpdate("INSERT INTO project_stars (project_id, user_id) VALUES (:projectId, :userId)")
|
||||
void setStargazing(long projectId, long userId);
|
||||
|
||||
@SqlUpdate("DELETE FROM project_stars WHERE project_id = :projectId AND user_id = :userId")
|
||||
void removeStargazing(long projectId, long userId);
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ public class ProjectService {
|
||||
String lastVisibilityChangeUser = null;
|
||||
ProjectVersionsTable recommendedVersion = null;
|
||||
String iconUrl = "";
|
||||
long starCount = 0;
|
||||
long watcherCount = 0;
|
||||
long starCount = userDao.get().getProjectStargazers(projectsTable.getId(), 0, null).size();
|
||||
long watcherCount = userDao.get().getProjectWatchers(projectsTable.getId(), 0, null).size();
|
||||
ProjectViewSettings settings = new ProjectViewSettings(
|
||||
projectsTable.getKeywords(),
|
||||
projectsTable.getHomepage(),
|
||||
@ -127,6 +127,14 @@ public class ProjectService {
|
||||
// TODO user action log
|
||||
}
|
||||
|
||||
public List<UsersTable> getProjectWatchers(long projectId, int offset, int limit) {
|
||||
return userDao.get().getProjectWatchers(projectId, offset, limit);
|
||||
}
|
||||
|
||||
public List<UsersTable> getProjectStargazers(long projectId, int offset, int limit) {
|
||||
return userDao.get().getProjectStargazers(projectId, offset, limit);
|
||||
}
|
||||
|
||||
public Project getProjectApi(String pluginId) { // TODO still probably have to work out a standard for how to handle the api models
|
||||
ProjectsTable projectsTable = projectDao.get().getByPluginId(pluginId);
|
||||
if (projectsTable == null) return null;
|
||||
|
7
src/main/java/me/minidigger/hangar/util/TriFunction.java
Normal file
7
src/main/java/me/minidigger/hangar/util/TriFunction.java
Normal file
@ -0,0 +1,7 @@
|
||||
package me.minidigger.hangar.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TriFunction<T, U, S, R> {
|
||||
|
||||
R apply(T t, U u, S s);
|
||||
}
|
@ -55,8 +55,8 @@ Documentation page within Project overview.
|
||||
<p><@spring.messageArgs code="project.category.info" args=[p.project.category.title] /></p>
|
||||
<p><@spring.messageArgs code="project.publishDate" args=[p.project.createdAt.format("yyyy-MM-dd")] /></p>
|
||||
<p><span id="view-count"></span> views</p>
|
||||
<p><span id="star-count"></span> <a href="${routes.getRouteUrl("projects.showStargazers", p.project.ownerName, p.project.slug, "")}">stars</a></p>
|
||||
<p><span id="watcher-count"></span> <a href="${routes.getRouteUrl("projects.showWatchers", p.project.ownerName, p.project.slug, "")}">watchers</a></p>
|
||||
<p><span id="star-count"></span> <a href="${routes.getRouteUrl("projects.showStargazers", p.project.ownerName, p.project.slug, "")}">star<#if p.starCount != 1>s</#if></a></p>
|
||||
<p><span id="watcher-count"></span> <a href="${routes.getRouteUrl("projects.showWatchers", p.project.ownerName, p.project.slug, "")}">watcher<#if p.watcherCount != 1>s</#if></a></p>
|
||||
<p><span id="download-count"></span> total downloads</p>
|
||||
<#if p.project.licenseName?has_content && p.project.licenseUrl?has_content>
|
||||
<p>
|
||||
|
@ -3,35 +3,51 @@
|
||||
<#import "*/utils/userAvatar.ftlh" as userAvatar />
|
||||
<#import "*/projects/view.ftlh" as projects />
|
||||
|
||||
@import controllers.sugar.Requests.OreRequest
|
||||
@import models.viewhelper.{ProjectData, ScopedProjectData}
|
||||
@import ore.OreConfig
|
||||
@import ore.markdown.MarkdownRenderer
|
||||
@import ore.models.user.User
|
||||
@import util.syntax._
|
||||
@(title: String, call: Int => Call, p: ProjectData, sp: ScopedProjectData, users: Seq[User], page: Int, pageSize: Int)(implicit messages: Messages, request: OreRequest[_], flash: Flash, config: OreConfig, renderer: MarkdownRenderer, assetsFinder: AssetsFinder)
|
||||
<#--@import controllers.sugar.Requests.OreRequest-->
|
||||
<#--@import models.viewhelper.{ProjectData, ScopedProjectData}-->
|
||||
<#--@import ore.OreConfig-->
|
||||
<#--@import ore.markdown.MarkdownRenderer-->
|
||||
<#--@import ore.models.user.User-->
|
||||
<#--@import util.syntax._-->
|
||||
<#--@(title: String, call: Int => Call, p: ProjectData, sp: ScopedProjectData, users: Seq[User], page: Int, pageSize: Int)(implicit messages: Messages, request: OreRequest[_], flash: Flash, config: OreConfig, renderer: MarkdownRenderer, assetsFinder: AssetsFinder)-->
|
||||
|
||||
<#assign columns = 3>
|
||||
|
||||
|
||||
<#-- @ftlvariable name="pageSize" type="java.lang.Integer" -->
|
||||
<#-- @ftlvariable name="page" type="java.lang.Integer" -->
|
||||
<@projects.view p=p sp=sp active="">
|
||||
<div class="row user-grid">
|
||||
<div class="col-xs-12">
|
||||
<h3 class="text-bold mb-0">@title</h3>
|
||||
<#-- @ftlvariable name="title" type="java.lang.String" -->
|
||||
<h3 class="text-bold mb-0">${title}</h3>
|
||||
<div class="extra-divider"></div>
|
||||
</div>
|
||||
|
||||
<#list 1..columns as i>
|
||||
<#list 1..columns as div>
|
||||
<div class="col-md-4">
|
||||
@users.iterator.zipWithIndex.filter(_._2 % columns == div).map(_._1).map { user =>
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<@userAvatar.userAvatar userName=user.name avatarUrl=user.avatarUrl clazz="user-avatar-sm media-object" />
|
||||
<#-- @ftlvariable name="users" type="java.util.Collection<me.minidigger.hangar.db.model.UsersTable>" -->
|
||||
<#-- @ftlvariable name="gridUser" type="me.minidigger.hangar.db.model.UsersTable" -->
|
||||
<#list users?filter(u -> (users?seq_index_of(u) + 1) % columns == div) as gridUser>
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<@userAvatar.userAvatar userName=gridUser.name avatarUrl=gridUser.avatarUrl clazz="user-avatar-sm media-object" />
|
||||
</div>
|
||||
<div class="media-body center-vertically">
|
||||
<a class="media-heading mb-0" href="${routes.getRouteUrl("users.showProjects", gridUser.name)}">${gridUser.name}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-body center-vertically">
|
||||
<a class="media-heading mb-0" href="${routes.getRouteUrl("users.showProjects", user.name)}">${user.name}</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</#list>
|
||||
<#-- @users.iterator.zipWithIndex.filter(_._2 % columns == div).map(_._1).map { user =>-->
|
||||
<#-- <div class="media">-->
|
||||
<#-- <div class="media-left">-->
|
||||
<#-- <@userAvatar.userAvatar userName=user.name avatarUrl=user.avatarUrl clazz="user-avatar-sm media-object" />-->
|
||||
<#-- </div>-->
|
||||
<#-- <div class="media-body center-vertically">-->
|
||||
<#-- <a class="media-heading mb-0" href="${routes.getRouteUrl("users.showProjects", user.name)}">${user.name}</a>-->
|
||||
<#-- </div>-->
|
||||
<#-- </div>-->
|
||||
<#-- }-->
|
||||
</div>
|
||||
</#list>
|
||||
|
||||
|
@ -86,7 +86,7 @@ Base template for Project overview.
|
||||
}
|
||||
-->
|
||||
|
||||
<#if p.getVisibility() != Visibility.SOFTDELETE>
|
||||
<#if p.visibility != Visibility.SOFTDELETE>
|
||||
<#if headerData.hasUser() && p.isOwner(headerData.getCurrentUser())>
|
||||
<button class="btn btn-default btn-star">
|
||||
<i id="icon-star" <#if sp.starred>
|
||||
|
Loading…
Reference in New Issue
Block a user