From 86013742559fd5cc95374705fe1dfe860f2f762e Mon Sep 17 00:00:00 2001 From: nattamon Date: Sun, 30 Nov 2025 16:09:40 -0500 Subject: [PATCH 1/4] EDIT source info api key, get from controller --- .DS_Store | Bin 0 -> 8196 bytes app/actors/SourcesInfoActor.java | 15 +++++++-------- app/actors/SupervisorActor.java | 2 +- app/actors/UserActor.java | 2 -- app/controllers/HomeController.java | 10 ++-------- project/.DS_Store | Bin 0 -> 6148 bytes project/project/.DS_Store | Bin 0 -> 6148 bytes test/actors/SourcesInfoActorTest.java | 14 +++++++------- 8 files changed, 17 insertions(+), 26 deletions(-) create mode 100644 .DS_Store create mode 100644 project/.DS_Store create mode 100644 project/project/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4fd61f2082ce55f69bafcf147fdacb57ff17ef5d GIT binary patch literal 8196 zcmeHM!A=uF82$&UY(ZoxEvZqHjlGyaVoOCN9$X8?pa%#gSOQpf+oddQck1qziiD(R zeE=W82k`3E2hgKe559mG&-%~K6tIN@!2rgYWagXBKi|%NUx!)#EdY>Qy_^9^0)T>* zq1uPd5rxHB?I>MhB#KCo4=@iF)PRBqLC0)4ARUknNC%_?(gEqfMQ{M0*{mqXJokB2 zw$cIVz<=ogJ0CQx40VA`j^WXPO_%~8MsPSR*vC8|jU27JWk2NRc|eIO(W08%-Ob*c7}f4(vwNf3?qnuAs*O*K z?d?UCMC#6i`QnySb?F-}hlnEq`rG8aJx-fl+7{Z#=a#l_s@hT)?d`kLe|10|j13LO z2NQ|mSTb=fcKt?C9Wss5R>fm?Jw+Yr<(#@zR0n+2K2xIZoM&yL=0ae-3i9@A48__A z^H%xA!O+4^4d=uU2EvOz@hr<-u6TBNc75Hqg2JKx5?ih0QOB91z8%=qU0MlO53K5p zyH0UMb_cUH7V;M@&qwUw6qXFnGu(=m+gWuC({g6r91Q|mE!e1n-FdiVzGjqcw~~7J zgBu%7>9=`Lg;dMyls+b+@z#()vfvt33rTZ)Af-PO5d}uz5#(V7UP2Sz!F%`spWq98 zhoA6^^pjz7i;R#_GEOFlPG-ncvP{;9K{h$RtM!H76xS0#eC!;#nYZ(v>rl6XamJ0{ zR;N$_|GYPO=04lllj&1#@_jvRI(zVCoQFy`@wHqDg7a4Um;R*NRJCcoj7OP)sw=4Z z+!c>!@es?TPkV^{p{Y%;*!vQs11EK$n-h{O|9^b^`~Q<(R?e3WNC*BQ2S{W(Kb^xH zZv9`?e(x;T*08Q&WrfXaattZhgy}e9n2sav|6quH4W}}WF0jcFN3fjvi-5CCV&wBb L{ElUF@f`RKvW2=i literal 0 HcmV?d00001 diff --git a/app/actors/SourcesInfoActor.java b/app/actors/SourcesInfoActor.java index 501f3c5..7a707ee 100644 --- a/app/actors/SourcesInfoActor.java +++ b/app/actors/SourcesInfoActor.java @@ -21,8 +21,6 @@ public class SourcesInfoActor extends AbstractBehavior { /** HTTP client used to call external APIs (e.g., NewsAPI) and fetch JSON responses. */ private final WSClient wsClient; - /** API key read from configuration and attached to outbound API requests. */ - private final String apiKey; /** Cache to store list of sources information from the News Api */ private SourcesInfo cachedInfo = null; @@ -35,9 +33,11 @@ public interface Message {} */ public static class GetSourcesInfo implements Message { public final ActorRef replyTo; + public final String apiKey; - public GetSourcesInfo(ActorRef replyTo) { + public GetSourcesInfo(String apiKey, ActorRef replyTo) { this.replyTo = replyTo; + this.apiKey = apiKey; } } @@ -64,14 +64,13 @@ public SourcesInfoFailed(String error) { } } - public static Behavior create(WSClient wsClient, String apiKey) { - return Behaviors.setup(context -> new SourcesInfoActor(context, wsClient, apiKey)); + public static Behavior create(WSClient wsClient) { + return Behaviors.setup(context -> new SourcesInfoActor(context, wsClient)); } - private SourcesInfoActor(ActorContext context, WSClient wsClient, String apiKey) { + private SourcesInfoActor(ActorContext context, WSClient wsClient) { super(context); this.wsClient = wsClient; - this.apiKey = apiKey; } @Override @@ -91,7 +90,7 @@ private Behavior onGetSourcesInfo(GetSourcesInfo msg) { getContext().getLog().info("SourcesInfoActor processing request for all sources."); - SourcesInfo sourcesInfoModel = new SourcesInfo(this.apiKey); + SourcesInfo sourcesInfoModel = new SourcesInfo(msg.apiKey); CompletionStage future = sourcesInfoModel.fetchSourcesInfo(wsClient); future.whenComplete((ignored, error) -> { diff --git a/app/actors/SupervisorActor.java b/app/actors/SupervisorActor.java index bb12615..b41d91f 100644 --- a/app/actors/SupervisorActor.java +++ b/app/actors/SupervisorActor.java @@ -165,7 +165,7 @@ public static Behavior create(WSClient wsClient) { ); // create sourceInfo actor ActorRef sourcesInfoActor = context.spawn( - SourcesInfoActor.create(wsClient, apiKey), + SourcesInfoActor.create(wsClient), "sourcesInfoActor" ); context.getLog().info("sourceActor and sourcesInfoActor spawned and ready"); diff --git a/app/actors/UserActor.java b/app/actors/UserActor.java index 644f439..1e5a5ff 100644 --- a/app/actors/UserActor.java +++ b/app/actors/UserActor.java @@ -191,7 +191,6 @@ private static class SearchInstance { * @return behavior for handling user-specific messages * @author Nattamon Paiboon */ - // TODO rm cache public static Behavior create(String id, ActorRef newsActor, ActorRef rActor, ActorRef sentimentActor) { return Behaviors.setup(context -> new UserActor(id, context, newsActor, rActor, sentimentActor).behavior()); } @@ -207,7 +206,6 @@ public static Behavior create(String id, ActorRef ne * @param rActor reference to the ReadbailityActor for getting readability * @author Nattamon Paiboon */ - // TODO rm cache private UserActor(String id, ActorContext context, ActorRef newsActor, ActorRef rActor, ActorRef sentimentActor) { this.id = id; this.context = context; diff --git a/app/controllers/HomeController.java b/app/controllers/HomeController.java index 6623e6a..0964af3 100644 --- a/app/controllers/HomeController.java +++ b/app/controllers/HomeController.java @@ -41,9 +41,6 @@ public class HomeController extends Controller { /** API key read from configuration and attached to outbound API requests. */ private final String apiKey; - /** Asynchronous cache used to store session history and source data with a TTL. */ - private final AsyncCacheApi asyncCache; - private final ActorSystem actorSystem; private final ActorRef supervisorActor; @@ -57,17 +54,14 @@ public class HomeController extends Controller { * * @author Luan Tran, Nattamon Paiboon * @param ws the WSClient used to send HTTP requests to the News API - * @param asyncCache the cache used to store user search history and source information * @param config the application's configuration, which contains the API key */ @Inject - public HomeController(WSClient ws, AsyncCacheApi asyncCache, Config config, ActorSystem actorSystem) { + public HomeController(WSClient ws, Config config, ActorSystem actorSystem) { this.ws = ws; - this.asyncCache = asyncCache; this.apiKey = config.getString("api.key"); this.actorSystem = actorSystem; - // TODO rm cache this.supervisorActor = actorSystem.systemActorOf( SupervisorActor.create(ws), "SupervisorActor", Props.empty() ); @@ -145,7 +139,7 @@ public CompletionStage source(String identifier, String sourceName) { // Ask SourcesInfoActor for the list of all sources return AskPattern.ask( sourcesInfoActor, - (ActorRef replyTo) -> new SourcesInfoActor.GetSourcesInfo(replyTo), + (ActorRef replyTo) -> new SourcesInfoActor.GetSourcesInfo(this.apiKey, replyTo), Duration.ofSeconds(10), actorSystem.scheduler() ).thenCompose(infoResponse -> { diff --git a/project/.DS_Store b/project/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6c51da10b361613840c9f1f12c1e370a0f4185e0 GIT binary patch literal 6148 zcmeHK%}T>S5T3QwrWBzEg&r5Y7VM8jikDF93mDOZN^MNgXv~&2wTDv3SzpK}@p+ut z-GJ2|Jc-yD*!^bbXE*af_6Gn&ZyGcKssP|%BNU{p5HhcHZP;K!q2~zU7E*sU8Ts*w ziTbM4)$nU@aJ>7+LtU()DI zso2l;p?@BQvq5#|SS9H&O2V;Dh=LG9t}db^P_v$zCc#AKddA_Do${bso6pW zJBzxUcbo0H>>Rchi?Xx3w|{gxc#NMC^}4Y zAbL=QNkufN!agyCNk_Z1ajwP8ph*XzSH^kl%K76(=+)6KbvOvuAot7wGqB7+!3?W( z{-5A4v+|L@oWdh!fEoB_42WXi>-VrId$xWnkIq_&?FJhO#bu47Bho13)yu#B3}eFA>1(ozrer;H1bTa literal 0 HcmV?d00001 diff --git a/project/project/.DS_Store b/project/project/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..18616c59ce7b6cda69377171152b58a3650ab870 GIT binary patch literal 6148 zcmeHK%}T>S5Z<-5-BN@c6nb3nTChJBDPBUXFJMFuDm5Xc24l9gsXdfJ&iX<=iO=KA z?&c6IcoVTRu=~x<&u->}>7$+pVZ3Ff^50)g83beu9Zr{ zLJz{5c(NKhhZic%f;gSbbwV6XAmsiwP9wGQ)H010I@dQ2(GZQX(^{|l!_&6x4F{XH zTo1ebwj7-GHk*bxIzBnS8b2p5sd_U+a^PIcfyDyeK`GVr>d(_erBkpMIYlfXF+dCu z1H{1YF<{RE(cHb#sbXS)82Et!+#e(~MAu?&P;VX3;q@8)RYVlf@hyQUExHzSgWv(- zCKb@6a{I*KCLQe3#<>=AgC?DEy)w*WS1ukeT(1sxslyp}4N^}G5CdffDrV^5`F{z& z%+^PKIfX{V05R~-7~s{BKk}d`d$xWn56@Z&?GYLZ#^tDhfL^);zySA=mUbGyL>=N> Xi@8CZ1?@T=kS+q65bB75Utr)10k%v$ literal 0 HcmV?d00001 diff --git a/test/actors/SourcesInfoActorTest.java b/test/actors/SourcesInfoActorTest.java index de1e6fd..a84d8b4 100644 --- a/test/actors/SourcesInfoActorTest.java +++ b/test/actors/SourcesInfoActorTest.java @@ -67,10 +67,10 @@ public void testGetSourcesInfo_Success() { when(mockResponse.getStatus()).thenReturn(200); when(mockResponse.asJson()).thenReturn(json); - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); SourcesInfoActor.SourcesInfoLoaded response = probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); assertNotNull(response.sourcesInfo); @@ -90,10 +90,10 @@ public void testGetSourcesInfo_Failure() { when(mockRequest.get()).thenReturn(CompletableFuture.completedFuture(mockResponse)); when(mockResponse.getStatus()).thenReturn(500); // Server error - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); SourcesInfoActor.SourcesInfoFailed response = probe.expectMessageClass(SourcesInfoActor.SourcesInfoFailed.class); assertNotNull(response.error); @@ -115,15 +115,15 @@ public void testGetSourcesInfo_Caching() { when(mockResponse.getStatus()).thenReturn(200); when(mockResponse.asJson()).thenReturn(json); - ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient, "key")); + ActorRef actor = testKit.spawn(SourcesInfoActor.create(mockWsClient)); TestProbe probe = testKit.createTestProbe(); // 1st Call - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); // 2nd Call: Hits Cache - actor.tell(new SourcesInfoActor.GetSourcesInfo(probe.getRef())); + actor.tell(new SourcesInfoActor.GetSourcesInfo("key", probe.getRef())); probe.expectMessageClass(SourcesInfoActor.SourcesInfoLoaded.class); // Verify API called ONCE From 556794024f79f8e85ca9d5e79e33c4d70031ea5b Mon Sep 17 00:00:00 2001 From: nattamon Date: Sun, 30 Nov 2025 16:16:22 -0500 Subject: [PATCH 2/4] rm ds_store file --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 4fd61f2082ce55f69bafcf147fdacb57ff17ef5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM!A=uF82$&UY(ZoxEvZqHjlGyaVoOCN9$X8?pa%#gSOQpf+oddQck1qziiD(R zeE=W82k`3E2hgKe559mG&-%~K6tIN@!2rgYWagXBKi|%NUx!)#EdY>Qy_^9^0)T>* zq1uPd5rxHB?I>MhB#KCo4=@iF)PRBqLC0)4ARUknNC%_?(gEqfMQ{M0*{mqXJokB2 zw$cIVz<=ogJ0CQx40VA`j^WXPO_%~8MsPSR*vC8|jU27JWk2NRc|eIO(W08%-Ob*c7}f4(vwNf3?qnuAs*O*K z?d?UCMC#6i`QnySb?F-}hlnEq`rG8aJx-fl+7{Z#=a#l_s@hT)?d`kLe|10|j13LO z2NQ|mSTb=fcKt?C9Wss5R>fm?Jw+Yr<(#@zR0n+2K2xIZoM&yL=0ae-3i9@A48__A z^H%xA!O+4^4d=uU2EvOz@hr<-u6TBNc75Hqg2JKx5?ih0QOB91z8%=qU0MlO53K5p zyH0UMb_cUH7V;M@&qwUw6qXFnGu(=m+gWuC({g6r91Q|mE!e1n-FdiVzGjqcw~~7J zgBu%7>9=`Lg;dMyls+b+@z#()vfvt33rTZ)Af-PO5d}uz5#(V7UP2Sz!F%`spWq98 zhoA6^^pjz7i;R#_GEOFlPG-ncvP{;9K{h$RtM!H76xS0#eC!;#nYZ(v>rl6XamJ0{ zR;N$_|GYPO=04lllj&1#@_jvRI(zVCoQFy`@wHqDg7a4Um;R*NRJCcoj7OP)sw=4Z z+!c>!@es?TPkV^{p{Y%;*!vQs11EK$n-h{O|9^b^`~Q<(R?e3WNC*BQ2S{W(Kb^xH zZv9`?e(x;T*08Q&WrfXaattZhgy}e9n2sav|6quH4W}}WF0jcFN3fjvi-5CCV&wBb L{ElUF@f`RKvW2=i From b4e89c284a631ce58945dcc50c6a989fd2246e5f Mon Sep 17 00:00:00 2001 From: nattamon Date: Sun, 30 Nov 2025 16:18:05 -0500 Subject: [PATCH 3/4] rm ds_store file --- project/.DS_Store | Bin 6148 -> 0 bytes project/project/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 project/.DS_Store delete mode 100644 project/project/.DS_Store diff --git a/project/.DS_Store b/project/.DS_Store deleted file mode 100644 index 6c51da10b361613840c9f1f12c1e370a0f4185e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T3QwrWBzEg&r5Y7VM8jikDF93mDOZN^MNgXv~&2wTDv3SzpK}@p+ut z-GJ2|Jc-yD*!^bbXE*af_6Gn&ZyGcKssP|%BNU{p5HhcHZP;K!q2~zU7E*sU8Ts*w ziTbM4)$nU@aJ>7+LtU()DI zso2l;p?@BQvq5#|SS9H&O2V;Dh=LG9t}db^P_v$zCc#AKddA_Do${bso6pW zJBzxUcbo0H>>Rchi?Xx3w|{gxc#NMC^}4Y zAbL=QNkufN!agyCNk_Z1ajwP8ph*XzSH^kl%K76(=+)6KbvOvuAot7wGqB7+!3?W( z{-5A4v+|L@oWdh!fEoB_42WXi>-VrId$xWnkIq_&?FJhO#bu47Bho13)yu#B3}eFA>1(ozrer;H1bTa diff --git a/project/project/.DS_Store b/project/project/.DS_Store deleted file mode 100644 index 18616c59ce7b6cda69377171152b58a3650ab870..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z<-5-BN@c6nb3nTChJBDPBUXFJMFuDm5Xc24l9gsXdfJ&iX<=iO=KA z?&c6IcoVTRu=~x<&u->}>7$+pVZ3Ff^50)g83beu9Zr{ zLJz{5c(NKhhZic%f;gSbbwV6XAmsiwP9wGQ)H010I@dQ2(GZQX(^{|l!_&6x4F{XH zTo1ebwj7-GHk*bxIzBnS8b2p5sd_U+a^PIcfyDyeK`GVr>d(_erBkpMIYlfXF+dCu z1H{1YF<{RE(cHb#sbXS)82Et!+#e(~MAu?&P;VX3;q@8)RYVlf@hyQUExHzSgWv(- zCKb@6a{I*KCLQe3#<>=AgC?DEy)w*WS1ukeT(1sxslyp}4N^}G5CdffDrV^5`F{z& z%+^PKIfX{V05R~-7~s{BKk}d`d$xWn56@Z&?GYLZ#^tDhfL^);zySA=mUbGyL>=N> Xi@8CZ1?@T=kS+q65bB75Utr)10k%v$ From 881904a1598f19202c66fa9ba406aa9c0e32be95 Mon Sep 17 00:00:00 2001 From: nattamon Date: Sun, 30 Nov 2025 16:21:54 -0500 Subject: [PATCH 4/4] edit gitignore --- .gitignore | 1 + conf/application.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 71eee8c..4e7ea5b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ target /RUNNING_PID /htmlReport *.iml +.DS_Store \ No newline at end of file diff --git a/conf/application.conf b/conf/application.conf index 6a91315..19f2aeb 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -13,5 +13,6 @@ api { # "test" "a482d6d109894277b9ec6a6d2f4e83e9", "1002d5e24b1a4a0b92719ed6281694a9", + "c3f75cdb287647839659a5d323e7d01a" ] } \ No newline at end of file