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