diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index ce889bd..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - -
- - - - xmlns:android - - ^$ - - - -
-
- - - - xmlns:.* - - ^$ - - - BY_NAME - -
-
- - - - .*:id - - http://schemas.android.com/apk/res/android - - - -
-
- - - - .*:name - - http://schemas.android.com/apk/res/android - - - -
-
- - - - name - - ^$ - - - -
-
- - - - style - - ^$ - - - -
-
- - - - .* - - ^$ - - - BY_NAME - -
-
- - - - .* - - http://schemas.android.com/apk/res/android - - - ANDROID_ATTRIBUTE_ORDER - -
-
- - - - .* - - .* - - - BY_NAME - -
-
-
-
- - -
-
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index b73660a..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b2..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 146ab09..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index a5f05cd..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 355212c..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 50a28b1..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 25d3265..3cd8500 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/lib/src/main/java/com/kirkbushman/zammad/ZammadApi.kt b/lib/src/main/java/com/kirkbushman/zammad/ZammadApi.kt index 983f3e8..9154ce1 100644 --- a/lib/src/main/java/com/kirkbushman/zammad/ZammadApi.kt +++ b/lib/src/main/java/com/kirkbushman/zammad/ZammadApi.kt @@ -28,6 +28,12 @@ interface ZammadApi { @HeaderMap header: HashMap ): Call + @GET("/api/v1/signatures") + fun signatures( + @Query("expand") expanded: Boolean, + @HeaderMap header: HashMap + ): Call> + @FormUrlEncoded @PUT("/api/v1/users/{id}") fun updateUser( @@ -213,6 +219,23 @@ interface ZammadApi { @HeaderMap header: HashMap ): Call> + @GET("/api/v1/tags") + fun ticketTags( + @Query("object") ticket: String, + @Query("o_id") query: String, + @Query("expand") expanded: Boolean, + @HeaderMap header: HashMap + ): Call + + @FormUrlEncoded + @POST("/api/v1/tags/add") + fun addTag( + @Field("item") item: String, + @Field("object") tagObject: String, + @Field("o_id") oId: String, + @HeaderMap header: HashMap + ): Call + @GET("/api/v1/ticket_states") fun ticketStates( @Query("expand") expanded: Boolean, @@ -338,6 +361,7 @@ interface ZammadApi { @Field("customer_id") customerId: Int? = null, @Field("customer") customer: String? = null, @Field("note") note: String? = null, + @Field("pending_time") pendingTime: String? = null, @HeaderMap header: HashMap ): Call diff --git a/lib/src/main/java/com/kirkbushman/zammad/ZammadClient.kt b/lib/src/main/java/com/kirkbushman/zammad/ZammadClient.kt index 112ce26..8cf7b09 100644 --- a/lib/src/main/java/com/kirkbushman/zammad/ZammadClient.kt +++ b/lib/src/main/java/com/kirkbushman/zammad/ZammadClient.kt @@ -16,7 +16,7 @@ class ZammadClient( private val logging: Boolean ) { - constructor(baseUrl: String, username: String, password: String, logging: Boolean) : this(baseUrl, "$username:$password", logging) + constructor(baseUrl: String, username: String, password: String, logging: Boolean ) : this(baseUrl, "$username:$password", logging) companion object { @@ -52,11 +52,9 @@ class ZammadClient( @Synchronized fun getApi(baseUrl: String, logging: Boolean): ZammadApi { synchronized(this) { - if (api == null) { api = getRetrofit(baseUrl, logging).create(ZammadApi::class.java) } - return api!! } } @@ -85,13 +83,13 @@ class ZammadClient( val api = getApi(baseUrl, logging) val req = api.me(expanded, authMap) val res = req.execute() - if (!res.isSuccessful) { return null } return res.body() } + } private val api = getApi(baseUrl, logging) @@ -632,6 +630,24 @@ class ZammadClient( return res.body() } + fun signatures(expanded: Boolean = false): List? { + + val authMap = getHeaderMap() + val req = api.signatures(expanded, authMap) + val res = req.execute() + + if (!res.isSuccessful) { + + if (logging) { + Log.i("Retrofit Error", res.errorBody().toString()) + } + + return null + } + + return res.body() + } + fun ticketStates(expanded: Boolean = false): List? { val authMap = getHeaderMap() @@ -979,7 +995,8 @@ class ZammadClient( owner: String? = null, customerId: Int? = null, customer: String? = null, - note: String? = null + note: String? = null, + pendingTime: String? = null ): Ticket? { val authMap = getHeaderMap() @@ -997,7 +1014,8 @@ class ZammadClient( customerId = customerId, customer = customer, note = note, - header = authMap + header = authMap, + pendingTime = pendingTime ) val res = req.execute() @@ -1037,6 +1055,42 @@ class ZammadClient( return true } + fun ticketTags(ticket: String, query: String, expanded: Boolean = false): TicketTags? { + + val authMap = getHeaderMap() + val req = api.ticketTags(ticket, query, expanded, authMap) + val res = req.execute() + + if (!res.isSuccessful) { + + if (logging) { + Log.i("Retrofit Error", res.errorBody().toString()) + } + + return null + } + + return res.body() + } + + fun addTag(item: String, tagObject: String, oId: String): Any? { + + val authMap = getHeaderMap() + val req = api.addTag(item, tagObject, oId, authMap) + val res = req.execute() + + if (!res.isSuccessful) { + + if (logging) { + Log.i("Retrofit Error", res.errorBody().toString()) + } + + return null + } + + return res.body() + } + fun searchTickets(query: String, page: Int, perPage: Int, expanded: Boolean = false): SearchResult? { val authMap = getHeaderMap() diff --git a/lib/src/main/java/com/kirkbushman/zammad/models/MailSignature.kt b/lib/src/main/java/com/kirkbushman/zammad/models/MailSignature.kt new file mode 100644 index 0000000..f0db002 --- /dev/null +++ b/lib/src/main/java/com/kirkbushman/zammad/models/MailSignature.kt @@ -0,0 +1,40 @@ +package com.kirkbushman.zammad.models + +import android.os.Parcelable +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import kotlinx.parcelize.Parcelize + +@JsonClass(generateAdapter = true) +@Parcelize +data class MailSignature( + + @Json(name = "id") + val id: Int, + + @Json(name = "name") + val name: String, + + @Json(name = "body") + val body: String, + + @Json(name = "active") + val active: Boolean, + + @Json(name = "note") + val note: String?, + + @Json(name = "created_by_id") + val createdById: Int, + + @Json(name = "updated_by_id") + val updatedById: Int, + + @Json(name = "created_at") + val createdAt: String, + + @Json(name = "updated_at") + val updatedAt: String, + +) : Parcelable + diff --git a/lib/src/main/java/com/kirkbushman/zammad/models/Ticket.kt b/lib/src/main/java/com/kirkbushman/zammad/models/Ticket.kt index 93be453..20c8757 100644 --- a/lib/src/main/java/com/kirkbushman/zammad/models/Ticket.kt +++ b/lib/src/main/java/com/kirkbushman/zammad/models/Ticket.kt @@ -82,6 +82,9 @@ data class Ticket( override val createdBy: String?, @Json(name = "updated_by") - override val updatedBy: String? + override val updatedBy: String?, + + @Json(name = "pending_time") + val pendingTime: String? ) : Parcelable, Identifiable, Creatable, Updatable diff --git a/lib/src/main/java/com/kirkbushman/zammad/models/TicketState.kt b/lib/src/main/java/com/kirkbushman/zammad/models/TicketState.kt index 78e2969..2fdfe2d 100644 --- a/lib/src/main/java/com/kirkbushman/zammad/models/TicketState.kt +++ b/lib/src/main/java/com/kirkbushman/zammad/models/TicketState.kt @@ -31,7 +31,7 @@ data class TicketState( val defaultFollowUp: Boolean, @Json(name = "note") - val note: String, + val note: String?, @Json(name = "created_by_id") override val createdById: Int, diff --git a/lib/src/main/java/com/kirkbushman/zammad/models/TicketTags.kt b/lib/src/main/java/com/kirkbushman/zammad/models/TicketTags.kt new file mode 100644 index 0000000..02dfd56 --- /dev/null +++ b/lib/src/main/java/com/kirkbushman/zammad/models/TicketTags.kt @@ -0,0 +1,16 @@ +package com.kirkbushman.zammad.models + +import android.os.Parcelable +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import kotlinx.parcelize.Parcelize +import kotlinx.parcelize.RawValue + +@JsonClass(generateAdapter = true) +@Parcelize +data class TicketTags( + + @Json(name = "tags") + val tags: @RawValue List + +) : Parcelable \ No newline at end of file diff --git a/lib/src/main/java/com/kirkbushman/zammad/models/compat/TicketCompat.kt b/lib/src/main/java/com/kirkbushman/zammad/models/compat/TicketCompat.kt index 65d4197..ffe7fde 100644 --- a/lib/src/main/java/com/kirkbushman/zammad/models/compat/TicketCompat.kt +++ b/lib/src/main/java/com/kirkbushman/zammad/models/compat/TicketCompat.kt @@ -46,6 +46,9 @@ data class TicketCompat( val article: TicketArticleCompat, @Json(name = "note") - val note: String? = null + val note: String? = null, + + @Json(name = "pending_time") + val pendingTime: String? = null ) : Parcelable diff --git a/sampleapp/src/main/AndroidManifest.xml b/sampleapp/src/main/AndroidManifest.xml index 862da94..169181d 100644 --- a/sampleapp/src/main/AndroidManifest.xml +++ b/sampleapp/src/main/AndroidManifest.xml @@ -20,7 +20,9 @@ tools:targetApi="n" tools:ignore="GoogleAppIndexingWarning"> - + @@ -28,45 +30,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/sampleapp/src/main/java/com/kirkbushman/sampleapp/LoginActivity.kt b/sampleapp/src/main/java/com/kirkbushman/sampleapp/LoginActivity.kt index 5819625..d09ad11 100644 --- a/sampleapp/src/main/java/com/kirkbushman/sampleapp/LoginActivity.kt +++ b/sampleapp/src/main/java/com/kirkbushman/sampleapp/LoginActivity.kt @@ -2,14 +2,16 @@ package com.kirkbushman.sampleapp import android.content.Intent import android.os.Bundle +import android.util.Base64 import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.kirkbushman.sampleapp.data.Preferences import com.kirkbushman.sampleapp.databinding.ActivityLoginBinding import com.kirkbushman.sampleapp.di.SingletonModule import com.kirkbushman.zammad.ZammadClient -import com.kirkbushman.zammad.models.User import dagger.hilt.android.AndroidEntryPoint +import java.net.HttpURLConnection +import java.net.URL import javax.inject.Inject @AndroidEntryPoint @@ -28,7 +30,7 @@ class LoginActivity : AppCompatActivity() { if (prefs.getIsLoggedIn()) { - SingletonModule.setClient(ZammadClient(prefs.getBaseUrl(), prefs.getUsername(), prefs.getPassword(), true)) + SingletonModule.setClient(ZammadClient(prefs.getBaseUrl(), prefs.getUsername(), prefs.getPassword(), true )) startActivity(Intent(this, MainActivity::class.java)) } @@ -39,7 +41,7 @@ class LoginActivity : AppCompatActivity() { val username = binding.emailEdit.text.trim().toString() val password = binding.passwordEdit.text.trim().toString() - if (baseUrl == "") { + if (!baseUrl.contains("https://")) { Toast.makeText(this, "baseurl not found!", Toast.LENGTH_SHORT).show() } @@ -51,30 +53,69 @@ class LoginActivity : AppCompatActivity() { Toast.makeText(this, "password not found!", Toast.LENGTH_SHORT).show() } - var me: User? = null - DoAsync( - doWork = { - me = ZammadClient.me(baseUrl, username, password, true) - }, - onPost = { - - if (me != null) { - - SingletonModule.setClient(ZammadClient(baseUrl, username, password, true)) - - with(prefs) { - setIsLoggedIn(true) - setBaseUrl(baseUrl) - setUsername(username) - setPassword(password) + else { + var logText: String? + var isReachable:Int?=null + DoAsync( + doWork = { + kotlin.runCatching { + val userpass = "$username:$password" + val basicAuth = "Basic " + Base64.encodeToString( + userpass.toByteArray(), + Base64.NO_WRAP + ) + + isReachable = + if (android.os.Build.VERSION.SDK_INT >= 25) { + val connection: HttpURLConnection = URL( + baseUrl + "/api/v1/users/me" + ).openConnection() as HttpURLConnection + connection.setRequestProperty("Authorization", basicAuth); + connection.requestMethod = "GET" + connection.responseCode + } else 200 + } + }, + onPost = { + if (isReachable != 200) { + Toast.makeText( + this, + getString(R.string.inaccessible_error) + "\nERROR: " + isReachable.toString(), + Toast.LENGTH_LONG + ) + .show() + return@DoAsync + } + logText = if (isReachable == 401) getString(R.string.unauthorized_error) else getString( + R.string.inaccessible_error + ) + + if (isReachable == 200) { + + SingletonModule.setClient( + ZammadClient( + baseUrl, + username, + password, + true + ) + ) + + with(prefs) { + setIsLoggedIn(true) + setBaseUrl(baseUrl) + setUsername(username) + setPassword(password) + } + + startActivity(Intent(this, MainActivity::class.java)) + } else { + Toast.makeText(this, logText, Toast.LENGTH_LONG) + .show() } - - startActivity(Intent(this, MainActivity::class.java)) - } else { - Toast.makeText(this, "Error while trying to login!", Toast.LENGTH_SHORT).show() } - } - ) + ) + } } } } diff --git a/sampleapp/src/main/res/values/strings.xml b/sampleapp/src/main/res/values/strings.xml index 68f774c..b7a2bca 100644 --- a/sampleapp/src/main/res/values/strings.xml +++ b/sampleapp/src/main/res/values/strings.xml @@ -55,4 +55,6 @@ Search: No items to show. + Error while trying to login!\nUnauthorized! Please check your username and password. + Error while trying to login!\nUrl is inaccessible! Check network and input!