Commit 5c7aeb4f authored by Eugene Shapovalov's avatar Eugene Shapovalov 💬

Fixed bug associated with getting not full Issue/MergeRequest notes.

parent 9a7a7292
package ru.terrakok.gitlabclient.entity
import com.google.gson.annotations.SerializedName
data class Discussion(
@SerializedName("id") val id: String,
@SerializedName("individual_note") val isIndividualNote: Boolean,
@SerializedName("notes") val notes: List<Note>
)
\ No newline at end of file
......@@ -3,8 +3,21 @@ package ru.terrakok.gitlabclient.model.data.server
import io.reactivex.Completable
import io.reactivex.Single
import org.threeten.bp.LocalDateTime
import retrofit2.http.*
import ru.terrakok.gitlabclient.entity.*
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query
import ru.terrakok.gitlabclient.entity.Discussion
import ru.terrakok.gitlabclient.entity.File
import ru.terrakok.gitlabclient.entity.OrderBy
import ru.terrakok.gitlabclient.entity.Project
import ru.terrakok.gitlabclient.entity.RepositoryTreeNode
import ru.terrakok.gitlabclient.entity.Sort
import ru.terrakok.gitlabclient.entity.TokenData
import ru.terrakok.gitlabclient.entity.User
import ru.terrakok.gitlabclient.entity.Visibility
import ru.terrakok.gitlabclient.entity.event.Event
import ru.terrakok.gitlabclient.entity.event.EventAction
import ru.terrakok.gitlabclient.entity.event.EventTarget
......@@ -24,6 +37,7 @@ import ru.terrakok.gitlabclient.entity.todo.TodoState
* @author Konstantin Tskhovrebov (aka terrakok). Date: 28.03.17
*/
interface GitlabApi {
companion object {
const val API_PATH = "api/v4"
}
......@@ -31,47 +45,47 @@ interface GitlabApi {
@FormUrlEncoded
@POST("oauth/token")
fun auth(
@Field("client_id") appId: String,
@Field("client_secret") appKey: String,
@Field("code") code: String,
@Field("redirect_uri") redirectUri: String,
@Field("grant_type") type: String = "authorization_code"
@Field("client_id") appId: String,
@Field("client_secret") appKey: String,
@Field("code") code: String,
@Field("redirect_uri") redirectUri: String,
@Field("grant_type") type: String = "authorization_code"
): Single<TokenData>
@GET("$API_PATH/projects")
fun getProjects(
@Query("archived") archived: Boolean?,
@Query("visibility") visibility: Visibility?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("search") search: String?,
@Query("simple") simple: Boolean?,
@Query("owned") owned: Boolean?,
@Query("membership") membership: Boolean?,
@Query("starred") starred: Boolean?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Query("archived") archived: Boolean?,
@Query("visibility") visibility: Visibility?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("search") search: String?,
@Query("simple") simple: Boolean?,
@Query("owned") owned: Boolean?,
@Query("membership") membership: Boolean?,
@Query("starred") starred: Boolean?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<Project>>
@GET("$API_PATH/projects/{id}")
fun getProject(
@Path("id") id: Long,
@Query("statistics") statistics: Boolean = true
@Path("id") id: Long,
@Query("statistics") statistics: Boolean = true
): Single<Project>
@GET("$API_PATH/projects/{id}/repository/files/{file_path}")
fun getFile(
@Path("id") id: Long,
@Path("file_path") filePath: String,
@Query("ref") branchName: String
@Path("id") id: Long,
@Path("file_path") filePath: String,
@Query("ref") branchName: String
): Single<File>
@GET("$API_PATH/projects/{id}/repository/tree")
fun getRepositoryTree(
@Path("id") id: Long,
@Query("path") path: String?,
@Query("ref") branchName: String?,
@Query("recursive") recursive: Boolean?
@Path("id") id: Long,
@Query("path") path: String?,
@Query("ref") branchName: String?,
@Query("recursive") recursive: Boolean?
): Single<List<RepositoryTreeNode>>
@GET("$API_PATH/user")
......@@ -79,115 +93,111 @@ interface GitlabApi {
@GET("$API_PATH/issues")
fun getMyIssues(
@Query("scope") scope: IssueScope?,
@Query("state") state: IssueState?,
@Query("labels") labels: String?,
@Query("milestone") milestone: String?,
@Query("iids") iids: Array<Long>?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("search") search: String?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Query("scope") scope: IssueScope?,
@Query("state") state: IssueState?,
@Query("labels") labels: String?,
@Query("milestone") milestone: String?,
@Query("iids") iids: Array<Long>?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("search") search: String?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<Issue>>
@GET("$API_PATH/projects/{project_id}/issues/{issue_id}")
fun getIssue(
@Path("project_id") projectId: Long,
@Path("issue_id") issueId: Long
@Path("project_id") projectId: Long,
@Path("issue_id") issueId: Long
): Single<Issue>
@GET("$API_PATH/events")
fun getEvents(
@Query("action") action: EventAction?,
@Query("target_type") targetType: EventTarget?,
@Query("before") beforeDay: String?,
@Query("after") afterDay: String?,
@Query("sort") sort: Sort?,
@Query("order_by") orderBy: OrderBy?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Query("action") action: EventAction?,
@Query("target_type") targetType: EventTarget?,
@Query("before") beforeDay: String?,
@Query("after") afterDay: String?,
@Query("sort") sort: Sort?,
@Query("order_by") orderBy: OrderBy?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<Event>>
@GET("$API_PATH/merge_requests")
fun getMergeRequests(
@Query("state") state: MergeRequestState?,
@Query("milestone") milestone: String?,
@Query("view") viewType: MergeRequestViewType?,
@Query("labels") labels: String?,
@Query("created_before") createdBefore: LocalDateTime?,
@Query("created_after") createdAfter: LocalDateTime?,
@Query("scope") scope: MergeRequestScope?,
@Query("author_id") authorId: Int?,
@Query("assignee_id") assigneeId: Int?,
@Query("my_reaction_emoji") meReactionEmoji: String?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Query("state") state: MergeRequestState?,
@Query("milestone") milestone: String?,
@Query("view") viewType: MergeRequestViewType?,
@Query("labels") labels: String?,
@Query("created_before") createdBefore: LocalDateTime?,
@Query("created_after") createdAfter: LocalDateTime?,
@Query("scope") scope: MergeRequestScope?,
@Query("author_id") authorId: Int?,
@Query("assignee_id") assigneeId: Int?,
@Query("my_reaction_emoji") meReactionEmoji: String?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<MergeRequest>>
fun getProjectMergeRequests(
@Path("project_id") projectId: Long,
@Query("state") state: MergeRequestState?,
@Query("milestone") milestone: String?,
@Query("view") viewType: MergeRequestViewType?,
@Query("labels") labels: String?,
@Query("created_before") createdBefore: LocalDateTime?,
@Query("created_after") createdAfter: LocalDateTime?,
@Query("scope") scope: MergeRequestScope?,
@Query("author_id") authorId: Int?,
@Query("assignee_id") assigneeId: Int?,
@Query("my_reaction_emoji") meReactionEmoji: String?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Path("project_id") projectId: Long,
@Query("state") state: MergeRequestState?,
@Query("milestone") milestone: String?,
@Query("view") viewType: MergeRequestViewType?,
@Query("labels") labels: String?,
@Query("created_before") createdBefore: LocalDateTime?,
@Query("created_after") createdAfter: LocalDateTime?,
@Query("scope") scope: MergeRequestScope?,
@Query("author_id") authorId: Int?,
@Query("assignee_id") assigneeId: Int?,
@Query("my_reaction_emoji") meReactionEmoji: String?,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<MergeRequest>>
@GET("$API_PATH/projects/{project_id}/merge_requests/{merge_request_id}")
fun getMergeRequest(
@Path("project_id") projectId: Long,
@Path("merge_request_id") mergeRequestId: Long
@Path("project_id") projectId: Long,
@Path("merge_request_id") mergeRequestId: Long
): Single<MergeRequest>
@GET("$API_PATH/users/{user_id}")
fun getUser(
@Path("user_id") userId: Long
@Path("user_id") userId: Long
): Single<User>
@GET("$API_PATH/todos")
fun getTodos(
@Query("action") action: TodoAction?,
@Query("author_id") authorId: Long?,
@Query("project_id") projectId: Long?,
@Query("state") state: TodoState?,
@Query("type") targetType: TargetType?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
@Query("action") action: TodoAction?,
@Query("author_id") authorId: Long?,
@Query("project_id") projectId: Long?,
@Query("state") state: TodoState?,
@Query("type") targetType: TargetType?,
@Query("page") page: Int,
@Query("per_page") pageSize: Int
): Single<List<Todo>>
@POST("$API_PATH/todos/{id}/mark_as_done")
fun markPendingTodoAsDone(
@Path("id") id: Int
@Path("id") id: Int
): Single<Todo>
@POST("$API_PATH/todos/mark_as_done")
fun markAllPendingTodosAsDone(): Completable
@GET("$API_PATH/projects/{project_id}/issues/{issue_id}/notes")
fun getIssueNotes(
@Path("project_id") projectId: Long,
@Path("issue_id") issueId: Long,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?
): Single<List<Note>>
@GET("$API_PATH/projects/{project_id}/merge_requests/{merge_request_id}/notes")
fun getMergeRequestNotes(
@Path("project_id") projectId: Long,
@Path("merge_request_id") mergeRequestId: Long,
@Query("order_by") orderBy: OrderBy?,
@Query("sort") sort: Sort?
): Single<List<Note>>
@GET("$API_PATH/projects/{project_id}/issues/{issue_id}/discussions")
fun getIssueDiscussions(
@Path("project_id") projectId: Long,
@Path("issue_id") issueId: Long
): Single<List<Discussion>>
@GET("$API_PATH/projects/{project_id}/merge_requests/{merge_request_id}/discussions")
fun getMergeRequestDiscussions(
@Path("project_id") projectId: Long,
@Path("merge_request_id") mergeRequestId: Long
): Single<List<Discussion>>
}
\ No newline at end of file
......@@ -6,7 +6,14 @@ import io.reactivex.functions.BiFunction
import ru.terrakok.gitlabclient.entity.OrderBy
import ru.terrakok.gitlabclient.entity.Project
import ru.terrakok.gitlabclient.entity.Sort
import ru.terrakok.gitlabclient.entity.app.target.*
import ru.terrakok.gitlabclient.entity.app.target.AppTarget
import ru.terrakok.gitlabclient.entity.app.target.TargetBadge
import ru.terrakok.gitlabclient.entity.app.target.TargetBadgeIcon
import ru.terrakok.gitlabclient.entity.app.target.TargetBadgeStatus
import ru.terrakok.gitlabclient.entity.app.target.TargetHeader
import ru.terrakok.gitlabclient.entity.app.target.TargetHeaderIcon
import ru.terrakok.gitlabclient.entity.app.target.TargetHeaderTitle
import ru.terrakok.gitlabclient.entity.app.target.TargetInternal
import ru.terrakok.gitlabclient.entity.event.EventAction
import ru.terrakok.gitlabclient.entity.issue.Issue
import ru.terrakok.gitlabclient.entity.issue.IssueScope
......@@ -21,32 +28,44 @@ import javax.inject.Inject
* @author Konstantin Tskhovrebov (aka terrakok) on 14.06.17.
*/
class IssueRepository @Inject constructor(
private val api: GitlabApi,
private val schedulers: SchedulersProvider,
@DefaultPageSize private val defaultPageSizeWrapper: PrimitiveWrapper<Int>
private val api: GitlabApi,
private val schedulers: SchedulersProvider,
@DefaultPageSize private val defaultPageSizeWrapper: PrimitiveWrapper<Int>
) {
private val defaultPageSize = defaultPageSizeWrapper.value
fun getMyIssues(
scope: IssueScope? = null,
state: IssueState? = null,
labels: String? = null,
milestone: String? = null,
iids: Array<Long>? = null,
orderBy: OrderBy? = null,
sort: Sort? = null,
search: String? = null,
page: Int,
pageSize: Int = defaultPageSize
scope: IssueScope? = null,
state: IssueState? = null,
labels: String? = null,
milestone: String? = null,
iids: Array<Long>? = null,
orderBy: OrderBy? = null,
sort: Sort? = null,
search: String? = null,
page: Int,
pageSize: Int = defaultPageSize
) = api
.getMyIssues(scope, state, labels, milestone, iids, orderBy, sort, search, page, pageSize)
.getMyIssues(
scope,
state,
labels,
milestone,
iids,
orderBy,
sort,
search,
page,
pageSize
)
.flatMap { issues ->
Single.zip(
Single.just(issues),
getDistinctProjects(issues),
BiFunction<List<Issue>, Map<Long, Project>, List<TargetHeader>> { sourceIssues, projects ->
sourceIssues.map { getTargetHeader(it, projects[it.projectId]!!) }
}
Single.just(issues),
getDistinctProjects(issues),
BiFunction<List<Issue>, Map<Long, Project>, List<TargetHeader>> { sourceIssues, projects ->
sourceIssues.map { getTargetHeader(it, projects[it.projectId]!!) }
}
)
}
.subscribeOn(schedulers.io())
......@@ -61,10 +80,14 @@ class IssueRepository @Inject constructor(
private fun getTargetHeader(issue: Issue, project: Project): TargetHeader {
val badges = mutableListOf<TargetBadge>()
badges.add(TargetBadge.Status(when(issue.state) {
IssueState.OPENED -> TargetBadgeStatus.OPENED
IssueState.CLOSED -> TargetBadgeStatus.CLOSED
}))
badges.add(
TargetBadge.Status(
when (issue.state) {
IssueState.OPENED -> TargetBadgeStatus.OPENED
IssueState.CLOSED -> TargetBadgeStatus.CLOSED
}
)
)
badges.add(TargetBadge.Text(project.name, AppTarget.PROJECT, project.id))
badges.add(TargetBadge.Text(issue.author.username, AppTarget.USER, issue.author.id))
badges.add(TargetBadge.Icon(TargetBadgeIcon.COMMENTS, issue.userNotesCount))
......@@ -73,38 +96,39 @@ class IssueRepository @Inject constructor(
issue.labels.forEach { label -> badges.add(TargetBadge.Text(label)) }
return TargetHeader(
issue.author,
TargetHeaderIcon.NONE,
TargetHeaderTitle.Event(
issue.author.name,
EventAction.CREATED,
"${AppTarget.ISSUE} #${issue.iid}",
project.name
),
issue.title ?: "",
issue.createdAt,
AppTarget.ISSUE,
issue.id,
TargetInternal(issue.projectId, issue.iid),
badges
issue.author,
TargetHeaderIcon.NONE,
TargetHeaderTitle.Event(
issue.author.name,
EventAction.CREATED,
"${AppTarget.ISSUE} #${issue.iid}",
project.name
),
issue.title ?: "",
issue.createdAt,
AppTarget.ISSUE,
issue.id,
TargetInternal(issue.projectId, issue.iid),
badges
)
}
fun getIssue(
projectId: Long,
issueId: Long
projectId: Long,
issueId: Long
) = api
.getIssue(projectId, issueId)
.subscribeOn(schedulers.io())
.observeOn(schedulers.ui())
fun getIssueNotes(
projectId: Long,
issueId: Long,
orderBy: OrderBy? = null,
sort: Sort? = Sort.ASC
projectId: Long,
issueId: Long
) = api
.getIssueNotes(projectId, issueId, orderBy, sort)
.getIssueDiscussions(projectId, issueId)
.flattenAsObservable { it }
.concatMap { discussion -> Observable.fromIterable(discussion.notes) }
.toList()
.subscribeOn(schedulers.io())
.observeOn(schedulers.ui())
}
\ No newline at end of file
......@@ -7,7 +7,14 @@ import org.threeten.bp.LocalDateTime
import ru.terrakok.gitlabclient.entity.OrderBy
import ru.terrakok.gitlabclient.entity.Project
import ru.terrakok.gitlabclient.entity.Sort
import ru.terrakok.gitlabclient.entity.app.target.*
import ru.terrakok.gitlabclient.entity.app.target.AppTarget
import ru.terrakok.gitlabclient.entity.app.target.TargetBadge
import ru.terrakok.gitlabclient.entity.app.target.TargetBadgeIcon
import ru.terrakok.gitlabclient.entity.app.target.TargetBadgeStatus
import ru.terrakok.gitlabclient.entity.app.target.TargetHeader
import ru.terrakok.gitlabclient.entity.app.target.TargetHeaderIcon
import ru.terrakok.gitlabclient.entity.app.target.TargetHeaderTitle
import ru.terrakok.gitlabclient.entity.app.target.TargetInternal
import ru.terrakok.gitlabclient.entity.event.EventAction
import ru.terrakok.gitlabclient.entity.mergerequest.MergeRequest
import ru.terrakok.gitlabclient.entity.mergerequest.MergeRequestScope
......@@ -20,39 +27,40 @@ import ru.terrakok.gitlabclient.toothpick.qualifier.DefaultPageSize
import javax.inject.Inject
class MergeRequestRepository @Inject constructor(
private val api: GitlabApi,
private val schedulers: SchedulersProvider,
@DefaultPageSize private val defaultPageSizeWrapper: PrimitiveWrapper<Int>
private val api: GitlabApi,
private val schedulers: SchedulersProvider,
@DefaultPageSize private val defaultPageSizeWrapper: PrimitiveWrapper<Int>
) {
private val defaultPageSize = defaultPageSizeWrapper.value
fun getMergeRequests(
state: MergeRequestState? = null,
milestone: String? = null,
viewType: MergeRequestViewType? = null,
labels: String? = null,
createdBefore: LocalDateTime? = null,
createdAfter: LocalDateTime? = null,
scope: MergeRequestScope? = null,
authorId: Int? = null,
assigneeId: Int? = null,
meReactionEmoji: String? = null,
orderBy: OrderBy? = null,
sort: Sort? = null,
page: Int,
pageSize: Int = defaultPageSize
state: MergeRequestState? = null,
milestone: String? = null,
viewType: MergeRequestViewType? = null,
labels: String? = null,
createdBefore: LocalDateTime? = null,
createdAfter: LocalDateTime? = null,
scope: MergeRequestScope? = null,
authorId: Int? = null,
assigneeId: Int? = null,
meReactionEmoji: String? = null,
orderBy: OrderBy? = null,
sort: Sort? = null,
page: Int,
pageSize: Int = defaultPageSize
) = api
.getMergeRequests(
state, milestone, viewType, labels, createdBefore, createdAfter, scope,
authorId, assigneeId, meReactionEmoji, orderBy, sort, page, pageSize
state, milestone, viewType, labels, createdBefore, createdAfter, scope,
authorId, assigneeId, meReactionEmoji, orderBy, sort, page, pageSize
)
.flatMap { mrs ->
Single.zip(
Single.just(mrs),
getDistinctProjects(mrs),
BiFunction<List<MergeRequest>, Map<Long, Project>, List<TargetHeader>> { sourceMrs, projects ->
sourceMrs.map { getTargetHeader(it, projects[it.projectId]!!) }
}
Single.just(mrs),
getDistinctProjects(mrs),
BiFunction<List<MergeRequest>, Map<Long, Project>, List<TargetHeader>> { sourceMrs, projects ->
sourceMrs.map { getTargetHeader(it, projects[it.projectId]!!) }
}
)
}
.subscribeOn(schedulers.io())
......@@ -67,11 +75,15 @@ class MergeRequestRepository @Inject constructor(
private fun getTargetHeader(mr: MergeRequest, project: Project): TargetHeader {
val badges = mutableListOf<TargetBadge>()
badges.add(TargetBadge.Status(when(mr.state) {
MergeRequestState.OPENED -> TargetBadgeStatus.OPENED
MergeRequestState.CLOSED -> TargetBadgeStatus.CLOSED
MergeRequestState.MERGED -> TargetBadgeStatus.MERGED
}))
badges.add(
TargetBadge.Status(
when (mr.state) {
MergeRequestState.OPENED -> TargetBadgeStatus.OPENED
MergeRequestState.CLOSED -> TargetBadgeStatus.CLOSED
MergeRequestState.MERGED -> TargetBadgeStatus.MERGED
}
)
)
badges.add(TargetBadge.Text(project.name, AppTarget.PROJECT, project.id))
badges.add(TargetBadge.Text(mr.author.username, AppTarget.USER, mr.author.id))
badges.add(TargetBadge.Icon(TargetBadgeIcon.COMMENTS, mr.userNotesCount))
......@@ -80,38 +92,39 @@ class MergeRequestRepository @Inject constructor(
mr.labels.forEach { label -> badges.add(TargetBadge.Text(label)) }
return TargetHeader(
mr.author,
TargetHeaderIcon.NONE,
TargetHeaderTitle.Event(
mr.author.name,
EventAction.CREATED,
"${AppTarget.MERGE_REQUEST} !${mr.iid}",
project.name
),
mr.title ?: "",
mr.createdAt,
AppTarget.MERGE_REQUEST,
mr.id,
TargetInternal(mr.projectId, mr.iid),
badges
mr.author,
TargetHeaderIcon.NONE,
TargetHeaderTitle.Event(
mr.author.name,
EventAction.CREATED,
"${AppTarget.MERGE_REQUEST} !${mr.iid}",
project.name
),
mr.title ?: "",
mr.createdAt,
AppTarget.MERGE_REQUEST,
mr.id,
TargetInternal(mr.projectId, mr.iid),
badges
)
}
fun getMergeRequest(
projectId: Long,
mergeRequestId: Long
projectId: Long,
mergeRequestId: Long
) = api
.getMergeRequest(projectId, mergeRequestId)
.subscribeOn(schedulers.io())
.observeOn(schedulers.ui())
fun getMergeRequestNotes(
projectId: Long,
mergeRequestId: Long,
orderBy: OrderBy? = null,
sort: Sort? = Sort.ASC
projectId: Long,
mergeRequestId: Long
) = api
.getMergeRequestNotes(projectId, mergeRequestId, orderBy, sort)
.getMergeRequestDiscussions(projectId, mergeRequestId)
.flattenAsObservable { it }
.concatMap { discussion -> Observable.fromIterable(discussion.notes) }
.toList()
.subscribeOn(schedulers.io())
.observeOn(schedulers.ui())
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment