From f7687cdbd3cf755cce288375400d17c6285e890b Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Sun, 19 Nov 2017 17:09:24 +0300 Subject: [PATCH 01/10] feat: add useremail proto message, update other --- src/main/kotlin/app/model/Repo.kt | 2 -- src/main/kotlin/app/model/User.kt | 12 +++++--- src/main/kotlin/app/model/UserEmail.kt | 41 ++++++++++++++++++++++++++ src/main/proto/sourcerer.proto | 12 ++++++-- 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/app/model/UserEmail.kt diff --git a/src/main/kotlin/app/model/Repo.kt b/src/main/kotlin/app/model/Repo.kt index 62e35562..d0b60c08 100644 --- a/src/main/kotlin/app/model/Repo.kt +++ b/src/main/kotlin/app/model/Repo.kt @@ -28,7 +28,6 @@ data class Repo( constructor(proto: Protos.Repo) : this() { rehash = proto.rehash initialCommitRehash = proto.initialCommitRehash - userEmail = proto.userEmail emails = proto.emailsList commits = proto.commitsList.map { Commit(it) } } @@ -42,7 +41,6 @@ data class Repo( return Protos.Repo.newBuilder() .setRehash(rehash) .setInitialCommitRehash(rehash) - .setUserEmail(userEmail) .addAllEmails(emails) .addAllCommits(commits.map { it.getProto() }) .build() diff --git a/src/main/kotlin/app/model/User.kt b/src/main/kotlin/app/model/User.kt index c9181490..0ba4311e 100644 --- a/src/main/kotlin/app/model/User.kt +++ b/src/main/kotlin/app/model/User.kt @@ -11,12 +11,15 @@ import java.security.InvalidParameterException * User information. */ data class User ( - var repos: MutableList = mutableListOf() + var repos: MutableList = mutableListOf(), + var emails: MutableList = mutableListOf() ) { @Throws(InvalidParameterException::class) constructor(proto: Protos.User) : this() { repos = proto.reposList.map { repo -> Repo(repo) } - .toMutableList() + .toMutableList() + emails = proto.emailsList.map { email -> UserEmail(email) } + .toMutableList() } @Throws(InvalidProtocolBufferException::class) @@ -26,8 +29,9 @@ data class User ( fun getProto(): Protos.User { return Protos.User.newBuilder() - .addAllRepos(repos.map { repo -> repo.getProto() }) - .build() + .addAllRepos(repos.map { repo -> repo.getProto() }) + .addAllEmails(emails.map { email -> email.getProto() }) + .build() } fun serialize(): ByteArray { diff --git a/src/main/kotlin/app/model/UserEmail.kt b/src/main/kotlin/app/model/UserEmail.kt new file mode 100644 index 00000000..b61b1748 --- /dev/null +++ b/src/main/kotlin/app/model/UserEmail.kt @@ -0,0 +1,41 @@ +// Copyright 2017 Sourcerer Inc. All Rights Reserved. +// Author: Anatoly Kislov (anatoly@sourcerer.io) + +package app.model + +import app.Protos +import com.google.protobuf.InvalidProtocolBufferException +import java.security.InvalidParameterException + +/** + * User information. + */ +data class UserEmail( + var email: String = "", + var primary: Boolean = false, + var verified: Boolean = false +) { + @Throws(InvalidParameterException::class) + constructor(proto: Protos.UserEmail) : this() { + email = proto.email + primary = proto.primary + verified = proto.verified + } + + @Throws(InvalidProtocolBufferException::class) + constructor(bytes: ByteArray) : this(Protos.UserEmail.parseFrom(bytes)) + + constructor(serialized: String) : this(serialized.toByteArray()) + + fun getProto(): Protos.UserEmail { + return Protos.UserEmail.newBuilder() + .setEmail(email) + .setPrimary(primary) + .setVerified(verified) + .build() + } + + fun serialize(): ByteArray { + return getProto().toByteArray() + } +} diff --git a/src/main/proto/sourcerer.proto b/src/main/proto/sourcerer.proto index f3d11913..153ea403 100644 --- a/src/main/proto/sourcerer.proto +++ b/src/main/proto/sourcerer.proto @@ -86,6 +86,15 @@ message AuthorGroup { message User { // List of known repos containing basic information for indentifying repo. repeated Repo repos = 1; + // List of known emails. + repeated UserEmail emails = 2; +} + +// Email of user with its status information. +message UserEmail { + string email = 1; + bool primary = 2; + bool verified = 3; } // Repository parameters for hashing. @@ -97,9 +106,6 @@ message Repo { // Rehash of first commit in repo. Used for indentifying forks. string initial_commit_rehash = 2; - // Email of app user from git config of repo. - string user_email = 3; - // Authors' email filter for hashed commits. If empty list then hash only // commits that created by current user. repeated string emails = 4; From 5b9d49b538436a943a1573077de649bccc381135 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Sun, 19 Nov 2017 23:39:36 +0300 Subject: [PATCH 02/10] wip: add workflow for adding multiple emails --- src/main/kotlin/app/config/Configurator.kt | 6 +- .../kotlin/app/config/FileConfigurator.kt | 15 ++-- .../kotlin/app/config/MockConfigurator.kt | 12 +-- src/main/kotlin/app/model/User.kt | 5 +- src/main/kotlin/app/model/UserEmail.kt | 19 ++++- src/main/kotlin/app/ui/AddRepoState.kt | 5 +- src/main/kotlin/app/ui/AuthState.kt | 4 +- src/main/kotlin/app/ui/EmailState.kt | 82 +++++++++++++++++++ 8 files changed, 123 insertions(+), 25 deletions(-) create mode 100644 src/main/kotlin/app/ui/EmailState.kt diff --git a/src/main/kotlin/app/config/Configurator.kt b/src/main/kotlin/app/config/Configurator.kt index 0cab1036..c9960ed0 100644 --- a/src/main/kotlin/app/config/Configurator.kt +++ b/src/main/kotlin/app/config/Configurator.kt @@ -4,7 +4,7 @@ package app.config import app.model.LocalRepo -import app.model.Repo +import app.model.User import app.utils.Options interface Configurator { @@ -13,7 +13,7 @@ interface Configurator { fun getPassword(): String fun isValidCredentials(): Boolean fun getLocalRepos(): List - fun getRepos(): List + fun getUser(): User fun setUsernameCurrent(username: String) fun setPasswordCurrent(password: String) fun getUuidPersistent(): String @@ -21,7 +21,7 @@ interface Configurator { fun setPasswordPersistent(password: String) fun addLocalRepoPersistent(localRepo: LocalRepo) fun removeLocalRepoPersistent(localRepo: LocalRepo) - fun setRepos(repos: List) + fun setUser(user: User) fun isFirstLaunch(): Boolean fun loadFromFile() fun saveToFile() diff --git a/src/main/kotlin/app/config/FileConfigurator.kt b/src/main/kotlin/app/config/FileConfigurator.kt index c5577ca5..fa2b48e3 100644 --- a/src/main/kotlin/app/config/FileConfigurator.kt +++ b/src/main/kotlin/app/config/FileConfigurator.kt @@ -6,6 +6,7 @@ package app.config import app.Logger import app.model.LocalRepo import app.model.Repo +import app.model.User import app.utils.Options import app.utils.PasswordHelper import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility @@ -62,7 +63,7 @@ class FileConfigurator : Configurator { /** * Used to temporarily save list of repos that known by server. */ - private var repos: List = listOf() + private var user: User = User() /** * User directory path is where persistent config stored. @@ -143,10 +144,10 @@ class FileConfigurator : Configurator { } /** - * Gets list of temprorary saved repos. + * Gets temprorary saved user information. */ - override fun getRepos(): List { - return repos + override fun getUser(): User { + return user } /** @@ -199,10 +200,10 @@ class FileConfigurator : Configurator { } /** - * Temporarily sets list of repos. + * Temporarily sets info about user. */ - override fun setRepos(repos: List) { - this.repos = repos + override fun setUser(user: User) { + this.user = user } /** diff --git a/src/main/kotlin/app/config/MockConfigurator.kt b/src/main/kotlin/app/config/MockConfigurator.kt index 1b482c23..75c30bbf 100644 --- a/src/main/kotlin/app/config/MockConfigurator.kt +++ b/src/main/kotlin/app/config/MockConfigurator.kt @@ -4,14 +4,14 @@ package app.config import app.model.LocalRepo -import app.model.Repo +import app.model.User import app.utils.Options class MockConfigurator(var mockUsername: String = "", var mockPassword: String = "", var mockIsValidCredentials: Boolean = true, var mockIsFirstLaunch: Boolean = true, - var mockRepos: MutableList = mutableListOf(), + var mockUser: User = User(), var mockLocalRepos: MutableList = mutableListOf(), var uuid: String = "") : Configurator { @@ -39,8 +39,8 @@ class MockConfigurator(var mockUsername: String = "", return mockLocalRepos } - override fun getRepos(): List { - return mockRepos + override fun getUser(): User { + return mockUser } override fun setUsernameCurrent(username: String) { @@ -72,8 +72,8 @@ class MockConfigurator(var mockUsername: String = "", mockPersistent.localRepos.remove(localRepo) } - override fun setRepos(repos: List) { - mockRepos = repos.toMutableList() + override fun setUser(user: User) { + mockUser = user } override fun isFirstLaunch(): Boolean { diff --git a/src/main/kotlin/app/model/User.kt b/src/main/kotlin/app/model/User.kt index 0ba4311e..78f731bc 100644 --- a/src/main/kotlin/app/model/User.kt +++ b/src/main/kotlin/app/model/User.kt @@ -12,14 +12,13 @@ import java.security.InvalidParameterException */ data class User ( var repos: MutableList = mutableListOf(), - var emails: MutableList = mutableListOf() + var emails: HashSet = hashSetOf() ) { @Throws(InvalidParameterException::class) constructor(proto: Protos.User) : this() { repos = proto.reposList.map { repo -> Repo(repo) } .toMutableList() - emails = proto.emailsList.map { email -> UserEmail(email) } - .toMutableList() + emails = proto.emailsList.map { email -> UserEmail(email) }.toHashSet() } @Throws(InvalidProtocolBufferException::class) diff --git a/src/main/kotlin/app/model/UserEmail.kt b/src/main/kotlin/app/model/UserEmail.kt index b61b1748..3dd4f964 100644 --- a/src/main/kotlin/app/model/UserEmail.kt +++ b/src/main/kotlin/app/model/UserEmail.kt @@ -10,7 +10,7 @@ import java.security.InvalidParameterException /** * User information. */ -data class UserEmail( +class UserEmail( var email: String = "", var primary: Boolean = false, var verified: Boolean = false @@ -38,4 +38,21 @@ data class UserEmail( fun serialize(): ByteArray { return getProto().toByteArray() } + + override fun toString(): String { + val primary = if (this.primary) " (Primary)" else "" + val verified = if (this.verified) "Verified" else "Unverified" + return "${this.email}$primary — $verified" + } + + override fun equals(other: Any?): Boolean { + if (other is UserEmail) { + return email == other.email + } + return false + } + + override fun hashCode(): Int { + return email.hashCode() + } } diff --git a/src/main/kotlin/app/ui/AddRepoState.kt b/src/main/kotlin/app/ui/AddRepoState.kt index 33e55194..b73c390a 100644 --- a/src/main/kotlin/app/ui/AddRepoState.kt +++ b/src/main/kotlin/app/ui/AddRepoState.kt @@ -21,8 +21,7 @@ class AddRepoState constructor(private val context: Context, if (configurator.getLocalRepos().isNotEmpty()) return while (true) { - println("Type a path to repository, or hit Enter to start " - + "hashing.") + println("Type a path to repository, or hit Enter to continue.") val pathString = readLine() ?: "" if (pathString.isEmpty()) { @@ -52,6 +51,6 @@ class AddRepoState constructor(private val context: Context, } override fun next() { - context.changeState(UpdateRepoState(context, api, configurator)) + context.changeState(EmailState(context, api, configurator)) } } diff --git a/src/main/kotlin/app/ui/AuthState.kt b/src/main/kotlin/app/ui/AuthState.kt index 66948e9b..5d48600c 100644 --- a/src/main/kotlin/app/ui/AuthState.kt +++ b/src/main/kotlin/app/ui/AuthState.kt @@ -83,12 +83,12 @@ class AuthState constructor(private val context: Context, error.ifNotNullThrow() val user = api.getUser().getOrThrow() - configurator.setRepos(user.repos) + configurator.setUser(user) println("You are successfully authenticated. Your profile page is " + BuildConfig.PROFILE_URL + configurator.getUsername()) - saveCredentialsIfChanged() + saveCredentialsIfChanged() Logger.username = configurator.getUsername() Logger.info(Logger.Events.AUTH) { "Auth success" } diff --git a/src/main/kotlin/app/ui/EmailState.kt b/src/main/kotlin/app/ui/EmailState.kt new file mode 100644 index 00000000..f0578572 --- /dev/null +++ b/src/main/kotlin/app/ui/EmailState.kt @@ -0,0 +1,82 @@ +package app.ui + +import app.Logger +import app.api.Api +import app.config.Configurator +import app.model.User +import app.model.UserEmail +import app.utils.UiHelper +import org.eclipse.jgit.api.Git +import java.io.File + +/** + * Update repositories console UI state. + */ +class EmailState constructor(private val context: Context, + private val api: Api, + private val configurator: Configurator) + : ConsoleState { + override fun doAction() { + val user = configurator.getUser() + + println("List of your emails:") + user.emails.forEach { email -> println(email) } + + val knownEmails = user.emails.map { it.email } + val newEmails = hashSetOf() + val configEmails = hashSetOf() + // TODO(anatoly): Add global config parsing. + // TODO(anatoly): Add user config parsing. + + // Add emails from git configs. + for (repo in configurator.getLocalRepos()) { + try { + val git = Git.open(File(repo.path)) + val email = git.repository + .config.getString("user", null, "email") ?: "" + if (!knownEmails.contains(email)) { + configEmails.add(email) + } + } catch (e: Exception) { + Logger.error(e, "Error while parsing git config") + } + } + + if (configEmails.isNotEmpty()) { + println("Your git configs contains untracked emails:") + configEmails.forEach { email -> println(email) } + if (UiHelper.confirm("Do you want to add this emails to your" + + "account?", defaultIsYes = true)) { + newEmails.addAll(configEmails) + } + } + + // Ask user to enter his emails. + if (UiHelper.confirm("Do you want to specify additional emails " + + "that you use in repositories?", defaultIsYes = false)) { + while (true) { + println("Type a email, or hit Enter to continue.") + val email = readLine() ?: "" + if (email.isBlank()) break + if (!knownEmails.contains(email)) newEmails.add(email) + } + } + + if (newEmails.isNotEmpty()) { + val user = User(emails = newEmails.map { UserEmail(it) } + .toHashSet()) + // TODO(anatoly): Post user/. + } + + // Warn user about need of confirmation. + if (user.emails.filter { email -> !email.verified }.isNotEmpty() || + newEmails.isNotEmpty()) { + println("Confirm your emails to show all statistics in " + + "profile.") + } + } + + override fun next() { + context.changeState(UpdateRepoState(context, api, configurator)) + } +} From b767fc9e989820a1f3954220ab8b7c1b88391970 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Sun, 19 Nov 2017 23:40:25 +0300 Subject: [PATCH 03/10] wip: edit configurator api call --- src/main/kotlin/app/hashers/RepoHasher.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index d38b3a85..96afbfbe 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -117,7 +117,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, } private fun isKnownRepo(): Boolean { - return configurator.getRepos() + return configurator.getUser().repos .find { it.rehash == serverRepo.rehash } != null } From b7be4d16e52b836d3aed1ca6a8fdb5a51791ffe3 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Sun, 19 Nov 2017 23:58:19 +0300 Subject: [PATCH 04/10] wip: edit filtering of emails --- src/main/kotlin/app/hashers/RepoHasher.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index 96afbfbe..432ca4b0 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -178,8 +178,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, } val knownEmails = hashSetOf() - knownEmails.add(localRepo.author.email) - knownEmails.add(serverRepo.userEmail) + knownEmails.addAll(configurator.getUser().emails.map { it.email }) knownEmails.addAll(serverRepo.emails) return knownEmails.filter { emails.contains(it) }.toHashSet() From aaf8a59e5ece54c22bac1eb21af47be461a69c92 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 00:08:29 +0300 Subject: [PATCH 05/10] chore: add todo --- src/main/kotlin/app/ui/EmailState.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/app/ui/EmailState.kt b/src/main/kotlin/app/ui/EmailState.kt index f0578572..5b651b7a 100644 --- a/src/main/kotlin/app/ui/EmailState.kt +++ b/src/main/kotlin/app/ui/EmailState.kt @@ -25,6 +25,7 @@ class EmailState constructor(private val context: Context, val knownEmails = user.emails.map { it.email } val newEmails = hashSetOf() val configEmails = hashSetOf() + // TODO(anatoly): Tell about web editing emails, when it's ready. // TODO(anatoly): Add global config parsing. // TODO(anatoly): Add user config parsing. From 2e27c6081418f7bc496020fd9dda6e958e7d1e41 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 00:50:56 +0300 Subject: [PATCH 06/10] wip: saving of emails --- src/main/kotlin/app/ui/EmailState.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/app/ui/EmailState.kt b/src/main/kotlin/app/ui/EmailState.kt index 5b651b7a..dc0ff64e 100644 --- a/src/main/kotlin/app/ui/EmailState.kt +++ b/src/main/kotlin/app/ui/EmailState.kt @@ -64,8 +64,11 @@ class EmailState constructor(private val context: Context, } if (newEmails.isNotEmpty()) { - val user = User(emails = newEmails.map { UserEmail(it) } - .toHashSet()) + val newUserEmails = newEmails.map { UserEmail(it) } + // We will need new emails during hashing. + user.emails.addAll(newUserEmails) + + val userNewEmails = User(emails = newUserEmails.toHashSet()) // TODO(anatoly): Post user/. } From ec228a219c95d59026f42eb428270052fcff0d55 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 01:15:12 +0300 Subject: [PATCH 07/10] wip: change of incremental protocol --- src/main/kotlin/app/api/Api.kt | 2 +- src/main/kotlin/app/api/MockApi.kt | 2 +- src/main/kotlin/app/api/ServerApi.kt | 11 +++++----- src/main/kotlin/app/hashers/RepoHasher.kt | 25 ++++++----------------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index b42f9a5b..cdbc5b2e 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -16,7 +16,7 @@ interface Api { fun authorize(): Result fun getUser(): Result - fun getRepo(repoRehash: String): Result + fun getRepo(repo: Repo): Result fun postRepo(repo: Repo): Result fun postCommits(commitsList: List): Result fun deleteCommits(commitsList: List): Result diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index 042e7aa5..ee93bf92 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -33,7 +33,7 @@ class MockApi( // GET requests. return Result(mockUser) } - override fun getRepo(repoRehash: String): Result { + override fun getRepo(repo: Repo): Result { Logger.debug { "MockApi: getRepo request" } return Result(mockRepo) } diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index a7a03d85..b2be251f 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -83,8 +83,9 @@ class ServerApi (private val configurator: Configurator) : Api { return get("/user") } - private fun createRequestGetRepo(repoRehash: String): Request { - return get("/repo/$repoRehash") + private fun createRequestGetRepo(repo: Repo): Request { + return get("/repo/${repo.rehash}").header(getContentTypeHeader()) + .body(repo.serialize()) } private fun createRequestPostRepo(repo: Repo): Request { @@ -154,12 +155,12 @@ class ServerApi (private val configurator: Configurator) : Api { { body -> User(body) }) } - override fun getRepo(repoRehash: String): Result { - if (repoRehash.isBlank()) { + override fun getRepo(repo: Repo): Result { + if (repo.rehash.isBlank()) { throw IllegalArgumentException() } - return makeRequest(createRequestGetRepo(repoRehash), "getRepo", + return makeRequest(createRequestGetRepo(repo), "getRepo", { body -> Repo(body) }) } diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index 432ca4b0..3707c8a9 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -38,26 +38,18 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, val (rehashes, emails) = fetchRehashesAndEmails(git) localRepo.parseGitConfig(git.repository.config) - if (localRepo.author.email.isBlank()) { - throw IllegalStateException("Can't load email from Git config") - } - initServerRepo(rehashes.last) Logger.debug { "Local repo path: ${localRepo.path}" } + Logger.debug { "Repo remote: ${localRepo.remoteOrigin}" } Logger.debug { "Repo rehash: ${serverRepo.rehash}" } - val filteredEmails = filterEmails(emails) - - if (!isKnownRepo()) { - // Notify server about new contributor and his email. - postRepoToServer() - } + // Get repo setup (commits, emails to hash) from server. + getRepoFromServer() // Send all repo emails for invites. postAuthorsToServer(emails) - // Get repo setup (commits, emails to hash) from server. - getRepoFromServer() + val filteredEmails = filterEmails(emails) // Common error handling for subscribers. // Exceptions can't be thrown out of reactive chain. @@ -116,15 +108,10 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, git.close() } - private fun isKnownRepo(): Boolean { - return configurator.getUser().repos - .find { it.rehash == serverRepo.rehash } != null - } - private fun getRepoFromServer() { - val repo = api.getRepo(serverRepo.rehash).getOrThrow() + val repo = api.getRepo(serverRepo).getOrThrow() serverRepo.commits = repo.commits - Logger.info{ + Logger.info { "Received repo from server with ${serverRepo.commits.size} commits" } Logger.debug { serverRepo.toString() } From ac67e5ed9c22669eb4a1208c223a3b8a0d56c5e6 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 02:02:32 +0300 Subject: [PATCH 08/10] feat: post user request --- src/main/kotlin/app/api/Api.kt | 1 + src/main/kotlin/app/api/MockApi.kt | 7 +++++++ src/main/kotlin/app/api/ServerApi.kt | 9 +++++++++ src/main/kotlin/app/ui/EmailState.kt | 3 ++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index cdbc5b2e..c96e2890 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -16,6 +16,7 @@ interface Api { fun authorize(): Result fun getUser(): Result + fun postUser(user: User): Result fun getRepo(repo: Repo): Result fun postRepo(repo: Repo): Result fun postCommits(commitsList: List): Result diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index ee93bf92..23b26a16 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -19,6 +19,7 @@ class MockApi( // GET requests. var receivedAddedCommits: MutableList = mutableListOf() var receivedFacts: MutableList = mutableListOf() var receivedAuthors: MutableList = mutableListOf() + var receivedUsers: MutableList = mutableListOf() // DELETE requests. var receivedDeletedCommits: MutableList = mutableListOf() @@ -33,6 +34,12 @@ class MockApi( // GET requests. return Result(mockUser) } + override fun postUser(user: User): Result { + Logger.debug { "MockApi: postUser request" } + receivedUsers.add(user) + return Result() + } + override fun getRepo(repo: Repo): Result { Logger.debug { "MockApi: getRepo request" } return Result(mockRepo) diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index b2be251f..cabdc0b2 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -83,6 +83,11 @@ class ServerApi (private val configurator: Configurator) : Api { return get("/user") } + private fun createRequestPostUser(user: User): Request { + return post("/user").header(getContentTypeHeader()) + .body(user.serialize()) + } + private fun createRequestGetRepo(repo: Repo): Request { return get("/repo/${repo.rehash}").header(getContentTypeHeader()) .body(repo.serialize()) @@ -155,6 +160,10 @@ class ServerApi (private val configurator: Configurator) : Api { { body -> User(body) }) } + override fun postUser(user: User): Result { + return makeRequest(createRequestPostUser(user), "postUser", {}) + } + override fun getRepo(repo: Repo): Result { if (repo.rehash.isBlank()) { throw IllegalArgumentException() diff --git a/src/main/kotlin/app/ui/EmailState.kt b/src/main/kotlin/app/ui/EmailState.kt index dc0ff64e..191afccc 100644 --- a/src/main/kotlin/app/ui/EmailState.kt +++ b/src/main/kotlin/app/ui/EmailState.kt @@ -68,8 +68,9 @@ class EmailState constructor(private val context: Context, // We will need new emails during hashing. user.emails.addAll(newUserEmails) + // Send new emails to server. val userNewEmails = User(emails = newUserEmails.toHashSet()) - // TODO(anatoly): Post user/. + api.postUser(userNewEmails) } // Warn user about need of confirmation. From 705f2c19fcb9d21b3131b398205075c16a60ee7c Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 20:25:19 +0300 Subject: [PATCH 09/10] feat: add complete route, change hashing protocol --- src/main/kotlin/app/api/Api.kt | 4 ++-- src/main/kotlin/app/api/MockApi.kt | 12 +++++++----- src/main/kotlin/app/api/ServerApi.kt | 21 ++++++++++----------- src/main/kotlin/app/hashers/RepoHasher.kt | 22 ++++++---------------- src/main/kotlin/app/model/Repo.kt | 2 -- src/main/kotlin/app/ui/EmailState.kt | 4 ++-- src/main/kotlin/app/ui/UpdateRepoState.kt | 1 + 7 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index c96e2890..ea33d98e 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -17,8 +17,8 @@ interface Api { fun authorize(): Result fun getUser(): Result fun postUser(user: User): Result - fun getRepo(repo: Repo): Result - fun postRepo(repo: Repo): Result + fun postRepo(repo: Repo): Result + fun postComplete(): Result fun postCommits(commitsList: List): Result fun deleteCommits(commitsList: List): Result fun postFacts(factsList: List): Result diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index 23b26a16..667d38ad 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -20,6 +20,7 @@ class MockApi( // GET requests. var receivedFacts: MutableList = mutableListOf() var receivedAuthors: MutableList = mutableListOf() var receivedUsers: MutableList = mutableListOf() + var receivedComplete: Int = 0 // DELETE requests. var receivedDeletedCommits: MutableList = mutableListOf() @@ -40,14 +41,15 @@ class MockApi( // GET requests. return Result() } - override fun getRepo(repo: Repo): Result { - Logger.debug { "MockApi: getRepo request" } + override fun postRepo(repo: Repo): Result { + Logger.debug { "MockApi: postRepo request" } + receivedRepos.add(repo) return Result(mockRepo) } - override fun postRepo(repo: Repo): Result { - Logger.debug { "MockApi: postRepo request ($repo)" } - receivedRepos.add(repo) + override fun postComplete(): Result { + Logger.debug { "MockApi: postComplete request " } + receivedComplete++ return Result() } diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index cabdc0b2..25622c7e 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -76,7 +76,7 @@ class ServerApi (private val configurator: Configurator) : Api { private fun createRequestGetToken(): Request { return post("/auth").authenticate(username, password) - .header(getVersionCodeHeader()) + .header(getVersionCodeHeader()) } private fun createRequestGetUser(): Request { @@ -88,16 +88,15 @@ class ServerApi (private val configurator: Configurator) : Api { .body(user.serialize()) } - private fun createRequestGetRepo(repo: Repo): Request { - return get("/repo/${repo.rehash}").header(getContentTypeHeader()) - .body(repo.serialize()) - } - private fun createRequestPostRepo(repo: Repo): Request { return post("/repo").header(getContentTypeHeader()) .body(repo.serialize()) } + private fun createRequestPostComplete(): Request { + return post("/complete").header(getContentTypeHeader()) + } + private fun createRequestPostCommits(commits: CommitGroup): Request { return post("/commits").header(getContentTypeHeader()) .body(commits.serialize()) @@ -164,18 +163,18 @@ class ServerApi (private val configurator: Configurator) : Api { return makeRequest(createRequestPostUser(user), "postUser", {}) } - override fun getRepo(repo: Repo): Result { + override fun postRepo(repo: Repo): Result { if (repo.rehash.isBlank()) { throw IllegalArgumentException() } - return makeRequest(createRequestGetRepo(repo), "getRepo", + return makeRequest(createRequestPostRepo(repo), "getRepo", { body -> Repo(body) }) } - override fun postRepo(repo: Repo): Result { - return makeRequest(createRequestPostRepo(repo), - "postRepo", {}) + override fun postComplete(): Result { + return makeRequest(createRequestPostComplete(), + "postComplete", {}) } override fun postCommits(commitsList: List): Result { diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index 3707c8a9..2f6b0f0b 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -44,7 +44,7 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, Logger.debug { "Repo rehash: ${serverRepo.rehash}" } // Get repo setup (commits, emails to hash) from server. - getRepoFromServer() + postRepoFromServer() // Send all repo emails for invites. postAuthorsToServer(emails) @@ -79,9 +79,6 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, onError(e) } - // Confirm hashing completion. - postRepoToServer() - if (errors.isNotEmpty()) { throw HashingException(errors) } @@ -108,8 +105,8 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, git.close() } - private fun getRepoFromServer() { - val repo = api.getRepo(serverRepo).getOrThrow() + private fun postRepoFromServer() { + val repo = api.postRepo(serverRepo).getOrThrow() serverRepo.commits = repo.commits Logger.info { "Received repo from server with ${serverRepo.commits.size} commits" @@ -117,12 +114,6 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, Logger.debug { serverRepo.toString() } } - private fun postRepoToServer() { - serverRepo.commits = listOf() - api.postRepo(serverRepo).onErrorThrow() - Logger.debug { serverRepo.toString() } - } - private fun postAuthorsToServer(emails: HashSet) { api.postAuthors(emails.map { email -> Author(email=email, repo=serverRepo) @@ -130,10 +121,9 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, } private fun initServerRepo(initCommitRehash: String) { - serverRepo = Repo(userEmail = localRepo.author.email) - serverRepo.initialCommitRehash = initCommitRehash - serverRepo.rehash = RepoHelper.calculateRepoRehash( - serverRepo.initialCommitRehash, localRepo) + serverRepo = Repo(initialCommitRehash = initCommitRehash, + rehash = RepoHelper.calculateRepoRehash( + initCommitRehash, localRepo)) } private fun fetchRehashesAndEmails(git: Git): diff --git a/src/main/kotlin/app/model/Repo.kt b/src/main/kotlin/app/model/Repo.kt index d0b60c08..b609d23b 100644 --- a/src/main/kotlin/app/model/Repo.kt +++ b/src/main/kotlin/app/model/Repo.kt @@ -15,8 +15,6 @@ data class Repo( var rehash: String = "", var initialCommitRehash: String = "", - var userEmail: String = "", - // Authors' email filter for hashed commits. If empty list then hash // only commits that created by current user. var emails: List = listOf(), diff --git a/src/main/kotlin/app/ui/EmailState.kt b/src/main/kotlin/app/ui/EmailState.kt index 191afccc..02dee5de 100644 --- a/src/main/kotlin/app/ui/EmailState.kt +++ b/src/main/kotlin/app/ui/EmailState.kt @@ -44,9 +44,9 @@ class EmailState constructor(private val context: Context, } if (configEmails.isNotEmpty()) { - println("Your git configs contains untracked emails:") + println("Your git config contains untracked emails:") configEmails.forEach { email -> println(email) } - if (UiHelper.confirm("Do you want to add this emails to your" + + if (UiHelper.confirm("Do you want to add this emails to your " + "account?", defaultIsYes = true)) { newEmails.addAll(configEmails) } diff --git a/src/main/kotlin/app/ui/UpdateRepoState.kt b/src/main/kotlin/app/ui/UpdateRepoState.kt index d0d3d96a..28b52f1c 100644 --- a/src/main/kotlin/app/ui/UpdateRepoState.kt +++ b/src/main/kotlin/app/ui/UpdateRepoState.kt @@ -32,6 +32,7 @@ class UpdateRepoState constructor(private val context: Context, } } + api.postComplete().onErrorThrow() println("The repositories have been hashed. See result online on your " + "Sourcerer profile.") Logger.info(Logger.Events.HASHING_SUCCESS) { "Hashing success" } From 1d011843cce83cf56ee81025c92dc54602c33061 Mon Sep 17 00:00:00 2001 From: Anatoly Kislov Date: Mon, 20 Nov 2017 20:48:44 +0300 Subject: [PATCH 10/10] fix: codelongevitytest incremental hashing from previous runs --- src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt b/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt index 50cda460..a9d00f0a 100644 --- a/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt +++ b/src/test/kotlin/test/tests/hashers/CodeLongevityTest.kt @@ -60,6 +60,8 @@ class CodeLongevityTest : Spek({ assertEquals(isDeleted, actualLine.isDeleted, "'$lineText' line is deleted") } + Runtime.getRuntime().exec("rm -r ./.sourcerer/longevity").waitFor() + given("'line collecting #1'") { val testRepoPath = "../CodeLongevity_lc1" val testRepo = TestRepo(testRepoPath)