From 7256630c0af44587c62c87a1e96cbeb1129a0684 Mon Sep 17 00:00:00 2001 From: Alex Bogdanovski Date: Thu, 30 Nov 2023 21:55:12 +0200 Subject: [PATCH] added 3 new standard webhook events - question.view, user.signin, user.search, closes #418 --- .../controllers/QuestionController.java | 22 ++++++++++++ .../scoold/controllers/SearchController.java | 34 ++++++++++++++++++- .../scoold/controllers/SigninController.java | 20 +++++++++++ .../com/erudika/scoold/utils/ScooldUtils.java | 3 ++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/erudika/scoold/controllers/QuestionController.java b/src/main/java/com/erudika/scoold/controllers/QuestionController.java index 2f34123b..87b14148 100755 --- a/src/main/java/com/erudika/scoold/controllers/QuestionController.java +++ b/src/main/java/com/erudika/scoold/controllers/QuestionController.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -56,6 +57,7 @@ import javax.ws.rs.Produces; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.hc.core5.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; @@ -136,6 +138,7 @@ public String get(@PathVariable String id, @PathVariable(required = false) Strin if (showPost.getAuthor() != null) { model.addAttribute("ogimage", utils.getFullAvatarURL(showPost.getAuthor(), AvatarFormat.Profile)); } + triggerQuestionViewEvent(showPost, req); return "base"; } @@ -604,4 +607,23 @@ private void unApproveAnswer(Profile authUser, Profile author, Post showPost) { pc.updateAll(Arrays.asList(author, authUser)); } } + + private void triggerQuestionViewEvent(Post question, HttpServletRequest req) { + if (req != null) { + Profile authUser = utils.getAuthUser(req); + Map payload = new LinkedHashMap<>(ParaObjectUtils.getAnnotatedFields(authUser, false)); + if (authUser != null) { + payload.put("visitor", ParaObjectUtils.getAnnotatedFields(authUser, false)); + } else { + payload.put("visitor", Collections.emptyMap()); + } + Map headers = new HashMap<>(); + headers.put(HttpHeaders.REFERER, req.getHeader(HttpHeaders.REFERER)); + headers.put(HttpHeaders.USER_AGENT, req.getHeader(HttpHeaders.USER_AGENT)); + headers.put("User-IP", req.getRemoteAddr()); + payload.put("headers", headers); + payload.put("question", question); + utils.triggerHookEvent("question.view", payload); + } + } } diff --git a/src/main/java/com/erudika/scoold/controllers/SearchController.java b/src/main/java/com/erudika/scoold/controllers/SearchController.java index ede056e4..a377bce0 100755 --- a/src/main/java/com/erudika/scoold/controllers/SearchController.java +++ b/src/main/java/com/erudika/scoold/controllers/SearchController.java @@ -20,6 +20,7 @@ import com.erudika.para.client.ParaClient; import com.erudika.para.core.utils.Config; import com.erudika.para.core.utils.Pager; +import com.erudika.para.core.utils.ParaObjectUtils; import com.erudika.para.core.utils.Utils; import com.erudika.scoold.ScooldConfig; import static com.erudika.scoold.ScooldServer.SEARCHLINK; @@ -43,11 +44,20 @@ import com.sun.syndication.io.FeedException; import com.sun.syndication.io.SyndFeedOutput; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; +import org.apache.hc.core5.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.CacheControl; @@ -135,6 +145,7 @@ public String get(@PathVariable(required = false) String type, @PathVariable(req model.addAttribute("feedbacklist", feedbacklist); model.addAttribute("commentslist", commentslist); + triggerSearchEvent(type, qs, userlist.size() + questionslist.size() + answerslist.size() + commentslist.size(), req); return "base"; } @@ -299,4 +310,25 @@ private String getSitemap(HttpServletRequest req) throws IOException, FeedExcept logger.debug("Sitemap generation skipped - public={} auth={}", utils.isDefaultSpacePublic(), utils.isAuthenticated(req)); return "<_/>"; } + + private void triggerSearchEvent(String type, String query, int results, HttpServletRequest req) { + if (req != null) { + Profile authUser = utils.getAuthUser(req); + Map payload = new LinkedHashMap<>(ParaObjectUtils.getAnnotatedFields(authUser, false)); + if (authUser != null) { + payload.put("visitor", ParaObjectUtils.getAnnotatedFields(authUser, false)); + } else { + payload.put("visitor", Collections.emptyMap()); + } + Map headers = new HashMap<>(); + headers.put(HttpHeaders.REFERER, req.getHeader(HttpHeaders.REFERER)); + headers.put(HttpHeaders.USER_AGENT, req.getHeader(HttpHeaders.USER_AGENT)); + headers.put("User-IP", req.getRemoteAddr()); + payload.put("headers", headers); + payload.put("category", type); + payload.put("query", query); + payload.put("results", results); + utils.triggerHookEvent("user.search", payload); + } + } } diff --git a/src/main/java/com/erudika/scoold/controllers/SigninController.java b/src/main/java/com/erudika/scoold/controllers/SigninController.java index c4253518..fea66fa4 100755 --- a/src/main/java/com/erudika/scoold/controllers/SigninController.java +++ b/src/main/java/com/erudika/scoold/controllers/SigninController.java @@ -22,16 +22,19 @@ import com.erudika.para.core.User; import com.erudika.para.core.annotations.Email; import com.erudika.para.core.utils.Config; +import com.erudika.para.core.utils.ParaObjectUtils; import com.erudika.para.core.utils.Utils; import com.erudika.scoold.ScooldConfig; import static com.erudika.scoold.ScooldServer.HOMEPAGE; import static com.erudika.scoold.ScooldServer.SIGNINLINK; +import com.erudika.scoold.core.Profile; import com.erudika.scoold.utils.HttpUtils; import static com.erudika.scoold.utils.HttpUtils.getBackToUrl; import static com.erudika.scoold.utils.HttpUtils.setAuthCookie; import com.erudika.scoold.utils.ScooldUtils; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.inject.Inject; @@ -39,6 +42,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.apache.hc.core5.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; @@ -159,6 +163,7 @@ public String signup(@RequestParam String name, @RequestParam String email, @Req User u = pc.signIn("password", email + ":" + name + ":" + passw, false); if (u != null && u.getActive()) { setAuthCookie(u.getPassword(), req, res); + triggerLoginEvent(u, req); return "redirect:" + getBackToUrl(req); } else { verifyEmailIfNecessary(name, email, req); @@ -305,6 +310,7 @@ private String onAuthSuccess(User u, HttpServletRequest req, HttpServletResponse if (u != null && utils.isEmailDomainApproved(u.getEmail())) { // the user password in this case is a Bearer token (JWT) setAuthCookie(u.getPassword(), req, res); + triggerLoginEvent(u, req); return "redirect:" + getBackToUrl(req); } else if (u != null && !utils.isEmailDomainApproved(u.getEmail())) { logger.warn("Signin failed for {} because that domain is not in the whitelist.", u.getEmail()); @@ -421,4 +427,18 @@ private boolean isValidResetToken(Sysprop s, String key, String token) { } return false; } + + private void triggerLoginEvent(User u, HttpServletRequest req) { + if (req != null && u != null) { + Profile authUser = utils.getAuthUser(req); + Map payload = new LinkedHashMap<>(ParaObjectUtils.getAnnotatedFields(authUser, false)); + Map headers = new HashMap<>(); + headers.put(HttpHeaders.REFERER, req.getHeader(HttpHeaders.REFERER)); + headers.put(HttpHeaders.USER_AGENT, req.getHeader(HttpHeaders.USER_AGENT)); + headers.put("User-IP", req.getRemoteAddr()); + payload.put("user", u); + payload.put("headers", headers); + utils.triggerHookEvent("user.signin", payload); + } + } } diff --git a/src/main/java/com/erudika/scoold/utils/ScooldUtils.java b/src/main/java/com/erudika/scoold/utils/ScooldUtils.java index 5745f72d..fee52301 100755 --- a/src/main/java/com/erudika/scoold/utils/ScooldUtils.java +++ b/src/main/java/com/erudika/scoold/utils/ScooldUtils.java @@ -157,11 +157,14 @@ public final class ScooldUtils { HOOK_EVENTS = new HashSet<>(Arrays.asList( "question.create", "question.close", + "question.view", "answer.create", "answer.accept", "report.create", "comment.create", + "user.signin", "user.signup", + "user.search", "revision.restore")); WHITELISTED_MACROS = new HashMap();