diff --git a/src/main/java/io/paradaux/api/controllers/VisitsController.java b/src/main/java/io/paradaux/api/controllers/VisitsController.java index 6584d1b..5b4351f 100644 --- a/src/main/java/io/paradaux/api/controllers/VisitsController.java +++ b/src/main/java/io/paradaux/api/controllers/VisitsController.java @@ -1,10 +1,13 @@ package io.paradaux.api.controllers; +import io.paradaux.api.models.VisitCountEntry; import io.paradaux.api.models.VisitEntry; import io.paradaux.api.models.annotations.ProtectedRoute; import io.paradaux.api.services.VisitsService; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/api/analytics/visits") public class VisitsController { @@ -25,4 +28,9 @@ public void insertVisit(@RequestBody VisitEntry visit) { public Integer getVisitCountByProject(@PathVariable String project) { return visitsService.getVisitCount(project); } + + @GetMapping("/projects") + public List getVisitCountsForProjects() { + return visitsService.getVisitCountsForProjects(); + } } diff --git a/src/main/java/io/paradaux/api/mappers/VisitsMapper.java b/src/main/java/io/paradaux/api/mappers/VisitsMapper.java index cba676d..4783c45 100644 --- a/src/main/java/io/paradaux/api/mappers/VisitsMapper.java +++ b/src/main/java/io/paradaux/api/mappers/VisitsMapper.java @@ -1,11 +1,15 @@ package io.paradaux.api.mappers; +import io.paradaux.api.models.VisitCountEntry; import io.paradaux.api.models.VisitEntry; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface VisitsMapper { void insertVisit(VisitEntry visit); Integer getVisitCount(String project); + List getVisitCountsForProjects(); void refreshVisitCache(); } diff --git a/src/main/java/io/paradaux/api/models/VisitCountEntry.java b/src/main/java/io/paradaux/api/models/VisitCountEntry.java new file mode 100644 index 0000000..67e8a95 --- /dev/null +++ b/src/main/java/io/paradaux/api/models/VisitCountEntry.java @@ -0,0 +1,16 @@ +package io.paradaux.api.models; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +public class VisitCountEntry implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private String project; + private int totalCount; +} diff --git a/src/main/java/io/paradaux/api/services/VisitsService.java b/src/main/java/io/paradaux/api/services/VisitsService.java index 5247e91..5ea132a 100644 --- a/src/main/java/io/paradaux/api/services/VisitsService.java +++ b/src/main/java/io/paradaux/api/services/VisitsService.java @@ -1,7 +1,10 @@ package io.paradaux.api.services; +import io.paradaux.api.models.VisitCountEntry; import io.paradaux.api.models.VisitEntry; +import java.util.List; + public interface VisitsService { /** * Inserts a new IfumVisit record into the database. @@ -15,6 +18,13 @@ public interface VisitsService { */ Integer getVisitCount(String project); + /** + * Retrieves a list of visit counts grouped by project. + * + * @return a list of VisitCountEntry objects containing project names and their visit counts + */ + List getVisitCountsForProjects(); + /** * Refreshes the visit view which groups visit counts by project. */ diff --git a/src/main/java/io/paradaux/api/services/impl/VisitsServiceImpl.java b/src/main/java/io/paradaux/api/services/impl/VisitsServiceImpl.java index df2c057..8755335 100644 --- a/src/main/java/io/paradaux/api/services/impl/VisitsServiceImpl.java +++ b/src/main/java/io/paradaux/api/services/impl/VisitsServiceImpl.java @@ -1,6 +1,7 @@ package io.paradaux.api.services.impl; import io.paradaux.api.mappers.VisitsMapper; +import io.paradaux.api.models.VisitCountEntry; import io.paradaux.api.models.VisitEntry; import io.paradaux.api.services.VisitsService; import lombok.extern.slf4j.Slf4j; @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.TreeSet; @@ -18,9 +20,9 @@ public class VisitsServiceImpl implements VisitsService { private static final TreeSet IGNORED_USER_AGENTS = new TreeSet<>(Arrays.asList( "bot", "crawler", "spider", "scanner", "curl", "wget", - "python", "java", "php", "unknown", "discord", "(compatible)", + "python", "java", "php", "unknown", "discord", "(compatible;", "zgrab", "scrapy", "censys", "okhttp", "axios", "go-http-client", - "google", "bing", "yahoo" + "google", "bing", "yahoo", "WhatCMS" )); private final VisitsMapper visitsMapper; @@ -52,6 +54,11 @@ public Integer getVisitCount(String project) { return visitsMapper.getVisitCount(project); } + @Override + public List getVisitCountsForProjects() { + return visitsMapper.getVisitCountsForProjects(); + } + @CacheEvict(value = "visitCounts", allEntries = true) @Override public void refreshVisitCache() { diff --git a/src/main/resources/mappers/VisitsMapper.xml b/src/main/resources/mappers/VisitsMapper.xml index 4c1c599..befce98 100644 --- a/src/main/resources/mappers/VisitsMapper.xml +++ b/src/main/resources/mappers/VisitsMapper.xml @@ -18,6 +18,15 @@ SELECT total_count FROM analytics.visit_count_view WHERE project = #{project} + + + + + + + REFRESH MATERIALIZED VIEW CONCURRENTLY analytics.visit_count_view;