From a8d7d758f85116ef17f8dd7ad42437a01b2cef35 Mon Sep 17 00:00:00 2001
From: William Walker <wnwalker@ucsc.edu>
Date: Wed, 17 Jul 2024 16:09:38 -0700
Subject: [PATCH] Work on devices API, set up scheduler report scpt

---
 gradle/libs.versions.toml                     | 20 ++++++-----------
 temerity/.env.vault                           | 16 +++++++-------
 temerity/build.gradle.kts                     |  1 +
 .../edu/ucsc/its/temerity/PlatformClient.kt   | 10 ++++++---
 .../kotlin/edu/ucsc/its/temerity/Util.kt      | 13 +++++++++++
 .../ucsc/its/temerity/remote/PlatformApi.kt   | 10 +++++++--
 .../ucsc/its/temerity/SchedulerReportUtils.kt | 22 +++++++++++++++++++
 7 files changed, 66 insertions(+), 26 deletions(-)
 create mode 100644 temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/Util.kt
 create mode 100644 temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/SchedulerReportUtils.kt

diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 5165314..c864b6e 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,11 +1,12 @@
 [versions]
-agp = "8.2.0"
-compose-multiplatform = "1.7.0-alpha01"
+agp = "8.2.2"
+compose-multiplatform = "1.7.0-dev1731"
 kotlin = "2.0.0"
 ksp = "2.0.0-1.0.23"
 
-ktor = "3.0.0-beta-1"
+ktor = "3.0.0-beta-2"
 kotlinx-serialization = "1.7.1"
+kotlinx-io = "0.5.1"
 slf4j = "2.0.12"
 
 
@@ -23,12 +24,11 @@ molecule = "2.0.0"
 androidxLifecycle = "2.8.3"
 jetbrainsNavigationCompose = "2.7.0-alpha07"
 androidxRoom = "2.7.0-alpha05"
-sqlite = "2.5.0-alpha05"
+sqlite = "2.5.0-SNAPSHOT"
 androidxDatastore = "1.1.1"
 
 material3WindowSizeClass = "0.5.0"
-material3adaptive = "1.0.0-beta04"
-landscapistCoil3 = "2.3.2"
+landscapistCoil3 = "2.3.6"
 composables-menu = "1.4.0"
 bottomsheet = "0.1.3"
 composetheme = "1.1.0-alpha"
@@ -61,13 +61,9 @@ compileSdk = "34"
 
 ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
 ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" }
-ktor-client-logging-jvm = { group = "io.ktor", name = "ktor-client-logging-jvm", version.ref = "ktor" }
-ktor-client-logging-native = { group = "io.ktor", name = "ktor-client-logging-native", version.ref = "ktor" }
 ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serialization", version.ref = "ktor" }
 ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" }
-ktor-client-ios = { group = "io.ktor", name = "ktor-client-ios", version.ref = "ktor" }
 ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktor" }
-ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" }
 ktor-test = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
 slf4j = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
 
@@ -89,9 +85,6 @@ arrow-fx-coroutines = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref
 
 # Shared compose UI deps (some usages are platform-specific)
 koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koinComposeMultiplatform" }
-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3adaptive" }
-material3-adaptiveLayout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "material3adaptive" }
-material3-adaptiveNavigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "material3adaptive" }
 
 # Compose multiplatform libs
 # Koin version for Compose on Android: koin-androidx-compose
@@ -130,6 +123,7 @@ kotest-framework-datatest = { module = "io.kotest:kotest-framework-datatest", ve
 kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
 
 kotlinx-dataframe = { module = "org.jetbrains.kotlinx:dataframe", version.ref = "kotlinx-dataframe" }
+kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
 dokka-base = { module = "org.jetbrains.dokka:dokka-base", version.ref = "dokka" }
 
 klaxon = { module = "com.beust:klaxon", version.ref = "klaxon" }
diff --git a/temerity/.env.vault b/temerity/.env.vault
index d06c918..0f777f6 100644
--- a/temerity/.env.vault
+++ b/temerity/.env.vault
@@ -4,20 +4,20 @@
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="oft1TPnXDvV4VEi6xoMzeClw8U09BWo8iiMFqFGZdXoKJ7tVSFzaI3mRj49QKDYPr4ccJZVTwQcgQ8cjDEeqZk3edQXhVkztHBSQN49KhKdsZG99AtqQbBfUxFokOIuk+54Rz6PVBgel25ntmJILUcSP6Z7ApvOeO15PApTn5sWGSk4+KpUa7kuSfMYT3hBwdAhdwhxJsaIAxeFn8qQfM8CrQkYU4S4k/Uk4gcQ2GxEY70Kxz5Iz31Vzi5WlEsQkTlVKnqP9Tj2UYOWUtdhc+FGMLuMpQtVG2fH6TDYZvXRPR8jJesbTsSvSGt0FAR8T3W9uja0F+zswm4JlywSIRaFS1tLtbKkl8TyMQOOgkXb9Mf62d841B3VOsqYDbvKlQqwAYI4DR+vVkfZ6jv+DTBN1wZFAtXfuIv4Z+WWdwgeBRPyM05697SH0kk+uesPYHH0MIEDYvHpTleXGwV9dR9OZsZTMaleCtXS90foq8ZefDLIIzzRRvsoPVNIZZlbSqIc0r4HAvsOnb8znLtLBuTSsufkuF47O+qMubn8HPD6y+e+Qz53ZqVRcpiYnbfbwqEEwl7iUe59fGQBr0QGztPw1U/6yfb+TqIUbddivzf8xGleexvQUeps50o9/Hx6nxWRTyXYW5GN6FBP7sxlHma1uB5BsLOBKejTbARg5wRGRn19qhdNMgjaGUrIVPhJ/s2isre9OGn3mpmUEOH03NjG9UdvPa/0v6syAuH11f1kYBxlRMYi6Rq9rAMSomYUYjSdZ+T02x0m3zv3QJa9+mqQ/H8ULsF3J8jgXq8KX8e/KHya29Em07FK82pJavPeQABcaAK10/cUEnFeKyxvFITZgk8u/uahdVjvdwQuxkYj2bYpFOHzr56UzdRzsDDMg2iW8gitf9rkW0v7NlDeKenHZJCY1u2U5ir1MdHhSbnIsO/1gKnTVyt3PpHBhMYsNtRa7WTWJYtJ5rlpdBv0q5gNONh1Hx+ig70LMWjZNsJmghQX6Q9GOC/x74kjUNzbF4fLujiz5ahhzDresRCDn+5on8Wu59TpijWNsPxfxxaTKNX1qwxOlC/UyHweMwo+xnvlyXVlsQKfFZ5TxAySnYA0uw4MJYbaTQ4XtOSuoD64W702SkRqSP9lhtXhq2nWlnbXIbbhrnLHxtu8lcAyVAcXzsN6PRLBB3Tchhfrw6xwH5jxM3H4y"
-DOTENV_VAULT_DEVELOPMENT_VERSION=16
+DOTENV_VAULT_DEVELOPMENT="EnE6TVLniZFXFzAtABkOsICj+34eLqzVZQ3YDI1Bd5nOR7HI37TlQWH6CJWOwEfk0m4W6CUmzzi3H8lFI9WQaLeowM7Ta1i/ApZlSKQNX3E/oyKCNil2N/w/mC/haYFeUsTimh7wHj0G78c1z3+MQCLlymldQGqBVXOKLsaeJuNZdpEW+2SC43xciFBWCxGnfCgJfeyXBVcIgL8+vaPQYh6BYpvfEiuA/L/VupwZh8FLiCY9a2BvyhGscXwQbGEcUNLudmnAhtUzAps1FaDpKEP87ZNmU7ZWef/wr9fu7zTBOceBnLCmcDL3hP8yrZMREk4hEiQXDag5VE1shcqHfGUJ6pXm8yimzBEfncbyF4WLMR8tphX3FbxclPUoHBXbraIrL22aNjeXzoY/348K20mYAbqcrhlLgx7gPCcl/9/rSY5+wCnJfzQWFZcnmF3t2x1iHw2tAHj8btimfMLV/E+70pBfDxCsTIN6hQZ2uSGnWqLWT1ZpffKmJn/GkjmwM/8nSjCWhuNCUp/lmPJ7SFF4kPRiuq9N5JsEDPNSr6hAeqbJwiNl371lHpiHYhvu/5GqCuzZGhs2dkDbROV3gtcNGLu9hWF279xmGU2roWyI4YE9Pne5jaSfM4VA7E7f47zP4JRztJHQ9JhjgVXiQ1rB78UDf9hPTy+eYIDYuE1zuwr2+Ufupggs8pLLWwY18ysI+ck5Jh9mM9Q8oTLOQpPqFEnOGeM59yH4f/J9V4Gbopusrlre/P/CXNV9SxSflfy3Z0HPDAtKRvdZYiVQN9pVfcChS3FGobAUnbQf7crRd7AWr0lv06bkwbP3tq0wTwv7IDRbLamYX7tP0zJjNFNRZ3Nk+WRNVGr96368/O1Nnyn6v/vwlEd7vN6tXqIBASUNumo9DfRC2OT1RdE6jRYHnADFecLeksh1acY9MCA425scJEsuBnfbWiTQzwVhpVs9w6dGQUsx8dUfsti0tY156J2oB7gILcITQKo9GSxgvop3rpniiGYAOSvCMYQ2tq87e+WjqANKI6YwIMnFUVqDiXgtxQ8w3OvHz2k9F9yyk7TJkKJLOwsvgLPFLdiQYadp6HglsCbkA6PM++jZN91JyXgTvEon84EqAhp7LjdmvIHGR5RyWcIHkKvtfcDuehT3NFO+WOCBrd5vQrf2O6edSsDZGwDgMSPStfvIA4mXzR73wKGIucwc1cmPehLJOdzGmZu0UErKpyqFtXcZWtbk+esMkplRirCebYSVykN3FX5Sm6QyaldewPB/BZ6nXnnqPfbI0UZ78ISnO3stKYYmnkUxZc7iUaR/urL2NQRvR83Z7QiqUH4="
+DOTENV_VAULT_DEVELOPMENT_VERSION=17
 
 # ci
-DOTENV_VAULT_CI="mX/PmBU2v+/KE2qkVC2FgZsdT9Hr4aHqii/5QsSkt7lvfqAhpKwHHHlpsbZv/XZsJDSiet/34tPqC1p/JUa8mQ9nAOFbwKLkcxq7YwbGyTukmCpX4otyOvzs9+VlxyIcUK0nOxjNK9QU4r3uQHp2Oa8AjQPGlk7PIAi0Shbq/OL80B7cpXXtme9ZtytJSgM38mT3fFpZN4+Hp+724JzfrdpYDwhkMcH7DRvW/7QvB2zZJJXJr/j8WnlsjKz+u0O6j6pLLgbToHhKyZhkUXFaqwMO/uE9oxeFaK7+SNHT2M5OuX8WJR6S0Capz8KMfJK4osy77xv5x6rq4vx5GUQoh/8h2uj222nyIBp7OqLRySDjLw=="
-DOTENV_VAULT_CI_VERSION=12
+DOTENV_VAULT_CI="7FwpxhDzCuOFcwtQSYAWObVjrYcjvY1XFgSlbiE5+JprBEYK9B9iwUFeNhIiek1iq3IMXH7bUWpwV2J47kuWRVXZSuQJQPYJp+57HJO60eHoDhBfzzgjI2qX/3QL6/RPZoU1x4MuZvhuut5wNm3Z/V7B7WY6LFnTzNcLtDpq2j59xHiSkgxFu4MAgdd5sMlIN4+7XfhbhA4Bq0JOhWYhzj77BjA32mZVmlM5K/NdTelb05uPP6K+re9FpRst2iR6idCyjqxVbmRzrP4M8N0EXFxfJAl88Ra8t1100Y4J0ra/Cyt4jkQtSUEldFJB2/ilZZRY5Td3KaSyOhGl/HbyH58+ZQr3VChoGsR6fZffcZxwOfLsqUh3z2DHf04fk4FM4MiB+7MqhvmpBeEgbM6Yzw=="
+DOTENV_VAULT_CI_VERSION=13
 
 # staging
-DOTENV_VAULT_STAGING="t3GqwVK42/9SnmNi4JQKguGr7GCqMynNLtkx5tYlc64fNU19KeflFwAbO54IFRfYYR8EauYIiKrQcymw9Z8Pjul5X5IboPS8huEJDiU4Swbb/d6w4dpOaFiVJnV/0v2CbaNiek1te8mSO94x79gc1AFt4ROrWSMKEoR3zbcq8Qfxgz/Lbwv2SqGuCq3qVQATZpdNO22/N91OAOlk5eXJO/fvn3pVYeP2cdZoOruFvF7q+GEV7XJd+5Iv2WyrRW3NVMupcMHyyYlPgA2r98A2BmvTTXvKi8kJavfCK8t6W2lbkE6qZ2BXK19AakRmA8Z4KM7HLn6TG6IoXiGZbOlWpiolFMbSzdLrpVB8WSa5Nl3a7Q=="
-DOTENV_VAULT_STAGING_VERSION=12
+DOTENV_VAULT_STAGING="EW6ym8FguTI9isGbcqgo7Jo1/rW4jSJ6b0Hgh/npVi0KVsNntnhdpCo9/4Jlh13lJr1zJd/ECS+6H7eoo+i8+h6mMQG1QyKeFy4ASTvDSNiVVNkiuUbeo5RaiRiHUR9OMDkmjbUoOL1MlNfjQ8J9qkoTNynPvlamgW1rpUF9ohQ5QiYJ1QupQ7vEMwsCv+N+grsc57+5C+E4aAjFT39BvjoGjNMIdJ0Qz8MvOvRoSs2oXNAK/mVMKTGsLbHvQGHq9CwqzoTjFqZ5PmW7jU2KXb5TMwtQ+lsQBZMqG8qC+DDkCbKKBfaW6KX9L7nH0HGg26jFf4KcGnl69cIEuWYJxKe4Cgm4R7MjgUSxEig8sLG5ShpXzph53jMDO2i6nFRNSqYY+Kku4LfRSJgSHr/b4g=="
+DOTENV_VAULT_STAGING_VERSION=13
 
 # production
-DOTENV_VAULT_PRODUCTION="wBk4p1ZptcmMJ+IIO8xz8V/Uzn0t8TyEF1CCKlwZQRG85rZZTy0ZcDGWS68Tea2Ia91OBHJySLxPyIJeVFjZFfFVui4m1FYIHbLj/O5cZEAfd9CH90Kq1xZXu6SlEtTvkqNf/18jPEcbCVfvtcB6xZK+5IEvEgh2OxUehAjfw++23hHaMxvBwkFP6oBzrjl7hAF0wv4PtYgZs1NwSTFjMAYMNFQ2ZtdIKzZI1EFJJdI3Vpu84tGOvWMparYEPmOUqTBKL6k78+nt6/iIYfNYO4KNLDYqMIS2Ed5Of25dC5jFAWi58pXg+hE6fO/ziMuD9+/Dyivi55UuxpWu+6RQ0ZLrzWcjIPCV07TeZ1UkaKl9Iw=="
-DOTENV_VAULT_PRODUCTION_VERSION=12
+DOTENV_VAULT_PRODUCTION="TELuDo48wkR9KcSxWAM90AQBomt8Tc9daTKplPZq2DGBeP4dhZFz8C5GTVH7iaSaRfwz36ccaEnifr9oAiOK6ZCoj5eEQYzKkp6j8VKYrr+IQ6H8JG59/11kzvNGYJT8i/Hn1wLhHVoeUJON8/birb0HdIJzdD7Rrc2udmuqSZit77wFx+cBnzfLGlEogKPYTGogjycJupfHvWE2M33SDld3wRwHAGal6mGWJOa++IobA0QJGy6FNe+KSrsma9j5xvyTQYAR1Y0SCghqlKmLtvCnnMbJ5RCFxf4+ASEeLQS0tt2RPA1JibyM4TkxrAmAyoQMGZerKIJ4gi+lUcpRIOpcPSrpFxeMHRczLsbL9y0SLWeXeubQ+WCEKrjYYgP/qCQFfyinzzPCHBlR5JLvjA=="
+DOTENV_VAULT_PRODUCTION_VERSION=13
 
 #/----------------settings/metadata-----------------/
 DOTENV_VAULT="vlt_ccfca07e33ba68df250eca253b674d058bb3faf455ca8372b203edec7cb7afc5"
diff --git a/temerity/build.gradle.kts b/temerity/build.gradle.kts
index 14850df..97be4cc 100644
--- a/temerity/build.gradle.kts
+++ b/temerity/build.gradle.kts
@@ -112,6 +112,7 @@ kotlin {
                 implementation(libs.kotlinx.dataframe)
                 // Required to parse dataframe rows back to JSON objects
                 implementation(libs.klaxon)
+                implementation(libs.kotlinx.io.core)
             }
         }
     }
diff --git a/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/PlatformClient.kt b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/PlatformClient.kt
index 7c8bd78..1b6fe61 100644
--- a/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/PlatformClient.kt
+++ b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/PlatformClient.kt
@@ -30,11 +30,15 @@ import edu.ucsc.its.temerity.remote.UserGroup
 import edu.ucsc.its.temerity.remote.UserRecordingSession
 import edu.ucsc.its.temerity.remote.UserUpdate
 import io.ktor.client.statement.HttpResponse
+import kotlinx.datetime.DatePeriod
+import kotlinx.datetime.DateTimePeriod
+import kotlinx.datetime.DateTimeUnit
 import kotlinx.datetime.LocalDate
 import kotlinx.datetime.LocalDateTime
 import kotlinx.datetime.format
 import kotlinx.datetime.format.DateTimeFormat
 import kotlinx.datetime.format.char
+import kotlinx.datetime.plus
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.descriptors.PrimitiveKind
 import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
@@ -208,11 +212,11 @@ public interface PlatformClient {
   /**
    * Fetches a list of sessions on a device's schedule for a given time period.
    * @param deviceId The ID of the device to fetch the sessions for.
-   * @param startTime The start date for the sessions.
-   * @param endTime The end date for the sessions.
+   * @param startTime The start date for the sessions. Defaults to the current date.
+   * @param endTime The end date for the sessions. Defaults to one week from the current date.
    * @return A list of DeviceRecordingSession objects.
    */
-  public suspend fun getDeviceSchedule(deviceId: Long, startTime: LocalDate, endTime: LocalDate): List<DeviceRecordingSession>
+  public suspend fun getDeviceSchedule(deviceId: Long, startTime: LocalDate = currentDate(), endTime: LocalDate = currentDate().plus(1, DateTimeUnit.WEEK)): List<DeviceRecordingSession>
 
   /**
    * Fetches a file containing storage usage details of a specific group.
diff --git a/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/Util.kt b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/Util.kt
new file mode 100644
index 0000000..901f9f0
--- /dev/null
+++ b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/Util.kt
@@ -0,0 +1,13 @@
+package edu.ucsc.its.temerity
+
+import kotlinx.datetime.Clock
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.LocalTime
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.toLocalDateTime
+
+internal fun getDateTime() = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
+
+internal fun currentDate() : LocalDate = getDateTime().date
+
+internal fun currentTime() : LocalTime = getDateTime().time
\ No newline at end of file
diff --git a/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/remote/PlatformApi.kt b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/remote/PlatformApi.kt
index f4ff0b4..4b0dee1 100644
--- a/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/remote/PlatformApi.kt
+++ b/temerity/src/commonMain/kotlin/edu/ucsc/its/temerity/remote/PlatformApi.kt
@@ -103,10 +103,16 @@ internal interface PlatformApi {
   @GET("devices/{deviceId}")
   suspend fun getDeviceById(@Path deviceId: Long): HttpStatement
 
-  @GET("devices/registrations/")
+  @PUT("devices/{deviceId}")
+  suspend fun updateDeviceRegistration(@Path deviceId: Long, @Body device: String): ApiResponse<HttpResponse>
+
+  @POST("devices/{deviceId}/register")
+  suspend fun registerDevice(@Path deviceId: Long, @Body device: String): ApiResponse<HttpResponse>
+
+  @GET("devices/registrations/{access_id}")
   suspend fun getDeviceRegistration(
     @Query("access_id") deviceCode: Int,
-  ): HttpStatement
+  ): ApiResponse<HttpResponse>
 
   @Streaming
   @GET("devices/{deviceId}/schedule")
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/SchedulerReportUtils.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/SchedulerReportUtils.kt
new file mode 100644
index 0000000..ab1477c
--- /dev/null
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/SchedulerReportUtils.kt
@@ -0,0 +1,22 @@
+package edu.ucsc.its.temerity
+
+import io.kotest.core.spec.style.FunSpec
+import java.io.FilenameFilter
+import kotlin.io.path.Path
+import org.dotenv.vault.dotenvVault
+
+class SchedulerReportUtils : FunSpec() {
+    init {
+        coroutineDebugProbes = true
+
+        val dotenv = dotenvVault()
+
+        test("Collate recordings per room") {
+            val schedulerReportsRoot = Path(dotenv["SCHEDULER_REPORTS_LOCATION"]).toFile()
+            val reportFilter = FilenameFilter { _, name -> name.endsWith(".csv") }
+            val reportFrames = schedulerReportsRoot.listFiles(reportFilter)
+
+
+        }
+    }
+}
\ No newline at end of file
-- 
GitLab