diff --git a/HaveAMagicalDay/app/build.gradle.kts b/HaveAMagicalDay/app/build.gradle.kts index 590e176..79a14e5 100644 --- a/HaveAMagicalDay/app/build.gradle.kts +++ b/HaveAMagicalDay/app/build.gradle.kts @@ -10,6 +10,7 @@ plugins { dependencies { implementation("com.github.ajalt.clikt:clikt:3.5.2") implementation("com.algorand:algosdk:2.0.0") + testImplementation("junit:junit:4.13.2") } fun buildVersionCode(): Int { diff --git a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/App.kt b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/App.kt index e5c2a31..a6b815f 100644 --- a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/App.kt +++ b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/App.kt @@ -1,23 +1,18 @@ package com.michaeltchuang.cron -import com.algorand.algosdk.v2.client.common.AlgodClient import com.michaeltchuang.cron.data.AlgorandRepository import com.michaeltchuang.cron.utils.Constants +import com.michaeltchuang.cron.utils.DateUtils +import java.nio.file.Files +import java.nio.file.Paths +import java.nio.file.StandardOpenOption import java.time.LocalDate -import java.time.Period import java.time.format.DateTimeFormatter import java.util.TimeZone -private val TAG: String = "AlgorandRepository" -private var client: AlgodClient = AlgodClient( - Constants.ALGOD_API_ADDR, - Constants.ALGOD_PORT, - Constants.ALGOD_API_TOKEN, - Constants.ALGOD_API_TOKEN_KEY -) - -val txHeaders = arrayOf("Content-Type") -val txValues = arrayOf("application/x-binary") +val tz = TimeZone.getTimeZone("America/Los_Angeles") +val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(tz.toZoneId()) +val currentDateStr = LocalDate.now(tz.toZoneId()).format(dateFormatter).toString() fun main() { val repository = AlgorandRepository() @@ -26,38 +21,37 @@ fun main() { if (account == null) { throw Exception("Could not find account") } else { - account.address?.apply { repository.sendPayment(account, Constants.COINFLIP_APP_ID_TESTNET, - Constants.DEFAULT_MICRO_ALGO_TRANSFER_AMOUNT, getGreeting(false)) } + val volumeNum = DateUtils().calculateVolumeNum(false, Constants.VOL2_START_DATE, currentDateStr) + var vlogNum = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, currentDateStr) + account.address?.apply { AppendToCsvFile(vlogNum, repository.sendPayment(account, Constants.COINFLIP_APP_ID_TESTNET, + Constants.DEFAULT_MICRO_ALGO_TRANSFER_AMOUNT, getGreeting(volumeNum, vlogNum))) } //send twice if Mondays - 8th vlog - val tz = TimeZone.getTimeZone("America/Los_Angeles") if(LocalDate.now(tz.toZoneId()).dayOfWeek.value == 1) { - account.address?.apply { repository.sendPayment(account, Constants.COINFLIP_APP_ID_TESTNET, - Constants.DEFAULT_MICRO_ALGO_TRANSFER_AMOUNT, getGreeting(true)) } + vlogNum = DateUtils().calculateVlogNum(true, Constants.VOL2_START_DATE, currentDateStr) + account.address?.apply { AppendToCsvFile(vlogNum, repository.sendPayment(account, Constants.COINFLIP_APP_ID_TESTNET, + Constants.DEFAULT_MICRO_ALGO_TRANSFER_AMOUNT, getGreeting(volumeNum, vlogNum))) } } } } -fun getGreeting(isEighth: Boolean) : String { - var vlogNum = calculateVlogNum(isEighth) - - val note = "Volume 2 Vlog ${vlogNum}, have a magical day everyone! - Michael T Chuang" +fun getGreeting(volume: Int, vlogNum: Int) : String { + val note = "Vlog ${volume}-${vlogNum}, have a magical day everyone! - Michael T Chuang" println(note) return note } -fun calculateVlogNum(isEighth: Boolean) : Int { - val tz = TimeZone.getTimeZone("America/Los_Angeles") - val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd").withZone(tz.toZoneId()) - val from = LocalDate.parse("20230220", dateFormatter) - val to = LocalDate.now(tz.toZoneId()) - val period = Period.between(from, to) - val weeks = period.days / 8 - println("${period.days} days is ${weeks} weeks since Feb 21, 2023") - - if(!isEighth) { - return ((weeks * 8) + (period.days % 7)) - } else { - return (weeks * 8) + 8 - } +fun AppendToCsvFile(vlogNum: Int, txnId: String?) { + try { + if(txnId != null) { + val str = "\n${currentDateStr},2-${vlogNum},${txnId}" + Files.write( + Paths.get(Constants.HISTORY_CSV_FILE), + str.toByteArray(), + StandardOpenOption.APPEND + ) + } else { + throw IllegalStateException("Error in creating Algorand transaction") + } + } catch (e: Exception) { println(e.toString())} } diff --git a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/data/AlgorandRepository.kt b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/data/AlgorandRepository.kt index 1fd5616..2e4eb58 100644 --- a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/data/AlgorandRepository.kt +++ b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/data/AlgorandRepository.kt @@ -9,8 +9,6 @@ import com.algorand.algosdk.v2.client.Utils import com.algorand.algosdk.v2.client.common.AlgodClient import com.algorand.algosdk.v2.client.model.PendingTransactionResponse import com.algorand.algosdk.v2.client.model.TransactionParametersResponse -import com.michaeltchuang.cron.txHeaders -import com.michaeltchuang.cron.txValues import com.michaeltchuang.cron.utils.Constants class AlgorandRepository() { @@ -22,6 +20,9 @@ class AlgorandRepository() { Constants.ALGOD_API_TOKEN_KEY ) + val txHeaders = arrayOf("Content-Type") + val txValues = arrayOf("application/x-binary") + fun recoverAccount(passPhrase: String): Account? { try { return Account(passPhrase) @@ -31,7 +32,7 @@ class AlgorandRepository() { } } - fun sendPayment(account: Account, appId: Long, amount: Int, note: String): PendingTransactionResponse? { + fun sendPayment(account: Account, appId: Long, amount: Int, note: String): String? { try { val respAcct = client.AccountInformation(account.getAddress()).execute() if (!respAcct.isSuccessful) { @@ -66,7 +67,7 @@ class AlgorandRepository() { // Wait for transaction confirmation val pTrx: PendingTransactionResponse = Utils.waitForConfirmation(client, txnId, 10) println("${account.address} sent $amount microAlgos to ${Address.forApplication(appId)} for transaction $txnId") - return pTrx + return txnId } catch (e: Exception) { println(e.toString()) return null diff --git a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/Constants.kt b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/Constants.kt index e9e5e65..e33e0f1 100644 --- a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/Constants.kt +++ b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/Constants.kt @@ -1,7 +1,7 @@ package com.michaeltchuang.cron.utils object Constants { - const val ALGOD_API_ADDR = "https://testnet-algorand.api.purestake.io/ps2" + const val ALGOD_API_ADDR = "https://testnet-api.algonode.cloud" const val ALGOD_PORT = 443 const val ALGOD_API_TOKEN_KEY = "X-API-Key" const val ALGOD_API_TOKEN = "B3SU4KcVKi94Jap2VXkK83xx38bsv95K5UZm2lab" @@ -9,4 +9,7 @@ object Constants { const val TEST_ADDRESS = "LMRZRYVM3EXPLNGW7VRIIZ4CQKW5IVPDDXCKFZKCLJF35CNJMEKJNUTJIQ" const val TEST_PASSPHRASE = "swing enrich bring novel oak gadget barely deer bottom brown where fossil can intact cactus rail pumpkin cost actual famous gauge deny pink above rubber" const val DEFAULT_MICRO_ALGO_TRANSFER_AMOUNT = 888 + const val DEFAULT_VLOG_TIME = "T08:08:08.888" + const val VOL2_START_DATE = "2023-02-20" + const val HISTORY_CSV_FILE = "greeting-history.log" } diff --git a/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/DateUtils.kt b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/DateUtils.kt new file mode 100644 index 0000000..342cb9c --- /dev/null +++ b/HaveAMagicalDay/app/src/main/kotlin/com/michaeltchuang/cron/utils/DateUtils.kt @@ -0,0 +1,26 @@ +package com.michaeltchuang.cron.utils + +import java.time.Duration +import java.time.LocalDateTime + +class DateUtils() { + fun calculateVlogNum(returnEighth: Boolean, startDateStr: String, endDateStr: String) : Int { + val from = LocalDateTime.parse(startDateStr + Constants.DEFAULT_VLOG_TIME) + val to = LocalDateTime.parse(endDateStr + Constants.DEFAULT_VLOG_TIME) + val days = Duration.between(from, to).toDays() + println("${days} days between ${startDateStr} and ${endDateStr}") + + if(returnEighth) { + return (days / 7 * 8).toInt() + } else if (days % 7 == 0L) { + return ((days / 7 * 8) - 1).toInt() + } else { + return ((days / 7 * 8) + (days % 7)).toInt() + } + } + + fun calculateVolumeNum(returnEighth: Boolean, startDateStr: String, endDateStr: String) : Int { + //hardcode to volume 2 for now + return 2 + } +} \ No newline at end of file diff --git a/HaveAMagicalDay/app/src/test/kotlin/com/michaeltchuang/cron/UnitTests.kt b/HaveAMagicalDay/app/src/test/kotlin/com/michaeltchuang/cron/UnitTests.kt new file mode 100644 index 0000000..38fd904 --- /dev/null +++ b/HaveAMagicalDay/app/src/test/kotlin/com/michaeltchuang/cron/UnitTests.kt @@ -0,0 +1,66 @@ +package com.michaeltchuang.cron + +import com.michaeltchuang.cron.data.AlgorandRepository +import com.michaeltchuang.cron.utils.Constants +import com.michaeltchuang.cron.utils.DateUtils +import org.junit.Assert.assertEquals +import org.junit.Test + +class UnitTests { + val VOL2_VLOG1_DATE = "2023-02-21" + val VOL2_VLOG22_DATE = "2023-03-12" + val VOL2_VLOG23_DATE = "2023-03-13" + val VOL2_VLOG24_DATE = "2023-03-13" + val VOL2_VLOG25_DATE = "2023-03-14" + val VOL2_VLOG31_DATE = "2023-03-20" + val VOL2_VLOG39_DATE = "2023-03-27" + val VOL2_VLOG42_DATE = "2023-03-29" + + @Test + fun vlog1() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG1_DATE) + assertEquals(output, 1) + } + + @Test + fun vlog22() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG22_DATE) + assertEquals(22, output) + } + + @Test + fun vlog23() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG23_DATE) + assertEquals(23, output) + } + + @Test + fun vlog24() { + val output = DateUtils().calculateVlogNum(true, Constants.VOL2_START_DATE, VOL2_VLOG24_DATE) + assertEquals(24, output) + } + + @Test + fun vlog25() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG25_DATE) + assertEquals(25, output) + } + + @Test + fun vlog31() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG31_DATE) + assertEquals(31, output) + } + + @Test + fun vlog39() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG39_DATE) + assertEquals(39, output) + } + + @Test + fun vlog42() { + val output = DateUtils().calculateVlogNum(false, Constants.VOL2_START_DATE, VOL2_VLOG42_DATE) + assertEquals(42, output) + } +} \ No newline at end of file diff --git a/HaveAMagicalDay/greeting-history.log b/HaveAMagicalDay/greeting-history.log new file mode 100644 index 0000000..e75c887 --- /dev/null +++ b/HaveAMagicalDay/greeting-history.log @@ -0,0 +1,3 @@ +"Date,"Vlog #","Transaction" +2023-03-13,2-23,W2RVPD6SRQRKBIYKFH5JFSSUKWVPVUV6TOL5DOF2D3RQIPJ6IILQ +2023-03-13,2-24,33LDJYKXY6QEKFZPIA2KRTNL6I7ISWZCXEEH3IKCHE4D254CJC5Q \ No newline at end of file diff --git a/HaveAMagicalDay/release.config.js b/HaveAMagicalDay/release.config.js index 557aa06..ac0f65d 100644 --- a/HaveAMagicalDay/release.config.js +++ b/HaveAMagicalDay/release.config.js @@ -99,7 +99,7 @@ module.exports = { { assets: ["CHANGELOG.md", "build.gradle", "README.md"], message: - "chore: ${nextRelease.version} (release) \n\n${nextRelease.notes}", + "chore: v${nextRelease.version} (release) \n\n${nextRelease.notes}", }, ], ],