Skip to content
Snippets Groups Projects
Commit cbd7ebc0 authored by John Carlson's avatar John Carlson
Browse files

Merge branch 'develop'

parents 35eba923 e31b881c
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing
with 222 additions and 192 deletions
package com.commit451.gitlab.api
 
import android.net.Uri
import com.bluelinelabs.logansquare.LoganSquare
import com.commit451.gitlab.api.converter.UriTypeConverter
import com.commit451.gitlab.model.Account
import com.squareup.moshi.Moshi
import okhttp3.OkHttpClient
 
/**
* Provides access to all the GitLab things. Wraps RSS and the Retrofit service, in
* case we need to do overrides or global
*/
class GitLab(gitLabService: GitLabService, gitLabRss: GitLabRss): GitLabService by gitLabService,
class GitLab private constructor(val account: Account, val client: OkHttpClient, gitLabService: GitLabService, gitLabRss: GitLabRss): GitLabService by gitLabService,
GitLabRss by gitLabRss {
 
companion object {
fun init() {
/**
* Register our type converters on our singleton LoganSquare get. Needs to be set here
* since we are fetching accounts immediately with LoganSquare
*/
LoganSquare.registerTypeConverter(Uri::class.java, UriTypeConverter())
lateinit var moshi: Moshi
class Builder(private val account: Account) {
private var clientBuilder: OkHttpClient.Builder? = null
fun clientBuilder(clientBuilder: OkHttpClient.Builder): Builder {
this.clientBuilder = clientBuilder
return this
}
}
 
fun build(): GitLab {
var clientBuilder = clientBuilder
if (clientBuilder == null) {
clientBuilder = OkHttpClient.Builder()
}
val client = clientBuilder.build()
val gitLabService = GitLabFactory.create(account, client)
val gitLab = GitLab(account, client, gitLabService, GitLabRssFactory.create(account, client))
return gitLab
}
}
}
\ No newline at end of file
package com.commit451.gitlab.api
 
import android.support.annotation.VisibleForTesting
import com.commit451.gitlab.model.Account
import com.github.aurae.retrofit2.LoganSquareConverterFactory
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
 
/**
Loading
Loading
@@ -13,6 +12,12 @@ import retrofit2.converter.scalars.ScalarsConverterFactory
*/
object GitLabFactory {
 
fun createGitLab(account: Account, clientBuilder: OkHttpClient.Builder): GitLab {
return GitLab.Builder(account)
.clientBuilder(clientBuilder)
.build()
}
/**
* Create a GitLabService get with the current account passed.
* @param account the account to try and log in with
Loading
Loading
@@ -20,22 +25,13 @@ object GitLabFactory {
* @return the GitLabService configured client
*/
fun create(account: Account, client: OkHttpClient): GitLabService {
return create(account, client, false)
}
@VisibleForTesting
fun create(account: Account, client: OkHttpClient, dummyExecutor: Boolean): GitLabService {
val retrofitBuilder = Retrofit.Builder()
.baseUrl(account.serverUrl.toString())
.client(client)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(LoganSquareConverterFactory.create())
if (dummyExecutor) {
retrofitBuilder.callbackExecutor {
//dumb, to prevent tests from failing }
}
}
.addConverterFactory(MoshiConverterFactory.create(MoshiProvider.moshi))
return retrofitBuilder.build().create(GitLabService::class.java)
}
}
Loading
Loading
Loading
Loading
@@ -15,7 +15,7 @@ import retrofit2.http.*
interface GitLabService {
 
companion object {
const val API_VERSION = "api/v3"
const val API_VERSION = "api/v4"
}
 
/* --- LOGIN --- */
Loading
Loading
@@ -80,19 +80,19 @@ interface GitLabService {
 
/* --- PROJECTS --- */
 
@GET(API_VERSION + "/projects?order_by=last_activity_at&archived=false")
@GET(API_VERSION + "/projects?membership=true&order_by=last_activity_at&archived=false")
fun getAllProjects(): Single<Response<List<Project>>>
 
@GET(API_VERSION + "/projects/owned?order_by=last_activity_at&archived=false")
@GET(API_VERSION + "/projects?owned=true&order_by=last_activity_at&archived=false")
fun getMyProjects(): Single<Response<List<Project>>>
 
@GET(API_VERSION + "/projects/starred")
@GET(API_VERSION + "/projects?starred=true")
fun getStarredProjects(): Single<Response<List<Project>>>
 
@GET(API_VERSION + "/projects/{id}")
fun getProject(@Path("id") projectId: String): Single<Project>
 
// see https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md#get-single-project
// see https://docs.gitlab.com/ce/api/projects.html#get-single-project
@GET(API_VERSION + "/projects/{namespace}%2F{project_name}")
fun getProject(@Path("namespace") namespace: String,
@Path("project_name") projectName: String): Single<Project>
Loading
Loading
@@ -100,8 +100,8 @@ interface GitLabService {
@GET
fun getProjects(@Url url: String): Single<Response<List<Project>>>
 
@GET(API_VERSION + "/projects/search/{query}")
fun searchAllProjects(@Path("query") query: String): Single<Response<List<Project>>>
@GET(API_VERSION + "/projects")
fun searchAllProjects(@Query("search") query: String): Single<Response<List<Project>>>
 
@GET(API_VERSION + "/projects/{id}/members")
fun getProjectMembers(@Path("id") projectId: Long): Single<Response<List<Member>>>
Loading
Loading
@@ -125,13 +125,13 @@ interface GitLabService {
fun removeProjectMember(@Path("id") projectId: Long,
@Path("user_id") userId: Long): Single<String>
 
@POST(API_VERSION + "/projects/fork/{id}")
@POST(API_VERSION + "/projects/{id}/fork")
fun forkProject(@Path("id") projectId: Long): Single<String>
 
@POST(API_VERSION + "/projects/{id}/star")
fun starProject(@Path("id") projectId: Long): Single<Response<Project>>
 
@DELETE(API_VERSION + "/projects/{id}/star")
@POST(API_VERSION + "/projects/{id}/unstar")
fun unstarProject(@Path("id") projectId: Long): Single<Project>
 
@Multipart
Loading
Loading
@@ -150,7 +150,7 @@ interface GitLabService {
 
@GET(API_VERSION + "/projects/{id}/issues")
fun getMilestonesByIid(@Path("id") projectId: Long,
@Query("iid") internalMilestoneId: String): Single<List<Milestone>>
@Query("iids") internalMilestoneId: String): Single<List<Milestone>>
 
@GET(API_VERSION + "/projects/{id}/milestones/{milestone_id}/issues")
fun getMilestoneIssues(@Path("id") projectId: Long,
Loading
Loading
@@ -191,9 +191,9 @@ interface GitLabService {
 
@GET(API_VERSION + "/projects/{id}/merge_requests")
fun getMergeRequestsByIid(@Path("id") projectId: Long,
@Query("iid") internalMergeRequestId: String): Single<List<MergeRequest>>
@Query("iids") internalMergeRequestId: String): Single<List<MergeRequest>>
 
@GET(API_VERSION + "/projects/{id}/merge_request/{merge_request_id}")
@GET(API_VERSION + "/projects/{id}/merge_requests/{merge_request_id}")
fun getMergeRequest(@Path("id") projectId: Long,
@Path("merge_request_id") mergeRequestId: Long): Single<MergeRequest>
 
Loading
Loading
@@ -236,8 +236,7 @@ interface GitLabService {
@Path("issue_id") issueId: String): Single<Issue>
 
@GET(API_VERSION + "/projects/{id}/issues")
fun getIssuesByIid(@Path("id") projectId: Long,
@Query("iid") internalIssueId: String): Single<List<Issue>>
fun getIssuesByIid(@Path("id") projectId: Long): Single<List<Issue>>
 
@FormUrlEncoded
@POST(API_VERSION + "/projects/{id}/issues")
Loading
Loading
@@ -249,9 +248,9 @@ interface GitLabService {
@Field("labels") commaSeparatedLabelNames: String?,
@Field("confidential") isConfidential: Boolean): Single<Issue>
 
@PUT(API_VERSION + "/projects/{id}/issues/{issue_id}")
@PUT(API_VERSION + "/projects/{id}/issues/{issue_iid}")
fun updateIssue(@Path("id") projectId: Long,
@Path("issue_id") issueId: Long,
@Path("issue_iid") issueIid: Long,
@Query("title") title: String,
@Query("description") description: String,
@Query("assignee_id") assigneeId: Long?,
Loading
Loading
@@ -259,27 +258,27 @@ interface GitLabService {
@Query("labels") commaSeparatedLabelNames: String?,
@Query("confidential") isConfidential: Boolean): Single<Issue>
 
@PUT(API_VERSION + "/projects/{id}/issues/{issue_id}")
@PUT(API_VERSION + "/projects/{id}/issues/{issue_iid}")
fun updateIssueStatus(@Path("id") projectId: Long,
@Path("issue_id") issueId: Long,
@Path("issue_iid") issueIid: Long,
@Query("state_event") @Issue.EditState status: String): Single<Issue>
 
@GET(API_VERSION + "/projects/{id}/issues/{issue_id}/notes")
@GET(API_VERSION + "/projects/{id}/issues/{issue_iid}/notes")
fun getIssueNotes(@Path("id") projectId: Long,
@Path("issue_id") issueId: Long): Single<Response<List<Note>>>
@Path("issue_iid") issueIid: Long): Single<Response<List<Note>>>
 
@GET
fun getIssueNotes(@Url url: String): Single<Response<List<Note>>>
 
@FormUrlEncoded
@POST(API_VERSION + "/projects/{id}/issues/{issue_id}/notes")
@POST(API_VERSION + "/projects/{id}/issues/{issue_iid}/notes")
fun addIssueNote(@Path("id") projectId: Long,
@Path("issue_id") issueId: Long,
@Path("issue_iid") issueIid: Long,
@Field("body") body: String): Single<Note>
 
@DELETE(API_VERSION + "/projects/{id}/issues/{issue_id}")
@DELETE(API_VERSION + "/projects/{id}/issues/{issue_iid}")
fun deleteIssue(@Path("id") projectId: Long,
@Path("issue_id") issueId: Long): Single<String>
@Path("issue_iid") issueIid: Long): Single<String>
 
/* --- REPOSITORY --- */
 
Loading
Loading
@@ -294,9 +293,9 @@ interface GitLabService {
@Query("ref_name") branchName: String,
@Query("path") path: String?): Single<List<RepositoryTreeObject>>
 
@GET(API_VERSION + "/projects/{id}/repository/files")
@GET(API_VERSION + "/projects/{id}/repository/files/{file_path}")
fun getFile(@Path("id") projectId: Long,
@Query("file_path") path: String,
@Path("file_path") path: String,
@Query("ref") ref: String): Single<RepositoryFile>
 
@GET(API_VERSION + "/projects/{id}/repository/commits")
Loading
Loading
@@ -352,7 +351,7 @@ interface GitLabService {
 
 
/* --- BUILDS --- */
@GET(API_VERSION + "/projects/{id}/builds")
@GET(API_VERSION + "/projects/{id}/jobs")
fun getBuilds(@Path("id") projectId: Long,
@Query("scope") scope: String?): Single<Response<List<Build>>>
 
Loading
Loading
@@ -360,19 +359,19 @@ interface GitLabService {
fun getBuilds(@Url url: String,
@Query("scope") state: String?): Single<Response<List<Build>>>
 
@GET(API_VERSION + "/projects/{id}/builds/{build_id}")
@GET(API_VERSION + "/projects/{id}/jobs/{build_id}")
fun getBuild(@Path("id") projectId: Long,
@Path("build_id") buildId: Long): Single<Build>
 
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/retry")
@POST(API_VERSION + "/projects/{id}/jobs/{build_id}/retry")
fun retryBuild(@Path("id") projectId: Long,
@Path("build_id") buildId: Long): Single<Build>
 
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/erase")
@POST(API_VERSION + "/projects/{id}/jobs/{build_id}/erase")
fun eraseBuild(@Path("id") projectId: Long,
@Path("build_id") buildId: Long): Single<Build>
 
@POST(API_VERSION + "/projects/{id}/builds/{build_id}/cancel")
@POST(API_VERSION + "/projects/{id}/jobs/{build_id}/cancel")
fun cancelBuild(@Path("id") projectId: Long,
@Path("build_id") buildId: Long): Single<Build>
 
Loading
Loading
package com.commit451.gitlab.api
import com.commit451.gitlab.api.converter.DashDateAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Rfc3339DateJsonAdapter
import java.util.*
object MoshiProvider {
val moshi: Moshi by lazy {
Moshi.Builder()
.add(DashDateAdapter())
.add(Date::class.java, Rfc3339DateJsonAdapter())
.build()
}
}
\ No newline at end of file
Loading
Loading
@@ -19,7 +19,7 @@ object OkHttpClientFactory {
* *
* @return a configured [okhttp3.OkHttpClient.Builder]
*/
@JvmOverloads fun create(account: Account, includeSignInAuthenticator: Boolean = true): OkHttpClient.Builder {
fun create(account: Account, includeSignInAuthenticator: Boolean = true): OkHttpClient.Builder {
// Do we even need a custom trust manager?
// Yep. Otherwise SSL won't work properly with some configurations :) -Michi
val customTrustManager = CustomTrustManager()
Loading
Loading
package com.commit451.gitlab.api.converter
import com.commit451.gitlab.model.api.Milestone
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.ToJson
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
/**
* Converts due dates
*/
class DashDateAdapter {
companion object {
val format by lazy {
SimpleDateFormat("yyyy-MM-d", Locale.US)
}
}
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DueDate
@ToJson
fun toJson(@DueDate date: Date): String {
return format.format(date)
}
@FromJson
@DueDate
fun fromJson(json: String): Date {
return format.parse(json)
}
}
\ No newline at end of file
package com.commit451.gitlab.api.converter
import com.bluelinelabs.logansquare.typeconverters.DateTypeConverter
import com.commit451.gitlab.model.api.Milestone
import java.text.DateFormat
/**
* Converts due dates
*/
class DueDateTypeConverter : DateTypeConverter() {
override fun getDateFormat(): DateFormat {
return Milestone.DUE_DATE_FORMAT
}
}
\ No newline at end of file
package com.commit451.gitlab.api.converter
import android.net.Uri
import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter
/**
* Simple Uri type converter
*/
class UriTypeConverter : StringBasedTypeConverter<Uri>() {
override fun convertToString(`object`: Uri): String {
return `object`.toString()
}
override fun getFromString(string: String?): Uri? {
if (string != null) {
return Uri.parse(string)
} else {
return null
}
}
}
package com.commit451.gitlab.api.request;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Start a session
*/
@JsonObject
public class SessionRequest {
@JsonField(name = "email")
String email;
@JsonField(name = "login")
String login;
@JsonField(name = "password")
String password;
public SessionRequest setEmail(String email) {
this.email = email;
return this;
}
public SessionRequest setLogin(String login) {
this.login = login;
return this;
}
public SessionRequest setPassword(String password) {
this.password = password;
return this;
}
}
package com.commit451.gitlab.api.request
import com.squareup.moshi.Json
/**
* Start a session
*/
class SessionRequest {
@Json(name = "email")
var email: String? = null
@Json(name = "login")
var login: String? = null
@Json(name = "password")
var password: String? = null
}
package com.commit451.gitlab.api.rss
 
import com.commit451.gitlab.util.ConversionUtil
import org.simpleframework.xml.transform.Transform
import org.threeten.bp.Instant
import org.threeten.bp.format.DateTimeFormatter
import java.util.*
 
/**
Loading
Loading
@@ -11,11 +12,11 @@ class DateTransform : Transform<Date> {
 
@Throws(Exception::class)
override fun read(value: String): Date? {
return ConversionUtil.toDate(value)
return Date(Instant.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(value)).toEpochMilli())
}
 
@Throws(Exception::class)
override fun write(value: Date): String {
return ConversionUtil.fromDate(value)
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(Instant.ofEpochMilli(value.time))
}
}
Loading
Loading
@@ -5,10 +5,16 @@ import android.content.Context
import android.content.SharedPreferences
import android.preference.PreferenceManager
import android.support.annotation.IntDef
import com.bluelinelabs.logansquare.LoganSquare
import com.commit451.gitlab.api.MoshiProvider
import com.commit451.gitlab.model.Account
import java.io.IOException
import java.util.*
import com.squareup.moshi.Moshi
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Types.newParameterizedType
import com.squareup.moshi.Types
 
/**
* Shared prefs things
Loading
Loading
@@ -40,12 +46,9 @@ object Prefs {
fun getAccounts(): MutableList<Account> {
val accountsJson = prefs.getString(KEY_ACCOUNTS, null)
if (!accountsJson.isNullOrEmpty()) {
try {
return LoganSquare.parseList(accountsJson, Account::class.java)
} catch (e: IOException) {
prefs.edit().remove(KEY_ACCOUNTS).apply()
}
return ArrayList()
val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = MoshiProvider.moshi.adapter<List<Account>>(type)
return adapter.fromJson(accountsJson)!!.toMutableList()
} else {
return ArrayList()
}
Loading
Loading
@@ -53,7 +56,9 @@ object Prefs {
 
fun setAccounts(accounts: List<Account>) {
try {
val json = LoganSquare.serialize<List<Account>>(accounts)
val type = Types.newParameterizedType(List::class.java, Account::class.java)
val adapter = MoshiProvider.moshi.adapter<List<Account>>(type)
val json = adapter.toJson(accounts)
prefs.edit()
.putString(KEY_ACCOUNTS, json)
.apply()
Loading
Loading
Loading
Loading
@@ -11,16 +11,11 @@ import com.commit451.gitlab.R
 
class HttpLoginDialog(context: Context, realm: String, loginListener: HttpLoginDialog.LoginListener) : AppCompatDialog(context) {
 
@BindView(R.id.message_text)
lateinit var textMessage: TextView
@BindView(R.id.login_username)
lateinit var textUsername: EditText
@BindView(R.id.login_password)
lateinit var textPassword: EditText
@BindView(R.id.ok_button)
lateinit var buttonOk: Button
@BindView(R.id.cancel_button)
lateinit var buttonCancel: Button
@BindView(R.id.message_text) lateinit var textMessage: TextView
@BindView(R.id.login_username) lateinit var textUsername: EditText
@BindView(R.id.login_password) lateinit var textPassword: EditText
@BindView(R.id.ok_button) lateinit var buttonOk: Button
@BindView(R.id.cancel_button) lateinit var buttonCancel: Button
 
init {
setContentView(R.layout.dialog_http_login)
Loading
Loading
package com.commit451.gitlab.extension
 
import android.net.Uri
import com.commit451.gitlab.api.GitLabService
import com.commit451.gitlab.model.api.Build
import com.commit451.gitlab.model.api.Project
 
fun Build.getRawBuildUrl(baseUrl: Uri, project: Project): String {
return baseUrl.toString() + project.pathWithNamespace + "/builds/" + id + "/raw"
fun Build.getRawBuildUrl(baseUrl: String, project: Project): String {
return baseUrl + project.pathWithNamespace + "/builds/" + id + "/raw"
}
 
fun Build.getDownloadBuildUrl(baseUrl: Uri, project: Project): String {
return baseUrl.toString() + GitLabService.API_VERSION + "/projects/" + project.id + "/builds/" + id + "/artifacts"
fun Build.getDownloadBuildUrl(baseUrl: String, project: Project): String {
return baseUrl + GitLabService.API_VERSION + "/projects/" + project.id + "/builds/" + id + "/artifacts"
}
package com.commit451.gitlab.extension
import android.os.Bundle
import org.parceler.Parcels
//Bundle extensions
fun Bundle.putParcelParcelableExtra(key: String, thing: Any?) {
this.putParcelable(key, org.parceler.Parcels.wrap(thing))
}
/**
* Get Parcelable that was put in the bundle using Parceler
*/
fun <T> Bundle.getParcelerParcelable(key: String): T? {
return Parcels.unwrap<T>(getParcelable(key))
}
\ No newline at end of file
package com.commit451.gitlab.extension
import android.content.Intent
import org.parceler.Parcels
/**
* Get Parcelable that was put in the intent using Parceler
*/
fun <T> Intent.getParcelerParcelable(key: String): T? {
return Parcels.unwrap<T>(getParcelableExtra(key))
}
fun Intent.putParcelParcelableExtra(key: String, thing: Any?) {
this.putExtra(key, org.parceler.Parcels.wrap(thing))
}
package com.commit451.gitlab.extension
import android.net.Uri
import com.commit451.gitlab.model.api.Issue
import com.commit451.gitlab.model.api.Project
fun Issue.getUrl(project: Project): Uri {
val projectUri = Uri.parse(project.webUrl)
return projectUri.buildUpon()
.appendPath("issues")
.appendPath(iid.toString())
.build()
}
package com.commit451.gitlab.extension
import com.commit451.gitlab.model.api.Project
import android.net.Uri
/**
* Created by johncarlson on 7/28/17.
*/
fun Project.getFeedUrl(): Uri? {
if (webUrl == null) {
return null
}
return Uri.parse(webUrl + ".atom")
}
\ No newline at end of file
package com.commit451.gitlab.extension
import android.net.Uri
import android.support.annotation.DrawableRes
import com.commit451.gitlab.R
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.model.api.RepositoryTreeObject
import com.commit451.gitlab.model.api.RepositoryTreeObject.*
@DrawableRes
fun RepositoryTreeObject.getDrawableForType(): Int {
if (type == null) {
return R.drawable.ic_unknown_24dp
}
when (type) {
TYPE_FILE -> return R.drawable.ic_file_24dp
TYPE_FOLDER -> return R.drawable.ic_folder_24dp
TYPE_REPO -> return R.drawable.ic_repo_24dp
}
return R.drawable.ic_unknown_24dp
}
fun RepositoryTreeObject.getUrl(project: Project, branchName: String, currentPath: String): Uri {
val projectUri = Uri.parse(project.webUrl)
return projectUri.buildUpon()
.appendPath("tree")
.appendPath(branchName)
.appendEncodedPath(currentPath)
.appendPath(name)
.build()
}
\ No newline at end of file
Loading
Loading
@@ -6,8 +6,6 @@ import android.text.Spanned
import android.util.Base64
import io.reactivex.Single
 
//String extension methods
fun String.base64Decode(): Single<ByteArray> {
return Single.fromCallable {
Base64.decode(this, Base64.DEFAULT)
Loading
Loading
@@ -18,10 +16,10 @@ fun String.base64Decode(): Single<ByteArray> {
* Assures HTML is formatted the same way pre and post Android N
*/
@Suppress("DEPRECATION")
fun String.formatAsHtml(): Spanned {
fun String.formatAsHtml(imageGetter: Html.ImageGetter? = null, tagHandler: Html.TagHandler? = null): Spanned {
if (Build.VERSION.SDK_INT >= 24) {
return Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
return Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY, imageGetter, tagHandler)
} else {
return Html.fromHtml(this)
return Html.fromHtml(this, imageGetter, tagHandler)
}
}
\ No newline at end of file
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment