code: Сделал api админа

This commit is contained in:
DKaverznev 2025-02-20 12:54:44 +03:00
parent 0e3fde6347
commit 9372266f4f
17 changed files with 107 additions and 36 deletions

View File

@ -48,7 +48,13 @@ dependencies {
implementation(Dependencies.Retrofit.gsonConverter) implementation(Dependencies.Retrofit.gsonConverter)
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0") implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
implementation("com.squareup.picasso:picasso:2.8") // Убираем Picasso
// implementation("com.squareup.picasso:picasso:2.8")
// Добавляем Glide
implementation("com.github.bumptech.glide:glide:4.14.2")
kapt("com.github.bumptech.glide:compiler:4.14.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
implementation("androidx.datastore:datastore-preferences:1.1.2") implementation("androidx.datastore:datastore-preferences:1.1.2")
implementation("com.google.mlkit:barcode-scanning:17.3.0") implementation("com.google.mlkit:barcode-scanning:17.3.0")

View File

@ -6,6 +6,7 @@ import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain import ru.myitschool.work.api.main.ApiServiceMain
@ -45,4 +46,10 @@ object NetworkModule {
fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList { fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList {
return retrofitClient.getApiServiceList() return retrofitClient.getApiServiceList()
} }
@Provides
@Singleton
fun provideApiServiceAdmin(retrofitClient: RetrofitClient): ApiServiceAdmin {
return retrofitClient.getApiServiceAdmin()
}
} }

View File

@ -1,11 +1,11 @@
package ru.myitschool.work.api package ru.myitschool.work.api
import android.content.Context import android.content.Context
import com.google.android.datatransport.BuildConfig
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain import ru.myitschool.work.api.main.ApiServiceMain
@ -57,4 +57,8 @@ class RetrofitClient(context: Context) {
fun getApiServiceList(): ApiServiceList { fun getApiServiceList(): ApiServiceList {
return retrofitWithAuth.create(ApiServiceList::class.java) return retrofitWithAuth.create(ApiServiceList::class.java)
} }
fun getApiServiceAdmin(): ApiServiceAdmin {
return retrofitWithAuth.create(ApiServiceAdmin::class.java)
}
} }

View File

@ -0,0 +1,7 @@
package ru.myitschool.work.api.admin
import com.google.gson.annotations.SerializedName
class AdminJson(
@SerializedName("authority") var authority: String? = null,
)

View File

@ -0,0 +1,16 @@
package ru.myitschool.work.api.admin
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
import retrofit2.http.Path
import ru.myitschool.work.api.main.UserInfo
interface ApiServiceAdmin {
@PATCH("api/admin/authority/change/{login}")
suspend fun block(
@Path("login") login: String,
@Body data: AdminJson
): Response<Void>
}

View File

@ -5,6 +5,6 @@ import retrofit2.http.GET
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceList { interface ApiServiceList {
@GET("api/list/{login}") @GET("api/user/list/{login}")
suspend fun getList(@Path("login") login: String): Response<List<ListInfo>> suspend fun getList(@Path("login") login: String): Response<List<ListInfo>>
} }

View File

@ -1,13 +1,9 @@
package ru.myitschool.work.api.login package ru.myitschool.work.api.login
import retrofit2.Call import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import ru.myitschool.work.api.main.UserInfo
interface ApiServiceLogin { interface ApiServiceLogin {
@GET("api/login") @GET("api/user/login")
fun authenticate(): Call<Void> fun authenticate(): Call<Void>
} }

View File

@ -5,6 +5,6 @@ import retrofit2.http.GET
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceMain { interface ApiServiceMain {
@GET("api/info/{login}") @GET("api/user/info/{login}")
fun getDataUser(@Path("login") login: String): Call<UserInfo> fun getDataUser(@Path("login") login: String): Call<UserInfo>
} }

View File

@ -9,15 +9,16 @@ data class UserInfo(
@SerializedName("photo") val photoUrl: String, @SerializedName("photo") val photoUrl: String,
@SerializedName("position") val position: String, @SerializedName("position") val position: String,
@SerializedName("lastVisit") val lastVisit: String, @SerializedName("lastVisit") val lastVisit: String,
) { @SerializedName("authority") val authority: List<AuthorityData>
companion object {
val Initial = UserInfo(
id = 0,
login = "",
name = "",
photoUrl = "",
position = "",
lastVisit = "",
) )
}
data class AuthorityData(
@SerializedName("id") val id: Int,
@SerializedName("authority") val authority: String,
)
object Authorities {
const val ROLE_ADMIN = "ROLE_ADMIN"
const val ROLE_USER = "ROLE_USER"
const val ROLE_BLOCK = "ROLE_BLOCK"
} }

View File

@ -6,6 +6,6 @@ import retrofit2.http.POST
import retrofit2.http.Path import retrofit2.http.Path
interface ApiServiceScan { interface ApiServiceScan {
@POST("api/add/{login}") @POST("api/user/add/{login}")
fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void> fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void>
} }

View File

@ -36,6 +36,7 @@ class RootActivity : AppCompatActivity() {
fragment<QrScanFragment, QrScanDestination>() fragment<QrScanFragment, QrScanDestination>()
fragment<MainFragment, MainDestination>() fragment<MainFragment, MainDestination>()
fragment<ResultFragment, ResultDestination>() fragment<ResultFragment, ResultDestination>()
/*fragment<AdminFragment, AdminDestination>()*/
} }
} }

View File

@ -104,8 +104,6 @@ class LoginFragment : Fragment(R.layout.fragment_login) {
text = "Ошибка авторизации" text = "Ошибка авторизации"
} }
authPreferences.clearLoginState()
Log.d("Authentication", "Ошибка авторизации") Log.d("Authentication", "Ошибка авторизации")
} }

View File

@ -36,7 +36,7 @@ class LoginViewModel @Inject constructor(
_state.value = LoginState.InvalidCredentials _state.value = LoginState.InvalidCredentials
} }
401 -> { 401 -> {
_state.value = LoginState.Error _state.value = LoginState.InvalidCredentials
} }
else -> { else -> {
_state.value = LoginState.Error _state.value = LoginState.Error

View File

@ -8,9 +8,9 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.api.main.Authorities
import ru.myitschool.work.databinding.FragmentMainBinding import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.ui.list.ListAdapter import ru.myitschool.work.ui.list.ListAdapter
import ru.myitschool.work.ui.login.LoginDestination import ru.myitschool.work.ui.login.LoginDestination
@ -100,6 +100,16 @@ class MainFragment : Fragment(R.layout.fragment_main) {
username.text = state.userInfo.name username.text = state.userInfo.name
position.text = state.userInfo.position position.text = state.userInfo.position
if (state.userInfo.authority[0].authority == Authorities.ROLE_ADMIN) {
admin.visibleOrGone(true)
} else if (state.userInfo.authority[0].authority == Authorities.ROLE_USER) {
admin.visibleOrGone(false)
} else {
admin.visibleOrGone(false)
Log.e("MainFragment", "Unknown role")
}
loadImageFromUrl(state.userInfo.photoUrl) loadImageFromUrl(state.userInfo.photoUrl)
val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()) val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
@ -107,7 +117,8 @@ class MainFragment : Fragment(R.layout.fragment_main) {
try { try {
val parsedDate = inputFormat.parse(state.userInfo.lastVisit) val parsedDate = inputFormat.parse(state.userInfo.lastVisit)
lastEntry.text = parsedDate?.let { outputFormat.format(it) } ?: state.userInfo.lastVisit lastEntry.text = parsedDate?.let { outputFormat.format(it) }
?: state.userInfo.lastVisit
} catch (e: Exception) { } catch (e: Exception) {
lastEntry.text = state.userInfo.lastVisit lastEntry.text = state.userInfo.lastVisit
} }
@ -125,13 +136,13 @@ class MainFragment : Fragment(R.layout.fragment_main) {
viewModel.listState.collectWhenStarted(this) { state -> viewModel.listState.collectWhenStarted(this) { state ->
when (state) { when (state) {
is MainViewModel.ListState.Loading -> { is MainViewModel.ListState.Loading -> {
//TODO hideAll()
} }
is MainViewModel.ListState.Success -> { is MainViewModel.ListState.Success -> {
listAdapter.submitList(state.data) listAdapter.submitList(state.data)
} }
is MainViewModel.ListState.Error -> { is MainViewModel.ListState.Error -> {
//TODO hideAll()
binding.error.text = state.message binding.error.text = state.message
} }
} }
@ -139,11 +150,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
} }
private fun loadImageFromUrl(url: String) { private fun loadImageFromUrl(url: String) {
Picasso
.get()
.load(url)
.error(R.drawable.icon_profile)
.into(binding.photo)
} }
private fun setupMainComponents() { private fun setupMainComponents() {
@ -152,6 +159,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
navigateToLogin() navigateToLogin()
} }
binding.admin.setOnClickListener {
navigateToAdmin()
}
binding.refresh.setOnClickListener { binding.refresh.setOnClickListener {
viewModel.getUserData(authPreferences.getLogin() ?: "") viewModel.getUserData(authPreferences.getLogin() ?: "")
} }
@ -173,6 +184,19 @@ class MainFragment : Fragment(R.layout.fragment_main) {
} }
} }
private fun navigateToAdmin() {
try {/*
authPreferences.clearLoginState()
findNavController().apply {
popBackStack(AdminDestination, false)
navigate(AdminDestination)
}*/
} catch (e: Exception) {
Log.e("MainFragment", "Error navigating to login", e)
}
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null

View File

@ -36,12 +36,15 @@ class MainViewModel @Inject constructor(
when { when {
response.isSuccessful -> { response.isSuccessful -> {
val userInfo = response.body() ?: UserInfo.Initial val userInfo = response.body()
_state.value = MainState.Success(userInfo) _state.value = userInfo?.let { MainState.Success(it) }!!
} }
response.code() == 401 -> { response.code() == 401 -> {
_state.value = MainState.Error("Unauthorized") _state.value = MainState.Error("Unauthorized")
} }
response.code() == 403 -> {
_state.value = MainState.Error("Block")
}
else -> { else -> {
_state.value = MainState.Error("Error") _state.value = MainState.Error("Error")
} }

View File

@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M17,11c0.34,0 0.67,0.04 1,0.09V6.27L10.5,3L3,6.27v4.91c0,4.54 3.2,8.79 7.5,9.82c0.55,-0.13 1.08,-0.32 1.6,-0.55C11.41,19.47 11,18.28 11,17C11,13.69 13.69,11 17,11z"/>
<path android:fillColor="@android:color/white" android:pathData="M17,13c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C21,14.79 19.21,13 17,13zM17,14.38c0.62,0 1.12,0.51 1.12,1.12s-0.51,1.12 -1.12,1.12s-1.12,-0.51 -1.12,-1.12S16.38,14.38 17,14.38zM17,19.75c-0.93,0 -1.74,-0.46 -2.24,-1.17c0.05,-0.72 1.51,-1.08 2.24,-1.08s2.19,0.36 2.24,1.08C18.74,19.29 17.93,19.75 17,19.75z"/>
</vector>

View File

@ -33,13 +33,14 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<View <View
android:id="@+id/admin" android:id="@+id/admin"
android:layout_width="44dp" android:layout_width="44dp"
android:layout_height="44dp" android:layout_height="44dp"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:background="@drawable/ic_admin" android:background="@drawable/baseline_admin_panel_settings_24"
app:layout_constraintEnd_toStartOf="@+id/refresh" app:layout_constraintEnd_toStartOf="@+id/refresh"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />