From 870cd9b215940b986afab2be4633fdad7027156a Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Fri, 2 Apr 2021 16:06:59 -0700 Subject: [PATCH] better notification handling for joinables * work on #395 --- frontend/locales/en.ts | 14 +++- frontend/types/internal/users.d.ts | 1 - .../internal/HangarUserController.java | 2 +- .../controller/internal/LoginController.java | 81 ++++--------------- .../controllerold/OrganizationController.java | 2 +- .../hangar/db/customtypes/PGLoggedAction.java | 2 +- .../dao/internal/HangarNotificationsDAO.java | 2 +- .../dao/internal/table/NotificationsDAO.java | 4 +- .../db/modelold/NotificationsTable.java | 2 +- .../hangar/model/db/NotificationTable.java | 15 +--- .../notifications/HangarNotification.java | 11 +-- .../user/notifications/InviteFilter.java | 29 ------- .../user/notifications/Notification.java | 6 ++ .../NotificationType.java | 5 +- .../service/internal/auth/SSOService.java | 8 +- .../organizations/OrganizationFactory.java | 2 +- .../organizations/OrganizationService.java | 7 +- .../internal/perms/members/MemberService.java | 34 +++++--- .../members/OrganizationMemberService.java | 8 +- .../perms/members/ProjectMemberService.java | 8 +- .../internal/projects/ProjectService.java | 6 +- .../internal/users/NotificationService.java | 17 +--- .../internal/users/invites/InviteService.java | 25 +++--- .../invites/OrganizationInviteService.java | 14 ++-- .../users/invites/ProjectInviteService.java | 14 ++-- .../JoinableNotificationService.java | 74 +++++++++++++++++ .../visibility/VisibilityService.java | 2 +- .../serviceold/NotificationService.java | 2 +- .../V1.0.1__removeNotificationType.sql | 1 + 29 files changed, 200 insertions(+), 198 deletions(-) delete mode 100644 src/main/java/io/papermc/hangar/model/internal/user/notifications/InviteFilter.java create mode 100644 src/main/java/io/papermc/hangar/model/internal/user/notifications/Notification.java rename src/main/java/io/papermc/hangar/{model/internal/user/notifications => modelold}/NotificationType.java (69%) create mode 100644 src/main/java/io/papermc/hangar/service/internal/users/notifications/JoinableNotificationService.java create mode 100644 src/main/resources/db/migration/V1.0.1__removeNotificationType.sql diff --git a/frontend/locales/en.ts b/frontend/locales/en.ts index 175a15671..368d4431c 100644 --- a/frontend/locales/en.ts +++ b/frontend/locales/en.ts @@ -53,6 +53,12 @@ const msgs: LocaleMessageObject = { log: 'User Action Log', platformVersions: 'Platform Versions', logout: 'Sign out', + error: { + loginFailed: 'Authentication Failed', + hangarAuth: "Couldn't connect to HangarAuth", + loginDisabled: 'Login is temporarily unavailable, please try again later', + fakeUserEnabled: 'Fake user is enabled. {0} is therefore disabled', + }, }, createNew: 'Create new...', new: { @@ -453,11 +459,17 @@ const msgs: LocaleMessageObject = { project: { reviewed: '{0} {1} has been reviewed and is approved', reviewedPartial: '{0} {1} has been reviewed and is partially approved', - invite: 'You have been invited to join the group {0} on the project {1}', newVersion: 'A new version has been released for {0}: {1}', + invite: 'You have been invited to join the group {0} on the project {1}', + inviteRescinded: 'Your invite to you the group {0} in the project {1} has been rescinded', + removed: 'You have been removed from the group {0} in the project {1}', + roleChanged: 'You have been added to the {0} group in the project {1}', }, organization: { invite: 'You have been invited to join the group {0} in the organization {1}', + inviteRescinded: 'Your invite to you the group {0} in the organization {1} has been rescinded', + removed: 'You have been removed from the group {0} in the organization {1}', + roleChanged: 'You have been added to the {0} group in the organization {1}', }, }, visibility: { diff --git a/frontend/types/internal/users.d.ts b/frontend/types/internal/users.d.ts index df92566f0..fb1f62d62 100644 --- a/frontend/types/internal/users.d.ts +++ b/frontend/types/internal/users.d.ts @@ -5,7 +5,6 @@ declare module 'hangar-internal' { interface HangarNotification { id: number; - type: 'PROJECT_INVITE' | 'ORGANIZATION_INVITE' | 'NEW_PROJECT_VERSION' | 'VERSION_REVIEWED'; action: string; message: string[]; read: boolean; diff --git a/src/main/java/io/papermc/hangar/controller/internal/HangarUserController.java b/src/main/java/io/papermc/hangar/controller/internal/HangarUserController.java index adb3610d8..f6f19da42 100644 --- a/src/main/java/io/papermc/hangar/controller/internal/HangarUserController.java +++ b/src/main/java/io/papermc/hangar/controller/internal/HangarUserController.java @@ -152,7 +152,7 @@ public class HangarUserController extends HangarController { updateRole(organizationRoleService, organizationInviteService, id, status); } - private >, RS extends RoleService, IS extends InviteService> void updateRole(RS roleService, IS inviteService, long id, InviteStatus status) { + private >, RS extends RoleService, IS extends InviteService> void updateRole(RS roleService, IS inviteService, long id, InviteStatus status) { RT table = roleService.getRole(id); if (table == null) { throw new HangarApiException(HttpStatus.NOT_FOUND); diff --git a/src/main/java/io/papermc/hangar/controller/internal/LoginController.java b/src/main/java/io/papermc/hangar/controller/internal/LoginController.java index a44207c3c..aee83251c 100644 --- a/src/main/java/io/papermc/hangar/controller/internal/LoginController.java +++ b/src/main/java/io/papermc/hangar/controller/internal/LoginController.java @@ -1,7 +1,7 @@ package io.papermc.hangar.controller.internal; import io.papermc.hangar.controller.HangarController; -import io.papermc.hangar.exceptions.HangarException; +import io.papermc.hangar.exceptions.HangarApiException; import io.papermc.hangar.model.api.auth.RefreshResponse; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.internal.sso.AuthUser; @@ -12,7 +12,6 @@ import io.papermc.hangar.service.TokenService; import io.papermc.hangar.service.internal.auth.SSOService; import io.papermc.hangar.service.internal.perms.roles.GlobalRoleService; import io.papermc.hangar.service.internal.users.UserService; -import io.papermc.hangar.util.AlertUtil; import io.papermc.hangar.util.Routes; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -49,7 +48,7 @@ public class LoginController extends HangarController { } @GetMapping(path = "/login", params = "returnUrl") - public Object loginFromFrontend(@RequestParam(defaultValue = Routes.Paths.SHOW_HOME) String returnUrl, RedirectAttributes attributes) { + public Object loginFromFrontend(@RequestParam(defaultValue = Routes.Paths.SHOW_HOME) String returnUrl) { if (config.fakeUser.isEnabled()) { config.checkDev(); @@ -57,13 +56,8 @@ public class LoginController extends HangarController { tokenService.createTokenForUser(fakeUser); return new RedirectView(returnUrl); } else { - try { - response.addCookie(new Cookie("url", returnUrl)); - return redirectToSso(ssoService.getLoginUrl(config.getBaseUrl() + "/login"), attributes); - } catch (HangarException e) { - AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs()); - return Routes.SHOW_HOME.getRedirect(); - } + response.addCookie(new Cookie("url", returnUrl)); + return redirectToSso(ssoService.getLoginUrl(config.getBaseUrl() + "/login")); } } @@ -71,8 +65,7 @@ public class LoginController extends HangarController { public ModelAndView loginFromAuth(@RequestParam String sso, @RequestParam String sig, @CookieValue String url, RedirectAttributes attributes) { AuthUser authUser = ssoService.authenticate(sso, sig); if (authUser == null) { - AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.loginFailed"); - return Routes.SHOW_HOME.getRedirect(); + throw new HangarApiException("nav.user.error.loginFailed"); } UserTable user = userService.getOrCreate(authUser.getUserName(), authUser); @@ -93,66 +86,28 @@ public class LoginController extends HangarController { tokenService.invalidateToken(refreshToken); } -// @GetMapping("/login") -// public ModelAndView login(@RequestParam(defaultValue = "") String sso, @RequestParam(defaultValue = "") String sig, @RequestParam(defaultValue = "") String returnUrl, @CookieValue(value = "url", required = false) String redirectUrl, RedirectAttributes attributes) { -// if (hangarConfig.fakeUser.isEnabled()) { -// hangarConfig.checkDebug(); -// -// UserTable fakeUser = authenticationService.loginAsFakeUser(); -// -// return redirectBackOnSuccessfulLogin(returnUrl, fakeUser); -// } else if (sso.isEmpty()) { -// String returnPath = returnUrl.isBlank() ? request.getRequestURI() : returnUrl; -// try { -// response.addCookie(new Cookie("url", returnPath)); -// return redirectToSso(ssoService.getLoginUrl(hangarConfig.getBaseUrl() + "/login"), attributes); -// } catch (HangarException e) { -// AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs()); -// return Routes.SHOW_HOME.getRedirect(); -// } -// -// } else { -// AuthUser authUser = ssoService.authenticate(sso, sig); -// if (authUser == null) { -// AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.loginFailed"); -// return Routes.SHOW_HOME.getRedirect(); -// } -// -// UserTable user = userService.getOrCreate(authUser.getUserName(), authUser); -// roleService.removeAllGlobalRoles(user.getId()); -// authUser.getGlobalRoles().forEach(globalRole -> roleService.addRole(globalRole.create(null, user.getId(), true))); -// authenticationService.setAuthenticatedUser(user); -// -// String redirectPath = redirectUrl != null ? redirectUrl : Routes.getRouteUrlOf("showHome"); -// return redirectBackOnSuccessfulLogin(redirectPath, user); -// } -// } - + // TODO needed? @PostMapping("/verify") - public ModelAndView verify(@RequestParam String returnPath, RedirectAttributes attributes) { - try { - return redirectToSso(ssoService.getVerifyUrl(config.getBaseUrl() + returnPath), attributes); - } catch (HangarException e) { - AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs()); - return Routes.SHOW_HOME.getRedirect(); + public ModelAndView verify(@RequestParam String returnPath) { + if (config.fakeUser.isEnabled()) { + throw new HangarApiException("nav.user.error.fakeUserEnabled", "Verififcation"); } + return redirectToSso(ssoService.getVerifyUrl(config.getBaseUrl() + returnPath)); } + // TODO needed? @GetMapping("/logout") public ModelAndView logout(HttpSession session) { - // TODO flash session.invalidate(); return Routes.getRedirectToUrl(config.getAuthUrl() + "/accounts/logout/"); } @GetMapping("/signup") - public ModelAndView signUp(@RequestParam(defaultValue = "") String returnUrl, RedirectAttributes attributes) { - try { - return redirectToSso(ssoService.getSignupUrl(returnUrl), attributes); - } catch (HangarException e) { - AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, e.getMessageKey(), e.getArgs()); - return Routes.SHOW_HOME.getRedirect(); + public ModelAndView signUp(@RequestParam(defaultValue = "") String returnUrl) { + if (config.fakeUser.isEnabled()) { + throw new HangarApiException("nav.user.error.fakeUserEnabled", "Signup"); } + return redirectToSso(ssoService.getSignupUrl(returnUrl)); } private ModelAndView redirectBackOnSuccessfulLogin(String url, UserTable user) { @@ -163,14 +118,12 @@ public class LoginController extends HangarController { url = config.getBaseUrl() + "/" + url; } } -// response.addCookie(CookieUtils.builder(HangarAuthenticationFilter.AUTH_NAME, tokenService.expiring())); return Routes.getRedirectToUrl(url); } - private ModelAndView redirectToSso(URLWithNonce urlWithNonce, RedirectAttributes attributes) { + private ModelAndView redirectToSso(URLWithNonce urlWithNonce) { if (!config.sso.isEnabled()) { - AlertUtil.showAlert(attributes, AlertUtil.AlertType.ERROR, "error.noLogin"); - return Routes.SHOW_HOME.getRedirect(); + throw new HangarApiException("nav.user.error.loginDisabled"); } ssoService.insert(urlWithNonce.getNonce()); return Routes.getRedirectToUrl(urlWithNonce.getUrl()); diff --git a/src/main/java/io/papermc/hangar/controllerold/OrganizationController.java b/src/main/java/io/papermc/hangar/controllerold/OrganizationController.java index a67ea6895..05b9940e3 100644 --- a/src/main/java/io/papermc/hangar/controllerold/OrganizationController.java +++ b/src/main/java/io/papermc/hangar/controllerold/OrganizationController.java @@ -8,7 +8,7 @@ import io.papermc.hangar.db.customtypes.RoleCategory; import io.papermc.hangar.db.modelold.OrganizationsTable; import io.papermc.hangar.db.modelold.UsersTable; import io.papermc.hangar.model.common.NamedPermission; -import io.papermc.hangar.model.internal.user.notifications.NotificationType; +import io.papermc.hangar.modelold.NotificationType; import io.papermc.hangar.modelold.viewhelpers.UserData; import io.papermc.hangar.securityold.annotations.OrganizationPermission; import io.papermc.hangar.serviceold.AuthenticationService; diff --git a/src/main/java/io/papermc/hangar/db/customtypes/PGLoggedAction.java b/src/main/java/io/papermc/hangar/db/customtypes/PGLoggedAction.java index cf3d24f23..3639d9dbf 100644 --- a/src/main/java/io/papermc/hangar/db/customtypes/PGLoggedAction.java +++ b/src/main/java/io/papermc/hangar/db/customtypes/PGLoggedAction.java @@ -42,7 +42,7 @@ public class PGLoggedAction extends PGobject { public static final PGLoggedAction VERSION_PLUGIN_DEPENDENCY_EDITED = new PGLoggedAction("version_plugin_dependency_edited"); public static final PGLoggedAction VERSION_PLUGIN_DEPENDENCY_REMOVED = new PGLoggedAction("version_plugin_dependency_removed"); public static final PGLoggedAction VERSION_PLATFORM_DEPENDENCY_ADDED = new PGLoggedAction("version_platform_dependency_added"); - // public static final PGLoggedAction VERSION_PLATFORM_DEPENDENCY_CHANGED = new PGLoggedAction("version_platform_dependency_changed"); // TODO add to sql + // public static final PGLoggedAction VERSION_PLATFORM_DEPENDENCY_CHANGED = new PGLoggedAction("version_platform_dependency_changed"); // TODO add to sql (is this needed? you only ever add or remove them, not change them) public static final PGLoggedAction VERSION_PLATFORM_DEPENDENCY_REMOVED = new PGLoggedAction("version_platform_dependency_removed"); // Users diff --git a/src/main/java/io/papermc/hangar/db/dao/internal/HangarNotificationsDAO.java b/src/main/java/io/papermc/hangar/db/dao/internal/HangarNotificationsDAO.java index 0e62caa26..8c5e06296 100644 --- a/src/main/java/io/papermc/hangar/db/dao/internal/HangarNotificationsDAO.java +++ b/src/main/java/io/papermc/hangar/db/dao/internal/HangarNotificationsDAO.java @@ -12,7 +12,7 @@ import java.util.List; public interface HangarNotificationsDAO { @RegisterConstructorMapper(HangarNotification.class) - @SqlQuery("SELECT n.id, n.notification_type AS type, n.action, n.message_args message, n.read, u.name as origin_user_name" + + @SqlQuery("SELECT n.id, n.action, n.message_args message, n.read, u.name as origin_user_name" + " FROM notifications n" + " LEFT OUTER JOIN users u ON u.id = n.origin_id" + " WHERE n.user_id = :userId" + diff --git a/src/main/java/io/papermc/hangar/db/dao/internal/table/NotificationsDAO.java b/src/main/java/io/papermc/hangar/db/dao/internal/table/NotificationsDAO.java index d111c1662..bd933e4c8 100644 --- a/src/main/java/io/papermc/hangar/db/dao/internal/table/NotificationsDAO.java +++ b/src/main/java/io/papermc/hangar/db/dao/internal/table/NotificationsDAO.java @@ -18,11 +18,11 @@ public interface NotificationsDAO { @Timestamped @GetGeneratedKeys - @SqlUpdate("INSERT INTO notifications (created_at, user_id, notification_type, action, origin_id, message_args) VALUES (:now, :userId, :notificationType, :action, :originId, :messageArgs)") + @SqlUpdate("INSERT INTO notifications (created_at, user_id, action, origin_id, message_args) VALUES (:now, :userId, :action, :originId, :messageArgs)") NotificationTable insert(@BindBean NotificationTable notificationTable); @Timestamped - @SqlBatch("INSERT INTO notifications (created_at, user_id, notification_type, action, origin_id, message_args) VALUES (:now, :userId, :notificationType, :action, :originId, :messageArgs)") + @SqlBatch("INSERT INTO notifications (created_at, user_id, action, origin_id, message_args) VALUES (:now, :userId, :action, :originId, :messageArgs)") void insert(@BindBean Collection notificationTables); @SqlUpdate("UPDATE notifications SET read = TRUE WHERE id = :notificationId AND user_id = :userId") diff --git a/src/main/java/io/papermc/hangar/db/modelold/NotificationsTable.java b/src/main/java/io/papermc/hangar/db/modelold/NotificationsTable.java index f1369b57f..a218c6713 100644 --- a/src/main/java/io/papermc/hangar/db/modelold/NotificationsTable.java +++ b/src/main/java/io/papermc/hangar/db/modelold/NotificationsTable.java @@ -1,7 +1,7 @@ package io.papermc.hangar.db.modelold; -import io.papermc.hangar.model.internal.user.notifications.NotificationType; +import io.papermc.hangar.modelold.NotificationType; import org.jdbi.v3.core.enums.EnumByOrdinal; import java.time.OffsetDateTime; diff --git a/src/main/java/io/papermc/hangar/model/db/NotificationTable.java b/src/main/java/io/papermc/hangar/model/db/NotificationTable.java index 3e81770a3..525e1e880 100644 --- a/src/main/java/io/papermc/hangar/model/db/NotificationTable.java +++ b/src/main/java/io/papermc/hangar/model/db/NotificationTable.java @@ -1,7 +1,5 @@ package io.papermc.hangar.model.db; -import io.papermc.hangar.model.internal.user.notifications.NotificationType; -import org.jdbi.v3.core.enums.EnumByOrdinal; import org.jdbi.v3.core.mapper.reflect.JdbiConstructor; import java.time.OffsetDateTime; @@ -9,27 +7,23 @@ import java.time.OffsetDateTime; public class NotificationTable extends Table { private final long userId; - @EnumByOrdinal - private final NotificationType notificationType; private final String action; private final boolean read; private final Long originId; private final String[] messageArgs; @JdbiConstructor - public NotificationTable(OffsetDateTime createdAt, long id, long userId, @EnumByOrdinal NotificationType notificationType, String action, boolean read, Long originId, String[] messageArgs) { + public NotificationTable(OffsetDateTime createdAt, long id, long userId, String action, boolean read, Long originId, String[] messageArgs) { super(createdAt, id); this.userId = userId; - this.notificationType = notificationType; this.action = action; this.read = read; this.originId = originId; this.messageArgs = messageArgs; } - public NotificationTable(long userId, NotificationType notificationType, String action, Long originId, String[] messageArgs) { + public NotificationTable(long userId, String action, Long originId, String[] messageArgs) { this.userId = userId; - this.notificationType = notificationType; this.action = action; this.read = false; this.originId = originId; @@ -40,11 +34,6 @@ public class NotificationTable extends Table { return userId; } - @EnumByOrdinal - public NotificationType getNotificationType() { - return notificationType; - } - public String getAction() { return action; } diff --git a/src/main/java/io/papermc/hangar/model/internal/user/notifications/HangarNotification.java b/src/main/java/io/papermc/hangar/model/internal/user/notifications/HangarNotification.java index 71e68b9ef..9a978a053 100644 --- a/src/main/java/io/papermc/hangar/model/internal/user/notifications/HangarNotification.java +++ b/src/main/java/io/papermc/hangar/model/internal/user/notifications/HangarNotification.java @@ -1,21 +1,17 @@ package io.papermc.hangar.model.internal.user.notifications; -import org.jdbi.v3.core.enums.EnumByOrdinal; - import java.util.List; public class HangarNotification { private final long id; - private final NotificationType type; private final String action; private final List message; private final boolean read; private final String originUserName; - public HangarNotification(long id, @EnumByOrdinal NotificationType type, String action, List message, boolean read, String originUserName) { + public HangarNotification(long id, String action, List message, boolean read, String originUserName) { this.id = id; - this.type = type; this.action = action; this.message = message; this.read = read; @@ -26,10 +22,6 @@ public class HangarNotification { return id; } - public NotificationType getType() { - return type; - } - public String getAction() { return action; } @@ -50,7 +42,6 @@ public class HangarNotification { public String toString() { return "Notification{" + "id=" + id + - ", type=" + type + ", action='" + action + '\'' + ", message=" + message + ", read=" + read + diff --git a/src/main/java/io/papermc/hangar/model/internal/user/notifications/InviteFilter.java b/src/main/java/io/papermc/hangar/model/internal/user/notifications/InviteFilter.java deleted file mode 100644 index 2837ffe30..000000000 --- a/src/main/java/io/papermc/hangar/model/internal/user/notifications/InviteFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.papermc.hangar.model.internal.user.notifications; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonFormat.Shape; - -@JsonFormat(shape = Shape.OBJECT) -public enum InviteFilter { - ALL("all", "notification.invite.all"), - PROJECTS("projects", "notification.invite.projects"), - ORGANIZATIONS("organizations", "notification.invite.organizations"); - - private final String name; - private final String title; - - public static final InviteFilter[] VALUES = values(); - - InviteFilter(String name, String title) { - this.name = name; - this.title = title; - } - - public String getName() { - return name; - } - - public String getTitle() { - return title; - } -} diff --git a/src/main/java/io/papermc/hangar/model/internal/user/notifications/Notification.java b/src/main/java/io/papermc/hangar/model/internal/user/notifications/Notification.java new file mode 100644 index 000000000..0b7ba1534 --- /dev/null +++ b/src/main/java/io/papermc/hangar/model/internal/user/notifications/Notification.java @@ -0,0 +1,6 @@ +package io.papermc.hangar.model.internal.user.notifications; + +public interface Notification { + + String messageKey(); +} diff --git a/src/main/java/io/papermc/hangar/model/internal/user/notifications/NotificationType.java b/src/main/java/io/papermc/hangar/modelold/NotificationType.java similarity index 69% rename from src/main/java/io/papermc/hangar/model/internal/user/notifications/NotificationType.java rename to src/main/java/io/papermc/hangar/modelold/NotificationType.java index 86f98c623..584d2daaf 100644 --- a/src/main/java/io/papermc/hangar/model/internal/user/notifications/NotificationType.java +++ b/src/main/java/io/papermc/hangar/modelold/NotificationType.java @@ -1,5 +1,6 @@ -package io.papermc.hangar.model.internal.user.notifications; +package io.papermc.hangar.modelold; +@Deprecated(forRemoval = true) public enum NotificationType { PROJECT_INVITE, @@ -7,4 +8,6 @@ public enum NotificationType { NEW_PROJECT_VERSION, VERSION_REVIEWED, VERSION_REVIEWED_PARTIAL, + + } diff --git a/src/main/java/io/papermc/hangar/service/internal/auth/SSOService.java b/src/main/java/io/papermc/hangar/service/internal/auth/SSOService.java index 38448eb7d..ea1f3b15e 100644 --- a/src/main/java/io/papermc/hangar/service/internal/auth/SSOService.java +++ b/src/main/java/io/papermc/hangar/service/internal/auth/SSOService.java @@ -5,7 +5,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import io.papermc.hangar.config.hangar.HangarConfig; import io.papermc.hangar.db.dao.HangarDao; import io.papermc.hangar.db.dao.internal.table.auth.UserSignOnDAO; -import io.papermc.hangar.exceptions.HangarException; +import io.papermc.hangar.exceptions.HangarApiException; import io.papermc.hangar.model.db.auth.UserSignOnTable; import io.papermc.hangar.model.internal.sso.AuthUser; import io.papermc.hangar.model.internal.sso.URLWithNonce; @@ -114,7 +114,7 @@ public class SSOService { return CryptoUtils.hmacSha256(hangarConfig.sso.getSecret(), payload.getBytes(StandardCharsets.UTF_8)); } catch (NoSuchAlgorithmException | InvalidKeyException e) { LOGGER.warn("Error while singing sso key", e); - throw new HangarException("error.loginFailed"); + throw new HangarApiException("nav.user.error.loginFailed"); } } @@ -137,9 +137,9 @@ public class SSOService { return returnUrls.getIfPresent(nonce); } - public static class SignatureException extends HangarException { + public static class SignatureException extends HangarApiException { SignatureException(String payload, String signature) { - super("error.spongeauth.auth", payload, signature); + super("nav.user.error.hangarAuth", payload, signature); } } } diff --git a/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationFactory.java b/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationFactory.java index 867b9e809..044500407 100644 --- a/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationFactory.java +++ b/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationFactory.java @@ -115,7 +115,7 @@ public class OrganizationFactory extends HangarService { organizationMemberService.addNewAcceptedByDefaultMember(OrganizationRole.ORGANIZATION_OWNER.create(organizationTable.getId(), getHangarPrincipal().getId(), true)); List errors = new ArrayList<>(); - organizationInviteService.sendInvites(errors, members, organizationTable.getId(), organizationTable.getName()); + organizationInviteService.sendInvites(errors, members, organizationTable); if (!errors.isEmpty()) { throw new MultiHangarApiException(errors); diff --git a/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationService.java b/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationService.java index a051e5eb3..336b5b3ba 100644 --- a/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationService.java +++ b/src/main/java/io/papermc/hangar/service/internal/organizations/OrganizationService.java @@ -18,7 +18,6 @@ import io.papermc.hangar.service.HangarService; import io.papermc.hangar.service.PermissionService; import io.papermc.hangar.service.internal.perms.members.OrganizationMemberService; import io.papermc.hangar.service.internal.users.invites.OrganizationInviteService; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -79,9 +78,9 @@ public class OrganizationService extends HangarService { OrganizationTable organizationTable = getOrganizationTable(name); List errors = new ArrayList<>(); - organizationInviteService.sendInvites(errors, editMembersForm.getNewInvitees(), organizationTable.getId(), organizationTable.getName()); - organizationMemberService.editMembers(errors, editMembersForm.getEditedMembers(), organizationTable.getId()); - organizationMemberService.removeMembers(errors, editMembersForm.getDeletedMembers(), organizationTable.getId()); + organizationInviteService.sendInvites(errors, editMembersForm.getNewInvitees(), organizationTable); + organizationMemberService.editMembers(errors, editMembersForm.getEditedMembers(), organizationTable); + organizationMemberService.removeMembers(errors, editMembersForm.getDeletedMembers(), organizationTable); if (!errors.isEmpty()) { throw new MultiHangarApiException(errors); diff --git a/src/main/java/io/papermc/hangar/service/internal/perms/members/MemberService.java b/src/main/java/io/papermc/hangar/service/internal/perms/members/MemberService.java index 1df39843c..5449da797 100644 --- a/src/main/java/io/papermc/hangar/service/internal/perms/members/MemberService.java +++ b/src/main/java/io/papermc/hangar/service/internal/perms/members/MemberService.java @@ -5,15 +5,19 @@ import io.papermc.hangar.db.dao.internal.table.UserDAO; import io.papermc.hangar.db.dao.internal.table.members.MembersDAO; import io.papermc.hangar.db.dao.internal.table.roles.IRolesDAO; import io.papermc.hangar.exceptions.HangarApiException; +import io.papermc.hangar.model.Named; import io.papermc.hangar.model.common.roles.Role; +import io.papermc.hangar.model.db.Table; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.members.MemberTable; import io.papermc.hangar.model.db.roles.ExtendedRoleTable; import io.papermc.hangar.model.internal.api.requests.EditMembersForm.Member; import io.papermc.hangar.service.HangarService; import io.papermc.hangar.service.internal.perms.roles.RoleService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService; import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; @@ -23,6 +27,8 @@ public abstract class MemberService< RT extends ExtendedRoleTable, RD extends IRolesDAO, S extends RoleService, + J extends Table & Named, + JNS extends JoinableNotificationService, MD extends MembersDAO, MT extends MemberTable > extends HangarService { @@ -30,14 +36,16 @@ public abstract class MemberService< @Autowired private HangarDao userDAO; - protected final S roleService; - protected final MD membersDao; - protected final MemberTableConstructor constructor; + private final S roleService; + private final MD membersDao; + private final JNS joinableNotificationService; + private final MemberTableConstructor constructor; private final String errorPrefix; - protected MemberService(S roleService, MD membersDao, MemberTableConstructor constructor, String errorPrefix) { + protected MemberService(S roleService, MD membersDao, JNS joinableNotificationService, MemberTableConstructor constructor, String errorPrefix) { this.roleService = roleService; this.membersDao = membersDao; + this.joinableNotificationService = joinableNotificationService; this.constructor = constructor; this.errorPrefix = errorPrefix; } @@ -74,10 +82,11 @@ public abstract class MemberService< logMemberRemoval(roleTable.getPrincipalId(), sb); } - public void removeMembers(List errors, List> members, long principalId) { + @Transactional + public void removeMembers(List errors, List> members, J joinable) { List toBeRemoved = new ArrayList<>(); StringBuilder sb = new StringBuilder("Removed: "); - handleEditOrRemoval(errors, toBeRemoved, members, principalId, (member, rt, notLast) -> { + handleEditOrRemoval(errors, toBeRemoved, members, joinable.getId(), (member, rt, notLast) -> { sb.append(member.getName()).append(" (").append(member.getRole().getTitle()).append(")"); if (notLast) { sb.append(", "); @@ -88,19 +97,20 @@ public abstract class MemberService< membersDao.delete(rt.getPrincipalId(), rt.getUserId()); roleService.deleteRole(rt); } - // TODO notifications for removal if (!toBeRemoved.isEmpty()) { - logMemberRemoval(principalId, sb.toString()); + joinableNotificationService.removedFrom(toBeRemoved, joinable); + logMemberRemoval(joinable.getId(), sb.toString()); } } abstract void logMemberRemoval(long principalId, String logEntry); - public void editMembers(List errors, List> members, long principalId) { + @Transactional + public void editMembers(List errors, List> members, J joinable) { List toBeUpdated = new ArrayList<>(); StringBuilder oldState = new StringBuilder("Old Roles: "); StringBuilder newState = new StringBuilder("New Roles: "); - handleEditOrRemoval(errors, toBeUpdated, members, principalId, (member, rt, notLast) -> { + handleEditOrRemoval(errors, toBeUpdated, members, joinable.getId(), (member, rt, notLast) -> { if (member.getRole() == rt.getRole()) { return false; } @@ -118,9 +128,9 @@ public abstract class MemberService< for (RT rt : toBeUpdated) { roleService.updateRoles(toBeUpdated); } - // TODO notifications for new role if (!toBeUpdated.isEmpty()) { - logMemberUpdate(principalId, oldState.toString(), newState.toString()); + joinableNotificationService.roleChanged(toBeUpdated, joinable); + logMemberUpdate(joinable.getId(), oldState.toString(), newState.toString()); } } diff --git a/src/main/java/io/papermc/hangar/service/internal/perms/members/OrganizationMemberService.java b/src/main/java/io/papermc/hangar/service/internal/perms/members/OrganizationMemberService.java index 129a1496b..32a25ab7b 100644 --- a/src/main/java/io/papermc/hangar/service/internal/perms/members/OrganizationMemberService.java +++ b/src/main/java/io/papermc/hangar/service/internal/perms/members/OrganizationMemberService.java @@ -4,12 +4,14 @@ import io.papermc.hangar.db.dao.HangarDao; import io.papermc.hangar.db.dao.internal.table.members.OrganizationMembersDAO; import io.papermc.hangar.db.dao.internal.table.roles.OrganizationRolesDAO; import io.papermc.hangar.model.common.roles.OrganizationRole; +import io.papermc.hangar.model.db.OrganizationTable; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.members.OrganizationMemberTable; import io.papermc.hangar.model.db.roles.OrganizationRoleTable; import io.papermc.hangar.model.internal.logs.LogAction; import io.papermc.hangar.model.internal.logs.contexts.OrganizationContext; import io.papermc.hangar.service.internal.perms.roles.OrganizationRoleService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService.OrganizationNotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -21,13 +23,15 @@ public class OrganizationMemberService extends MemberService< OrganizationRoleTable, OrganizationRolesDAO, OrganizationRoleService, + OrganizationTable, + OrganizationNotificationService, OrganizationMembersDAO, OrganizationMemberTable > { @Autowired - public OrganizationMemberService(OrganizationRoleService roleService, HangarDao organizationMembersDAO) { - super(roleService, organizationMembersDAO.get(), OrganizationMemberTable::new, "organization.settings.members."); + public OrganizationMemberService(OrganizationRoleService roleService, HangarDao organizationMembersDAO, OrganizationNotificationService organizationNotificationService) { + super(roleService, organizationMembersDAO.get(), organizationNotificationService, OrganizationMemberTable::new, "organization.settings.members."); } @Override diff --git a/src/main/java/io/papermc/hangar/service/internal/perms/members/ProjectMemberService.java b/src/main/java/io/papermc/hangar/service/internal/perms/members/ProjectMemberService.java index bded56cf9..918e808fd 100644 --- a/src/main/java/io/papermc/hangar/service/internal/perms/members/ProjectMemberService.java +++ b/src/main/java/io/papermc/hangar/service/internal/perms/members/ProjectMemberService.java @@ -6,10 +6,12 @@ import io.papermc.hangar.db.dao.internal.table.roles.ProjectRolesDAO; import io.papermc.hangar.model.common.roles.ProjectRole; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.members.ProjectMemberTable; +import io.papermc.hangar.model.db.projects.ProjectTable; import io.papermc.hangar.model.db.roles.ProjectRoleTable; import io.papermc.hangar.model.internal.logs.LogAction; import io.papermc.hangar.model.internal.logs.contexts.ProjectContext; import io.papermc.hangar.service.internal.perms.roles.ProjectRoleService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService.ProjectNotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -21,13 +23,15 @@ public class ProjectMemberService extends MemberService< ProjectRoleTable, ProjectRolesDAO, ProjectRoleService, + ProjectTable, + ProjectNotificationService, ProjectMembersDAO, ProjectMemberTable > { @Autowired - public ProjectMemberService(ProjectRoleService projectRoleService, HangarDao projectMembersDAO) { - super(projectRoleService, projectMembersDAO.get(), ProjectMemberTable::new, "project.settings.error.members."); + public ProjectMemberService(ProjectRoleService projectRoleService, HangarDao projectMembersDAO, ProjectNotificationService projectNotificationService) { + super(projectRoleService, projectMembersDAO.get(), projectNotificationService, ProjectMemberTable::new, "project.settings.error.members."); } @Override diff --git a/src/main/java/io/papermc/hangar/service/internal/projects/ProjectService.java b/src/main/java/io/papermc/hangar/service/internal/projects/ProjectService.java index 7e64a5325..e78fd922f 100644 --- a/src/main/java/io/papermc/hangar/service/internal/projects/ProjectService.java +++ b/src/main/java/io/papermc/hangar/service/internal/projects/ProjectService.java @@ -197,9 +197,9 @@ public class ProjectService extends HangarService { ProjectTable projectTable = getProjectTable(author, slug); List errors = new ArrayList<>(); - projectInviteService.sendInvites(errors, editMembersForm.getNewInvitees(), projectTable.getId(), projectTable.getName()); - projectMemberService.editMembers(errors, editMembersForm.getEditedMembers(), projectTable.getId()); - projectMemberService.removeMembers(errors, editMembersForm.getDeletedMembers(), projectTable.getId()); + projectInviteService.sendInvites(errors, editMembersForm.getNewInvitees(), projectTable); + projectMemberService.editMembers(errors, editMembersForm.getEditedMembers(), projectTable); + projectMemberService.removeMembers(errors, editMembersForm.getDeletedMembers(), projectTable); if (!errors.isEmpty()) { throw new MultiHangarApiException(errors); diff --git a/src/main/java/io/papermc/hangar/service/internal/users/NotificationService.java b/src/main/java/io/papermc/hangar/service/internal/users/NotificationService.java index 2b35e90d5..3932ac203 100644 --- a/src/main/java/io/papermc/hangar/service/internal/users/NotificationService.java +++ b/src/main/java/io/papermc/hangar/service/internal/users/NotificationService.java @@ -5,15 +5,11 @@ import io.papermc.hangar.db.dao.internal.HangarNotificationsDAO; import io.papermc.hangar.db.dao.internal.table.NotificationsDAO; import io.papermc.hangar.db.dao.internal.table.projects.ProjectsDAO; import io.papermc.hangar.model.common.Permission; -import io.papermc.hangar.model.common.roles.OrganizationRole; -import io.papermc.hangar.model.common.roles.ProjectRole; import io.papermc.hangar.model.db.NotificationTable; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.projects.ProjectTable; import io.papermc.hangar.model.db.versions.ProjectVersionTable; -import io.papermc.hangar.model.internal.api.requests.EditMembersForm.Member; import io.papermc.hangar.model.internal.user.notifications.HangarNotification; -import io.papermc.hangar.model.internal.user.notifications.NotificationType; import io.papermc.hangar.service.HangarService; import io.papermc.hangar.service.PermissionService; import org.springframework.stereotype.Service; @@ -49,7 +45,6 @@ public class NotificationService extends HangarService { for (UserTable projectWatcher : projectWatchers) { notificationTables.add(new NotificationTable( projectWatcher.getId(), - NotificationType.NEW_PROJECT_VERSION, projectTable.getOwnerName() + "/" + projectTable.getSlug(), projectTable.getId(), new String[]{"notifications.project.newVersion", projectTable.getName(), projectVersionTable.getVersionString()}) @@ -64,22 +59,14 @@ public class NotificationService extends HangarService { permissionService.getProjectMemberPermissions(projectVersionTable.getProjectId()).forEach((user, perm) -> { if (perm.has(Permission.EditVersion)) { if (partial) { - notificationTables.add(new NotificationTable(user.getId(), NotificationType.VERSION_REVIEWED_PARTIAL, null, null, + notificationTables.add(new NotificationTable(user.getId(), null, null, new String[]{"notifications.project.reviewedPartial", projectTable.getSlug(), projectVersionTable.getVersionString()})); } else { - notificationTables.add(new NotificationTable(user.getId(), NotificationType.VERSION_REVIEWED, null, null, + notificationTables.add(new NotificationTable(user.getId(), null, null, new String[]{"notifications.project.reviewed", projectTable.getSlug(), projectVersionTable.getVersionString()})); } } }); notificationsDAO.insert(notificationTables); } - - public void notifyNewProjectInvite(Member member, long userId, long projectId, String projectName) { - notificationsDAO.insert(new NotificationTable(userId, NotificationType.PROJECT_INVITE, null, projectId, new String[]{"notifications.project.invite", member.getRole().getTitle(), projectName})); - } - - public void notifyNewOrganizationInvite(Member member, long userId, long organizationId, String organizationName) { - notificationsDAO.insert(new NotificationTable(userId, NotificationType.ORGANIZATION_INVITE, null, organizationId, new String[]{"notifications.organization.invite", member.getRole().getTitle(), organizationName})); - } } diff --git a/src/main/java/io/papermc/hangar/service/internal/users/invites/InviteService.java b/src/main/java/io/papermc/hangar/service/internal/users/invites/InviteService.java index ad9614b78..1f2af68f8 100644 --- a/src/main/java/io/papermc/hangar/service/internal/users/invites/InviteService.java +++ b/src/main/java/io/papermc/hangar/service/internal/users/invites/InviteService.java @@ -4,7 +4,9 @@ import io.papermc.hangar.db.dao.HangarDao; import io.papermc.hangar.db.dao.internal.HangarNotificationsDAO; import io.papermc.hangar.db.dao.internal.table.UserDAO; import io.papermc.hangar.exceptions.HangarApiException; +import io.papermc.hangar.model.Named; import io.papermc.hangar.model.common.roles.Role; +import io.papermc.hangar.model.db.Table; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.roles.ExtendedRoleTable; import io.papermc.hangar.model.internal.api.requests.EditMembersForm.Member; @@ -12,12 +14,14 @@ import io.papermc.hangar.service.HangarService; import io.papermc.hangar.service.internal.perms.members.MemberService; import io.papermc.hangar.service.internal.perms.roles.RoleService; import io.papermc.hangar.service.internal.users.NotificationService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; -public abstract class InviteService, RT extends ExtendedRoleTable> extends HangarService { +public abstract class InviteService, RT extends ExtendedRoleTable, J extends Table & Named> extends HangarService { @Autowired protected HangarDao hangarNotificationsDAO; @@ -29,18 +33,21 @@ public abstract class InviteService, RT extends ExtendedRoleT private HangarDao userDAO; private final RoleService roleService; - private final MemberService memberService; + private final MemberService memberService; + private final JoinableNotificationService joinableNotificationService; private final String errorPrefix; - protected InviteService(RoleService roleService, MemberService memberService, String errorPrefix) { + protected InviteService(RoleService roleService, MemberService memberService, JoinableNotificationService joinableNotificationService, String errorPrefix) { this.roleService = roleService; this.memberService = memberService; + this.joinableNotificationService = joinableNotificationService; this.errorPrefix = errorPrefix; } @Transactional - public void sendInvites(List errors, List> invitees, long principalId, String principalName) { + public void sendInvites(List errors, List> invitees, J joinable) { StringBuilder sb = new StringBuilder("Invited: "); + List toBeInvited = new ArrayList<>(); for (int i = 0; i < invitees.size(); i++) { Member invitee = invitees.get(i); UserTable userTable = userDAO.get().getUserTable(invitee.getName()); @@ -48,23 +55,23 @@ public abstract class InviteService, RT extends ExtendedRoleT errors.add(new HangarApiException(this.errorPrefix + "invalidUser", invitee.getName())); continue; } - if (roleService.addRole(invitee.getRole().create(principalId, userTable.getId(), false), true) == null) { + RT rt = roleService.addRole(invitee.getRole().create(joinable.getId(), userTable.getId(), false), true); + if (rt == null) { errors.add(new HangarApiException(this.errorPrefix + "alreadyInvited", invitee.getName())); continue; } - notifyNewInvites(invitee, userTable.getId(), principalId, principalName); + toBeInvited.add(rt); sb.append(userTable.getName()).append(" (").append(invitee.getRole().getTitle()).append(")"); if (i + 1 != invitees.size()) { sb.append(", "); } } if (!invitees.isEmpty()) { - logInvitesSent(principalId, sb.toString()); + joinableNotificationService.invited(toBeInvited, joinable); + logInvitesSent(joinable.getId(), sb.toString()); } } - abstract void notifyNewInvites(Member invitee, long userId, long principalId, String principalName); - abstract void logInvitesSent(long principalId, String log); public void acceptInvite(RT roleTable) { diff --git a/src/main/java/io/papermc/hangar/service/internal/users/invites/OrganizationInviteService.java b/src/main/java/io/papermc/hangar/service/internal/users/invites/OrganizationInviteService.java index 2f586879e..a04fd87d3 100644 --- a/src/main/java/io/papermc/hangar/service/internal/users/invites/OrganizationInviteService.java +++ b/src/main/java/io/papermc/hangar/service/internal/users/invites/OrganizationInviteService.java @@ -1,14 +1,15 @@ package io.papermc.hangar.service.internal.users.invites; import io.papermc.hangar.model.common.roles.OrganizationRole; +import io.papermc.hangar.model.db.OrganizationTable; import io.papermc.hangar.model.db.UserTable; import io.papermc.hangar.model.db.roles.OrganizationRoleTable; -import io.papermc.hangar.model.internal.api.requests.EditMembersForm.Member; import io.papermc.hangar.model.internal.logs.LogAction; import io.papermc.hangar.model.internal.logs.contexts.OrganizationContext; import io.papermc.hangar.model.internal.user.notifications.HangarInvite.HangarOrganizationInvite; import io.papermc.hangar.service.internal.perms.members.OrganizationMemberService; import io.papermc.hangar.service.internal.perms.roles.OrganizationRoleService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService.OrganizationNotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,22 +17,17 @@ import java.time.format.DateTimeFormatter; import java.util.List; @Service -public class OrganizationInviteService extends InviteService { +public class OrganizationInviteService extends InviteService { @Autowired - public OrganizationInviteService(OrganizationRoleService roleService, OrganizationMemberService memberService) { - super(roleService, memberService, "organization.settings.members."); + public OrganizationInviteService(OrganizationRoleService roleService, OrganizationMemberService memberService, OrganizationNotificationService organizationNotificationService) { + super(roleService, memberService, organizationNotificationService, "organization.settings.members."); } public List getOrganizationInvites() { return hangarNotificationsDAO.get().getOrganizationInvites(getHangarPrincipal().getId()); } - @Override - void notifyNewInvites(Member invitee, long userId, long principalId, String principalName) { - notificationService.notifyNewOrganizationInvite(invitee, userId, principalId, principalName); - } - @Override void logInvitesSent(long principalId, String log) { userActionLogService.organization(LogAction.ORGANIZATION_INVITES_SENT.create(OrganizationContext.of(principalId), log, "")); diff --git a/src/main/java/io/papermc/hangar/service/internal/users/invites/ProjectInviteService.java b/src/main/java/io/papermc/hangar/service/internal/users/invites/ProjectInviteService.java index 780dd8ca0..c1cf12d18 100644 --- a/src/main/java/io/papermc/hangar/service/internal/users/invites/ProjectInviteService.java +++ b/src/main/java/io/papermc/hangar/service/internal/users/invites/ProjectInviteService.java @@ -2,13 +2,14 @@ package io.papermc.hangar.service.internal.users.invites; import io.papermc.hangar.model.common.roles.ProjectRole; import io.papermc.hangar.model.db.UserTable; +import io.papermc.hangar.model.db.projects.ProjectTable; import io.papermc.hangar.model.db.roles.ProjectRoleTable; -import io.papermc.hangar.model.internal.api.requests.EditMembersForm.Member; import io.papermc.hangar.model.internal.logs.LogAction; import io.papermc.hangar.model.internal.logs.contexts.ProjectContext; import io.papermc.hangar.model.internal.user.notifications.HangarInvite.HangarProjectInvite; import io.papermc.hangar.service.internal.perms.members.ProjectMemberService; import io.papermc.hangar.service.internal.perms.roles.ProjectRoleService; +import io.papermc.hangar.service.internal.users.notifications.JoinableNotificationService.ProjectNotificationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,22 +17,17 @@ import java.time.format.DateTimeFormatter; import java.util.List; @Service -public class ProjectInviteService extends InviteService { +public class ProjectInviteService extends InviteService { @Autowired - public ProjectInviteService(ProjectRoleService roleService, ProjectMemberService memberService) { - super(roleService, memberService, "project.settings.error.members."); + public ProjectInviteService(ProjectRoleService roleService, ProjectMemberService memberService, ProjectNotificationService projectNotificationService) { + super(roleService, memberService, projectNotificationService, "project.settings.error.members."); } public List getProjectInvites() { return hangarNotificationsDAO.get().getProjectInvites(getHangarPrincipal().getId()); } - @Override - void notifyNewInvites(Member invitee, long userId, long principalId, String principalName) { - notificationService.notifyNewProjectInvite(invitee, userId, principalId, principalName); - } - @Override void logInvitesSent(long principalId, String log) { userActionLogService.project(LogAction.PROJECT_INVITES_SENT.create(ProjectContext.of(principalId), log, "")); diff --git a/src/main/java/io/papermc/hangar/service/internal/users/notifications/JoinableNotificationService.java b/src/main/java/io/papermc/hangar/service/internal/users/notifications/JoinableNotificationService.java new file mode 100644 index 000000000..e3b3c62a7 --- /dev/null +++ b/src/main/java/io/papermc/hangar/service/internal/users/notifications/JoinableNotificationService.java @@ -0,0 +1,74 @@ +package io.papermc.hangar.service.internal.users.notifications; + +import io.papermc.hangar.db.dao.HangarDao; +import io.papermc.hangar.db.dao.internal.table.NotificationsDAO; +import io.papermc.hangar.model.Named; +import io.papermc.hangar.model.common.roles.Role; +import io.papermc.hangar.model.db.NotificationTable; +import io.papermc.hangar.model.db.OrganizationTable; +import io.papermc.hangar.model.db.Table; +import io.papermc.hangar.model.db.projects.ProjectTable; +import io.papermc.hangar.model.db.roles.ExtendedRoleTable; +import io.papermc.hangar.model.db.roles.OrganizationRoleTable; +import io.papermc.hangar.model.db.roles.ProjectRoleTable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.HashSet; + +public abstract class JoinableNotificationService>, J extends Table & Named> { + + @Autowired + private HangarDao notificationsDAO; + + protected final String msgPrefix; + + protected JoinableNotificationService(String msgPrefix) { + this.msgPrefix = msgPrefix; + } + + public void invited(Collection inviteeRoleTables, J joinable) { + Collection notificationTables = new HashSet<>(); + for (RT rt : inviteeRoleTables) { + notificationTables.add(new NotificationTable(rt.getUserId(), null, joinable.getId(), new String[]{ this.msgPrefix + "invite", rt.getRole().getTitle(), joinable.getName()})); + } + notificationsDAO.get().insert(notificationTables); + } + + public void removedFrom(Collection removedFromRoleTables, J joinable) { + Collection notificationTables = new HashSet<>(); + for (RT rt : removedFromRoleTables) { + String msgKey = this.msgPrefix + (rt.isAccepted() ? "removed" : "inviteRescinded"); + notificationTables.add(new NotificationTable(rt.getUserId(), null, joinable.getId(), new String[] {msgKey, rt.getRole().getTitle(), joinable.getName()})); + } + notificationsDAO.get().insert(notificationTables); + } + + public void roleChanged(Collection changedRoleTables, J joinable) { + Collection notificationTables = new HashSet<>(); + for (RT rt : changedRoleTables) { + notificationTables.add(new NotificationTable(rt.getUserId(), null, joinable.getId(), new String[] {this.msgPrefix + "roleChanged", rt.getRole().getTitle(), joinable.getName()})); + } + notificationsDAO.get().insert(notificationTables); + } + + + @Service + public static class ProjectNotificationService extends JoinableNotificationService { + + public ProjectNotificationService() { + super("notifications.project."); + } + + } + + @Service + public static class OrganizationNotificationService extends JoinableNotificationService { + + public OrganizationNotificationService() { + super("notifications.organization."); + } + + } +} diff --git a/src/main/java/io/papermc/hangar/service/internal/visibility/VisibilityService.java b/src/main/java/io/papermc/hangar/service/internal/visibility/VisibilityService.java index e3ca15b89..b4836d9d9 100644 --- a/src/main/java/io/papermc/hangar/service/internal/visibility/VisibilityService.java +++ b/src/main/java/io/papermc/hangar/service/internal/visibility/VisibilityService.java @@ -15,7 +15,7 @@ import org.springframework.http.HttpStatus; import java.util.Map.Entry; -public abstract class VisibilityService extends HangarService { +abstract class VisibilityService extends HangarService { @Autowired private PermissionService permissionService; diff --git a/src/main/java/io/papermc/hangar/serviceold/NotificationService.java b/src/main/java/io/papermc/hangar/serviceold/NotificationService.java index 5909d8e60..16a663dbd 100644 --- a/src/main/java/io/papermc/hangar/serviceold/NotificationService.java +++ b/src/main/java/io/papermc/hangar/serviceold/NotificationService.java @@ -3,7 +3,7 @@ package io.papermc.hangar.serviceold; import io.papermc.hangar.db.dao.HangarDao; import io.papermc.hangar.db.daoold.NotificationsDao; import io.papermc.hangar.db.modelold.NotificationsTable; -import io.papermc.hangar.model.internal.user.notifications.NotificationType; +import io.papermc.hangar.modelold.NotificationType; import org.postgresql.shaded.com.ongres.scram.common.util.Preconditions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/src/main/resources/db/migration/V1.0.1__removeNotificationType.sql b/src/main/resources/db/migration/V1.0.1__removeNotificationType.sql new file mode 100644 index 000000000..d0483e097 --- /dev/null +++ b/src/main/resources/db/migration/V1.0.1__removeNotificationType.sql @@ -0,0 +1 @@ +ALTER TABLE notifications DROP COLUMN notification_type;