review notifications to members

This commit is contained in:
Jake Potrebic 2020-09-03 18:36:27 -07:00
parent 7123067a91
commit 63435b7dd4
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
7 changed files with 64 additions and 25 deletions

View File

@ -1,20 +1,25 @@
package io.papermc.hangar.controller;
import io.papermc.hangar.db.customtypes.JSONB;
import io.papermc.hangar.db.model.ProjectVersionReviewsTable;
import io.papermc.hangar.db.model.ProjectVersionsTable;
import io.papermc.hangar.model.generated.ReviewState;
import io.papermc.hangar.model.viewhelpers.VersionReview;
import io.papermc.hangar.model.viewhelpers.VersionReviewMessage;
import io.papermc.hangar.service.ReviewService;
import io.papermc.hangar.service.UserService;
import io.papermc.hangar.db.customtypes.LoggedActionType;
import io.papermc.hangar.db.customtypes.LoggedActionType.VersionContext;
import io.papermc.hangar.db.model.ProjectVersionReviewsTable;
import io.papermc.hangar.db.model.ProjectVersionsTable;
import io.papermc.hangar.db.model.UsersTable;
import io.papermc.hangar.model.NamedPermission;
import io.papermc.hangar.model.NotificationType;
import io.papermc.hangar.model.Permission;
import io.papermc.hangar.model.generated.ReviewState;
import io.papermc.hangar.model.viewhelpers.VersionData;
import io.papermc.hangar.model.viewhelpers.VersionReview;
import io.papermc.hangar.model.viewhelpers.VersionReviewMessage;
import io.papermc.hangar.security.annotations.GlobalPermission;
import io.papermc.hangar.service.NotificationService;
import io.papermc.hangar.service.ReviewService;
import io.papermc.hangar.service.UserActionLogService;
import io.papermc.hangar.service.UserService;
import io.papermc.hangar.service.VersionService;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.RouteHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@ -25,7 +30,6 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
@ -33,12 +37,15 @@ import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
@Controller
public class ReviewsController extends HangarController {
private final ProjectService projectService;
private final VersionService versionService;
private final ReviewService reviewService;
private final NotificationService notificationService;
private final UserActionLogService userActionLogService;
private final UserService userService;
private final RouteHelper routeHelper;
@ -46,9 +53,11 @@ public class ReviewsController extends HangarController {
private final HttpServletRequest request;
@Autowired
public ReviewsController(VersionService versionService, ReviewService reviewService, UserActionLogService userActionLogService, UserService userService, RouteHelper routeHelper, HttpServletRequest request) {
public ReviewsController(ProjectService projectService, VersionService versionService, ReviewService reviewService, NotificationService notificationService, UserActionLogService userActionLogService, UserService userService, RouteHelper routeHelper, HttpServletRequest request) {
this.projectService = projectService;
this.versionService = versionService;
this.reviewService = reviewService;
this.notificationService = notificationService;
this.userActionLogService = userActionLogService;
this.userService = userService;
this.routeHelper = routeHelper;
@ -98,8 +107,13 @@ public class ReviewsController extends HangarController {
}
review.setEndedAt(OffsetDateTime.now());
reviewService.update(review);
// TODO notifications
Map<UsersTable, Permission> users = projectService.getUsersPermissions(versionsTable.getProjectId());
// TODO bulk insert
users.forEach((user, perm) -> {
if (perm.has(Permission.EditVersion)) {
notificationService.sendNotification(user.getId(), null, NotificationType.VERSION_REVIEWED, new String[]{"notification.project.reviewed", slug, version});
}
});
return new ModelAndView("redirect:" + routeHelper.getRouteUrl("reviews.showReviews", author, slug, version));
}

View File

@ -38,7 +38,6 @@ import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@ -162,7 +161,7 @@ public class UsersController extends HangarController {
ModelAndView mav = new ModelAndView("users/notifications");
mav.addObject("notificationFilter", notificationFilter);
mav.addObject("inviteFilter", inviteFilter);
Map<NotificationsTable, UserData> notifications = notificationService.getNotifications(notificationFilter);
Map<NotificationsTable, UsersTable> notifications = notificationService.getNotifications(notificationFilter);
mav.addObject("notifications", notifications);
Map<UserRole<?>, InviteSubject<?>> invites = notificationService.getInvites(inviteFilter);
mav.addObject("invites", invites);

View File

@ -2,7 +2,6 @@ package io.papermc.hangar.db.dao;
import io.papermc.hangar.db.model.NotificationsTable;
import io.papermc.hangar.db.model.UsersTable;
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.customizer.Define;

View File

@ -172,4 +172,20 @@ public interface ProjectDao {
"FROM project_versions v JOIN projects p on v.project_id = p.id ")
@RegisterBeanMapper(value = ProjectMissingFile.class)
List<ProjectMissingFile> allProjectsForMissingFiles();
@RegisterBeanMapper(value = Permission.class, prefix = "perm")
@RegisterBeanMapper(UsersTable.class)
@SqlQuery("SELECT u.*, (coalesce(gt.permission, B'0'::BIT(64)) | coalesce(pt.permission, B'0'::BIT(64)) | coalesce(ot.permission, B'0'::BIT(64)))::BIGINT AS perm_value" +
" FROM users u " +
" LEFT JOIN global_trust gt ON u.id = gt.user_id" +
" LEFT JOIN projects p ON p.id = :projectId" +
" LEFT JOIN project_trust pt ON u.id = pt.user_id AND pt.project_id = p.id" +
" LEFT JOIN organization_trust ot ON u.id = ot.user_id AND ot.organization_id = p.owner_id" +
" WHERE " +
" (" +
" u.id IN (SELECT pm.user_id FROM project_members pm WHERE pm.project_id = p.id) OR " +
" u.id IN (SELECT om.user_id FROM organization_members om WHERE om.organization_id = ot.organization_id)" +
" ) AND " +
" u.id NOT IN (SELECT o.user_id FROM organizations o)")
Map<UsersTable, Permission> getAllUsersPermissions(long projectId);
}

View File

@ -15,10 +15,10 @@ public class NotificationsTable {
private NotificationType notificationType;
private String action;
private boolean read;
private long originId;
private Long originId;
private String[] messageArgs;
public NotificationsTable(long userId, NotificationType notificationType, String action, long originId, String[] messageArgs) {
public NotificationsTable(long userId, NotificationType notificationType, String action, Long originId, String[] messageArgs) {
this.userId = userId;
this.notificationType = notificationType;
this.action = action;
@ -84,11 +84,11 @@ public class NotificationsTable {
}
public long getOriginId() {
public Long getOriginId() {
return originId;
}
public void setOriginId(long originId) {
public void setOriginId(Long originId) {
this.originId = originId;
}

View File

@ -1,6 +1,5 @@
package io.papermc.hangar.service;
import io.papermc.hangar.model.InviteFilter;
import io.papermc.hangar.db.dao.HangarDao;
import io.papermc.hangar.db.dao.NotificationsDao;
import io.papermc.hangar.db.dao.UserOrganizationRolesDao;
@ -10,10 +9,11 @@ import io.papermc.hangar.db.model.OrganizationsTable;
import io.papermc.hangar.db.model.ProjectsTable;
import io.papermc.hangar.db.model.UserOrganizationRolesTable;
import io.papermc.hangar.db.model.UserProjectRolesTable;
import io.papermc.hangar.db.model.UsersTable;
import io.papermc.hangar.model.InviteFilter;
import io.papermc.hangar.model.NotificationFilter;
import io.papermc.hangar.model.NotificationType;
import io.papermc.hangar.model.viewhelpers.InviteSubject;
import io.papermc.hangar.model.viewhelpers.UserData;
import io.papermc.hangar.model.viewhelpers.UserRole;
import org.postgresql.shaded.com.ongres.scram.common.util.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
@ -22,7 +22,6 @@ import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
@Service
public class NotificationService {
@ -40,11 +39,11 @@ public class NotificationService {
this.userOrganizationRolesTable = userOrganizationRolesTable;
}
public NotificationsTable sendNotification(long userId, long originId, NotificationType type, String[] messageArgs) {
public NotificationsTable sendNotification(long userId, Long originId, NotificationType type, String[] messageArgs) {
return sendNotification(userId, originId, type, messageArgs, null);
}
public NotificationsTable sendNotification(long userId, long originId, NotificationType type, String[] messageArgs, String action) {
public NotificationsTable sendNotification(long userId, Long originId, NotificationType type, String[] messageArgs, String action) {
Preconditions.checkArgument(messageArgs.length != 0, "messageArgs must be non-empty");
NotificationsTable notification = new NotificationsTable(userId, type, action, originId, messageArgs);
notificationsDao.get().insert(notification);
@ -55,8 +54,15 @@ public class NotificationService {
return notificationsDao.get().markAsRead(notificationId, userService.getCurrentUser().getId());
}
public Map<NotificationsTable, UserData> getNotifications(NotificationFilter filter) {
return notificationsDao.get().getUserNotifications(userService.getCurrentUser().getId(), filter.getFilter()).entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> userService.getUserData(entry.getValue())));
public Map<NotificationsTable, UsersTable> getNotifications(NotificationFilter filter) {
return notificationsDao.get().getUserNotifications(userService.getCurrentUser().getId(), filter.getFilter())
.entrySet().stream().collect(HashMap::new, (m, v) -> {
if (v.getValue() == null || v.getValue().getName() == null) {
m.put(v.getKey(), null);
} else {
m.put(v.getKey(), v.getValue());
}
}, HashMap::putAll);
}
public Map<UserRole<?>, InviteSubject<?>> getInvites(InviteFilter inviteFilter) {

View File

@ -12,6 +12,7 @@ import io.papermc.hangar.db.model.ProjectVisibilityChangesTable;
import io.papermc.hangar.db.model.ProjectsTable;
import io.papermc.hangar.db.model.UserProjectRolesTable;
import io.papermc.hangar.db.model.UsersTable;
import io.papermc.hangar.model.Permission;
import io.papermc.hangar.model.Visibility;
import io.papermc.hangar.model.generated.Project;
import io.papermc.hangar.model.generated.ProjectLicense;
@ -228,4 +229,8 @@ public class ProjectService {
return !path.resolve(project.getFileName()).toFile().exists();
}).collect(Collectors.toList());
}
public Map<UsersTable, Permission> getUsersPermissions(long projectId) {
return projectDao.get().getAllUsersPermissions(projectId);
}
}