Skip to content
This repository was archived by the owner on Jul 15, 2023. It is now read-only.

Commit 6baf22f

Browse files
author
Ворожцов Михаил Александрович
committed
Merge branch 'feature/hse-auth-engine' into 'develop'
Feature/hse auth engine See merge request 19111/androidodoo!27
2 parents b5f7b9f + e019595 commit 6baf22f

File tree

31 files changed

+613
-105
lines changed

31 files changed

+613
-105
lines changed

common/network/authorization/api/src/main/kotlin/odoo/miem/android/common/network/authorization/api/IAuthorizationInteractor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ interface IAuthorizationInteractor {
1919
*
2020
* @return Observable<Result> which we can observer and get Success or Error result
2121
*/
22-
fun generalAuthorization(baseUrl: String, login: String, password: String): ResultSingle<Int>
22+
fun generalAuthorization(baseUrl: String, login: String, password: String): ResultSingle<Unit>
2323
}

common/network/authorization/impl/src/main/kotlin/odoo/miem/android/common/network/authorization/impl/AuthorizationInteractor.kt

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import odoo.miem.android.common.network.authorization.api.IAuthorizationInteract
44
import odoo.miem.android.common.network.authorization.api.di.IAuthorizationRepositoryApi
55
import odoo.miem.android.core.dataStore.api.di.IDataStoreApi
66
import odoo.miem.android.core.di.impl.api
7+
import odoo.miem.android.core.utils.builder.urlProcessing
8+
import odoo.miem.android.core.utils.regex.getSessionIdFromCookie
79
import odoo.miem.android.core.utils.state.ErrorResult
810
import odoo.miem.android.core.utils.state.Result
911
import odoo.miem.android.core.utils.state.ResultSingle
@@ -25,45 +27,36 @@ class AuthorizationInteractor @Inject constructor() : IAuthorizationInteractor {
2527
baseUrl: String,
2628
login: String,
2729
password: String
28-
): ResultSingle<Int> {
30+
): ResultSingle<Unit> {
2931
Timber.d("generalAuthorization(): baseUrl = $baseUrl, login = $login, password = $password")
3032

31-
dataStore.setHseAuthorized(false)
3233
dataStore.setUrl(proceedUrl(baseUrl))
3334

3435
return authorizationRepository.generalAuthorization(
3536
login = login,
3637
password = password
3738
)
38-
.map<Result<Int>> {
39-
Timber.d("generalAuthorization(): uid = $it")
40-
dataStore.setUID(it)
41-
SuccessResult(data = it)
39+
.map<Result<Unit>> { cookie ->
40+
Timber.d("generalAuthorization(): sessionId = $cookie")
41+
dataStore.setAuthorized(true)
42+
dataStore.setSessionId(
43+
cookie.split(COOKIE_SPLIT_SIGN)
44+
.find { it.contains(FIELD_SESSION_ID) }
45+
.orEmpty()
46+
.getSessionIdFromCookie()
47+
)
48+
SuccessResult()
4249
}
4350
.onErrorReturn {
4451
Timber.e("generalAuthorization(): error message = ${it.message}")
4552
ErrorResult(R.string.general_authorization_error)
4653
}
4754
}
4855

49-
private fun proceedUrl(inputUrl: String): String {
50-
var proceededUrl = if (!inputUrl.run { startsWith("https://") || startsWith("http://") }) {
51-
"https://"
52-
} else {
53-
""
54-
} + inputUrl.trim()
56+
private fun proceedUrl(inputUrl: String): String = "${urlProcessing(inputUrl)}web/"
5557

56-
if (!inputUrl.endsWith("/")) {
57-
proceededUrl += "/"
58-
}
59-
60-
return proceededUrl + urlSuffix
58+
private companion object {
59+
const val COOKIE_SPLIT_SIGN = ";"
60+
const val FIELD_SESSION_ID = "session_id"
6161
}
62-
63-
private val urlSuffix: String
64-
get() = if (dataStore.isHseAuthorized) {
65-
"web/datastore/"
66-
} else {
67-
"jsonrpc/"
68-
}
6962
}

common/uiKitComponents/src/main/kotlin/odoo/miem/android/common/uiKitComponents/textfields/BaseTextField.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fun BaseTextField(
3535
keyboardType: KeyboardType = KeyboardType.Text,
3636
@StringRes labelResource: Int,
3737
leadingIcon: @Composable (() -> Unit)? = null,
38+
placeholder: @Composable (() -> Unit)? = null,
3839
modifier: Modifier = Modifier,
3940
enabled: Boolean = true,
4041
onValueChange: (TextFieldValue) -> Unit = {},
@@ -52,6 +53,7 @@ fun BaseTextField(
5253
enabled = enabled,
5354
singleLine = true,
5455
label = { Text(text = stringResource(labelResource), style = MaterialTheme.typography.bodyMedium) },
56+
placeholder = placeholder,
5557
visualTransformation = visualTransformation,
5658
keyboardOptions = KeyboardOptions(keyboardType = keyboardType, imeAction = imeAction),
5759
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),

common/uiKitComponents/src/main/kotlin/odoo/miem/android/common/uiKitComponents/textfields/LoginTextField.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fun LoginTextField(
4141
visualTransformation: VisualTransformation = VisualTransformation.None,
4242
imeAction: ImeAction = ImeAction.Done,
4343
isError: Boolean = false,
44+
placeholder: @Composable (() -> Unit)? = null,
4445
modifier: Modifier = Modifier
4546
) {
4647
var isPasswordVisible by remember { mutableStateOf(false) }
@@ -84,6 +85,7 @@ fun LoginTextField(
8485
trailingIcon = trailingIcon,
8586
imeAction = imeAction,
8687
isError = isError,
88+
placeholder = placeholder,
8789
modifier = modifier
8890
)
8991
}

core/dataStore/api/src/main/kotlin/odoo/miem/android/core/dataStore/api/IDataStore.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ interface IDataStore {
2020
val currentUID: Int
2121
fun setUID(uid: Int)
2222

23-
val isHseAuthorized: Boolean
24-
fun setHseAuthorized(authorized: Boolean)
23+
val isAuthorized: Boolean
24+
fun setAuthorized(authorized: Boolean)
25+
26+
val sessionId: String
27+
fun setSessionId(newSessionId: String)
2528
}

core/dataStore/impl/src/main/kotlin/odoo/miem/android/core/dataStore/impl/DataStore.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,26 @@ class DataStore @Inject constructor() : IDataStore {
4545
}
4646
}
4747

48-
override val isHseAuthorized by sharedPreferences.delegates.boolean()
49-
override fun setHseAuthorized(authorized: Boolean) {
50-
if (authorized != isHseAuthorized) {
48+
override val isAuthorized by sharedPreferences.delegates.boolean()
49+
override fun setAuthorized(authorized: Boolean) {
50+
if (authorized != isAuthorized) {
5151
sharedPreferences.edit {
52-
putBoolean(::isHseAuthorized.name, authorized)
52+
putBoolean(::isAuthorized.name, authorized)
5353
}
5454
Timber.d("setHseAuthorized(): authorized = $authorized")
5555
}
5656
}
5757

58+
override val sessionId by sharedPreferences.delegates.string()
59+
override fun setSessionId(newSessionId: String) {
60+
if (newSessionId != sessionId) {
61+
sharedPreferences.edit {
62+
putString(::sessionId.name, newSessionId)
63+
}
64+
Timber.d("setSessionId(): sessionId = $newSessionId")
65+
}
66+
}
67+
5868
private companion object {
5969
const val PREFERENCES_NAME = "dataStore"
6070
}

core/jsonrpc/README.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Json Rpc
2+
3+
## Description
4+
This module is a Retrofit implementation of a similar add-on on Okhttp. It consists of 4 submodules:
5+
- [base](core/jsonrpc/base) - contains protocols, base interfaces for implementation and errors
6+
- [core](core/jsonrpc/core) - special module, for external consumers, so **if you want to use this library, just include it**
7+
- [engine](core/jsonrpc/engine) - main module of library, which contain all implementations of [base](core/jsonrpc/base)
8+
- [parser](core/jsonrpc/parser) - module, which contains parser for request and response result
9+
10+
## Details about creating request
11+
So, in the basic scenario, you will need to create the following request body:
12+
```
13+
{
14+
'jsonrpc': '2.0',
15+
'id': 1,
16+
'method': 'your_method',
17+
'params': {
18+
'model': 'your_model',
19+
'method': 'your_model_method',
20+
'args': [
21+
[('filter', '=', 'your_filter')],
22+
['your_args']
23+
],
24+
'kwargs': {
25+
'your_kwargs_key' : 'your_kwargs_value'
26+
}
27+
}
28+
}
29+
```
30+
31+
Let's go by step:
32+
- `jsonrpc` - will always (99%) `2.0`, that is why this value is default
33+
- `id` - this value will generate engine, therefore you do not need to set it
34+
- `method` - method of execution (default value is `call`)
35+
- `params` - parameters by which the request will be executed:
36+
- `model` - the model you are referring to (for example, `res.partner`)
37+
- `method` - method **IN MODEL** (for example, `search_read`)
38+
- `args` - additional arguments for filtering out your request. For example, if you want to have a results only with filed `active=true`
39+
and view only `id`, your args should be:
40+
```
41+
'args': [
42+
[('active', '=', 'true')],
43+
['id']
44+
],
45+
```
46+
- `kwargs` - addition keyword arguments. For example, if you want to see only first 5 records:
47+
```
48+
'kwargs': {
49+
'limit' : 5
50+
}
51+
```
52+
53+
## Example
54+
Let's try to create such response body with a help of library:
55+
```
56+
{
57+
'jsonrpc': '2.0',
58+
'id': 1,
59+
'method': 'call',
60+
'params': {
61+
'model': 'ir.ui.menu',
62+
'method': 'search_read',
63+
'args': [
64+
[('active', '=', 'true')],
65+
['id'],
66+
],
67+
'kwargs': {},
68+
}
69+
}
70+
```
71+
72+
Firstly, we need to create *IMenusRepository* by url `https://odoo.miem.tv/web/dataset/`:
73+
```kotlin
74+
interface IMenusRepository {
75+
76+
@JsonRpc("call")
77+
fun getMenus(
78+
@JsonRpcPath path: String = "web/dataset",
79+
@JsonRpcArgument("model") model: String = "ir.ui.menu",
80+
@JsonRpcArgument("method") modelMethod: String = "search_read",
81+
@JsonRpcArgument("args") args: List<Any> = listOf(
82+
listOf<String>("active", "=", "true"),
83+
listOf<String>("id")
84+
),
85+
@JsonRpcArgument("kwargs") kwargs: Map<String, Any> = emptyMap()
86+
)
87+
}
88+
```
89+
90+
Secondly, just create instance of this interface, using [JsonRpcClient](core/jsonrpc/core/src/main/kotlin/odoo/miem/android/core/jsonrpc/core/JsonRpcClient.kt):
91+
```kotlin
92+
val jsonRpcClient = JsonRpcClient.Builder()
93+
.baseUrl("https://odoo.miem.tv/")
94+
.build()
95+
96+
val menuRepository = jsonRpcClient.create(IMenusRepository::class.java)
97+
// or it is also possible like that: val menuInterface by jsonRpcClient.create<IMenusRepository::class.java>()
98+
```
99+
100+
And finally, call method (it is network call, so you asynchronous tools, like coroutines or rxjava):
101+
```kotlin
102+
val menus = menuRepository.getMenus()
103+
```
104+
105+
## Alertness
106+
Without any doubt this type of json body can change to suit your needs as you like

core/jsonrpc/base/src/main/kotlin/odoo/miem/android/core/jsonrpc/base/engine/JsonRpcCaller.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package odoo.miem.android.core.jsonrpc.base.engine
22

33
import odoo.miem.android.core.jsonrpc.base.engine.protocol.JsonRpcRequest
44
import odoo.miem.android.core.jsonrpc.base.engine.protocol.JsonRpcResponse
5+
import okhttp3.Response
56

67
/**
78
* [JsonRpcCaller] is a client, with a help of which
@@ -29,6 +30,7 @@ interface JsonRpcCaller {
2930
fun call(
3031
jsonRpcRequest: JsonRpcRequest,
3132
headers: Map<String, String> = emptyMap(),
32-
paths: List<String> = emptyList()
33+
paths: List<String> = emptyList(),
34+
onResponseProceed: ((id: Long, Response) -> JsonRpcResponse)? = null
3335
): JsonRpcResponse
3436
}

core/jsonrpc/base/src/main/kotlin/odoo/miem/android/core/jsonrpc/base/engine/annotation/JsonRpc.kt

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,12 @@ package odoo.miem.android.core.jsonrpc.base.engine.annotation
1717
* { "id": 1, "method": "call", .... }
1818
* ```
1919
*
20-
* ATTENTION
21-
* Depending on the type of authorization (hse or general, for example),
22-
* this method will be in body of `params` map or like in example above
23-
*
2420
* @author Vorozhtsov Mikhail
2521
*/
2622
annotation class JsonRpc(val value: String)
2723

2824
/**
29-
* [JsonArgument] is annotation, which provide parameters
25+
* [JsonRpcArgument] is annotation, which provide parameters
3026
* in `params` field of json body.
3127
*
3228
* @param value contains name of field
@@ -35,7 +31,7 @@ annotation class JsonRpc(val value: String)
3531
* ```
3632
* @JsonRpc("call")
3733
* fun getCoolUser(
38-
* @JsonArgument("name") name: String = "Mike"
34+
* @JsonRpcArgument("name") name: String = "Mike"
3935
* ): User
4036
* ```
4137
*
@@ -46,4 +42,36 @@ annotation class JsonRpc(val value: String)
4642
*
4743
* @author Vorozhtsov Mikhail
4844
*/
49-
annotation class JsonArgument(val value: String)
45+
annotation class JsonRpcArgument(val value: String)
46+
47+
/**
48+
* [JsonRpcPath] is annotation, which provide path in request url
49+
*
50+
*
51+
* For example:
52+
* ```
53+
* val baseUrl = "https://odoo.com/"
54+
*
55+
* @JsonRpc("call")
56+
* fun getCoolUser(
57+
* @JsonRpcPath path: String = "web"
58+
* @JsonRpcPath path: String = "dataset"
59+
* ): User
60+
* ```
61+
*
62+
* So, in example above final url will be:
63+
* ```
64+
* https://odoo.com/web/dataset/
65+
* ```
66+
*
67+
* It is also possible make path, and we will have same result url:
68+
* ```
69+
* @JsonRpc("call")
70+
* fun getCoolUser(
71+
* @JsonRpcPath path: String = "web/dataset"
72+
* ): User
73+
* ```
74+
*
75+
* @author Vorozhtsov Mikhail
76+
*/
77+
annotation class JsonRpcPath

0 commit comments

Comments
 (0)