From 16992a46dddcf3378ff943c4105c38684b2979a1 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 1 Jul 2026 09:14:07 -0700 Subject: [PATCH 1/7] Only send required news items --- .../wise/portal/dao/newsitem/NewsItemDao.java | 4 ++-- .../newsitem/impl/HibernateNewsItemDao.java | 15 ++++++++++--- .../controllers/news/NewsAPIController.java | 17 +++++++++----- .../service/newsitem/NewsItemService.java | 14 +++++++----- .../newsitem/impl/NewsItemServiceImpl.java | 9 ++++---- .../impl/HibernateNewsItemDaoTest.java | 22 +++++++++---------- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java b/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java index 5691a6e7ee..e6703689f6 100644 --- a/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java +++ b/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java @@ -24,6 +24,7 @@ package org.wise.portal.dao.newsitem; import java.util.List; +import java.util.Optional; import org.wise.portal.dao.SimpleDao; import org.wise.portal.domain.newsitem.NewsItem; @@ -34,6 +35,5 @@ */ public interface NewsItemDao extends SimpleDao { - List getListByType(String type); - + List getLatestNews(Optional number, Optional type); } diff --git a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java index 464a31da18..f90c98efee 100644 --- a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java +++ b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java @@ -24,6 +24,7 @@ package org.wise.portal.dao.newsitem.impl; import java.util.List; +import java.util.Optional; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; @@ -50,13 +51,21 @@ protected Class getDataObjectClass() { @Override @SuppressWarnings("unchecked") - public List getListByType(String type) { + public List getLatestNews(Optional number, Optional type) { CriteriaBuilder cb = getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(NewsItemImpl.class); Root newsItemRoot = cq.from(NewsItemImpl.class); - cq.select(newsItemRoot).where(cb.equal(newsItemRoot.get("type"), type)) - .orderBy(cb.desc(newsItemRoot.get("id"))); + + cq.select(newsItemRoot); + if (type.isPresent()) { + cq.where(cb.equal(newsItemRoot.get("type"), type.get())); + } + cq.orderBy(cb.desc(newsItemRoot.get("id"))); + TypedQuery query = entityManager.createQuery(cq); + if (number.isPresent() && number.get() >= 0) { + query.setMaxResults(number.get()); + } return (List) (Object) query.getResultList(); } } diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java index cf7df012bd..003f8fe048 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java @@ -4,13 +4,16 @@ import org.json.JSONException; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.wise.portal.domain.newsitem.NewsItem; import org.wise.portal.service.newsitem.NewsItemService; import java.util.List; +import java.util.Optional; @RestController @RequestMapping(value = "/api/news", produces = "application/json;charset=UTF-8") @@ -19,10 +22,14 @@ public class NewsAPIController { @Autowired private NewsItemService newsItemService; - @RequestMapping(value = "", method = RequestMethod.GET) - protected String getNews() { - List newsItems = newsItemService.retrieveAllNewsItem(); - JSONArray newsItemsJSON = getNewsItemsJSON(newsItems); + @GetMapping() + protected String getNews(@RequestParam Optional num, @RequestParam Optional type) { + List newsItems = newsItemService.retrieveLatestNewsItems(num, type); + return this.convertNewsToJSONString(newsItems); + } + + private String convertNewsToJSONString(List newsItems) { + JSONArray newsItemsJSON = this.getNewsItemsJSON(newsItems); return newsItemsJSON.toString(); } diff --git a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java index affa99b020..628c85dd7b 100644 --- a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java +++ b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; +import java.util.Optional; import org.wise.portal.dao.ObjectNotFoundException; import org.wise.portal.domain.newsitem.NewsItem; @@ -48,16 +49,17 @@ public interface NewsItemService { NewsItem createNewsItem(Date date, User owner, String title, String news, String type); /** - * Retrieves all NewsItem from the data store. + * Retrieves the latest NewsItems from the data store. + * @param number the number of news items to return. Get all if number is not present or negative. + * @param type the type of news items to retrieve. Get all if type is not present. * @return a Set of NewsItem */ - List retrieveAllNewsItem(); + List retrieveLatestNewsItems(Optional number, Optional type); - /** - * Retrieves all NewsItem by specified type - * @return a Set of NewsItem of specified type + /** Retrieves all NewsItem from the data store. + * @return a Set of NewsItem */ - List retrieveByType(String type); + List retrieveAllNewsItem(); /** * Retrieves a NewsItem given an ID diff --git a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java index a34e57f971..c7034b5acf 100644 --- a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java +++ b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java @@ -35,6 +35,7 @@ import java.util.Date; import java.util.List; +import java.util.Optional; /** * @author Patrick Lawler @@ -45,12 +46,12 @@ public class NewsItemServiceImpl implements NewsItemService { @Autowired private NewsItemDao newsItemDao; - public List retrieveAllNewsItem() { - return newsItemDao.getList(); + public List retrieveLatestNewsItems(Optional number, Optional type) { + return newsItemDao.getLatestNews(number, type); } - public List retrieveByType(String type) { - return newsItemDao.getListByType(type); + public List retrieveAllNewsItem() { + return this.retrieveLatestNewsItems(Optional.empty(), Optional.empty()); } public NewsItem retrieveById(Integer id) throws ObjectNotFoundException { diff --git a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java index 140ba8f969..dd785b26d1 100644 --- a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java +++ b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java @@ -56,18 +56,18 @@ public void setUp() throws Exception { Schoollevel.COLLEGE, "1234567890"); } - @Test - public void getListByType_TypeThatDoesNotExist_ShouldReturnNone() { - List newsItems = newsItemDao.getListByType("test"); - assertEquals(0, newsItems.size()); - } + // @Test + // public void getListByType_TypeThatDoesNotExist_ShouldReturnNone() { + // List newsItems = newsItemDao.getListByType("test"); + // assertEquals(0, newsItems.size()); + // } - @Test - public void getListByType_TypeThatExists_ShouldReturnNewsItems() { - createNewsItem(teacher, new Date(), "public", "News Title", "news1"); - List newsItems = newsItemDao.getListByType("public"); - assertEquals(1, newsItems.size()); - } + // @Test + // public void getListByType_TypeThatExists_ShouldReturnNewsItems() { + // createNewsItem(teacher, new Date(), "public", "News Title", "news1"); + // List newsItems = newsItemDao.getListByType("public"); + // assertEquals(1, newsItems.size()); + // } private NewsItem createNewsItem(User owner, Date date, String type, String title, String news) { NewsItem newsItem = new NewsItemImpl(); From 3db8d3a93c82373b912e035de21a54e98cc057f3 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Thu, 2 Jul 2026 13:09:01 -0700 Subject: [PATCH 2/7] Caching and cache eviction --- .../domain/newsitem/impl/NewsItemImpl.java | 3 +- .../controllers/news/NewsAPIController.java | 18 ++++++------ .../service/newsitem/NewsItemService.java | 9 +++++- .../newsitem/impl/NewsItemServiceImpl.java | 29 +++++++++++++++++-- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/wise/portal/domain/newsitem/impl/NewsItemImpl.java b/src/main/java/org/wise/portal/domain/newsitem/impl/NewsItemImpl.java index 1b0a5b7166..b9bdc1567e 100644 --- a/src/main/java/org/wise/portal/domain/newsitem/impl/NewsItemImpl.java +++ b/src/main/java/org/wise/portal/domain/newsitem/impl/NewsItemImpl.java @@ -23,6 +23,7 @@ */ package org.wise.portal.domain.newsitem.impl; +import java.io.Serializable; import java.util.Date; import javax.persistence.Column; @@ -52,7 +53,7 @@ @Table(name = NewsItemImpl.DATA_STORE_NAME) @Getter @Setter -public class NewsItemImpl implements NewsItem, Comparable { +public class NewsItemImpl implements NewsItem, Comparable, Serializable { @Transient public static final String DATA_STORE_NAME = "newsitem"; diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java index 003f8fe048..6c44fa7a83 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java @@ -5,7 +5,6 @@ import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -23,22 +22,23 @@ public class NewsAPIController { private NewsItemService newsItemService; @GetMapping() - protected String getNews(@RequestParam Optional num, @RequestParam Optional type) { - List newsItems = newsItemService.retrieveLatestNewsItems(num, type); - return this.convertNewsToJSONString(newsItems); + protected String getAllNews(@RequestParam Optional num, @RequestParam Optional type) { + List newsItems = this.newsItemService.retrieveLatestNews(num, type); + return this.getNewsItemsJSONString(newsItems); } - private String convertNewsToJSONString(List newsItems) { - JSONArray newsItemsJSON = this.getNewsItemsJSON(newsItems); - return newsItemsJSON.toString(); + @GetMapping("/home") + protected String getHomePageNews(@RequestParam Optional type) { + List newsItems = this.newsItemService.retrieveAndCacheHomePageNews(type); + return this.getNewsItemsJSONString(newsItems); } - private JSONArray getNewsItemsJSON(List newsItems) { + private String getNewsItemsJSONString(List newsItems) { JSONArray newsItemsJSON = new JSONArray(); for (NewsItem newsItem: newsItems) { newsItemsJSON.put(getNewsItemJSON(newsItem)); } - return newsItemsJSON; + return newsItemsJSON.toString(); } private JSONObject getNewsItemJSON(NewsItem newsItem) { diff --git a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java index 628c85dd7b..c23ec919b3 100644 --- a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java +++ b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java @@ -54,7 +54,14 @@ public interface NewsItemService { * @param type the type of news items to retrieve. Get all if type is not present. * @return a Set of NewsItem */ - List retrieveLatestNewsItems(Optional number, Optional type); + List retrieveLatestNews(Optional number, Optional type); + + /** + * Uses cached value or retrieves and caches the latest three NewsItems from the data store. + * @param type the type of news items to retrieve. Get all if type is not present. + * @return a Set of NewsItem + */ + List retrieveAndCacheHomePageNews(Optional type); /** Retrieves all NewsItem from the data store. * @return a Set of NewsItem diff --git a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java index c7034b5acf..a9341530ab 100644 --- a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java +++ b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java @@ -24,6 +24,10 @@ package org.wise.portal.service.newsitem.impl; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.CacheManager; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.wise.portal.dao.ObjectNotFoundException; @@ -36,6 +40,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import javax.management.timer.Timer; /** * @author Patrick Lawler @@ -46,14 +51,26 @@ public class NewsItemServiceImpl implements NewsItemService { @Autowired private NewsItemDao newsItemDao; - public List retrieveLatestNewsItems(Optional number, Optional type) { + @Autowired + private CacheManager cacheManager; + + @Override + public List retrieveLatestNews(Optional number, Optional type) { return newsItemDao.getLatestNews(number, type); } + @Override + @Cacheable(value = "newsItems", key = "#type.orElse('all')") + public List retrieveAndCacheHomePageNews(Optional type) { + return newsItemDao.getLatestNews(Optional.of(3), type); + } + + @Override public List retrieveAllNewsItem() { - return this.retrieveLatestNewsItems(Optional.empty(), Optional.empty()); + return newsItemDao.getLatestNews(Optional.empty(), Optional.empty()); } + @Override public NewsItem retrieveById(Integer id) throws ObjectNotFoundException { try { return newsItemDao.getById(id); @@ -63,6 +80,7 @@ public NewsItem retrieveById(Integer id) throws ObjectNotFoundException { } @Transactional + @CacheEvict(value = "newsItems", allEntries = true) public NewsItem createNewsItem(Date date, User owner, String title, String news, String type) { NewsItem newsItem = new NewsItemImpl(); newsItem.setDate(date); @@ -75,6 +93,7 @@ public NewsItem createNewsItem(Date date, User owner, String title, String news, } @Transactional + @CacheEvict(value = "newsItems", allEntries = true) public void updateNewsItem(Integer id, Date date, User owner, String title, String news, String type) throws ObjectNotFoundException { NewsItem newsItem = newsItemDao.getById(id); @@ -87,8 +106,14 @@ public void updateNewsItem(Integer id, Date date, User owner, String title, } @Transactional + @CacheEvict(value = "newsItems", allEntries = true) public void deleteNewsItem(Integer id) throws ObjectNotFoundException { NewsItem newsItem = newsItemDao.getById(id); newsItemDao.delete(newsItem); } + + @Scheduled(fixedRate = Timer.ONE_HOUR) + @CacheEvict(value = "newsItems", allEntries = true) + public void evictNewsItemsCache() { + } } From 717fed7984563465ccc3683a5e7b13c659b74fcd Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Fri, 3 Jul 2026 18:57:04 -0700 Subject: [PATCH 3/7] Fixed broken test --- .../portal/service/newsitem/impl/NewsItemServiceImplTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java b/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java index dd2aaac49f..15cdefc972 100644 --- a/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java +++ b/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java @@ -36,6 +36,7 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Optional; import org.easymock.EasyMockExtension; import org.easymock.Mock; @@ -162,7 +163,7 @@ public void retrieveAllNewsItem_TwoNewsItemsInDB_ShouldSucceed() { List newsItemsInDB = new ArrayList(); newsItemsInDB.add(newsItem1); newsItemsInDB.add(newsItem2); - expect(newsItemDao.getList()).andReturn(newsItemsInDB); + expect(newsItemDao.getLatestNews(Optional.empty(), Optional.empty())).andReturn(newsItemsInDB); replay(newsItemDao); List newsItemsFromDB = newsItemServiceImpl.retrieveAllNewsItem(); From 3880cd820559c77f225db67c692bccb481c087cb Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Tue, 7 Jul 2026 19:28:55 -0700 Subject: [PATCH 4/7] Tried to fix tests (I can't run them locally, so not sure if they pass) --- .../impl/HibernateNewsItemDaoTest.java | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java index dd785b26d1..91da628361 100644 --- a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java +++ b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java @@ -26,6 +26,7 @@ import java.util.Date; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,18 +57,27 @@ public void setUp() throws Exception { Schoollevel.COLLEGE, "1234567890"); } - // @Test - // public void getListByType_TypeThatDoesNotExist_ShouldReturnNone() { - // List newsItems = newsItemDao.getListByType("test"); - // assertEquals(0, newsItems.size()); - // } + @Test + public void getLatestNews_TypeThatDoesNotExist_ShouldReturnNone() { + List newsItems = newsItemDao.getLatestNews(Optional.empty(), Optional.of("test")); + assertEquals(0, newsItems.size()); + } + + @Test + public void getLatestNews_TypeThatExists_ShouldReturnNewsItems() { + createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 2", "news2"); + List newsItems = newsItemDao.getLatestNews(Optional.empty(), Optional.of("public")); + assertEquals(1, newsItems.size()); + } - // @Test - // public void getListByType_TypeThatExists_ShouldReturnNewsItems() { - // createNewsItem(teacher, new Date(), "public", "News Title", "news1"); - // List newsItems = newsItemDao.getListByType("public"); - // assertEquals(1, newsItems.size()); - // } + @Test + public void getLatestNews_NumberSpecified_ShouldReturnNumberOfNewsItems() { + createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); + createNewsItem(teacher, new Date(), "public", "News Title 2", "news2"); + List newsItems = newsItemDao.getLatestNews(Optional.of(1), Optional.empty()); + assertEquals(1, newsItems.size()); + } private NewsItem createNewsItem(User owner, Date date, String type, String title, String news) { NewsItem newsItem = new NewsItemImpl(); From ed43b9a9a26afa35e5c1c9ac37589c92ab16f4ff Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 8 Jul 2026 16:46:26 -0700 Subject: [PATCH 5/7] Remove optionals, change bad names, and other code improvements --- .../wise/portal/dao/newsitem/NewsItemDao.java | 8 ++++-- .../newsitem/impl/HibernateNewsItemDao.java | 26 ++++++++++++++----- .../wise/portal/domain/newsitem/NewsType.java | 13 ++++++++++ .../controllers/news/NewsAPIController.java | 12 +++++---- .../service/newsitem/NewsItemService.java | 7 +++-- .../newsitem/impl/NewsItemServiceImpl.java | 18 +++++-------- 6 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 src/main/java/org/wise/portal/domain/newsitem/NewsType.java diff --git a/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java b/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java index e6703689f6..b3d71a4367 100644 --- a/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java +++ b/src/main/java/org/wise/portal/dao/newsitem/NewsItemDao.java @@ -24,10 +24,10 @@ package org.wise.portal.dao.newsitem; import java.util.List; -import java.util.Optional; import org.wise.portal.dao.SimpleDao; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; /** * @author Patrick Lawler @@ -35,5 +35,9 @@ */ public interface NewsItemDao extends SimpleDao { - List getLatestNews(Optional number, Optional type); + List getNewsPageNews(NewsType type); + + List getHomePageNews(NewsType type); + + List getAllNews(); } diff --git a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java index f90c98efee..0a9fe0524e 100644 --- a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java +++ b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java @@ -24,7 +24,6 @@ package org.wise.portal.dao.newsitem.impl; import java.util.List; -import java.util.Optional; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; @@ -35,6 +34,7 @@ import org.wise.portal.dao.impl.AbstractHibernateDao; import org.wise.portal.dao.newsitem.NewsItemDao; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.domain.newsitem.impl.NewsItemImpl; /** @@ -50,21 +50,35 @@ protected Class getDataObjectClass() { } @Override + public List getNewsPageNews(NewsType type) { + return getLatestNews(-1, type); + } + + @Override + public List getHomePageNews(NewsType type) { + return getLatestNews(3, type); + } + + @Override + public List getAllNews() { + return getLatestNews(-1, NewsType.PUBLIC_AND_TEACHER); + } + @SuppressWarnings("unchecked") - public List getLatestNews(Optional number, Optional type) { + private List getLatestNews(int number, NewsType type) { CriteriaBuilder cb = getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(NewsItemImpl.class); Root newsItemRoot = cq.from(NewsItemImpl.class); cq.select(newsItemRoot); - if (type.isPresent()) { - cq.where(cb.equal(newsItemRoot.get("type"), type.get())); + if (type.equals(NewsType.PUBLIC_ONLY)) { + cq.where(cb.equal(newsItemRoot.get("type"), "public")); } cq.orderBy(cb.desc(newsItemRoot.get("id"))); TypedQuery query = entityManager.createQuery(cq); - if (number.isPresent() && number.get() >= 0) { - query.setMaxResults(number.get()); + if (number >= 0) { + query.setMaxResults(number); } return (List) (Object) query.getResultList(); } diff --git a/src/main/java/org/wise/portal/domain/newsitem/NewsType.java b/src/main/java/org/wise/portal/domain/newsitem/NewsType.java new file mode 100644 index 0000000000..f834e576d4 --- /dev/null +++ b/src/main/java/org/wise/portal/domain/newsitem/NewsType.java @@ -0,0 +1,13 @@ +package org.wise.portal.domain.newsitem; + +public enum NewsType { + PUBLIC_ONLY, PUBLIC_AND_TEACHER; + + public static NewsType stringToNewsType(String type) throws IllegalArgumentException { + return switch (type) { + case "publicOnly" -> PUBLIC_ONLY; + case "publicAndTeacher" -> PUBLIC_AND_TEACHER; + default -> throw new IllegalArgumentException("Invalid news type: " + type); + }; + } +} diff --git a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java index 6c44fa7a83..fa8c04382a 100644 --- a/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java +++ b/src/main/java/org/wise/portal/presentation/web/controllers/news/NewsAPIController.java @@ -9,10 +9,10 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.service.newsitem.NewsItemService; import java.util.List; -import java.util.Optional; @RestController @RequestMapping(value = "/api/news", produces = "application/json;charset=UTF-8") @@ -22,14 +22,16 @@ public class NewsAPIController { private NewsItemService newsItemService; @GetMapping() - protected String getAllNews(@RequestParam Optional num, @RequestParam Optional type) { - List newsItems = this.newsItemService.retrieveLatestNews(num, type); + protected String getNewsPageNews(@RequestParam String type) { + NewsType newsType = NewsType.stringToNewsType(type); + List newsItems = this.newsItemService.retrieveNewsPageNews(newsType); return this.getNewsItemsJSONString(newsItems); } @GetMapping("/home") - protected String getHomePageNews(@RequestParam Optional type) { - List newsItems = this.newsItemService.retrieveAndCacheHomePageNews(type); + protected String getHomePageNews(@RequestParam String type) { + NewsType newsType = NewsType.stringToNewsType(type); + List newsItems = this.newsItemService.retrieveAndCacheHomePageNews(newsType); return this.getNewsItemsJSONString(newsItems); } diff --git a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java index c23ec919b3..e4042e38c1 100644 --- a/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java +++ b/src/main/java/org/wise/portal/service/newsitem/NewsItemService.java @@ -25,10 +25,10 @@ import java.util.Date; import java.util.List; -import java.util.Optional; import org.wise.portal.dao.ObjectNotFoundException; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.domain.user.User; /** @@ -50,18 +50,17 @@ public interface NewsItemService { /** * Retrieves the latest NewsItems from the data store. - * @param number the number of news items to return. Get all if number is not present or negative. * @param type the type of news items to retrieve. Get all if type is not present. * @return a Set of NewsItem */ - List retrieveLatestNews(Optional number, Optional type); + List retrieveNewsPageNews(NewsType type); /** * Uses cached value or retrieves and caches the latest three NewsItems from the data store. * @param type the type of news items to retrieve. Get all if type is not present. * @return a Set of NewsItem */ - List retrieveAndCacheHomePageNews(Optional type); + List retrieveAndCacheHomePageNews(NewsType type); /** Retrieves all NewsItem from the data store. * @return a Set of NewsItem diff --git a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java index a9341530ab..1ed7bff765 100644 --- a/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java +++ b/src/main/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImpl.java @@ -26,20 +26,19 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.CacheManager; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.wise.portal.dao.ObjectNotFoundException; import org.wise.portal.dao.newsitem.NewsItemDao; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.domain.newsitem.impl.NewsItemImpl; import org.wise.portal.domain.user.User; import org.wise.portal.service.newsitem.NewsItemService; import java.util.Date; import java.util.List; -import java.util.Optional; import javax.management.timer.Timer; /** @@ -51,23 +50,20 @@ public class NewsItemServiceImpl implements NewsItemService { @Autowired private NewsItemDao newsItemDao; - @Autowired - private CacheManager cacheManager; - @Override - public List retrieveLatestNews(Optional number, Optional type) { - return newsItemDao.getLatestNews(number, type); + public List retrieveNewsPageNews(NewsType type) { + return newsItemDao.getNewsPageNews(type); } @Override - @Cacheable(value = "newsItems", key = "#type.orElse('all')") - public List retrieveAndCacheHomePageNews(Optional type) { - return newsItemDao.getLatestNews(Optional.of(3), type); + @Cacheable(value = "newsItems", key = "#type") + public List retrieveAndCacheHomePageNews(NewsType type) { + return newsItemDao.getHomePageNews(type); } @Override public List retrieveAllNewsItem() { - return newsItemDao.getLatestNews(Optional.empty(), Optional.empty()); + return newsItemDao.getAllNews(); } @Override From d6bc0ff9df37c1708601a3515a61f6e1bea80183 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 8 Jul 2026 17:00:18 -0700 Subject: [PATCH 6/7] Replaced number argument for boolean since limit is always either 3 or none --- .../dao/newsitem/impl/HibernateNewsItemDao.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java index 0a9fe0524e..d8da555785 100644 --- a/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java +++ b/src/main/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDao.java @@ -51,21 +51,21 @@ protected Class getDataObjectClass() { @Override public List getNewsPageNews(NewsType type) { - return getLatestNews(-1, type); + return getLatestNews(false, type); } @Override public List getHomePageNews(NewsType type) { - return getLatestNews(3, type); + return getLatestNews(true, type); } @Override public List getAllNews() { - return getLatestNews(-1, NewsType.PUBLIC_AND_TEACHER); + return getLatestNews(false, NewsType.PUBLIC_AND_TEACHER); } @SuppressWarnings("unchecked") - private List getLatestNews(int number, NewsType type) { + private List getLatestNews(boolean limitQuery, NewsType type) { CriteriaBuilder cb = getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(NewsItemImpl.class); Root newsItemRoot = cq.from(NewsItemImpl.class); @@ -77,8 +77,8 @@ private List getLatestNews(int number, NewsType type) { cq.orderBy(cb.desc(newsItemRoot.get("id"))); TypedQuery query = entityManager.createQuery(cq); - if (number >= 0) { - query.setMaxResults(number); + if (limitQuery) { + query.setMaxResults(3); } return (List) (Object) query.getResultList(); } From 77f0c0bd49103a62681fc95b4f4fb69bc3f4f4a3 Mon Sep 17 00:00:00 2001 From: Aaron Detre Date: Wed, 8 Jul 2026 17:01:07 -0700 Subject: [PATCH 7/7] Fixed tests --- .../impl/HibernateNewsItemDaoTest.java | 35 +++++++++++++------ .../impl/NewsItemServiceImplTest.java | 7 ++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java index 91da628361..5b8be1a8e5 100644 --- a/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java +++ b/src/test/java/org/wise/portal/dao/newsitem/impl/HibernateNewsItemDaoTest.java @@ -34,6 +34,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.wise.portal.domain.authentication.Schoollevel; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.domain.newsitem.impl.NewsItemImpl; import org.wise.portal.domain.user.User; import org.wise.portal.junit.AbstractTransactionalDbTests; @@ -58,25 +59,39 @@ public void setUp() throws Exception { } @Test - public void getLatestNews_TypeThatDoesNotExist_ShouldReturnNone() { - List newsItems = newsItemDao.getLatestNews(Optional.empty(), Optional.of("test")); - assertEquals(0, newsItems.size()); + public void getNewsPageNews_WithPublicOnlyType_ShouldReturnAllNewsItems() { + createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 2", "news2"); + List newsItems = newsItemDao.getNewsPageNews(NewsType.PUBLIC_ONLY); + assertEquals(1, newsItems.size()); } @Test - public void getLatestNews_TypeThatExists_ShouldReturnNewsItems() { + public void getNewsPageNews_WithPublicAndTeacherType_ShouldReturnAllNewsItems() { createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); createNewsItem(teacher, new Date(), "teacherOnly", "News Title 2", "news2"); - List newsItems = newsItemDao.getLatestNews(Optional.empty(), Optional.of("public")); - assertEquals(1, newsItems.size()); + List newsItems = newsItemDao.getNewsPageNews(NewsType.PUBLIC_AND_TEACHER); + assertEquals(2, newsItems.size()); } @Test - public void getLatestNews_NumberSpecified_ShouldReturnNumberOfNewsItems() { + public void getHomePageNews_ShouldReturnThreeNewsItems() { createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); - createNewsItem(teacher, new Date(), "public", "News Title 2", "news2"); - List newsItems = newsItemDao.getLatestNews(Optional.of(1), Optional.empty()); - assertEquals(1, newsItems.size()); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 2", "news2"); + createNewsItem(teacher, new Date(), "public", "News Title 3", "news3"); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 4", "news4"); + List newsItems = newsItemDao.getHomePageNews(NewsType.PUBLIC_AND_TEACHER); + assertEquals(3, newsItems.size()); + } + + @Test + public void getAllNews_ShouldReturnAllNewsItems() { + createNewsItem(teacher, new Date(), "public", "News Title 1", "news1"); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 2", "news2"); + createNewsItem(teacher, new Date(), "public", "News Title 3", "news3"); + createNewsItem(teacher, new Date(), "teacherOnly", "News Title 4", "news4"); + List newsItems = newsItemDao.getAllNews(); + assertEquals(4, newsItems.size()); } private NewsItem createNewsItem(User owner, Date date, String type, String title, String news) { diff --git a/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java b/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java index 15cdefc972..ce9433ded8 100644 --- a/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java +++ b/src/test/java/org/wise/portal/service/newsitem/impl/NewsItemServiceImplTest.java @@ -48,6 +48,7 @@ import org.wise.portal.dao.ObjectNotFoundException; import org.wise.portal.dao.newsitem.NewsItemDao; import org.wise.portal.domain.newsitem.NewsItem; +import org.wise.portal.domain.newsitem.NewsType; import org.wise.portal.domain.newsitem.impl.NewsItemImpl; import org.wise.portal.domain.user.User; import org.wise.portal.domain.user.impl.UserImpl; @@ -159,14 +160,14 @@ public void deleteNewsItem_InvalidNewsItemID_ShouldThrowException() } @Test - public void retrieveAllNewsItem_TwoNewsItemsInDB_ShouldSucceed() { + public void retrieveNewsPageNews_TwoNewsItemsInDB_ShouldSucceed() { List newsItemsInDB = new ArrayList(); newsItemsInDB.add(newsItem1); newsItemsInDB.add(newsItem2); - expect(newsItemDao.getLatestNews(Optional.empty(), Optional.empty())).andReturn(newsItemsInDB); + expect(newsItemDao.getNewsPageNews(NewsType.PUBLIC_AND_TEACHER)).andReturn(newsItemsInDB); replay(newsItemDao); - List newsItemsFromDB = newsItemServiceImpl.retrieveAllNewsItem(); + List newsItemsFromDB = newsItemServiceImpl.retrieveNewsPageNews(NewsType.PUBLIC_AND_TEACHER); assertEquals(newsItemsFromDB.size(), 2); assertTrue(newsItemsFromDB.get(0).equals(newsItem1)); assertTrue(newsItemsFromDB.get(1).equals(newsItem2));