From 55bc9baa307703c997877aaf9a7409e6a8c70e95 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 24 Oct 2026 20:04:02 +0300 Subject: [PATCH 1/2] Samples: store entity timestamps as java.time.Instant Restores the demo conversion held back from #6094, for the release that maps java.time entity fields, and resyncs the Initializr templates. Co-Authored-By: Claude Opus 5.5 --- .../src/main/resources/parley-modules.zip | Bin 613584 -> 617266 bytes .../src/main/resources/savor-modules.zip | Bin 3132552 -> 3137361 bytes .../src/main/resources/skirmish-modules.zip | Bin 676839 -> 679147 bytes .../src/main/resources/wayline-modules.zip | Bin 960206 -> 963412 bytes .../com/codenameone/examples/parley/Rows.java | 13 ++++- .../parley/account/AccountCleanup.java | 3 +- .../examples/parley/account/Accounts.java | 5 +- .../examples/parley/account/Moderation.java | 9 ++-- .../parley/account/PhoneVerification.java | 23 ++++----- .../examples/parley/admin/Statistics.java | 17 +++---- .../examples/parley/bridge/Bridges.java | 9 ++-- .../examples/parley/call/Calls.java | 21 ++++---- .../examples/parley/chat/Conversations.java | 25 +++++----- .../examples/parley/chat/Fanout.java | 11 +++-- .../examples/parley/chat/Media.java | 5 +- .../examples/parley/chat/Messages.java | 19 ++++---- .../examples/parley/contact/Contacts.java | 13 ++--- .../examples/parley/device/Devices.java | 13 ++--- .../examples/parley/domain/BridgeEvent.java | 9 ++-- .../examples/parley/domain/BridgeLink.java | 7 +-- .../examples/parley/domain/CallRecord.java | 19 ++++---- .../examples/parley/domain/ClosedAccount.java | 7 +-- .../examples/parley/domain/ContactBlock.java | 7 +-- .../examples/parley/domain/Conversation.java | 13 ++--- .../parley/domain/ConversationPhoto.java | 7 +-- .../examples/parley/domain/Device.java | 13 ++--- .../examples/parley/domain/Envelope.java | 13 ++--- .../examples/parley/domain/InviteLink.java | 13 ++--- .../examples/parley/domain/LiveTicket.java | 7 +-- .../examples/parley/domain/MediaBlob.java | 7 +-- .../examples/parley/domain/Membership.java | 7 +-- .../examples/parley/domain/MessageLog.java | 7 +-- .../parley/domain/ModerationEvent.java | 7 +-- .../examples/parley/domain/PhoneCode.java | 19 ++++---- .../examples/parley/domain/Profile.java | 13 ++--- .../examples/parley/domain/ProfilePhoto.java | 7 +-- .../examples/parley/domain/PushDevice.java | 7 +-- .../examples/parley/domain/Report.java | 7 +-- .../examples/parley/live/LiveTickets.java | 7 +-- .../examples/parley/push/PushDevices.java | 5 +- .../repository/BridgeEventRepository.java | 3 +- .../repository/CallRecordRepository.java | 13 ++--- .../repository/ConversationRepository.java | 3 +- .../parley/repository/DeviceRepository.java | 3 +- .../parley/repository/EnvelopeRepository.java | 7 +-- .../repository/LiveTicketRepository.java | 3 +- .../repository/MediaBlobRepository.java | 5 +- .../repository/MessageLogRepository.java | 7 +-- .../repository/ModerationEventRepository.java | 3 +- .../parley/repository/ProfileRepository.java | 5 +- .../com/codenameone/examples/savor/Rows.java | 8 ++++ .../savor/account/AccountCleanup.java | 3 +- .../examples/savor/account/Accounts.java | 5 +- .../examples/savor/account/DemoAccounts.java | 9 ++-- .../examples/savor/account/Moderation.java | 12 +++-- .../savor/account/PhoneVerification.java | 21 ++++---- .../examples/savor/admin/Statistics.java | 19 ++++---- .../examples/savor/catalog/Catalog.java | 3 +- .../savor/catalog/DemoRestaurants.java | 13 ++--- .../examples/savor/catalog/Restaurants.java | 29 +++++------ .../examples/savor/courier/Couriers.java | 11 +++-- .../examples/savor/courier/Earnings.java | 11 +++-- .../examples/savor/delivery/Deliveries.java | 40 ++++++++-------- .../examples/savor/delivery/Matcher.java | 3 +- .../examples/savor/domain/ClosedAccount.java | 7 +-- .../savor/domain/CourierApplication.java | 19 ++++---- .../savor/domain/CourierDocument.java | 7 +-- .../examples/savor/domain/CourierState.java | 7 +-- .../examples/savor/domain/CustomerOrder.java | 31 ++++++------ .../examples/savor/domain/Delivery.java | 25 +++++----- .../savor/domain/DeliveryActivity.java | 13 ++--- .../examples/savor/domain/DeliveryEvent.java | 7 +-- .../examples/savor/domain/Favorite.java | 7 +-- .../examples/savor/domain/LiveTicket.java | 7 +-- .../savor/domain/ModerationEvent.java | 7 +-- .../examples/savor/domain/OrderEvent.java | 7 +-- .../examples/savor/domain/Payment.java | 13 ++--- .../examples/savor/domain/PaymentMethod.java | 7 +-- .../examples/savor/domain/PaymentSetup.java | 7 +-- .../examples/savor/domain/Payout.java | 7 +-- .../examples/savor/domain/PhoneCode.java | 19 ++++---- .../examples/savor/domain/Photo.java | 7 +-- .../examples/savor/domain/Pricing.java | 7 +-- .../examples/savor/domain/Profile.java | 7 +-- .../examples/savor/domain/Promo.java | 7 +-- .../examples/savor/domain/PushDevice.java | 7 +-- .../examples/savor/domain/Restaurant.java | 13 ++--- .../examples/savor/domain/SavedAddress.java | 7 +-- .../examples/savor/live/LiveTickets.java | 7 +-- .../savor/onboarding/Applications.java | 23 ++++----- .../examples/savor/order/Addresses.java | 3 +- .../examples/savor/order/DemoKitchen.java | 7 +-- .../examples/savor/order/DemoOrders.java | 27 ++++++----- .../examples/savor/order/OrderEvents.java | 3 +- .../examples/savor/order/Orders.java | 30 ++++++------ .../examples/savor/order/Promos.java | 3 +- .../examples/savor/order/Quotes.java | 5 +- .../examples/savor/pay/Payments.java | 38 ++++++++------- .../examples/savor/push/OrderPushes.java | 21 ++++---- .../examples/savor/push/PushDevices.java | 5 +- .../CourierApplicationRepository.java | 7 +-- .../repository/CourierDocumentRepository.java | 3 +- .../repository/CourierStateRepository.java | 5 +- .../repository/CustomerOrderRepository.java | 35 +++++++------- .../DeliveryActivityRepository.java | 21 ++++---- .../repository/DeliveryEventRepository.java | 3 +- .../savor/repository/DeliveryRepository.java | 41 ++++++++-------- .../repository/LiveTicketRepository.java | 3 +- .../repository/ModerationEventRepository.java | 3 +- .../repository/PaymentMethodRepository.java | 3 +- .../savor/repository/PaymentRepository.java | 3 +- .../repository/PaymentSetupRepository.java | 5 +- .../savor/repository/PricingRepository.java | 3 +- .../savor/repository/ProfileRepository.java | 3 +- .../examples/skirmish/account/Accounts.java | 5 +- .../skirmish/admin/AdminEndpoint.java | 5 +- .../examples/skirmish/admin/Flags.java | 5 +- .../examples/skirmish/admin/Moderation.java | 14 +++--- .../examples/skirmish/domain/AdminAction.java | 7 +-- .../examples/skirmish/domain/Broadcast.java | 7 +-- .../examples/skirmish/domain/Flag.java | 7 +-- .../examples/skirmish/domain/ForgeAsset.java | 7 +-- .../examples/skirmish/domain/ForgePack.java | 13 ++--- .../skirmish/domain/ForgePackVersion.java | 7 +-- .../examples/skirmish/domain/GameTicket.java | 7 +-- .../examples/skirmish/domain/MatchRecord.java | 7 +-- .../skirmish/domain/MissionStars.java | 7 +-- .../examples/skirmish/domain/Pipeline.java | 7 +-- .../examples/skirmish/domain/PipelineHit.java | 7 +-- .../examples/skirmish/domain/Profile.java | 19 ++++---- .../examples/skirmish/domain/PushDevice.java | 7 +-- .../examples/skirmish/domain/Referral.java | 13 ++--- .../skirmish/domain/ReferralCode.java | 7 +-- .../examples/skirmish/domain/Spotlight.java | 7 +-- .../skirmish/domain/StorePurchase.java | 7 +-- .../examples/skirmish/forge/Forge.java | 25 +++++----- .../examples/skirmish/game/GameEndpoint.java | 4 +- .../examples/skirmish/game/GameTickets.java | 9 ++-- .../examples/skirmish/game/Results.java | 5 +- .../examples/skirmish/push/PushDevices.java | 5 +- .../repository/BroadcastRepository.java | 3 +- .../repository/ForgeAssetRepository.java | 3 +- .../repository/GameTicketRepository.java | 3 +- .../repository/MatchRecordRepository.java | 5 +- .../repository/ProfileRepository.java | 10 ++-- .../repository/StorePurchaseRepository.java | 3 +- .../examples/skirmish/shop/Shop.java | 3 +- .../examples/skirmish/social/Audience.java | 4 +- .../examples/skirmish/social/Insights.java | 21 ++++---- .../examples/skirmish/social/Pipelines.java | 13 ++--- .../examples/skirmish/social/Promotion.java | 19 ++++---- .../examples/skirmish/social/Referrals.java | 11 +++-- .../examples/wayline/account/Accounts.java | 9 ++-- .../wayline/account/DemoAccounts.java | 11 +++-- .../examples/wayline/account/Moderation.java | 14 +++--- .../wayline/account/PhoneVerification.java | 23 ++++----- .../examples/wayline/admin/Statistics.java | 35 +++++++++----- .../wayline/domain/ClosedAccount.java | 7 +-- .../wayline/domain/DriverApplication.java | 19 ++++---- .../wayline/domain/DriverDocument.java | 7 +-- .../examples/wayline/domain/DriverState.java | 7 +-- .../examples/wayline/domain/LiveTicket.java | 7 +-- .../wayline/domain/ModerationEvent.java | 7 +-- .../examples/wayline/domain/Payment.java | 13 ++--- .../wayline/domain/PaymentMethod.java | 7 +-- .../examples/wayline/domain/PaymentSetup.java | 7 +-- .../examples/wayline/domain/Payout.java | 7 +-- .../examples/wayline/domain/PhoneCode.java | 19 ++++---- .../examples/wayline/domain/Pricing.java | 7 +-- .../examples/wayline/domain/Profile.java | 7 +-- .../examples/wayline/domain/PushDevice.java | 7 +-- .../examples/wayline/domain/Ride.java | 25 +++++----- .../examples/wayline/domain/RideActivity.java | 13 ++--- .../examples/wayline/domain/RideEvent.java | 7 +-- .../examples/wayline/driver/Drivers.java | 15 +++--- .../examples/wayline/driver/Earnings.java | 11 +++-- .../wayline/driving/Applications.java | 24 ++++++---- .../examples/wayline/live/LiveTickets.java | 9 ++-- .../examples/wayline/pay/Payments.java | 34 ++++++------- .../examples/wayline/push/PushDevices.java | 7 +-- .../examples/wayline/push/RidePushes.java | 25 +++++----- .../DriverApplicationRepository.java | 7 +-- .../repository/DriverDocumentRepository.java | 3 +- .../repository/DriverStateRepository.java | 5 +- .../repository/LiveTicketRepository.java | 3 +- .../repository/ModerationEventRepository.java | 3 +- .../repository/PaymentMethodRepository.java | 3 +- .../wayline/repository/PaymentRepository.java | 3 +- .../repository/PaymentSetupRepository.java | 5 +- .../wayline/repository/PricingRepository.java | 3 +- .../wayline/repository/ProfileRepository.java | 3 +- .../repository/RideActivityRepository.java | 20 ++++---- .../repository/RideEventRepository.java | 3 +- .../wayline/repository/RideRepository.java | 43 +++++++++-------- .../examples/wayline/ride/DemoRides.java | 15 +++--- .../examples/wayline/ride/Fares.java | 5 +- .../examples/wayline/ride/Matcher.java | 3 +- .../examples/wayline/ride/Rides.java | 45 ++++++++++-------- 198 files changed, 1158 insertions(+), 917 deletions(-) diff --git a/scripts/initializr/common/src/main/resources/parley-modules.zip b/scripts/initializr/common/src/main/resources/parley-modules.zip index 5cdfc79667b332c94edf15a97dfcb5828bcec71e..064091cef09a979d1e16b6568db72a8c77836af6 100644 GIT binary patch delta 13285 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

bo4&lo7aj+^VhwH2aZ%XRKcIM#>ZVO1X{Fv#m- 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 DX;j5T delta 9747 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 Q#ynfHie-P||1+5X10HYLwg3PC diff --git a/scripts/initializr/common/src/main/resources/savor-modules.zip b/scripts/initializr/common/src/main/resources/savor-modules.zip index f66519b68a529f8c9e53c9133fff11129fa1cd96..c438df29fe5667cc149f08818bc408ea97c7b0ca 100644 GIT binary patch delta 20529 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 delta 15638 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 G;{O55S0ar7 diff --git a/scripts/initializr/common/src/main/resources/skirmish-modules.zip b/scripts/initializr/common/src/main/resources/skirmish-modules.zip index 58e4b92ae447d70d06a892c03503276d1b2d9f54..f01c26c14ca593e3cc87657d68b5ccc6399487df 100644 GIT binary patch delta 10499 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 TzpJt<28c~fnfLH-pP2svh}K$P delta 8083 zcmai33tUvy)<1inede)w%peaD2OKp;5s?r>QCeh8 z@y7n1|9Gco?baiF%>0@i4Plbh5C*#%T89f@PrHBFsiQ;^&ls-83& z>RxYHWl~a0N~b+l9e%2l_*IvEYJ4BQspn9?2Pox1*!#7Fn4SBg_sU-CZ)UPYf&0~R zv|4W=ONrQ|4)-JXe9bpcn63qNkfb0r&rW&?ZO&cwkB}dHbZBi1F&g310i*}->t(nb z5G+Xn!NS(nc4Al?#x3gbcrvWj_VbD4MIPofG|EvruSZXNFZ=W<^ULiKcELPkmslX}AJiS}qn$R!eG9}nwb%~lcxwM&UbeRl>qB|pT>{&4>R@dnGsgoFK6VpRLgB2k2| zmzSQtYm%h9CK$1Sq(kyEL;)YlIeh3K+tuevNrc=c60msz@mDX+ArAHsJsA*AxpnP6 z(%)&aiUMmGuS$A*Xk|M|s%$4hoFB_Hk18o=Pl#|y=ICW)6qgL!*)o1 zg0zDwU)ljoBaPl_&f8>>K`1%1gA6eVC64KErGx~k1K%UXgjdFtp0r|ut){iLEoC%U z;eG%&sb2FdE)lDGb{E;E*StI4TlNqiJ;`mt8Zq86c7eAfEr0@*+y~pI=1}#u4@k2t zJS~}0UNLg61ITXjC=?cu5Vh$biPLROI6{Vq$7jV6a?NLL!;r{Z7*6ez3u`WtRB#x$ z1&$xZ0$lwG;Z!_4Gm7!q83?xv$SZ1E1Bnpfr5VL=Wg2M@uYFF!h1A2JlR-RPIr49Cyz0IXTZwmmX|q$JlauFTmq*mNk2Gvg7kezJqniQ z+^C`=2c(R_ZnWYgQH>%AS!c-vVZzR{0{kubd~(x8uw6Q@_tQN>aX2 zJc$LrU>!VqlLYF|pDQb{`%5`keeO27uD7E$sY%(;)Re|0DGmJYVrtM`AGKd2nW(2` zW@)iQFQ_QtPg%*7`OX&i;CIrXr~A|c-8$&pOj3j^vzl9YA2pM7{=w`gdIVz50$EFC zS>S?+n_=uRvRy>^F+v^sqv2|#fLemo3lw|uLn4%6mW!_*UWyOwQmAM2fqG7%>Hk%i zNhW&dq0aNn4vW5;i@WCH}|D{9k?jWefdZT~?dEPXF~k ze?PNGlFlp=E%<7_IW=?qdv=WMDU`?nQ66oQ*37&>t0X zWI=N=K6nK)sa^dfiPrf&B8srsF|Ej+pdWkUEbQ$*1l1iQs87q8cX$+y_0rG3rUH7O z>%UR(IQ`gH3+B-8TF&rc74(J|*t2jtIDC~E)q+a8K*s@|pWPv&k_J`Z`m<5(vYfV; zVQM`KRf|^9@K7G$w`0!207+UHpcQ4}Itw~~ZW}$|qi#{@s}x3+F&p^qrP1oj1JoGA z?RihJz1Yk4`Z)W%6aVc=YN4v>G|f|>^GP{G#zP)vpQY{9xBuUz5SoQ8B z1Dz^+-=p_sJm@ZhIr#la@{_)LgpT{l_gbR(rJwxGK6CB0H-ghUN>aMIvqAojx^sH* zxV+U8hz6CGOfM?0hvSePY(VW`s6Va0IYnY7Jpa-5WyGX)-I+ zHymSZy~Rw5dS727OVS#3Rsf49YJDJELPgKltgy$h05HX{jxaffS(WIUO!Tu2of?;!T z{nZGzAu!rL#WCGpn1x+0Dm!J|djvAF$b+KOk?OKQ}4&KExIkvfS(`4-q7PWKao9UHNW!CxNk4pB}D79u-2uC2QGf8QVx0xYoA@HKCd9pcb*>x=X0ORJkZSjgSq>&$6EMMzit{qP4vsm3k|&RLn5t zc*J8zhJ0To18N!#7H?6M$jeC|3x&Q)JXkG?3H+8|JBYL>>8Ag~sZLk(znvS3hf=6; z%D#*l;gv_YuljNa<>^-Up|mh%yID8tZn&~p3CBdb&y}9&WolN+uQ-ksc7l>FZNMxwRE~gG0K-R?0(BI5KbIm7Om66jt`99aCtSI`ciP5f*%8ZjQBCB z!Exr#J~6v)oAARu^D6rJHMq@KymskKr5EnF2ouCTFvrq7H+k$yG7<9^k1(F`Hb<7HrKTUXEslpZoDZxT*NS39#;|%C8e7LEPFGtf=R(ZxGxuN zGkon`fyJvvXPfJ?fER`=50Qm?1#Fgqo1jVIfi{oZfCo0M-i5W>+~d6@4flX;{#3wl z*7t@+1CO9b&kD{oBM-H?$LzLI$o)~kaPYRk&qj35HA&+%?P+)5ZGjzcLXqx4xNQ`U zGzr*g6Gp)`*kblPOLm9^Rx{?;J-kZN2oI-XjT&OGHp_Olx#!Zhz@TQc70!C`5IJYR&X4ov9Yfs{ zURy76k2`TW@R2udv zzF5tQ4~+2Tr9bLi?}s|)y{E7F@kF}tV;4|?(sn%3<{BSyg!Ihmpd+oY zjqOn9&zDPpid*C<=@aS?x8$+}wt75#_o1uGim5UA>i z73!KdagdzQg2wNyWau5&hOSO5ga@KOiN6VUrGA-p^pLX}OIV99 zZm`0i363t>2Iv=r!c5Jr*4_%@$@C63_8{y-RTjpeS9?ByPQv$B8mG2BUdgw33nDp~ zceA+Li_>DpMEM%M;8iFKhk`#Oy?*;(t@-RdB~ zRb7|~N<;V{+Rf(Tv=;&J7;ZgOZ4MJyoOOdVYy>rh3(mK_nb-|IY#0q&Pr+Vp!*ekW@%L|4TD>uc6P!T{X4xC=ld)c2q6iWch^je!|o6dt*IHV4GQeF z^BDSKQ7cYW36_JiM`UzH-zmN~(aplwhvg`Ke`k!;Du;{R-R2sqQI}^o?f9GqOM&oZ z%m-?_pk1y3+ujzt{w;wG?TVe(J&m?~{NfI3u)*+#26GRUZDDh-Yp}_o?g_0eVv<#X z&51bre7uDjw4trPoDkKTwJA>V7m?`I4ZG#Jz6zY0jPHJDcjJ%ArxSE4bf{v57b5V< z>5-{e@rEq^wvwO}9Z{I6_`=Zc*g8)S(ODb2^Fi{$OeYl$-r=ZwL5@xxABzG*G=UI~ zYHP{X=mV|${h?>cm?H4Aa3 z-P9A6jhW+S1#8OiU2wV1DvQ8|xP1{UiNxmcQv~+6S62w4uoo7~m1;qJ*^Bq58}|v~ zw?h~zo`m%}5cuw*b$~gVe^0D z5kmm1N<>V06k-na(bx;K?-r@ou3Yy2l~$*O`K-nrAdXbcN9ecEsU> z8RKxVgCMd$a%#(693yP(uXXOFtvI0rFpvCY7smjOHR#Cp0l4+*E3Mce@q8fNw7V7O zt$4KK-Z{as{)#4a9EcUN2Xn0j1UZ4Q45vxhGZ39U-qdPqAI0Pg_CXj-l3{{Vi;SsI zH3&1YZiY^ICt#UY)S0wgC%_8{sQbWPs88U}(vyd@??hOfh?e_Y6ofMj_mCqm#21wt z{LPUtEeT!dk`1eqFasZrhLjAR03nmj7MRfsjcS-?Zhe;Q%NKykWNhgX69sWE8Mi(@ zNf2{WaOLj>g1DW+<7h>xAf6nIN00w(L6j{p`@la3qi#~};wUgF6|K#v5S*`4ard^l zg2+rm=hi$Uh?`5yUT`7}cW<9BIQ`Rcx$8nfRK9@152fRB`Xa&UF$9KNK~stkj4^cy%c6M`u2-5vlOSN)$DJFh-(V2BwF+ps_2cy-NE|hRQe1 z=5@nR((pB6^UPr=DY{xC65z@({uo{MhKpb@J`l@e^T6 z1pUh)!7+T^Vl#}?tf&|4kB(tR9*jiopC1vN8KY46ouh)dG76vFZyQ{M5egs2$8Gd+ z!TH#ShUxQd~!8HYgmyxx8j*vhONC;7mK*D`xO*SN$I~#5#C@Kg- zAV7%<1O*gP4iy``IK<UkWi&AvJ9EJ&)1Cf)tL2zDV{eU~mj)QZ_;w;#GosDiP zoE6k`e0Vaf_?kP=)KDKF{|KOO_Fy+~KK8N-ThH9eI=i(JPF`YzVPmPz+|+A?5!Qak zCDGRt+0%hO%6EIu%BtBg?K>fy9?W8YCmM3=$A%F4bq@P0D>%{gi(Gbfx+jP}vXs3y z-1zWpTmPj47-s1JIDbJAS)`F$*sD4?Sk3$TdWdAF!Q0uToqBl)5EI+8qO7vMZbVsm zd0Aadv2|`;=8P&!cS{!j>Nz5J`0(6(XnmXn(F;e|M}1P9RV}5~%3@n_Zlz_ArG0KH zyEsc?EF3z*hJeLRbaa0UJILq%NeW2$l6}~v5;*iF+bz8P=HZPaY!`?uHHnZgmKSK> zuh>eHF=6Q8&GjaRsW(AlPth^NB2?r_ez5LIQ+KdTAv_drVJ%R7oqYkW|Cc@1=BUQO z1R_L%Z;Zi6BQLWr=v1kWwX$&wU3$VX_Eu4<(c=7bfzVtksu5Ocn{BJJTcYq+eR;X1 zTQ^ITLh4yoH`rEERcnhuezBHxC$eXCxjJ%*!(%Ne7X0jB4}E`TyXzf%A?mO`2sZr8 zUNySfv)Uo5w=S7}@(WwanS0u+va73#N*yK;6B}=-t(x6)hRvQ?WUqp#@5GQMOFtbf z{7MiENGhwUL=4niWsjP=)^5BjDS=_+XDkGm*}?SjYwSy;4a4j62TKH#W~?A8))+x6 z2w9|8bvN>5u?r0mNj{reZL2IUtDGTAl5eZDXWG$J<^JZ|imED$>te=a=Vy=1nx3CM zWYoy4{8&^`W{KTaD{BZ^LrEX_*g*cxM!_y4=^$wpNIx=?4_H5!G}(Ehh75~Mg&H4X z0Y6`2fP=ndY`CViA)~Ug)waMIL^{yHCbC)=;^ypP=MdnM7zB+bG^LqcNN4c>l+`t* z@8@Z+Kq9iL8XOHfn5_#UqSAC>5b3N1(1su~R^NU@sgUubsHeTc2xq|lHU^T;?SMD$ z=Y#3OXwoIw_(5)9^blM%h73>^x@lvi5PEYGY0z36`oj5 z3^Zdld4MQiS~qYp^oP0R3D!}j3+9tB^Q5 zRZ>=NtLy0`#W;j;G<5$WGThg5TG4}x$ZBVU)_O67mMyoqf5%PqOMP8^a);f#T zQd4iMoolgH*3Gun)>+Ez@s_em3-+(s)Cm$7=t7{`!t0%to7k!_NLb72!lGhkSF|IDgD#TdLvH+v~ z^+EKnMzWDLW*>QA@D`3?ws7)>lLiR|91rKlNP)26XRoO6!J{-D8IzZk! z(%lq3xH;vIV1|*Of~L&k6lgw31ZdfTQ}FmYvft94SgA&1uU@?@nUL9E*AY6s$QtO& zKwi^FsSVZItoAk~U3HlB=;DIa)!$c9W^W%D?E==?W|iSO-&WTH)|1}Q_yGx{NgK%l zqq-^vd`j}v!iXP8R)C9{yf``<2KEQk(BADNNd;coPVP|)DKCNxstjn;X&BqO|j@D4`x{G@$^s5Vt@t;4;-=IN9uHigpkrt9Az|K?Od z7QRD9xC*r89kP@)ZhHBh(tC6abB_*MPv{287IdI}RZKlZtgLD!wmH>hwYIw3H9}%exTJS$ZLg=Ly66GG& zw);X~{gf`usr# zxI1>orQmJX+60?#k{q>g=_a{sa0xYIZ6X&8y6q%rZ3`!^mAL*c+}>O+O)?A`pET?! zPS~UJguT(eT9){6CbxmsR~NUl-?_J^9|O4wysI(D7{bNl+cf-NAS17|(Td%haxl=)hjwAMO$MR?IMC zL(ZTX-J=+$dlbFUo9n?s;T}#1xZPLs?ZZvgtG-384L!oT_I(R=acNgDkoV(mF2kuR zDY4bIYo-pY+IF4IT3b{)w$ff!?rr`wF@-BKsb=tG4mZwYRh31CgR+C>H;n6{qP%sY z7>oM(%VFGfwUD06xt*4Ex!gF{7kVX^yJj#poqOg>UmQ$dL0JMFo`W<+3V@t~JB{X# z1>8{bzvg!Oc<$v$m&Py_ZEFXj*T!?V+>505R83XYfqq(cWwGqWhQgLfT%0S9V?oBs z)^lkR7i+jO5Rz}dfDfh95rN5jT%bYk} zNsYzQCEK`@I+I2=I(`S&LJX$T(ib))G0X;w>Xj_kRT&<&X_i}d|U2d$l)rzW0 zduhHLD96$l4{*!W{i|JAEI49N+aa!0D;G43VMFQHhqwaCWq)!Ga$PzJrbR7WR)80L z>jf^+@ahl0Ui%y~qMy@q7r2^stU>NYxSZysnC9GccUZe-LC5>+{`B)~9Y%LE1;Z5% zBh-x5VkZ64qFWy937`#qb@NzH3LqsEQWvm3v~Pdi2+s2xeJVw_-Phc%0BDzRWr!}8 zuFlcz_s+yD{Dq64GjnxjJ><R=cI_ws5+&Kn!=}#2Od-SOTNHV`?j~?+Bq# zRqhigqhd5sl1G?rwQJ2BPM#Hm;oLkDx^5{ZNq--y8^?K#$f65eC-WFJfb^Otn3toq zV{{ERqi*s3W4kfOx!a^1-3_*l)ZEZFbYt``FGe;9uS8ox?vQ)43)JKn zJ$69nr#js9>|tFX+fKfzRnCG{pXWrd9MN}%>3^bwJK>0~#dE*_Q{BO|;5}VZZ$oq4 z)QC?`GR!Bm@v82jJJ^~t6IFXtx31IOuF0xM?wQTb&n_67r_R*GaD4?A*FL)UaGctn zRg}E<*$Dj=(Nki_e7Vt0zsEPB&Ey}duRS5)&>*%SSWJfSlGx|B5>U z`s)CF{GH7=VZXj3{FH`q!kiTSNH+WbOV*gSrs|i4x%O9R7^{zRxeHE{@a)r=?1C|_ zB@hx;i+MC`oPLszrL2RZ zNdxq#h@-5SO!G#4D$!<2Wl=`a_|5u$ymsQy!sqol94x-T1vFLn7vY5$^3IU6IHCpaz3w_!_<>uzhi0@56j#h{k~BEW145(69}|jmZy-2KWO( z9c}~VjL9654U4vMK{RCtY6yooQ^%&fX+o2wR7c0J<0pl>=8$4}-i`0c(uKjkUA!OtWhehN ze+PYB-^*`~&~(*`haj`c>~obPv)EXN5jX7~jp+eDy#Xo;c!{2So!=i~C_B8E3qYWQ7zA z&6&ahXdEmofyNscBdy$n{@~9)@xk7#BWZ^#e61RI(dEDMuj^ei(o%9SG5n{^A#_C!?~X2YG+; z=?2!=JntLi_08U9Vash@&Z2XPQ0&&^1x_&OO<6-HZo7rqJ^7iYC=9bR<8Q0oh3+s4 zz10m4E|`S-O`nz(j|@S_Tz)1f`ohWr7^@{eik(=LL=-9K1o7=Z`acYen(T2A19-VBmw<0j}*Ur z;vGq^_7VE3HVp}BLbxi^$TZ;_Vk&)V=K5za-zz_ke&@moyVOxu<5Rcs>q18k5f-}p zcrsh);^GI_vV~~_wG{Re5n8L{$qh&?{RAfTcr)Tz!hn2R<1p3{l&_2E&77a&)X~0Yhep>YO9I z@2v1mj!>KE+^{V7ISy*$Eg5;%T5Cm2bQ^W!9Vft06OC@H1;Hk*|Z{8IB}a2BkAyag_qnWy=kS;opu`~5S?M)OQT*`ki{?y zXkxz5wT&gJWUMe>RJHNNG@%QK(}WW)3PnnpPM!2PL(#$B{5&2OS&M`ibq>N4#lmb? z9k~!rqisUG>bg6o_T*VYXGkp+d}%|eV0YKGlnV(oW~ShA83IXHG=RI{Uc1nNj;s_0 zyEn@T2P<%EiGL{>&0ZdSk6{h&6T@yz-$V{Tb#+e>uR%Oz|A_TZAWtK)#J=pyNiNzqzB! z`_cr!cx}MCUogY{ZwN;9+Jy$;NRv1~@%iq&k?Ukp8?j<&6=xZcfPcdsHRuO#2#wT)CYo{YbOWr*SkVTxNpA@1kFbUAG+|Eu$c{Q zr{}Q{{u>*wTqeob;Um%Fk8z@zJ{y=h>+Y@$BR@msH9Qs0&ysX>;R#`0Th}12o)q%k zfxg2D?up4gYk6Ia^VY>!Ous_fRxuKq&j=!2^ri5!pmB9D1`MW?E($sR#ufWt99$mH zFy-;E>Z*JMfCCFHvn5}8{a0bK&U=O*&uq$ zBy!zN2R4tWzqFrW~H~FM@zKjX}^-j{#9svG^Mo z>Up_ENkS?P7u3uYL*U0Z1QQ)vDt;S&2j6Yf!(u|1#&^>ME^@cRP!bJd>_`j&3x;QB zIUHF)M>dsSdRTmxbnsdyoJERW>!yywTpw@m82W9l`#xnQ7WuXV`ufUMmD;jmN8Zb0 zu7DgfJDkY{Tg47wUg&Ft!yCn&ewqwZOe|Dy5<|U07)K_hdWg;l2PWzSx?_`=pudB5 zZf+6dU_hl{>LAM}%jKDLYr6@rh#qB3^pk6PTtuP=w~FDMYe!JrZ%0OohHV!U-HS6` z_1PP!E^n)jh>1}BF{`5k4~nBz6d?VzJM^LSJ#jURzJx2k`F$}`-G`j5x~8m&t~e?d zb`0?9prr>aO3`(qKK~ZacxPHxeIuIT);FS$myTunV|RTk;$y(ah>s6GzVxndO$$m5 z>it33K2oZQaNo^im^{Y)w}svJ91D9UkpWOWN*c`V`pR7r;O1AX&$>LxKf--gjbTQ* zYcpHe=YH_4fVbBoBQ%$>G~mV8Ji&NFs{`E1le&}cm?<19;k7}L6`_2zltLC}Dipj8 z#KZ7R5(pKAlE2w~S%_hVYgk85Rx5NhyDx@#_x8jZ8I~d65{Wizu4-twU3gM~xo&Ov z!-vJ#yym8YrozabYK0(JKSlBfQXqwsOM6u^55-6^yYCoyYqH=C4=i3d2sgX00Wi!6 zO>@iMRj|(=Bz|ye4vMBZs@GsMK9sS=X7$t@59038ARasc0pp}uyc>LVS>^}Tum{A(8;omE;KQG%|G64i!%s472;@wVdXx3PD}{F^ zNRejuk*fD#|Mw3WmI-fPB__z3D0SyX@f@uBf@Hv3EGNk%{|NQa@wWb!1v$aJCP|$l z+-HK`dU-n1iF;ngsRwp=&Z8ZT$q7yzp5JwjaG$I(Opd0jW0DcKgQUay$x>K^`^?B& za~CE$ad?6h6`>x*pj)lA`AJqMZrKzmnR|DJi@TNcgZFFE2Jf1RHfX;eGNwvJX7}le zcRxRwDN+S*^P4m*u5D8R1~`15 z6l!*7ti9EJ@qmKG9CkXn`LSFW1TPm!S>((qxsU;UTXcR78)ispa_w1 zcGkO2h4Fw1MF~DAk}cqB1m)V_nVwlMqY>gf+ z)S!@4DX3<_*=r8JCOH_3%;NYD$4oMug4NmJ1nsA73|uuAG`)})a% z*he~gU@@x{Y1X8NG+6%#4=iSj(g@QYIVvsQ{RYZ678*7Eu)upaSvMCusDTb{Wf4R+^11zVZq#KMd;!P79qhbe$J z((r`L!Az44(lGn>9vPbj$Lvy^Sno!r6KpQZ=`M`Hiuf zI%lUUuzC3y{5iyM$H?Bx^vBQ2*c3Ugi#BWGJq^q2XH*zomOmjF9Wy7w9in-!GK(1z z0+R6`5HMit$BpaZC}qNqC@}yg&%w<#I>kx)#~j?>G=Z0<<-dkFa5-@AT&y+XrU*6j zrGa4i8N;L#^Kka2{3d#i!7D6WSRmnrL)Oq89{EiSQ&5xV;e6X6dVG8EPqCBytvl&2 zspNjj9#=3Q(QgK*vcvsUP_qEl2*G@*u8esRc@*`9WzQq2rW-VIc|-I7KdW zhqDXuy58rb3>~4e0aftiLTu?D)75X8WFh`^`C}hhER{Fr9?ze*Re%pobMJ zaOdB*MWH-v)=U-F`g{#nxsvD6qVTT9hr$%&} z&%CTs(#b2kzLlb?r|mGm*NYcM((d_sO_!P{%30qo~+avh4h<9$;gl&?l(8@Cqiy5GNKUISt0 zT5NLV=St!3bvS8`o>2`m&n)eQ3^}a burWuM3$~%q7e^@Mm$pe}{;jsn$^1qA05FZMD^!infN|dY=8{uY#U9-9&R)EgzA~Rnj<76zA?57&1e0le z0#x56NpM-=6nHpT4TP;RTuz1kvo?_3O?rl&-^{fUDsB{rG-ew&rvZ%XD9KQ7pCt?e zzvG%f=hd7{Z+*hewc54CT%+@g3)}@gieckKYgANAS9C%Cl=9S3C9W7(o93<-u5|3S z>fIwVvqx@6=+jGRK+k>2#aJP5pCyuU9D0_Qq2~o|mM%S9Swz(cNHg1`;IHN z+iN28%VX^(lh(2{O?7$q7w!}X`$NsKFwH7Aqe<7fJ%W&la>3o3Tuh=aVg5*uyUdm3 zDt1qDmwQ}E_}he{B3EZuT&640ptjPG1M-U|xTBkEl4ru2TU={%?|jebR^##~N9)>@ zV_iBgIMCD*0#|Nv_n5vf-{v;)4P#wpC6ii>a(hxocuLBmoBQ?)ONt@zrV>)&dRC|$ zB$(mUJ+8(caV77^2dzyet@YRU10_S$FnaGkS4ngW?D(7eTdK1pjCDyt^dup(MMd9Q zamggOxsY#6XDTFzi^Hy~rK{9kTu@j%N)sj5UF=Eq;FdbM`ex*2WTg+y%}C46O3y{Z zw26y@@8@vsA=yH%KqD&&v$~Q|H^}3ur(CeiMnY+xmF(h3Tqaz$k;c%`PV&N0J89YJ z8UBnAu`HN`(Ia-UTp+Gakn#!N0Qyx64mvl8Jgc)nK$ONJ6fW9H5Hh9pLP&qn7aa(f zJwhx!SfB7_SkRaRLrxH}5?3|GOeU@Aho&Q)JeXY7 z56ug3<1Im;r}IgqErO{8?KonzyR21L)I#^6%p0LeG3l!6?pf~1FY`nrl&&u(*9Ca= zfDeG<>=}c-?6-{d^4Ionam?TRQhNtS;`rN z&c}HdI8WgbK02LTVnn)o2AOBLYo|FR(q}HrnL{$oUZ{=I?hx9IZ0r`t&;ld8{I+?FP@l&iCWKF3IXn74zpW8*bDNKZB=bSKGXw6QzM zO?#sYqhcONc+#--@!3h$F7mFXB9Xqdn+zqYF5-mJqLO^P)0o&Wv@x&Hj(f;5!j|r@ z4{HjGfP3$d*7`EEIS_JWm)$)vR`?>hUmCBo>c56Dl36^io9@oc(_>Bf&p zh`>ayIY4?aUXFugK4;(X(Su*Z1(Qi@y&10y`Dy^j_sA~#@h4;u$Ha9{E-fr`m!nCm zKN0G|sjo>RT6PEz9b@~?!?oJmM)-J0{){**)4DHsV-2cejRcpIq$J20t~P+G&&W2W zi^)fbyVhNNEXXVa3kvw=nvH^?^C?n~uKR*)F_!W(R2Kd17+KGmuRWjoMupX6s(@L+ zd{@XBp-MpRk-fC)OOinT+fQ6D>oJL;{k|gIINdv}?vWF;CnnX?(E=y03Bgp`BF}c` zU6P`2oMsk+w&xAw(^t-uUwO-_w(V{Qn@y%*vvx4LK~8}xz>!Pj9eukn;SuuOeVK&v z4&DAEj6ECc)qnRYnPb?!I0d9 zuTL-EA`=XC_z9gwF>JUm+B05iF>VFwL~EHE|1MDDR_#FJdBY1LACdvaBDF52pJO=i zh$L9qVb-4)sP~wh4ATjvWq6cJCX{E?`sCgqKEV*f&k@fu^DX50H2s!yl_M*tUWs1y z8_$2kMo(%lK*3591T`YBz~2JjfgO+pkxy35uRVA$4bZbd^Q^y^W>$sp63?7!LTQ2b z^3gTZlG^I=&q;>kbl{Ckt#$$5TPuqu$M7+t`9|E44+hF6(?Ga+Mo5OLIDS8qdvP1y!Pj0t zOl}X|{|x_ktqpy}jfb3g-eEcZC~3?Nm&vrl1=*?@1G;|^85)jO&6?nsX>|fWSkzCD z**$&&Mn1JS+JCF3RgiAIl940bWwoaBy|dl4 zsiZ;t`%F(^gZa+H&-u!S@H=g~_!#zRw*>8+$3HfX*Z;%6n&@lu8N~(c-Mcf4kFnJ8 zfNH{rKuSIzZSHgNCC^bj+(+s7e7+q=KOW8t#xqgt10MQA0pGpWPQF%W7X&>yigyHA z@}6rmu^`c8DoE5kEV*)wYNPF^@>LSWIKOKU%$z|)nDL>d1szkt7m)~zPg(4O!HLJM z1#_9Tk497_AJ5w{($k}pSPe&Kuj0AjFg8Q`znLpNbzp6zvug+cW^7qufxEm_X?|fr zt`^ip7nBuFbeHL~kyQsRRQJxHTX*s&1^V(H{x~t;Y1ys3Yde#vE6v->Ha5WiXpq7$NpX(0?VCs_!i!AZh!j%704KjDKZ5{r3#oIXqyw%T;gFsPT{ zqSvy7eOkOqcjpKRBFq{f*h#*pVp?%S?Z@lI^3=&G+_De%sI(B2$qP5J5RP=$@0keRQOVA0jYJ|TyJ=!02Q0OIUsZWD? zF|K|+(t2g|dos+X=MM`3Ji7&Nel7%YzTvY2hQ%liD{}H=sLCM%Y}i8rVdPQaOSV%? z6EoVH*Sen1Tz=AIT27Ze7UoErHI0CIktA07qTt38;j$3JuS1e%|u_( z2jS!pF`V9RCf-tf41#8rsnA-iw(*#E=yN2-3tm4VhgD{Aaj+m+biszvB6?G_h>AEM zMnR2BjDVbeqDt3w5=V$Ejgz~GvHu@w9L?$?7I9DHaf*@0HK&i$#0B-)m9%V#*hrVv z);FVHU+>Y$c~Qxs&GW>8R-YYa?z5Qbrb6*TQ{7rZBBqk?`V6$WW&pUlS#;9ti^VzN zf|g>kWJpWWp=6P$&^O-{+Yv3P%6?JFrtPV_J~a}>OQbiX#)G5iVY(7iVoWIpW@U8%q6}!F0Ptn7XNAz|9*tY z^gbQeRk}d*{FpB3Ateax1YPef{mT-LwkavXE5W1PE&Ywh(i2?~xH?ozQ|V97OFs*Y z?YBduQK6RMPfvKuHq>OY4TYh5`6T*sx%7r_!nJ9NG%^SljU}z0Dkv){#oN_g(8WEn zq|B|QR(Qu~`KO<9hc1-b1sen1`lhC3)OuUhLTL+Oc6nim^bBxo6(`gz6q~@sC6ZyV zM@yu5ShigZhFNcm0^}_c?T}KTG=S16qDbd2l{VXbOqQ`;D)Z^iY-+ZEYXPy+tLvpf z^`0Cl%@73W_MQ|#=TPYfsqS)yS3j0kI8fyL5uU<{g`O$B3yX>hVf_pxyrQa)3`;gk z;k0DGv@g`$>+0IMVSy%77;W>7q!38CV0XaC8+#BF+NAs--QZX- zl&@WyC?WHp@T{3xyD7NW-s5 zjbz5X^9^aCWPfS3`e%e{GHLAv@9YR|Vp|Se6QyBr&{*88*DA+MskAYHR6q z%$`uj{ou-!Yv2UIi|6Z+QV^6{Wh;HZzTAzM^&lYM1Ix^Eu>D4ZGw1u`NLzyoylu5-bOPA!MnQEw^ z`O@F`D6wz^mTF*G7d4o6?;v*;nbV^$M8S?ua-jLW1|v_S)lXaMc+h|(d5WQlJ;`!= zGrK8&>n2Aq%LR0o|4l66FPu8}F2Oo<) zY=s@UawA`;rXTx?3mxJHp;Gk*Trar?T%N6lFbC>9R6YtP`pX!Bp+i#p0C@*{@ZkG( zatr$NK$!^kgTLN8>Pk16wANqeK)dA0XAP~S50j@UY*+gWH<;!LAKaG?8>Poq>VQy4mJJ?x@hPk;~KF(C6 zPrR_k=u+%9H#ULjU?bT0dxLzLv#cJz>VN}FZjKIG5Ss+PoUXW_ zW-7l0lK1M{wkk)|EUy^fl9YiGH~m^{)pz&u^3CoX}^05DJ$M%Sxq3!E(=0 zxt`twmq)Q#^F3H>Oo+pOnUMdf+<>MXl9wtP%89X!C{XhWxv!wq7E>zn?}XCDU&(GB zmYk5o;o~nk3uNw*6sY+|mT3GL`ArVa-r<7aE%}_F`Gqt^Ev5*Ya$K+sI`jh;j%wCY-n;3ldx*>OS zSW2(u<@Afi!dWahwhBpmzg3C^I#g6jLs*pITZ*K2>nouxER%?IsAQkXRI(2O&&yq) zs-+^(!Rg9gJ?4Ia&dXG0HDRG@&30aGpN%amX`*rVKu(BEQ6 z*sEA!<`Sj;)A(%pKEJi0fB!6u&iZ9$q}Qek`1*FGF-w&<2rG!_MekVM_W)nr2$vREch-HQF`05qb^kVV2RA|LAT?F{VAGLo{El^O7db2J zD_0#2{63A;%`gUG?eQUJy-O@`<~dx`uR`m`ryFGxhUKd+r(f~a57w)O!LSzF&{hlHi?gIw%?k6T=hj8vV@x?!Xf*?t6sqmXZv`4H5i35;opn{9C%4wSycT7H1!L4Or?>2arI%iQ zi`3s$3zgvE7?h{3aPp*IeD=K#)k-O8+#m=nRuiCPtg65tW7W>waE*`zFOCrum|CR9 za3dMvxe~zvLtetKJp4Gd0awDPFN{;;xpMaVrfEVj6plm09~xq=MxDYf(S9UowT&<~ z{pVsFT+gVTOVmbAze0%Lrmj-&WW6x*EP41Tqr{bAx&FE1LIiw_hX96@suASd6W%cy z_LZs$BPH!~?D3uHSbhB1M9m#Y!{N7sA@pTC7^sV?miZLo8!#AZf$)HHrx`?{V4O_HTh zh?|HTJM2Md{{&;uIYDg`>CNOZoA-CLkmOq2L@fAjpP)X=#}BL{CG+J&jNXcgYRkyF z-2F*s`euxQ3!kJW^F2S8pihjP25Tm%u}*Iai)rj|KkdAFv~r5t6J~uQMO4nklkJzG z`XOBxbtI;$spPAl@b_Y;Uqb2!zJ6T?|2UKcz=c_AXry1N=?9(tz>pME&*qWdj1sfT zVSc#zCYkLBv&<+>RtT7edOjiOO0-e6t&uUel_VH5SB;AF2J{%zclG1e>;!{dnX5)b*2U>h-T)PMG*}P)>4k!piUW(c?B8at zcOyk#2}ATy*g6os>gGRCTlHIc$pXwu#Oj@Pi$>N3_D_m(r-RRgFJ8i1=I~8Lzbh)u zW&slCsh#=QKfDwXY{Xm-vghG~`xLXUM9m&}Q4JZu{W4yZ)f~)zSuMwp)7sAzc=i>1 zkpdO1lLR+H%pnYW{1wFZz>i-VIXbeI+-p9Pw?t@UEVCu!(#z-LU3<7WqgOsw`IAL!$AIeh;)J~*LPan#X1t`?QY%e7oZY)r{leAoaiVR~H zs)^*!;XdRUXH6rCrn$YIvxJ6{ZFHOKp!qrdyutb{V58RPBuHVxege( zSi32T%+O}J8V|b`qcIk~T-TGJ)e^NGzjBj7TDwF|}c8FT4w%~s`V~`GA zH8+6uNFu*9g1F`QR32(&35Kc5ajmD8p{f(p8F|_=jPesoStn!$VsMrNLY5=u`dW?b z;U9LfYH}sO<>l%#{Jdbj$N&hCy`gyXg@o{l(iT$%vuL+)?tu%cP%>esr6cCBI&o05wEXP z<4No$4W0znD!U#2-i_R5uSafw?PTP0>(wqK^c~h2{5rCXevftJPwl~M`DTaw#9y|L z0ZI?qRT#Vhon~i^M(G3#j$tKPm-vSbxW&V{Qalyua z>zl4raK;O7qbk1Ij!PvzV5*4Ofn4W5WSvnKEHhW_z)1~xIIs)leiVQd-CprKah5~Y z$SL61g>m@Wov5aDikH%n3{Y8T(JmbMI!fzIA%mMSVp3cDy9E8csoagMB4Qc&K|BV5 z=yff~opu@}2@0yv{%zaC#wwgWHbMKD1UXOsVDzabx5tc<3|P4{{a{84{QJc diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/Rows.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/Rows.java index 987454aa527..46069737430 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/Rows.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/Rows.java @@ -18,7 +18,7 @@ */ package com.codenameone.examples.parley; - +import java.time.Instant; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,6 +39,17 @@ public static long number(Object value) { return value instanceof Number ? ((Number) value).longValue() : 0L; } + /// A timestamp column as epoch milliseconds. Anything but an `Instant` + /// means the query selected something other than a timestamp, which is + /// a bug to see rather than a zero to chart. + public static long millis(Object value) { + if (value instanceof Instant) { + return ((Instant) value).toEpochMilli(); + } + throw new IllegalStateException("Expected a java.time.Instant column but got " + + (value == null ? "null" : value.getClass().getName())); + } + /// A column as text; empty for null. public static String text(Object value) { return value == null ? "" : String.valueOf(value); diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/AccountCleanup.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/AccountCleanup.java index e505e65c17a..0efb76745b8 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/AccountCleanup.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/AccountCleanup.java @@ -38,6 +38,7 @@ import com.codenameone.examples.parley.repository.ReportRepository; import java.io.IOException; +import java.time.Instant; import java.util.List; /// What closing an account does to the rows other parts of the server keep @@ -118,7 +119,7 @@ public void removeEverythingOf(String username) throws IOException { pushDevices.deleteByUsername(username); // The other side of a live call holds a line too, and nothing else // would ever free it once the call record is gone. - List live = calls.liveOf(username); + List live = calls.liveOf(username, Instant.EPOCH); for (int iter = 0; iter < live.size(); iter++) { lines.deleteByCallId(live.get(iter).getId()); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Accounts.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Accounts.java index b82015a1006..897d74e3be7 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Accounts.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Accounts.java @@ -40,6 +40,7 @@ import com.codenameone.examples.parley.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -156,7 +157,7 @@ void create(String username, String password, String displayName, String phone, profile.setDisplayName(displayName); profile.setPhone(phone); profile.setPhoneVerified(phoneVerified); - profile.setCreatedAt(openedAt); + profile.setCreatedAt(Instant.ofEpochMilli(openedAt)); profile.setLanguage(""); profiles.insert(profile); } @@ -393,7 +394,7 @@ private void retire(String username) throws IOException { if (!closed.existsById(hash)) { ClosedAccount row = new ClosedAccount(); row.setUsernameHash(hash); - row.setClosedAt(System.currentTimeMillis()); + row.setClosedAt(Instant.now()); closed.insert(row); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Moderation.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Moderation.java index 826c2485d4d..3004e49d4ab 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Moderation.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/Moderation.java @@ -26,6 +26,7 @@ import com.codenameone.examples.parley.repository.ModerationEventRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -58,8 +59,8 @@ public void record(String username, String by, String action, String reason) // came with it -- would otherwise be listed in either order. The later // one is stamped after the one before it, so the list is the order in // which things were done. - Long newest = events.newest(username); - long after = newest == null ? 0L : newest.longValue() + 1L; + Instant newest = events.newest(username); + long after = newest == null ? 0L : newest.toEpochMilli() + 1L; record(username, by, action, reason, Math.max(System.currentTimeMillis(), after)); } @@ -72,7 +73,7 @@ public void record(String username, String by, String action, String reason, lon ModerationEvent event = new ModerationEvent(); event.setId(Ids.next()); event.setUsername(username); - event.setCreatedAt(at); + event.setCreatedAt(Instant.ofEpochMilli(at)); event.setActor(by); event.setAction(action); event.setReason(why.length() > 255 ? why.substring(0, 255) : why); @@ -86,7 +87,7 @@ public List events(String username) throws IOException { List out = new ArrayList(); for (int iter = 0; iter < rows.size(); iter++) { ModerationEvent row = rows.get(iter); - out.add(new ModerationEventDto(row.getCreatedAt(), row.getActor(), row.getAction(), + out.add(new ModerationEventDto(row.getCreatedAt().toEpochMilli(), row.getActor(), row.getAction(), row.getReason())); } return out; diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/PhoneVerification.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/PhoneVerification.java index 63106e3db47..8af67ae0050 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/PhoneVerification.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/account/PhoneVerification.java @@ -31,6 +31,7 @@ import com.codenameone.examples.parley.sms.SmsSender; import java.io.IOException; +import java.time.Instant; /// Proves an account's phone number by texting it a code. /// @@ -72,7 +73,7 @@ public PhoneChallengeDto start(String username) throws IOException { UserDto user = accounts.describe(username); String code = newCode(); String codeHash = hash(username, code); - store(username, codeHash, System.currentTimeMillis()); + store(username, codeHash, Instant.now()); try { sms.send(user.phone(), "Your Parley code is " + code); } catch (IOException failed) { @@ -98,20 +99,20 @@ public PhoneChallengeDto start(String username) throws IOException { /// one is kept, so at most two codes are live, and only one whose guesses /// were not used up. @Transactional - void store(String username, String codeHash, long now) throws IOException { + void store(String username, String codeHash, Instant now) throws IOException { // Before the code is read: two requests for one account take turns, // so the second finds the code the first just stored and is told to // wait. Otherwise both pass the check below and both send a text. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending != null && now - pending.getSentAt() < RESEND_SECONDS * 1000L) { + if (pending != null && pending.getSentAt().plusSeconds(RESEND_SECONDS).isAfter(now)) { throw new ResponseStatusException(429, "Wait a moment before asking for another code"); } boolean first = pending == null; if (first) { pending = new PhoneCode(); pending.setUsername(username); - } else if (pending.getExpiresAt() >= now && pending.getAttempts() < MAX_ATTEMPTS) { + } else if (!pending.getExpiresAt().isBefore(now) && pending.getAttempts() < MAX_ATTEMPTS) { // With the guesses it has used: asking for another code must not // buy the old one a fresh set. pending.setPreviousHash(pending.getCodeHash()); @@ -119,11 +120,11 @@ void store(String username, String codeHash, long now) throws IOException { pending.setPreviousAttempts(pending.getAttempts()); } else { pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); } pending.setCodeHash(codeHash); - pending.setExpiresAt(now + CODE_SECONDS * 1000L); + pending.setExpiresAt(now.plusSeconds(CODE_SECONDS)); pending.setAttempts(0); pending.setSentAt(now); if (first) { @@ -148,7 +149,7 @@ void discard(String username, String codeHash) throws IOException { return; } if (pending.getPreviousHash().length() == 0 - || pending.getPreviousExpiresAt() < System.currentTimeMillis()) { + || pending.getPreviousExpiresAt().isBefore(Instant.now())) { codes.deleteById(username); return; } @@ -156,9 +157,9 @@ void discard(String username, String codeHash) throws IOException { pending.setExpiresAt(pending.getPreviousExpiresAt()); pending.setAttempts(pending.getPreviousAttempts()); pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); - pending.setSentAt(0L); + pending.setSentAt(Instant.EPOCH); } /// Checks the code the user typed. Answers 400 for a wrong or expired one @@ -186,7 +187,7 @@ boolean guess(String username, String code) throws IOException { // row the other has. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending == null || pending.getExpiresAt() < System.currentTimeMillis()) { + if (pending == null || pending.getExpiresAt().isBefore(Instant.now())) { throw new ResponseStatusException(400, "That code has expired. Ask for a new one"); } if (pending.getAttempts() >= MAX_ATTEMPTS) { @@ -222,7 +223,7 @@ boolean guess(String username, String code) throws IOException { boolean previous = Crypto.equalsConstantTime(given, pending.getPreviousHash().getBytes("UTF-8")) && pending.getPreviousHash().length() > 0 - && pending.getPreviousExpiresAt() >= System.currentTimeMillis() + && !pending.getPreviousExpiresAt().isBefore(Instant.now()) && counted != null && counted.getPreviousAttempts() <= MAX_ATTEMPTS; if (!current && !previous) { return false; diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/admin/Statistics.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/admin/Statistics.java index 37106cf12a8..3530fd69057 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/admin/Statistics.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/admin/Statistics.java @@ -40,6 +40,7 @@ import com.codenameone.examples.parley.repository.ReportRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -93,8 +94,8 @@ public AdminStatsDto dashboard() throws IOException { (int) conversations.count(), (int) (conversations.countByKind(Conversations.GROUP) + conversations.countByKind(Conversations.CHANNEL)), - (int) messages.countBySentAtGreaterThanEqual(today), - (int) calls.countByStartedAtGreaterThanEqual(today), + (int) messages.countBySentAtGreaterThanEqual(Instant.ofEpochMilli(today)), + (int) calls.countByStartedAtGreaterThanEqual(Instant.ofEpochMilli(today)), (int) reports.countByStatus(OPEN), (int) bridges.count()); } @@ -113,8 +114,8 @@ public StatsSeriesDto series(int days) throws IOException { active.add(new HashSet<>()); } int[] byHour = new int[24]; - for (Object[] row : messages.since(since)) { - long at = Rows.number(row[0]); + for (Object[] row : messages.since(Instant.ofEpochMilli(since))) { + long at = Rows.millis(row[0]); byHour[(int) (at % Days.MILLIS / 3600000L)]++; int index = index(at, since, span); if (index >= 0) { @@ -122,14 +123,14 @@ public StatsSeriesDto series(int days) throws IOException { active.get(index).add(Rows.text(row[1])); } } - for (Long at : calls.startedSince(since)) { - int index = index(Rows.number(at), since, span); + for (Instant at : calls.startedSince(Instant.ofEpochMilli(since))) { + int index = index(Rows.millis(at), since, span); if (index >= 0) { dayCalls[index]++; } } - for (Long at : profiles.signUps(since)) { - int index = index(Rows.number(at), since, span); + for (Instant at : profiles.signUps(Instant.ofEpochMilli(since))) { + int index = index(Rows.millis(at), since, span); if (index >= 0) { dayUsers[index]++; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/bridge/Bridges.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/bridge/Bridges.java index 8e1369fdebf..e592d2c6468 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/bridge/Bridges.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/bridge/Bridges.java @@ -39,6 +39,7 @@ import com.codenameone.examples.parley.repository.MembershipRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -134,7 +135,7 @@ public BridgeLinkDto link(String username, BridgeRequestDto request) throws IOEx link.setExternalChat(chat); link.setLabel(Text.optional(request.label(), 80, "the link's name")); link.setCreatedBy(username); - link.setCreatedAt(System.currentTimeMillis()); + link.setCreatedAt(Instant.now()); links.save(link); conversations.announce(row.getId(), "This conversation is now bridged to " + name(bridge.network()) + ". Messages here are no longer end-to-end encrypted."); @@ -174,8 +175,8 @@ public void incoming(String network, String externalChat, String senderName, Str return; } long now = System.currentTimeMillis(); - events.deleteByReceivedAtLessThan(now - EVENT_MEMORY_MILLIS); - events.insert(new BridgeEvent(key, now)); + events.deleteByReceivedAtLessThan(Instant.ofEpochMilli(now - EVENT_MEMORY_MILLIS)); + events.insert(new BridgeEvent(key, Instant.ofEpochMilli(now))); } BridgeLink link = links.findByNetworkAndExternalChat(network, externalChat); if (link == null) { @@ -232,6 +233,6 @@ static String name(String network) { static BridgeLinkDto toDto(BridgeLink row) { return new BridgeLinkDto(row.getId(), row.getConversationId(), row.getNetwork(), - row.getExternalChat(), row.getLabel(), row.getCreatedAt()); + row.getExternalChat(), row.getLabel(), row.getCreatedAt().toEpochMilli()); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/call/Calls.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/call/Calls.java index 27dee836f85..f22939baf1a 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/call/Calls.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/call/Calls.java @@ -52,6 +52,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; @@ -173,11 +174,11 @@ public CallDto start(String username, CallStartDto request, boolean busy) throws row.setCallee(callee); row.setCalleeDevice(""); row.setVideo(request.video()); - row.setStartedAt(now); + row.setStartedAt(Instant.ofEpochMilli(now)); boolean blocked = blocked(username, callee); if (busy || lines.findById(callee) != null) { row.setState(BUSY); - row.setEndedAt(now); + row.setEndedAt(Instant.ofEpochMilli(now)); } else { row.setState(RINGING); } @@ -235,7 +236,7 @@ public void ring(CallDto call) throws IOException { /// where it learns who is calling and that the call is still live. @Transactional(readOnly = true) public void ringDevice(String username, String device) throws IOException { - for (CallRecord row : calls.liveOf(username)) { + for (CallRecord row : calls.liveOf(username, Instant.EPOCH)) { if (username.equals(row.getCallee()) && RINGING.equals(row.getState()) && !blocked(row.getCaller(), row.getCallee())) { live.toDevice(device, frame(row, "ring")); @@ -262,7 +263,7 @@ public CallDto signal(String username, String id, CallSignalDto signal) throws I if (signal.payload() != null && signal.payload().length() > MAX_PAYLOAD) { throw new ResponseStatusException(413, "That signal is too long"); } - if (row.getEndedAt() != 0) { + if (!row.getEndedAt().equals(Instant.EPOCH)) { // A late candidate for a call that is over is not an error the // app can do anything about. return toDto(row); @@ -291,7 +292,7 @@ public CallDto signal(String username, String id, CallSignalDto signal) throws I remember(row, signal.payload(), false); } else if (ACCEPT.equals(type) && !caller && RINGING.equals(row.getState())) { row.setState(ACCEPTED); - row.setAnsweredAt(now); + row.setAnsweredAt(Instant.ofEpochMilli(now)); row.setCalleeDevice(device); // The callee's other devices are still ringing. String ringId = uuid(row.getId()); @@ -377,14 +378,14 @@ public IceConfigDto ice(String username) { @Transactional(rollbackFor = IOException.class) public void reap() throws IOException { long now = System.currentTimeMillis(); - for (CallRecord row : calls.openSince(now - RING_MILLIS)) { + for (CallRecord row : calls.openSince(Instant.ofEpochMilli(now - RING_MILLIS), Instant.EPOCH)) { if (RINGING.equals(row.getState())) { end(row, MISSED, now); Map frame = frame(row, "signal"); List to = blocked(row.getCaller(), row.getCallee()) ? Arrays.asList(row.getCaller()) : Arrays.asList(row.getCaller(), row.getCallee()); afterCommit(() -> live.toUsers(to, frame)); - } else if (row.getAnsweredAt() < now - STALE_MILLIS) { + } else if (row.getAnsweredAt().toEpochMilli() < now - STALE_MILLIS) { end(row, ENDED, now); // Both apps still hold the call; without this they keep it // open and turn every later call away as busy. @@ -449,7 +450,7 @@ private Map replayed(CallRecord row, String type, String payload private void end(CallRecord row, String state, long now) { boolean ringing = RINGING.equals(row.getState()); row.setState(state); - row.setEndedAt(now); + row.setEndedAt(Instant.ofEpochMilli(now)); lines.deleteByCallId(row.getId()); if (setups.findById(row.getId()) != null) { setups.deleteById(row.getId()); @@ -548,7 +549,7 @@ private static List split(String urls) { static CallDto toDto(CallRecord row) { return new CallDto(row.getId(), row.getConversationId(), row.getCaller(), - row.getCallee(), row.isVideo(), row.getState(), row.getStartedAt(), - row.getAnsweredAt(), row.getEndedAt(), uuid(row.getId())); + row.getCallee(), row.isVideo(), row.getState(), row.getStartedAt().toEpochMilli(), + row.getAnsweredAt().toEpochMilli(), row.getEndedAt().toEpochMilli(), uuid(row.getId())); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Conversations.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Conversations.java index 7df3428193e..f5dcea7ae50 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Conversations.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Conversations.java @@ -51,6 +51,7 @@ import com.codenameone.examples.parley.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -426,7 +427,7 @@ private void depart(Conversation row, Membership mine) throws IOException { for (int iter = 0; iter < rest.size(); iter++) { Membership each = rest.get(iter); if (heir == null || rank(each) > rank(heir) - || rank(each) == rank(heir) && each.getJoinedAt() < heir.getJoinedAt()) { + || rank(each) == rank(heir) && each.getJoinedAt().isBefore(heir.getJoinedAt())) { heir = each; } } @@ -462,8 +463,8 @@ public InviteDto invite(String username, String id) throws IOException { link.setCode(Ids.next()); link.setConversationId(id); link.setCreatedBy(username); - link.setCreatedAt(now); - link.setExpiresAt(now + INVITE_LIFE); + link.setCreatedAt(Instant.ofEpochMilli(now)); + link.setExpiresAt(Instant.ofEpochMilli(now + INVITE_LIFE)); invites.insert(link); return toDto(link, row, members.countByConversationId(id)); } @@ -496,8 +497,8 @@ public ConversationDto join(String username, String code) throws IOException { private InviteLink link(String code) { InviteLink link = code == null ? null : invites.findById(code); - if (link == null || link.getExpiresAt() > 0 - && link.getExpiresAt() < System.currentTimeMillis()) { + if (link == null || link.getExpiresAt().isAfter(Instant.EPOCH) + && link.getExpiresAt().isBefore(Instant.now())) { throw new ResponseStatusException(404, "That invite link does not work any more"); } return link; @@ -519,12 +520,12 @@ public ConversationDto savePhoto(String username, String id, PhotoDto photo) stored = new ConversationPhoto(); stored.setConversationId(id); stored.setContentType(photo.contentType()); - stored.setUpdatedAt(System.currentTimeMillis()); + stored.setUpdatedAt(Instant.now()); stored.setData(data); photos.insert(stored); } else { stored.setContentType(photo.contentType()); - stored.setUpdatedAt(System.currentTimeMillis()); + stored.setUpdatedAt(Instant.now()); stored.setData(data); } row.setHasPhoto(true); @@ -559,8 +560,8 @@ private static Conversation conversation(String kind, String title, String by, l row.setKind(kind); row.setTitle(title); row.setCreatedBy(by); - row.setCreatedAt(now); - row.setLastActivityAt(now); + row.setCreatedAt(Instant.ofEpochMilli(now)); + row.setLastActivityAt(Instant.ofEpochMilli(now)); // direct_key is unique, so it is what keeps two people to one direct // chat even when both start it at once: the second insert fails rather // than splitting their history. Every other conversation has a key of @@ -575,7 +576,7 @@ private void join(String id, String username, String role, long now) { row.setConversationId(id); row.setUsername(username); row.setRole(role); - row.setJoinedAt(now); + row.setJoinedAt(Instant.ofEpochMilli(now)); members.insert(row); } @@ -683,11 +684,11 @@ ConversationDto describe(Conversation row, Membership mine) { return new ConversationDto(row.getId(), row.getKind(), title, row.getAbout(), out, mine.getRole(), mine.isMuted(), mine.isArchived(), mine.isPinned(), row.getDisappearingSeconds(), row.isAdminsOnly(), bridge(row.getId()), - row.getLastActivityAt(), row.isHasPhoto()); + row.getLastActivityAt().toEpochMilli(), row.isHasPhoto()); } private static InviteDto toDto(InviteLink link, Conversation row, long count) { return new InviteDto(link.getCode(), row.getId(), row.getTitle(), (int) count, - link.getExpiresAt()); + link.getExpiresAt().toEpochMilli()); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Fanout.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Fanout.java index b446c6a3c51..628cb1d7694 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Fanout.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Fanout.java @@ -35,6 +35,7 @@ import com.codenameone.examples.parley.domain.Membership; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -176,8 +177,8 @@ static Envelope envelope(String messageId, String conversationId, String sender, row.setKind(kind); row.setHeader(header == null ? "" : header); row.setPayload(payload); - row.setSentAt(sentAt); - row.setExpiresAt(expiresAt); + row.setSentAt(Instant.ofEpochMilli(sentAt)); + row.setExpiresAt(Instant.ofEpochMilli(expiresAt)); return row; } @@ -194,8 +195,8 @@ private void send(List batch) { frame.put("kind", row.getKind()); frame.put("header", row.getHeader()); frame.put("ciphertext", Base64.encode(row.getPayload())); - frame.put("sentAt", Long.valueOf(row.getSentAt())); - frame.put("expiresAt", Long.valueOf(row.getExpiresAt())); + frame.put("sentAt", Long.valueOf(row.getSentAt().toEpochMilli())); + frame.put("expiresAt", Long.valueOf(row.getExpiresAt().toEpochMilli())); live.toDevice(row.getRecipientDevice(), frame); } } @@ -203,6 +204,6 @@ private void send(List batch) { static EnvelopeDto toDto(Envelope row) { return new EnvelopeDto(row.getId(), row.getMessageId(), row.getConversationId(), row.getSender(), row.getSenderDevice(), row.getKind(), row.getHeader(), - Base64.encode(row.getPayload()), row.getSentAt(), row.getExpiresAt()); + Base64.encode(row.getPayload()), row.getSentAt().toEpochMilli(), row.getExpiresAt().toEpochMilli()); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Media.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Media.java index 2bf509e5020..f59ada5dae9 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Media.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Media.java @@ -30,6 +30,7 @@ import com.codenameone.examples.parley.repository.MediaBlobRepository; import java.io.IOException; +import java.time.Instant; /// Encrypted attachments. /// @@ -68,7 +69,7 @@ public MediaRefDto upload(String username, MediaUploadDto media) throws IOExcept // day's bytes are capped as well, well past what anyone sharing // photos and voice notes uploads. long now = System.currentTimeMillis(); - Long stored = blobs.storedSince(username, now - DAY_MILLIS); + Long stored = blobs.storedSince(username, Instant.ofEpochMilli(now - DAY_MILLIS)); if ((stored == null ? 0L : stored.longValue()) + data.length > DAILY_BYTES) { throw new ResponseStatusException(429, "You have uploaded too much today"); } @@ -76,7 +77,7 @@ public MediaRefDto upload(String username, MediaUploadDto media) throws IOExcept row.setId(Ids.next()); row.setOwner(username); row.setSize(data.length); - row.setCreatedAt(now); + row.setCreatedAt(Instant.ofEpochMilli(now)); row.setData(data); blobs.insert(row); return new MediaRefDto(row.getId(), data.length); diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Messages.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Messages.java index c7e0a90bcef..bfc63f12ce1 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Messages.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/chat/Messages.java @@ -49,6 +49,7 @@ import com.codenameone.examples.parley.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.HashMap; @@ -151,7 +152,7 @@ public SendResultDto send(String username, OutgoingDto message) throws IOExcepti logId = Ids.sha256(username + "/" + clientId); MessageLog seen = log.findById(logId); if (seen != null) { - return new SendResultDto(seen.getMessageId(), seen.getSentAt(), + return new SendResultDto(seen.getMessageId(), seen.getSentAt().toEpochMilli(), new ArrayList(), new ArrayList()); } } @@ -236,7 +237,7 @@ public SendResultDto send(String username, OutgoingDto message) throws IOExcepti fanout.deliver(batch, wake, group); if (MESSAGE.equals(kind)) { record(logId, messageId, id, username, kind, now); - conversationRows.touched(id, now); + conversationRows.touched(id, Instant.ofEpochMilli(now)); } return new SendResultDto(messageId, now, missing, stale); } @@ -258,7 +259,7 @@ private SendResultDto sendPlain(String username, OutgoingDto message, Conversati String messageId = fanout.plain(row.getId(), username, message.senderDevice(), MESSAGE, to, text, expiresAt, group); record(logId, messageId, row.getId(), username, kind, now); - conversationRows.touched(row.getId(), now); + conversationRows.touched(row.getId(), Instant.ofEpochMilli(now)); Profile profile = profiles.findById(username); relays.posted(row.getId(), username, profile == null ? username : profile.getDisplayName(), text); @@ -278,7 +279,7 @@ public String post(String conversationId, String sender, String text) throws IOE !Conversations.DIRECT.equals(row.getKind())); record(Ids.sha256(sender + "/" + messageId), messageId, conversationId, sender, MESSAGE, now); - conversationRows.touched(conversationId, now); + conversationRows.touched(conversationId, Instant.ofEpochMilli(now)); return messageId; } @@ -314,10 +315,10 @@ public KeyCountDto ack(String username, String device, AckDto ack) { @Transactional public void reap() { long now = System.currentTimeMillis(); - envelopes.expire(now); - envelopes.deleteBySentAtLessThan(now - UNCLAIMED); - media.deleteByCreatedAtLessThan(now - UNCLAIMED); - log.deleteBySentAtLessThan(now - 90L * 24 * 60 * 60 * 1000); + envelopes.expire(Instant.ofEpochMilli(now), Instant.EPOCH); + envelopes.deleteBySentAtLessThan(Instant.ofEpochMilli(now - UNCLAIMED)); + media.deleteByCreatedAtLessThan(Instant.ofEpochMilli(now - UNCLAIMED)); + log.deleteBySentAtLessThan(Instant.ofEpochMilli(now - 90L * 24 * 60 * 60 * 1000)); } private void record(String logId, String messageId, String conversationId, String sender, @@ -331,7 +332,7 @@ private void record(String logId, String messageId, String conversationId, Strin row.setConversationId(conversationId); row.setSender(sender); row.setKind(kind); - row.setSentAt(now); + row.setSentAt(Instant.ofEpochMilli(now)); log.insert(row); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/contact/Contacts.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/contact/Contacts.java index 5330ec1106a..c17bdd6739f 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/contact/Contacts.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/contact/Contacts.java @@ -45,6 +45,7 @@ import com.codenameone.examples.parley.repository.ReportRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -146,7 +147,7 @@ public ContactDto block(String viewer, String username) throws IOException { row.setId(id); row.setBlocker(viewer); row.setBlocked(username); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); blocks.insert(row); } return view(viewer, profile, peers(viewer)); @@ -185,7 +186,7 @@ public ReportViewDto report(String reporter, ReportDto report) throws IOExceptio row.setConversationId(Text.optional(report.conversationId(), 32, "the conversation")); row.setReason(Text.required(report.reason(), 255, "why you are reporting them")); row.setEvidence(Text.optional(report.evidence(), 4000, "the messages you attach")); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); row.setStatus("OPEN"); reports.insert(row); java.util.Map frame = new java.util.LinkedHashMap(); @@ -217,7 +218,7 @@ private List peers(String username) { public static ReportViewDto toDto(Report row) { return new ReportViewDto(row.getId(), row.getReporter(), row.getSubject(), - row.getConversationId(), row.getReason(), row.getEvidence(), row.getCreatedAt(), + row.getConversationId(), row.getReason(), row.getEvidence(), row.getCreatedAt().toEpochMilli(), row.getStatus()); } @@ -235,12 +236,12 @@ public void savePhoto(String username, PhotoDto photo) throws IOException { row = new ProfilePhoto(); row.setUsername(username); row.setContentType(photo.contentType()); - row.setUpdatedAt(System.currentTimeMillis()); + row.setUpdatedAt(Instant.now()); row.setData(data); photos.insert(row); } else { row.setContentType(photo.contentType()); - row.setUpdatedAt(System.currentTimeMillis()); + row.setUpdatedAt(Instant.now()); row.setData(data); } profile.setHasPhoto(true); @@ -268,7 +269,7 @@ private ContactDto view(String viewer, Profile profile, List peers) boolean reciprocal = mine == null || !NOBODY.equals(mine.getLastSeen()); if (reciprocal && allowed(viewer, profile, theirs == null ? EVERYONE : theirs.getLastSeen(), peers)) { - lastSeen = live.online(username) ? -1L : profile.getLastSeenAt(); + lastSeen = live.online(username) ? -1L : profile.getLastSeenAt().toEpochMilli(); } boolean photo = profile.isHasPhoto() && allowed(viewer, profile, photoSetting(username), peers); diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/device/Devices.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/device/Devices.java index a8dfbc75a8d..6862616a0c3 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/device/Devices.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/device/Devices.java @@ -41,6 +41,7 @@ import com.codenameone.examples.parley.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -109,8 +110,8 @@ public DeviceDto register(String username, DeviceRegistrationDto request) throws row.setSignedPreKeyId(signed.id()); row.setSignedPreKey(signed.publicKey()); row.setSignedPreKeySignature(signed.signature()); - row.setCreatedAt(now); - row.setLastSeenAt(now); + row.setCreatedAt(Instant.ofEpochMilli(now)); + row.setLastSeenAt(Instant.ofEpochMilli(now)); devices.insert(row); store(row.getId(), request.oneTimePreKeys()); return toDto(row); @@ -197,8 +198,8 @@ public boolean owns(String username, String device) { @Transactional public void seen(String username, String device) { long now = System.currentTimeMillis(); - devices.seen(device, now); - profiles.seen(username, now); + devices.seen(device, Instant.ofEpochMilli(now)); + profiles.seen(username, Instant.ofEpochMilli(now)); } /// The device, or a 404 when it is not the caller's: a device of somebody @@ -296,7 +297,7 @@ static String key(String value, String what) { } private static DeviceDto toDto(Device row) { - return new DeviceDto(row.getId(), row.getName(), row.getPlatform(), row.getCreatedAt(), - row.getLastSeenAt()); + return new DeviceDto(row.getId(), row.getName(), row.getPlatform(), row.getCreatedAt().toEpochMilli(), + row.getLastSeenAt().toEpochMilli()); } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeEvent.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeEvent.java index af3e1c5e5d4..8fdc22847f1 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeEvent.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeEvent.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A webhook event already posted, keyed by the network and its own id for /// the event. Telegram and WhatsApp retry a delivery whose answer they did @@ -32,12 +33,12 @@ public class BridgeEvent { private String id = ""; @Column(nullable = false) - private long receivedAt; + private Instant receivedAt = Instant.EPOCH; public BridgeEvent() { } - public BridgeEvent(String id, long receivedAt) { + public BridgeEvent(String id, Instant receivedAt) { this.id = id; this.receivedAt = receivedAt; } @@ -50,11 +51,11 @@ public void setId(String id) { this.id = id; } - public long getReceivedAt() { + public Instant getReceivedAt() { return receivedAt; } - public void setReceivedAt(long receivedAt) { + public void setReceivedAt(Instant receivedAt) { this.receivedAt = receivedAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeLink.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeLink.java index 766ad68ecb6..79737385bf6 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeLink.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/BridgeLink.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A Parley conversation linked to a chat on Telegram or WhatsApp. @Entity @@ -45,7 +46,7 @@ public class BridgeLink { private String createdBy = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public BridgeLink() { } @@ -98,11 +99,11 @@ public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/CallRecord.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/CallRecord.java index a46ab855659..2a86dfb3be8 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/CallRecord.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/CallRecord.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A voice or video call, from ringing to hang-up. @Entity @@ -51,13 +52,13 @@ public class CallRecord { private String state = ""; @Column(nullable = false) - private long startedAt; + private Instant startedAt = Instant.EPOCH; @Column(nullable = false) - private long answeredAt; + private Instant answeredAt = Instant.EPOCH; @Column(nullable = false) - private long endedAt; + private Instant endedAt = Instant.EPOCH; public CallRecord() { } @@ -126,27 +127,27 @@ public void setState(String state) { this.state = state; } - public long getStartedAt() { + public Instant getStartedAt() { return startedAt; } - public void setStartedAt(long startedAt) { + public void setStartedAt(Instant startedAt) { this.startedAt = startedAt; } - public long getAnsweredAt() { + public Instant getAnsweredAt() { return answeredAt; } - public void setAnsweredAt(long answeredAt) { + public void setAnsweredAt(Instant answeredAt) { this.answeredAt = answeredAt; } - public long getEndedAt() { + public Instant getEndedAt() { return endedAt; } - public void setEndedAt(long endedAt) { + public void setEndedAt(Instant endedAt) { this.endedAt = endedAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ClosedAccount.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ClosedAccount.java index 218bcca199d..fe2a48f48da 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ClosedAccount.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ClosedAccount.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What is left of an account that was closed: the hash of its e-mail, kept so /// that the address cannot be registered again. @@ -31,7 +32,7 @@ public class ClosedAccount { private String usernameHash = ""; @Column(nullable = false) - private long closedAt; + private Instant closedAt = Instant.EPOCH; public ClosedAccount() { } @@ -44,11 +45,11 @@ public void setUsernameHash(String usernameHash) { this.usernameHash = usernameHash; } - public long getClosedAt() { + public Instant getClosedAt() { return closedAt; } - public void setClosedAt(long closedAt) { + public void setClosedAt(Instant closedAt) { this.closedAt = closedAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ContactBlock.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ContactBlock.java index d724142d9cd..7530dcda457 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ContactBlock.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ContactBlock.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One account blocking another. @Entity @@ -36,7 +37,7 @@ public class ContactBlock { private String blocked = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public ContactBlock() { } @@ -65,11 +66,11 @@ public void setBlocked(String blocked) { this.blocked = blocked; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Conversation.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Conversation.java index fe392c733ed..c3b0492f6e3 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Conversation.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Conversation.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A direct chat, a group or a channel. @Entity @@ -51,10 +52,10 @@ public class Conversation { private String createdBy = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long lastActivityAt; + private Instant lastActivityAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(400)") private String directKey = ""; @@ -126,19 +127,19 @@ public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getLastActivityAt() { + public Instant getLastActivityAt() { return lastActivityAt; } - public void setLastActivityAt(long lastActivityAt) { + public void setLastActivityAt(Instant lastActivityAt) { this.lastActivityAt = lastActivityAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ConversationPhoto.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ConversationPhoto.java index 42fd1c7283b..585299d0207 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ConversationPhoto.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ConversationPhoto.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A group's photo. @Entity @@ -33,7 +34,7 @@ public class ConversationPhoto { private String contentType = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false) private byte[] data = new byte[0]; @@ -57,11 +58,11 @@ public void setContentType(String contentType) { this.contentType = contentType; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Device.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Device.java index b5ef39ad02b..da2a9fa2240 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Device.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Device.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One device of an account, with the public keys it published. Private keys /// never leave the device; the server hands these out so others can open @@ -53,10 +54,10 @@ public class Device { private String signedPreKeySignature = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long lastSeenAt; + private Instant lastSeenAt = Instant.EPOCH; public Device() { } @@ -125,19 +126,19 @@ public void setSignedPreKeySignature(String signedPreKeySignature) { this.signedPreKeySignature = signedPreKeySignature; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getLastSeenAt() { + public Instant getLastSeenAt() { return lastSeenAt; } - public void setLastSeenAt(long lastSeenAt) { + public void setLastSeenAt(Instant lastSeenAt) { this.lastSeenAt = lastSeenAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Envelope.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Envelope.java index f0ff74365fc..a7c11c43ae5 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Envelope.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Envelope.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One encrypted copy of a message, waiting for one device to fetch it. It is /// deleted when the device acknowledges it, or when its disappearing timer runs @@ -59,10 +60,10 @@ public class Envelope { private byte[] payload = new byte[0]; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public Envelope() { } @@ -147,19 +148,19 @@ public void setPayload(byte[] payload) { this.payload = payload; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/InviteLink.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/InviteLink.java index de7fa5c6e95..77f49fb3036 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/InviteLink.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/InviteLink.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A code that lets whoever holds it join a group. @Entity @@ -36,10 +37,10 @@ public class InviteLink { private String createdBy = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public InviteLink() { } @@ -68,19 +69,19 @@ public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/LiveTicket.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/LiveTicket.java index 4d4f5ce392f..bcc13b8b614 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/LiveTicket.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/LiveTicket.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A ticket for one connection to the live channel, as its hash. @Entity @@ -33,7 +34,7 @@ public class LiveTicket { private String username = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public LiveTicket() { } @@ -54,11 +55,11 @@ public void setUsername(String username) { this.username = username; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MediaBlob.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MediaBlob.java index 78c7fa4154c..a025c07fb59 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MediaBlob.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MediaBlob.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An encrypted attachment. The key is in the message that refers to it. @Entity @@ -36,7 +37,7 @@ public class MediaBlob { private int size; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) private byte[] data = new byte[0]; @@ -68,11 +69,11 @@ public void setSize(int size) { this.size = size; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Membership.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Membership.java index f4b5e9aab52..a9178067f42 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Membership.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Membership.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One account's place in a conversation, and its own view of it. @Entity @@ -48,7 +49,7 @@ public class Membership { private boolean pinned; @Column(nullable = false) - private long joinedAt; + private Instant joinedAt = Instant.EPOCH; public Membership() { } @@ -109,11 +110,11 @@ public void setPinned(boolean pinned) { this.pinned = pinned; } - public long getJoinedAt() { + public Instant getJoinedAt() { return joinedAt; } - public void setJoinedAt(long joinedAt) { + public void setJoinedAt(Instant joinedAt) { this.joinedAt = joinedAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MessageLog.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MessageLog.java index beee8559cde..4e2d8b39705 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MessageLog.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/MessageLog.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// That a message was sent: who, where and when, never what. It makes a /// retried send idempotent and feeds the admin's counts. @@ -43,7 +44,7 @@ public class MessageLog { private String kind = ""; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; public MessageLog() { } @@ -88,11 +89,11 @@ public void setKind(String kind) { this.kind = kind; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ModerationEvent.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ModerationEvent.java index 49fe0e5d86f..17ad2945e5b 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ModerationEvent.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ModerationEvent.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One thing an admin did to an account, and why. Written once, never changed. @Entity @@ -33,7 +34,7 @@ public class ModerationEvent { private String username = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String actor = ""; @@ -63,11 +64,11 @@ public void setUsername(String username) { this.username = username; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PhoneCode.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PhoneCode.java index 4084d725165..b401b05eb4e 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PhoneCode.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PhoneCode.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The verification code an account was last sent, as its hash. @Entity @@ -33,20 +34,20 @@ public class PhoneCode { private String codeHash = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; @Column(nullable = false) private int attempts; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; /// The code sent before this one, while it is still good, or empty. @Column(nullable = false, type = "VARCHAR(64)") private String previousHash = ""; @Column(nullable = false) - private long previousExpiresAt; + private Instant previousExpiresAt = Instant.EPOCH; /// The guesses already taken at the code before, which keeps the budget /// it had rather than starting a new one when another code is sent. @@ -72,11 +73,11 @@ public void setCodeHash(String codeHash) { this.codeHash = codeHash; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } @@ -88,11 +89,11 @@ public void setAttempts(int attempts) { this.attempts = attempts; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } @@ -104,11 +105,11 @@ public void setPreviousHash(String previousHash) { this.previousHash = previousHash; } - public long getPreviousExpiresAt() { + public Instant getPreviousExpiresAt() { return previousExpiresAt; } - public void setPreviousExpiresAt(long previousExpiresAt) { + public void setPreviousExpiresAt(Instant previousExpiresAt) { this.previousExpiresAt = previousExpiresAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Profile.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Profile.java index d0412fa68c5..40dcc9b1bb5 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Profile.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Profile.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's profile: who it is to the people it talks to. /// @@ -48,10 +49,10 @@ public class Profile { private boolean hasPhoto; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long lastSeenAt; + private Instant lastSeenAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(8)") private String language = ""; @@ -113,19 +114,19 @@ public void setHasPhoto(boolean hasPhoto) { this.hasPhoto = hasPhoto; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getLastSeenAt() { + public Instant getLastSeenAt() { return lastSeenAt; } - public void setLastSeenAt(long lastSeenAt) { + public void setLastSeenAt(Instant lastSeenAt) { this.lastSeenAt = lastSeenAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ProfilePhoto.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ProfilePhoto.java index 7853aaba4f5..50289ca95c2 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ProfilePhoto.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/ProfilePhoto.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's profile photo. @Entity @@ -33,7 +34,7 @@ public class ProfilePhoto { private String contentType = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false) private byte[] data = new byte[0]; @@ -57,11 +58,11 @@ public void setContentType(String contentType) { this.contentType = contentType; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PushDevice.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PushDevice.java index 8c5377843d2..7e2d1dbf673 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PushDevice.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/PushDevice.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A device an account is sent push notifications on. /// @@ -46,7 +47,7 @@ public class PushDevice { private String platform = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public PushDevice() { } @@ -91,11 +92,11 @@ public void setPlatform(String platform) { this.platform = platform; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Report.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Report.java index 784c72f5341..2d4cc27c840 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Report.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/domain/Report.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An abuse report, and what the admins did about it. @Entity @@ -45,7 +46,7 @@ public class Report { private String evidence = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(16)") private String status = ""; @@ -107,11 +108,11 @@ public void setEvidence(String evidence) { this.evidence = evidence; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/live/LiveTickets.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/live/LiveTickets.java index 685412bed0f..1fda517193f 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/live/LiveTickets.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/live/LiveTickets.java @@ -28,6 +28,7 @@ import com.codenameone.examples.parley.repository.LiveTicketRepository; import java.io.IOException; +import java.time.Instant; /// Tickets for the live channel. /// @@ -58,7 +59,7 @@ public TicketDto issue(String username) throws IOException { LiveTicket row = new LiveTicket(); row.setTicketHash(Ids.sha256(ticket)); row.setUsername(username); - row.setExpiresAt(System.currentTimeMillis() + TICKET_SECONDS * 1000L); + row.setExpiresAt(Instant.now().plusSeconds(TICKET_SECONDS)); tickets.insert(row); return new TicketDto(ticket, TICKET_SECONDS); } @@ -78,7 +79,7 @@ public String redeem(String ticket) throws IOException { return null; } String username = row.getUsername(); - long expiresAt = row.getExpiresAt(); + long expiresAt = row.getExpiresAt().toEpochMilli(); // One delete statement: the count it answers is what says this // connection, and not another presenting the same ticket, used it. int removed = tickets.deleteByTicketHash(hash); @@ -92,7 +93,7 @@ public String redeem(String ticket) throws IOException { @Scheduled(fixedDelay = 60000, initialDelay = 60000) @Transactional public void sweep() throws IOException { - tickets.deleteByExpiresAtLessThan(System.currentTimeMillis()); + tickets.deleteByExpiresAtLessThan(Instant.now()); } /// Forgets the tickets of an account that is being closed. diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/push/PushDevices.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/push/PushDevices.java index 7cb6d50afc1..84aea8499e5 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/push/PushDevices.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/push/PushDevices.java @@ -30,6 +30,7 @@ import com.codenameone.examples.parley.repository.PushDeviceRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -115,7 +116,7 @@ private void makeRoom(String username) { while (held.size() >= MAX_PER_ACCOUNT) { PushDevice oldest = held.get(0); for (PushDevice each : held) { - if (each.getUpdatedAt() < oldest.getUpdatedAt()) { + if (each.getUpdatedAt().isBefore(oldest.getUpdatedAt())) { oldest = each; } } @@ -168,7 +169,7 @@ private List targetsOf(String username, boolean voip) { private static void fill(PushDevice row, String username, PushDeviceDto device, long now) { row.setUsername(username); row.setPlatform(Text.optional(device.platform(), 32, "the platform")); - row.setUpdatedAt(now); + row.setUpdatedAt(Instant.ofEpochMilli(now)); } /// The device as a target of the push service, which also spells its diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/BridgeEventRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/BridgeEventRepository.java index 3188205f617..47cd4578f6f 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/BridgeEventRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/BridgeEventRepository.java @@ -21,9 +21,10 @@ import com.codename1.orm.repository.CrudRepository; import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.BridgeEvent; +import java.time.Instant; /// Webhook events already posted. @Repository(entity = BridgeEvent.class, key = String.class) public interface BridgeEventRepository extends CrudRepository { - int deleteByReceivedAtLessThan(long before); + int deleteByReceivedAtLessThan(Instant before); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/CallRecordRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/CallRecordRepository.java index f993ecd4e05..c7eafc30338 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/CallRecordRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/CallRecordRepository.java @@ -25,6 +25,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.CallRecord; +import java.time.Instant; import java.util.List; /// Calls, live and past. @@ -42,16 +43,16 @@ public interface CallRecordRepository extends CrudRepository @Query("select c from CallRecord c where c.caller = :username or c.callee = :username order by c.startedAt desc") List historyOf(@Param("username") String username); - @Query("select c from CallRecord c where (c.caller = :username or c.callee = :username) and c.endedAt = 0") - List liveOf(@Param("username") String username); + @Query("select c from CallRecord c where (c.caller = :username or c.callee = :username) and c.endedAt = :none") + List liveOf(@Param("username") String username, @Param("none") Instant none); - @Query("select c from CallRecord c where c.endedAt = 0 and c.startedAt < :before") - List openSince(@Param("before") long before); + @Query("select c from CallRecord c where c.endedAt = :none and c.startedAt < :before") + List openSince(@Param("before") Instant before, @Param("none") Instant none); - long countByStartedAtGreaterThanEqual(long since); + long countByStartedAtGreaterThanEqual(Instant since); @Query("select c.startedAt from CallRecord c where c.startedAt >= :since") - List startedSince(@Param("since") long since); + List startedSince(@Param("since") Instant since); @Modifying @Query("delete from CallRecord c where c.caller = :username or c.callee = :username") diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ConversationRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ConversationRepository.java index 81ed407f776..b91dcea7e89 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ConversationRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ConversationRepository.java @@ -25,6 +25,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.Conversation; +import java.time.Instant; import java.util.List; /// Conversations of every kind. @@ -48,5 +49,5 @@ public interface ConversationRepository extends CrudRepository { @Modifying @Query("update Device d set d.lastSeenAt = :at where d.id = :id") - int seen(@Param("id") String id, @Param("at") long at); + int seen(@Param("id") String id, @Param("at") Instant at); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/EnvelopeRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/EnvelopeRepository.java index e48afdf5652..8b9e7b16e14 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/EnvelopeRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/EnvelopeRepository.java @@ -25,6 +25,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.Envelope; +import java.time.Instant; import java.util.List; /// Envelopes waiting for their device. @@ -45,9 +46,9 @@ public interface EnvelopeRepository extends CrudRepository { /// Removes what the disappearing timer has run out on. @Modifying - @Query("delete from Envelope e where e.expiresAt > 0 and e.expiresAt <= :now") - int expire(@Param("now") long now); + @Query("delete from Envelope e where e.expiresAt > :none and e.expiresAt <= :now") + int expire(@Param("now") Instant now, @Param("none") Instant none); /// Removes what nobody fetched for a month: the device is gone or lost. - int deleteBySentAtLessThan(long before); + int deleteBySentAtLessThan(Instant before); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/LiveTicketRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/LiveTicketRepository.java index f8f8857177b..4bb95fd8253 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/LiveTicketRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/LiveTicketRepository.java @@ -21,6 +21,7 @@ import com.codename1.orm.repository.CrudRepository; import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.LiveTicket; +import java.time.Instant; /// The tickets that open a live connection. Only the hash of a ticket is /// stored, and it is the row's key. @@ -33,7 +34,7 @@ public interface LiveTicketRepository extends CrudRepository int deleteByTicketHash(String ticketHash); /// Deletes the tickets that went stale before `now`. - int deleteByExpiresAtLessThan(long now); + int deleteByExpiresAtLessThan(Instant now); int deleteByUsername(String username); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MediaBlobRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MediaBlobRepository.java index db2dc77aca2..76e0471caf0 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MediaBlobRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MediaBlobRepository.java @@ -23,14 +23,15 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.MediaBlob; +import java.time.Instant; /// Encrypted attachments. @Repository(entity = MediaBlob.class, key = String.class) public interface MediaBlobRepository extends CrudRepository { int deleteByOwner(String owner); - int deleteByCreatedAtLessThan(long before); + int deleteByCreatedAtLessThan(Instant before); @Query("select coalesce(sum(m.size), 0) from MediaBlob m where m.owner = :owner and m.createdAt >= :since") - Long storedSince(@Param("owner") String owner, @Param("since") long since); + Long storedSince(@Param("owner") String owner, @Param("since") Instant since); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MessageLogRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MessageLogRepository.java index 4667c1949ba..f0d87a050e2 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MessageLogRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/MessageLogRepository.java @@ -24,19 +24,20 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.MessageLog; +import java.time.Instant; import java.util.List; /// That messages were sent, never what they said. @Repository(entity = MessageLog.class, key = String.class) public interface MessageLogRepository extends CrudRepository { - long countBySentAtGreaterThanEqual(long since); + long countBySentAtGreaterThanEqual(Instant since); long countBySender(String sender); @Query("select m.sentAt, m.sender from MessageLog m where m.sentAt >= :since and m.kind = 'MESSAGE'") - List since(@Param("since") long since); + List since(@Param("since") Instant since); int deleteBySender(String sender); - int deleteBySentAtLessThan(long before); + int deleteBySentAtLessThan(Instant before); } diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ModerationEventRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ModerationEventRepository.java index ee2385462bd..38ecf943b74 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ModerationEventRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ModerationEventRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.ModerationEvent; +import java.time.Instant; import java.util.List; /// The record of what the admins did to each account. @@ -32,7 +33,7 @@ public interface ModerationEventRepository extends CrudRepository findTop100ByUsernameOrderByCreatedAtDescIdAsc(String username); diff --git a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ProfileRepository.java b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ProfileRepository.java index cfbaa34aee4..a94031b9ca2 100644 --- a/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ProfileRepository.java +++ b/scripts/parley/backend/src/main/java/com/codenameone/examples/parley/repository/ProfileRepository.java @@ -25,6 +25,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.parley.domain.Profile; +import java.time.Instant; import java.util.List; /// Profiles, keyed by the e-mail an account signs in with. @@ -61,9 +62,9 @@ public interface ProfileRepository extends CrudRepository { /// When each account made since `since` was made. @Query("select p.createdAt from Profile p where p.createdAt >= :since") - List signUps(@Param("since") long since); + List signUps(@Param("since") Instant since); @Modifying @Query("update Profile p set p.lastSeenAt = :at where p.username = :username") - int seen(@Param("username") String username, @Param("at") long at); + int seen(@Param("username") String username, @Param("at") Instant at); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/Rows.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/Rows.java index 6c84eae362d..40bef0bb2e1 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/Rows.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/Rows.java @@ -21,6 +21,7 @@ import com.codenameone.examples.savor.api.DeliveryState; import com.codenameone.examples.savor.api.OrderState; +import java.time.Instant; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,6 +42,13 @@ public static long number(Object value) { return value instanceof Number ? ((Number) value).longValue() : 0L; } + /// A column holding a point in time as milliseconds since the epoch: the + /// `Instant` an entity's time field is read as, or 0 for null or anything + /// else. + public static long millis(Object value) { + return value instanceof Instant ? ((Instant) value).toEpochMilli() : 0L; + } + /// A column as text; empty for null. public static String text(Object value) { return value == null ? "" : String.valueOf(value); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/AccountCleanup.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/AccountCleanup.java index ecac220794f..aa2f296d130 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/AccountCleanup.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/AccountCleanup.java @@ -39,6 +39,7 @@ import com.codenameone.examples.savor.repository.DeliveryActivityRepository; import com.codenameone.examples.savor.repository.DeliveryRepository; +import java.time.Instant; import java.util.List; /// What closing or restricting an account does to the rows other parts of the @@ -205,7 +206,7 @@ public void removeEverythingOf(String username) { && staff.findByRestaurantId(restaurantId).size() < 2) { restaurant.setStatus(Catalog.SUSPENDED); restaurant.setReason("Its only merchant closed their account"); - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); } } staff.deleteByUsername(username); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Accounts.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Accounts.java index d761c97ad69..8994ab9d3f9 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Accounts.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Accounts.java @@ -43,6 +43,7 @@ import com.codenameone.examples.savor.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -184,7 +185,7 @@ void create(String username, String password, String displayName, String phone, profile.setPhoneVerified(phoneVerified); profile.setVehicle(vehicle); profile.setPlate(plate); - profile.setCreatedAt(openedAt); + profile.setCreatedAt(Instant.ofEpochMilli(openedAt)); profiles.insert(profile); if (courier) { applications.grant(username, username); @@ -517,7 +518,7 @@ private void retire(String username) throws IOException { if (!closed.existsById(hash)) { ClosedAccount row = new ClosedAccount(); row.setUsernameHash(hash); - row.setClosedAt(System.currentTimeMillis()); + row.setClosedAt(Instant.now()); closed.insert(row); } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/DemoAccounts.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/DemoAccounts.java index 24fc43cac8e..d3a0fffd763 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/DemoAccounts.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/DemoAccounts.java @@ -40,6 +40,7 @@ import com.codenameone.examples.savor.order.DemoOrders; import java.io.IOException; +import java.time.Instant; /// The accounts a server starts with. /// @@ -170,7 +171,7 @@ void flag(String username, String why, int daysAgo) throws IOException { profile.setFlagged(true); profile.setFlagReason(why); moderation.record(username, ADMIN, Moderation.FLAG, why, - System.currentTimeMillis() - daysAgo * Days.MILLIS); + Instant.now().minusMillis(daysAgo * Days.MILLIS)); } /// An admin, or the plainest kind of account. @@ -240,7 +241,7 @@ void approved(String username, String name, String colour, String make, String m form.setVehicleYear(year() - 3); form.setVehicleColor(colour); form.setVehiclePlate(plate); - form.setSubmittedAt(handedIn); + form.setSubmittedAt(Instant.ofEpochMilli(handedIn)); form.setReviewedBy(ADMIN); for (int iter = 0; iter < Applications.KINDS.length; iter++) { CourierDocument picture = new CourierDocument(); @@ -248,7 +249,7 @@ void approved(String username, String name, String colour, String make, String m picture.setKind(Applications.KINDS[iter]); picture.setContentType("image/png"); picture.setStatus("accepted"); - picture.setUploadedAt(handedIn); + picture.setUploadedAt(Instant.ofEpochMilli(handedIn)); picture.setData(PLACEHOLDER_PICTURE); documents.insert(picture); } @@ -284,7 +285,7 @@ private void applicant() throws IOException { @Transactional(rollbackFor = IOException.class) void handedIn(String username, int daysAgo) throws IOException { CourierApplication form = forms.findById(username); - form.setSubmittedAt(System.currentTimeMillis() - daysAgo * Days.MILLIS); + form.setSubmittedAt(Instant.ofEpochMilli(System.currentTimeMillis() - daysAgo * Days.MILLIS)); } /// When an account opened that many days ago was opened, so that the chart diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Moderation.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Moderation.java index 24ab4f8f2dc..85db0b83e34 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Moderation.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/Moderation.java @@ -26,6 +26,7 @@ import com.codenameone.examples.savor.repository.ModerationEventRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -60,15 +61,16 @@ public void record(String username, String by, String action, String reason) // came with it -- would otherwise be listed in either order. The later // one is stamped after the one before it, so the list is the order in // which things were done. - Long newest = events.newest(username); - long after = newest == null ? 0L : newest.longValue() + 1L; - record(username, by, action, reason, Math.max(System.currentTimeMillis(), after)); + Instant newest = events.newest(username); + Instant now = Instant.now(); + Instant after = newest == null ? Instant.EPOCH : newest.plusMillis(1L); + record(username, by, action, reason, after.isAfter(now) ? after : now); } /// As [#record(String, String, String, String)], at a time of the caller's /// choosing; the demo data is the one caller that has a past to write. @Transactional - public void record(String username, String by, String action, String reason, long at) + public void record(String username, String by, String action, String reason, Instant at) throws IOException { String why = reason == null ? "" : reason.trim(); ModerationEvent event = new ModerationEvent(); @@ -88,7 +90,7 @@ public List events(String username) throws IOException { List out = new ArrayList(); for (int iter = 0; iter < rows.size(); iter++) { ModerationEvent row = rows.get(iter); - out.add(new ModerationEventDto(row.getCreatedAt(), row.getActor(), row.getAction(), + out.add(new ModerationEventDto(row.getCreatedAt().toEpochMilli(), row.getActor(), row.getAction(), row.getReason())); } return out; diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/PhoneVerification.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/PhoneVerification.java index cb85edf4f8e..92f869eb193 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/PhoneVerification.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/account/PhoneVerification.java @@ -31,6 +31,7 @@ import com.codenameone.examples.savor.sms.SmsSender; import java.io.IOException; +import java.time.Instant; /// Proves an account's phone number by texting it a code. /// @@ -104,14 +105,14 @@ void store(String username, String codeHash, long now) throws IOException { // wait. Otherwise both pass the check below and both send a text. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending != null && now - pending.getSentAt() < RESEND_SECONDS * 1000L) { + if (pending != null && now - pending.getSentAt().toEpochMilli() < RESEND_SECONDS * 1000L) { throw new ResponseStatusException(429, "Wait a moment before asking for another code"); } boolean first = pending == null; if (first) { pending = new PhoneCode(); pending.setUsername(username); - } else if (pending.getExpiresAt() >= now && pending.getAttempts() < MAX_ATTEMPTS) { + } else if (pending.getExpiresAt().toEpochMilli() >= now && pending.getAttempts() < MAX_ATTEMPTS) { // With the guesses it has used: asking for another code must not // buy the old one a fresh set. pending.setPreviousHash(pending.getCodeHash()); @@ -119,13 +120,13 @@ void store(String username, String codeHash, long now) throws IOException { pending.setPreviousAttempts(pending.getAttempts()); } else { pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); } pending.setCodeHash(codeHash); - pending.setExpiresAt(now + CODE_SECONDS * 1000L); + pending.setExpiresAt(Instant.ofEpochMilli(now + CODE_SECONDS * 1000L)); pending.setAttempts(0); - pending.setSentAt(now); + pending.setSentAt(Instant.ofEpochMilli(now)); if (first) { codes.insert(pending); } @@ -148,7 +149,7 @@ void discard(String username, String codeHash) throws IOException { return; } if (pending.getPreviousHash().length() == 0 - || pending.getPreviousExpiresAt() < System.currentTimeMillis()) { + || pending.getPreviousExpiresAt().isBefore(Instant.now())) { codes.deleteById(username); return; } @@ -156,9 +157,9 @@ void discard(String username, String codeHash) throws IOException { pending.setExpiresAt(pending.getPreviousExpiresAt()); pending.setAttempts(pending.getPreviousAttempts()); pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); - pending.setSentAt(0L); + pending.setSentAt(Instant.EPOCH); } /// Checks the code the user typed. Answers 400 for a wrong or expired one @@ -186,7 +187,7 @@ boolean guess(String username, String code) throws IOException { // row the other has. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending == null || pending.getExpiresAt() < System.currentTimeMillis()) { + if (pending == null || pending.getExpiresAt().isBefore(Instant.now())) { throw new ResponseStatusException(400, "That code has expired. Ask for a new one"); } if (pending.getAttempts() >= MAX_ATTEMPTS) { @@ -222,7 +223,7 @@ boolean guess(String username, String code) throws IOException { boolean previous = Crypto.equalsConstantTime(given, pending.getPreviousHash().getBytes("UTF-8")) && pending.getPreviousHash().length() > 0 - && pending.getPreviousExpiresAt() >= System.currentTimeMillis() + && !pending.getPreviousExpiresAt().isBefore(Instant.now()) && counted != null && counted.getPreviousAttempts() <= MAX_ATTEMPTS; if (!current && !previous) { return false; diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/admin/Statistics.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/admin/Statistics.java index 5e476f363bf..124da6a1ff0 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/admin/Statistics.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/admin/Statistics.java @@ -48,6 +48,7 @@ import com.codenameone.examples.savor.delivery.Matcher; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -123,8 +124,8 @@ public AdminStatsDto dashboard() throws IOException { } } int online = (int) cars.countByOnlineTrueAndLastSeenGreaterThanEqual( - now - Matcher.FRESH_MILLIS); - int today = (int) orders.countByPlacedAtGreaterThanEqual(Days.start(now)); + Instant.ofEpochMilli(now - Matcher.FRESH_MILLIS)); + int today = (int) orders.countByPlacedAtGreaterThanEqual(Instant.ofEpochMilli(Days.start(now))); int active = (int) orders.countByStateIn(ACTIVE); int done = (int) orders.countByStateIn(new OrderState[] {OrderState.DELIVERED}); long revenue = Rows.number(orders.totals(OrderState.DELIVERED, PAID)); @@ -153,10 +154,10 @@ public StatsSeriesDto series(int days) throws IOException { long finished = 0L; long totalSum = 0L; long tookMillis = 0L; - List timeline = orders.timeline(since); + List timeline = orders.timeline(Instant.ofEpochMilli(since)); for (int iter = 0; iter < timeline.size(); iter++) { Object[] order = timeline.get(iter); - long at = whole(order[1]); + long at = Rows.millis(order[1]); OrderState state = Rows.orderState(order[2]); byHour[(int) (at % Days.MILLIS / 3600000L)]++; if (state != null) { @@ -168,7 +169,7 @@ public StatsSeriesDto series(int days) throws IOException { delivered++; finished++; totalSum += whole(order[3]); - tookMillis += Math.max(0L, whole(order[5]) - at); + tookMillis += Math.max(0L, Rows.millis(order[5]) - at); } else if (ended(state)) { finished++; } @@ -186,7 +187,7 @@ public StatsSeriesDto series(int days) throws IOException { } } Map completedBy = new HashMap(); - List perCourier = deliveries.countByCourier(since, DeliveryState.COMPLETED); + List perCourier = deliveries.countByCourier(Instant.ofEpochMilli(since), DeliveryState.COMPLETED); for (int iter = 0; iter < perCourier.size(); iter++) { completedBy.put(Rows.text(perCourier.get(iter)[0]), new int[] {(int) whole(perCourier.get(iter)[1])}); @@ -203,7 +204,7 @@ public StatsSeriesDto series(int days) throws IOException { } } List byRestaurant = new ArrayList(); - List kitchens = orders.countByRestaurant(since); + List kitchens = orders.countByRestaurant(Instant.ofEpochMilli(since)); for (int iter = 0; iter < kitchens.size(); iter++) { // Counted by id, and named as the restaurant is called now: two // kitchens may share a name, and one may have been renamed. @@ -220,9 +221,9 @@ public StatsSeriesDto series(int days) throws IOException { double completionRate = finished == 0L ? 0d : Math.round(delivered * 100d / finished) / 100d; - List signUps = profiles.signUps(since); + List signUps = profiles.signUps(Instant.ofEpochMilli(since)); for (int iter = 0; iter < signUps.size(); iter++) { - int index = (int) ((signUps.get(iter).longValue() - since) / Days.MILLIS); + int index = (int) ((signUps.get(iter).toEpochMilli() - since) / Days.MILLIS); if (index >= 0 && index < span) { dayNewUsers[index]++; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Catalog.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Catalog.java index 0e61b522f0d..0e126aa1b5f 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Catalog.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Catalog.java @@ -45,6 +45,7 @@ import com.codenameone.examples.savor.repository.PhotoRepository; import com.codenameone.examples.savor.repository.RestaurantRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -343,7 +344,7 @@ public RestaurantSummaryDto favorite(String viewer, String id, boolean keep) Favorite row = new Favorite(); row.setUsername(viewer); row.setRestaurantId(id); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); favorites.insert(row); } else if (!keep && kept) { favorites.deleteById(key); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/DemoRestaurants.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/DemoRestaurants.java index 0fadb79eb42..2a23086e5ae 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/DemoRestaurants.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/DemoRestaurants.java @@ -42,6 +42,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.time.Instant; /// The restaurants a development server starts with: a dozen around San /// Francisco's waterfront, one per cuisine on the home screen's row, each with @@ -266,8 +267,8 @@ public void seed(String merchant) throws IOException { restaurant.setPhotoId(photoFor(RESTAURANT_PHOTOS, restaurant.getId(), restaurant.getId())); restaurant.setApplicant(iter == 0 ? merchant : ""); restaurant.setReason(""); - restaurant.setCreatedAt(now - (60 - iter) * 86400000L); - restaurant.setUpdatedAt(now); + restaurant.setCreatedAt(Instant.ofEpochMilli(now - (60 - iter) * 86400000L)); + restaurant.setUpdatedAt(Instant.ofEpochMilli(now)); restaurants.insert(restaurant); menu(restaurant.getId(), MENUS[iter]); } @@ -291,8 +292,8 @@ public void seed(String merchant) throws IOException { waiting.setPhotoId(""); waiting.setApplicant(""); waiting.setReason(""); - waiting.setCreatedAt(now - 2L * 86400000L); - waiting.setUpdatedAt(now - 2L * 86400000L); + waiting.setCreatedAt(Instant.ofEpochMilli(now - 2L * 86400000L)); + waiting.setUpdatedAt(Instant.ofEpochMilli(now - 2L * 86400000L)); restaurants.insert(waiting); promo("WELCOME10", 10, 0L, 1500L, now); @@ -371,7 +372,7 @@ private String photo(String key, String restaurantId) throws IOException { row.setRestaurantId(restaurantId); row.setContentType(type); row.setData(read(file)); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); photos.insert(row); return id; } @@ -395,7 +396,7 @@ private void promo(String code, int percent, long amount, long minimum, long now promo.setAmountOffCents(amount); promo.setMinimumCents(minimum); promo.setActive(true); - promo.setCreatedAt(now); + promo.setCreatedAt(Instant.ofEpochMilli(now)); promos.insert(promo); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Restaurants.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Restaurants.java index 869bc359a6d..f90eecb347e 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Restaurants.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/catalog/Restaurants.java @@ -56,6 +56,7 @@ import com.codenameone.examples.savor.repository.RestaurantStaffRepository; import com.codenameone.examples.savor.Days; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -150,8 +151,8 @@ public RestaurantDto apply(String username, RestaurantEditDto form) throws IOExc restaurant.setReason(""); restaurant.setPhotoId(""); long now = System.currentTimeMillis(); - restaurant.setCreatedAt(now); - restaurant.setUpdatedAt(now); + restaurant.setCreatedAt(Instant.ofEpochMilli(now)); + restaurant.setUpdatedAt(Instant.ofEpochMilli(now)); fill(restaurant, form); restaurants.insert(restaurant); return catalog.detail(restaurant, username, 0d, 0d, true); @@ -182,7 +183,7 @@ public PhotoDto applicationPhoto(String username, PhotoDto photo) throws IOExcep } PhotoDto saved = store(last.getId(), photo); last.setPhotoId(saved.id()); - last.setUpdatedAt(System.currentTimeMillis()); + last.setUpdatedAt(Instant.now()); return saved; } @@ -258,7 +259,7 @@ public RestaurantDto approve(String by, String id) throws IOException { } restaurant.setStatus(Catalog.APPROVED); restaurant.setReason(""); - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); if (!staff.existsById(Identifier.of(restaurant.getId(), applicant))) { RestaurantStaff row = new RestaurantStaff(); row.setRestaurantId(restaurant.getId()); @@ -281,7 +282,7 @@ public RestaurantDto reject(String by, String id, String reason) throws IOExcept } restaurant.setStatus(Catalog.REJECTED); restaurant.setReason(Text.required(reason, 255, "why it is turned down")); - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); return catalog.detail(restaurant, null, 0d, 0d, true); } @@ -306,7 +307,7 @@ public RestaurantDto suspend(String by, String id, boolean suspended, String rea } restaurant.setStatus(suspended ? Catalog.SUSPENDED : Catalog.APPROVED); restaurant.setReason(suspended ? Text.required(reason, 255, "why it is suspended") : ""); - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); return catalog.detail(restaurant, null, 0d, 0d, true); } @@ -350,7 +351,7 @@ public RestaurantDto save(String username, RestaurantEditDto form) throws IOExce ownPhoto(restaurant, form.photoId()); restaurant.setPhotoId(form.photoId()); } - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); return catalog.detail(restaurant, username, 0d, 0d, true); } @@ -359,7 +360,7 @@ public RestaurantDto save(String username, RestaurantEditDto form) throws IOExce public RestaurantDto pause(String username, boolean paused) throws IOException { Restaurant restaurant = mine(username); restaurant.setPaused(paused); - restaurant.setUpdatedAt(System.currentTimeMillis()); + restaurant.setUpdatedAt(Instant.now()); return catalog.detail(restaurant, username, 0d, 0d, true); } @@ -372,7 +373,7 @@ public MerchantSummaryDto summary(String username) throws IOException { long today = Days.start(now); long week = today - 6L * Days.MILLIS; List delivered = orders.findByRestaurantIdAndStateAndDeliveredAtGreaterThanEqual( - restaurant.getId(), OrderState.DELIVERED, week); + restaurant.getId(), OrderState.DELIVERED, Instant.ofEpochMilli(week)); long count = 0L; long todayCents = 0L; long weekCents = 0L; @@ -386,7 +387,7 @@ public MerchantSummaryDto summary(String username) throws IOException { long earned = order.getSubtotalCents() - order.getDiscountCents() - order.getCommissionCents(); weekCents += earned; - if (order.getDeliveredAt() >= today) { + if (order.getDeliveredAt().toEpochMilli() >= today) { todayCents += earned; count++; } @@ -606,7 +607,7 @@ private PhotoDto store(String restaurantId, PhotoDto photo) throws IOException { row.setRestaurantId(restaurantId); row.setContentType(type); row.setData(bytes); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); photos.insert(row); return new PhotoDto(row.getId(), type, ""); } @@ -624,14 +625,14 @@ private int prune(String restaurantId) { for (int iter = 0; iter < menu.size(); iter++) { used.add(menu.get(iter).getPhotoId()); } - long before = System.currentTimeMillis() - UNUSED_PHOTO_GRACE; + Instant before = Instant.now().minusMillis(UNUSED_PHOTO_GRACE); List stored = photos.stored(restaurantId); int remaining = 0; for (int iter = 0; iter < stored.size(); iter++) { Object id = stored.get(iter)[0]; Object at = stored.get(iter)[1]; - long createdAt = at instanceof Number ? ((Number) at).longValue() : Long.MAX_VALUE; - if (id instanceof String && !used.contains(id) && createdAt < before) { + boolean aged = at instanceof Instant && ((Instant) at).isBefore(before); + if (id instanceof String && !used.contains(id) && aged) { photos.deleteById((String) id); } else { remaining++; diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Couriers.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Couriers.java index f1c1253ab0a..484fd01d5fb 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Couriers.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Couriers.java @@ -47,6 +47,7 @@ import com.codenameone.examples.savor.delivery.Matcher; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -156,14 +157,14 @@ private Report store(String courier, CourierStatusDto status) throws IOException // is, so the row read here stays managed and its change is written // either way; a statement marked clearAutomatically would detach it, // and a change made after that would be lost. - long since = state != null && state.isOnline() ? now - state.getLastSeen() : 0L; + long since = state != null && state.isOnline() ? now - state.getLastSeen().toEpochMilli() : 0L; boolean first = state == null; if (first) { state = new CourierState(); state.setUsername(courier); } state.setOnline(status.online()); - state.setLastSeen(now); + state.setLastSeen(Instant.ofEpochMilli(now)); // Off line keeps the last position: there is none to report. A first // report stores whatever came with it. if (status.online() || first) { @@ -282,10 +283,10 @@ public EarningsDto earnings(String courier) throws IOException { long now = System.currentTimeMillis(); // The day's trips and the day's money from one query, so the header // that shows them together counts the deliveries that made the sum. - Object[] day = deliveries.paidTotalsSince(courier, now - now % DAY_MILLIS); + Object[] day = deliveries.paidTotalsSince(courier, Instant.ofEpochMilli(now - now % DAY_MILLIS)); int todayCount = day == null ? 0 : (int) Rows.number(day[0]); long today = day == null ? 0L : Rows.number(day[1]); - long week = Rows.number(deliveries.paidSince(courier, now - 7 * DAY_MILLIS)); + long week = Rows.number(deliveries.paidSince(courier, Instant.ofEpochMilli(now - 7 * DAY_MILLIS))); Object[] total = deliveries.paidTotals(courier); int count = total == null ? 0 : (int) Rows.number(total[0]); long all = total == null ? 0L : Rows.number(total[1]); @@ -305,7 +306,7 @@ private static CourierDto toDto(Profile profile, CourierApplication application, double rating = 5d; long lastSeen = 0L; if (car != null) { - lastSeen = car.getLastSeen(); + lastSeen = car.getLastSeen().toEpochMilli(); // On line means said so and heard from lately; see Matcher. online = car.isOnline() && System.currentTimeMillis() - lastSeen < Matcher.FRESH_MILLIS; diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Earnings.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Earnings.java index d082b078f0c..a345522114d 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Earnings.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/courier/Earnings.java @@ -48,6 +48,7 @@ import com.codenameone.examples.savor.order.Quotes; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -115,16 +116,16 @@ public EarningsSummaryDto summary(String courier) throws IOException { long monthStart = today - 29 * Days.MILLIS; long weekStart = today - 6 * Days.MILLIS; List done = deliveries.findByCourierAndStateAndUpdatedAtGreaterThanEqual(courier, - DeliveryState.COMPLETED, monthStart); + DeliveryState.COMPLETED, Instant.ofEpochMilli(monthStart)); // A card tip is on its delivery from the moment it is asked for, and is // still there when the processor never answered. Only one whose charge // is on record is earned, here as in the balance: otherwise a day's // total would show money that cannot be cashed out. Set charged = new HashSet( - deliveries.tipChargedSince(courier, monthStart)); + deliveries.tipChargedSince(courier, Instant.ofEpochMilli(monthStart))); for (int iter = 0; iter < done.size(); iter++) { Delivery delivery = done.get(iter); - long at = delivery.getUpdatedAt(); + long at = delivery.getUpdatedAt().toEpochMilli(); boolean tipped = "cash".equals(delivery.getMethodId()) || charged.contains(delivery.getId()); // The fare likewise counts only once it is paid, as in the balance: // a card charge that failed, was refunded or has not come back is @@ -197,7 +198,7 @@ public PayoutDto cashOut(String courier) throws IOException { row.setCourier(courier); row.setAmountCents(amount); row.setStatus("paid"); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); row.setDestination(account.getBankName() + " ****" + account.getLast4()); payouts.insert(row); return toDto(row); @@ -297,6 +298,6 @@ private static PayoutAccountDto toDto(PayoutAccount row) { private static PayoutDto toDto(Payout row) { return new PayoutDto(row.getId(), row.getAmountCents(), row.getStatus(), - row.getCreatedAt(), row.getDestination()); + row.getCreatedAt().toEpochMilli(), row.getDestination()); } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Deliveries.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Deliveries.java index 0e556c6e391..8c5bab31928 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Deliveries.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Deliveries.java @@ -56,6 +56,7 @@ import com.codenameone.examples.savor.repository.DeliveryRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -177,9 +178,9 @@ public void dispatch(CustomerOrder order, Restaurant restaurant) throws IOExcept delivery.setMethodLabel(order.getMethodLabel()); delivery.setPaymentStatus(order.getPaymentStatus()); delivery.setNote(order.getNote()); - delivery.setRequestedAt(now); - delivery.setUpdatedAt(now); - delivery.setSearchUntil(now + searchMillis); + delivery.setRequestedAt(Instant.ofEpochMilli(now)); + delivery.setUpdatedAt(Instant.ofEpochMilli(now)); + delivery.setSearchUntil(Instant.ofEpochMilli(now + searchMillis)); deliveries.insert(delivery); event(order.getId(), DeliveryState.REQUESTED, ""); } @@ -279,7 +280,7 @@ private Delivery finish(String courier, String id) throws IOException { Delivery delivery = owned(id, COURIER, courier); move(id, DeliveryState.COMPLETED, courier, COURIER, null, null); if (orders.deliver(id, OrderStateMachine.sources(OrderState.DELIVERED), - OrderState.DELIVERED, System.currentTimeMillis()) == 1) { + OrderState.DELIVERED, Instant.now()) == 1) { orderEvents.record(id, OrderState.DELIVERED, courier); } return delivery; @@ -334,13 +335,13 @@ public void settleLeftBehind() throws IOException { @Transactional(readOnly = true) private List unsettled(long after, long before) { - return deliveries.unsettled(after, before, new PageRequest(0, 50)); + return deliveries.unsettled(Instant.ofEpochMilli(after), Instant.ofEpochMilli(before), new PageRequest(0, 50)); } @Transactional private Change settled(String courier, String id, String status) throws IOException { deliveries.paymentStatus(id, status); - orders.paymentStatus(id, status, System.currentTimeMillis()); + orders.paymentStatus(id, status, Instant.now()); Delivery delivery = find(id); return new Change(id, delivery.getState(), delivery.getCustomer(), delivery.getCourier(), "", toDto(delivery, courier, new HashMap())); @@ -359,7 +360,7 @@ public DeliveryDto cancelByCourier(String courier, String id) throws IOException private Change giveUp(String courier, String id) throws IOException { Delivery delivery = owned(id, COURIER, courier); if (deliveries.giveBack(id, TAKEN_NOT_STARTED, DeliveryState.REQUESTED, - System.currentTimeMillis(), courier, "") != 1) { + Instant.now(), courier, "") != 1) { throw new ResponseStatusException(409, "That delivery is " + describe(find(id).getState())); } @@ -394,7 +395,7 @@ private Change step(String courier, String id, DeliveryState to) throws IOExcept // The courier has the food: the order is picked up in the same // transaction, and only once the kitchen said it is ready. if (orders.move(id, OrderStateMachine.sources(OrderState.PICKED_UP), - OrderState.PICKED_UP, System.currentTimeMillis()) != 1) { + OrderState.PICKED_UP, Instant.now()) != 1) { throw new ResponseStatusException(409, "The kitchen has not marked it ready yet"); } orderEvents.record(id, OrderState.PICKED_UP, courier); @@ -494,17 +495,17 @@ private Change choose(String id, String[] chosen) throws IOException { return null; } long now = System.currentTimeMillis(); - if (now > delivery.getSearchUntil()) { + if (now > delivery.getSearchUntil().toEpochMilli()) { if (!tryMove(id, DeliveryState.NO_COURIERS, "", null, null, null)) { return null; } if (orders.end(id, OrderStateMachine.sources(OrderState.NO_COURIERS), - OrderState.NO_COURIERS, "No courier was free to bring it", now) == 1) { + OrderState.NO_COURIERS, "No courier was free to bring it", Instant.ofEpochMilli(now)) == 1) { orderEvents.record(id, OrderState.NO_COURIERS, ""); } return new Change(id, DeliveryState.NO_COURIERS, delivery.getCustomer(), "", "", null); } - chosen[0] = matcher.pick(delivery, now - delivery.getRequestedAt()); + chosen[0] = matcher.pick(delivery, now - delivery.getRequestedAt().toEpochMilli()); return null; } @@ -535,7 +536,7 @@ Change offer(String id, String courier) throws IOException { return null; } long now = System.currentTimeMillis(); - if (!matcher.fits(delivery, courier, now - delivery.getRequestedAt())) { + if (!matcher.fits(delivery, courier, now - delivery.getRequestedAt().toEpochMilli())) { return null; } return tryMove(id, DeliveryState.OFFERED, "", null, courier, Long.valueOf(now + offerMillis)) @@ -584,7 +585,7 @@ public void tick() throws IOException { @Transactional(readOnly = true) private List lapsedOffers(long now) throws IOException { - return deliveries.findByStateAndOfferExpiresAtLessThan(DeliveryState.OFFERED, now); + return deliveries.findByStateAndOfferExpiresAtLessThan(DeliveryState.OFFERED, Instant.ofEpochMilli(now)); } @Transactional(readOnly = true) @@ -723,10 +724,11 @@ private boolean tryMove(String id, DeliveryState to, String actor, String ownerF if (sources.length == 0) { return false; } - long now = System.currentTimeMillis(); + Instant now = Instant.now(); int moved; if (newOfferExpiresAt != null) { - moved = deliveries.offer(id, sources, to, now, newCourier, newOfferExpiresAt.longValue()); + moved = deliveries.offer(id, sources, to, now, newCourier, + Instant.ofEpochMilli(newOfferExpiresAt.longValue())); } else if (CUSTOMER.equals(ownerField)) { moved = deliveries.moveAsCustomer(id, sources, to, now, actor); } else if (!COURIER.equals(ownerField)) { @@ -754,7 +756,7 @@ private void event(String id, DeliveryState state, String actor) throws IOExcept event.setDeliveryId(id); event.setState(state); event.setActor(actor); - event.setCreatedAt(System.currentTimeMillis()); + event.setCreatedAt(Instant.now()); events.insert(event); } @@ -888,7 +890,7 @@ private DeliveryDto toDto(Delivery delivery, String viewer, Map } if (offered) { offerExpiresInSeconds = (int) Math.max(0L, - (delivery.getOfferExpiresAt() - System.currentTimeMillis()) / 1000L); + (delivery.getOfferExpiresAt().toEpochMilli() - System.currentTimeMillis()) / 1000L); } long fareCents = delivery.getFareCents(); long tip = delivery.getTipCents(); @@ -921,8 +923,8 @@ private DeliveryDto toDto(Delivery delivery, String viewer, Map delivery.getCurrency(), delivery.getDistanceMeters(), delivery.getDurationSeconds(), - delivery.getRequestedAt(), - delivery.getUpdatedAt(), + delivery.getRequestedAt().toEpochMilli(), + delivery.getUpdatedAt().toEpochMilli(), delivery.getStars(), delivery.getPaymentStatus(), offerExpiresInSeconds, diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Matcher.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Matcher.java index 3d632f9b9a7..226f645a0e8 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Matcher.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/delivery/Matcher.java @@ -37,6 +37,7 @@ import com.codenameone.examples.savor.repository.DeliveryPassedRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -132,7 +133,7 @@ private List free(double lat, double lng, double radiusMeters) throws double dLat = radiusMeters / Geo.METERS_PER_DEGREE; double shrink = Math.max(0.01d, Math.cos(Math.toRadians(lat))); double dLng = radiusMeters / (Geo.METERS_PER_DEGREE * shrink); - List boxed = couriers.freeInBox(System.currentTimeMillis() - FRESH_MILLIS, + List boxed = couriers.freeInBox(Instant.now().minusMillis(FRESH_MILLIS), lat - dLat, lat + dLat, lng - dLng, lng + dLng, Applications.APPROVED, WITH_DELIVERY); List inReach = new ArrayList(); List names = new ArrayList(); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ClosedAccount.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ClosedAccount.java index 14f1392da29..07f19a9c45c 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ClosedAccount.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ClosedAccount.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What is left of an account that was closed: the hash of its e-mail, kept so /// that the address cannot be registered again. @@ -31,7 +32,7 @@ public class ClosedAccount { private String usernameHash = ""; @Column(nullable = false) - private long closedAt; + private Instant closedAt = Instant.EPOCH; public ClosedAccount() { } @@ -44,11 +45,11 @@ public void setUsernameHash(String usernameHash) { this.usernameHash = usernameHash; } - public long getClosedAt() { + public Instant getClosedAt() { return closedAt; } - public void setClosedAt(long closedAt) { + public void setClosedAt(Instant closedAt) { this.closedAt = closedAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierApplication.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierApplication.java index dabb9e342e9..1c5662f6f58 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierApplication.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierApplication.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's application to deliver, and what became of it. @Entity @@ -63,13 +64,13 @@ public class CourierApplication { private String rejectionReason = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long submittedAt; + private Instant submittedAt = Instant.EPOCH; @Column(nullable = false) - private long reviewedAt; + private Instant reviewedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String reviewedBy = ""; @@ -173,27 +174,27 @@ public void setRejectionReason(String rejectionReason) { this.rejectionReason = rejectionReason; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getSubmittedAt() { + public Instant getSubmittedAt() { return submittedAt; } - public void setSubmittedAt(long submittedAt) { + public void setSubmittedAt(Instant submittedAt) { this.submittedAt = submittedAt; } - public long getReviewedAt() { + public Instant getReviewedAt() { return reviewedAt; } - public void setReviewedAt(long reviewedAt) { + public void setReviewedAt(Instant reviewedAt) { this.reviewedAt = reviewedAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierDocument.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierDocument.java index 51f6214e105..cb5f0d610d7 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierDocument.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierDocument.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A document an applicant uploaded, one of each kind. `data` is the file in /// Base64, which is text on every database. @@ -41,7 +42,7 @@ public class CourierDocument { private String status = ""; @Column(nullable = false) - private long uploadedAt; + private Instant uploadedAt = Instant.EPOCH; @Column(nullable = false) private String data = ""; @@ -81,11 +82,11 @@ public void setStatus(String status) { this.status = status; } - public long getUploadedAt() { + public Instant getUploadedAt() { return uploadedAt; } - public void setUploadedAt(long uploadedAt) { + public void setUploadedAt(Instant uploadedAt) { this.uploadedAt = uploadedAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierState.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierState.java index 85d1049a05c..6401313002d 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierState.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CourierState.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// Where a courier's car is, whether they are on line, and what customers made of them. @Entity @@ -42,7 +43,7 @@ public class CourierState { private double heading; @Column(nullable = false) - private long lastSeen; + private Instant lastSeen = Instant.EPOCH; @Column(nullable = false) private long ratingSum; @@ -98,11 +99,11 @@ public void setHeading(double heading) { this.heading = heading; } - public long getLastSeen() { + public Instant getLastSeen() { return lastSeen; } - public void setLastSeen(long lastSeen) { + public void setLastSeen(Instant lastSeen) { this.lastSeen = lastSeen; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CustomerOrder.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CustomerOrder.java index d34529b2739..b1f2b1494c9 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CustomerOrder.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/CustomerOrder.java @@ -23,6 +23,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An order: what a customer bought from one restaurant, what it cost, and where /// it stands. Its lines, prices and address are copied in when it is placed, so a @@ -107,19 +108,19 @@ public class CustomerOrder { private int prepMinutes; @Column(nullable = false) - private long placedAt; + private Instant placedAt = Instant.EPOCH; @Column(nullable = false) - private long acceptedAt; + private Instant acceptedAt = Instant.EPOCH; @Column(nullable = false) - private long readyAt; + private Instant readyAt = Instant.EPOCH; @Column(nullable = false) - private long deliveredAt; + private Instant deliveredAt = Instant.EPOCH; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(255)") private String reason = ""; @@ -330,43 +331,43 @@ public void setPrepMinutes(int prepMinutes) { this.prepMinutes = prepMinutes; } - public long getPlacedAt() { + public Instant getPlacedAt() { return placedAt; } - public void setPlacedAt(long placedAt) { + public void setPlacedAt(Instant placedAt) { this.placedAt = placedAt; } - public long getAcceptedAt() { + public Instant getAcceptedAt() { return acceptedAt; } - public void setAcceptedAt(long acceptedAt) { + public void setAcceptedAt(Instant acceptedAt) { this.acceptedAt = acceptedAt; } - public long getReadyAt() { + public Instant getReadyAt() { return readyAt; } - public void setReadyAt(long readyAt) { + public void setReadyAt(Instant readyAt) { this.readyAt = readyAt; } - public long getDeliveredAt() { + public Instant getDeliveredAt() { return deliveredAt; } - public void setDeliveredAt(long deliveredAt) { + public void setDeliveredAt(Instant deliveredAt) { this.deliveredAt = deliveredAt; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Delivery.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Delivery.java index 174d2eb5ea3..64075d9c942 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Delivery.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Delivery.java @@ -22,6 +22,7 @@ import com.codename1.annotations.Entity; import com.codename1.annotations.Id; import com.codenameone.examples.savor.api.DeliveryState; +import java.time.Instant; // tag::savor-entity[] /// A delivery, from the request to its end. @@ -75,16 +76,16 @@ public class Delivery { private double durationSeconds; @Column(nullable = false) - private long requestedAt; + private Instant requestedAt = Instant.EPOCH; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false) - private long offerExpiresAt; + private Instant offerExpiresAt = Instant.EPOCH; @Column(nullable = false) - private long searchUntil; + private Instant searchUntil = Instant.EPOCH; @Column(nullable = false, type = "SMALLINT") private int stars; @@ -225,35 +226,35 @@ public void setDurationSeconds(double durationSeconds) { this.durationSeconds = durationSeconds; } - public long getRequestedAt() { + public Instant getRequestedAt() { return requestedAt; } - public void setRequestedAt(long requestedAt) { + public void setRequestedAt(Instant requestedAt) { this.requestedAt = requestedAt; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } - public long getOfferExpiresAt() { + public Instant getOfferExpiresAt() { return offerExpiresAt; } - public void setOfferExpiresAt(long offerExpiresAt) { + public void setOfferExpiresAt(Instant offerExpiresAt) { this.offerExpiresAt = offerExpiresAt; } - public long getSearchUntil() { + public Instant getSearchUntil() { return searchUntil; } - public void setSearchUntil(long searchUntil) { + public void setSearchUntil(Instant searchUntil) { this.searchUntil = searchUntil; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryActivity.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryActivity.java index b44ee60cffa..1e8b9d4eebf 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryActivity.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryActivity.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The Live Activity a customer's phone shows a delivery in, while the delivery lasts. @Entity @@ -38,12 +39,12 @@ public class DeliveryActivity { /// When the server last sent it a state, for spacing out the updates. @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; /// When its delivery ended, 0 while the delivery lasts. An ended activity is kept /// until the phone has been told to end it. @Column(nullable = false) - private long endedAt; + private Instant endedAt = Instant.EPOCH; public DeliveryActivity() { } @@ -72,19 +73,19 @@ public void setActivityId(String activityId) { this.activityId = activityId; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } - public long getEndedAt() { + public Instant getEndedAt() { return endedAt; } - public void setEndedAt(long endedAt) { + public void setEndedAt(Instant endedAt) { this.endedAt = endedAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryEvent.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryEvent.java index 53e646b615c..1ac81efdafb 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryEvent.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/DeliveryEvent.java @@ -22,6 +22,7 @@ import com.codename1.annotations.Entity; import com.codename1.annotations.Id; import com.codenameone.examples.savor.api.DeliveryState; +import java.time.Instant; /// One change of a delivery's state: what it became, who made it so, and when. @Entity @@ -40,7 +41,7 @@ public class DeliveryEvent { private String actor = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public DeliveryEvent() { } @@ -77,11 +78,11 @@ public void setActor(String actor) { this.actor = actor; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Favorite.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Favorite.java index 0c6e5d11b64..6161bf14cfd 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Favorite.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Favorite.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A restaurant a customer keeps, keyed by `Identifier.of(username, restaurantId)`. @Entity @@ -34,7 +35,7 @@ public class Favorite { private String restaurantId = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public Favorite() { } @@ -55,11 +56,11 @@ public void setRestaurantId(String restaurantId) { this.restaurantId = restaurantId; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/LiveTicket.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/LiveTicket.java index 4e0f5fecd38..801de0c7994 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/LiveTicket.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/LiveTicket.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A ticket for one connection to the live channel, as its hash. @Entity @@ -33,7 +34,7 @@ public class LiveTicket { private String username = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public LiveTicket() { } @@ -54,11 +55,11 @@ public void setUsername(String username) { this.username = username; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ModerationEvent.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ModerationEvent.java index 0ad8aeb3fdb..d8c37f92589 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ModerationEvent.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/ModerationEvent.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One thing an admin did to an account, and why. Written once, never changed. @Entity @@ -33,7 +34,7 @@ public class ModerationEvent { private String username = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String actor = ""; @@ -63,11 +64,11 @@ public void setUsername(String username) { this.username = username; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/OrderEvent.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/OrderEvent.java index 94d091face4..a9a98afadd0 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/OrderEvent.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/OrderEvent.java @@ -23,6 +23,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A change of an order's state: what it became, who made it, and when. @Entity @@ -41,7 +42,7 @@ public class OrderEvent { private String actor = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public OrderEvent() { } @@ -78,11 +79,11 @@ public void setActor(String actor) { this.actor = actor; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payment.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payment.java index 8157760cf44..5c4cc53be74 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payment.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payment.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What a completed delivery was charged, and what was given back. @Entity @@ -42,7 +43,7 @@ public class Payment { private String providerRef = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(64)") private String tipRef = ""; @@ -57,7 +58,7 @@ public class Payment { private String refundReason = ""; @Column(nullable = false) - private long refundedAt; + private Instant refundedAt = Instant.EPOCH; public Payment() { } @@ -102,11 +103,11 @@ public void setProviderRef(String providerRef) { this.providerRef = providerRef; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } @@ -142,11 +143,11 @@ public void setRefundReason(String refundReason) { this.refundReason = refundReason; } - public long getRefundedAt() { + public Instant getRefundedAt() { return refundedAt; } - public void setRefundedAt(long refundedAt) { + public void setRefundedAt(Instant refundedAt) { this.refundedAt = refundedAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentMethod.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentMethod.java index 8edddcfdf35..4edbb85fabc 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentMethod.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentMethod.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A saved card: what the provider calls it and what to show for it. The /// number itself is never here. @@ -52,7 +53,7 @@ public class PaymentMethod { private boolean preferred; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public PaymentMethod() { } @@ -121,11 +122,11 @@ public void setPreferred(boolean preferred) { this.preferred = preferred; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentSetup.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentSetup.java index 410658a37e0..5b0757fee9c 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentSetup.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PaymentSetup.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A card being added on the provider's page, until the browser comes back. @Entity @@ -36,7 +37,7 @@ public class PaymentSetup { private String reference = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) private boolean completed; @@ -68,11 +69,11 @@ public void setReference(String reference) { this.reference = reference; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payout.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payout.java index 295beb14887..69c99a0ff6b 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payout.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Payout.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One payment of earnings to a courier. @Entity @@ -39,7 +40,7 @@ public class Payout { private String status = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(120)") private String destination = ""; @@ -79,11 +80,11 @@ public void setStatus(String status) { this.status = status; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PhoneCode.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PhoneCode.java index 87115e9f825..db6ea1e2477 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PhoneCode.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PhoneCode.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The verification code an account was last sent, as its hash. @Entity @@ -33,20 +34,20 @@ public class PhoneCode { private String codeHash = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; @Column(nullable = false) private int attempts; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; /// The code sent before this one, while it is still good, or empty. @Column(nullable = false, type = "VARCHAR(64)") private String previousHash = ""; @Column(nullable = false) - private long previousExpiresAt; + private Instant previousExpiresAt = Instant.EPOCH; /// The guesses already taken at the code before, which keeps the budget /// it had rather than starting a new one when another code is sent. @@ -72,11 +73,11 @@ public void setCodeHash(String codeHash) { this.codeHash = codeHash; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } @@ -88,11 +89,11 @@ public void setAttempts(int attempts) { this.attempts = attempts; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } @@ -104,11 +105,11 @@ public void setPreviousHash(String previousHash) { this.previousHash = previousHash; } - public long getPreviousExpiresAt() { + public Instant getPreviousExpiresAt() { return previousExpiresAt; } - public void setPreviousExpiresAt(long previousExpiresAt) { + public void setPreviousExpiresAt(Instant previousExpiresAt) { this.previousExpiresAt = previousExpiresAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Photo.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Photo.java index 10c7a383d9a..b26494ea2ca 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Photo.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Photo.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A restaurant's or a dish's picture: the bytes of a JPEG or a PNG. @Entity @@ -36,7 +37,7 @@ public class Photo { private String contentType = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) private byte[] data = new byte[0]; @@ -68,11 +69,11 @@ public void setContentType(String contentType) { this.contentType = contentType; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Pricing.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Pricing.java index 5fe90ebfb8e..ab0cea02412 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Pricing.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Pricing.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What an order costs on top of its food, and what the service keeps of it. /// There is one row; see V6. @@ -55,7 +56,7 @@ public class Pricing { private double commissionPercent; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String updatedBy = ""; @@ -135,11 +136,11 @@ public void setCommissionPercent(double commissionPercent) { this.commissionPercent = commissionPercent; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Profile.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Profile.java index d9bdfef5872..d4c63522b49 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Profile.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Profile.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's profile: who it is to the people it deliveries with. /// @@ -48,7 +49,7 @@ public class Profile { private String plate = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(8)") private String language = "en"; @@ -110,11 +111,11 @@ public void setPlate(String plate) { this.plate = plate; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Promo.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Promo.java index 384b8cf25d7..0d07ce19894 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Promo.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Promo.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A code a customer types at checkout: a percentage or an amount off the food, /// for an order of at least `minimumCents`, once per account. @@ -43,7 +44,7 @@ public class Promo { private boolean active; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public Promo() { } @@ -88,11 +89,11 @@ public void setActive(boolean active) { this.active = active; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PushDevice.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PushDevice.java index d5c941dde26..ec59e720d4a 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PushDevice.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/PushDevice.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A device an account is sent push notifications on. /// @@ -46,7 +47,7 @@ public class PushDevice { private String platform = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public PushDevice() { } @@ -91,11 +92,11 @@ public void setPlatform(String platform) { this.platform = platform; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Restaurant.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Restaurant.java index cd0cf9878ba..23b931465eb 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Restaurant.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/Restaurant.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A restaurant on the service: listed once an admin approves it, and taking /// orders while it is open and its staff have not paused it. @@ -85,10 +86,10 @@ public class Restaurant { private String reason = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public Restaurant() { } @@ -245,19 +246,19 @@ public void setReason(String reason) { this.reason = reason; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/SavedAddress.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/SavedAddress.java index 2065edf1f35..43a6b2f66fa 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/SavedAddress.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/domain/SavedAddress.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A place a customer has kept to be delivered to. @Entity @@ -48,7 +49,7 @@ public class SavedAddress { private String note = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public SavedAddress() { } @@ -109,11 +110,11 @@ public void setNote(String note) { this.note = note; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/live/LiveTickets.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/live/LiveTickets.java index 8cf7d0215b7..c4e4d3a167f 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/live/LiveTickets.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/live/LiveTickets.java @@ -28,6 +28,7 @@ import com.codenameone.examples.savor.repository.LiveTicketRepository; import java.io.IOException; +import java.time.Instant; /// Tickets for the live channel. /// @@ -58,7 +59,7 @@ public TicketDto issue(String username) throws IOException { LiveTicket row = new LiveTicket(); row.setTicketHash(Ids.sha256(ticket)); row.setUsername(username); - row.setExpiresAt(System.currentTimeMillis() + TICKET_SECONDS * 1000L); + row.setExpiresAt(Instant.ofEpochMilli(System.currentTimeMillis() + TICKET_SECONDS * 1000L)); tickets.insert(row); return new TicketDto(ticket, TICKET_SECONDS); } @@ -78,7 +79,7 @@ public String redeem(String ticket) throws IOException { return null; } String username = row.getUsername(); - long expiresAt = row.getExpiresAt(); + long expiresAt = row.getExpiresAt().toEpochMilli(); // One delete statement: the count it answers is what says this // connection, and not another presenting the same ticket, used it. int removed = tickets.deleteByTicketHash(hash); @@ -92,7 +93,7 @@ public String redeem(String ticket) throws IOException { @Scheduled(fixedDelay = 60000, initialDelay = 60000) @Transactional public void sweep() throws IOException { - tickets.deleteByExpiresAtLessThan(System.currentTimeMillis()); + tickets.deleteByExpiresAtLessThan(Instant.now()); } /// Forgets the tickets of an account that is being closed. diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/onboarding/Applications.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/onboarding/Applications.java index 64e1c6652ac..ce62acc5b13 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/onboarding/Applications.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/onboarding/Applications.java @@ -30,6 +30,7 @@ import com.codename1.orm.session.Identifier; import com.codenameone.examples.savor.Days; import com.codenameone.examples.savor.Roles; +import com.codenameone.examples.savor.Rows; import com.codenameone.examples.savor.Text; import com.codenameone.examples.savor.account.Moderation; import com.codenameone.examples.savor.api.DocumentContentDto; @@ -44,6 +45,7 @@ import com.codenameone.examples.savor.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -244,13 +246,13 @@ public CourierApplicationDto upload(String username, DocumentUploadDto upload) long now = System.currentTimeMillis(); // Replaced with a statement where there is one already, so the picture // it held is not read only to be overwritten. - if (documents.replace(username, kind, type, "uploaded", now, data) == 0) { + if (documents.replace(username, kind, type, "uploaded", Instant.ofEpochMilli(now), data) == 0) { CourierDocument document = new CourierDocument(); document.setUsername(username); document.setKind(kind); document.setContentType(type); document.setStatus("uploaded"); - document.setUploadedAt(now); + document.setUploadedAt(Instant.ofEpochMilli(now)); document.setData(data); documents.insert(document); } @@ -310,7 +312,7 @@ public CourierApplicationDto submit(String username) throws IOException { throw new ResponseStatusException(400, what.toString()); } // Held to the status it was read in: handed in twice, it is handed in once. - applications.submit(username, was, PENDING, System.currentTimeMillis()); + applications.submit(username, was, PENDING, Instant.now()); return get(username); } @@ -424,7 +426,7 @@ public void grant(String by, String username) throws IOException { applications.insert(blank(username, APPROVED, "", "")); return; } - applications.approveUnlessApproved(username, APPROVED, System.currentTimeMillis(), by); + applications.approveUnlessApproved(username, APPROVED, Instant.now(), by); } /// Takes the approval back, when an admin withdraws the COURIER role. The @@ -432,7 +434,7 @@ public void grant(String by, String username) throws IOException { @Transactional public void withdraw(String by, String username) throws IOException { applications.move(username, APPROVED, REJECTED, "Onboarding was withdrawn by an admin", - System.currentTimeMillis(), by); + Instant.now(), by); } /// Everything kept about an account's application, for an account being @@ -453,7 +455,7 @@ private void decide(String by, String username, String to, String reason) if (find(username) == null) { throw new ResponseStatusException(404, "No such application"); } - if (applications.move(username, PENDING, to, reason, System.currentTimeMillis(), by) + if (applications.move(username, PENDING, to, reason, Instant.now(), by) != 1) { throw new ResponseStatusException(409, "That application is not waiting for an answer"); } @@ -534,8 +536,8 @@ private static CourierApplication blank(String username, String status, String v application.setStatus(status); application.setVehicleModel(vehicle.length() > 40 ? vehicle.substring(0, 40) : vehicle); application.setVehiclePlate(plate); - application.setCreatedAt(now); - application.setReviewedAt(APPROVED.equals(status) ? now : 0L); + application.setCreatedAt(Instant.ofEpochMilli(now)); + application.setReviewedAt(APPROVED.equals(status) ? Instant.ofEpochMilli(now) : Instant.EPOCH); return application; } @@ -566,8 +568,7 @@ private static CourierApplicationDto toDto(String username, String name, Object[] stored = documents.get(iter); if (KINDS[kind].equals(stored[from])) { status = (String) stored[from + 1]; - Object at = stored[from + 2]; - uploadedAt = at instanceof Number ? ((Number) at).longValue() : 0L; + uploadedAt = Rows.millis(stored[from + 2]); } } listed.add(new DocumentDto(KINDS[kind], status, uploadedAt)); @@ -581,7 +582,7 @@ private static CourierApplicationDto toDto(String username, String name, row.getDateOfBirth(), row.getLicenceNumber(), row.getLicenceExpiry(), row.getVehicleMake(), row.getVehicleModel(), row.getVehicleYear(), row.getVehicleColor(), row.getVehiclePlate(), listed, - row.getRejectionReason(), row.getSubmittedAt(), row.getReviewedAt(), + row.getRejectionReason(), row.getSubmittedAt().toEpochMilli(), row.getReviewedAt().toEpochMilli(), row.getReviewedBy()); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Addresses.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Addresses.java index 48261e9e938..eecfc124c9b 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Addresses.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Addresses.java @@ -29,6 +29,7 @@ import com.codenameone.examples.savor.repository.ProfileRepository; import com.codenameone.examples.savor.repository.SavedAddressRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -77,7 +78,7 @@ public SavedAddressDto save(String username, SavedAddressDto form) throws IOExce row = new SavedAddress(); row.setId(Ids.next()); row.setUsername(username); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); } row.setLabel(Text.required(form.label(), 40, "a name for the place")); row.setAddress(Text.required(form.address(), 255, "the address")); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoKitchen.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoKitchen.java index de13aa5c456..1d8c20aae98 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoKitchen.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoKitchen.java @@ -28,6 +28,7 @@ import com.codenameone.examples.savor.repository.CustomerOrderRepository; import com.codenameone.examples.savor.repository.RestaurantStaffRepository; import java.io.IOException; +import java.time.Instant; import java.util.List; /// The kitchens of the demo restaurants nobody runs, on a development server: @@ -62,7 +63,7 @@ public void cook() throws IOException { return; } long now = System.currentTimeMillis(); - List waiting = unattended(OrderState.PLACED, now - ACCEPT_AFTER_MILLIS); + List waiting = unattended(OrderState.PLACED, Instant.ofEpochMilli(now - ACCEPT_AFTER_MILLIS)); for (int iter = 0; iter < waiting.size(); iter++) { CustomerOrder order = waiting.get(iter); try { @@ -72,7 +73,7 @@ public void cook() throws IOException { // Cancelled or turned down in the meantime. } } - List cooking = unattended(OrderState.ACCEPTED, now - READY_AFTER_MILLIS); + List cooking = unattended(OrderState.ACCEPTED, Instant.ofEpochMilli(now - READY_AFTER_MILLIS)); for (int iter = 0; iter < cooking.size(); iter++) { CustomerOrder order = cooking.get(iter); try { @@ -85,7 +86,7 @@ public void cook() throws IOException { /// Orders in `state` since before `before` at restaurants with no staff. @Transactional(readOnly = true) - private List unattended(OrderState state, long before) { + private List unattended(OrderState state, Instant before) { List rows = OrderState.PLACED == state ? orders.findByStateAndPlacedAtLessThan(state, before) : orders.findByStateAndAcceptedAtLessThan(state, before); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoOrders.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoOrders.java index 82a3b972b2f..88392e3bbc0 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoOrders.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/DemoOrders.java @@ -49,6 +49,7 @@ import com.codenameone.examples.savor.repository.PayoutRepository; import com.codenameone.examples.savor.repository.RestaurantRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -226,12 +227,12 @@ public void seed(String[] customers, String[] couriers) throws IOException { order.setPaymentStatus(delivered ? Payments.PAID : cash ? Payments.PENDING : Payments.RELEASED); order.setPrepMinutes(kitchen.getPrepMinutes()); - order.setPlacedAt(at); - order.setUpdatedAt(ended); + order.setPlacedAt(Instant.ofEpochMilli(at)); + order.setUpdatedAt(Instant.ofEpochMilli(ended)); order.setAcceptedAt(OrderState.REJECTED == state - || OrderState.CANCELLED_BY_CUSTOMER == state ? 0L : accepted); - order.setReadyAt(delivered ? ready : 0L); - order.setDeliveredAt(delivered ? ended : 0L); + || OrderState.CANCELLED_BY_CUSTOMER == state ? Instant.EPOCH : Instant.ofEpochMilli(accepted)); + order.setReadyAt(delivered ? Instant.ofEpochMilli(ready) : Instant.EPOCH); + order.setDeliveredAt(delivered ? Instant.ofEpochMilli(ended) : Instant.EPOCH); order.setReason(OrderState.REJECTED == state ? "Out of ingredients" : OrderState.NO_COURIERS == state ? "No courier was free to bring it" : OrderState.CANCELLED_BY_CUSTOMER == state ? "Cancelled by the customer" @@ -270,9 +271,9 @@ public void seed(String[] customers, String[] couriers) throws IOException { delivery.setCurrency(pricing.currency()); delivery.setDistanceMeters(meters); delivery.setDurationSeconds(meters / Quotes.METERS_PER_SECOND); - delivery.setRequestedAt(accepted); - delivery.setUpdatedAt(ended); - delivery.setSearchUntil(accepted + 900000L); + delivery.setRequestedAt(Instant.ofEpochMilli(accepted)); + delivery.setUpdatedAt(Instant.ofEpochMilli(ended)); + delivery.setSearchUntil(Instant.ofEpochMilli(accepted + 900000L)); delivery.setStars(given); delivery.setPaymentStatus(delivered ? Payments.PAID : Payments.PENDING); delivery.setMethodId(method[0]); @@ -300,7 +301,7 @@ public void seed(String[] customers, String[] couriers) throws IOException { payment.setStatus(Payments.PAID); payment.setProviderRef(cash ? Payments.CASH : "sim_ch_order-" + id); payment.setTipRef(""); - payment.setCreatedAt(ended); + payment.setCreatedAt(Instant.ofEpochMilli(ended)); paid.insert(payment); lastSeen[courierIndex] = Math.max(lastSeen[courierIndex], ended); if (ended < now - 7L * Days.MILLIS) { @@ -324,7 +325,7 @@ public void seed(String[] customers, String[] couriers) throws IOException { } state.setLat(real(iter % DOORS.length, 1)); state.setLng(real(iter % DOORS.length, 2)); - state.setLastSeen(lastSeen[iter]); + state.setLastSeen(Instant.ofEpochMilli(lastSeen[iter])); state.setRatingSum(stars[iter]); state.setRatingCount(rated[iter]); if (first) { @@ -343,7 +344,7 @@ public void seed(String[] customers, String[] couriers) throws IOException { payout.setCourier(couriers[iter]); payout.setAmountCents(earnedEarlier[iter]); payout.setStatus("paid"); - payout.setCreatedAt(now - 7L * Days.MILLIS); + payout.setCreatedAt(Instant.ofEpochMilli(now - 7L * Days.MILLIS)); payout.setDestination("Bay Credit Union ****67" + (10 + iter)); payouts.insert(payout); } @@ -357,7 +358,7 @@ private void orderEvent(String order, OrderState state, String actor, long at) event.setOrderId(order); event.setState(state); event.setActor(actor); - event.setCreatedAt(at); + event.setCreatedAt(Instant.ofEpochMilli(at)); orderEvents.insert(event); } @@ -368,7 +369,7 @@ private void deliveryEvent(String delivery, DeliveryState state, String actor, l event.setDeliveryId(delivery); event.setState(state); event.setActor(actor); - event.setCreatedAt(at); + event.setCreatedAt(Instant.ofEpochMilli(at)); deliveryEvents.insert(event); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/OrderEvents.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/OrderEvents.java index b9388a118e3..2bdd7ff8f11 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/OrderEvents.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/OrderEvents.java @@ -24,6 +24,7 @@ import com.codenameone.examples.savor.domain.OrderEvent; import com.codenameone.examples.savor.repository.OrderEventRepository; import java.io.IOException; +import java.time.Instant; /// The history of an order: one row per move, with who made it. Written in /// the transaction that made the move. @@ -41,7 +42,7 @@ public void record(String orderId, OrderState state, String actor) throws IOExce event.setOrderId(orderId); event.setState(state); event.setActor(actor == null ? "" : actor); - event.setCreatedAt(System.currentTimeMillis()); + event.setCreatedAt(Instant.now()); events.insert(event); } } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Orders.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Orders.java index 6d21f69e3dd..77088e66460 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Orders.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Orders.java @@ -53,6 +53,7 @@ import com.codenameone.examples.savor.repository.RestaurantRepository; import com.codenameone.examples.savor.repository.RestaurantStaffRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -299,8 +300,8 @@ private Void store(String id, String customer, CartDto cart, Quotes.Priced charg order.setAuthorizationRef(hold); order.setPaymentStatus(Payments.CASH.equals(hold) ? Payments.PENDING : Payments.AUTHORIZED); order.setPrepMinutes(priced.restaurant.getPrepMinutes()); - order.setPlacedAt(now); - order.setUpdatedAt(now); + order.setPlacedAt(Instant.ofEpochMilli(now)); + order.setUpdatedAt(Instant.ofEpochMilli(now)); order.setReason(""); orders.insert(order); for (int iter = 0; iter < priced.lines.size(); iter++) { @@ -401,7 +402,7 @@ private Void adminEnd(String by, String id, String why, Deliveries.Change[] chan @Transactional private Void end(String id, OrderState to, String actor, String reason) throws IOException { if (orders.end(id, OrderStateMachine.sources(to), to, reason, - System.currentTimeMillis()) != 1) { + Instant.now()) != 1) { CustomerOrder now = find(id); throw new ResponseStatusException(409, "That order is " + (now == null ? "gone" : describe(now.getState()))); @@ -426,7 +427,7 @@ private Void rated(String customer, String id, int stars) throws IOException { if (OrderState.DELIVERED != order.getState()) { throw new ResponseStatusException(409, "Only a delivered order can be rated"); } - if (orders.rate(id, customer, stars, System.currentTimeMillis()) != 1) { + if (orders.rate(id, customer, stars, Instant.now()) != 1) { throw new ResponseStatusException(409, "That order is already rated"); } restaurants.addRating(order.getRestaurantId(), stars); @@ -501,7 +502,7 @@ private Void accepted(String actor, String restaurantId, String id, int prepMinu throws IOException { CustomerOrder order = kitchens(restaurantId, id); if (orders.accept(id, OrderStateMachine.sources(OrderState.ACCEPTED), - OrderState.ACCEPTED, prepMinutes, System.currentTimeMillis()) != 1) { + OrderState.ACCEPTED, prepMinutes, Instant.now()) != 1) { throw new ResponseStatusException(409, "That order is " + describe(order.getState())); } @@ -531,7 +532,7 @@ public OrderDto ready(String actor, String restaurantId, String id) throws IOExc private Void readied(String actor, String restaurantId, String id) throws IOException { CustomerOrder order = kitchens(restaurantId, id); if (orders.ready(id, OrderStateMachine.sources(OrderState.READY), OrderState.READY, - System.currentTimeMillis()) != 1) { + Instant.now()) != 1) { throw new ResponseStatusException(409, "That order is " + describe(order.getState())); } @@ -544,7 +545,7 @@ private Void readied(String actor, String restaurantId, String id) throws IOExce /// kitchen. @Scheduled(fixedDelay = 15000, initialDelay = 15000, lock = "savor-kitchen") public void sweep() throws IOException { - List late = late(System.currentTimeMillis() - answerMillis); + List late = late(Instant.now().minusMillis(answerMillis)); for (int iter = 0; iter < late.size(); iter++) { String id = late.get(iter).getId(); try { @@ -562,7 +563,7 @@ public void sweep() throws IOException { // still held, and asking to end it again is refused: it has ended. // Releasing is safe to repeat -- see Payments.release -- so this // finishes what was left, for every way an order ends short of the door. - List held = unreleased(System.currentTimeMillis() - UNRELEASED_MILLIS); + List held = unreleased(Instant.now().minusMillis(UNRELEASED_MILLIS)); for (int iter = 0; iter < held.size(); iter++) { payments.release(held.get(iter).getId()); } @@ -576,12 +577,12 @@ public void sweep() throws IOException { OrderState.CANCELLED_BY_CUSTOMER, OrderState.CANCELLED_BY_ADMIN, OrderState.NO_COURIERS}; @Transactional(readOnly = true) - private List late(long before) { + private List late(Instant before) { return orders.findByStateAndPlacedAtLessThan(OrderState.PLACED, before); } @Transactional(readOnly = true) - private List unreleased(long before) { + private List unreleased(Instant before) { return orders.unreleased(ENDED_SHORT, new String[] {Payments.AUTHORIZED, Payments.PENDING}, before, new PageRequest(0, 50)); @@ -716,8 +717,8 @@ private OrderDto toDto(CustomerOrder order, String viewer, boolean customer, boo if (OrderState.PICKED_UP == state && delivery != null && delivery.etaMinutes() > 0) { eta = delivery.etaMinutes(); } else { - long cooked = (order.getAcceptedAt() == 0L ? order.getPlacedAt() - : order.getAcceptedAt()) + order.getPrepMinutes() * 60000L; + long cooked = (order.getAcceptedAt().toEpochMilli() == 0L ? order.getPlacedAt().toEpochMilli() + : order.getAcceptedAt().toEpochMilli()) + order.getPrepMinutes() * 60000L; int left = (int) Math.max(0L, (cooked - System.currentTimeMillis()) / 60000L); eta = left + ride; } @@ -734,8 +735,9 @@ private OrderDto toDto(CustomerOrder order, String viewer, boolean customer, boo order.getDiscountCents(), order.getTipCents(), order.getTotalCents(), order.getCurrency(), order.getDropoffLat(), order.getDropoffLng(), order.getDropoffAddress(), order.getNote(), order.getMethodLabel(), - order.getPaymentStatus(), order.getPrepMinutes(), order.getPlacedAt(), - order.getAcceptedAt(), order.getReadyAt(), order.getDeliveredAt(), eta, + order.getPaymentStatus(), order.getPrepMinutes(), order.getPlacedAt().toEpochMilli(), + order.getAcceptedAt().toEpochMilli(), order.getReadyAt().toEpochMilli(), + order.getDeliveredAt().toEpochMilli(), eta, order.getReason(), order.getStars(), delivery); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Promos.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Promos.java index 5726384ae6d..43ed7cd6b3e 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Promos.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Promos.java @@ -25,6 +25,7 @@ import com.codenameone.examples.savor.api.PromoDto; import com.codenameone.examples.savor.domain.Promo; import com.codenameone.examples.savor.repository.PromoRepository; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -77,7 +78,7 @@ public PromoDto save(PromoDto form) { if (unsaved) { row = new Promo(); row.setCode(code); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); } row.setPercentOff(form.percentOff()); row.setAmountOffCents(form.amountOffCents()); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Quotes.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Quotes.java index fd64514b7eb..d1b896bc1fd 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Quotes.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/order/Quotes.java @@ -41,6 +41,7 @@ import com.codenameone.examples.savor.repository.PromoUseRepository; import com.codenameone.examples.savor.repository.RestaurantRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -119,7 +120,7 @@ public PricingDto pricing() throws IOException { } private PricingDto toDto(Pricing row) { - if (row == null || row.getUpdatedAt() == 0L) { + if (row == null || Instant.EPOCH.equals(row.getUpdatedAt())) { return defaults; } return new PricingDto(defaults.currency(), row.getBaseCents(), row.getPerKmCents(), @@ -143,7 +144,7 @@ public PricingDto save(String by, PricingDto wanted) throws IOException { if (prices.change(PricingRepository.ONLY.intValue(), wanted.baseCents(), wanted.perKmCents(), wanted.surge(), wanted.smallOrderCents(), wanted.smallOrderFeeCents(), wanted.serviceFeePercent(), wanted.taxPercent(), - wanted.commissionPercent(), System.currentTimeMillis(), by) == 0) { + wanted.commissionPercent(), Instant.now(), by) == 0) { throw new IllegalStateException("The pricing row is missing; the V6 migration " + "creates it"); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/pay/Payments.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/pay/Payments.java index 35c5fb933c2..28479f62f9e 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/pay/Payments.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/pay/Payments.java @@ -48,6 +48,7 @@ import com.codenameone.examples.savor.repository.DeliveryRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -211,7 +212,7 @@ private String customerForSetup(String username) { /// that are neither finished nor abandoned. private void refuseTooManySetups(String username) { if (setups.countByUsernameAndCompletedFalseAndCreatedAtGreaterThan(username, - System.currentTimeMillis() - SETUP_MILLIS) >= MAX_OPEN_SETUPS) { + Instant.now().minusMillis(SETUP_MILLIS)) >= MAX_OPEN_SETUPS) { throw new ResponseStatusException(429, "Too many cards are being added. Finish one, or try again later"); } @@ -228,7 +229,7 @@ private void refuseTooManySetups(String username) { @Transactional public void sweepSetups() throws IOException { setups.deleteByCompletedTrue(); - setups.deleteByCreatedAtLessThan(System.currentTimeMillis() - 2L * SETUP_MILLIS); + setups.deleteByCreatedAtLessThan(Instant.now().minusMillis(2L * SETUP_MILLIS)); } /// Keeps the reference the processor made for a customer on first use, and @@ -276,7 +277,7 @@ private void keepSetup(String username, String id, String reference) { row.setId(id); row.setUsername(username); row.setReference(reference); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); row.setCompleted(false); setups.insert(row); } @@ -339,7 +340,7 @@ private String[] openSetup(String username, String setupId) { PaymentSetup setup = setupId == null || setupId.length() == 0 || setupId.length() > 32 ? null : setups.findFirstByIdAndUsername(setupId, username); if (setup == null || setup.isCompleted() - || setup.getCreatedAt() < System.currentTimeMillis() - SETUP_MILLIS) { + || setup.getCreatedAt().plusMillis(SETUP_MILLIS).isBefore(Instant.now())) { throw new ResponseStatusException(404, "No such card setup"); } PaymentCustomer customer = customers.findById(username); @@ -368,8 +369,9 @@ private PaymentMethodDto keepCard(String username, String setupId, String id, // Cards are listed in the order they were added, and two added in the // same millisecond would have no order: the later is stamped after // the one before it. - Long newest = cards.newestAt(username); - long after = newest == null ? 0L : newest.longValue() + 1L; + Instant newest = cards.newestAt(username); + Instant now = Instant.now(); + Instant after = newest == null ? Instant.EPOCH : newest.plusMillis(1L); PaymentMethod row = new PaymentMethod(); row.setId(id); row.setUsername(username); @@ -379,7 +381,7 @@ private PaymentMethodDto keepCard(String username, String setupId, String id, row.setExpYear(card.expYear); row.setToken(card.token); row.setPreferred(first); - row.setCreatedAt(Math.max(System.currentTimeMillis(), after)); + row.setCreatedAt(after.isAfter(now) ? after : now); cards.insert(row); return card(row); } @@ -509,8 +511,8 @@ public void forget(String username) throws IOException { } } - private static long retriedSince() { - return System.currentTimeMillis() - RETRY_MILLIS; + private static Instant retriedSince() { + return Instant.now().minusMillis(RETRY_MILLIS); } // --------------------------------------------------------------- charges @@ -591,7 +593,7 @@ private CustomerOrder order(String id) { @Transactional private void orderPaymentStatus(String id, String status) { - orders.paymentStatus(id, status, System.currentTimeMillis()); + orders.paymentStatus(id, status, Instant.now()); } /// Writes what came of a delivery's payment to the delivery and to its @@ -600,7 +602,7 @@ private void orderPaymentStatus(String id, String status) { /// caller's transaction. private void paymentStatus(String deliveryId, String status) { deliveries.paymentStatus(deliveryId, status); - orders.paymentStatus(deliveryId, status, System.currentTimeMillis()); + orders.paymentStatus(deliveryId, status, Instant.now()); } /// Settles a delivery that has just completed and returns [#PAID], [#FAILED], @@ -675,7 +677,7 @@ private void keepPayment(String deliveryId, long amount, String currency, String row.setCurrency(currency); row.setStatus(status); row.setProviderRef(reference); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); payments.insert(row); } @@ -869,7 +871,7 @@ private List refundsPending() { @Transactional private Delivery endRefund(String deliveryId, String outcome) { if (payments.endRefund(deliveryId, outcome, - REFUNDED.equals(outcome) ? System.currentTimeMillis() : 0L) != 1) { + REFUNDED.equals(outcome) ? Instant.now() : Instant.EPOCH) != 1) { return null; } paymentStatus(deliveryId, outcome); @@ -991,7 +993,7 @@ private void keepRefund(String deliveryId, PaymentProvider.Refund fare, payment.setRefundRef(cut(fare.reference, 64)); payment.setTipRefundRef(tip == null ? "" : cut(tip.reference, 64)); payment.setRefundReason(reason); - payment.setRefundedAt(pending ? 0L : System.currentTimeMillis()); + payment.setRefundedAt(pending ? Instant.EPOCH : Instant.now()); } /// Records a refund of the fare whose tip could not be refunded: the delivery @@ -1004,7 +1006,7 @@ private void keepPartialRefund(String deliveryId, PaymentProvider.Refund fare, S payment.setRefundRef(cut(fare.reference, 64)); payment.setTipRefundRef(""); payment.setRefundReason(reason); - payment.setRefundedAt(0L); + payment.setRefundedAt(Instant.EPOCH); } // -------------------------------------------------------------- receipts @@ -1041,7 +1043,7 @@ public ReceiptDto receipt(String viewer, boolean admin, String deliveryId) throw throw new ResponseStatusException(404, "No such receipt"); } Payment payment = payments.findById(deliveryId); - return receipt(delivery, payment == null ? 0L : payment.getCreatedAt(), admin, + return receipt(delivery, payment == null ? 0L : payment.getCreatedAt().toEpochMilli(), admin, new HashMap()); } @@ -1058,7 +1060,7 @@ private List receipts(List completed, boolean admin) { List rows = payments.findByDeliveryIdIn(ids); for (int iter = 0; iter < rows.size(); iter++) { Payment payment = rows.get(iter); - paidAt.put(payment.getDeliveryId(), Long.valueOf(payment.getCreatedAt())); + paidAt.put(payment.getDeliveryId(), Long.valueOf(payment.getCreatedAt().toEpochMilli())); } } Map couriers = new HashMap(); @@ -1252,7 +1254,7 @@ private PaymentMethod card(String username, String id) { /// A card tip left unknown counts too, with no time limit: see [#tip]. /// Its retry charges the delivery's card under the same key, so with the card /// gone a tip that may have been charged would be cleared as refused. - private boolean awaitsCharge(String customer, String methodId, long since) { + private boolean awaitsCharge(String customer, String methodId, Instant since) { List tipped = deliveries.findByCustomerAndPaymentStatusAndTipCentsGreaterThan(customer, PAID, 0L); for (Delivery delivery : tipped) { diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/OrderPushes.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/OrderPushes.java index 5b99403e1df..6e061e83002 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/OrderPushes.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/OrderPushes.java @@ -48,6 +48,7 @@ import com.codenameone.examples.savor.repository.RestaurantStaffRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -182,8 +183,8 @@ public void deliveryChanged(String id, DeliveryState state, String courier) { @Scheduled(fixedDelay = 60000, initialDelay = 50000, lock = "savor-activity-ends") public void endLeftBehind() throws IOException { long now = System.currentTimeMillis(); - dropEndedBefore(now - END_RETRY_MILLIS); - List left = leftBehind(now - END_GRACE_MILLIS); + dropEndedBefore(Instant.ofEpochMilli(now - END_RETRY_MILLIS)); + List left = leftBehind(Instant.ofEpochMilli(now - END_GRACE_MILLIS)); Exception failed = null; for (int iter = 0; iter < left.size(); iter++) { String id = left.get(iter).getDeliveryId(); @@ -204,13 +205,13 @@ public void endLeftBehind() throws IOException { } @Transactional - private void dropEndedBefore(long before) { - activities.dropEndedBefore(before); + private void dropEndedBefore(Instant before) { + activities.dropEndedBefore(Instant.EPOCH, before); } @Transactional(readOnly = true) - private List leftBehind(long before) { - return activities.leftBehind(before, new PageRequest(0, 50)); + private List leftBehind(Instant before) { + return activities.leftBehind(Instant.EPOCH, before, new PageRequest(0, 50)); } @Transactional @@ -280,11 +281,11 @@ public DeliveryActivityDto attach(String customer, String orderId, DeliveryActiv row.setDeliveryId(orderId); row.setUsername(customer); row.setActivityId(activityId); - row.setSentAt(System.currentTimeMillis()); + row.setSentAt(Instant.now()); activities.insert(row); } else { row.setActivityId(activityId); - row.setSentAt(System.currentTimeMillis()); + row.setSentAt(Instant.now()); } return new DeliveryActivityDto(activityId); } @@ -400,7 +401,7 @@ private List compose(String id, OrderState state) throws IOException { } // end::savor-push-messages[] if (!state.isActive() && activity != null) { - activities.markEnded(id, System.currentTimeMillis()); + activities.markEnded(id, Instant.now(), Instant.EPOCH); } if (toCustomer != null && !wants(customer, OrderState.DELIVERED == state)) { toCustomer = null; @@ -485,7 +486,7 @@ private List moved(String orderId, double lat, double lng) throws IOEx long now = System.currentTimeMillis(); // A conditional update, so that two reports arriving together send one // update between them. - if (activities.claim(orderId, now, now - activityMillis) != 1) { + if (activities.claim(orderId, Instant.ofEpochMilli(now), Instant.ofEpochMilli(now - activityMillis)) != 1) { return out; } CustomerOrder order = orders.findById(orderId); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/PushDevices.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/PushDevices.java index 30e63516f9a..cb4a9db6d83 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/PushDevices.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/push/PushDevices.java @@ -30,6 +30,7 @@ import com.codenameone.examples.savor.repository.PushDeviceRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -112,7 +113,7 @@ private void makeRoom(String username) { while (held.size() >= MAX_PER_ACCOUNT) { PushDevice oldest = held.get(0); for (PushDevice each : held) { - if (each.getUpdatedAt() < oldest.getUpdatedAt()) { + if (each.getUpdatedAt().isBefore(oldest.getUpdatedAt())) { oldest = each; } } @@ -151,7 +152,7 @@ List targetsOf(String username) { private static void fill(PushDevice row, String username, PushDeviceDto device, long now) { row.setUsername(username); row.setPlatform(Text.optional(device.platform(), 32, "the platform")); - row.setUpdatedAt(now); + row.setUpdatedAt(Instant.ofEpochMilli(now)); } /// The device as a target of the push service, which also spells its diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierApplicationRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierApplicationRepository.java index 0a71b192ff4..78091c4b52b 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierApplicationRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierApplicationRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.CourierApplication; +import java.time.Instant; import java.util.List; /// Applications to deliver, one per account at most, keyed by the account. @@ -72,7 +73,7 @@ public interface CourierApplicationRepository extends CrudRepository :to") int approveUnlessApproved(@Param("username") String username, - @Param("to") String approved, @Param("at") long at, @Param("by") String by); + @Param("to") String approved, @Param("at") Instant at, @Param("by") String by); /// Hands an application in: from the status it was read in to `to`, with /// the last rejection's reason cleared. @@ -89,7 +90,7 @@ int approveUnlessApproved(@Param("username") String username, @Query("update CourierApplication a set a.status = :to, a.submittedAt = :at, " + "a.rejectionReason = '' where a.username = :username and a.status = :from") int submit(@Param("username") String username, @Param("from") String from, - @Param("to") String to, @Param("at") long at); + @Param("to") String to, @Param("at") Instant at); /// Makes the rest of the transaction wait its turn behind any other that /// holds, or moves, the same application. diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierDocumentRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierDocumentRepository.java index cf4fe3015a6..5148ee9b4b7 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierDocumentRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CourierDocumentRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.session.Identifier; import com.codenameone.examples.savor.domain.CourierDocument; +import java.time.Instant; import java.util.List; /// The documents of applications to deliver, keyed by @@ -58,7 +59,7 @@ public interface CourierDocumentRepository extends CrudRepository freeInBox(@Param("fresh") long fresh, @Param("south") double south, + List freeInBox(@Param("fresh") Instant fresh, @Param("south") double south, @Param("north") double north, @Param("west") double west, @Param("east") double east, @Param("approved") String approved, @Param("withDelivery") DeliveryState[] withDelivery); @@ -85,7 +86,7 @@ List freeInBox(@Param("fresh") long fresh, @Param("south") double int takeOffLine(@Param("username") String username); /// The couriers on line who reported in at or after `seenSince`. - long countByOnlineTrueAndLastSeenGreaterThanEqual(long seenSince); + long countByOnlineTrueAndLastSeenGreaterThanEqual(Instant seenSince); int deleteByUsername(String username); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CustomerOrderRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CustomerOrderRepository.java index 43ab2087711..e73d898ab97 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CustomerOrderRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/CustomerOrderRepository.java @@ -27,6 +27,7 @@ import com.codenameone.examples.savor.api.OrderState; import com.codenameone.examples.savor.domain.CustomerOrder; +import java.time.Instant; import java.util.List; /// Every order. @@ -44,16 +45,16 @@ List findTop50ByRestaurantIdAndStateInOrderByPlacedAtDesc(String OrderState[] states); List findByRestaurantIdAndStateAndDeliveredAtGreaterThanEqual(String restaurantId, - OrderState state, long since); + OrderState state, Instant since); - List findByStateAndPlacedAtLessThan(OrderState state, long before); + List findByStateAndPlacedAtLessThan(OrderState state, Instant before); - List findByStateAndAcceptedAtLessThan(OrderState state, long before); + List findByStateAndAcceptedAtLessThan(OrderState state, Instant before); boolean existsByCustomerAndMethodIdAndStateIn(String customer, String methodId, OrderState[] states); - List findByPaymentStatusAndUpdatedAtLessThan(String paymentStatus, long before); + List findByPaymentStatusAndUpdatedAtLessThan(String paymentStatus, Instant before); /// Orders in one of `states` whose payment is one of `statuses` and has /// not changed since `before`, oldest first: ended orders whose hold was @@ -62,12 +63,12 @@ boolean existsByCustomerAndMethodIdAndStateIn(String customer, String methodId, + "and o.paymentStatus in :statuses and o.updatedAt < :before " + "order by o.updatedAt asc") List unreleased(@Param("states") OrderState[] states, - @Param("statuses") String[] statuses, @Param("before") long before, PageRequest page); + @Param("statuses") String[] statuses, @Param("before") Instant before, PageRequest page); @Query("select o from CustomerOrder o order by o.placedAt desc") List newest(PageRequest page); - List findByPlacedAtGreaterThanEqual(long since); + List findByPlacedAtGreaterThanEqual(Instant since); long countByCustomerAndStateIn(String customer, OrderState[] states); @@ -78,54 +79,54 @@ List unreleased(@Param("states") OrderState[] states, @Query("update CustomerOrder o set o.state = :to, o.updatedAt = :now " + "where o.id = :id and o.state in :from") int move(@Param("id") String id, @Param("from") OrderState[] from, @Param("to") OrderState to, - @Param("now") long now); + @Param("now") Instant now); @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.paymentStatus = :status, o.updatedAt = :now " + "where o.id = :id") - int paymentStatus(@Param("id") String id, @Param("status") String status, @Param("now") long now); + int paymentStatus(@Param("id") String id, @Param("status") String status, @Param("now") Instant now); /// The kitchen takes an order and says how long it needs. @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.state = :to, o.updatedAt = :now, o.acceptedAt = :now, " + "o.prepMinutes = :prep where o.id = :id and o.state in :from") int accept(@Param("id") String id, @Param("from") OrderState[] from, - @Param("to") OrderState to, @Param("prep") int prep, @Param("now") long now); + @Param("to") OrderState to, @Param("prep") int prep, @Param("now") Instant now); /// The kitchen has finished an order. @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.state = :to, o.updatedAt = :now, o.readyAt = :now " + "where o.id = :id and o.state in :from") int ready(@Param("id") String id, @Param("from") OrderState[] from, - @Param("to") OrderState to, @Param("now") long now); + @Param("to") OrderState to, @Param("now") Instant now); /// The order reached the door. @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.state = :to, o.updatedAt = :now, o.deliveredAt = :now " + "where o.id = :id and o.state in :from") int deliver(@Param("id") String id, @Param("from") OrderState[] from, - @Param("to") OrderState to, @Param("now") long now); + @Param("to") OrderState to, @Param("now") Instant now); /// An order ends without reaching the door, and why. @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.state = :to, o.updatedAt = :now, o.reason = :reason " + "where o.id = :id and o.state in :from") int end(@Param("id") String id, @Param("from") OrderState[] from, - @Param("to") OrderState to, @Param("reason") String reason, @Param("now") long now); + @Param("to") OrderState to, @Param("reason") String reason, @Param("now") Instant now); /// A customer's stars for a delivered order, once. @Modifying(clearAutomatically = true) @Query("update CustomerOrder o set o.stars = :stars, o.updatedAt = :now " + "where o.id = :id and o.customer = :customer and o.stars = 0") int rate(@Param("id") String id, @Param("customer") String customer, - @Param("stars") int stars, @Param("now") long now); + @Param("stars") int stars, @Param("now") Instant now); /// The orders placed since `since`, counted by restaurant: `{id, count}`. @Query("select o.restaurantId, count(o) from CustomerOrder o where o.placedAt >= :since " + "group by o.restaurantId") - List countByRestaurant(@Param("since") long since); + List countByRestaurant(@Param("since") Instant since); - long countByPlacedAtGreaterThanEqual(long since); + long countByPlacedAtGreaterThanEqual(Instant since); long countByStateIn(OrderState[] states); @@ -137,7 +138,7 @@ int rate(@Param("id") String id, @Param("customer") String customer, /// The orders placed since `since`, counted by state: `{state, count}`. @Query("select o.state, count(o) from CustomerOrder o where o.placedAt >= :since " + "group by o.state") - List countByState(@Param("since") long since); + List countByState(@Param("since") Instant since); /// One row for each order placed since `since`: `{id, placedAt, state, /// totalCents, paymentStatus, deliveredAt}`. @@ -149,7 +150,7 @@ int rate(@Param("id") String id, @Param("customer") String customer, /// see the two as one expression. @Query("select o.id, o.placedAt, o.state, o.totalCents, o.paymentStatus, o.deliveredAt " + "from CustomerOrder o where o.placedAt >= :since") - List timeline(@Param("since") long since); + List timeline(@Param("since") Instant since); /// Locks the order's row until the transaction ends, if it is still the /// customer's and in one of `states`; 1 when it is, 0 when it is not. diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryActivityRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryActivityRepository.java index c4e42751c00..982a0364719 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryActivityRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryActivityRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.DeliveryActivity; +import java.time.Instant; import java.util.List; /// The Live Activities customers follow their deliveries in, by delivery. @@ -40,23 +41,27 @@ public interface DeliveryActivityRepository extends CrudRepository 0 and a.endedAt < :before " + @Query("select a from DeliveryActivity a where a.endedAt > :never and a.endedAt < :before " + "order by a.endedAt") - List leftBehind(@Param("before") long before, PageRequest page); + List leftBehind(@Param("never") Instant never, @Param("before") Instant before, + PageRequest page); /// Forgets the activities whose delivery ended before `before`. @Modifying - @Query("delete from DeliveryActivity a where a.endedAt > 0 and a.endedAt < :before") - int dropEndedBefore(@Param("before") long before); + @Query("delete from DeliveryActivity a where a.endedAt > :never and a.endedAt < :before") + int dropEndedBefore(@Param("never") Instant never, @Param("before") Instant before); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryEventRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryEventRepository.java index 30c49dfc92e..0e30b71449f 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryEventRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryEventRepository.java @@ -25,6 +25,7 @@ import com.codenameone.examples.savor.api.DeliveryState; import com.codenameone.examples.savor.domain.DeliveryEvent; +import java.time.Instant; import java.util.List; /// What happened to each delivery: one row for every state it came into. @@ -42,5 +43,5 @@ public interface DeliveryEventRepository extends CrudRepository= :since)") - List reached(@Param("since") long since, @Param("state") DeliveryState state); + List reached(@Param("since") Instant since, @Param("state") DeliveryState state); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryRepository.java index ddb775291aa..2512f7c304c 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/DeliveryRepository.java @@ -27,6 +27,7 @@ import com.codenameone.examples.savor.api.DeliveryState; import com.codenameone.examples.savor.domain.Delivery; +import java.time.Instant; import java.util.List; /// Deliveries. @@ -70,11 +71,11 @@ boolean existsByCustomerAndMethodIdAndStateIn(String customer, String methodId, /// `paymentStatus` and which ended after `since`, is to be charged to /// this method. boolean existsByCustomerAndStateAndPaymentStatusAndUpdatedAtGreaterThanAndMethodId( - String customer, DeliveryState state, String paymentStatus, long since, String methodId); + String customer, DeliveryState state, String paymentStatus, Instant since, String methodId); /// The same, to be charged to any method but `methodId`. boolean existsByCustomerAndStateAndPaymentStatusAndUpdatedAtGreaterThanAndMethodIdNot( - String customer, DeliveryState state, String paymentStatus, long since, String methodId); + String customer, DeliveryState state, String paymentStatus, Instant since, String methodId); /// A customer's deliveries whose payment is `paymentStatus` and that carry a tip. List findByCustomerAndPaymentStatusAndTipCentsGreaterThan(String customer, @@ -99,16 +100,16 @@ List findByCustomerAndStateOrderByRequestedAtDesc(String customer, Del List newest(PageRequest page); /// The deliveries in `state` whose offer ran out before `now`. - List findByStateAndOfferExpiresAtLessThan(DeliveryState state, long now); + List findByStateAndOfferExpiresAtLessThan(DeliveryState state, Instant now); /// The deliveries in `state`, the one that has waited longest first. List findByStateOrderByRequestedAtAsc(DeliveryState state); /// A courier's deliveries in `state` that changed at or after a time. List findByCourierAndStateAndUpdatedAtGreaterThanEqual(String courier, - DeliveryState state, long since); + DeliveryState state, Instant since); - long countByRequestedAtGreaterThanEqual(long since); + long countByRequestedAtGreaterThanEqual(Instant since); long countByStateIn(DeliveryState[] states); @@ -126,14 +127,14 @@ long countByCustomerAndStateOrCourierAndState(String customer, DeliveryState asC @Query("update Delivery r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from and r.customer = :customer") int moveAsCustomer(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now, @Param("customer") String customer); + @Param("to") DeliveryState to, @Param("now") Instant now, @Param("customer") String customer); /// Moves a delivery of `courier`'s from one of `from` to `to`. @Modifying(clearAutomatically = true) @Query("update Delivery r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from and r.courier = :courier") int moveAsCourier(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now, @Param("courier") String courier); + @Param("to") DeliveryState to, @Param("now") Instant now, @Param("courier") String courier); // tag::savor-delivery-move[] /// Takes an offer made to `courier`: refused once the offer has lapsed, as @@ -143,7 +144,7 @@ int moveAsCourier(@Param("id") String id, @Param("from") DeliveryState[] from, + "where r.id = :id and r.state in :from and r.courier = :courier " + "and r.offerExpiresAt >= :now") int takeOffer(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now, @Param("courier") String courier); + @Param("to") DeliveryState to, @Param("now") Instant now, @Param("courier") String courier); // end::savor-delivery-move[] /// Gives a delivery of `courier`'s back to be offered again, writing @@ -152,7 +153,7 @@ int takeOffer(@Param("id") String id, @Param("from") DeliveryState[] from, @Query("update Delivery r set r.state = :to, r.updatedAt = :now, r.courier = :newCourier " + "where r.id = :id and r.state in :from and r.courier = :courier") int giveBack(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now, @Param("courier") String courier, + @Param("to") DeliveryState to, @Param("now") Instant now, @Param("courier") String courier, @Param("newCourier") String newCourier); /// Holds `customer`'s delivery while it is in one of `states`, answering 0 when @@ -172,15 +173,15 @@ int holdWhile(@Param("id") String id, @Param("customer") String customer, @Query("update Delivery r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from") int moveByServer(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now); + @Param("to") DeliveryState to, @Param("now") Instant now); /// Offers a delivery to `courier` until `expiresAt`. @Modifying(clearAutomatically = true) @Query("update Delivery r set r.state = :to, r.updatedAt = :now, r.courier = :courier, " + "r.offerExpiresAt = :expiresAt where r.id = :id and r.state in :from") int offer(@Param("id") String id, @Param("from") DeliveryState[] from, - @Param("to") DeliveryState to, @Param("now") long now, @Param("courier") String courier, - @Param("expiresAt") long expiresAt); + @Param("to") DeliveryState to, @Param("now") Instant now, @Param("courier") String courier, + @Param("expiresAt") Instant expiresAt); // ----------------------------------------------------------- the rest @@ -201,7 +202,7 @@ int offer(@Param("id") String id, @Param("from") DeliveryState[] from, @Query("select r from Delivery r where r.state = 'COMPLETED' " + "and (r.paymentStatus = 'PENDING' or r.paymentStatus = 'AUTHORIZED') " + "and r.updatedAt < :before and r.updatedAt > :after order by r.updatedAt asc") - List unsettled(@Param("after") long after, @Param("before") long before, + List unsettled(@Param("after") Instant after, @Param("before") Instant before, PageRequest page); /// Records how the charge for a delivery came out. A statement of its own and @@ -263,13 +264,13 @@ List unsettled(@Param("after") long after, @Param("before") long befor @Query("select count(r), coalesce(sum(r.courierCents), 0) from Delivery r " + "where r.courier = :courier and r.state = 'COMPLETED' and r.paymentStatus = 'PAID' " + "and r.updatedAt >= :since") - Object[] paidTotalsSince(@Param("courier") String courier, @Param("since") long since); + Object[] paidTotalsSince(@Param("courier") String courier, @Param("since") Instant since); /// What the courier's share of their completed, paid deliveries came to since /// a time. @Query("select coalesce(sum(r.courierCents), 0) from Delivery r where r.courier = :courier " + "and r.state = 'COMPLETED' and r.paymentStatus = 'PAID' and r.updatedAt >= :since") - Long paidSince(@Param("courier") String courier, @Param("since") long since); + Long paidSince(@Param("courier") String courier, @Param("since") Instant since); /// The courier's share of the fares of every delivery they completed and that /// was paid for -- in cash, or by a card whose charge came back. A charge @@ -302,7 +303,7 @@ List unsettled(@Param("after") long after, @Param("before") long befor @Query("select r.id from Delivery r where r.courier = :courier and r.state = 'COMPLETED' " + "and r.updatedAt >= :since and r.methodId <> 'cash' and r.paymentStatus = 'PAID' " + "and r.id in (select p.deliveryId from Payment p where p.tipRef <> '')") - List tipChargedSince(@Param("courier") String courier, @Param("since") long since); + List tipChargedSince(@Param("courier") String courier, @Param("since") Instant since); /// What customers paid in fares for deliveries in `state` whose payment is `paid`. @Query("select coalesce(sum(r.fareCents), 0) from Delivery r " @@ -312,17 +313,17 @@ List unsettled(@Param("after") long after, @Param("before") long befor /// The fares of the deliveries in `state` asked for since `since`, paid or not. @Query("select coalesce(sum(r.fareCents), 0) from Delivery r " + "where r.requestedAt >= :since and r.state = :state") - Long faresSince(@Param("since") long since, @Param("state") DeliveryState state); + Long faresSince(@Param("since") Instant since, @Param("state") DeliveryState state); /// The deliveries asked for since `since`, counted by state: `{state, count}`. @Query("select r.state, count(r) from Delivery r where r.requestedAt >= :since group by r.state") - List countByState(@Param("since") long since); + List countByState(@Param("since") Instant since); /// The deliveries in `state` asked for since `since`, counted by courier: /// `{courier, count}`. @Query("select r.courier, count(r) from Delivery r where r.requestedAt >= :since " + "and r.state = :state group by r.courier") - List countByCourier(@Param("since") long since, @Param("state") DeliveryState state); + List countByCourier(@Param("since") Instant since, @Param("state") DeliveryState state); /// One row for each delivery asked for since `since`: `{id, requestedAt, /// state, fareCents, paymentStatus}`. @@ -335,7 +336,7 @@ List unsettled(@Param("after") long after, @Param("before") long befor /// word does not see those as one expression. @Query("select r.id, r.requestedAt, r.state, r.fareCents, r.paymentStatus from Delivery r " + "where r.requestedAt >= :since") - List timeline(@Param("since") long since); + List timeline(@Param("since") Instant since); /// What a customer paid for deliveries in `state` whose payment is `paid`: /// `{fares, fees, tips}`. diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/LiveTicketRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/LiveTicketRepository.java index 28eda4163e2..88d51bbd62f 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/LiveTicketRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/LiveTicketRepository.java @@ -21,6 +21,7 @@ import com.codename1.orm.repository.CrudRepository; import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.LiveTicket; +import java.time.Instant; /// The tickets that open a live connection. Only the hash of a ticket is /// stored, and it is the row's key. @@ -33,7 +34,7 @@ public interface LiveTicketRepository extends CrudRepository int deleteByTicketHash(String ticketHash); /// Deletes the tickets that went stale before `now`. - int deleteByExpiresAtLessThan(long now); + int deleteByExpiresAtLessThan(Instant now); int deleteByUsername(String username); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/ModerationEventRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/ModerationEventRepository.java index c26c87168d8..2b7d5db2ee7 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/ModerationEventRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/ModerationEventRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.ModerationEvent; +import java.time.Instant; import java.util.List; /// The record of what the admins did to each account. @@ -32,7 +33,7 @@ public interface ModerationEventRepository extends CrudRepository findTop100ByUsernameOrderByCreatedAtDescIdAsc(String username); diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentMethodRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentMethodRepository.java index 38dd2ce9c24..6f7c4e4a202 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentMethodRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentMethodRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.PaymentMethod; +import java.time.Instant; import java.util.List; /// The cards accounts saved. @@ -42,7 +43,7 @@ public interface PaymentMethodRepository extends CrudRepository { @Query("update Payment p set p.status = :status, p.refundedAt = :at " + "where p.deliveryId = :id and p.status = 'REFUND_PENDING'") int endRefund(@Param("id") String deliveryId, @Param("status") String status, - @Param("at") long at); + @Param("at") Instant at); } diff --git a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentSetupRepository.java b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentSetupRepository.java index 9f6aa508e46..e0bbc2b43e8 100644 --- a/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentSetupRepository.java +++ b/scripts/savor/backend/src/main/java/com/codenameone/examples/savor/repository/PaymentSetupRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.savor.domain.PaymentSetup; +import java.time.Instant; /// The card setups accounts began with the payment processor. @Repository(entity = PaymentSetup.class, key = String.class) @@ -39,7 +40,7 @@ public interface PaymentSetupRepository extends CrudRepository { /// When each account made since `since` was made. @Query("select p.createdAt from Profile p where p.createdAt >= :since") - List signUps(@Param("since") long since); + List signUps(@Param("since") Instant since); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/account/Accounts.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/account/Accounts.java index 821c571194d..060dbda2b2b 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/account/Accounts.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/account/Accounts.java @@ -36,6 +36,7 @@ import com.codenameone.examples.skirmish.rules.Deck; import com.codenameone.examples.skirmish.shop.Catalog; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -91,8 +92,8 @@ public void create(String username, String password, String name, boolean admin) p.setDeck(Lists.join(Deck.starter())); p.setOwned(Catalog.DEFAULT_ARENA + "," + Catalog.DEFAULT_EMOTES); p.setArena(Catalog.DEFAULT_ARENA); - p.setCreatedAt(Clock.now()); - p.setLastSeen(Clock.now()); + p.setCreatedAt(Instant.now()); + p.setLastSeen(Instant.now()); profiles.insert(p); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/AdminEndpoint.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/AdminEndpoint.java index 61124b57830..16e016b7819 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/AdminEndpoint.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/AdminEndpoint.java @@ -55,6 +55,7 @@ import com.codenameone.examples.skirmish.social.Insights; import com.codenameone.examples.skirmish.social.Pipelines; import com.codenameone.examples.skirmish.social.Promotion; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -96,7 +97,7 @@ public AdminEndpoint(Accounts accounts, ProfileRepository profiles, MatchRecordR @Override @Transactional(readOnly = true) public AdminStatsDto stats() throws Exception { - long today = Clock.dayOf(Clock.now()); + Instant today = Instant.ofEpochMilli(Clock.dayOf(Clock.now())); int gems = 0; List sold = purchases.since(today); for (StorePurchase s : sold) { @@ -104,7 +105,7 @@ public AdminStatsDto stats() throws Exception { } return new AdminStatsDto((int) profiles.count(), rooms.online(), rooms.live().size(), (int) matches.countByEndedAtGreaterThan(today), (int) flags.pendingCount(), - (int) count(profiles.suspended(Clock.now())), sold.size(), gems); + (int) count(profiles.suspended(Instant.now())), sold.size(), gems); } @Override diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Flags.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Flags.java index b6778461f35..dc848a877d7 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Flags.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Flags.java @@ -35,6 +35,7 @@ import com.codenameone.examples.skirmish.repository.MatchRecordRepository; import com.codenameone.examples.skirmish.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -115,7 +116,7 @@ Flag store(String username, String kind, String reason, String matchId, String r f.setReason(reason); f.setMatchId(matchId); f.setReporter(reporter); - f.setCreatedAt(Clock.now()); + f.setCreatedAt(Instant.now()); f.setPending(true); flags.insert(f); Profile p = profiles.findById(username); @@ -168,7 +169,7 @@ public long pendingCount() { static FlagDto toDto(Flag f, Profile p) { return new FlagDto(f.getId(), f.getUsername(), p == null ? f.getUsername() : p.getDisplayName(), - f.getKind(), f.getReason(), f.getMatchId(), f.getReporter(), f.getCreatedAt(), f.isPending()); + f.getKind(), f.getReason(), f.getMatchId(), f.getReporter(), f.getCreatedAt().toEpochMilli(), f.isPending()); } } // end::skirmish-flags[] diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Moderation.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Moderation.java index 418a5f3a1c6..265d12a3b46 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Moderation.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/admin/Moderation.java @@ -37,6 +37,7 @@ import com.codenameone.examples.skirmish.repository.ProfileRepository; import com.codenameone.examples.skirmish.shop.Catalog; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -101,7 +102,7 @@ boolean apply(String admin, String username, String action, String reason, int d if (days < 1 || days > 365) { throw new ResponseStatusException(400, "Suspend for 1 to 365 days"); } - p.setSuspendedUntil(Clock.now() + days * Clock.DAY); + p.setSuspendedUntil(Instant.now().plusMillis(days * Clock.DAY)); accounts.setEnabled(username, false); closes = true; } else if (BAN.equals(action)) { @@ -110,7 +111,7 @@ boolean apply(String admin, String username, String action, String reason, int d closes = true; } else if (UNBAN.equals(action)) { p.setBanned(false); - p.setSuspendedUntil(0); + p.setSuspendedUntil(Instant.EPOCH); accounts.setEnabled(username, true); } else if (RESET_TROPHIES.equals(action)) { p.setTrophies(0); @@ -125,7 +126,7 @@ boolean apply(String admin, String username, String action, String reason, int d a.setUsername(username); a.setAction(SUSPEND.equals(action) ? SUSPEND + " " + days + "d" : action); a.setReason(reason); - a.setCreatedAt(Clock.now()); + a.setCreatedAt(Instant.now()); audit.insert(a); return closes; } @@ -140,8 +141,9 @@ public void liftExpired() { public int lift(long now) { int lifted = 0; for (Profile p : profiles.findAll()) { - if (!p.isBanned() && p.getSuspendedUntil() > 0 && p.getSuspendedUntil() <= now) { - p.setSuspendedUntil(0); + if (!p.isBanned() && p.getSuspendedUntil().isAfter(Instant.EPOCH) + && p.getSuspendedUntil().toEpochMilli() <= now) { + p.setSuspendedUntil(Instant.EPOCH); profiles.save(p); accounts.setEnabled(p.getUsername(), true); lifted++; @@ -164,7 +166,7 @@ private static List toDtos(List rows) { List out = new ArrayList(); for (AdminAction a : rows) { out.add(new AuditDto(a.getId(), a.getAdmin(), a.getUsername(), a.getAction(), a.getReason(), - a.getCreatedAt())); + a.getCreatedAt().toEpochMilli())); } return out; } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/AdminAction.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/AdminAction.java index 3d371e9559a..253ca75d0b7 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/AdminAction.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/AdminAction.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One entry of the admin audit log. Rows are only ever inserted. @Entity @@ -42,7 +43,7 @@ public class AdminAction { private String reason = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public AdminAction() { } @@ -87,11 +88,11 @@ public void setReason(String reason) { this.reason = reason; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Broadcast.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Broadcast.java index 0530c15a4b4..a149cda2e3a 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Broadcast.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Broadcast.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A push an operator sent to a segment of players, kept as the record of it. @Entity @@ -54,7 +55,7 @@ public class Broadcast { private String sentBy = ""; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; public Broadcast() { } @@ -131,11 +132,11 @@ public void setSentBy(String sentBy) { this.sentBy = sentBy; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Flag.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Flag.java index 34d8b6d41f2..10f3e3976d3 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Flag.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Flag.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A reason for an admin to look at a player: an opponent's report or something the server detected. @Entity @@ -45,7 +46,7 @@ public class Flag { private String reporter = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) private boolean pending; @@ -104,11 +105,11 @@ public void setReporter(String reporter) { this.reporter = reporter; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgeAsset.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgeAsset.java index f5e11a9f632..42d97421f1c 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgeAsset.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgeAsset.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An uploaded model or image, stored once under the SHA-256 of its bytes. @Entity @@ -51,7 +52,7 @@ public class ForgeAsset { private String data = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public ForgeAsset() { } @@ -120,11 +121,11 @@ public void setData(String data) { this.data = data; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePack.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePack.java index e2c1f8ab013..9d823f23415 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePack.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePack.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A pack in the Forge: its owner's draft and, once published, which version is /// current. The versions themselves are [ForgePackVersion] rows. @@ -82,10 +83,10 @@ public class ForgePack { private boolean pendingAssets; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public ForgePack() { } @@ -234,19 +235,19 @@ public void setPendingAssets(boolean pendingAssets) { this.pendingAssets = pendingAssets; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePackVersion.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePackVersion.java index c88fca804af..cc7b5a2f3a0 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePackVersion.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ForgePackVersion.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One published version of a pack, kept for good: replays and mission results /// name the version they were played on. @@ -43,7 +44,7 @@ public class ForgePackVersion { private String content = ""; @Column(nullable = false) - private long publishedAt; + private Instant publishedAt = Instant.EPOCH; public ForgePackVersion() { } @@ -88,11 +89,11 @@ public void setContent(String content) { this.content = content; } - public long getPublishedAt() { + public Instant getPublishedAt() { return publishedAt; } - public void setPublishedAt(long publishedAt) { + public void setPublishedAt(Instant publishedAt) { this.publishedAt = publishedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/GameTicket.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/GameTicket.java index 3155f92e400..4d6779bc905 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/GameTicket.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/GameTicket.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A ticket for one connection to the live channel, as its hash. @Entity @@ -33,7 +34,7 @@ public class GameTicket { private String username = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public GameTicket() { } @@ -54,11 +55,11 @@ public void setUsername(String username) { this.username = username; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MatchRecord.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MatchRecord.java index 977ff589d67..70077982f07 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MatchRecord.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MatchRecord.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A finished match: who played, how it ended, and the replay that reproduces it. @Entity @@ -60,7 +61,7 @@ public class MatchRecord { private int ticks; @Column(nullable = false) - private long endedAt; + private Instant endedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(16)") private String rulesVersion = ""; @@ -159,11 +160,11 @@ public void setTicks(int ticks) { this.ticks = ticks; } - public long getEndedAt() { + public Instant getEndedAt() { return endedAt; } - public void setEndedAt(long endedAt) { + public void setEndedAt(Instant endedAt) { this.endedAt = endedAt; } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MissionStars.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MissionStars.java index 51d64019762..c72add2c1b9 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MissionStars.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/MissionStars.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A player's best on one mission, and how many of those stars were paid for. @Entity @@ -48,7 +49,7 @@ public class MissionStars { private int plays; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public MissionStars() { } @@ -109,11 +110,11 @@ public void setPlays(int plays) { this.plays = plays; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Pipeline.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Pipeline.java index 7eeb8b2d099..2eaeee1e657 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Pipeline.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Pipeline.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An engagement pipeline: a query over the players and what to do for each /// one who matches. See `social.Pipelines`. @@ -61,7 +62,7 @@ public class Pipeline { private int reached; @Column(nullable = false) - private long lastRun; + private Instant lastRun = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String createdBy = ""; @@ -154,11 +155,11 @@ public void setReached(int reached) { this.reached = reached; } - public long getLastRun() { + public Instant getLastRun() { return lastRun; } - public void setLastRun(long lastRun) { + public void setLastRun(Instant lastRun) { this.lastRun = lastRun; } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PipelineHit.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PipelineHit.java index 730947c1b30..825e22a5d20 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PipelineHit.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PipelineHit.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// When a pipeline last acted on a player, so it waits its cool-down before /// acting on them again. The id is the pipeline id, a colon and the username. @@ -37,7 +38,7 @@ public class PipelineHit { private String username = ""; @Column(nullable = false) - private long hitAt; + private Instant hitAt = Instant.EPOCH; public String getId() { return id; @@ -63,11 +64,11 @@ public void setUsername(String username) { this.username = username; } - public long getHitAt() { + public Instant getHitAt() { return hitAt; } - public void setHitAt(long hitAt) { + public void setHitAt(Instant hitAt) { this.hitAt = hitAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Profile.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Profile.java index 91b48bbf849..ce8ca0d36d9 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Profile.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Profile.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A player's account data beyond the sign-in record: rating, currencies, deck, cosmetics and moderation state. @Entity @@ -66,16 +67,16 @@ public class Profile { private boolean muted; @Column(nullable = false) - private long suspendedUntil; + private Instant suspendedUntil = Instant.EPOCH; @Column(nullable = false) private boolean banned; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long lastSeen; + private Instant lastSeen = Instant.EPOCH; @Column(nullable = false) private long adDay; @@ -193,11 +194,11 @@ public void setMuted(boolean muted) { this.muted = muted; } - public long getSuspendedUntil() { + public Instant getSuspendedUntil() { return suspendedUntil; } - public void setSuspendedUntil(long suspendedUntil) { + public void setSuspendedUntil(Instant suspendedUntil) { this.suspendedUntil = suspendedUntil; } @@ -209,19 +210,19 @@ public void setBanned(boolean banned) { this.banned = banned; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getLastSeen() { + public Instant getLastSeen() { return lastSeen; } - public void setLastSeen(long lastSeen) { + public void setLastSeen(Instant lastSeen) { this.lastSeen = lastSeen; } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PushDevice.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PushDevice.java index f61eafee87d..0626603248f 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PushDevice.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/PushDevice.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A device an account is sent push notifications on. /// @@ -46,7 +47,7 @@ public class PushDevice { private String platform = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public PushDevice() { } @@ -91,11 +92,11 @@ public void setPlatform(String platform) { this.platform = platform; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Referral.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Referral.java index da3343c91a8..916de9aea08 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Referral.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Referral.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A player who joined through someone's invite, keyed by that player: one /// inviter each, for good. @@ -52,10 +53,10 @@ public class Referral { private boolean rewarded; @Column(nullable = false) - private long joinedAt; + private Instant joinedAt = Instant.EPOCH; @Column(nullable = false) - private long playedAt; + private Instant playedAt = Instant.EPOCH; public Referral() { } @@ -124,19 +125,19 @@ public void setRewarded(boolean rewarded) { this.rewarded = rewarded; } - public long getJoinedAt() { + public Instant getJoinedAt() { return joinedAt; } - public void setJoinedAt(long joinedAt) { + public void setJoinedAt(Instant joinedAt) { this.joinedAt = joinedAt; } - public long getPlayedAt() { + public Instant getPlayedAt() { return playedAt; } - public void setPlayedAt(long playedAt) { + public void setPlayedAt(Instant playedAt) { this.playedAt = playedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ReferralCode.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ReferralCode.java index 52e674981e2..55faaeae845 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ReferralCode.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/ReferralCode.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A player's invite code: what their links carry, so the server knows whose friend /// has joined. @@ -34,7 +35,7 @@ public class ReferralCode { private String username = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public ReferralCode() { } @@ -55,11 +56,11 @@ public void setUsername(String username) { this.username = username; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Spotlight.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Spotlight.java index 36f0c791350..ec57f9279c1 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Spotlight.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/Spotlight.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The home screen's banner. One row, `home`. @Entity @@ -42,7 +43,7 @@ public class Spotlight { private String updatedBy = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public Spotlight() { } @@ -87,11 +88,11 @@ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/StorePurchase.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/StorePurchase.java index 3941f4203e3..fab55e39ac5 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/StorePurchase.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/domain/StorePurchase.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A verified store transaction. The key is the store's transaction id, so a receipt can only ever be redeemed once. @Entity @@ -42,7 +43,7 @@ public class StorePurchase { private int gems; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public StorePurchase() { } @@ -87,11 +88,11 @@ public void setGems(int gems) { this.gems = gems; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/forge/Forge.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/forge/Forge.java index 940278c771f..6f37bc1269a 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/forge/Forge.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/forge/Forge.java @@ -65,6 +65,7 @@ import com.codenameone.examples.skirmish.rules.forge.Samples; import com.codenameone.examples.skirmish.rules.forge.Validator; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -140,7 +141,7 @@ public void seedOfficial() throws IOException { p = new ForgePack(); p.setId(official.id); p.setOwner(SYSTEM); - p.setCreatedAt(Clock.now()); + p.setCreatedAt(Instant.now()); } else if (!SYSTEM.equals(p.getOwner())) { return; } @@ -226,7 +227,7 @@ public PackSummaryDto saveDraft(String username, String content) throws IOExcept p.setId(pack.id); p.setOwner(username); p.setStatus(DRAFT); - p.setCreatedAt(Clock.now()); + p.setCreatedAt(Instant.now()); fillDraft(p, pack, username); packs.insert(p); } else { @@ -263,7 +264,7 @@ public PackSummaryDto delete(String username, boolean admin, String id) throws I } // Versions are kept: a replay names the version it was played on. p.setStatus(DELETED); - p.setUpdatedAt(Clock.now()); + p.setUpdatedAt(Instant.now()); packs.save(p); return summary(p); } @@ -368,7 +369,7 @@ public AssetDto upload(String username, AssetUploadDto file) throws IOException if (a != null) { return asset(a, false); } - long since = Clock.now() - Clock.DAY; + Instant since = Instant.now().minusMillis(Clock.DAY); if (assets.countByOwnerAndCreatedAtGreaterThan(username, since) >= MAX_UPLOADS_PER_DAY) { throw new ResponseStatusException(429, "That is enough uploads for today"); } @@ -381,7 +382,7 @@ public AssetDto upload(String username, AssetUploadDto file) throws IOException a.setStatus(PENDING); a.setAnimations(clip(join(animations), 2000)); a.setData(file.data()); - a.setCreatedAt(Clock.now()); + a.setCreatedAt(Instant.now()); assets.insert(a); return asset(a, false); } @@ -448,7 +449,7 @@ public MissionOutcomeDto result(String username, String encoded) throws IOExcept row.setStars(Math.max(row.getStars(), won)); int newStars = Math.max(0, won - row.getPaidStars()); row.setPaidStars(row.getPaidStars() + newStars); - row.setUpdatedAt(Clock.now()); + row.setUpdatedAt(Instant.now()); stars.save(row); p.setPlays(p.getPlays() + 1); packs.save(p); @@ -514,7 +515,7 @@ public PackSummaryDto packAction(String admin, String id, String action, String } else { throw new ResponseStatusException(400, "Unknown action"); } - p.setUpdatedAt(Clock.now()); + p.setUpdatedAt(Instant.now()); packs.save(p); record(admin, id, "PACK_" + action, reason); return summary(p); @@ -565,7 +566,7 @@ private void publishVersion(ForgePack p, ContentPack pack, boolean insert) throw v.setVersion(version); v.setHash(hash); v.setContent(canonical); - v.setPublishedAt(Clock.now()); + v.setPublishedAt(Instant.now()); versions.insert(v); p.setVersion(version); p.setHash(hash); @@ -578,7 +579,7 @@ private void publishVersion(ForgePack p, ContentPack pack, boolean insert) throw if (!HIDDEN.equals(p.getStatus())) { p.setStatus(PUBLISHED); } - p.setUpdatedAt(Clock.now()); + p.setUpdatedAt(Instant.now()); if (insert) { packs.insert(p); } else { @@ -659,7 +660,7 @@ private void fillDraft(ForgePack p, ContentPack pack, String username) throws IO p.setMissions(pack.missions.size()); p.setCards(pack.cards.size()); } - p.setUpdatedAt(Clock.now()); + p.setUpdatedAt(Instant.now()); } private static ContentPack parse(String content) { @@ -717,7 +718,7 @@ private void record(String admin, String target, String action, String reason) t a.setUsername(clip("pack:" + target, 190)); a.setAction(clip(action, 24)); a.setReason(clip(reason == null ? "" : reason, 255)); - a.setCreatedAt(Clock.now()); + a.setCreatedAt(Instant.now()); audit.insert(a); } @@ -737,7 +738,7 @@ static PackSummaryDto summary(ForgePack p) { int rating = p.getRatingCount() == 0 ? 0 : (p.getRatingSum() * 10 + p.getRatingCount() / 2) / p.getRatingCount(); return new PackSummaryDto(p.getId(), p.getName(), p.getAuthor(), p.getOwner(), p.getDescription(), p.getVersion(), p.getHash(), p.isOfficial(), p.getStatus(), p.getPlays(), rating, - p.getRatingCount(), p.getMissions(), p.getCards(), p.isPendingAssets(), p.getUpdatedAt()); + p.getRatingCount(), p.getMissions(), p.getCards(), p.isPendingAssets(), p.getUpdatedAt().toEpochMilli()); } private static AssetDto asset(ForgeAsset a, boolean withData) { diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameEndpoint.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameEndpoint.java index ce07979d380..27e652595cb 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameEndpoint.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameEndpoint.java @@ -92,7 +92,7 @@ public static List summaries(String me, List rows) out.add(new MatchSummaryDto(m.getId(), seat == 0 ? m.getPlayer1() : m.getPlayer0(), seat == 0 ? m.getName1() : m.getName0(), result, seat == 0 ? m.getCrowns0() : m.getCrowns1(), seat == 0 ? m.getCrowns1() : m.getCrowns0(), - seat == 0 ? m.getTrophies0() : m.getTrophies1(), m.getEndedAt(), m.getTicks())); + seat == 0 ? m.getTrophies0() : m.getTrophies1(), m.getEndedAt().toEpochMilli(), m.getTicks())); } return out; } @@ -107,7 +107,7 @@ public ReplayDto replay(String id) throws Exception { throw new ResponseStatusException(404, "No such match"); } return new ReplayDto(m.getId(), m.getPlayer0(), m.getPlayer1(), m.getName0(), m.getName1(), - m.getResult(), m.getCrowns0(), m.getCrowns1(), m.getReplay(), m.getRulesVersion(), m.getEndedAt()); + m.getResult(), m.getCrowns0(), m.getCrowns1(), m.getReplay(), m.getRulesVersion(), m.getEndedAt().toEpochMilli()); } @Override diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameTickets.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameTickets.java index 466e8db8bd4..149bfb0ae07 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameTickets.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/GameTickets.java @@ -28,6 +28,7 @@ import com.codenameone.examples.skirmish.repository.GameTicketRepository; import java.io.IOException; +import java.time.Instant; /// Tickets for the live channel. /// @@ -58,7 +59,7 @@ public TicketDto issue(String username) throws IOException { GameTicket row = new GameTicket(); row.setTicketHash(Ids.sha256(ticket)); row.setUsername(username); - row.setExpiresAt(System.currentTimeMillis() + TICKET_SECONDS * 1000L); + row.setExpiresAt(Instant.now().plusMillis(TICKET_SECONDS * 1000L)); tickets.insert(row); return new TicketDto(ticket, TICKET_SECONDS); } @@ -78,11 +79,11 @@ public String redeem(String ticket) throws IOException { return null; } String username = row.getUsername(); - long expiresAt = row.getExpiresAt(); + Instant expiresAt = row.getExpiresAt(); // One delete statement: the count it answers is what says this // connection, and not another presenting the same ticket, used it. int removed = tickets.deleteByTicketHash(hash); - if (removed != 1 || expiresAt < System.currentTimeMillis()) { + if (removed != 1 || expiresAt.isBefore(Instant.now())) { return null; } return username; @@ -92,7 +93,7 @@ public String redeem(String ticket) throws IOException { @Scheduled(fixedDelay = 60000, initialDelay = 60000) @Transactional public void sweep() throws IOException { - tickets.deleteByExpiresAtLessThan(System.currentTimeMillis()); + tickets.deleteByExpiresAtLessThan(Instant.now()); } /// Forgets the tickets of an account that is being closed. diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/Results.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/Results.java index ec5c1485c6f..bc63b076cad 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/Results.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/game/Results.java @@ -35,6 +35,7 @@ import com.codenameone.examples.skirmish.rules.RulesVersion; import com.codenameone.examples.skirmish.social.Referrals; import java.io.IOException; +import java.time.Instant; /// Records a finished match: the replay, and what it did to each player. // tag::skirmish-results[] @@ -134,7 +135,7 @@ Outcome[] save(MatchRoom room) throws IOException { p.setTrophies(p.getTrophies() + trophies); p.setCoins(p.getCoins() + coins); p.setLeftStreak(room.forfeit == i ? p.getLeftStreak() + 1 : 0); - p.setLastSeen(Clock.now()); + p.setLastSeen(Instant.now()); progression.afterMatch(p, result == i, result == Match.DRAW, room.match.player(i).crowns(), cards[i], spells[i]); profiles.save(p); @@ -152,7 +153,7 @@ Outcome[] save(MatchRoom room) throws IOException { m.setTrophies0(out[0].trophies); m.setTrophies1(out[1].trophies); m.setTicks(room.match.tick()); - m.setEndedAt(Clock.now()); + m.setEndedAt(Instant.now()); m.setRulesVersion(RulesVersion.ID); m.setReplay(replay.encode()); matches.insert(m); diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/push/PushDevices.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/push/PushDevices.java index e6a69f3e49a..6509bb30565 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/push/PushDevices.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/push/PushDevices.java @@ -30,6 +30,7 @@ import com.codenameone.examples.skirmish.repository.PushDeviceRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -112,7 +113,7 @@ private void makeRoom(String username) { while (held.size() >= MAX_PER_ACCOUNT) { PushDevice oldest = held.get(0); for (PushDevice each : held) { - if (each.getUpdatedAt() < oldest.getUpdatedAt()) { + if (each.getUpdatedAt().isBefore(oldest.getUpdatedAt())) { oldest = each; } } @@ -151,7 +152,7 @@ public List targetsOf(String username) { private static void fill(PushDevice row, String username, PushDeviceDto device, long now) { row.setUsername(username); row.setPlatform(Text.optional(device.platform(), 32, "the platform")); - row.setUpdatedAt(now); + row.setUpdatedAt(Instant.ofEpochMilli(now)); } /// The device as a target of the push service, which also spells its diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/BroadcastRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/BroadcastRepository.java index 4cc3112a94e..5686c2c7e47 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/BroadcastRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/BroadcastRepository.java @@ -23,6 +23,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.Broadcast; +import java.time.Instant; import java.util.List; @Repository(entity = Broadcast.class, key = String.class) @@ -30,5 +31,5 @@ public interface BroadcastRepository extends CrudRepository { @Query("select b from Broadcast b order by b.sentAt desc, b.id asc") List newest(PageRequest page); - long countBySentAtGreaterThan(long since); + long countBySentAtGreaterThan(Instant since); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ForgeAssetRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ForgeAssetRepository.java index c18fe584309..9a252a5160c 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ForgeAssetRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ForgeAssetRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.ForgeAsset; +import java.time.Instant; import java.util.List; @Repository(entity = ForgeAsset.class, key = String.class) @@ -31,5 +32,5 @@ public interface ForgeAssetRepository extends CrudRepository @Query("select a from ForgeAsset a where a.status = :s order by a.createdAt asc, a.sha256 asc") List inStatus(@Param("s") String status, PageRequest page); - long countByOwnerAndCreatedAtGreaterThan(String owner, long since); + long countByOwnerAndCreatedAtGreaterThan(String owner, Instant since); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/GameTicketRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/GameTicketRepository.java index f86069e9dd2..ad1d9594f8b 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/GameTicketRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/GameTicketRepository.java @@ -21,6 +21,7 @@ import com.codename1.orm.repository.CrudRepository; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.GameTicket; +import java.time.Instant; /// The tickets that open a live connection. Only the hash of a ticket is /// stored, and it is the row's key. @@ -33,7 +34,7 @@ public interface GameTicketRepository extends CrudRepository int deleteByTicketHash(String ticketHash); /// Deletes the tickets that went stale before `now`. - int deleteByExpiresAtLessThan(long now); + int deleteByExpiresAtLessThan(Instant now); int deleteByUsername(String username); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/MatchRecordRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/MatchRecordRepository.java index c94f09d57e7..e9e8661499e 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/MatchRecordRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/MatchRecordRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.MatchRecord; +import java.time.Instant; import java.util.List; @Repository(entity = MatchRecord.class, key = String.class) @@ -32,8 +33,8 @@ public interface MatchRecordRepository extends CrudRepository of(@Param("u") String username, PageRequest page); - long countByEndedAtGreaterThan(long since); + long countByEndedAtGreaterThan(Instant since); @Query("select m from MatchRecord m where m.endedAt >= :since") - List since(@Param("since") long since); + List since(@Param("since") Instant since); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ProfileRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ProfileRepository.java index e2c501941fc..c4f02bddf2d 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ProfileRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/ProfileRepository.java @@ -25,6 +25,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.Profile; +import java.time.Instant; import java.util.List; @Repository(entity = Profile.class, key = String.class) @@ -44,15 +45,16 @@ public interface ProfileRepository extends CrudRepository { long countByFlaggedTrue(); @Query("select count(p) from Profile p where p.banned = true or p.suspendedUntil > :now") - Long suspended(@Param("now") long now); + Long suspended(@Param("now") Instant now); /// The players a broadcast reaches, a page at a time. Banned players are /// never sent anything; `seenBefore` and `joinedAfter` narrow it to the - /// lapsed and the new (pass 0 and `Long.MAX_VALUE` to leave them out). + /// lapsed and the new (pass `Instant.ofEpochMilli(Long.MAX_VALUE)` and + /// `Instant.ofEpochMilli(Long.MIN_VALUE)` to leave them out). @Query("select p from Profile p where p.banned = false and p.lastSeen < :seen and p.createdAt > :joined " + "order by p.username asc") - List audience(@Param("seen") long seenBefore, @Param("joined") long joinedAfter, PageRequest page); + List audience(@Param("seen") Instant seenBefore, @Param("joined") Instant joinedAfter, PageRequest page); @Query("select count(p) from Profile p where p.banned = false and p.lastSeen < :seen and p.createdAt > :joined") - Long audienceSize(@Param("seen") long seenBefore, @Param("joined") long joinedAfter); + Long audienceSize(@Param("seen") Instant seenBefore, @Param("joined") Instant joinedAfter); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/StorePurchaseRepository.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/StorePurchaseRepository.java index ecff245a83d..2e9421728fd 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/StorePurchaseRepository.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/repository/StorePurchaseRepository.java @@ -23,6 +23,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.skirmish.domain.StorePurchase; +import java.time.Instant; import java.util.List; @Repository(entity = StorePurchase.class, key = String.class) @@ -31,5 +32,5 @@ public interface StorePurchaseRepository extends CrudRepository of(@Param("u") String username); @Query("select s from StorePurchase s where s.createdAt >= :since") - List since(@Param("since") long since); + List since(@Param("since") Instant since); } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/shop/Shop.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/shop/Shop.java index a9339f80a96..0e448019e2f 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/shop/Shop.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/shop/Shop.java @@ -33,6 +33,7 @@ import com.codenameone.examples.skirmish.repository.ProfileRepository; import com.codenameone.examples.skirmish.repository.StorePurchaseRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -136,7 +137,7 @@ WalletDto redeem(String username, String store, ShopItemDto item, String transac row.setSku(item.sku()); int gems = Catalog.gems(item); row.setGems(gems); - row.setCreatedAt(Clock.now()); + row.setCreatedAt(Instant.now()); purchases.insert(row); if (gems > 0) { p.setGems(p.getGems() + gems); diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Audience.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Audience.java index 39fd4e0b0ec..3d41e789b5a 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Audience.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Audience.java @@ -118,9 +118,9 @@ public List filter(List all) { private int value(Profile p, String field) { switch (field) { case "daysAway": - return days(now - p.getLastSeen()); + return days(now - p.getLastSeen().toEpochMilli()); case "daysSinceJoin": - return days(now - p.getCreatedAt()); + return days(now - p.getCreatedAt().toEpochMilli()); case "trophies": return p.getTrophies(); case "battles": diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Insights.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Insights.java index 3830930bb64..bc56309d471 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Insights.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Insights.java @@ -36,6 +36,7 @@ import com.codenameone.examples.skirmish.repository.ProfileRepository; import com.codenameone.examples.skirmish.repository.ReferralRepository; import com.codenameone.examples.skirmish.repository.StorePurchaseRepository; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -80,15 +81,15 @@ public InsightsDto report(int days) { List all = profiles.findAll(); int[] joined = new int[n]; for (Profile p : all) { - bump(joined, first, p.getCreatedAt()); + bump(joined, first, p.getCreatedAt().toEpochMilli()); } int[] battles = new int[n]; List> fought = new ArrayList<>(); for (int i = 0; i < n; i++) { fought.add(new HashSet()); } - for (MatchRecord m : matches.since(first)) { - int d = dayIndex(first, m.getEndedAt(), n); + for (MatchRecord m : matches.since(Instant.ofEpochMilli(first))) { + int d = dayIndex(first, m.getEndedAt().toEpochMilli(), n); if (d >= 0) { battles[d]++; fought.get(d).add(m.getPlayer0()); @@ -106,10 +107,10 @@ public InsightsDto report(int days) { active[i] = fought.get(i).size(); } int[] gems = new int[n]; - List sales = purchases.since(0); + List sales = purchases.since(Instant.EPOCH); Set paid = new HashSet<>(); for (StorePurchase s : sales) { - int d = dayIndex(first, s.getCreatedAt(), n); + int d = dayIndex(first, s.getCreatedAt().toEpochMilli(), n); if (d >= 0) { gems[d] += s.getGems(); } @@ -149,9 +150,9 @@ private static List retention(List all, long now) { int cohort = 0; int back = 0; for (Profile p : all) { - if (p.getCreatedAt() <= now - span) { + if (p.getCreatedAt().toEpochMilli() <= now - span) { cohort++; - if (p.getLastSeen() - p.getCreatedAt() >= span) { + if (p.getLastSeen().toEpochMilli() - p.getCreatedAt().toEpochMilli() >= span) { back++; } } @@ -184,8 +185,8 @@ private static List bands(List all) { public QueryResultDto query(QueryDto q) { Audience audience = audience(q == null ? null : q.conditions()); List found = audience.filter(profiles.findAll()); - Collections.sort(found, (a, b) -> a.getLastSeen() < b.getLastSeen() ? -1 - : a.getLastSeen() > b.getLastSeen() ? 1 : a.getUsername().compareTo(b.getUsername())); + Collections.sort(found, (a, b) -> a.getLastSeen().isBefore(b.getLastSeen()) ? -1 + : a.getLastSeen().isAfter(b.getLastSeen()) ? 1 : a.getUsername().compareTo(b.getUsername())); List listed = new ArrayList<>(); for (int i = 0; i < found.size() && i < LISTED; i++) { listed.add(accounts.toDto(found.get(i))); @@ -197,7 +198,7 @@ public QueryResultDto query(QueryDto q) { /// the conditions may ask about. public Audience audience(List conditions) { Audience.check(conditions); - return Audience.of(conditions, purchases.since(0), referrals.findAll()); + return Audience.of(conditions, purchases.since(Instant.EPOCH), referrals.findAll()); } // end::skirmish-insights[] diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Pipelines.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Pipelines.java index 052009212fe..f94cf3aed94 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Pipelines.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Pipelines.java @@ -36,6 +36,7 @@ import com.codenameone.examples.skirmish.repository.PipelineRepository; import com.codenameone.examples.skirmish.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -108,7 +109,7 @@ public PipelineDto run(String id) throws IOException { for (Profile player : audience.filter(profiles.findAll())) { String key = p.getId() + ":" + player.getUsername(); PipelineHit hit = last.get(player.getUsername()); - if (hit != null && hit.getHitAt() > now - p.getCooldownDays() * Clock.DAY) { + if (hit != null && hit.getHitAt().toEpochMilli() > now - p.getCooldownDays() * Clock.DAY) { continue; } if (GEMS.equals(p.getAction())) { @@ -120,10 +121,10 @@ public PipelineDto run(String id) throws IOException { hit.setId(key); hit.setPipeline(p.getId()); hit.setUsername(player.getUsername()); - hit.setHitAt(now); + hit.setHitAt(Instant.ofEpochMilli(now)); hits.insert(hit); } else { - hit.setHitAt(now); + hit.setHitAt(Instant.ofEpochMilli(now)); hits.save(hit); } due.add(player.getUsername()); @@ -135,7 +136,7 @@ public PipelineDto run(String id) throws IOException { pushes.broadcast(due, Ids.next(), p.getTitle(), p.getBody(), p.getScreen(), "pipeline-" + p.getName()); } p.setReached(p.getReached() + due.size()); - p.setLastRun(now); + p.setLastRun(Instant.ofEpochMilli(now)); pipelines.save(p); return dto(p); } @@ -239,7 +240,7 @@ private static void check(PipelineDto d) { private static PipelineDto dto(Pipeline p) { List c = Audience.decode(p.getConditions()); return new PipelineDto(p.getId(), p.getName(), p.isEnabled(), c, p.getAction(), p.getTitle(), p.getBody(), - p.getScreen(), p.getAmount(), p.getCooldownDays(), p.getReached(), p.getLastRun()); + p.getScreen(), p.getAmount(), p.getCooldownDays(), p.getReached(), p.getLastRun().toEpochMilli()); } private void record(String admin, String action, String reason) throws IOException { @@ -249,7 +250,7 @@ private void record(String admin, String action, String reason) throws IOExcepti a.setUsername("promote"); a.setAction(action); a.setReason(reason.length() > 255 ? reason.substring(0, 255) : reason); - a.setCreatedAt(Clock.now()); + a.setCreatedAt(Instant.now()); audit.insert(a); } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Promotion.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Promotion.java index e90013eca96..f4c6f5d8a45 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Promotion.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Promotion.java @@ -40,6 +40,7 @@ import com.codenameone.examples.skirmish.repository.ReferralRepository; import com.codenameone.examples.skirmish.repository.SpotlightRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -121,7 +122,7 @@ public PromoteDto overview() throws IOException { sent.add(dto(b)); } return new PromoteDto((int) profiles.count(), - profiles.audienceSize(Long.MAX_VALUE, now - 7 * Clock.DAY).intValue(), + profiles.audienceSize(Instant.ofEpochMilli(Long.MAX_VALUE), Instant.ofEpochMilli(now - 7 * Clock.DAY)).intValue(), (int) referrals.count(), referrals.inState(Referrals.PLAYED).intValue(), top, sent, spotlightOf()); } @@ -138,7 +139,7 @@ public BroadcastDto audience(BroadcastDto b) throws IOException { public BroadcastDto broadcast(String admin, BroadcastDto b) throws IOException { check(b, true); long now = Clock.now(); - if (broadcasts.countBySentAtGreaterThan(now - Clock.DAY) >= MAX_BROADCASTS_PER_DAY) { + if (broadcasts.countBySentAtGreaterThan(Instant.ofEpochMilli(now - Clock.DAY)) >= MAX_BROADCASTS_PER_DAY) { throw new ResponseStatusException(429, "At most " + MAX_BROADCASTS_PER_DAY + " broadcasts a day: players who are pushed too often switch notifications off"); } @@ -157,7 +158,7 @@ public BroadcastDto broadcast(String admin, BroadcastDto b) throws IOException { row.setCampaign(campaign.length() > 40 ? campaign.substring(0, 40) : campaign); row.setTargets(reached); row.setSentBy(admin); - row.setSentAt(now); + row.setSentAt(Instant.ofEpochMilli(now)); broadcasts.insert(row); record(admin, "BROADCAST", b.segment() + ": " + b.title().trim()); return dto(row); @@ -185,7 +186,7 @@ public SpotlightDto spotlight(String admin, SpotlightDto s) throws IOException { row.setPackId(s.packId() == null ? "" : s.packId().trim()); row.setScreen(screen(s.screen())); row.setUpdatedBy(admin); - row.setUpdatedAt(Clock.now()); + row.setUpdatedAt(Instant.now()); if (fresh) { spotlights.insert(row); } else { @@ -198,7 +199,7 @@ public SpotlightDto spotlight(String admin, SpotlightDto s) throws IOException { private SpotlightDto spotlightOf() { Spotlight s = spotlights.findById(HOME); return s == null ? new SpotlightDto("", "", "", 0) - : new SpotlightDto(s.getMessage(), s.getPackId(), s.getScreen(), s.getUpdatedAt()); + : new SpotlightDto(s.getMessage(), s.getPackId(), s.getScreen(), s.getUpdatedAt().toEpochMilli()); } private List audienceOf(BroadcastDto b) { @@ -216,8 +217,8 @@ private List audienceOf(BroadcastDto b) { return out; } long now = Clock.now(); - long seen = LAPSED.equals(b.segment()) ? now - b.days() * Clock.DAY : Long.MAX_VALUE; - long joined = NEW.equals(b.segment()) ? now - b.days() * Clock.DAY : Long.MIN_VALUE; + Instant seen = Instant.ofEpochMilli(LAPSED.equals(b.segment()) ? now - b.days() * Clock.DAY : Long.MAX_VALUE); + Instant joined = Instant.ofEpochMilli(NEW.equals(b.segment()) ? now - b.days() * Clock.DAY : Long.MIN_VALUE); for (int page = 0; out.size() < MAX_AUDIENCE; page++) { List rows = profiles.audience(seen, joined, new PageRequest(page, PAGE)); for (Profile p : rows) { @@ -268,7 +269,7 @@ private static BroadcastDto with(BroadcastDto b, int targets, String by, long at private static BroadcastDto dto(Broadcast b) { return new BroadcastDto(b.getId(), b.getSegment(), b.getDays(), b.getTitle(), b.getBody(), b.getScreen(), - b.getCampaign(), b.getTargets(), b.getSentBy(), b.getSentAt()); + b.getCampaign(), b.getTargets(), b.getSentBy(), b.getSentAt().toEpochMilli()); } private void record(String admin, String action, String reason) throws IOException { @@ -278,7 +279,7 @@ private void record(String admin, String action, String reason) throws IOExcepti a.setUsername("promote"); a.setAction(action); a.setReason(reason.length() > 255 ? reason.substring(0, 255) : reason); - a.setCreatedAt(Clock.now()); + a.setCreatedAt(Instant.now()); audit.insert(a); } } diff --git a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Referrals.java b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Referrals.java index bec0d5b9d74..4c45b622668 100644 --- a/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Referrals.java +++ b/scripts/skirmish/backend/src/main/java/com/codenameone/examples/skirmish/social/Referrals.java @@ -37,6 +37,7 @@ import com.codenameone.examples.skirmish.repository.ReferralCodeRepository; import com.codenameone.examples.skirmish.repository.ReferralRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -95,7 +96,7 @@ public InviteDto invite(String username) throws IOException { ReferralCode c = new ReferralCode(); c.setCode(code); c.setUsername(username); - c.setCreatedAt(Clock.now()); + c.setCreatedAt(Instant.now()); codes.insert(c); } else { code = mine.get(0).getCode(); @@ -125,7 +126,7 @@ public RewardDto claim(String username, InviteClaimDto claim) throws IOException throw new ResponseStatusException(400, "You invited that player"); } Profile p = profiles.findById(username); - if (p == null || p.getCreatedAt() < Clock.now() - CLAIM_DAYS * Clock.DAY) { + if (p == null || p.getCreatedAt().isBefore(Instant.now().minusMillis(CLAIM_DAYS * Clock.DAY))) { throw new ResponseStatusException(400, "Invites count for new players only"); } Referral r = new Referral(); @@ -136,7 +137,7 @@ public RewardDto claim(String username, InviteClaimDto claim) throws IOException r.setChannel(clip(claim.channel(), 40)); r.setMatchType(clip(claim.match(), 20)); r.setState(JOINED); - r.setJoinedAt(Clock.now()); + r.setJoinedAt(Instant.now()); referrals.insert(r); Profile from = profiles.findById(inviter); pushes.friendJoined(inviter, p.getDisplayName()); @@ -154,7 +155,7 @@ public void played(String username) throws IOException { return; } r.setState(PLAYED); - r.setPlayedAt(Clock.now()); + r.setPlayedAt(Instant.now()); boolean pay = referrals.countByInviterAndRewardedTrue(r.getInviter()) < MAX_REWARDED; r.setRewarded(pay); referrals.save(r); @@ -173,7 +174,7 @@ public List friends(String username) throws IOException { Profile p = profiles.findById(r.getInvitee()); if (p != null) { out.add(new FriendDto(p.getDisplayName(), p.getTrophies(), r.getState(), r.isRewarded(), - r.getJoinedAt())); + r.getJoinedAt().toEpochMilli())); } } return out; diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Accounts.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Accounts.java index 533ae91da46..7308eb70487 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Accounts.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Accounts.java @@ -43,6 +43,7 @@ import com.codenameone.examples.wayline.repository.ProfileRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -152,7 +153,7 @@ private UserDto open(RegisterDto request) throws IOException { // older app asks -- begins an application, and the role waits for an // admin to approve it. create(username, request.password(), displayName, phone, false, vehicle, plate, false, - false, gender, System.currentTimeMillis()); + false, gender, Instant.now()); if (request.driver() || request.wantsToDrive()) { applications.open(username, vehicle, plate); } @@ -167,7 +168,7 @@ void create(String username, String password, String displayName, String phone, boolean phoneVerified, String vehicle, String plate, boolean driver, boolean admin) throws IOException { create(username, password, displayName, phone, phoneVerified, vehicle, plate, driver, - admin, GENDERS[0], System.currentTimeMillis()); + admin, GENDERS[0], Instant.now()); } /// As the method above, for a caller that also knows the gender and when @@ -177,7 +178,7 @@ void create(String username, String password, String displayName, String phone, @Transactional(rollbackFor = IOException.class) void create(String username, String password, String displayName, String phone, boolean phoneVerified, String vehicle, String plate, boolean driver, boolean admin, - String gender, long openedAt) throws IOException { + String gender, Instant openedAt) throws IOException { users.createUser(User.withUsername(username).password(encoder.encode(password)) .roles(roles(driver, admin)).build()); Profile profile = new Profile(); @@ -491,7 +492,7 @@ private void retire(String username) throws IOException { if (!closed.existsById(hash)) { ClosedAccount row = new ClosedAccount(); row.setUsernameHash(hash); - row.setClosedAt(System.currentTimeMillis()); + row.setClosedAt(Instant.now()); closed.insert(row); } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/DemoAccounts.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/DemoAccounts.java index e2a2ea122e4..7a7190b9614 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/DemoAccounts.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/DemoAccounts.java @@ -40,6 +40,7 @@ import com.codenameone.examples.wayline.ride.Fares; import java.io.IOException; +import java.time.Instant; /// The accounts a server starts with. /// @@ -169,7 +170,7 @@ void flag(String username, String why, int daysAgo) throws IOException { profile.setFlagged(true); profile.setFlagReason(why); moderation.record(username, ADMIN, Moderation.FLAG, why, - System.currentTimeMillis() - daysAgo * Days.MILLIS); + Instant.now().minusMillis(daysAgo * Days.MILLIS)); } /// An admin, or the plainest kind of account. @@ -231,7 +232,7 @@ private void driver(String username, String name, String phone, String gender, S void approved(String username, String name, String product, String colour, String make, String model, String plate, int seats, boolean wheelchair, boolean pets, int daysAgo) throws IOException { - long handedIn = System.currentTimeMillis() - (daysAgo + 1) * Days.MILLIS; + Instant handedIn = Instant.now().minusMillis((daysAgo + 1) * Days.MILLIS); DriverApplication form = forms.findById(username); form.setLegalName(name); form.setDateOfBirth("1988-04-12"); @@ -291,13 +292,13 @@ private void applicant() throws IOException { @Transactional(rollbackFor = IOException.class) void handedIn(String username, int daysAgo) throws IOException { DriverApplication form = forms.findById(username); - form.setSubmittedAt(System.currentTimeMillis() - daysAgo * Days.MILLIS); + form.setSubmittedAt(Instant.now().minusMillis(daysAgo * Days.MILLIS)); } /// When an account opened that many days ago was opened, so that the chart /// of new accounts is not one bar. - private static long opened(int daysAgo) { - return System.currentTimeMillis() - daysAgo * Days.MILLIS; + private static Instant opened(int daysAgo) { + return Instant.now().minusMillis(daysAgo * Days.MILLIS); } private static int year() { diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Moderation.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Moderation.java index 08d0a5c220d..844c4753e22 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Moderation.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/Moderation.java @@ -26,6 +26,7 @@ import com.codenameone.examples.wayline.repository.ModerationEventRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -57,15 +58,16 @@ public void record(String username, String by, String action, String reason) // came with it -- would otherwise be listed in either order. The later // one is stamped after the one before it, so the list is the order in // which things were done. - Long newest = events.newest(username); - long after = newest == null ? 0L : newest.longValue() + 1L; - record(username, by, action, reason, Math.max(System.currentTimeMillis(), after)); + Instant newest = events.newest(username); + Instant now = Instant.now(); + Instant stamp = newest != null && !newest.isBefore(now) ? newest.plusMillis(1L) : now; + record(username, by, action, reason, stamp); } /// As [#record(String, String, String, String)], at a time of the caller's /// choosing; the demo data is the one caller that has a past to write. @Transactional - public void record(String username, String by, String action, String reason, long at) + public void record(String username, String by, String action, String reason, Instant at) throws IOException { String why = reason == null ? "" : reason.trim(); ModerationEvent event = new ModerationEvent(); @@ -85,8 +87,8 @@ public List events(String username) throws IOException { List out = new ArrayList(); for (int iter = 0; iter < rows.size(); iter++) { ModerationEvent row = rows.get(iter); - out.add(new ModerationEventDto(row.getCreatedAt(), row.getActor(), row.getAction(), - row.getReason())); + out.add(new ModerationEventDto(row.getCreatedAt().toEpochMilli(), row.getActor(), + row.getAction(), row.getReason())); } return out; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/PhoneVerification.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/PhoneVerification.java index 10ed791a384..1c53c360b64 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/PhoneVerification.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/account/PhoneVerification.java @@ -31,6 +31,7 @@ import com.codenameone.examples.wayline.sms.SmsSender; import java.io.IOException; +import java.time.Instant; /// Proves an account's phone number by texting it a code. /// @@ -72,7 +73,7 @@ public PhoneChallengeDto start(String username) throws IOException { UserDto user = accounts.describe(username); String code = newCode(); String codeHash = hash(username, code); - store(username, codeHash, System.currentTimeMillis()); + store(username, codeHash, Instant.now()); try { sms.send(user.phone(), "Your Wayline code is " + code); } catch (IOException failed) { @@ -98,20 +99,20 @@ public PhoneChallengeDto start(String username) throws IOException { /// one is kept, so at most two codes are live, and only one whose guesses /// were not used up. @Transactional - void store(String username, String codeHash, long now) throws IOException { + void store(String username, String codeHash, Instant now) throws IOException { // Before the code is read: two requests for one account take turns, // so the second finds the code the first just stored and is told to // wait. Otherwise both pass the check below and both send a text. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending != null && now - pending.getSentAt() < RESEND_SECONDS * 1000L) { + if (pending != null && pending.getSentAt().plusSeconds(RESEND_SECONDS).isAfter(now)) { throw new ResponseStatusException(429, "Wait a moment before asking for another code"); } boolean first = pending == null; if (first) { pending = new PhoneCode(); pending.setUsername(username); - } else if (pending.getExpiresAt() >= now && pending.getAttempts() < MAX_ATTEMPTS) { + } else if (!pending.getExpiresAt().isBefore(now) && pending.getAttempts() < MAX_ATTEMPTS) { // With the guesses it has used: asking for another code must not // buy the old one a fresh set. pending.setPreviousHash(pending.getCodeHash()); @@ -119,11 +120,11 @@ void store(String username, String codeHash, long now) throws IOException { pending.setPreviousAttempts(pending.getAttempts()); } else { pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); } pending.setCodeHash(codeHash); - pending.setExpiresAt(now + CODE_SECONDS * 1000L); + pending.setExpiresAt(now.plusSeconds(CODE_SECONDS)); pending.setAttempts(0); pending.setSentAt(now); if (first) { @@ -148,7 +149,7 @@ void discard(String username, String codeHash) throws IOException { return; } if (pending.getPreviousHash().length() == 0 - || pending.getPreviousExpiresAt() < System.currentTimeMillis()) { + || pending.getPreviousExpiresAt().isBefore(Instant.now())) { codes.deleteById(username); return; } @@ -156,9 +157,9 @@ void discard(String username, String codeHash) throws IOException { pending.setExpiresAt(pending.getPreviousExpiresAt()); pending.setAttempts(pending.getPreviousAttempts()); pending.setPreviousHash(""); - pending.setPreviousExpiresAt(0L); + pending.setPreviousExpiresAt(Instant.EPOCH); pending.setPreviousAttempts(0); - pending.setSentAt(0L); + pending.setSentAt(Instant.EPOCH); } /// Checks the code the user typed. Answers 400 for a wrong or expired one @@ -186,7 +187,7 @@ boolean guess(String username, String code) throws IOException { // row the other has. accounts.hold(username); PhoneCode pending = codes.findById(username); - if (pending == null || pending.getExpiresAt() < System.currentTimeMillis()) { + if (pending == null || pending.getExpiresAt().isBefore(Instant.now())) { throw new ResponseStatusException(400, "That code has expired. Ask for a new one"); } if (pending.getAttempts() >= MAX_ATTEMPTS) { @@ -222,7 +223,7 @@ boolean guess(String username, String code) throws IOException { boolean previous = Crypto.equalsConstantTime(given, pending.getPreviousHash().getBytes("UTF-8")) && pending.getPreviousHash().length() > 0 - && pending.getPreviousExpiresAt() >= System.currentTimeMillis() + && !pending.getPreviousExpiresAt().isBefore(Instant.now()) && counted != null && counted.getPreviousAttempts() <= MAX_ATTEMPTS; if (!current && !previous) { return false; diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/admin/Statistics.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/admin/Statistics.java index c8a89ce9e44..7f15a0b03c3 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/admin/Statistics.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/admin/Statistics.java @@ -44,6 +44,7 @@ import com.codenameone.examples.wayline.ride.Matcher; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -116,8 +117,9 @@ public AdminStatsDto dashboard() throws IOException { } } int online = (int) cars.countByOnlineTrueAndLastSeenGreaterThanEqual( - now - Matcher.FRESH_MILLIS); - int today = (int) rides.countByRequestedAtGreaterThanEqual(Days.start(now)); + Instant.ofEpochMilli(now - Matcher.FRESH_MILLIS)); + int today = (int) rides.countByRequestedAtGreaterThanEqual( + Instant.ofEpochMilli(Days.start(now))); int active = (int) rides.countByStateIn(ACTIVE); int done = (int) rides.countByStateIn(new RideState[] {RideState.COMPLETED}); long revenue = Rows.number(rides.fares(RideState.COMPLETED, PAID)); @@ -141,10 +143,11 @@ public StatsSeriesDto series(int days) throws IOException { int[] byHour = new int[24]; // By day and by hour, counted here from one row per ride. Map requestedAt = new HashMap(); - List timeline = rides.timeline(since); + Instant from = Instant.ofEpochMilli(since); + List timeline = rides.timeline(from); for (int iter = 0; iter < timeline.size(); iter++) { Object[] ride = timeline.get(iter); - long at = whole(ride[1]); + long at = millis(ride[1]); RideState state = Rows.state(ride[2]); requestedAt.put(Rows.text(ride[0]), Long.valueOf(at)); int index = (int) ((at - since) / Days.MILLIS); @@ -166,7 +169,7 @@ public StatsSeriesDto series(int days) throws IOException { int[] byState = new int[STATES.length]; long completed = 0L; long finished = 0L; - List states = rides.countByState(since); + List states = rides.countByState(from); for (int iter = 0; iter < states.size(); iter++) { RideState state = Rows.state(states.get(iter)[0]); long count = whole(states.get(iter)[1]); @@ -183,7 +186,7 @@ public StatsSeriesDto series(int days) throws IOException { } } int[] byProduct = new int[Fares.PRODUCTS.length]; - List products = rides.countByProduct(since); + List products = rides.countByProduct(from); for (int iter = 0; iter < products.size(); iter++) { for (int p = 0; p < Fares.PRODUCTS.length; p++) { if (Fares.PRODUCTS[p].equals(products.get(iter)[0])) { @@ -192,12 +195,12 @@ public StatsSeriesDto series(int days) throws IOException { } } Map completedBy = new HashMap(); - List perDriver = rides.countByDriver(since, RideState.COMPLETED); + List perDriver = rides.countByDriver(from, RideState.COMPLETED); for (int iter = 0; iter < perDriver.size(); iter++) { completedBy.put(Rows.text(perDriver.get(iter)[0]), new int[] {(int) whole(perDriver.get(iter)[1])}); } - long fareSum = Rows.number(rides.faresSince(since, RideState.COMPLETED)); + long fareSum = Rows.number(rides.faresSince(from, RideState.COMPLETED)); List hours = new ArrayList(); for (int iter = 0; iter < byHour.length; iter++) { hours.add(Integer.valueOf(byHour[iter])); @@ -219,9 +222,9 @@ public StatsSeriesDto series(int days) throws IOException { double completionRate = finished == 0L ? 0d : Math.round(completed * 100d / finished) / 100d; - List signUps = profiles.signUps(since); + List signUps = profiles.signUps(from); for (int iter = 0; iter < signUps.size(); iter++) { - int index = (int) ((signUps.get(iter).longValue() - since) / Days.MILLIS); + int index = (int) ((signUps.get(iter).toEpochMilli() - since) / Days.MILLIS); if (index >= 0 && index < span) { dayNewUsers[index]++; } @@ -235,13 +238,13 @@ public StatsSeriesDto series(int days) throws IOException { // How long a rider waited for a driver to take the ride: each time one // was accepted, set against when it was asked for. - List waits = events.reached(since, RideState.ACCEPTED); + List waits = events.reached(from, RideState.ACCEPTED); long waited = 0L; int answered = 0; for (int iter = 0; iter < waits.size(); iter++) { Long asked = requestedAt.get(Rows.text(waits.get(iter)[0])); if (asked != null) { - waited += Math.max(0L, whole(waits.get(iter)[1]) - asked.longValue()); + waited += Math.max(0L, millis(waits.get(iter)[1]) - asked.longValue()); answered++; } } @@ -297,6 +300,14 @@ private static boolean cancelled(RideState state) { || RideState.CANCELLED_BY_ADMIN == state; } + /// A time as a query answers it, in milliseconds since the epoch. + private static long millis(Object value) { + if (!(value instanceof Instant)) { + throw new IllegalStateException("Not a time: " + value); + } + return ((Instant) value).toEpochMilli(); + } + /// A count or a sum as a query answers it. private static long whole(Object value) { return value instanceof Number ? ((Number) value).longValue() : 0L; diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ClosedAccount.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ClosedAccount.java index 88afe0cfffd..ccc84fe5bdb 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ClosedAccount.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ClosedAccount.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What is left of an account that was closed: the hash of its e-mail, kept so /// that the address cannot be registered again. @@ -31,7 +32,7 @@ public class ClosedAccount { private String usernameHash = ""; @Column(nullable = false) - private long closedAt; + private Instant closedAt = Instant.EPOCH; public ClosedAccount() { } @@ -44,11 +45,11 @@ public void setUsernameHash(String usernameHash) { this.usernameHash = usernameHash; } - public long getClosedAt() { + public Instant getClosedAt() { return closedAt; } - public void setClosedAt(long closedAt) { + public void setClosedAt(Instant closedAt) { this.closedAt = closedAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverApplication.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverApplication.java index 7cc3acad6c8..939786f2446 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverApplication.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverApplication.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's application to drive, and what became of it. @Entity @@ -75,13 +76,13 @@ public class DriverApplication { private String rejectionReason = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) - private long submittedAt; + private Instant submittedAt = Instant.EPOCH; @Column(nullable = false) - private long reviewedAt; + private Instant reviewedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String reviewedBy = ""; @@ -217,27 +218,27 @@ public void setRejectionReason(String rejectionReason) { this.rejectionReason = rejectionReason; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } - public long getSubmittedAt() { + public Instant getSubmittedAt() { return submittedAt; } - public void setSubmittedAt(long submittedAt) { + public void setSubmittedAt(Instant submittedAt) { this.submittedAt = submittedAt; } - public long getReviewedAt() { + public Instant getReviewedAt() { return reviewedAt; } - public void setReviewedAt(long reviewedAt) { + public void setReviewedAt(Instant reviewedAt) { this.reviewedAt = reviewedAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverDocument.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverDocument.java index 893c17c14f4..565daaf0805 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverDocument.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverDocument.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A document an applicant uploaded, one of each kind. `data` is the file in /// Base64, which is text on every database. @@ -41,7 +42,7 @@ public class DriverDocument { private String status = ""; @Column(nullable = false) - private long uploadedAt; + private Instant uploadedAt = Instant.EPOCH; @Column(nullable = false) private String data = ""; @@ -81,11 +82,11 @@ public void setStatus(String status) { this.status = status; } - public long getUploadedAt() { + public Instant getUploadedAt() { return uploadedAt; } - public void setUploadedAt(long uploadedAt) { + public void setUploadedAt(Instant uploadedAt) { this.uploadedAt = uploadedAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverState.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverState.java index 28a89341862..19e92bad01f 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverState.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/DriverState.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// Where a driver's car is, whether they are on line, and what riders made of them. @Entity @@ -42,7 +43,7 @@ public class DriverState { private double heading; @Column(nullable = false) - private long lastSeen; + private Instant lastSeen = Instant.EPOCH; @Column(nullable = false) private long ratingSum; @@ -98,11 +99,11 @@ public void setHeading(double heading) { this.heading = heading; } - public long getLastSeen() { + public Instant getLastSeen() { return lastSeen; } - public void setLastSeen(long lastSeen) { + public void setLastSeen(Instant lastSeen) { this.lastSeen = lastSeen; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/LiveTicket.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/LiveTicket.java index 64fa22794f3..62847a03e56 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/LiveTicket.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/LiveTicket.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A ticket for one connection to the live channel, as its hash. @Entity @@ -33,7 +34,7 @@ public class LiveTicket { private String username = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; public LiveTicket() { } @@ -54,11 +55,11 @@ public void setUsername(String username) { this.username = username; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ModerationEvent.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ModerationEvent.java index 56cf4f985eb..b6509c576c8 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ModerationEvent.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/ModerationEvent.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One thing an admin did to an account, and why. Written once, never changed. @Entity @@ -33,7 +34,7 @@ public class ModerationEvent { private String username = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String actor = ""; @@ -63,11 +64,11 @@ public void setUsername(String username) { this.username = username; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payment.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payment.java index 5fffb1fe321..84e32e0d6b8 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payment.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payment.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// What a completed ride was charged, and what was given back. @Entity @@ -42,7 +43,7 @@ public class Payment { private String providerRef = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(64)") private String tipRef = ""; @@ -57,7 +58,7 @@ public class Payment { private String refundReason = ""; @Column(nullable = false) - private long refundedAt; + private Instant refundedAt = Instant.EPOCH; public Payment() { } @@ -102,11 +103,11 @@ public void setProviderRef(String providerRef) { this.providerRef = providerRef; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } @@ -142,11 +143,11 @@ public void setRefundReason(String refundReason) { this.refundReason = refundReason; } - public long getRefundedAt() { + public Instant getRefundedAt() { return refundedAt; } - public void setRefundedAt(long refundedAt) { + public void setRefundedAt(Instant refundedAt) { this.refundedAt = refundedAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentMethod.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentMethod.java index 45f6f0e8ec5..8ce68550890 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentMethod.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentMethod.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A saved card: what the provider calls it and what to show for it. The /// number itself is never here. @@ -52,7 +53,7 @@ public class PaymentMethod { private boolean preferred; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public PaymentMethod() { } @@ -121,11 +122,11 @@ public void setPreferred(boolean preferred) { this.preferred = preferred; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentSetup.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentSetup.java index 22a6a37ad10..595124dfb85 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentSetup.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PaymentSetup.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A card being added on the provider's page, until the browser comes back. @Entity @@ -36,7 +37,7 @@ public class PaymentSetup { private String reference = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false) private boolean completed; @@ -68,11 +69,11 @@ public void setReference(String reference) { this.reference = reference; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payout.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payout.java index 0a1ebaa393c..46b49521a8d 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payout.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Payout.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// One payment of earnings to a driver. @Entity @@ -39,7 +40,7 @@ public class Payout { private String status = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(120)") private String destination = ""; @@ -79,11 +80,11 @@ public void setStatus(String status) { this.status = status; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PhoneCode.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PhoneCode.java index 8547e5f09a4..c3bed31bb96 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PhoneCode.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PhoneCode.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The verification code an account was last sent, as its hash. @Entity @@ -33,20 +34,20 @@ public class PhoneCode { private String codeHash = ""; @Column(nullable = false) - private long expiresAt; + private Instant expiresAt = Instant.EPOCH; @Column(nullable = false) private int attempts; @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; /// The code sent before this one, while it is still good, or empty. @Column(nullable = false, type = "VARCHAR(64)") private String previousHash = ""; @Column(nullable = false) - private long previousExpiresAt; + private Instant previousExpiresAt = Instant.EPOCH; /// The guesses already taken at the code before, which keeps the budget /// it had rather than starting a new one when another code is sent. @@ -72,11 +73,11 @@ public void setCodeHash(String codeHash) { this.codeHash = codeHash; } - public long getExpiresAt() { + public Instant getExpiresAt() { return expiresAt; } - public void setExpiresAt(long expiresAt) { + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } @@ -88,11 +89,11 @@ public void setAttempts(int attempts) { this.attempts = attempts; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } @@ -104,11 +105,11 @@ public void setPreviousHash(String previousHash) { this.previousHash = previousHash; } - public long getPreviousExpiresAt() { + public Instant getPreviousExpiresAt() { return previousExpiresAt; } - public void setPreviousExpiresAt(long previousExpiresAt) { + public void setPreviousExpiresAt(Instant previousExpiresAt) { this.previousExpiresAt = previousExpiresAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Pricing.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Pricing.java index f9c57e3bae9..df169909ed4 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Pricing.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Pricing.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The prices an admin set. One row, with the id 1, once they have set any. @Entity @@ -57,7 +58,7 @@ public class Pricing { private double xl; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(190)") private String updatedBy = ""; @@ -145,11 +146,11 @@ public void setXl(double xl) { this.xl = xl; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Profile.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Profile.java index e58122895bb..3576a87c28c 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Profile.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Profile.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// An account's profile: who it is to the people it rides with. /// @@ -48,7 +49,7 @@ public class Profile { private String plate = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; @Column(nullable = false, type = "VARCHAR(16)") private String gender = "unspecified"; @@ -125,11 +126,11 @@ public void setPlate(String plate) { this.plate = plate; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PushDevice.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PushDevice.java index 88f00470019..fb84f6e8cc2 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PushDevice.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/PushDevice.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// A device an account is sent push notifications on. /// @@ -46,7 +47,7 @@ public class PushDevice { private String platform = ""; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; public PushDevice() { } @@ -91,11 +92,11 @@ public void setPlatform(String platform) { this.platform = platform; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Ride.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Ride.java index 02537248968..aba0a2ce4ae 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Ride.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/Ride.java @@ -22,6 +22,7 @@ import com.codename1.annotations.Entity; import com.codename1.annotations.Id; import com.codenameone.examples.wayline.api.RideState; +import java.time.Instant; // tag::wayline-entity[] /// A ride, from the request to its end. @@ -75,16 +76,16 @@ public class Ride { private double durationSeconds; @Column(nullable = false) - private long requestedAt; + private Instant requestedAt = Instant.EPOCH; @Column(nullable = false) - private long updatedAt; + private Instant updatedAt = Instant.EPOCH; @Column(nullable = false) - private long offerExpiresAt; + private Instant offerExpiresAt = Instant.EPOCH; @Column(nullable = false) - private long searchUntil; + private Instant searchUntil = Instant.EPOCH; @Column(nullable = false, type = "SMALLINT") private int stars; @@ -251,35 +252,35 @@ public void setDurationSeconds(double durationSeconds) { this.durationSeconds = durationSeconds; } - public long getRequestedAt() { + public Instant getRequestedAt() { return requestedAt; } - public void setRequestedAt(long requestedAt) { + public void setRequestedAt(Instant requestedAt) { this.requestedAt = requestedAt; } - public long getUpdatedAt() { + public Instant getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(long updatedAt) { + public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } - public long getOfferExpiresAt() { + public Instant getOfferExpiresAt() { return offerExpiresAt; } - public void setOfferExpiresAt(long offerExpiresAt) { + public void setOfferExpiresAt(Instant offerExpiresAt) { this.offerExpiresAt = offerExpiresAt; } - public long getSearchUntil() { + public Instant getSearchUntil() { return searchUntil; } - public void setSearchUntil(long searchUntil) { + public void setSearchUntil(Instant searchUntil) { this.searchUntil = searchUntil; } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideActivity.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideActivity.java index 1267299dc02..a81a5bd26d2 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideActivity.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideActivity.java @@ -21,6 +21,7 @@ import com.codename1.annotations.Column; import com.codename1.annotations.Entity; import com.codename1.annotations.Id; +import java.time.Instant; /// The Live Activity a rider's phone shows a ride in, while the ride lasts. @Entity @@ -38,12 +39,12 @@ public class RideActivity { /// When the server last sent it a state, for spacing out the updates. @Column(nullable = false) - private long sentAt; + private Instant sentAt = Instant.EPOCH; /// When its ride ended, 0 while the ride lasts. An ended activity is kept /// until the phone has been told to end it. @Column(nullable = false) - private long endedAt; + private Instant endedAt = Instant.EPOCH; public RideActivity() { } @@ -72,19 +73,19 @@ public void setActivityId(String activityId) { this.activityId = activityId; } - public long getSentAt() { + public Instant getSentAt() { return sentAt; } - public void setSentAt(long sentAt) { + public void setSentAt(Instant sentAt) { this.sentAt = sentAt; } - public long getEndedAt() { + public Instant getEndedAt() { return endedAt; } - public void setEndedAt(long endedAt) { + public void setEndedAt(Instant endedAt) { this.endedAt = endedAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideEvent.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideEvent.java index 4f96ce29a5a..134411957ce 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideEvent.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/domain/RideEvent.java @@ -22,6 +22,7 @@ import com.codename1.annotations.Entity; import com.codename1.annotations.Id; import com.codenameone.examples.wayline.api.RideState; +import java.time.Instant; /// One change of a ride's state: what it became, who made it so, and when. @Entity @@ -40,7 +41,7 @@ public class RideEvent { private String actor = ""; @Column(nullable = false) - private long createdAt; + private Instant createdAt = Instant.EPOCH; public RideEvent() { } @@ -77,11 +78,11 @@ public void setActor(String actor) { this.actor = actor; } - public long getCreatedAt() { + public Instant getCreatedAt() { return createdAt; } - public void setCreatedAt(long createdAt) { + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Drivers.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Drivers.java index 814a136912f..b084ccd10a1 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Drivers.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Drivers.java @@ -47,6 +47,7 @@ import com.codenameone.examples.wayline.ride.Matcher; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -147,7 +148,7 @@ private Report store(String driver, DriverStatusDto status) throws IOException { if (!status.online() && ride != null) { throw new ResponseStatusException(409, "Finish the ride before going off line"); } - long now = System.currentTimeMillis(); + Instant now = Instant.now(); DriverState state = drivers.findById(driver); // The time since the last report was time on line, unless it was so // long ago that the app had plainly stopped reporting. It is counted @@ -156,7 +157,8 @@ private Report store(String driver, DriverStatusDto status) throws IOException { // is, so the row read here stays managed and its change is written // either way; a statement marked clearAutomatically would detach it, // and a change made after that would be lost. - long since = state != null && state.isOnline() ? now - state.getLastSeen() : 0L; + long since = state != null && state.isOnline() + ? now.toEpochMilli() - state.getLastSeen().toEpochMilli() : 0L; boolean first = state == null; if (first) { state = new DriverState(); @@ -177,7 +179,7 @@ private Report store(String driver, DriverStatusDto status) throws IOException { if (since > 0L && since < Matcher.FRESH_MILLIS) { // Cut at midnight: a stretch on line across it belongs half to // each day, not all to the new one. - long[] days = Days.split(now - since, now); + long[] days = Days.split(now.toEpochMilli() - since, now.toEpochMilli()); for (int iter = 0; iter < days.length; iter += 2) { addHours(driver, days[iter], days[iter + 1]); } @@ -282,10 +284,11 @@ public EarningsDto earnings(String driver) throws IOException { long now = System.currentTimeMillis(); // The day's trips and the day's money from one query, so the header // that shows them together counts the rides that made the sum. - Object[] day = rides.paidTotalsSince(driver, now - now % DAY_MILLIS); + Object[] day = rides.paidTotalsSince(driver, Instant.ofEpochMilli(now - now % DAY_MILLIS)); int todayCount = day == null ? 0 : (int) Rows.number(day[0]); long today = day == null ? 0L : Rows.number(day[1]); - long week = Rows.number(rides.paidSince(driver, now - 7 * DAY_MILLIS)); + long week = Rows.number( + rides.paidSince(driver, Instant.ofEpochMilli(now - 7 * DAY_MILLIS))); Object[] total = rides.paidTotals(driver); int count = total == null ? 0 : (int) Rows.number(total[0]); long all = total == null ? 0L : Rows.number(total[1]); @@ -309,7 +312,7 @@ private static DriverDto toDto(Profile profile, DriverApplication application, double rating = 5d; long lastSeen = 0L; if (car != null) { - lastSeen = car.getLastSeen(); + lastSeen = car.getLastSeen().toEpochMilli(); // On line means said so and heard from lately; see Matcher. online = car.isOnline() && System.currentTimeMillis() - lastSeen < Matcher.FRESH_MILLIS; diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Earnings.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Earnings.java index 500767060fe..f1ecda06185 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Earnings.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driver/Earnings.java @@ -48,6 +48,7 @@ import com.codenameone.examples.wayline.ride.Fares; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -110,16 +111,16 @@ public EarningsSummaryDto summary(String driver) throws IOException { long monthStart = today - 29 * Days.MILLIS; long weekStart = today - 6 * Days.MILLIS; List done = rides.findByDriverAndStateAndUpdatedAtGreaterThanEqual(driver, - RideState.COMPLETED, monthStart); + RideState.COMPLETED, Instant.ofEpochMilli(monthStart)); // A card tip is on its ride from the moment it is asked for, and is // still there when the processor never answered. Only one whose charge // is on record is earned, here as in the balance: otherwise a day's // total would show money that cannot be cashed out. Set charged = new HashSet( - rides.tipChargedSince(driver, monthStart)); + rides.tipChargedSince(driver, Instant.ofEpochMilli(monthStart))); for (int iter = 0; iter < done.size(); iter++) { Ride ride = done.get(iter); - long at = ride.getUpdatedAt(); + long at = ride.getUpdatedAt().toEpochMilli(); boolean tipped = "cash".equals(ride.getMethodId()) || charged.contains(ride.getId()); // The fare likewise counts only once it is paid, as in the balance: // a card charge that failed, was refunded or has not come back is @@ -192,7 +193,7 @@ public PayoutDto cashOut(String driver) throws IOException { row.setDriver(driver); row.setAmountCents(amount); row.setStatus("paid"); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); row.setDestination(account.getBankName() + " ****" + account.getLast4()); payouts.insert(row); return toDto(row); @@ -291,6 +292,6 @@ private static PayoutAccountDto toDto(PayoutAccount row) { private static PayoutDto toDto(Payout row) { return new PayoutDto(row.getId(), row.getAmountCents(), row.getStatus(), - row.getCreatedAt(), row.getDestination()); + row.getCreatedAt().toEpochMilli(), row.getDestination()); } } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driving/Applications.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driving/Applications.java index 3a7e343e68a..0831bcf2439 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driving/Applications.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/driving/Applications.java @@ -45,6 +45,7 @@ import com.codenameone.examples.wayline.ride.Fares; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -254,7 +255,7 @@ public DriverApplicationDto upload(String username, DocumentUploadDto upload) // looked at the one it replaced. hold(username); editable(username); - long now = System.currentTimeMillis(); + Instant now = Instant.now(); // Replaced with a statement where there is one already, so the picture // it held is not read only to be overwritten. if (documents.replace(username, kind, type, "uploaded", now, data) == 0) { @@ -325,7 +326,7 @@ public DriverApplicationDto submit(String username) throws IOException { throw new ResponseStatusException(400, what.toString()); } // Held to the status it was read in: handed in twice, it is handed in once. - applications.submit(username, was, PENDING, System.currentTimeMillis()); + applications.submit(username, was, PENDING, Instant.now()); return get(username); } @@ -439,7 +440,7 @@ public void grant(String by, String username) throws IOException { applications.insert(blank(username, APPROVED, "", "")); return; } - applications.approveUnlessApproved(username, APPROVED, System.currentTimeMillis(), by); + applications.approveUnlessApproved(username, APPROVED, Instant.now(), by); } /// Takes the approval back, when an admin withdraws the DRIVER role. The @@ -447,7 +448,7 @@ public void grant(String by, String username) throws IOException { @Transactional public void withdraw(String by, String username) throws IOException { applications.move(username, APPROVED, REJECTED, "Driving was withdrawn by an admin", - System.currentTimeMillis(), by); + Instant.now(), by); } /// Everything kept about an account's application, for an account being @@ -468,7 +469,7 @@ private void decide(String by, String username, String to, String reason) if (find(username) == null) { throw new ResponseStatusException(404, "No such application"); } - if (applications.move(username, PENDING, to, reason, System.currentTimeMillis(), by) + if (applications.move(username, PENDING, to, reason, Instant.now(), by) != 1) { throw new ResponseStatusException(409, "That application is not waiting for an answer"); } @@ -543,7 +544,7 @@ private DriverApplication editable(String username) { /// moment it was made. private static DriverApplication blank(String username, String status, String vehicle, String plate) { - long now = System.currentTimeMillis(); + Instant now = Instant.now(); DriverApplication application = new DriverApplication(); application.setUsername(username); application.setStatus(status); @@ -552,7 +553,7 @@ private static DriverApplication blank(String username, String status, String ve application.setVehicleSeats(4); application.setProduct(Fares.STANDARD); application.setCreatedAt(now); - application.setReviewedAt(APPROVED.equals(status) ? now : 0L); + application.setReviewedAt(APPROVED.equals(status) ? now : Instant.EPOCH); return application; } @@ -584,7 +585,10 @@ private static DriverApplicationDto toDto(String username, String name, if (KINDS[kind].equals(stored[from])) { status = (String) stored[from + 1]; Object at = stored[from + 2]; - uploadedAt = at instanceof Number ? ((Number) at).longValue() : 0L; + if (!(at instanceof Instant)) { + throw new IllegalStateException("Not a time: " + at); + } + uploadedAt = ((Instant) at).toEpochMilli(); } } listed.add(new DocumentDto(KINDS[kind], status, uploadedAt)); @@ -599,8 +603,8 @@ private static DriverApplicationDto toDto(String username, String name, row.getVehicleMake(), row.getVehicleModel(), row.getVehicleYear(), row.getVehicleColor(), row.getVehiclePlate(), row.getVehicleSeats(), row.getProduct(), row.isWheelchair(), row.isPets(), listed, - row.getRejectionReason(), row.getSubmittedAt(), row.getReviewedAt(), - row.getReviewedBy()); + row.getRejectionReason(), row.getSubmittedAt().toEpochMilli(), + row.getReviewedAt().toEpochMilli(), row.getReviewedBy()); } /// Width and height from a PNG's header chunk, or null without one. diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/live/LiveTickets.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/live/LiveTickets.java index e902411ff0d..f6120900547 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/live/LiveTickets.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/live/LiveTickets.java @@ -28,6 +28,7 @@ import com.codenameone.examples.wayline.repository.LiveTicketRepository; import java.io.IOException; +import java.time.Instant; /// Tickets for the live channel. /// @@ -58,7 +59,7 @@ public TicketDto issue(String username) throws IOException { LiveTicket row = new LiveTicket(); row.setTicketHash(Ids.sha256(ticket)); row.setUsername(username); - row.setExpiresAt(System.currentTimeMillis() + TICKET_SECONDS * 1000L); + row.setExpiresAt(Instant.now().plusSeconds(TICKET_SECONDS)); tickets.insert(row); return new TicketDto(ticket, TICKET_SECONDS); } @@ -78,11 +79,11 @@ public String redeem(String ticket) throws IOException { return null; } String username = row.getUsername(); - long expiresAt = row.getExpiresAt(); + Instant expiresAt = row.getExpiresAt(); // One delete statement: the count it answers is what says this // connection, and not another presenting the same ticket, used it. int removed = tickets.deleteByTicketHash(hash); - if (removed != 1 || expiresAt < System.currentTimeMillis()) { + if (removed != 1 || expiresAt.isBefore(Instant.now())) { return null; } return username; @@ -92,7 +93,7 @@ public String redeem(String ticket) throws IOException { @Scheduled(fixedDelay = 60000, initialDelay = 60000) @Transactional public void sweep() throws IOException { - tickets.deleteByExpiresAtLessThan(System.currentTimeMillis()); + tickets.deleteByExpiresAtLessThan(Instant.now()); } /// Forgets the tickets of an account that is being closed. diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/pay/Payments.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/pay/Payments.java index 04a4b247ab4..629812f11c4 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/pay/Payments.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/pay/Payments.java @@ -45,6 +45,7 @@ import com.codenameone.examples.wayline.repository.RideRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -196,7 +197,7 @@ private String customerForSetup(String username) { /// that are neither finished nor abandoned. private void refuseTooManySetups(String username) { if (setups.countByUsernameAndCompletedFalseAndCreatedAtGreaterThan(username, - System.currentTimeMillis() - SETUP_MILLIS) >= MAX_OPEN_SETUPS) { + Instant.now().minusMillis(SETUP_MILLIS)) >= MAX_OPEN_SETUPS) { throw new ResponseStatusException(429, "Too many cards are being added. Finish one, or try again later"); } @@ -213,7 +214,7 @@ private void refuseTooManySetups(String username) { @Transactional public void sweepSetups() throws IOException { setups.deleteByCompletedTrue(); - setups.deleteByCreatedAtLessThan(System.currentTimeMillis() - 2L * SETUP_MILLIS); + setups.deleteByCreatedAtLessThan(Instant.now().minusMillis(2L * SETUP_MILLIS)); } /// Keeps the reference the processor made for a rider on first use, and @@ -261,7 +262,7 @@ private void keepSetup(String username, String id, String reference) { row.setId(id); row.setUsername(username); row.setReference(reference); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); row.setCompleted(false); setups.insert(row); } @@ -324,7 +325,7 @@ private String[] openSetup(String username, String setupId) { PaymentSetup setup = setupId == null || setupId.length() == 0 || setupId.length() > 32 ? null : setups.findFirstByIdAndUsername(setupId, username); if (setup == null || setup.isCompleted() - || setup.getCreatedAt() < System.currentTimeMillis() - SETUP_MILLIS) { + || setup.getCreatedAt().isBefore(Instant.now().minusMillis(SETUP_MILLIS))) { throw new ResponseStatusException(404, "No such card setup"); } PaymentCustomer customer = customers.findById(username); @@ -353,8 +354,8 @@ private PaymentMethodDto keepCard(String username, String setupId, String id, // Cards are listed in the order they were added, and two added in the // same millisecond would have no order: the later is stamped after // the one before it. - Long newest = cards.newestAt(username); - long after = newest == null ? 0L : newest.longValue() + 1L; + Instant newest = cards.newestAt(username); + Instant now = Instant.now(); PaymentMethod row = new PaymentMethod(); row.setId(id); row.setUsername(username); @@ -364,7 +365,7 @@ private PaymentMethodDto keepCard(String username, String setupId, String id, row.setExpYear(card.expYear); row.setToken(card.token); row.setPreferred(first); - row.setCreatedAt(Math.max(System.currentTimeMillis(), after)); + row.setCreatedAt(newest != null && !newest.isBefore(now) ? newest.plusMillis(1L) : now); cards.insert(row); return card(row); } @@ -491,8 +492,8 @@ public void forget(String username) throws IOException { } } - private static long retriedSince() { - return System.currentTimeMillis() - RETRY_MILLIS; + private static Instant retriedSince() { + return Instant.now().minusMillis(RETRY_MILLIS); } // --------------------------------------------------------------- charges @@ -556,7 +557,7 @@ private void keepPayment(String rideId, long amount, String currency, String sta row.setCurrency(currency); row.setStatus(status); row.setProviderRef(reference); - row.setCreatedAt(System.currentTimeMillis()); + row.setCreatedAt(Instant.now()); payments.insert(row); } @@ -750,7 +751,7 @@ private List refundsPending() { @Transactional private Ride endRefund(String rideId, String outcome) { if (payments.endRefund(rideId, outcome, - REFUNDED.equals(outcome) ? System.currentTimeMillis() : 0L) != 1) { + REFUNDED.equals(outcome) ? Instant.now() : Instant.EPOCH) != 1) { return null; } rides.paymentStatus(rideId, outcome); @@ -872,7 +873,7 @@ private void keepRefund(String rideId, PaymentProvider.Refund fare, payment.setRefundRef(cut(fare.reference, 64)); payment.setTipRefundRef(tip == null ? "" : cut(tip.reference, 64)); payment.setRefundReason(reason); - payment.setRefundedAt(pending ? 0L : System.currentTimeMillis()); + payment.setRefundedAt(pending ? Instant.EPOCH : Instant.now()); } /// Records a refund of the fare whose tip could not be refunded: the ride @@ -885,7 +886,7 @@ private void keepPartialRefund(String rideId, PaymentProvider.Refund fare, Strin payment.setRefundRef(cut(fare.reference, 64)); payment.setTipRefundRef(""); payment.setRefundReason(reason); - payment.setRefundedAt(0L); + payment.setRefundedAt(Instant.EPOCH); } // -------------------------------------------------------------- receipts @@ -917,7 +918,7 @@ public ReceiptDto receipt(String viewer, boolean admin, String rideId) throws IO throw new ResponseStatusException(404, "No such receipt"); } Payment payment = payments.findById(rideId); - return receipt(ride, payment == null ? 0L : payment.getCreatedAt(), admin, + return receipt(ride, payment == null ? 0L : payment.getCreatedAt().toEpochMilli(), admin, new HashMap()); } @@ -934,7 +935,8 @@ private List receipts(List completed, boolean admin) { List rows = payments.findByRideIdIn(ids); for (int iter = 0; iter < rows.size(); iter++) { Payment payment = rows.get(iter); - paidAt.put(payment.getRideId(), Long.valueOf(payment.getCreatedAt())); + paidAt.put(payment.getRideId(), + Long.valueOf(payment.getCreatedAt().toEpochMilli())); } } Map drivers = new HashMap(); @@ -1097,7 +1099,7 @@ private PaymentMethod card(String username, String id) { /// A card tip left unknown counts too, with no time limit: see [#tip]. /// Its retry charges the ride's card under the same key, so with the card /// gone a tip that may have been charged would be cleared as refused. - private boolean awaitsCharge(String rider, String methodId, long since) { + private boolean awaitsCharge(String rider, String methodId, Instant since) { List tipped = rides.findByRiderAndPaymentStatusAndTipCentsGreaterThan(rider, PAID, 0L); for (Ride ride : tipped) { diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/PushDevices.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/PushDevices.java index 37fe75b134b..2acda4d33fe 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/PushDevices.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/PushDevices.java @@ -30,6 +30,7 @@ import com.codenameone.examples.wayline.repository.PushDeviceRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -59,7 +60,7 @@ public PushDevices(PushDeviceRepository devices, ProfileRepository profiles) { public PushDeviceDto register(String username, PushDeviceDto device) throws IOException { PushTarget target = target(device); String id = key(target); - long now = System.currentTimeMillis(); + Instant now = Instant.now(); // Before anything is read, the account's profile row is held: a no-op // update that answers 0 when the profile is gone and otherwise keeps // the row locked until this commits. It settles two races. @@ -110,7 +111,7 @@ private void makeRoom(String username) { while (held.size() >= MAX_PER_ACCOUNT) { PushDevice oldest = held.get(0); for (PushDevice each : held) { - if (each.getUpdatedAt() < oldest.getUpdatedAt()) { + if (each.getUpdatedAt().isBefore(oldest.getUpdatedAt())) { oldest = each; } } @@ -146,7 +147,7 @@ List targetsOf(String username) { } // end::wayline-push-devices[] - private static void fill(PushDevice row, String username, PushDeviceDto device, long now) { + private static void fill(PushDevice row, String username, PushDeviceDto device, Instant now) { row.setUsername(username); row.setPlatform(Text.optional(device.platform(), 32, "the platform")); row.setUpdatedAt(now); diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/RidePushes.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/RidePushes.java index a1a6788db68..4ebcb84a229 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/RidePushes.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/push/RidePushes.java @@ -43,6 +43,7 @@ import com.codenameone.examples.wayline.ride.Rides; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -151,9 +152,9 @@ public void rideChanged(String id, RideState state, String rider, String driver) /// end that failed again is reported once the rest have been tried. @Scheduled(fixedDelay = 60000, initialDelay = 50000, lock = "wayline-activity-ends") public void endLeftBehind() throws IOException { - long now = System.currentTimeMillis(); - dropEndedBefore(now - END_RETRY_MILLIS); - List left = leftBehind(now - END_GRACE_MILLIS); + Instant now = Instant.now(); + dropEndedBefore(now.minusMillis(END_RETRY_MILLIS)); + List left = leftBehind(now.minusMillis(END_GRACE_MILLIS)); Exception failed = null; for (int iter = 0; iter < left.size(); iter++) { String id = left.get(iter).getRideId(); @@ -174,13 +175,13 @@ public void endLeftBehind() throws IOException { } @Transactional - private void dropEndedBefore(long before) { - activities.dropEndedBefore(before); + private void dropEndedBefore(Instant before) { + activities.dropEndedBefore(before, Instant.EPOCH); } @Transactional(readOnly = true) - private List leftBehind(long before) { - return activities.leftBehind(before, new PageRequest(0, 50)); + private List leftBehind(Instant before) { + return activities.leftBehind(before, Instant.EPOCH, new PageRequest(0, 50)); } @Transactional @@ -252,11 +253,11 @@ public RideActivityDto attach(String rider, String rideId, RideActivityDto activ row.setRideId(rideId); row.setUsername(rider); row.setActivityId(activityId); - row.setSentAt(System.currentTimeMillis()); + row.setSentAt(Instant.now()); activities.insert(row); } else { row.setActivityId(activityId); - row.setSentAt(System.currentTimeMillis()); + row.setSentAt(Instant.now()); } return new RideActivityDto(activityId); } @@ -376,7 +377,7 @@ private List compose(String id, RideState state, String rider, String } // end::wayline-push-messages[] if (!state.isActive() && activity != null) { - activities.markEnded(id, System.currentTimeMillis()); + activities.markEnded(id, Instant.now(), Instant.EPOCH); } if (toRider != null && !wants(rider, RideState.COMPLETED == state)) { toRider = null; @@ -423,10 +424,10 @@ private List moved(String rideId, double lat, double lng) throws IOExc if (activity == null) { return out; } - long now = System.currentTimeMillis(); + Instant now = Instant.now(); // A conditional update, so that two reports arriving together send one // update between them. - if (activities.claim(rideId, now, now - activityMillis) != 1) { + if (activities.claim(rideId, now, now.minusMillis(activityMillis)) != 1) { return out; } Ride ride = rides.findById(rideId); diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverApplicationRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverApplicationRepository.java index 45aea747af3..3d4b5e02329 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverApplicationRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverApplicationRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.DriverApplication; +import java.time.Instant; import java.util.List; /// Applications to drive, one per account at most, keyed by the account. @@ -72,7 +73,7 @@ public interface DriverApplicationRepository extends CrudRepository :to") int approveUnlessApproved(@Param("username") String username, - @Param("to") String approved, @Param("at") long at, @Param("by") String by); + @Param("to") String approved, @Param("at") Instant at, @Param("by") String by); /// Hands an application in: from the status it was read in to `to`, with /// the last rejection's reason cleared. @@ -89,7 +90,7 @@ int approveUnlessApproved(@Param("username") String username, @Query("update DriverApplication a set a.status = :to, a.submittedAt = :at, " + "a.rejectionReason = '' where a.username = :username and a.status = :from") int submit(@Param("username") String username, @Param("from") String from, - @Param("to") String to, @Param("at") long at); + @Param("to") String to, @Param("at") Instant at); /// Makes the rest of the transaction wait its turn behind any other that /// holds, or moves, the same application. diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverDocumentRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverDocumentRepository.java index 63015ad1e33..535816440bd 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverDocumentRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/DriverDocumentRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.session.Identifier; import com.codenameone.examples.wayline.domain.DriverDocument; +import java.time.Instant; import java.util.List; /// The documents of applications to drive, keyed by @@ -58,7 +59,7 @@ public interface DriverDocumentRepository extends CrudRepository freeInBox(@Param("fresh") long fresh, @Param("south") double south, + List freeInBox(@Param("fresh") Instant fresh, @Param("south") double south, @Param("north") double north, @Param("west") double west, @Param("east") double east, @Param("approved") String approved, @Param("withRide") RideState[] withRide); @@ -85,7 +86,7 @@ List freeInBox(@Param("fresh") long fresh, @Param("south") double s int takeOffLine(@Param("username") String username); /// The drivers on line who reported in at or after `seenSince`. - long countByOnlineTrueAndLastSeenGreaterThanEqual(long seenSince); + long countByOnlineTrueAndLastSeenGreaterThanEqual(Instant seenSince); int deleteByUsername(String username); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/LiveTicketRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/LiveTicketRepository.java index 1b84547ab97..44ae5c711de 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/LiveTicketRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/LiveTicketRepository.java @@ -21,6 +21,7 @@ import com.codename1.orm.repository.CrudRepository; import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.LiveTicket; +import java.time.Instant; /// The tickets that open a live connection. Only the hash of a ticket is /// stored, and it is the row's key. @@ -33,7 +34,7 @@ public interface LiveTicketRepository extends CrudRepository int deleteByTicketHash(String ticketHash); /// Deletes the tickets that went stale before `now`. - int deleteByExpiresAtLessThan(long now); + int deleteByExpiresAtLessThan(Instant now); int deleteByUsername(String username); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/ModerationEventRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/ModerationEventRepository.java index 680e8f19138..a7fbfe21c57 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/ModerationEventRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/ModerationEventRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.ModerationEvent; +import java.time.Instant; import java.util.List; /// The record of what the admins did to each account. @@ -32,7 +33,7 @@ public interface ModerationEventRepository extends CrudRepository findTop100ByUsernameOrderByCreatedAtDescIdAsc(String username); diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentMethodRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentMethodRepository.java index 01b1646738e..7b1b104e8cb 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentMethodRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentMethodRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.PaymentMethod; +import java.time.Instant; import java.util.List; /// The cards accounts saved. @@ -42,7 +43,7 @@ public interface PaymentMethodRepository extends CrudRepository { @Query("update Payment p set p.status = :status, p.refundedAt = :at " + "where p.rideId = :id and p.status = 'REFUND_PENDING'") int endRefund(@Param("id") String rideId, @Param("status") String status, - @Param("at") long at); + @Param("at") Instant at); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentSetupRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentSetupRepository.java index e81e7c95c63..a5feb7268e4 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentSetupRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/PaymentSetupRepository.java @@ -24,6 +24,7 @@ import com.codename1.orm.repository.Query; import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.PaymentSetup; +import java.time.Instant; /// The card setups accounts began with the payment processor. @Repository(entity = PaymentSetup.class, key = String.class) @@ -39,7 +40,7 @@ public interface PaymentSetupRepository extends CrudRepository { /// When each account made since `since` was made. @Query("select p.createdAt from Profile p where p.createdAt >= :since") - List signUps(@Param("since") long since); + List signUps(@Param("since") Instant since); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideActivityRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideActivityRepository.java index 5e0a7c64c84..efe7ae4c33a 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideActivityRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideActivityRepository.java @@ -26,6 +26,7 @@ import com.codename1.orm.repository.Repository; import com.codenameone.examples.wayline.domain.RideActivity; +import java.time.Instant; import java.util.List; /// The Live Activities riders follow their rides in, by ride. @@ -40,23 +41,26 @@ public interface RideActivityRepository extends CrudRepository 0 and a.endedAt < :before " + @Query("select a from RideActivity a where a.endedAt > :none and a.endedAt < :before " + "order by a.endedAt") - List leftBehind(@Param("before") long before, PageRequest page); + List leftBehind(@Param("before") Instant before, @Param("none") Instant none, + PageRequest page); /// Forgets the activities whose ride ended before `before`. @Modifying - @Query("delete from RideActivity a where a.endedAt > 0 and a.endedAt < :before") - int dropEndedBefore(@Param("before") long before); + @Query("delete from RideActivity a where a.endedAt > :none and a.endedAt < :before") + int dropEndedBefore(@Param("before") Instant before, @Param("none") Instant none); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideEventRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideEventRepository.java index dc9ca139a6f..9baef41d178 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideEventRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideEventRepository.java @@ -25,6 +25,7 @@ import com.codenameone.examples.wayline.api.RideState; import com.codenameone.examples.wayline.domain.RideEvent; +import java.time.Instant; import java.util.List; /// What happened to each ride: one row for every state it came into. @@ -42,5 +43,5 @@ public interface RideEventRepository extends CrudRepository { /// rides are named by a nested query. @Query("select e.rideId, e.createdAt from RideEvent e where e.state = :state " + "and e.rideId in (select r.id from Ride r where r.requestedAt >= :since)") - List reached(@Param("since") long since, @Param("state") RideState state); + List reached(@Param("since") Instant since, @Param("state") RideState state); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideRepository.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideRepository.java index 19e7a1fce90..411bfa8fcac 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideRepository.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/repository/RideRepository.java @@ -27,6 +27,7 @@ import com.codenameone.examples.wayline.api.RideState; import com.codenameone.examples.wayline.domain.Ride; +import java.time.Instant; import java.util.List; /// Rides. @@ -70,11 +71,11 @@ boolean existsByRiderAndMethodIdAndStateIn(String rider, String methodId, /// `paymentStatus` and which ended after `since`, is to be charged to /// this method. boolean existsByRiderAndStateAndPaymentStatusAndUpdatedAtGreaterThanAndMethodId( - String rider, RideState state, String paymentStatus, long since, String methodId); + String rider, RideState state, String paymentStatus, Instant since, String methodId); /// The same, to be charged to any method but `methodId`. boolean existsByRiderAndStateAndPaymentStatusAndUpdatedAtGreaterThanAndMethodIdNot( - String rider, RideState state, String paymentStatus, long since, String methodId); + String rider, RideState state, String paymentStatus, Instant since, String methodId); /// A rider's rides whose payment is `paymentStatus` and that carry a tip. List findByRiderAndPaymentStatusAndTipCentsGreaterThan(String rider, @@ -99,18 +100,18 @@ List findByRiderAndStateOrderByRequestedAtDesc(String rider, RideState sta List newest(PageRequest page); /// The rides in `state` whose offer ran out before `now`. - List findByStateAndOfferExpiresAtLessThan(RideState state, long now); + List findByStateAndOfferExpiresAtLessThan(RideState state, Instant now); /// The rides in `state`, the one that has waited longest first. List findByStateOrderByRequestedAtAsc(RideState state); /// A driver's rides in `state` that changed at or after a time. List findByDriverAndStateAndUpdatedAtGreaterThanEqual(String driver, - RideState state, long since); + RideState state, Instant since); long countByDriverAndState(String driver, RideState state); - long countByRequestedAtGreaterThanEqual(long since); + long countByRequestedAtGreaterThanEqual(Instant since); long countByStateIn(RideState[] states); @@ -128,14 +129,14 @@ long countByRiderAndStateOrDriverAndState(String rider, RideState asRider, Strin @Query("update Ride r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from and r.rider = :rider") int moveAsRider(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now, @Param("rider") String rider); + @Param("to") RideState to, @Param("now") Instant now, @Param("rider") String rider); /// Moves a ride of `driver`'s from one of `from` to `to`. @Modifying(clearAutomatically = true) @Query("update Ride r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from and r.driver = :driver") int moveAsDriver(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now, @Param("driver") String driver); + @Param("to") RideState to, @Param("now") Instant now, @Param("driver") String driver); // tag::wayline-ride-move[] /// Takes an offer made to `driver`: refused once the offer has lapsed, as @@ -145,7 +146,7 @@ int moveAsDriver(@Param("id") String id, @Param("from") RideState[] from, + "where r.id = :id and r.state in :from and r.driver = :driver " + "and r.offerExpiresAt >= :now") int takeOffer(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now, @Param("driver") String driver); + @Param("to") RideState to, @Param("now") Instant now, @Param("driver") String driver); // end::wayline-ride-move[] /// Gives a ride of `driver`'s back to be offered again, writing @@ -154,7 +155,7 @@ int takeOffer(@Param("id") String id, @Param("from") RideState[] from, @Query("update Ride r set r.state = :to, r.updatedAt = :now, r.driver = :newDriver " + "where r.id = :id and r.state in :from and r.driver = :driver") int giveBack(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now, @Param("driver") String driver, + @Param("to") RideState to, @Param("now") Instant now, @Param("driver") String driver, @Param("newDriver") String newDriver); /// Holds `rider`'s ride while it is in one of `states`, answering 0 when @@ -174,15 +175,15 @@ int holdWhile(@Param("id") String id, @Param("rider") String rider, @Query("update Ride r set r.state = :to, r.updatedAt = :now " + "where r.id = :id and r.state in :from") int moveByServer(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now); + @Param("to") RideState to, @Param("now") Instant now); /// Offers a ride to `driver` until `expiresAt`. @Modifying(clearAutomatically = true) @Query("update Ride r set r.state = :to, r.updatedAt = :now, r.driver = :driver, " + "r.offerExpiresAt = :expiresAt where r.id = :id and r.state in :from") int offer(@Param("id") String id, @Param("from") RideState[] from, - @Param("to") RideState to, @Param("now") long now, @Param("driver") String driver, - @Param("expiresAt") long expiresAt); + @Param("to") RideState to, @Param("now") Instant now, @Param("driver") String driver, + @Param("expiresAt") Instant expiresAt); // ----------------------------------------------------------- the rest @@ -200,7 +201,7 @@ int offer(@Param("id") String id, @Param("from") RideState[] from, /// behind the new arrivals until they aged out of the window unsettled. @Query("select r from Ride r where r.state = 'COMPLETED' and r.paymentStatus = 'PENDING' " + "and r.updatedAt < :before and r.updatedAt > :after order by r.updatedAt asc") - List unsettled(@Param("after") long after, @Param("before") long before, + List unsettled(@Param("after") Instant after, @Param("before") Instant before, PageRequest page); /// Records how the charge for a ride came out. A statement of its own and @@ -262,13 +263,13 @@ List unsettled(@Param("after") long after, @Param("before") long before, @Query("select count(r), coalesce(sum(r.driverCents), 0) from Ride r " + "where r.driver = :driver and r.state = 'COMPLETED' and r.paymentStatus = 'PAID' " + "and r.updatedAt >= :since") - Object[] paidTotalsSince(@Param("driver") String driver, @Param("since") long since); + Object[] paidTotalsSince(@Param("driver") String driver, @Param("since") Instant since); /// What the driver's share of their completed, paid rides came to since /// a time. @Query("select coalesce(sum(r.driverCents), 0) from Ride r where r.driver = :driver " + "and r.state = 'COMPLETED' and r.paymentStatus = 'PAID' and r.updatedAt >= :since") - Long paidSince(@Param("driver") String driver, @Param("since") long since); + Long paidSince(@Param("driver") String driver, @Param("since") Instant since); /// The driver's share of the fares of every ride they completed and that /// was paid for -- in cash, or by a card whose charge came back. A charge @@ -295,7 +296,7 @@ List unsettled(@Param("after") long after, @Param("before") long before, @Query("select r.id from Ride r where r.driver = :driver and r.state = 'COMPLETED' " + "and r.updatedAt >= :since and r.methodId <> 'cash' and r.paymentStatus = 'PAID' " + "and r.id in (select p.rideId from Payment p where p.tipRef <> '')") - List tipChargedSince(@Param("driver") String driver, @Param("since") long since); + List tipChargedSince(@Param("driver") String driver, @Param("since") Instant since); /// What riders paid in fares for rides in `state` whose payment is `paid`. @Query("select coalesce(sum(r.fareCents), 0) from Ride r " @@ -305,22 +306,22 @@ List unsettled(@Param("after") long after, @Param("before") long before, /// The fares of the rides in `state` asked for since `since`, paid or not. @Query("select coalesce(sum(r.fareCents), 0) from Ride r " + "where r.requestedAt >= :since and r.state = :state") - Long faresSince(@Param("since") long since, @Param("state") RideState state); + Long faresSince(@Param("since") Instant since, @Param("state") RideState state); /// The rides asked for since `since`, counted by state: `{state, count}`. @Query("select r.state, count(r) from Ride r where r.requestedAt >= :since group by r.state") - List countByState(@Param("since") long since); + List countByState(@Param("since") Instant since); /// The same by product: `{product, count}`. @Query("select r.product, count(r) from Ride r where r.requestedAt >= :since " + "group by r.product") - List countByProduct(@Param("since") long since); + List countByProduct(@Param("since") Instant since); /// The rides in `state` asked for since `since`, counted by driver: /// `{driver, count}`. @Query("select r.driver, count(r) from Ride r where r.requestedAt >= :since " + "and r.state = :state group by r.driver") - List countByDriver(@Param("since") long since, @Param("state") RideState state); + List countByDriver(@Param("since") Instant since, @Param("state") RideState state); /// One row for each ride asked for since `since`: `{id, requestedAt, /// state, fareCents, paymentStatus}`. @@ -333,7 +334,7 @@ List unsettled(@Param("after") long after, @Param("before") long before, /// word does not see those as one expression. @Query("select r.id, r.requestedAt, r.state, r.fareCents, r.paymentStatus from Ride r " + "where r.requestedAt >= :since") - List timeline(@Param("since") long since); + List timeline(@Param("since") Instant since); /// What a rider paid for rides in `state` whose payment is `paid`: /// `{fares, fees, tips}`. diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/DemoRides.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/DemoRides.java index 5c4e79d5bf5..5823d2f2173 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/DemoRides.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/DemoRides.java @@ -44,6 +44,7 @@ import com.codenameone.examples.wayline.repository.RideRepository; import java.io.IOException; +import java.time.Instant; /// Two weeks of rides that were never taken, so that the admin's charts, a /// driver's earnings and a rider's receipts have something in them the first @@ -180,9 +181,9 @@ public void seed(String[] riders, String[] drivers, boolean untilToday) throws I ride.setCurrency(fares.currency()); ride.setDistanceMeters(meters); ride.setDurationSeconds(seconds); - ride.setRequestedAt(at); - ride.setUpdatedAt(ended); - ride.setSearchUntil(at + 90000L); + ride.setRequestedAt(Instant.ofEpochMilli(at)); + ride.setUpdatedAt(Instant.ofEpochMilli(ended)); + ride.setSearchUntil(Instant.ofEpochMilli(at + 90000L)); ride.setStars(given); ride.setPaymentStatus(completed ? Payments.PAID : Payments.PENDING); ride.setProduct(products[driverIndex]); @@ -222,7 +223,7 @@ public void seed(String[] riders, String[] drivers, boolean untilToday) throws I // and for a refund -- once its charge has a reference. payment.setTipRef("sim_ch_tip-" + id); } - payment.setCreatedAt(ended); + payment.setCreatedAt(Instant.ofEpochMilli(ended)); paid.insert(payment); lastSeen[driverIndex] = Math.max(lastSeen[driverIndex], ended); if (ended < now - 7L * Days.MILLIS) { @@ -246,7 +247,7 @@ public void seed(String[] riders, String[] drivers, boolean untilToday) throws I } car.setLat(real(iter % PLACES.length, 1)); car.setLng(real(iter % PLACES.length, 2)); - car.setLastSeen(lastSeen[iter]); + car.setLastSeen(Instant.ofEpochMilli(lastSeen[iter])); car.setRatingSum(stars[iter]); car.setRatingCount(rated[iter]); if (first) { @@ -265,7 +266,7 @@ public void seed(String[] riders, String[] drivers, boolean untilToday) throws I payout.setDriver(drivers[iter]); payout.setAmountCents(earnedEarlier[iter]); payout.setStatus("paid"); - payout.setCreatedAt(now - 7L * Days.MILLIS); + payout.setCreatedAt(Instant.ofEpochMilli(now - 7L * Days.MILLIS)); payout.setDestination("Bay Credit Union ****67" + (10 + iter)); payouts.insert(payout); } @@ -278,7 +279,7 @@ private void event(String ride, RideState state, String actor, long at) throws I event.setRideId(ride); event.setState(state); event.setActor(actor); - event.setCreatedAt(at); + event.setCreatedAt(Instant.ofEpochMilli(at)); events.insert(event); } diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Fares.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Fares.java index b578c1a7f0e..55275fbc8b2 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Fares.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Fares.java @@ -30,6 +30,7 @@ import com.codenameone.examples.wayline.repository.PricingRepository; import java.io.IOException; +import java.time.Instant; /// What a ride costs. /// @@ -88,7 +89,7 @@ public PricingDto pricing() throws IOException { private PricingDto toDto(Pricing row) { // The row a migration created and nobody has saved over yet. - if (row == null || row.getUpdatedAt() == 0L) { + if (row == null || Instant.EPOCH.equals(row.getUpdatedAt())) { return defaults; } // The currency is a setting and stays one. Rides already taken are in @@ -121,7 +122,7 @@ public PricingDto save(String by, PricingDto wanted) throws IOException { if (prices.change(PricingRepository.ONLY.intValue(), wanted.baseFare(), wanted.perKm(), wanted.perMinute(), wanted.minimumFare(), wanted.serviceFeePercent(), wanted.commissionPercent(), wanted.surgeMultiplier(), - wanted.comfortMultiplier(), wanted.xlMultiplier(), System.currentTimeMillis(), + wanted.comfortMultiplier(), wanted.xlMultiplier(), Instant.now(), by) == 0) { throw new IllegalStateException("The pricing row is missing; the V6 migration " + "creates it"); diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Matcher.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Matcher.java index 4363ef2078f..a243eca7bca 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Matcher.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Matcher.java @@ -36,6 +36,7 @@ import com.codenameone.examples.wayline.repository.RidePassedRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -145,7 +146,7 @@ public List nearby(double lat, double lng, double radiusMeters, Strin double dLat = radiusMeters / Geo.METERS_PER_DEGREE; double shrink = Math.max(0.01d, Math.cos(Math.toRadians(lat))); double dLng = radiusMeters / (Geo.METERS_PER_DEGREE * shrink); - List boxed = drivers.freeInBox(System.currentTimeMillis() - FRESH_MILLIS, + List boxed = drivers.freeInBox(Instant.now().minusMillis(FRESH_MILLIS), lat - dLat, lat + dLat, lng - dLng, lng + dLng, Applications.APPROVED, WITH_RIDE); List inReach = new ArrayList(); List names = new ArrayList(); diff --git a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Rides.java b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Rides.java index 8bc4db9443a..52570aac5f6 100644 --- a/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Rides.java +++ b/scripts/wayline/backend/src/main/java/com/codenameone/examples/wayline/ride/Rides.java @@ -53,6 +53,7 @@ import com.codenameone.examples.wayline.repository.RideRepository; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -234,7 +235,7 @@ private String open(String rider, RideRequestDto request) throws IOException { double seconds = fares.durationSeconds(request, meters); PricingDto pricing = fares.pricing(); Fares.Price price = Fares.price(pricing, meters, seconds, product); - long now = System.currentTimeMillis(); + Instant now = Instant.now(); // The fare is fixed here, from the server's own arithmetic, and so is // the driver's share of it: a change of prices or of commission made // while the ride is under way is for the rides after it. The quote the @@ -255,7 +256,7 @@ private String open(String rider, RideRequestDto request) throws IOException { ride.setDurationSeconds(seconds); ride.setRequestedAt(now); ride.setUpdatedAt(now); - ride.setSearchUntil(now + searchMillis); + ride.setSearchUntil(now.plusMillis(searchMillis)); ride.setPaymentStatus(Payments.PENDING); ride.setProduct(product); ride.setMethodId(method[0]); @@ -412,8 +413,9 @@ private Ride finish(String driver, String id) throws IOException { /// became of such a ride is for a person to find in the processor's records. @Scheduled(fixedDelay = 60000, initialDelay = 30000, lock = "wayline-settlement") public void settleLeftBehind() throws IOException { - long now = System.currentTimeMillis(); - List unsettled = unsettled(now - RETRY_MILLIS, now - UNSETTLED_MILLIS); + Instant now = Instant.now(); + List unsettled = unsettled(now.minusMillis(RETRY_MILLIS), + now.minusMillis(UNSETTLED_MILLIS)); Exception failed = null; for (int iter = 0; iter < unsettled.size(); iter++) { Ride ride = unsettled.get(iter); @@ -434,7 +436,7 @@ public void settleLeftBehind() throws IOException { } @Transactional(readOnly = true) - private List unsettled(long after, long before) { + private List unsettled(Instant after, Instant before) { return rides.unsettled(after, before, new PageRequest(0, 50)); } @@ -568,12 +570,12 @@ private Change choose(String id, String[] chosen) throws IOException { if (ride == null || RideState.REQUESTED != ride.getState()) { return null; } - long now = System.currentTimeMillis(); - if (now > ride.getSearchUntil()) { + Instant now = Instant.now(); + if (now.isAfter(ride.getSearchUntil())) { return tryMove(id, RideState.NO_DRIVERS, "", null, null, null) ? new Change(id, RideState.NO_DRIVERS, ride.getRider(), "", "", null) : null; } - chosen[0] = matcher.pick(ride, now - ride.getRequestedAt()); + chosen[0] = matcher.pick(ride, now.toEpochMilli() - ride.getRequestedAt().toEpochMilli()); return null; } @@ -603,11 +605,12 @@ Change offer(String id, String driver) throws IOException { if (ride == null || RideState.REQUESTED != ride.getState()) { return null; } - long now = System.currentTimeMillis(); - if (!matcher.fits(ride, driver, now - ride.getRequestedAt())) { + Instant now = Instant.now(); + if (!matcher.fits(ride, driver, + now.toEpochMilli() - ride.getRequestedAt().toEpochMilli())) { return null; } - return tryMove(id, RideState.OFFERED, "", null, driver, Long.valueOf(now + offerMillis)) + return tryMove(id, RideState.OFFERED, "", null, driver, now.plusMillis(offerMillis)) ? new Change(id, RideState.OFFERED, ride.getRider(), driver, "", null) : null; } // end::wayline-ride-offer[] @@ -622,7 +625,7 @@ Change offer(String id, String driver) throws IOException { @Scheduled(fixedDelay = 2000, initialDelay = 2000, lock = "wayline-matching") public void tick() throws IOException { Exception failed = null; - List lapsed = lapsedOffers(System.currentTimeMillis()); + List lapsed = lapsedOffers(Instant.now()); for (int iter = 0; iter < lapsed.size(); iter++) { Ride ride = lapsed.get(iter); try { @@ -652,7 +655,7 @@ public void tick() throws IOException { } @Transactional(readOnly = true) - private List lapsedOffers(long now) throws IOException { + private List lapsedOffers(Instant now) throws IOException { return rides.findByStateAndOfferExpiresAtLessThan(RideState.OFFERED, now); } @@ -758,7 +761,7 @@ private static T attempt(Work work) throws IOException { /// Moves a ride to `to`, or answers 409 when its state does not allow it. private void move(String id, RideState to, String actor, String ownerField, String newDriver, - Long newOfferExpiresAt) throws IOException { + Instant newOfferExpiresAt) throws IOException { if (!tryMove(id, to, actor, ownerField, newDriver, newOfferExpiresAt)) { Ride now = find(id); throw new ResponseStatusException(409, "That ride is " @@ -781,15 +784,15 @@ private void move(String id, RideState to, String actor, String ownerField, Stri /// @param newOfferExpiresAt when the offer this change makes lapses, or null // tag::wayline-ride-trymove[] private boolean tryMove(String id, RideState to, String actor, String ownerField, - String newDriver, Long newOfferExpiresAt) throws IOException { + String newDriver, Instant newOfferExpiresAt) throws IOException { RideState[] sources = RideStateMachine.sources(to); if (sources.length == 0) { return false; } - long now = System.currentTimeMillis(); + Instant now = Instant.now(); int moved; if (newOfferExpiresAt != null) { - moved = rides.offer(id, sources, to, now, newDriver, newOfferExpiresAt.longValue()); + moved = rides.offer(id, sources, to, now, newDriver, newOfferExpiresAt); } else if (RIDER.equals(ownerField)) { moved = rides.moveAsRider(id, sources, to, now, actor); } else if (!DRIVER.equals(ownerField)) { @@ -817,7 +820,7 @@ private void event(String id, RideState state, String actor) throws IOException event.setRideId(id); event.setState(state); event.setActor(actor); - event.setCreatedAt(System.currentTimeMillis()); + event.setCreatedAt(Instant.now()); events.insert(event); } @@ -957,7 +960,7 @@ private RideDto toDto(Ride ride, String viewer, Map cache, bool } if (offered) { offerExpiresInSeconds = (int) Math.max(0L, - (ride.getOfferExpiresAt() - System.currentTimeMillis()) / 1000L); + (ride.getOfferExpiresAt().toEpochMilli() - System.currentTimeMillis()) / 1000L); } long fareCents = ride.getFareCents(); long serviceFee = ride.getFeeCents(); @@ -985,8 +988,8 @@ private RideDto toDto(Ride ride, String viewer, Map cache, bool ride.getCurrency(), ride.getDistanceMeters(), ride.getDurationSeconds(), - ride.getRequestedAt(), - ride.getUpdatedAt(), + ride.getRequestedAt().toEpochMilli(), + ride.getUpdatedAt().toEpochMilli(), ride.getStars(), ride.getPaymentStatus(), offerExpiresInSeconds, From 373da98ea4598f4dcfc7fe762f13ee328798f5d1 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:44:23 +0200 Subject: [PATCH 2/2] Initializr: gate the java.time demos on 7.0.280 Wayline, Savor, Skirmish and Parley now store java.time.Instant entity fields, which only 7.0.280's ORM maps, so they get the same gate Bastion and Reel already have. Resynced skirmish-modules.zip after the merge. Co-Authored-By: Claude Opus 5.5 --- .../codename1/initializr/model/GeneratorModel.java | 8 +++++++- .../initializr/model/GeneratorModelMatrixTest.java | 13 +++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/model/GeneratorModel.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/model/GeneratorModel.java index 27f89917f8f..e17d847771d 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/model/GeneratorModel.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/model/GeneratorModel.java @@ -92,10 +92,16 @@ public static boolean isMavenLayoutChoiceOffered() { /// generated there. static final String BASTION_SINCE = "7.0.280"; + /// The first release whose ORM maps `java.time.Instant` entity fields, which + /// every other full-stack template's server stores its timestamps in. Against + /// an older release its backend does not compile, so it is neither offered nor + /// generated there. + static final String JAVA_TIME_ENTITIES_SINCE = "7.0.280"; + /// The first release a template can be generated against. static String templateSince(Template template) { return template == Template.BASTION ? BASTION_SINCE - : template == Template.REEL ? REEL_SINCE : FULL_STACK_SINCE; + : template == Template.REEL ? REEL_SINCE : JAVA_TIME_ENTITIES_SINCE; } /// The brand colour of the full-stack template as it ships: the `--brand` its diff --git a/scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java b/scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java index 982382694c8..983fedfbda3 100644 --- a/scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java +++ b/scripts/initializr/common/src/test/java/com/codename1/initializr/model/GeneratorModelMatrixTest.java @@ -507,11 +507,14 @@ private void validateFullStackTemplate() throws Exception { true, false, ProjectOptions.PreviewLanguage.ENGLISH, ProjectOptions.JavaVersion.JAVA_8, null, ProjectOptions.BuildTool.MAVEN, ProjectOptions.ProjectType.APP_WITH_BACKEND); assertRefused(GeneratorModel.createForPluginVersion(IDE.INTELLIJ, Template.WAYLINE, "NoJava8", - "com.acme.nojava8", java8, FULL_STACK_VERSION), "Java 17", "A full-stack template is Java 17"); + "com.acme.nojava8", java8, WAYLINE_VERSION), "Java 17", "A full-stack template is Java 17"); // Bastion's app calls framework API newer than the other templates need. assertRefused(GeneratorModel.createForPluginVersion(IDE.INTELLIJ, Template.BASTION, "TooOld", "com.acme.tooold", mavenOptions(ProjectOptions.ProjectType.APP_WITH_BACKEND, false), FULL_STACK_VERSION), GeneratorModel.BASTION_SINCE, "Bastion must refuse a release before its own"); + assertRefused(GeneratorModel.createForPluginVersion(IDE.INTELLIJ, Template.WAYLINE, "OldTime", + "com.acme.oldtime", base, FULL_STACK_VERSION), GeneratorModel.JAVA_TIME_ENTITIES_SINCE, + "Wayline's server stores java.time entity fields, which a release before its gate cannot map"); ProjectOptions forced = java8.withBuild(ProjectOptions.BuildTool.GRADLE, ProjectOptions.ProjectType.APP) .forFullStack(); assertTrue(!forced.isGradle() && forced.projectType == ProjectOptions.ProjectType.APP_WITH_BACKEND @@ -519,7 +522,7 @@ private void validateFullStackTemplate() throws Exception { "forFullStack should settle the build, the project type and the Java level"); String themePath = "common/src/main/css/theme.css"; - String stock = getText(mavenEntries(FULL_STACK_VERSION, Template.WAYLINE, IDE.INTELLIJ, "StockApp", + String stock = getText(mavenEntries(WAYLINE_VERSION, Template.WAYLINE, IDE.INTELLIJ, "StockApp", "com.acme.stock", base), themePath); String brand = Integer.toHexString(GeneratorModel.FULL_STACK_BRAND); assertContains(stock, "--brand: #" + brand + ";", @@ -529,7 +532,7 @@ private void validateFullStackTemplate() throws Exception { "The stock scheme must leave the stylesheet exactly as the template has it"); byte[] icon = new byte[] {(byte) 0x89, 'P', 'N', 'G', 1, 2, 3}; - Map styled = mavenEntries(FULL_STACK_VERSION, Template.WAYLINE, IDE.INTELLIJ, "StyledApp", + Map styled = mavenEntries(WAYLINE_VERSION, Template.WAYLINE, IDE.INTELLIJ, "StyledApp", "com.acme.styled", base.withScheme(0x0f766e, false).withIcon(icon)); String css = getText(styled, themePath); assertContains(css, "--brand: #0f766e;", "The chosen brand colour should be the theme's"); @@ -545,7 +548,7 @@ private void validateFullStackTemplate() throws Exception { "Choosing a scheme should rewrite declarations and add no rules"); assertTrue(java.util.Arrays.equals(icon, styled.get("common/icon.png")), "The chosen icon should replace the stock one"); - assertFalse(java.util.Arrays.equals(icon, mavenEntries(FULL_STACK_VERSION, Template.WAYLINE, IDE.INTELLIJ, + assertFalse(java.util.Arrays.equals(icon, mavenEntries(WAYLINE_VERSION, Template.WAYLINE, IDE.INTELLIJ, "StockApp", "com.acme.stock", base).get("common/icon.png")), "Without a chosen icon the project keeps the stock one"); @@ -576,6 +579,8 @@ private void assertRefused(GeneratorModel model, String expectedReason, String m private static final String LAYOUTS_VERSION = "7.0.275"; /// The version the full-stack combinations are generated for. private static final String FULL_STACK_VERSION = GeneratorModel.FULL_STACK_SINCE; + /// The version Wayline is generated for: its own gate, past the contract module's. + private static final String WAYLINE_VERSION = GeneratorModel.templateSince(Template.WAYLINE); /// The streaming template needs a newer core than the other complete apps: /// below its own gate it is refused, and the page does not list it.