diff --git a/src/main/kotlin/app/api/Api.kt b/src/main/kotlin/app/api/Api.kt index a2a5658e..b42f9a5b 100644 --- a/src/main/kotlin/app/api/Api.kt +++ b/src/main/kotlin/app/api/Api.kt @@ -3,6 +3,7 @@ package app.api +import app.model.Author import app.model.Commit import app.model.Fact import app.model.Repo @@ -20,4 +21,5 @@ interface Api { fun postCommits(commitsList: List): Result fun deleteCommits(commitsList: List): Result fun postFacts(factsList: List): Result + fun postAuthors(authorsList: List): Result } diff --git a/src/main/kotlin/app/api/ApiError.kt b/src/main/kotlin/app/api/ApiError.kt index 981f1d5b..1093cf1e 100644 --- a/src/main/kotlin/app/api/ApiError.kt +++ b/src/main/kotlin/app/api/ApiError.kt @@ -30,9 +30,9 @@ class ApiError(exception: Exception) : Exception(exception.message) { get() = AUTH_ERROR_CODES.contains(httpStatusCode) constructor(fuelError: FuelError) : this(fuelError as Exception) { - httpStatusCode = fuelError.response.httpStatusCode - httpResponseMessage = fuelError.response.httpResponseMessage - if (fuelError.response.httpResponseHeaders["Content-Type"] + httpStatusCode = fuelError.response.statusCode + httpResponseMessage = fuelError.response.responseMessage + if (fuelError.response.headers["Content-Type"] ?.contains("application/octet-stream") == true) { try { serverErrors = Errors(fuelError.response.data).errors diff --git a/src/main/kotlin/app/api/MockApi.kt b/src/main/kotlin/app/api/MockApi.kt index c08688ec..042e7aa5 100644 --- a/src/main/kotlin/app/api/MockApi.kt +++ b/src/main/kotlin/app/api/MockApi.kt @@ -4,6 +4,7 @@ package app.api import app.Logger +import app.model.Author import app.model.Commit import app.model.Repo import app.model.Fact @@ -17,6 +18,7 @@ class MockApi( // GET requests. var receivedRepos: MutableList = mutableListOf() var receivedAddedCommits: MutableList = mutableListOf() var receivedFacts: MutableList = mutableListOf() + var receivedAuthors: MutableList = mutableListOf() // DELETE requests. var receivedDeletedCommits: MutableList = mutableListOf() @@ -58,8 +60,15 @@ class MockApi( // GET requests. } override fun postFacts(factsList: List): Result { - Logger.debug { "MockApi: postStats request (${factsList.size} stats)" } + Logger.debug { "MockApi: postFacts request (${factsList.size} facts)" } receivedFacts.addAll(factsList) return Result() } + + override fun postAuthors(authorsList: List): Result { + Logger.debug { "MockApi: postAuthors request (${authorsList.size} " + + "stats)" } + receivedAuthors.addAll(authorsList) + return Result() + } } diff --git a/src/main/kotlin/app/api/ServerApi.kt b/src/main/kotlin/app/api/ServerApi.kt index f475c6a4..a7a03d85 100644 --- a/src/main/kotlin/app/api/ServerApi.kt +++ b/src/main/kotlin/app/api/ServerApi.kt @@ -6,6 +6,8 @@ package app.api import app.BuildConfig import app.Logger import app.config.Configurator +import app.model.Author +import app.model.AuthorGroup import app.model.Commit import app.model.CommitGroup import app.model.Fact @@ -105,6 +107,11 @@ class ServerApi (private val configurator: Configurator) : Api { .body(facts.serialize()) } + private fun createRequestPostAuthors(authors: AuthorGroup): Request { + return post("/authors").header(getContentTypeHeader()) + .body(authors.serialize()) + } + private fun makeRequest(request: Request, requestName: String, parser: (ByteArray) -> T): Result { @@ -177,4 +184,9 @@ class ServerApi (private val configurator: Configurator) : Api { val facts = FactGroup(factsList) return makeRequest(createRequestPostFacts(facts), "postFacts", {}) } + + override fun postAuthors(authorsList: List): Result { + val authors = AuthorGroup(authorsList) + return makeRequest(createRequestPostAuthors(authors), "postAuthors", {}) + } } diff --git a/src/main/kotlin/app/hashers/RepoHasher.kt b/src/main/kotlin/app/hashers/RepoHasher.kt index 069a6aa1..7e4c71b7 100644 --- a/src/main/kotlin/app/hashers/RepoHasher.kt +++ b/src/main/kotlin/app/hashers/RepoHasher.kt @@ -6,6 +6,7 @@ package app.hashers import app.Logger import app.api.Api import app.config.Configurator +import app.model.Author import app.model.LocalRepo import app.model.Repo import app.utils.HashingException @@ -51,6 +52,9 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, // Notify server about new contributor and his email. postRepoToServer() } + + postAuthorsToServer(filteredEmails) + // Get repo setup (commits, emails to hash) from server. getRepoFromServer() @@ -130,6 +134,12 @@ class RepoHasher(private val localRepo: LocalRepo, private val api: Api, Logger.debug { serverRepo.toString() } } + private fun postAuthorsToServer(emails: HashSet) { + api.postAuthors(emails.map { email -> + Author(email=email, repo=serverRepo) + }).onErrorThrow() + } + private fun initServerRepo(initCommitRehash: String) { serverRepo = Repo(userEmail = localRepo.author.email) serverRepo.initialCommitRehash = initCommitRehash diff --git a/src/main/kotlin/app/model/Author.kt b/src/main/kotlin/app/model/Author.kt index 6f690f53..f302cc11 100644 --- a/src/main/kotlin/app/model/Author.kt +++ b/src/main/kotlin/app/model/Author.kt @@ -3,10 +3,40 @@ package app.model +import app.Protos +import com.google.protobuf.InvalidProtocolBufferException +import java.security.InvalidParameterException + /** * Commit author. */ -data class Author(var name: String = "", var email: String = "") { +data class Author( + var name: String = "", + var email: String = "", + var repo: Repo = Repo() +) { + @Throws(InvalidParameterException::class) + constructor(proto: Protos.Author) : this() { + email = proto.email + repo = Repo(proto.repoRehash) + } + + @Throws(InvalidProtocolBufferException::class) + constructor(bytes: ByteArray) : this(Protos.Author.parseFrom(bytes)) + + constructor(serialized: String) : this(serialized.toByteArray()) + + fun getProto(): Protos.Author { + return Protos.Author.newBuilder() + .setEmail(email) + .setRepoRehash(repo.rehash) + .build() + } + + fun serialize(): ByteArray { + return getProto().toByteArray() + } + // Email defines user identity. override fun equals(other: Any?): Boolean { if (other is Author) { diff --git a/src/main/kotlin/app/model/AuthorGroup.kt b/src/main/kotlin/app/model/AuthorGroup.kt new file mode 100644 index 00000000..bf252d78 --- /dev/null +++ b/src/main/kotlin/app/model/AuthorGroup.kt @@ -0,0 +1,32 @@ +package app.model + +import app.Protos +import com.google.protobuf.InvalidProtocolBufferException +import java.security.InvalidParameterException + +/** + * Group of commit authors. + */ +data class AuthorGroup( + var authors: List = listOf() +) { + @Throws(InvalidParameterException::class) + constructor(proto: Protos.AuthorGroup) : this() { + authors = proto.authorsList.map { it -> Author(it) } + } + + @Throws(InvalidProtocolBufferException::class) + constructor(bytes: ByteArray) : this(Protos.AuthorGroup.parseFrom(bytes)) + + constructor(serialized: String) : this(serialized.toByteArray()) + + fun getProto(): Protos.AuthorGroup { + return Protos.AuthorGroup.newBuilder() + .addAllAuthors(authors.map { it -> it.getProto() }) + .build() + } + + fun serialize(): ByteArray { + return getProto().toByteArray() + } +} diff --git a/src/main/proto/sourcerer.proto b/src/main/proto/sourcerer.proto index f30a9c9a..f3d11913 100644 --- a/src/main/proto/sourcerer.proto +++ b/src/main/proto/sourcerer.proto @@ -72,6 +72,16 @@ message FactGroup { repeated Fact facts = 1; } +// Used to authors for invitational procedures. +message Author { + string email = 1; + string repo_rehash = 2; +} + +message AuthorGroup { + repeated Author authors = 1; +} + // User properties and indentity information about repos. message User { // List of known repos containing basic information for indentifying repo.