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("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("androidx.datastore:datastore-preferences:1.1.2")
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.components.SingletonComponent
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.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain
@ -45,4 +46,10 @@ object NetworkModule {
fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList {
return retrofitClient.getApiServiceList()
}
@Provides
@Singleton
fun provideApiServiceAdmin(retrofitClient: RetrofitClient): ApiServiceAdmin {
return retrofitClient.getApiServiceAdmin()
}
}

View File

@ -1,11 +1,11 @@
package ru.myitschool.work.api
import android.content.Context
import com.google.android.datatransport.BuildConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import ru.myitschool.work.api.admin.ApiServiceAdmin
import ru.myitschool.work.api.list.ApiServiceList
import ru.myitschool.work.api.login.ApiServiceLogin
import ru.myitschool.work.api.main.ApiServiceMain
@ -57,4 +57,8 @@ class RetrofitClient(context: Context) {
fun getApiServiceList(): ApiServiceList {
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
interface ApiServiceList {
@GET("api/list/{login}")
@GET("api/user/list/{login}")
suspend fun getList(@Path("login") login: String): Response<List<ListInfo>>
}

View File

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

View File

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

View File

@ -9,15 +9,16 @@ data class UserInfo(
@SerializedName("photo") val photoUrl: String,
@SerializedName("position") val position: String,
@SerializedName("lastVisit") val lastVisit: String,
) {
companion object {
val Initial = UserInfo(
id = 0,
login = "",
name = "",
photoUrl = "",
position = "",
lastVisit = "",
@SerializedName("authority") val authority: List<AuthorityData>
)
}
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
interface ApiServiceScan {
@POST("api/add/{login}")
@POST("api/user/add/{login}")
fun open(@Path("login") login: String, @Body data: CodeJson): Call<Void>
}

View File

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

View File

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

View File

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

View File

@ -8,9 +8,9 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import ru.myitschool.work.R
import ru.myitschool.work.api.main.Authorities
import ru.myitschool.work.databinding.FragmentMainBinding
import ru.myitschool.work.ui.list.ListAdapter
import ru.myitschool.work.ui.login.LoginDestination
@ -100,6 +100,16 @@ class MainFragment : Fragment(R.layout.fragment_main) {
username.text = state.userInfo.name
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)
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 {
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) {
lastEntry.text = state.userInfo.lastVisit
}
@ -125,13 +136,13 @@ class MainFragment : Fragment(R.layout.fragment_main) {
viewModel.listState.collectWhenStarted(this) { state ->
when (state) {
is MainViewModel.ListState.Loading -> {
//TODO
hideAll()
}
is MainViewModel.ListState.Success -> {
listAdapter.submitList(state.data)
}
is MainViewModel.ListState.Error -> {
//TODO
hideAll()
binding.error.text = state.message
}
}
@ -139,11 +150,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
}
private fun loadImageFromUrl(url: String) {
Picasso
.get()
.load(url)
.error(R.drawable.icon_profile)
.into(binding.photo)
}
private fun setupMainComponents() {
@ -152,6 +159,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {
navigateToLogin()
}
binding.admin.setOnClickListener {
navigateToAdmin()
}
binding.refresh.setOnClickListener {
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() {
super.onDestroyView()
_binding = null

View File

@ -36,12 +36,15 @@ class MainViewModel @Inject constructor(
when {
response.isSuccessful -> {
val userInfo = response.body() ?: UserInfo.Initial
_state.value = MainState.Success(userInfo)
val userInfo = response.body()
_state.value = userInfo?.let { MainState.Success(it) }!!
}
response.code() == 401 -> {
_state.value = MainState.Error("Unauthorized")
}
response.code() == 403 -> {
_state.value = MainState.Error("Block")
}
else -> {
_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_constraintTop_toTopOf="parent" />
<View
android:id="@+id/admin"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginTop="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_constraintTop_toTopOf="parent" />