// ĠCopyright Ġ 2 0 2 0 ĠMat th ieu ĠF elix Ċ // Ċ // ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ // Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ // ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ // Ċ // Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ // Ċ // ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ // Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ // ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ // ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ // Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ċ package Ġio . ter b ium . oss i Ċ Ċ import Ġcom . mo and j ie z ana . toml . Tom l Ċ import Ġio . ktor . application . Application Ċ import Ġio . ktor . application . Application Call Ċ import Ġio . ktor . application . call Ċ import Ġio . ktor . application . install Ċ import Ġio . ktor . content . Text Content Ċ import Ġio . ktor . features .* Ċ import Ġio . ktor . gson . gson Ċ import Ġio . ktor . http . ContentType Ċ import Ġio . ktor . http . Cookie Ċ import Ġio . ktor . http . HttpStatusCode Ċ import Ġio . ktor . http . content . file Ċ import Ġio . ktor . http . content . files Ċ import Ġio . ktor . http . content . static Ċ import Ġio . ktor . http . with Charset Ċ import Ġio . ktor . locations .* Ċ import Ġio . ktor . request . receive Ċ import Ġio . ktor . response . respond Ċ import Ġio . ktor . response . respond Text Ċ import Ġio . ktor . routing . get Ċ import Ġio . ktor . routing . post Ċ import Ġio . ktor . routing . route Ċ import Ġio . ktor . routing . routing Ċ import Ġio . ktor . server . engine . embedded Server Ċ import Ġio . ktor . server . netty . Net ty Ċ import Ġio . ktor . util . date . to GMT Date Ċ import Ġjava . io . File Ċ import Ġjava . lang . RuntimeException Ċ import Ġjava . time . Instant Ċ import Ġjava . time . temporal . Ch rono Unit Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ val Ġcookie Validity Seconds Ġ= ĠTimeUnit . HOUR S . to Seconds ( 2 4 ) Ċ Ċ fun ĠApplication . oss i ( dao : ĠComment Dao , Ġprefix : ĠString , Ġserve Static : ĠBoolean Ġ= Ġfalse ) Ġ{ ĊĠĠĠ Ġinstall ( Default Headers ) ĊĊĠĠĠ Ġinstall ( Content Neg otiation ) Ġ{ ĊĠĠĠĠĠĠĠ Ġgson Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġserialize Null s () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġregister Type Adapter ( Comment Mode :: class . java , ĠComment Mode . Ser De ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġinstall ( Status Pages ) Ġ{ ĊĠĠĠĠĠĠĠ Ġstatus ( HttpStatusCode . NotFound ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( Text Content ("${ it . value } Ġ${ it . description }", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠContentType . Text . Plain . with Charset ( Charsets . UTF _ 8 ), Ġit )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġinstall ( Locations ) ĊĊĠĠĠ Ġrouting Ġ{ ĊĠĠĠĠĠĠĠ Ġroute ("/ $ prefix ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġget ("/") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġuri Ġ= Ġcall . request . query Parameters [" uri "] Ġ?: Ġreturn @ get Ġcall . response . status ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcomments Ġ= Ġdao . get ( uri ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( make Thread ( comments )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost ("/ new ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġuri Ġ= Ġcall . request . query Parameters [" uri "] Ġ?: Ġreturn @ post Ġcall . response . status ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnew Comment Ġ= Ġcall . receive < New Comment Request >() ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! new Comment . validate ()) Ġreturn @ post Ġcall . response . status ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġauthorization Ġ= Ġget Authentication Token () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsaved Comment Ġ= Ġdao . new ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnew Comment . to Dao New Comment ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuri , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠInstant . now (). to Epoch Milli () Ġ/ Ġ 1 0 0 0 L , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . request . origin . remote Host ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġauthorization ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTODO Ġwhat Ġis Ġthis Ġmad ness ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcookie Ex ptime Ġ= ĠInstant . now (). plus ( cookie Validity Seconds , ĠCh rono Unit . SECONDS ). to GMT Date () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . cookies . append ( Cookie ( saved Comment . id . toString (), Ġauthorization , Ġpath Ġ= Ġ"/", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpires Ġ= Ġcookie Ex ptime )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . headers . append (" X - Set - Cookie ", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" is so -${ saved Comment . id } =$ authorization ; ĠMax - Age =$ cookie Validity Seconds }; ĠPath =/ ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . Created , Ġsaved Comment ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost ("/ count ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text (" [] ", ĠContentType . Application . Json ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġget < GetId > Ġ{ ĠgetId Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġobj Ġ= Ġdao . getId ( getId . id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġplain Ġ= Ġcall . request . query Parameters [" plain "] Ġ== Ġ" 1 " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( obj Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . response . status ( HttpStatusCode . NotFound ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! plain ) Ġobj Ġ= Ġobj . rendered () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( obj ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput < GetId > Ġ{ ĠgetId Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġedit Comment Ġ= Ġcall . receive < Edit Comment Request >() ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! edit Comment . validate ()) Ġreturn @ put Ġcall . response . status ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġauthorization Ġ= Ġcall . request . cookies [ getId . id . toString ()] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġreturn @ put Ġcall . response . status ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdao Edit Comment Ġ= Ġedit Comment . to Dao Edit Comment ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠInstant . now (). to Epoch Milli () Ġ/ Ġ 1 0 0 0 L ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( val Ġresponse Ġ= Ġdao . edit ( getId . id , Ġdao Edit Comment , Ġauthorization )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Edit Response . NotFound Ġ-> Ġcall . response . status ( HttpStatusCode . NotFound ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Edit Response . Not Authorized Ġ-> Ġcall . response . status ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Edit Response . Ok Ġ-> Ġcall . respond ( response . comment . rendered ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdelete < GetId > Ġ{ ĠgetId Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġauthorization Ġ= Ġcall . request . cookies [ getId . id . toString ()] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġreturn @ delete Ġcall . response . status ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( dao . delete ( getId . id , Ġauthorization )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Delete Response . NotFound Ġ-> Ġcall . response . status ( HttpStatusCode . NotFound ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Delete Response . Not Authorized Ġ-> Ġcall . response . status ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠComment Dao . Delete Response . Ok Ġ-> Ġcall . respond Text (" null ", ĠContentType . Application . Json ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost ("/ preview ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpreview Request Ġ= Ġcall . receive < Preview Request >() ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond ( Preview Response ( render Markdown ( preview Request . text ))) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost < Like > Ġ{ Ġvote ( it . id , Ġcall , Ġtrue , Ġdao ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost < Dis like > Ġ{ Ġvote ( it . id , Ġcall , Ġfalse , Ġdao ) Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( serve Static ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstatic ("/ js ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfiles (" static / js ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstatic ("/ css ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfiles (" static / css ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstatic ("/ img ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfiles (" static / img ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( serve Static ) Ġstatic ("/") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfile (" index . html ", Ġ" static / index . html ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ suspend Ġfun Ġvote ( id : ĠLong , Ġcall : ĠApplication Call , Ġup vote : ĠBoolean , Ġdao : ĠComment Dao ) Ġ{ ĊĠĠĠ Ġwhen Ġ( val Ġvote Result Ġ= Ġdao . vote ( id , Ġcall . request . origin . remote Host , Ġup vote )) Ġ{ ĊĠĠĠĠĠĠĠ Ġnull Ġ-> Ġcall . response . status ( HttpStatusCode . NotFound ) ĊĠĠĠĠĠĠĠ Ġelse Ġ-> Ġcall . respond ( Like Response ( vote Result . likes , Ġvote Result . dis likes )) ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Location ("/ id /{ id }") Ċ data Ġclass ĠGet Id ( val Ġid : ĠLong ) Ċ Ċ @ Location ("/ id /{ id }/ like ") Ċ data Ġclass ĠLike ( val Ġid : ĠLong ) Ċ Ċ @ Location ("/ id /{ id }/ dis like ") Ċ data Ġclass ĠDis like ( val Ġid : ĠLong ) Ċ Ċ fun Ġmain ( args : ĠArray < String >) Ġ{ ĊĠĠĠ Ġval Ġconfig Path Ġ= Ġargs . get OrNull ( 0 ) ĊĠĠĠ Ġval Ġconfig File Ġ= Ġconfig Path ?. let Ġ{ ĠTom l (). read ( File ( it )) Ġ} ĊĠĠĠ Ġval Ġdao Ġ= Ġif Ġ( configFile Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠ Ġwhen Ġ( val Ġdb Type Ġ= Ġconfig File . getString (" db "). toLowerCase ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" firestore " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfire store Table Ġ= Ġconfig File . getTable (" firestore ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFire store Dao ( firestore Table . getString (" project "), Ġfire store Table . getString (" kind ")) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" sqlite " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsqlite Table Ġ= Ġconfig File . getTable (" firestore ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSql ite Dao (" jdbc : sqlite :${ sqlite Table . getString (" db Path ") }) ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġthrow ĠRuntimeException (" unknown Ġdatabase Ġtype : Ġ$ db Type ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠ ĠSql ite Dao (" jdbc : sqlite : test . db ") ĊĠĠĠ Ġ} ĊĠĠĠ Ġval Ġserve Static Ġ= Ġconfig File ?. getBoolean (" serve _ static ") Ġ?: Ġtrue ĊĊĠĠĠ Ġval Ġserver Ġ= Ġembedded Server ( Net ty , Ġ 8 0 8 0 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġo ssi ( dao , Ġ" is so ", Ġserve Static Ġ= Ġtrue ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġserver . start ( wait Ġ= Ġtrue ) Ċ } Ċ