• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

opensrp / opensrp-client-core / #182

08 Aug 2024 12:55PM UTC coverage: 68.316% (-0.08%) from 68.395%
#182

Pull #925

github

web-flow
Merge 0883be0a0 into 4fcf06cf5
Pull Request #925: migrate SyncserviceJob to work manager

18308 of 26799 relevant lines covered (68.32%)

0.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.43
opensrp-core/src/main/java/org/smartregister/login/interactor/BaseLoginInteractor.java
1
package org.smartregister.login.interactor;
2

3
import static org.smartregister.domain.LoginResponse.INVALID_GRANT;
4
import static org.smartregister.domain.LoginResponse.NO_INTERNET_CONNECTIVITY;
5
import static org.smartregister.domain.LoginResponse.UNAUTHORIZED;
6
import static org.smartregister.domain.LoginResponse.UNKNOWN_RESPONSE;
7

8
import android.content.Context;
9
import android.content.DialogInterface;
10
import android.content.Intent;
11

12
import androidx.annotation.VisibleForTesting;
13

14
import org.apache.commons.lang3.StringUtils;
15
import org.joda.time.DateTime;
16
import org.json.JSONArray;
17
import org.json.JSONException;
18
import org.json.JSONObject;
19
import org.smartregister.AllConstants;
20
import org.smartregister.CoreLibrary;
21
import org.smartregister.P2POptions;
22
import org.smartregister.R;
23
import org.smartregister.account.AccountAuthenticatorXml;
24
import org.smartregister.account.AccountHelper;
25
import org.smartregister.domain.LoginResponse;
26
import org.smartregister.domain.TimeStatus;
27
import org.smartregister.event.Listener;
28
import org.smartregister.job.P2pServiceJob;
29
import org.smartregister.job.PullUniqueIdsServiceJob;
30
import org.smartregister.job.SyncSettingsServiceJob;
31
import org.smartregister.job.SyncSettingsServiceWorker;
32
import org.smartregister.login.task.LocalLoginTask;
33
import org.smartregister.login.task.RemoteLoginTask;
34
import org.smartregister.multitenant.ResetAppHelper;
35
import org.smartregister.repository.AllSharedPreferences;
36
import org.smartregister.service.UserService;
37
import org.smartregister.sync.helper.ServerSettingsHelper;
38
import org.smartregister.sync.intent.SettingsSyncIntentService;
39
import org.smartregister.util.NetworkUtils;
40
import org.smartregister.view.activity.ChangePasswordActivity;
41
import org.smartregister.view.activity.DrishtiApplication;
42
import org.smartregister.view.contract.BaseLoginContract;
43

44
import java.lang.ref.WeakReference;
45
import java.net.HttpURLConnection;
46
import java.util.TimeZone;
47
import java.util.concurrent.ExecutorService;
48
import java.util.concurrent.Executors;
49

50
import timber.log.Timber;
51

52
/**
53
 * Created by ndegwamartin on 26/06/2018.
54
 */
55
public abstract class BaseLoginInteractor implements BaseLoginContract.Interactor {
56

57
    private static final int MINIMUM_JOB_FLEX_VALUE = 5;
58
    private BaseLoginContract.Presenter mLoginPresenter;
59
    private RemoteLoginTask remoteLoginTask;
60
    private boolean isLocalLogin;
61

62
    private ResetAppHelper resetAppHelper;
63

64
    public BaseLoginInteractor(BaseLoginContract.Presenter loginPresenter) {
1✔
65
        this.mLoginPresenter = loginPresenter;
1✔
66
        resetAppHelper = new ResetAppHelper(DrishtiApplication.getInstance());
1✔
67
    }
1✔
68

69
    @Override
70
    public void onDestroy(boolean isChangingConfiguration) {
71
        if (!isChangingConfiguration) {
1✔
72
            mLoginPresenter = null;
1✔
73
        }
74
    }
1✔
75

76
    @Override
77
    public void login(WeakReference<BaseLoginContract.View> view, String userName, char[] password) {
78
        getLoginView().showProgress(true);
1✔
79
        ExecutorService executorService = Executors.newSingleThreadExecutor();
1✔
80
        executorService.execute(() -> {
1✔
81

82
            isLocalLogin = !getSharedPreferences().fetchForceRemoteLogin(userName);
1✔
83
            org.smartregister.Context opensrpContext = CoreLibrary.getInstance().context();
1✔
84
            if (NetworkUtils.isNetworkAvailable() && (isRefreshTokenExpired(userName) || (opensrpContext.getAppProperties().getPropertyBoolean(AllConstants.PROPERTY.ALLOW_OFFLINE_LOGIN_WITH_INVALID_TOKEN)
1✔
85
                    && isLocalLogin
86
                    && HttpURLConnection.HTTP_UNAUTHORIZED == getSharedPreferences().getLastAuthenticationHttpStatus()))) {
×
87
                isLocalLogin = false;
×
88
            }
89

90
            getLoginView().getAppCompatActivity().runOnUiThread(() -> loginWithLocalFlag(view, isLocalLogin && getSharedPreferences().isRegisteredANM(userName), userName, password));
1✔
91

92
        });
1✔
93
    }
1✔
94

95
    @VisibleForTesting
96
    protected boolean isRefreshTokenExpired(String userName) {
97
        return !AccountHelper.isRefreshTokenValid(userName, CoreLibrary.getInstance().getAccountAuthenticatorXml().getAccountType());
×
98
    }
99

100
    public void loginWithLocalFlag(WeakReference<BaseLoginContract.View> view, boolean localLogin, String userName, char[] password) {
101

102
        getLoginView().hideKeyboard();
1✔
103
        getLoginView().enableLoginButton(false);
1✔
104
        if (localLogin) {
1✔
105
            localLogin(view, userName, password);
1✔
106
        } else {
107
            remoteLogin(userName, password, CoreLibrary.getInstance().getAccountAuthenticatorXml());
1✔
108
        }
109

110
        Timber.i("Login result finished " + DateTime.now());
1✔
111
    }
1✔
112

113
    private void localLogin(WeakReference<BaseLoginContract.View> view, String userName, char[] password) {
114
        getLoginView().enableLoginButton(true);
1✔
115

116
        new LocalLoginTask(view.get(), userName, password, isAuthenticated -> {
1✔
117

118
            if (!isAuthenticated) {
1✔
119

120
                getLoginView().showErrorDialog(getApplicationContext().getResources().getString(R.string.unauthorized));
1✔
121

122
            } else if (isAuthenticated && isValidTimecheck(getUserService().validateStoredServerTimeZone())) {
1✔
123

124
                navigateToHomePage(userName);
1✔
125

126
            } else {
127
                loginWithLocalFlag(view, false, userName, password);
×
128
            }
129

130

131
        }).execute();
1✔
132

133
    }
1✔
134

135
    private void navigateToHomePage(String userName) {
136

137
        getUserService().localLoginWith(userName);
1✔
138

139
        if (mLoginPresenter != null) {
1✔
140
            getLoginView().goToHome(false);
1✔
141
        }
142

143
        CoreLibrary.getInstance().initP2pLibrary(userName);
1✔
144

145
        new Thread(() -> {
1✔
146
            Timber.i("Starting DrishtiSyncScheduler " + DateTime.now().toString());
1✔
147

148
            scheduleJobsImmediately();
1✔
149

150
            Timber.i("Started DrishtiSyncScheduler " + DateTime.now().toString());
1✔
151

152
            CoreLibrary.getInstance().context().getUniqueIdRepository().releaseReservedIds();
1✔
153
        }).start();
1✔
154
    }
1✔
155

156
    private void remoteLogin(final String userName, final char[] password, final AccountAuthenticatorXml accountAuthenticatorXml) {
157

158
        try {
159
            if (getSharedPreferences().fetchBaseURL("").isEmpty() && StringUtils.isNotBlank(this.getApplicationContext().getString(R.string.opensrp_url))) {
1✔
160
                getSharedPreferences().savePreference("DRISHTI_BASE_URL", getApplicationContext().getString(R.string.opensrp_url));
1✔
161
            }
162
            if (!getSharedPreferences().fetchBaseURL("").isEmpty()) {
1✔
163

164
                tryRemoteLogin(userName, password, accountAuthenticatorXml, loginResponse -> {
1✔
165

166
                    getLoginView().enableLoginButton(true);
1✔
167

168
                    if (loginResponse == LoginResponse.SUCCESS) {
1✔
169

170
                        String username = getUsername(userName, loginResponse);
1✔
171

172
                        if (getUserService().isUserInPioneerGroup(username)) {
1✔
173

174
                            TimeStatus timeStatus = getUserService().validateDeviceTime(loginResponse.payload(), AllConstants.MAX_SERVER_TIME_DIFFERENCE);
1✔
175

176
                            if (isValidTimecheck(timeStatus)) {
1✔
177

178
                                postProcessRemoteLoginSuccess(username, loginResponse);
1✔
179

180
                            } else {
181

182
                                postProcessRemoteLoginServerTimeMismatch(timeStatus, loginResponse);
1✔
183
                            }
184
                        } else {
1✔
185

186
                            if (CoreLibrary.getInstance().getSyncConfiguration().clearDataOnNewTeamLogin()) {
1✔
187
                                getLoginView().showClearDataDialog((dialog, which) -> {
1✔
188

189
                                    dialog.dismiss();
1✔
190

191
                                    if (which == DialogInterface.BUTTON_POSITIVE) {
1✔
192
                                        resetAppHelper.startResetProcess(getLoginView().getAppCompatActivity(), () -> login(new WeakReference<>(getLoginView()), userName, mLoginPresenter.getPassword()));
1✔
193
                                    }
194
                                });
1✔
195
                            } else {
196
                                // Valid user from wrong group trying to log in
197
                                getLoginView().showErrorDialog(getApplicationContext().getString(R.string.unauthorized_group));
1✔
198
                            }
199

200
                        }
201
                    } else {
1✔
202
                        if (loginResponse == null) {
1✔
203
                            getLoginView().showErrorDialog(getApplicationContext().getString(R.string.remote_login_generic_error));
1✔
204
                        } else {
205
                            if (loginResponse == NO_INTERNET_CONNECTIVITY) {
1✔
206
                                getLoginView().showErrorDialog(getApplicationContext().getResources().getString(R.string.no_internet_connectivity));
1✔
207
                            } else if (loginResponse == UNKNOWN_RESPONSE) {
1✔
208
                                getLoginView().showErrorDialog(getApplicationContext().getResources().getString(R.string.unknown_response));
1✔
209
                            } else if (loginResponse == UNAUTHORIZED) {
1✔
210
                                getLoginView().showErrorDialog(getApplicationContext().getResources().getString(R.string.unauthorized));
1✔
211
                            } else if (loginResponse == INVALID_GRANT) {
1✔
212
                                String pwdResetEndpoint = loginResponse.getRawData() != null ? loginResponse.getRawData().optString(AccountHelper.CONFIGURATION_CONSTANTS.ISSUER_ENDPOINT_URL) : "";
1✔
213
                                showPasswordResetView(pwdResetEndpoint);
1✔
214
                            } else {
1✔
215
                                getLoginView().showErrorDialog(loginResponse.message());
1✔
216
                            }
217
                        }
218
                    }
219
                });
1✔
220
            } else {
221
                getLoginView().enableLoginButton(true);
1✔
222
                getLoginView().showErrorDialog(getApplicationContext().getString(R.string.remote_login_base_url_missing_error));
1✔
223
            }
224
        } catch (Exception e) {
1✔
225
            Timber.e(e);
1✔
226
            getLoginView().showErrorDialog(getApplicationContext().getString(R.string.remote_login_generic_error));
1✔
227
        }
1✔
228
    }
1✔
229

230
    private boolean isValidTimecheck(TimeStatus timeStatus) {
231
        return !CoreLibrary.getInstance().isTimecheckDisabled() || TimeStatus.OK.equals(timeStatus);
1✔
232
    }
233

234
    private void postProcessRemoteLoginServerTimeMismatch(TimeStatus timeStatus, LoginResponse loginResponse) {
235
        if (timeStatus.equals(TimeStatus.TIMEZONE_MISMATCH)) {
1✔
236

237
            TimeZone serverTimeZone = UserService.getServerTimeZone(loginResponse.payload());
1✔
238
            getLoginView().showErrorDialog(getApplicationContext().getString(timeStatus.getMessage(), serverTimeZone.getDisplayName()));
1✔
239

240
        } else {
1✔
241
            getLoginView().showErrorDialog(getApplicationContext().getString(timeStatus.getMessage()));
1✔
242
        }
243
    }
1✔
244

245
    private String getUsername(String userName, LoginResponse loginResponse) {
246
        return loginResponse.payload() != null && loginResponse.payload().user != null && StringUtils.isNotBlank(loginResponse.payload().user.getUsername())
1✔
247
                ? loginResponse.payload().user.getUsername() : userName;
1✔
248
    }
249

250
    private void tryRemoteLogin(final String userName, final char[] password, final AccountAuthenticatorXml accountAuthenticatorXml, final Listener<LoginResponse> afterLogincheck) {
251
        if (remoteLoginTask != null && !remoteLoginTask.isCancelled()) {
1✔
252
            remoteLoginTask.cancel(true);
1✔
253
        }
254
        remoteLoginTask = new RemoteLoginTask(getLoginView(), userName, password, accountAuthenticatorXml, afterLogincheck);
1✔
255
        remoteLoginTask.execute();
1✔
256
    }
1✔
257

258
    private void postProcessRemoteLoginSuccess(String userName, LoginResponse loginResponse) {
259
        getUserService().processLoginResponseDataForUser(userName, loginResponse.payload());
1✔
260
        processServerSettings(loginResponse);
1✔
261

262
        scheduleJobsPeriodically();
1✔
263
        scheduleJobsImmediately();
1✔
264

265
        CoreLibrary.getInstance().initP2pLibrary(userName);
1✔
266

267
        getLoginView().goToHome(true);
1✔
268
    }
1✔
269

270
    public Context getApplicationContext() {
271
        return getLoginView().getActivityContext();
1✔
272
    }
273

274
    public AllSharedPreferences getSharedPreferences() {
275
        return mLoginPresenter != null && mLoginPresenter.getOpenSRPContext() != null ? mLoginPresenter.getOpenSRPContext().allSharedPreferences() : null;
1✔
276
    }
277

278
    public BaseLoginContract.View getLoginView() {
279
        return mLoginPresenter != null ? mLoginPresenter.getLoginView() : null;
1✔
280
    }
281

282
    public UserService getUserService() {
283
        return CoreLibrary.getInstance().context().userService();
1✔
284
    }
285

286
    /**
287
     * Add all the metnods that should be scheduled remotely
288
     */
289
    protected abstract void scheduleJobsPeriodically();
290

291
    /**
292
     * Sync and pull unique ids are scheduleds by default.
293
     * Call super if you override this method.
294
     */
295
    protected void scheduleJobsImmediately() {
296
        P2POptions p2POptions = CoreLibrary.getInstance().getP2POptions();
1✔
297
        if (p2POptions != null && p2POptions.isEnableP2PLibrary()) {
1✔
298
            // Finish processing any unprocessed sync records here
299
            P2pServiceJob.scheduleJobImmediately(P2pServiceJob.TAG);
×
300
        }
301

302
        if (NetworkUtils.isNetworkAvailable()) {
1✔
303
            PullUniqueIdsServiceJob.scheduleJobImmediately(PullUniqueIdsServiceJob.TAG);
×
304
            SyncSettingsServiceWorker.enqueueOnetimeSettingsSyncIntentService(getApplicationContext());
×
305
        }
306
    }
1✔
307

308
    protected long getFlexValue(int value) {
309
        int minutes = MINIMUM_JOB_FLEX_VALUE;
1✔
310

311
        if (value > MINIMUM_JOB_FLEX_VALUE) {
1✔
312

313
            minutes = (int) Math.ceil(value / 3);
1✔
314
        }
315

316
        return minutes < MINIMUM_JOB_FLEX_VALUE ? MINIMUM_JOB_FLEX_VALUE : minutes;
1✔
317
    }
318

319
    //Always call super.processServerSettings( ) if you ever Override this
320
    protected void processServerSettings(LoginResponse loginResponse) {
321
        JSONObject data = loginResponse.getRawData();
1✔
322

323
        if (data != null) {
1✔
324
            try {
325

326
                JSONArray settings = data.has(AllConstants.PREF_KEY.SETTINGS) ? data.getJSONArray(AllConstants.PREF_KEY.SETTINGS) : null;
1✔
327

328
                if (settings != null && settings.length() > 0) {
1✔
329
                    ServerSettingsHelper.saveSetting(settings);
1✔
330
                }
331

332
            } catch (JSONException e) {
×
333
                Timber.e(e);
×
334

335
            }
1✔
336
        }
337
    }
1✔
338

339
    @Override
340
    public void showPasswordResetView(String passwordResetEndpoint) {
341
        Intent intent = new Intent(getLoginView().getActivityContext(), ChangePasswordActivity.class);
1✔
342
        intent.putExtra(AccountHelper.CONFIGURATION_CONSTANTS.ISSUER_ENDPOINT_URL, passwordResetEndpoint);
1✔
343
        getLoginView().getActivityContext().startActivity(intent);
1✔
344
    }
1✔
345
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc