From 55cb870d42580c813091a054aa3afc3307e813ba Mon Sep 17 00:00:00 2001
From: Haidar <16521522@mahasiswa.itb.ac.id>
Date: Fri, 5 Apr 2024 08:26:31 +0700
Subject: [PATCH] feat: add jwt services

---
 .../exe_android/data/login/ApiService.kt      |  9 +++
 .../exe_android/ui/login/LoginActivity.kt     | 56 ++++++++++++++++---
 .../ui/login/TokenExpirationService.kt        | 49 ++++++++++++++++
 3 files changed, 107 insertions(+), 7 deletions(-)
 create mode 100644 app/src/main/java/pbd/tubes/exe_android/ui/login/TokenExpirationService.kt

diff --git a/app/src/main/java/pbd/tubes/exe_android/data/login/ApiService.kt b/app/src/main/java/pbd/tubes/exe_android/data/login/ApiService.kt
index e4ca829..69161f0 100644
--- a/app/src/main/java/pbd/tubes/exe_android/data/login/ApiService.kt
+++ b/app/src/main/java/pbd/tubes/exe_android/data/login/ApiService.kt
@@ -1,10 +1,19 @@
 package pbd.tubes.exe_android.data.login
 
+import pbd.tubes.exe_android.data.TokenResponse
 import retrofit2.Response
 import retrofit2.http.Body
+import retrofit2.http.Header
 import retrofit2.http.POST
 
+
 interface ApiService {
     @POST("/api/auth/login")
     suspend fun login(@Body credentials: LoginRequest): Response<LoginResponse>
+
+    @POST("/api/auth/token")
+    suspend fun decodeToken(
+        @Header("Authorization") authorization: String): Response<TokenResponse>
 }
+
+
diff --git a/app/src/main/java/pbd/tubes/exe_android/ui/login/LoginActivity.kt b/app/src/main/java/pbd/tubes/exe_android/ui/login/LoginActivity.kt
index d92719f..8853cb4 100644
--- a/app/src/main/java/pbd/tubes/exe_android/ui/login/LoginActivity.kt
+++ b/app/src/main/java/pbd/tubes/exe_android/ui/login/LoginActivity.kt
@@ -14,6 +14,10 @@ import pbd.tubes.exe_android.data.login.ApiService
 import pbd.tubes.exe_android.data.login.LoginRequest
 import retrofit2.Retrofit
 import retrofit2.converter.gson.GsonConverterFactory
+import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.Observer
+import pbd.tubes.exe_android.ui.NetworkSensing.NetworkLiveData
+import pbd.tubes.exe_android.ui.login.TokenExpirationCheckService
 
 class LoginActivity : AppCompatActivity() {
 
@@ -25,6 +29,14 @@ class LoginActivity : AppCompatActivity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+
+        val networkStatusLiveData = NetworkLiveData(this)
+        networkStatusLiveData.observe(this, Observer { isConnected ->
+            if (!isConnected) {
+                showNoInternetPopup()
+            }
+        })
+
         setContentView(R.layout.activity_login)
 
         val retrofit = Retrofit.Builder()
@@ -39,24 +51,41 @@ class LoginActivity : AppCompatActivity() {
         passwordEditText = findViewById(R.id.passwordEditText)
 
         loginButton.setOnClickListener {
-            val email = emailEditText.text.toString()
-            val password = passwordEditText.text.toString()
+//            val email = emailEditText.text.toString()
+//            val password = passwordEditText.text.toString()
+            val email = "1@std.stei.itb.ac.id"
+            val password = "password_1"
             val loginRequest = LoginRequest(email, password)
             login(loginRequest)
 
         }
     }
-
     private fun login(loginRequest: LoginRequest) {
         CoroutineScope(Dispatchers.IO).launch {
             try {
                 val response = apiService.login(loginRequest)
                 if (response.isSuccessful) {
                     val token = response.body()?.token
-                    token?.let {
-                        saveToken(it)
-                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        finish()
+                    token?.let { tkn ->
+
+                        val responseDecode = apiService.decodeToken("Bearer $tkn")
+
+                        if (responseDecode.isSuccessful) {
+                            val expire = responseDecode.body()?.exp
+                            expire?.let {exp ->
+                                startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                                saveTokenExpiration(exp)
+                                saveToken(tkn)
+                                val serviceIntent = Intent(this@LoginActivity, TokenExpirationCheckService::class.java)
+                                startService(serviceIntent)
+                                finish()
+                            }
+                        }
+                        else {
+                            Log.d("Failed Token", "Failed Get decoded token (error response)")
+                        }
+
+
                     }
                     Toast.makeText(baseContext,
                         "Log In Success!",
@@ -78,6 +107,19 @@ class LoginActivity : AppCompatActivity() {
         sharedPreferences.edit().putString("token", token).apply()
     }
 
+    private fun saveTokenExpiration(expirationTime: Long) {
+        val sharedPreferences = getSharedPreferences("user_session", MODE_PRIVATE)
+        sharedPreferences.edit().putLong("expiration_time", expirationTime).apply()
+    }
+
+    private fun showNoInternetPopup() {
+        AlertDialog.Builder(this)
+            .setTitle("No Internet Connection")
+            .setMessage("Please check your internet connection and try again.")
+            .setPositiveButton("OK", null)
+            .show()
+    }
+
     companion object {
         private const val BASE_URL = "https://pbd-backend-2024.vercel.app"
     }
diff --git a/app/src/main/java/pbd/tubes/exe_android/ui/login/TokenExpirationService.kt b/app/src/main/java/pbd/tubes/exe_android/ui/login/TokenExpirationService.kt
new file mode 100644
index 0000000..5711465
--- /dev/null
+++ b/app/src/main/java/pbd/tubes/exe_android/ui/login/TokenExpirationService.kt
@@ -0,0 +1,49 @@
+package pbd.tubes.exe_android.ui.login
+import android.app.Notification
+import android.app.Service
+import android.content.Intent
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.util.Log
+import pbd.tubes.exe_android.LoginActivity
+
+class TokenExpirationCheckService : Service() {
+
+    private val sharedPreferences by lazy {
+        getSharedPreferences("user_session", MODE_PRIVATE)
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        checkTokenExpiration()
+        return START_STICKY
+    }
+
+    private fun checkTokenExpiration() {
+        val expirationTime = sharedPreferences.getLong("expiration_time", 0)
+        val currentTime = System.currentTimeMillis() / 1000
+        val timeDifference = expirationTime - currentTime
+//        Log.d("Difference", "difference is $timeDifference")
+
+        if (currentTime > expirationTime) {
+            redirectToLogin()
+            stopSelf()
+            return
+        }
+
+        Handler(Looper.getMainLooper()).postDelayed({
+            checkTokenExpiration()
+        }, (timeDifference) * 1000)
+    }
+
+    private fun redirectToLogin() {
+        val loginIntent = Intent(this, LoginActivity::class.java)
+        loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        sharedPreferences.edit().clear().apply()
+        startActivity(loginIntent)
+    }
+
+    override fun onBind(intent: Intent?): IBinder? {
+        return null
+    }
+}
\ No newline at end of file
-- 
GitLab