diff --git a/.gitignore b/.gitignore index ac542aaf..5eac7b1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.kotlin deepai.key xcuserdata firebase_service_account_key.json @@ -27,4 +28,4 @@ keystore.properties api-*.json *.db .terraform -.terraform.lock.hcl \ No newline at end of file +.terraform.lock.hcl diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index f29341d1..a862359a 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -4,21 +4,11 @@ plugins { dependencies { implementation(platform(libs.google.cloud.bom)) - implementation(platform(libs.firebase.bom)) implementation(libs.google.cloud.storage) implementation(libs.plugin.kotlin) - implementation(libs.plugin.android.application) - implementation(libs.plugin.apollo) implementation(libs.plugin.ksp) - implementation(libs.plugin.kmp.nativecoroutines) implementation(libs.plugin.kotlin.serialization) - implementation(libs.plugin.kotlin.spring) - implementation(libs.plugin.spring.boot) - implementation(libs.plugin.appengine) - implementation(libs.plugin.kmmbridge) - implementation(libs.plugin.google.services) - implementation(libs.plugin.firebase.crashlytics) - implementation(libs.plugin.wire) + implementation(libs.plugin.apollo.execution) implementation(libs.jib.core) implementation(libs.google.cloud.storage) implementation(libs.google.cloud.run) diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 4138b31c..caaf008f 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -12,7 +12,7 @@ pluginManagement { mavenCentral() google() gradlePluginPortal() - maven("https://storage.googleapis.com/martin-maven/m2/") + maven("https://storage.googleapis.com/apollo-snapshots/m2/") } } } diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt deleted file mode 100644 index 166c5be7..00000000 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ /dev/null @@ -1,16 +0,0 @@ - - -object AndroidSdk { - const val min = 21 - const val compile = 33 - const val target = compile -} - -object WearSdk { - const val min = 26 - const val compile = 33 - const val target = 30 -} - - - diff --git a/buildSrc/src/main/kotlin/PlayStoreScreenshotTask.kt b/buildSrc/src/main/kotlin/PlayStoreScreenshotTask.kt deleted file mode 100644 index 48d1812d..00000000 --- a/buildSrc/src/main/kotlin/PlayStoreScreenshotTask.kt +++ /dev/null @@ -1,56 +0,0 @@ -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import java.awt.Color -import java.awt.image.BufferedImage -import javax.imageio.ImageIO - -abstract class PlayStoreScreenshotTask : DefaultTask() { - @get:InputFiles - abstract val selectedImages: ConfigurableFileCollection - - @get:OutputDirectory - abstract val output: DirectoryProperty - - @TaskAction - fun generateImages() { - selectedImages.forEach { - checkSourceScreenshotExists(it) - } - - deleteAllExisting() - - selectedImages.forEachIndexed { index, file -> - copyScreenshot(file, index) - } - } - - private fun checkSourceScreenshotExists(it: java.io.File) { - check(it.exists()) { - "Source file $it does not exist" - } - } - - private fun deleteAllExisting() { - val existing = output.asFileTree.files - logger.info("Deleting " + existing.map { it.name }) - project.delete(existing) - } - - private fun copyScreenshot(file: java.io.File, index: Int) { - val sourceImage = ImageIO.read(file) - val destImage = BufferedImage(sourceImage.width, sourceImage.height, sourceImage.type) - val g = destImage.createGraphics() - - g.setColor(Color.BLACK) - g.fillRect(0, 0, destImage.width, destImage.height) - - g.drawImage(sourceImage, null, 0, 0) - - val destinationName = "${'a' + index}_${file.name.replace("\\W+.*".toRegex(), "")}.png" - ImageIO.write(destImage, "png", output.file(destinationName).get().asFile) - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/ReadmeScreenshotTask.kt b/buildSrc/src/main/kotlin/ReadmeScreenshotTask.kt deleted file mode 100644 index 793f3f2f..00000000 --- a/buildSrc/src/main/kotlin/ReadmeScreenshotTask.kt +++ /dev/null @@ -1,51 +0,0 @@ -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import java.awt.Color -import java.awt.image.BufferedImage -import java.awt.image.BufferedImage.TYPE_INT_ARGB -import javax.imageio.ImageIO -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty -import java.awt.geom.Point2D - -abstract class ReadmeScreenshotTask : DefaultTask() { - @get:InputFiles - abstract val selectedImages: ConfigurableFileCollection - - @get:OutputDirectory - abstract val output: RegularFileProperty - - @TaskAction - fun generateImages() { - selectedImages.forEach { - checkSourceScreenshotExists(it) - } - - generateCombinedScreenshot() - } - - private fun checkSourceScreenshotExists(it: java.io.File) { - check(it.exists()) { - "Source file $it does not exist" - } - } - - private fun generateCombinedScreenshot() { - val destImage = BufferedImage(1000, 1000, TYPE_INT_ARGB) - val g = destImage.createGraphics() - - selectedImages.forEachIndexed { index, file -> - val sourceImage = ImageIO.read(file) - val columns = 2 - val x = (index % columns) * 500 - val y = (index / columns) * 500 - g.drawImage(sourceImage, null, x, y) - } - - ImageIO.write(destImage, "png", output.get().asFile) - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/landing.kt b/buildSrc/src/main/kotlin/landing.kt deleted file mode 100644 index f1fef84f..00000000 --- a/buildSrc/src/main/kotlin/landing.kt +++ /dev/null @@ -1,40 +0,0 @@ -import com.google.auth.oauth2.GoogleCredentials -import com.google.cloud.storage.BlobId -import com.google.cloud.storage.BlobInfo -import com.google.cloud.storage.Storage -import com.google.cloud.storage.StorageOptions -import org.gradle.api.Project -import java.io.File - -fun Project.gcpServiceAccountFile() = rootProject.file("service-graphql/src/main/resources/firebase_service_account_key.json") - -fun Project.uploadLandingPage() { - val storage: Storage = StorageOptions.newBuilder() - .setCredentials(gcpServiceAccountFile().inputStream().use { - GoogleCredentials.fromStream(it) - }) - .build() - .service - - val bucketName = "confetti-landing-page" - - println("uploading landing page...") - val base = file("public") - base.walk().filter { it.isFile } - .forEach { file -> - file.inputStream().use { - val blobId = BlobId.of(bucketName, file.relativeTo(base).path) - val blobInfo = BlobInfo.newBuilder(blobId).setContentType(file.contentType()).build() - - storage.createFrom(blobInfo, it) - } - } -} - -private fun File.contentType() : String{ - return when (this.extension) { - "html", "htm" -> "text/html" - "css" -> "text/css" - else -> "application/octet-stream" - } -} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/options.kt b/buildSrc/src/main/kotlin/options.kt index 3e550566..6602a8b1 100644 --- a/buildSrc/src/main/kotlin/options.kt +++ b/buildSrc/src/main/kotlin/options.kt @@ -1,12 +1,8 @@ -import com.android.build.gradle.BaseExtension -import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.compile.JavaCompile import org.gradle.jvm.toolchain.JavaLanguageVersion -import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinCompile -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions private fun Int.toJavaVersion(): String = when(this) { @@ -33,12 +29,4 @@ fun Project.configureCompilerOptions(jvmVersion: Int = 11) { it.languageVersion.set(JavaLanguageVersion.of(17)) } } - - extensions.findByName("android")?.apply{ - this as BaseExtension - compileOptions { - it.sourceCompatibility = JavaVersion.toVersion(jvmVersion.toJavaVersion()) - it.targetCompatibility = JavaVersion.toVersion(jvmVersion.toJavaVersion()) - } - } } \ No newline at end of file diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 4832e84b..b5e0b9fb 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("org.jetbrains.kotlin.jvm") - id("org.jetbrains.kotlin.plugin.spring") id("org.jetbrains.kotlin.plugin.serialization") } diff --git a/gradle.properties b/gradle.properties index 3778b030..1e520724 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,3 +14,5 @@ kotlin.mpp.enableCInteropCommonization=true kotlin.mpp.stability.nowarn=true kotlin.mpp.androidSourceSetLayoutVersion=2 +#ksp.useKSP2=true +ksp.allow.all.target.configuration=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e3f9ea4..6a0c6d7b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,157 +1,26 @@ [versions] -accompanist = "0.30.0" -activity-compose = "1.7.0" -androidx-lifecycle = "2.6.1" -androidx-datastore = "1.1.0-alpha01" -apollo = "4.0.0-fork.0" -compose = "1.4.0" -compose-compiler = "1.4.4-dev-k1.8.20-f6ae19e64ff" -compose-material-3 = "1.0.1" -horologist = "0.4.1" -junit = "4.13" -kmp-nativecoroutines = "1.0.0-ALPHA-6" -kmm-viewmodel = "1.0.0-ALPHA-5" -koin-android = "3.4.0" -koin-android-compose = "3.4.3" -koin-core = "3.4.0" -kotlin = "1.8.20" -kotlin-coroutines = "1.6.4" -kotlinx-coroutines-play-services = "1.6.4" +apollo-execution = "0.1.1-SNAPSHOT-5283588453f1afa8a449786890d52788cc3dc60e" +kotlin = "2.1.10" kotlinx-datetime = "0.4.0" -lifecycle = "2.6.1" -lifecycle-livedata-ktx = "2.6.1" -multiplatform-settings = "1.0.0" -nav-compose = "2.5.3" -okio = "3.3.0" -robolectric = "4.10-alpha-1" -snapshot-android = "v1.0.2" -work-runtime-ktx = "2.8.1" [libraries] -accompanist-adaptive = { module = "com.google.accompanist:accompanist-adaptive", version.ref = "accompanist" } -accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } -accompanist-testharness = { module = "com.google.accompanist:accompanist-testharness", version.ref = "accompanist" } -activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" } -androidx-benchmarkmacro = "androidx.benchmark:benchmark-macro-junit4:1.2.0-alpha12" -androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "androidx-datastore" } -androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" } -androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle-livedata-ktx" } -androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } -androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "work-runtime-ktx" } -androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "work-runtime-ktx" } -apollo-adapters = { module = "com.apollographql.apollo3:apollo-adapters" } -apollo-normalized-cache-in-memory = { module = "com.apollographql.apollo3:apollo-normalized-cache" } -apollo-normalized-cache-sqlite = { module = "com.apollographql.apollo3:apollo-normalized-cache-sqlite" } -apollo-runtime = { module = "com.apollographql.apollo3:apollo-runtime" } -apollo-annotations = { module = "com.apollographql.apollo3:apollo-annotations", version.ref = "apollo" } -apollo-tooling = { module = "com.apollographql.apollo3:apollo-tooling", version.ref = "apollo" } +apollo-execution-ktor = { module = "com.apollographql.execution:apollo-execution-ktor", version.ref = "apollo-execution" } atomicfu = "org.jetbrains.kotlinx:atomicfu:0.20.1" -bare-graphQL = "net.mbonnin.bare-graphql:bare-graphql:0.0.2" -coil-base = "io.coil-kt:coil-base:2.3.0" -coil-compose = "io.coil-kt:coil-compose:2.3.0" -compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compose-compiler" } -compose-foundation-layout = { module = "androidx.compose.foundation:foundation-layout", version.ref = "compose" } -compose-material = { module = "androidx.compose.material:material", version.ref = "compose" } -compose-material-icons-core = { module = "androidx.compose.material:material-icons-core", version.ref = "compose" } -compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } -compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "nav-compose" } -compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "compose" } -compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } -compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics", version.ref = "compose" } -compose-ui-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose" } -compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" } -compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } -desugar = "com.android.tools:desugar_jdk_libs:2.0.2" -fastlane-screengrab = "tools.fastlane:screengrab:2.1.1" -federation-jvm = "com.apollographql.federation:federation-graphql-java-support:3.0.0" firebase-admin = { module = "com.google.firebase:firebase-admin", version = "9.1.1" } -firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" } -firebase-auth-ktx = { module = "com.google.firebase:firebase-auth-ktx" } -firebase-bom = "com.google.firebase:firebase-bom:31.2.3" -firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" } -firebase-performance = { module = "com.google.firebase:firebase-perf-ktx" } -firebase-mpp-auth = "dev.gitlive:firebase-auth:1.8.0" google-cloud-bom = "com.google.cloud:libraries-bom:26.11.0" -google-cloud-storage = { module = "com.google.cloud:google-cloud-storage" } google-cloud-datastore = "com.google.cloud:google-cloud-datastore:2.14.2" -google-services = "com.google.gms:google-services:4.3.15" -graphql-java = "com.graphql-java:graphql-java:230521-nf-execution" -graphql-kotlin-spring-server = "com.expediagroup:graphql-kotlin-spring-server:7.0.0-alpha.4" -horologist-auth-composables = { module = "com.google.android.horologist:horologist-auth-composables", version.ref = "horologist" } -horologist-auth-ui = { module = "com.google.android.horologist:horologist-auth-ui", version.ref = "horologist" } -horologist-auth-data = { module = "com.google.android.horologist:horologist-auth-data", version.ref = "horologist" } -horologist-base-ui = { module = "com.google.android.horologist:horologist-base-ui", version.ref = "horologist" } -horologist-composables = { module = "com.google.android.horologist:horologist-composables", version.ref = "horologist" } -horologist-compose-layout = { module = "com.google.android.horologist:horologist-compose-layout", version.ref = "horologist" } -horologist-compose-tools = { module = "com.google.android.horologist:horologist-compose-tools", version.ref = "horologist" } -horologist-datalayer = { module = "com.google.android.horologist:horologist-datalayer", version.ref = "horologist" } -horologist-datalayer-phone = { module = "com.google.android.horologist:horologist-datalayer-phone", version.ref = "horologist" } -horologist-datalayer-watch = { module = "com.google.android.horologist:horologist-datalayer-watch", version.ref = "horologist" } -horologist-tiles = { module = "com.google.android.horologist:horologist-tiles", version.ref = "horologist" } -junit = "junit:junit:4.13.2" -kaml = "com.charleskorn.kaml:kaml:0.53.0" -koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin-android" } -koin-workmanager = { module = "io.insert-koin:koin-androidx-workmanager", version.ref = "koin-android" } -koin-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin-android-compose" } -koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin-core" } -koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin-core" } -kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" } -kmm-viewmodel = { module = "com.rickclephas.kmm:kmm-viewmodel-core", version.ref = "kmm-viewmodel" } -kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" } -kotlinx-coroutines-play-services = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines-play-services" } -kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlin-coroutines" } +google-cloud-run = "com.google.cloud:google-cloud-run:0.35.0" +google-cloud-storage = { module = "com.google.cloud:google-cloud-storage" } +jib-core = "com.google.cloud.tools:jib-core:0.25.0" kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } kotlinx-serialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0" -ktor-cio = "io.ktor:ktor-server-cio:2.3.9" -ktor-server-core = "io.ktor:ktor-server-core:2.3.9" -ktor-server-netty = "io.ktor:ktor-server-netty:2.3.9" -ktor-status-pages = "io.ktor:ktor-server-status-pages:2.3.9" -ktor-server-cors = "io.ktor:ktor-server-cors:2.3.9" -slf4j-simple = "org.slf4j:slf4j-simple:2.0.9" -jib-core = "com.google.cloud.tools:jib-core:0.25.0" -google-cloud-run = "com.google.cloud:google-cloud-run:0.35.0" -lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" } -material3-core = { module = "androidx.compose.material3:material3", version.ref = "compose-material-3" } -material3-window-size = { module = "androidx.compose.material3:material3-window-size-class", version.ref = "compose-material-3" } -multiplatform-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatform-settings" } -multiplatform-settings-coroutines = { module = "com.russhwolf:multiplatform-settings-coroutines", version.ref = "multiplatform-settings" } -multiplatform-settings-datastore = { module = "com.russhwolf:multiplatform-settings-datastore", version.ref = "multiplatform-settings" } +ktor-server-core = "io.ktor:ktor-server-core:3.0.0" +ktor-server-cors = "io.ktor:ktor-server-cors:3.0.0" +ktor-server-netty = "io.ktor:ktor-server-netty:3.0.0" okhttp = "com.squareup.okhttp3:okhttp:5.0.0-alpha.11" okhttp-coroutines = "com.squareup.okhttp3:okhttp-coroutines:5.0.0-alpha.11" -okhttp-logging-interceptor = "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11" -play-services-auth = "com.google.android.gms:play-services-auth:20.4.1" +plugin-apollo-execution = { module = "com.apollographql.execution:apollo-execution-gradle-plugin", version.ref = "apollo-execution" } plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } -plugin-android-application = "com.android.tools.build:gradle:7.4.2" -plugin-apollo = { module = "com.apollographql.apollo3:apollo-gradle-plugin", version.ref = "apollo" } -plugin-appengine = "com.google.cloud.tools:appengine-gradle-plugin:2.4.5" -plugin-firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-gradle", version = "2.9.4" } -plugin-google-services = "com.google.gms:google-services:4.3.15" -plugin-kmmbridge = "co.touchlab.faktory:kmmbridge:0.3.7" -plugin-kmp-nativecoroutines = { module = "com.rickclephas.kmp:kmp-nativecoroutines-gradle-plugin", version.ref = "kmp-nativecoroutines" } plugin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } -plugin-kotlin-spring = { module = "org.jetbrains.kotlin:kotlin-allopen", version.ref = "kotlin" } -plugin-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version = "1.8.20-1.0.10" } -plugin-spring-boot = { module = "org.springframework.boot:spring-boot-gradle-plugin", version = "3.0.5" } -plugin-wire = { module = "com.squareup.wire:wire-gradle-plugin", version = "4.5.3" } -gax-grpc = "com.google.api:gax-grpc:2.38.0" -okio = { module = "com.squareup.okio:okio", version.ref = "okio" } -reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } -robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" } -snapshot-android = { module = "com.github.QuickBirdEng.kotlin-snapshot-testing:snapshot-android", version.ref = "snapshot-android" } -snapshot-jvm = { module = "com.github.QuickBirdEng.kotlin-snapshot-testing:snapshot-jvm", version.ref = "snapshot-android" } -splash-screen = "androidx.core:core-splashscreen:1.0.0" -test-espressocore = "androidx.test.espresso:espresso-core:3.5.1" -test-junit-ktx = "androidx.test.ext:junit-ktx:1.1.5" -test-runner = "androidx.test:runner:1.5.2" -test-uiautomator = "androidx.test.uiautomator:uiautomator:2.3.0-alpha02" -wear-complications-data = "androidx.wear.watchface:watchface-complications-data-source-ktx:1.1.1" -wear-compose-material = "androidx.wear.compose:compose-material:1.2.0-alpha07" -wear-compose-navigation = "androidx.wear.compose:compose-navigation:1.2.0-alpha07" -wire-runtime = "com.squareup.wire:wire-runtime:4.5.3" -xoxo = "net.mbonnin.xoxo:xoxo:0.3" -napier = "io.github.aakira:napier:2.6.1" -apollo-execution-ktor = {module = "com.apollographql.apollo3:apollo-execution-ktor", version.ref = "apollo"} -apollo-ksp-incubating = {module = "com.apollographql.apollo3:apollo-ksp-incubating", version.ref = "apollo"} -[bundles] -multiplatform-settings = ["multiplatform-settings", "multiplatform-settings-coroutines"] -apollo = ["apollo-normalized-cache-in-memory", "apollo-normalized-cache-sqlite", "apollo-adapters"] +plugin-ksp = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version = "2.1.10-1.0.29" } +slf4j-simple = "org.slf4j:slf4j-simple:2.0.9" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..cea7a793 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/service/build.gradle.kts b/service/build.gradle.kts index f096cd5b..ac1c4e12 100644 --- a/service/build.gradle.kts +++ b/service/build.gradle.kts @@ -1,63 +1,36 @@ plugins { - id("org.jetbrains.kotlin.multiplatform") + id("org.jetbrains.kotlin.jvm") id("com.google.devtools.ksp") + id("com.apollographql.execution") } -kotlin { - jvm() - - sourceSets { - getByName("commonMain") { - dependencies { - implementation(libs.ktor.server.core) - implementation(libs.ktor.server.cors) - implementation(libs.apollo.execution.ktor) - implementation(libs.kotlinx.datetime) - implementation(libs.okhttp) - implementation(libs.okhttp.coroutines) - implementation(libs.kotlinx.serialization) - implementation(libs.firebase.admin) - implementation(libs.google.cloud.datastore) - implementation(project(":module-openfeedback")) - } - } - - getByName("jvmMain") { - dependencies { - implementation(libs.ktor.server.netty) - implementation(libs.slf4j.simple) - } - } - } -} dependencies { - add("kspCommonMainMetadata", libs.apollo.ksp.incubating) - add("kspJvm", libs.apollo.ksp.incubating) + implementation(libs.ktor.server.core) + implementation(libs.ktor.server.cors) + implementation(libs.apollo.execution.ktor) + implementation(libs.kotlinx.datetime) + implementation(libs.okhttp) + implementation(libs.okhttp.coroutines) + implementation(libs.kotlinx.serialization) + implementation(libs.firebase.admin) + implementation(libs.google.cloud.datastore) + implementation(project(":module-openfeedback")) + implementation(libs.ktor.server.netty) + implementation(libs.slf4j.simple) } -ksp { - arg("apolloService", "androidmakers") - arg("apolloPackageName", "androidmakers.graphql") +apolloExecution { + service("AndroidMakers") { + packageName.set("androidmakers.graphql") + } } + configureCompilerOptions(17) tasks.register("run", JavaExec::class.java) { - classpath(configurations.getByName("jvmRuntimeClasspath")) - classpath(kotlin.targets.getByName("jvm").compilations.getByName("main").output.classesDirs) + classpath(configurations.getByName("runtimeClasspath")) + classpath(kotlin.target.compilations.getByName("main").output.classesDirs) mainClass.set("androidmakers.service.MainKt") } -tasks.register("dumpSchema", JavaExec::class.java) { - classpath(configurations.getByName("jvmRuntimeClasspath")) - classpath(kotlin.targets.getByName("jvm").compilations.getByName("main").output.classesDirs) - mainClass.set("androidmakers.service.DumpSchemaKt") - args("graphql/schema.graphqls") -} - configureDeploy("service", "androidmakers.service.MainKt") - -tasks.all { - if (name == "kspKotlinJvm") { - finalizedBy("dumpSchema") - } -} diff --git a/service/graphql/schema.graphqls b/service/graphql/schema.graphqls index 43801d4d..e979debc 100644 --- a/service/graphql/schema.graphqls +++ b/service/graphql/schema.graphqls @@ -1,12 +1,98 @@ -""" - A type representing a formatted kotlinx.datetime.Instant -""" -scalar GraphQLInstant +schema { + query: RootQuery + mutation: RootMutation +} scalar GraphQLLocalDate scalar GraphQLLocalDateTime +enum ConferenceField { + DAYS +} + +enum LinkType { + YouTube + + Audio + + AudioUncompressed + + Other +} + +enum OrderByDirection { + ASCENDING + + DESCENDING +} + +enum SessionField { + STARTS_AT +} + +type BookmarkConnection { + nodes: [Session!]! +} + +type Conference { + id: String! + + name: String! + + timezone: String! + + days: [GraphQLLocalDate!]! + + themeColor: String +} + +type Link { + type: LinkType! + + url: String! +} + +type PageInfo { + endCursor: String +} + +type Partner { + name: String! + + url: String! + + """ + @param dark returns the logo for use on a dark background or fallbacks to the light mode if none exist + """ + logoUrl(dark: Boolean = false): String! +} + +type PartnerGroup { + title: String! + + partners: [Partner!]! +} + +type Room { + id: String! + + name: String! + + capacity: Int +} + +type RootMutation { + addBookmark(sessionId: String!): BookmarkConnection! + + removeBookmark(sessionId: String!): BookmarkConnection! + + """ + Deletes the current user account, requires authentication + """ + deleteAccount: Boolean! +} + type RootQuery { rooms: [Room!]! @@ -16,7 +102,7 @@ type RootQuery { } ): SessionConnection! - speakers: [Speaker!]! + speakers: [Speaker!]! @deprecated(reason: "Use speakersPage instead") speakersPage(first: Int! = 10, after: String = null): SpeakerConnection! @@ -37,23 +123,51 @@ type RootQuery { conferences(orderBy: ConferenceOrderBy = null): [Conference!]! } -type RootMutation { - addBookmark(sessionId: String!): BookmarkConnection! +type Session implements Node { + id: String! - removeBookmark(sessionId: String!): BookmarkConnection! + title: String! """ - Deletes the current user account, requires authentication + The description of the event. [description] may contain emojis and '\n' Chars but no markdown or HTML. + + May be null if no description is available. """ - deleteAccount: Boolean! -} + description: String -type Room { - id: String! + """ + A shorter version of description for use when real estate is scarce like watches for an example. + This field might have the same value as description if a shortDescription is not available + """ + shortDescription: String - name: String! + """ + An [IETF language code](https://en.wikipedia.org/wiki/IETF_language_tag) like en-US + """ + language: String - capacity: Int + tags: [String!]! + + startsAt: GraphQLLocalDateTime! + + endsAt: GraphQLLocalDateTime! + + complexity: String + + feedbackId: String + + """ + One of "break", "lunch", "party", "keynote", "talk" or any other conference-specific format + """ + type: String! + + links: [Link!]! + + speakers: [Speaker!]! + + room: Room + + rooms: [Room!]! } type SessionConnection { @@ -62,10 +176,14 @@ type SessionConnection { pageInfo: PageInfo! } -input SessionOrderBy { - field: SessionField! +type Social { + icon: String - direction: OrderByDirection! + link: String! @deprecated(reason: "use url instead") + + name: String! + + url: String! } type Speaker implements Node { @@ -116,9 +234,9 @@ type Venue { floorPlanUrl: String - coordinates: String + coordinates: String @deprecated(reason: "use latitude and longitude instead") - descriptionFr: String! + descriptionFr: String! @deprecated(reason: "use description(language: \"fr\") instead") """ The description of the venue. [description] may contain emojis and '\n' Chars but no markdown or HTML. @@ -128,141 +246,172 @@ type Venue { description(language: String = "en"): String! } -type PartnerGroup { - title: String! - - partners: [Partner!]! +interface Node { + id: String! } -type Session implements Node { - id: String! +input ConferenceOrderBy { + field: ConferenceField! - title: String! + direction: OrderByDirection! +} - """ - The description of the event. [description] may contain emojis and '\n' Chars but no markdown or HTML. +input SessionOrderBy { + field: SessionField! - May be null if no description is available. - """ + direction: OrderByDirection! +} + +type __Schema { description: String - """ - A shorter version of description for use when real estate is scarce like watches for an example. - This field might have the same value as description if a shortDescription is not available - """ - shortDescription: String + types: [__Type!]! - """ - An [IETF language code](https://en.wikipedia.org/wiki/IETF_language_tag) like en-US - """ - language: String + queryType: __Type! - tags: [String!]! + mutationType: __Type - startsAt: GraphQLLocalDateTime! + subscriptionType: __Type - endsAt: GraphQLLocalDateTime! + directives: [__Directive!]! +} - complexity: String +type __Type { + kind: __TypeKind! - feedbackId: String + name: String - """ - One of "break", "lunch", "party", "keynote", "talk" or any other conference-specific format - """ - type: String! + description: String - links: [Link!]! + fields(includeDeprecated: Boolean = false): [__Field!] - speakers: [Speaker!]! + interfaces: [__Type!] - room: Room + possibleTypes: [__Type!] - rooms: [Room!]! + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + + inputFields(includeDeprecated: Boolean = false): [__InputValue!] + + ofType: __Type + + specifiedByURL: String } -type Conference { - id: String! +enum __TypeKind { + SCALAR - name: String! + OBJECT - timezone: String! + INTERFACE - days: [GraphQLLocalDate!]! + UNION - themeColor: String -} + ENUM -type BookmarkConnection { - nodes: [Session!]! -} + INPUT_OBJECT -input ConferenceOrderBy { - field: ConferenceField! + LIST - direction: OrderByDirection! + NON_NULL } -type PageInfo { - endCursor: String -} +type __Field { + name: String! -enum SessionField { - STARTS_AT -} + description: String -enum OrderByDirection { - ASCENDING + args(includeDeprecated: Boolean = false): [__InputValue!]! - DESCENDING -} + type: __Type! -type Social { - icon: String + isDeprecated: Boolean! - link: String! + deprecationReason: String +} +type __InputValue { name: String! - url: String! -} + description: String -interface Node { - id: String! + type: __Type! + + defaultValue: String + + isDeprecated: Boolean! + + deprecationReason: String } -type Partner { +type __EnumValue { name: String! - url: String! + description: String - """ - @param dark returns the logo for use on a dark background or fallbacks to the light mode if none exist - """ - logoUrl(dark: Boolean = false): String! + isDeprecated: Boolean! + + deprecationReason: String } -type Link { - type: LinkType! +type __Directive { + name: String! - url: String! -} + description: String -enum ConferenceField { - DAYS + locations: [__DirectiveLocation!]! + + args(includeDeprecated: Boolean = false): [__InputValue!]! + + isRepeatable: Boolean! } -enum LinkType { - YouTube +enum __DirectiveLocation { + QUERY - Audio + MUTATION - AudioUncompressed + SUBSCRIPTION - Other -} + FIELD -schema { - query: RootQuery - mutation: RootMutation + FRAGMENT_DEFINITION + + FRAGMENT_SPREAD + + INLINE_FRAGMENT + + VARIABLE_DEFINITION + + SCHEMA + + SCALAR + + OBJECT + + FIELD_DEFINITION + + ARGUMENT_DEFINITION + + INTERFACE + + UNION + + ENUM + + ENUM_VALUE + + INPUT_OBJECT + + INPUT_FIELD_DEFINITION } + +directive @skip (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @include (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @deprecated (reason: String! = "No longer supported") on FIELD_DEFINITION|ARGUMENT_DEFINITION|INPUT_FIELD_DEFINITION|ENUM_VALUE + +directive @defer (label: String, if: Boolean! = true) on FRAGMENT_SPREAD|INLINE_FRAGMENT + +directive @specifiedBy (url: String!) on SCALAR diff --git a/service/src/commonMain/kotlin/androidmakers/service/DumpSchema.kt b/service/src/commonMain/kotlin/androidmakers/service/DumpSchema.kt deleted file mode 100644 index 51742c17..00000000 --- a/service/src/commonMain/kotlin/androidmakers/service/DumpSchema.kt +++ /dev/null @@ -1,19 +0,0 @@ -@file:Suppress("OPT_IN_USAGE") - -package androidmakers.service - -import java.io.File -import com.apollographql.apollo3.ast.toUtf8 - -fun main(args: Array) { - check(args.isNotEmpty()) { - """ - the path to the schema is required - """.trimIndent() - } - - File(args[0]).apply { - parentFile.mkdirs() - writeText(androidmakers.graphql.androidmakersSchemaDocument.toUtf8(" ")) - } -} \ No newline at end of file diff --git a/service/src/commonMain/kotlin/androidmakers/service/Main.kt b/service/src/main/kotlin/androidmakers/service/Main.kt similarity index 92% rename from service/src/commonMain/kotlin/androidmakers/service/Main.kt rename to service/src/main/kotlin/androidmakers/service/Main.kt index f634f09d..1b0981b0 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/Main.kt +++ b/service/src/main/kotlin/androidmakers/service/Main.kt @@ -7,12 +7,11 @@ import androidmakers.service.context.AuthenticationContext import androidmakers.service.context.CacheControlContext import androidmakers.service.context.DatastoreContext import androidmakers.service.context.maxAge -import com.apollographql.apollo3.api.ExecutionContext -import com.apollographql.apollo3.execution.ExecutableSchema -import com.apollographql.apollo3.execution.ktor.respondGraphQL +import com.apollographql.apollo.api.ExecutionContext +import com.apollographql.apollo.execution.ExecutableSchema +import com.apollographql.execution.ktor.respondGraphQL import com.google.auth.oauth2.GoogleCredentials import com.google.cloud.datastore.DatastoreOptions -import com.google.firebase.auth.FirebaseAuthException import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.engine.* @@ -56,12 +55,12 @@ fun main(@Suppress("UNUSED_PARAMETER") args: Array) { } routing { - val executableSchema = androidmakers.graphql.AndroidmakersExecutableSchemaBuilder().build() + val executableSchema = androidmakers.graphql.AndroidMakersExecutableSchemaBuilder().build() post("/graphql") { - apolloCall(executableSchema) + call.respondGraphQL(executableSchema) } get("/graphql") { - apolloCall(executableSchema) + call.respondGraphQL(executableSchema) } get(Regex("/sandbox/?")) { call.respondRedirect(call.url { path("/sandbox/index.html") }) diff --git a/service/src/commonMain/kotlin/androidmakers/service/context/AuthenticationContext.kt b/service/src/main/kotlin/androidmakers/service/context/AuthenticationContext.kt similarity index 85% rename from service/src/commonMain/kotlin/androidmakers/service/context/AuthenticationContext.kt rename to service/src/main/kotlin/androidmakers/service/context/AuthenticationContext.kt index d175e981..35899856 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/context/AuthenticationContext.kt +++ b/service/src/main/kotlin/androidmakers/service/context/AuthenticationContext.kt @@ -1,6 +1,6 @@ package androidmakers.service.context -import com.apollographql.apollo3.api.ExecutionContext +import com.apollographql.apollo.api.ExecutionContext class AuthenticationContext(val uid: String?) : ExecutionContext.Element { override val key: ExecutionContext.Key<*> diff --git a/service/src/commonMain/kotlin/androidmakers/service/context/CacheControlContext.kt b/service/src/main/kotlin/androidmakers/service/context/CacheControlContext.kt similarity index 93% rename from service/src/commonMain/kotlin/androidmakers/service/context/CacheControlContext.kt rename to service/src/main/kotlin/androidmakers/service/context/CacheControlContext.kt index 8b19322f..ee09ebdc 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/context/CacheControlContext.kt +++ b/service/src/main/kotlin/androidmakers/service/context/CacheControlContext.kt @@ -1,6 +1,6 @@ package androidmakers.service.context -import com.apollographql.apollo3.api.ExecutionContext +import com.apollographql.apollo.api.ExecutionContext import com.google.auth.oauth2.GoogleCredentials import com.google.cloud.datastore.Datastore import com.google.cloud.datastore.DatastoreOptions diff --git a/service/src/commonMain/kotlin/androidmakers/service/context/DatastoreContext.kt b/service/src/main/kotlin/androidmakers/service/context/DatastoreContext.kt similarity index 93% rename from service/src/commonMain/kotlin/androidmakers/service/context/DatastoreContext.kt rename to service/src/main/kotlin/androidmakers/service/context/DatastoreContext.kt index d27319e3..45f5374d 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/context/DatastoreContext.kt +++ b/service/src/main/kotlin/androidmakers/service/context/DatastoreContext.kt @@ -1,7 +1,7 @@ package androidmakers.service.context import androidmakers.service.graphql.KIND_BOOKMARKS -import com.apollographql.apollo3.api.ExecutionContext +import com.apollographql.apollo.api.ExecutionContext import com.google.auth.oauth2.GoogleCredentials import com.google.cloud.datastore.Datastore import com.google.cloud.datastore.DatastoreOptions diff --git a/service/src/commonMain/kotlin/androidmakers/service/firebase.kt b/service/src/main/kotlin/androidmakers/service/firebase.kt similarity index 100% rename from service/src/commonMain/kotlin/androidmakers/service/firebase.kt rename to service/src/main/kotlin/androidmakers/service/firebase.kt diff --git a/service/src/commonMain/kotlin/androidmakers/service/graphql/model.kt b/service/src/main/kotlin/androidmakers/service/graphql/model.kt similarity index 97% rename from service/src/commonMain/kotlin/androidmakers/service/graphql/model.kt rename to service/src/main/kotlin/androidmakers/service/graphql/model.kt index e719e608..e5d7ce07 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/graphql/model.kt +++ b/service/src/main/kotlin/androidmakers/service/graphql/model.kt @@ -7,15 +7,18 @@ import androidmakers.service.context.bookmarksKeyFactory import androidmakers.service.context.datastore import androidmakers.service.context.uid import androidmakers.service.context.updateMaxAge -import com.apollographql.apollo3.annotations.* -import com.apollographql.apollo3.api.ExecutionContext +import com.apollographql.apollo.annotations.* +import com.apollographql.apollo.api.ExecutionContext +import com.apollographql.execution.annotation.GraphQLDefault +import com.apollographql.execution.annotation.GraphQLMutation +import com.apollographql.execution.annotation.GraphQLQuery import com.google.cloud.datastore.BooleanValue import com.google.cloud.datastore.Entity import kotlinx.datetime.LocalDateTime const val KIND_BOOKMARKS = "Bookmarks" -@GraphQLMutationRoot +@GraphQLMutation class RootMutation { fun addBookmark(executionContext: ExecutionContext, sessionId: String): BookmarkConnection { val uid = executionContext.uid() @@ -97,7 +100,7 @@ class RootMutation { } -@GraphQLQueryRoot +@GraphQLQuery class RootQuery { fun rooms(): List { return Sessionize.data().rooms @@ -253,7 +256,6 @@ enum class ConferenceField { DAYS, } - data class Room( val id: String, val name: String, diff --git a/service/src/commonMain/kotlin/androidmakers/service/graphql/scalars.kt b/service/src/main/kotlin/androidmakers/service/graphql/scalars.kt similarity index 86% rename from service/src/commonMain/kotlin/androidmakers/service/graphql/scalars.kt rename to service/src/main/kotlin/androidmakers/service/graphql/scalars.kt index eeafc127..6ead9536 100644 --- a/service/src/commonMain/kotlin/androidmakers/service/graphql/scalars.kt +++ b/service/src/main/kotlin/androidmakers/service/graphql/scalars.kt @@ -1,10 +1,10 @@ package androidmakers.service.graphql -import com.apollographql.apollo3.annotations.GraphQLScalar -import com.apollographql.apollo3.ast.GQLStringValue -import com.apollographql.apollo3.ast.GQLValue -import com.apollographql.apollo3.execution.Coercing -import com.apollographql.apollo3.execution.internal.ExternalValue +import com.apollographql.apollo.ast.GQLStringValue +import com.apollographql.apollo.ast.GQLValue +import com.apollographql.apollo.execution.Coercing +import com.apollographql.apollo.execution.ExternalValue +import com.apollographql.execution.annotation.GraphQLScalar import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDateTime diff --git a/service/src/commonMain/kotlin/androidmakers/service/sandbox.kt b/service/src/main/kotlin/androidmakers/service/sandbox.kt similarity index 100% rename from service/src/commonMain/kotlin/androidmakers/service/sandbox.kt rename to service/src/main/kotlin/androidmakers/service/sandbox.kt diff --git a/service/src/commonMain/kotlin/androidmakers/service/sessionize.kt b/service/src/main/kotlin/androidmakers/service/sessionize.kt similarity index 100% rename from service/src/commonMain/kotlin/androidmakers/service/sessionize.kt rename to service/src/main/kotlin/androidmakers/service/sessionize.kt diff --git a/sessionize/build.gradle.kts b/sessionize/build.gradle.kts index dc1d2d97..e5246546 100644 --- a/sessionize/build.gradle.kts +++ b/sessionize/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("org.jetbrains.kotlin.jvm") - id("org.jetbrains.kotlin.plugin.spring") id("org.jetbrains.kotlin.plugin.serialization") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 6fa41376..1c78a33a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,7 +4,7 @@ pluginManagement { mavenCentral() google() gradlePluginPortal() - maven("https://storage.googleapis.com/martin-maven/m2/") + maven("https://storage.googleapis.com/apollo-snapshots/m2/") } } @@ -19,7 +19,6 @@ pluginManagement { } rootProject.name = "AndroidMakersBackend" -include(":service-graphql") include(":sessionize") include(":data") include(":sync") diff --git a/sync/build.gradle.kts b/sync/build.gradle.kts index d3395076..8e927ae9 100644 --- a/sync/build.gradle.kts +++ b/sync/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("org.jetbrains.kotlin.jvm") - id("org.jetbrains.kotlin.plugin.spring") id("org.jetbrains.kotlin.plugin.serialization") }