-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
183 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# To save time-series CSV files supplied by customers. | ||
# Specifically quarter-hourly electricity usage and hourly gas usage. | ||
AZURE_STORAGE_ACCOUNT_NAME= | ||
AZURE_STORAGE_ACCOUNT_KEY= | ||
AZURE_STORAGE_CONTAINER= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.zenmo | ||
|
||
fun errorMessageToJson(message: String?): Any { | ||
return mapOf( | ||
"error" to mapOf( | ||
"message" to message | ||
) | ||
) | ||
} |
85 changes: 85 additions & 0 deletions
85
ztor/src/main/kotlin/com/zenmo/companysurvey/BlobStorage.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.zenmo.companysurvey | ||
|
||
import com.azure.storage.blob.BlobServiceClientBuilder | ||
import com.azure.storage.blob.sas.BlobSasPermission | ||
import com.azure.storage.blob.sas.BlobServiceSasSignatureValues | ||
import com.azure.storage.common.sas.SasProtocol | ||
import java.time.Instant | ||
import java.time.OffsetDateTime | ||
import java.time.ZoneId | ||
import java.time.ZoneOffset | ||
import java.time.format.DateTimeFormatter | ||
import kotlin.streams.asSequence | ||
|
||
enum class BlobPurpose { | ||
NATURAL_GAS_VALUES, | ||
ELECTRICITY_VALUES, | ||
ELECTRICITY_AUTHORIZATION; | ||
|
||
fun toNamePart(): String { | ||
return this.toString().lowercase().replace("_", "-") | ||
} | ||
} | ||
|
||
class BlobStorage( | ||
private val azureAccountName: String = System.getenv("AZURE_STORAGE_ACCOUNT_NAME"), | ||
private val azureAccountKey: String = System.getenv("AZURE_STORAGE_ACCOUNT_KEY"), | ||
private val containerName: String = System.getenv("AZURE_STORAGE_CONTAINER"), | ||
) { | ||
val blobServiceClient = BlobServiceClientBuilder() | ||
.connectionString("DefaultEndpointsProtocol=https;AccountName=$azureAccountName;AccountKey=$azureAccountKey") | ||
.buildClient() | ||
|
||
/** | ||
* You can use the result of this function to directly upload a file to Azure Blob Storage. | ||
* You only need to set the `x-ms-blob-type` header to `BlockBlob`. | ||
*/ | ||
fun getBlobSasUrl( | ||
blobPurpose: BlobPurpose, | ||
project: String, | ||
company: String, | ||
fileName: String, | ||
): String { | ||
if (project === "") { | ||
throw Exception("Company name cannot be empty") | ||
} | ||
|
||
if (company === "") { | ||
throw Exception("Company name cannot be empty") | ||
} | ||
|
||
if (fileName === "") { | ||
throw Exception("File name cannot be empty") | ||
} | ||
|
||
val dateStamp = DateTimeFormatter | ||
.ofPattern("yyyy-MM-dd") | ||
.withZone(ZoneId.of("Europe/Amsterdam")) | ||
.format(Instant.now()) | ||
|
||
val blobName = "${dateStamp}_${project}_${company}_${blobPurpose.toNamePart()}_${randomString(3u)}_${fileName}" | ||
|
||
val blobClient = blobServiceClient.getBlobContainerClient(containerName).getBlobClient(blobName) | ||
// We would like to (pre-)set some metadata but this is not (easily) possible. | ||
|
||
val permissions = BlobSasPermission().setReadPermission(true).setWritePermission(true).setCreatePermission(true) | ||
|
||
val expiryTime = OffsetDateTime.now().plusDays(1) | ||
|
||
val sasSignatureValues = BlobServiceSasSignatureValues(expiryTime, permissions) | ||
.setProtocol(SasProtocol.HTTPS_HTTP) | ||
|
||
val sasToken = blobClient.generateSas(sasSignatureValues) | ||
|
||
return "${blobClient.blobUrl}?$sasToken" | ||
} | ||
} | ||
|
||
fun randomString(length: UInt): String { | ||
val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | ||
|
||
return java.util.Random().ints(length.toLong(), 0, chars.length) | ||
.asSequence() | ||
.map(chars::get) | ||
.joinToString("") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.zenmo.plugins | ||
|
||
import io.ktor.server.application.* | ||
import io.ktor.server.response.* | ||
import io.ktor.server.routing.* | ||
import com.azure.storage.blob.BlobServiceClientBuilder | ||
import com.azure.storage.blob.sas.BlobSasPermission | ||
import com.azure.storage.blob.sas.BlobServiceSasSignatureValues | ||
import com.azure.storage.common.sas.SasProtocol | ||
import com.zenmo.companysurvey.BlobPurpose | ||
import com.zenmo.companysurvey.BlobStorage | ||
import com.zenmo.errorMessageToJson | ||
import io.ktor.http.* | ||
import io.ktor.server.plugins.* | ||
import java.time.OffsetDateTime | ||
|
||
fun Application.configureUpload() { | ||
val blobStorage = BlobStorage() | ||
|
||
routing { | ||
// Get a shared access signature (SAS) token that can be used to upload a blob. | ||
get("/upload-url") { | ||
val queryParams = call.request.queryParameters | ||
|
||
val required = listOf("project", "company", "fileName", "purpose") | ||
val missing = required.filter { !queryParams.contains(it) } | ||
if (missing.isNotEmpty()) { | ||
call.respond(HttpStatusCode.BadRequest, errorMessageToJson("Missing query parameters: ${missing.joinToString(", ")}")) | ||
return@get | ||
} | ||
|
||
val url = blobStorage.getBlobSasUrl( | ||
BlobPurpose.valueOf(queryParams["purpose"]!!), | ||
queryParams["project"]!!, | ||
queryParams["company"]!!, | ||
queryParams["fileName"]!!, | ||
) | ||
|
||
call.respond(mapOf("uploadUrl" to url)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ class RepositoryTest { | |
val repo = SurveyRepository(db) | ||
val survey = Survey( | ||
companyName = "Zenmo", | ||
project = "Project", | ||
personName = "John Doe", | ||
email = "[email protected]", | ||
gridConnections = emptyList(), | ||
|
@@ -69,6 +70,7 @@ class RepositoryTest { | |
val repo = SurveyRepository(db) | ||
val survey = Survey( | ||
companyName = "Zenmo", | ||
project = "Project", | ||
personName = "John Doe", | ||
email = "[email protected]", | ||
transport = Transport( | ||
|
@@ -162,6 +164,7 @@ class RepositoryTest { | |
), | ||
mainConsumptionProcess = "Main consumption process", | ||
electrificationPlans = "Electrification plans", | ||
consumptionFlexibility = "Consumption flexibility", | ||
) | ||
) | ||
) | ||
|