From 9d83dec681e7693450cd084787e9233ecffc8291 Mon Sep 17 00:00:00 2001 From: RIT Services Date: Thu, 20 Aug 2026 04:58:20 +0000 Subject: [PATCH] Time Table Fixed --- db/whatsappbot.mv.db | Bin 36864 -> 40960 bytes db/whatsappbot.trace.db | 336 ++++++++++++++++++ .../whatsapp/handler/StudentMenuHandler.java | 1 + .../rit/whatsapp/util/MessageFormatter.java | 263 +++++++++----- src/main/resources/application.properties | 2 +- .../whatsapp/WhatsappBotApplicationTests.java | 42 +++ 6 files changed, 557 insertions(+), 87 deletions(-) diff --git a/db/whatsappbot.mv.db b/db/whatsappbot.mv.db index 291090a86d98aabd50f49b3786f5d6c27ca22e07..a123c36473a1574963ab969c43f8e90267d0720a 100644 GIT binary patch literal 40960 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 I(?gy4KZWURUjP6A literal 36864 zcmeHQOK;rP73R#u4lT(J5}*YN6ey$Ev7Jn&yu2@RfHWRS<4A~J)r?ZB2q2J`myTj- zMvzC2)kTp-&{a?rL4Xtiy6R)mZ2Aw{ZCiBHKM-Wmzfg41MGr3@!+FS(t#R$dS1?H4 zAuoCOT@L4*?>qN+vF=oZ-LANkty?=klXYau7wyWPcwZjWX-ESXQ9fnpKaGG!KqH_L&Wk>KqH_L&%JdAH80d;a}8qL2iz=kM1Es~&W_Aofca@&aruk!M$XJA1NDcpw<}ib((+ zdB0cps=cnLBgCjRsXxdixZqp}jPfgniR{R+L+qN!VZP_%&_tdT6jN?GVd(k}$0oLg zE0`acnDa0Y)P{|SBVkh$dtvBP7CnyzB}8~8!9MjI*E1>dIh=}{6qC@Fj%`xc#sQ9y zNj;zWHir%A3mL20yW8s?$XXcGRu6Y~ z-}QG7<$~Yy+eiCSAM^C!Qym(w-u>FUNxF>;)u6=#cKN0+U^I`e3>^%EyV3nH8`kWo z=guYXkKv_RsUHyria2Un$m{-b1*(g~<HqOx34ZfPo-Jk_;N^o&j{Qb*wyWL*Aj>OXeH%i_HbA-I!Z$TC?k$bIVKfv$fgSz}D=wso1fcU0+;VZEmk_ zuFN$zX07?f#ztel4L9&^V`FP+_3dj8rPtN1tZptZSCc-?)%lIB^>%Y%d%e+W&95yq zkL#IsSXyaqFD)E*(A4$I*2@>yQux+4mR8`});rCug3alt+wkc&nYGqd3;WXh8N8M2 zSF9@+e-4nty^IF{09&x;*H&BYjmFYyyKut(hw-%v23;GvhPAZ1(7aXXIcO&QPXBS{ zo$_?Wxb)&n#=3_*Oo&HejoxefckX;}>mE8{-MO`Whb(@u@_M`R=9@ouz=efJ%H}q< zUFgFw_qdBagx=d)=pnv_H{aemoFn$y>p$)M@Ix`!$EHqv9nT}!qb|emZFxT-%R6G{ z;O2af+`4&l*N^Unw+F5R*8)rF%v5EjV!SwT$x8!9zcg@a=u`gW(kIWAzH6L=AgAW2 zB|aZ-6Pm1;`i!b&vdz`DtCpTx25KqJclf7of_2G;BAnsbvyQX>GsfSsQyutm>$o^MV|J2Cp9eGsG!ky|pf4826PFK`n z$(@fLl?5r+lauB5HF{(gf#v4|^wd#Vdg?ou{Dfq{qj1}$y58a_Nrdt~PCEe0- z9^Wku0hLi%*j92%qU4oW$t~d$Ed?cBCbUeLVU)hQ^xJcWX_zV?uSGoD@Sfj;ABfsc zcs`E7YbaSc$%-bcAX$k&l+tjXr#bz!IvCdP?%b2>D#VW?dkFCvg!u7?E6_-TeJ2g} zL!pBGAPSu<*vE_ur+U~qybH4dlGtCS%|@^P-1O-Hp7H=Lt#*Yt-1j@;sE(sAGdsQ1 zPFLB9Qu@JBCKc`Eqh^w7$~2_Z1iW+LPlO)Ht>q|kAI92*wcv;sjJ0tI&1A#}mY$O} zYzLT!tl@Bu@;%sQBHx2CA_U$w9~s7LU%)WmFv=gk1h1aI7?tyXGmHxSLkqC~hEe&^ zr?7_h*S}J0z0e3~1T+E~0gZr0KqH_L&C-Q&J2q^hK4t)DDHsgWckM~&?l*jTv;geJUEerJj%HJ!W8^(0b zk)Vttak352&f}s5wTNUJ^dabz-)FQ0N@)o^K%YQsm_EUyyhH|;P=tgNxikZdNk|DO z5E8(q1Z0#xDU?(|iav>gs7Ofg&oeXol^bG~Cu2`Y!Az_MvPklb45~;5HF8j%(*cJ0 zY}7EPKhD4i!2m$fPTshLj}VU`sqRNDfTIT){5+tFZz7W$?#!iB}S}h zCHi${B}uIueD;f@>?90*4U;fctFTFD>D1e&-Us!#Y7>f{q26fL~VSX!KZqcm1pM2WPR z$c@jcv}m6oE!tXIOeEy9NsFjV9C#LwF6@?#3lDOe&*CH}PD++KTy&pOjqyQVo_3NU zSGwrEKP67`WSqQ@644XH&GP1k^7+dD*{J6sh@C3ULE`H}2$H$bOmgmcBhD%4{aJtv zo3RVc2r9bJZmulbW1ag^bjP^Rb`r$$)VjpDq9?7a3v*9;Ag(Lu;C60o1fdle3+d)X zV^Iw9Q2d?UUc~y<^a$gW2HY>k?UUNh;{U-fahm@h$BmE8#(HQjU4!bGG+-K(^Q%8_AA<%vvVsG2P8pKHzrY0d_?)bX6n7ug(ulM7|gWDY=)r-K5H!yK3*cJOhv zG78)r?{jlwi(@#pO1(bgSe=SlyWsGrAevoBuFVThLi$w_LQ@=l9ZSn(t$Fa%%jI2Td*YVcoMDs{SmP~%Dk~$QRl#z7<7_?6l x72zMBC2PIZ2xtT}0vZ90fJQ(gFaZS8_&(MVStore.java:296) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2164) + at org.h2.mvstore.db.Store.(Store.java:133) + at org.h2.engine.Database.(Database.java:328) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:350) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:124) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:144) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:373) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:210) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:488) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:576) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:97) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.getConnection(DataSourceConnectionProvider.java:149) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:508) + at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:48) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:366) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironment(JdbcEnvironmentInitiator.java:143) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:120) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:80) + at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:133) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:260) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:235) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:212) + at org.hibernate.boot.model.relational.Database.(Database.java:44) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:251) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:203) + at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:180) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1388) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.populateSessionFactoryBuilder(EntityManagerFactoryBuilderImpl.java:1468) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1450) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:93) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:443) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:436) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:411) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:419) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1811) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:977) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$2(SpringBootContextLoader.java:155) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1465) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:600) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:155) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:114) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:247) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.lambda$loadContext$0(DefaultCacheAwareContextLoaderDelegate.java:167) + at org.springframework.test.context.cache.DefaultContextCache.put(DefaultContextCache.java:214) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:160) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:128) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:242) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$1(ClassBasedTestDescriptor.java:423) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:428) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$0(ClassBasedTestDescriptor.java:422) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:422) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$0(ClassBasedTestDescriptor.java:334) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:333) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$1(ClassBasedTestDescriptor.java:322) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$0(ClassBasedTestDescriptor.java:321) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:127) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:126) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:70) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$0(NodeTestTask.java:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:144) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:110) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58) + at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: /opt/projects/RITz-whatsapp-bot/db/whatsappbot.mv.db [2.4.240/7]" [50000-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:566) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + ... 153 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: /opt/projects/RITz-whatsapp-bot/db/whatsappbot.mv.db [2.4.240/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:996) + at org.h2.mvstore.SingleFileStore.lockFileChannel(SingleFileStore.java:143) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:117) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:81) + at org.h2.mvstore.MVStore.(MVStore.java:291) + ... 147 more +2026-08-20 04:52:47.925225Z database: flush +org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: /opt/projects/RITz-whatsapp-bot/db/whatsappbot.mv.db [2.4.240/7]" [50000-240] + at org.h2.message.DbException.get(DbException.java:212) + at org.h2.message.DbException.convert(DbException.java:407) + at org.h2.mvstore.db.Store.lambda$new$0(Store.java:122) + at org.h2.mvstore.MVStore.handleException(MVStore.java:1675) + at org.h2.mvstore.MVStore.panic(MVStore.java:502) + at org.h2.mvstore.MVStore.(MVStore.java:296) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2164) + at org.h2.mvstore.db.Store.(Store.java:133) + at org.h2.engine.Database.(Database.java:328) + at org.h2.engine.Engine.openSession(Engine.java:92) + at org.h2.engine.Engine.openSession(Engine.java:222) + at org.h2.engine.Engine.createSession(Engine.java:201) + at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:350) + at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:124) + at org.h2.Driver.connect(Driver.java:59) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:144) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:373) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:210) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:488) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:576) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:97) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) + at org.hibernate.engine.jdbc.connections.internal.DataSourceConnectionProvider.getConnection(DataSourceConnectionProvider.java:149) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:508) + at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:44) + at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:37) + at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:61) + at org.hibernate.tool.schema.extract.spi.ExtractionContext.getQueryResults(ExtractionContext.java:41) + at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:36) + at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.initializeSequences(DatabaseInformationImpl.java:73) + at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.(DatabaseInformationImpl.java:63) + at org.hibernate.tool.schema.extract.internal.CachingDatabaseInformationImpl.(CachingDatabaseInformationImpl.java:43) + at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.buildDatabaseInformation(GroupedSchemaMigratorImpl.java:112) + at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:83) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:269) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101) + at java.base/java.util.HashMap.forEach(HashMap.java:1429) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100) + at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35) + at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33) + at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:327) + at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64) + at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1452) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:93) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:443) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:436) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:411) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:419) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1811) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:977) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$2(SpringBootContextLoader.java:155) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1465) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:600) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:155) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:114) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:247) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.lambda$loadContext$0(DefaultCacheAwareContextLoaderDelegate.java:167) + at org.springframework.test.context.cache.DefaultContextCache.put(DefaultContextCache.java:214) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:160) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:128) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:242) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$1(ClassBasedTestDescriptor.java:423) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:428) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$0(ClassBasedTestDescriptor.java:422) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:422) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$0(ClassBasedTestDescriptor.java:334) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:333) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$1(ClassBasedTestDescriptor.java:322) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$0(ClassBasedTestDescriptor.java:321) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:127) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:126) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:70) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$0(NodeTestTask.java:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:144) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:110) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58) + at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) +Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: /opt/projects/RITz-whatsapp-bot/db/whatsappbot.mv.db [2.4.240/7]" [50000-240] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:566) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + ... 157 more +Caused by: org.h2.mvstore.MVStoreException: The file is locked: /opt/projects/RITz-whatsapp-bot/db/whatsappbot.mv.db [2.4.240/7] + at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:996) + at org.h2.mvstore.SingleFileStore.lockFileChannel(SingleFileStore.java:143) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:117) + at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:81) + at org.h2.mvstore.MVStore.(MVStore.java:291) + ... 151 more diff --git a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java index e505abc..1a63e24 100644 --- a/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java +++ b/src/main/java/com/rit/whatsapp/handler/StudentMenuHandler.java @@ -81,6 +81,7 @@ public class StudentMenuHandler { weeklyBtn.put("id", "student_weekly_timetable"); weeklyBtn.put("title", "Weekly Timetable"); buttons.add(weeklyBtn); + System.out.println("FINAL TODAY TIMETABLE MESSAGE:\n" + todaySchedule); Map buttonMessage = WhatsAppMessageBuilder.buildButtonMessage(todaySchedule, buttons); messageService.sendInteractiveMessage(phoneNumber, buttonMessage); diff --git a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java index 5f2d4bf..4e83e2f 100644 --- a/src/main/java/com/rit/whatsapp/util/MessageFormatter.java +++ b/src/main/java/com/rit/whatsapp/util/MessageFormatter.java @@ -95,74 +95,136 @@ public class MessageFormatter { return sb.toString(); } - public static String formatTimetable(String rawJson) { + private static class TimetableEntry { + String subjectName; + String subjectCode; + String staffName; + String staffCode; + + public TimetableEntry(String subjectName, String subjectCode, String staffName, String staffCode) { + this.subjectName = subjectName != null ? subjectName.trim() : ""; + this.subjectCode = subjectCode != null ? subjectCode.trim() : ""; + this.staffName = staffName != null ? staffName.trim() : ""; + this.staffCode = staffCode != null ? staffCode.trim() : ""; + } + + public boolean isValid() { + return !subjectName.isEmpty() && !subjectCode.isEmpty(); + } + + public String getUniqueKey() { + return subjectName + "||" + subjectCode; + } + } + + public static String formatTodayTimetable(String rawJson) { + String day = java.time.LocalDate.now() + .getDayOfWeek() + .getDisplayName(java.time.format.TextStyle.FULL, java.util.Locale.ENGLISH) + .toLowerCase(java.util.Locale.ROOT); + return formatTodayTimetableForDay(rawJson, day); + } + + public static String formatTodayTimetableForDay(String rawJson, String day) { if (rawJson == null) return "❌ Failed to retrieve timetable data."; try { JsonNode root = mapper.readTree(rawJson); + if (!root.has("data") || !root.get("data").isObject() || !root.get("data").has("schedule")) { + return "❌ Timetable details not available in this format."; + } + + JsonNode schedule = root.get("data").get("schedule"); + + System.out.println("TIMETABLE DEBUG"); + System.out.println("Current day: " + day.toUpperCase()); + System.out.println("Normalized day: " + day); + boolean hasSchedule = schedule.has(day); + System.out.println("Schedule found: " + hasSchedule); + StringBuilder sb = new StringBuilder(); - sb.append("\ud83d\uddd3\ufe0f *Today's Classes*\n\n"); + sb.append("📅 *Today's Classes*\n"); + sb.append("━━━━━━━━━━━━━━\n\n"); - boolean validFormat = false; - boolean hasClassesToday = false; - - if (root.has("data") && root.get("data").isObject() && root.get("data").has("schedule")) { - validFormat = true; - JsonNode schedule = root.get("data").get("schedule"); + if (hasSchedule) { + JsonNode daySchedule = schedule.get(day); - String today = java.time.LocalDate.now().getDayOfWeek().toString().toLowerCase(); + int maxPeriod = 7; + java.util.Iterator fieldNames = daySchedule.fieldNames(); + java.util.List foundPeriods = new java.util.ArrayList<>(); + while (fieldNames.hasNext()) { + String fName = fieldNames.next(); + foundPeriods.add(fName); + try { + int p = Integer.parseInt(fName); + if (p > maxPeriod) { + maxPeriod = p; + } + } catch (NumberFormatException e) {} + } + System.out.println("Periods found: [" + String.join(", ", foundPeriods) + "]"); - if (schedule.has(today)) { - JsonNode todaySchedule = schedule.get(today); + for (int period = 1; period <= maxPeriod; period++) { + String periodKey = String.valueOf(period); + sb.append(getNumberEmoji(period)).append(" "); - if (todaySchedule.isObject() && todaySchedule.size() > 0) { - java.util.Iterator> fields = todaySchedule.fields(); - while (fields.hasNext()) { - java.util.Map.Entry field = fields.next(); - String timeOrPeriod = field.getKey(); - JsonNode details = field.getValue(); - - if (details.isObject()) { - String course = details.has("course_name") ? details.get("course_name").asText() : - (details.has("name") ? details.get("name").asText() : "Unknown"); - String room = details.has("room") ? details.get("room").asText() : ""; - - sb.append("*").append(timeOrPeriod).append(":* ").append(course); - if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")"); - sb.append("\n"); - } else { - sb.append("*").append(timeOrPeriod).append(":* ").append(details.asText()).append("\n"); + if (daySchedule.has(periodKey)) { + JsonNode periodNode = daySchedule.get(periodKey); + java.util.List entries = new java.util.ArrayList<>(); + + if (periodNode.isArray()) { + for (JsonNode node : periodNode) { + String sName = node.has("subjectName") ? node.get("subjectName").asText() : ""; + String sCode = node.has("subjectCode") ? node.get("subjectCode").asText() : ""; + String stName = node.has("staffName") ? node.get("staffName").asText() : ""; + String stCode = node.has("staffCode") ? node.get("staffCode").asText() : ""; + entries.add(new TimetableEntry(sName, sCode, stName, stCode)); } - hasClassesToday = true; } - } else if (todaySchedule.isArray() && todaySchedule.size() > 0) { - for (JsonNode details : todaySchedule) { - String time = details.has("time") ? details.get("time").asText() : "TBA"; - String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown"; - String room = details.has("room") ? details.get("room").asText() : ""; - - sb.append("*").append(time).append(":* ").append(course); - if (!room.isEmpty()) sb.append(" (Room ").append(room).append(")"); - sb.append("\n"); - hasClassesToday = true; + + System.out.println("Period " + period + " entries: " + entries.size()); + if (!entries.isEmpty()) { + TimetableEntry first = entries.get(0); + System.out.println("Period " + period + " first subjectName: " + first.subjectName); + System.out.println("Period " + period + " first subjectCode: " + first.subjectCode); } + + java.util.Map uniqueMap = new java.util.LinkedHashMap<>(); + for (TimetableEntry entry : entries) { + if (entry.isValid()) { + uniqueMap.putIfAbsent(entry.getUniqueKey(), entry); + } + } + + if (!uniqueMap.isEmpty()) { + java.util.List formattedSubjects = new java.util.ArrayList<>(); + for (TimetableEntry entry : uniqueMap.values()) { + formattedSubjects.add("*" + entry.subjectName + "*\n `" + entry.subjectCode + "`"); + } + sb.append(String.join(" / ", formattedSubjects)).append("\n\n"); + } else { + sb.append("*Free Period*\n\n"); + } + } else { + sb.append("*Free Period*\n\n"); } } + } else { + sb.append("No classes scheduled for today.\n\n"); } - if (validFormat && !hasClassesToday) { - sb.append("No classes scheduled for today.\n"); - } else if (!validFormat) { - sb.append("Details not available in this format.\n"); - sb.append("\n\n*DEBUG RAW JSON:*\n").append(rawJson); - } - + sb.append("━━━━━━━━━━━━━━"); return sb.toString(); } catch (Exception e) { - return "⚠️ Error formatting timetable data.\nRAW JSON: " + rawJson; + System.err.println("Error formatting today's timetable: " + e.getMessage()); + return "⚠️ Error formatting timetable data."; } } + public static String formatTimetable(String rawJson) { + return formatTodayTimetable(rawJson); + } + public static String formatResults(String rawJson, int semester) { if (rawJson == null) return "❌ Failed to retrieve semester results."; @@ -444,76 +506,105 @@ public class MessageFormatter { return rows; } + private static String getNumberEmoji(int num) { + switch (num) { + case 1: return "1️⃣"; + case 2: return "2️⃣"; + case 3: return "3️⃣"; + case 4: return "4️⃣"; + case 5: return "5️⃣"; + case 6: return "6️⃣"; + case 7: return "7️⃣"; + case 8: return "8️⃣"; + case 9: return "9️⃣"; + default: return num + "️⃣"; + } + } + public static String formatWeeklyTimetable(String rawJson) { if (rawJson == null) return "❌ Failed to retrieve weekly timetable data."; try { JsonNode root = mapper.readTree(rawJson); - if (!root.has("data") || !root.get("data").isObject() || !root.get("data").has("schedule")) { return "❌ Weekly timetable details not available in the response."; } JsonNode schedule = root.get("data").get("schedule"); StringBuilder sb = new StringBuilder(); - sb.append("📅 *Weekly Class Timetable*\n\n"); - sb.append("```\n"); - sb.append(String.format("%-3s | %-11s | %s\n", "Day", "Time/Period", "Subject (Room)")); - sb.append("----+-------------+------------------------\n"); + sb.append("📚 WEEKLY TIMETABLE\n\n"); - String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}; - String[] dayAbbrevs = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday", "saturday"}; + String[] dayLabels = {"MON", "TUE", "WED", "THU", "FRI", "SAT"}; boolean hasAnyClasses = false; for (int i = 0; i < days.length; i++) { String day = days[i]; - String abbrev = dayAbbrevs[i]; + String label = dayLabels[i]; if (schedule.has(day)) { JsonNode daySchedule = schedule.get(day); - if (daySchedule.isObject() && daySchedule.size() > 0) { - java.util.Iterator> fields = daySchedule.fields(); - while (fields.hasNext()) { - java.util.Map.Entry field = fields.next(); - String timeOrPeriod = field.getKey(); - JsonNode details = field.getValue(); + sb.append(label).append("\n"); + + int maxPeriod = 7; + java.util.Iterator fieldNames = daySchedule.fieldNames(); + while (fieldNames.hasNext()) { + try { + int p = Integer.parseInt(fieldNames.next()); + if (p > maxPeriod) { + maxPeriod = p; + } + } catch (NumberFormatException e) {} + } + + for (int period = 1; period <= maxPeriod; period++) { + String periodKey = String.valueOf(period); + sb.append(getNumberEmoji(period)).append(" "); + + if (daySchedule.has(periodKey)) { + JsonNode details = daySchedule.get(periodKey); + java.util.Set subjects = new java.util.LinkedHashSet<>(); - String course = ""; - String room = ""; - if (details.isObject()) { - course = details.has("course_name") ? details.get("course_name").asText() : - (details.has("name") ? details.get("name").asText() : "Unknown"); - room = details.has("room") ? details.get("room").asText() : ""; - } else { - course = details.asText(); + if (details.isArray()) { + for (JsonNode entry : details) { + String name = entry.has("subjectName") ? entry.get("subjectName").asText() : ""; + String code = entry.has("subjectCode") ? entry.get("subjectCode").asText() : ""; + if (!name.trim().isEmpty()) { + subjects.add(name.trim() + " — " + code.trim()); + } + } + } else if (details.isObject()) { + String name = details.has("course_name") ? details.get("course_name").asText() : + (details.has("name") ? details.get("name").asText() : + (details.has("subjectName") ? details.get("subjectName").asText() : "")); + String code = details.has("course_code") ? details.get("course_code").asText() : + (details.has("code") ? details.get("code").asText() : + (details.has("subjectCode") ? details.get("subjectCode").asText() : "")); + if (!name.trim().isEmpty()) { + subjects.add(name.trim() + " — " + code.trim()); + } } - String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")"; - sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(timeOrPeriod, 11), subjectRoom)); - hasAnyClasses = true; - } - } else if (daySchedule.isArray() && daySchedule.size() > 0) { - for (JsonNode details : daySchedule) { - String time = details.has("time") ? details.get("time").asText() : "TBA"; - String course = details.has("course_name") ? details.get("course_name").asText() : "Unknown"; - String room = details.has("room") ? details.get("room").asText() : ""; - - String subjectRoom = room.isEmpty() ? course : course + " (" + room + ")"; - sb.append(String.format("%-3s | %-11s | %s\n", abbrev, truncate(time, 11), subjectRoom)); - hasAnyClasses = true; + if (!subjects.isEmpty()) { + sb.append(String.join(" / ", subjects)).append("\n"); + hasAnyClasses = true; + } else { + sb.append("—\n"); + } + } else { + sb.append("—\n"); } } + sb.append("\n"); } } - sb.append("```"); - if (!hasAnyClasses) { - return "📅 *Weekly Class Timetable*\n\nNo classes scheduled for this week."; + return "📚 WEEKLY TIMETABLE\n\nNo classes scheduled for this week."; } - return sb.toString(); + return sb.toString().trim(); } catch (Exception e) { return "⚠️ Error formatting weekly timetable data."; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5f14489..700cd92 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -19,4 +19,4 @@ spring.h2.console.enabled=true # Encryption Secret for Passcodes (Must be 16, 24, or 32 bytes) bot.encryption.secret=12345678901234567890123456789012 -whatsapp.api-token=EAAc3Wjql00oBSdoBhXozC8gKyWN9Il6cqpjvE531hZAnuFqOfHCuCBGt8hYZCICzm2dnXsH2RR3HIi3dpZAZBbNFE9Xj8Hvs3TS94nHrmxevicgThlqSQDjZCDm6SS1qFvt7NwRjiy1TWtZCuLLvcTxyjjNPUtjt91OZBr5DtddHzESLezP6R3oJEzIhSjLqlRAvNwfhW8wDYiCkkx0Qw69iO2UeodHw5E8Q86kZCPEvocldDZCyb7qZCMZAELPbYJYkWVLk8MjVyZAXjmnoGFnS5n4ZAsXBE +whatsapp.api-token=EAAc3Wjql00oBSUjYhQ1TZBiNJNmwNlpktCtJpqSLXycDVjWjPiP5dBWHvvFX2Deq1tGXQO2jgVOGChnJk9jsMxLVdxvUs4z7g7xlfcQtAPYiHwvQbPVSbGTTCBvjv2IvHf7Ql2iNBKL72GZCrxAJrQpmjHUG5sbQkVWmMpNfwgI52iDBw0BifU1QhQHFEOnQfiPu19KUp3hJOg6XkUbbXyfBKvbSkZB57xj0XHMv6wgpqDrQwAACOjSlSPrNEC3eZB9DbZAqWYnPkJCsX99Pz3GhA diff --git a/src/test/java/com/rit/whatsapp/WhatsappBotApplicationTests.java b/src/test/java/com/rit/whatsapp/WhatsappBotApplicationTests.java index 5bdaf10..2959ede 100644 --- a/src/test/java/com/rit/whatsapp/WhatsappBotApplicationTests.java +++ b/src/test/java/com/rit/whatsapp/WhatsappBotApplicationTests.java @@ -10,4 +10,46 @@ class WhatsappBotApplicationTests { void contextLoads() { } + @Test + void testFormatTodayTimetableThursday() { + String thursdayJson = "{\n" + + " \"success\": true,\n" + + " \"data\": {\n" + + " \"schedule\": {\n" + + " \"thursday\": {\n" + + " \"1\": [{\"subjectName\":\"Business Analytics\",\"subjectCode\":\"CB23531\",\"staffName\":\"FOUZIA SULTHANA K.\",\"staffCode\":\"CS84\"}],\n" + + " \"2\": [{\"subjectName\":\"Computer Networks\",\"subjectCode\":\"CS23511\",\"staffName\":\"SELVAKUMARAN S.\",\"staffCode\":\"CS91\"}],\n" + + " \"3\": [\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"DIVYA S\",\"staffCode\":\"CS193\"},\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"SARANYA S.\",\"staffCode\":\"CS85\"},\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"},\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"SANDHIYARAJESHWARI K\",\"staffCode\":\"CS153\"},\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"MONIKAA R\",\"staffCode\":\"CS178\"},\n" + + " {\"subjectName\":\"Deep Learning\",\"subjectCode\":\"AD23511\",\"staffName\":\"ARTHI A.\",\"staffCode\":\"CS87\"}\n" + + " ],\n" + + " \"4\": [{\"subjectName\":\"Image and Video Analytics\",\"subjectCode\":\"AD23V15\",\"staffName\":\"JOEL J\",\"staffCode\":\"CS226\"}],\n" + + " \"5\": [{\"subjectName\":\"Big Data Analytics\",\"subjectCode\":\"AD23V12\",\"staffName\":\"KAVITHA V\",\"staffCode\":\"CS253\"}],\n" + + " \"6\": [\n" + + " {\"subjectName\":\"Data Exploration and Visualization\",\"subjectCode\":\"AD23532\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"},\n" + + " {\"subjectName\":\"Data Exploration and Visualization\",\"subjectCode\":\"AD23532\",\"staffName\":\"DR.VIDHYA M\",\"staffCode\":\"CS256\"}\n" + + " ],\n" + + " \"7\": [{\"subjectName\":\"\",\"subjectCode\":\"\",\"staffName\":\"FOUZIA SULTHANA K.\",\"staffCode\":\"CS84\"}]\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + String formatted = com.rit.whatsapp.util.MessageFormatter.formatTodayTimetableForDay(thursdayJson, "thursday"); + System.out.println("Formatted output:\n" + formatted); + + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("📅 *Today's Classes*")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("1️⃣ *Business Analytics*\n `CB23531`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("2️⃣ *Computer Networks*\n `CS23511`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("3️⃣ *Deep Learning*\n `AD23511`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("4️⃣ *Image and Video Analytics*\n `AD23V15`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("5️⃣ *Big Data Analytics*\n `AD23V12`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("6️⃣ *Data Exploration and Visualization*\n `AD23532`")); + org.junit.jupiter.api.Assertions.assertTrue(formatted.contains("7️⃣ *Free Period*")); + } + }