From 7191fcf6e7294c3a13c9ee77550dd33b94d08ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mieszko=20Wrzeszczy=C5=84ski?= Date: Thu, 1 Nov 2018 20:37:51 +0100 Subject: [PATCH] Fix loginActivity - there is possibility to use ordinary validate endpoint --- app/src/main/AndroidManifest.xml | 7 +- .../findmytutor/activity/LoginActivity.java | 479 +++++------------- .../activity/UsersListActivity.java | 9 +- .../wmi/findmytutor/utils/RestApiHelper.java | 27 +- app/src/main/res/layout/users_list_main.xml | 10 - app/src/main/res/values/strings.xml | 1 + 6 files changed, 162 insertions(+), 371 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f0599bd..1f83ca9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -48,11 +48,6 @@ android:label="@string/title_activity_sharing" android:launchMode="singleTop" /> - - - + diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java index d76c182..ef96d14 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java @@ -3,33 +3,20 @@ package com.uam.wmi.findmytutor.activity; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; -import android.app.LoaderManager.LoaderCallbacks; -import android.content.CursorLoader; import android.content.Intent; -import android.content.Loader; -import android.content.pm.PackageManager; -import android.database.Cursor; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.provider.ContactsContract; -import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; -import android.util.Log; -import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; -import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; +import android.widget.ProgressBar; import android.widget.Switch; -import android.widget.TextView; -import android.widget.ToggleButton; import com.auth0.android.jwt.Claim; import com.auth0.android.jwt.JWT; @@ -44,403 +31,197 @@ import com.uam.wmi.findmytutor.service.UserService; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RestApiHelper; -import java.util.ArrayList; -import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; -import static android.Manifest.permission.READ_CONTACTS; - -/** - * A login screen that offers login via email/password. - */ -public class LoginActivity extends AppCompatActivity implements LoaderCallbacks { - - /** - * Id to identity READ_CONTACTS permission request. - */ - private static final int REQUEST_READ_CONTACTS = 0; - - /** - * A dummy authentication store containing known user names and passwords. - * TODO: remove after connecting to a real authentication system. - */ - private static final String[] DUMMY_CREDENTIALS = new String[]{ - "adam@o2.pl:adamadam", "foo@example.com:hello", "bar@example.com:world" - }; - /** - * Keep track of the login task to ensure we can cancel it if requested. - */ - private UserLoginTask mAuthTask = null; +public class LoginActivity extends AppCompatActivity { // UI references. - private AutoCompleteTextView mEmailView; + private AutoCompleteTextView mLoginNameView; private EditText mPasswordView; private View mProgressView; private View mLoginFormView; - private boolean loginOption; + private LdapService ldapService; + private UserService userService; + private CompositeDisposable disposable = new CompositeDisposable(); + private Boolean isTutor = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); - // Set up the login form. - mEmailView = (AutoCompleteTextView) findViewById(R.id.email); - populateAutoComplete(); + mLoginNameView = findViewById(R.id.email); - mPasswordView = (EditText) findViewById(R.id.password); - mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { - if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) { - attemptLogin(); - return true; - } - return false; - } - }); + ldapService = ApiClient.getClient(getApplicationContext()) + .create(LdapService.class); + userService = ApiClient.getClient(getApplicationContext()) + .create(UserService.class); - Switch tutorLogin = (Switch) findViewById(R.id.tutor_login_switch); - tutorLogin.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - loginOption = tutorLogin.isChecked(); - } - }); - - - Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); - mEmailSignInButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { + mPasswordView = findViewById(R.id.password); + mPasswordView.setOnEditorActionListener((textView, id, keyEvent) -> { + if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) { attemptLogin(); + return true; } + return false; }); + Switch tutorLogin = findViewById(R.id.tutor_login_switch); + + tutorLogin.setOnCheckedChangeListener((buttonView, isChecked) -> { + PrefUtils.storeIsTutor(getApplicationContext(), isChecked); + }); + + Button mEmailSignInButton = findViewById(R.id.email_sign_in_button); + mEmailSignInButton.setOnClickListener(view -> attemptLogin()); + mLoginFormView = findViewById(R.id.login_form); mProgressView = findViewById(R.id.login_progress); } - private void populateAutoComplete() { - if (!mayRequestContacts()) { - return; - } - getLoaderManager().initLoader(0, null, this); - } - - private boolean mayRequestContacts() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return true; - } - if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) { - return true; - } - if (shouldShowRequestPermissionRationale(READ_CONTACTS)) { - Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE) - .setAction(android.R.string.ok, new View.OnClickListener() { - @Override - @TargetApi(Build.VERSION_CODES.M) - public void onClick(View v) { - requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); - } - }); - } else { - requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); - } - return false; - } - - /** - * Callback received when a permissions request has been completed. - */ - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - if (requestCode == REQUEST_READ_CONTACTS) { - if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - populateAutoComplete(); - } - } - } - - - /** - * Attempts to sign in or register the account specified by the login form. - * If there are form errors (invalid email, missing fields, etc.), the - * errors are presented and no actual login attempt is made. - */ private void attemptLogin() { - if (mAuthTask != null) { - return; - } - // Reset errors. - mEmailView.setError(null); + mLoginNameView.setError(null); mPasswordView.setError(null); // Store values at the time of the login attempt. - String email = mEmailView.getText().toString(); + String loginName = mLoginNameView.getText().toString(); String password = mPasswordView.getText().toString(); boolean cancel = false; View focusView = null; - // Check for a valid password, if the user entered one. - if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) { + // Check for a valid email address. + if (TextUtils.isEmpty(loginName)) { + mLoginNameView.setError(getString(R.string.error_field_required)); + focusView = mLoginNameView; + cancel = true; + } else if (!isEmailValid(loginName)) { + mLoginNameView.setError(getString(R.string.error_invalid_login_name)); + focusView = mLoginNameView; + cancel = true; + } + + // Check for a valid password address. + if (TextUtils.isEmpty(password)) { + mPasswordView.setError(getString(R.string.error_field_required)); + focusView = mPasswordView; + cancel = true; + } else if (!isPasswordValid(password)) { mPasswordView.setError(getString(R.string.error_invalid_password)); focusView = mPasswordView; cancel = true; } - // Check for a valid email address. - if (TextUtils.isEmpty(email)) { - mEmailView.setError(getString(R.string.error_field_required)); - focusView = mEmailView; - cancel = true; - } else if (!isEmailValid(email)) { - mEmailView.setError(getString(R.string.error_invalid_email)); - focusView = mEmailView; - cancel = true; - } - if (cancel) { - // There was an error; don't attempt login and focus the first - // form field with an error. focusView.requestFocus(); } else { - // Show a progress spinner, and kick off a background task to - // perform the user login attempt. showProgress(true); - mAuthTask = new UserLoginTask(email, password, loginOption); - mAuthTask.execute((Void) null); + loginProcess(loginName, password); + } } - private boolean isEmailValid(String email) { - //TODO: Replace this with your own logic - return email.contains("@"); + private boolean isEmailValid(String loginName) { + Pattern pattern = Pattern.compile("^s\\d+"); + Matcher matcher = pattern.matcher(loginName); + return matcher.find(); } private boolean isPasswordValid(String password) { - //TODO: Replace this with your own logic return password.length() > 4; } - /** - * Shows the progress UI and hides the login form. - */ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) private void showProgress(final boolean show) { - // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow - // for very easy animations. If available, use these APIs to fade-in - // the progress spinner. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { - int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); + int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); - mLoginFormView.animate().setDuration(shortAnimTime).alpha( - show ? 0 : 1).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); - } - }); - - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); - mProgressView.animate().setDuration(shortAnimTime).alpha( - show ? 1 : 0).setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); - } - }); - } else { - // The ViewPropertyAnimator APIs are not available, so simply show - // and hide the relevant UI components. - mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); - mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); - } - } - - @Override - public Loader onCreateLoader(int i, Bundle bundle) { - return new CursorLoader(this, - // Retrieve data rows for the device user's 'profile' contact. - Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, - ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION, - - // Select only email addresses. - ContactsContract.Contacts.Data.MIMETYPE + - " = ?", new String[]{ContactsContract.CommonDataKinds.Email - .CONTENT_ITEM_TYPE}, - - // Show primary email addresses first. Note that there won't be - // a primary email address if the user hasn't specified one. - ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"); - } - - @Override - public void onLoadFinished(Loader cursorLoader, Cursor cursor) { - List emails = new ArrayList<>(); - cursor.moveToFirst(); - while (!cursor.isAfterLast()) { - emails.add(cursor.getString(ProfileQuery.ADDRESS)); - cursor.moveToNext(); - } - - addEmailsToAutoComplete(emails); - } - - @Override - public void onLoaderReset(Loader cursorLoader) { - - } - - private void addEmailsToAutoComplete(List emailAddressCollection) { - //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list. - ArrayAdapter adapter = - new ArrayAdapter<>(LoginActivity.this, - android.R.layout.simple_dropdown_item_1line, emailAddressCollection); - - mEmailView.setAdapter(adapter); - } - - - private interface ProfileQuery { - String[] PROJECTION = { - ContactsContract.CommonDataKinds.Email.ADDRESS, - ContactsContract.CommonDataKinds.Email.IS_PRIMARY, - }; - - int ADDRESS = 0; - int IS_PRIMARY = 1; - } - - /** - * Represents an asynchronous login/registration task used to authenticate - * the user. - */ - public class UserLoginTask extends AsyncTask { - - private final String mEmail; - private final String mPassword; - private boolean isTutor; - private LdapService ldapService; - private UserService userService; - private CompositeDisposable disposable = new CompositeDisposable(); - private Boolean isAuthorizate; - - // Constructor - UserLoginTask(String email, String password, Boolean loginOption) { - mEmail = email; - mPassword = password; - isTutor = loginOption; - isAuthorizate = false; - ldapService = ApiClient.getClient(getApplicationContext()) - .create(LdapService.class); - userService = ApiClient.getClient(getApplicationContext()) - .create(UserService.class); - - PrefUtils.storeIsTutor(getApplicationContext(), this.isTutor); - } - - private void saveUserProfileToSharedPreferences(User user){ - PrefUtils.storeUserFirstName(getApplicationContext(), user.getFirstName()); - PrefUtils.storeUserLastName(getApplicationContext(), user.getLastName()); - PrefUtils.storeUserName(getApplicationContext(), user.getUserName()); - } - - private void getUserProfile(String userId) { - disposable.add( - userService - .getUserByID(userId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableSingleObserver() { - @Override - public void onSuccess(User user) { - Log.e("USER", String.valueOf(user)); - saveUserProfileToSharedPreferences(user); - - onPostExecute(true); - } - - public void onError(Throwable e) { - ((HttpException) e).code(); - Log.e("Login onError", e.getMessage()); - - if (e instanceof HttpException) { - ResponseBody responseBody = ((HttpException) e).response().errorBody(); - Log.e("Login onError", RestApiHelper.getErrorMessage(responseBody)); - } - - } - })); - } - - @Override - protected Boolean doInBackground(Void... params) { - LdapUser user = new LdapUser(mEmail, mPassword, "admin", (isTutor) ? "Tutor" : "Student", "string", "string", mEmail); - - disposable.add( - ldapService - .fakeValidate(user) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableSingleObserver() { - @Override - public void onSuccess(JwtToken jwtToken) { - String token = jwtToken.getToken(); - - //String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIzY2QyMWFlYi00ZGRmLTQ0YTktOWM3OC1kNGE3MjVlN2MwNDkiLCJzdWIiOiJhc2RAYXNkc2FkYWEiLCJqdGkiOiIwMDMzYWZhMy0yNDZhLTQ1YTYtOWZmYi1lNzhiYjg3MDMzMmIiLCJleHAiOjE1NDMxMzUwNjAsImlzcyI6Imh0dHA6Ly9maW5kbXl0dXRvci5jb20iLCJhdWQiOiJodHRwOi8vZmluZG15dHV0b3IuY29tIn0.rzks6-yjvVuYoO0pdiBwAfqDnMg8C8XrM9eA4h692m0"; - - JWT jwt = new JWT(token); - Claim role = jwt.getClaim("nameid"); - - PrefUtils.storeIsLoggedIn(getApplicationContext(), true); - PrefUtils.storeApiKey(getApplicationContext(), token); - PrefUtils.storeUserId(getApplicationContext(), role.asString()); - - getUserProfile(role.asString()); - } - - @Override - public void onError(Throwable e) { - Log.e("LoginError", "onError: " + e.getMessage()); - } - })); - - return true; - } - - @Override - protected void onPostExecute(final Boolean success) { - mAuthTask = null; - showProgress(false); - - if (success) { - Intent data = new Intent(); - String txt = "Main Activity"; - data.setData(Uri.parse(txt)); - setResult(RESULT_OK, data); - finish(); - } else { - mPasswordView.setError(getString(R.string.error_incorrect_password)); - mPasswordView.requestFocus(); + mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); + mLoginFormView.animate().setDuration(shortAnimTime).alpha( + show ? 0 : 1).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); } + }); - } + mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); + mProgressView.animate().setDuration(shortAnimTime).alpha( + show ? 1 : 0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); + } + }); + } - @Override - protected void onCancelled() { - mAuthTask = null; - showProgress(false); + + private void loginProcess(String email, String password) { + LdapUser user = new LdapUser(email, password, "admin", (isTutor) ? "Tutor" : "Student", "string", "string", email); + + disposable.add(ldapService.fakeValidate(user) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleResponse, this::handleError)); + } + + private void getUserProfile(String userId) { + disposable.add( + userService + .getUserByID(userId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::saveUserProfileToSharedPreferences, this::handleError)); + } + + private void showSnackBarMessage(String message) { + Snackbar.make(findViewById(R.id.login_form), message, Snackbar.LENGTH_LONG) + .show(); + } + + private void handleResponse(JwtToken jwtToken) { + showProgress(false); + + String token = jwtToken.getToken(); + JWT jwt = new JWT(token); + Claim role = jwt.getClaim("nameid"); + + PrefUtils.storeIsLoggedIn(getApplicationContext(), true); + PrefUtils.storeApiKey(getApplicationContext(), token); + PrefUtils.storeUserId(getApplicationContext(), role.asString()); + + getUserProfile(role.asString()); + + Intent data = new Intent(); + String txt = "Main Activity"; + data.setData(Uri.parse(txt)); + setResult(RESULT_OK, data); + finish(); + } + + private void handleError(Throwable error) { + showProgress(false); + + if (error instanceof HttpException) { + + ResponseBody responseBody = ((HttpException) error).response().errorBody(); + showSnackBarMessage(RestApiHelper.getErrorMessage(responseBody)); + + } else { + showSnackBarMessage("Network Error !"); } } + + private void saveUserProfileToSharedPreferences(User user) { + PrefUtils.storeUserFirstName(getApplicationContext(), user.getFirstName()); + PrefUtils.storeUserLastName(getApplicationContext(), user.getLastName()); + PrefUtils.storeUserName(getApplicationContext(), user.getUserName()); + } } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListActivity.java index 22012a8..0d86a32 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListActivity.java @@ -53,8 +53,7 @@ public class UsersListActivity extends Fragment { CoordinatorLayout coordinatorLayout; @BindView(R.id.recycler_view) RecyclerView recyclerView; - @BindView(R.id.txt_empty_notes_view) - TextView noNotesView; + private UserService userService; private TutorTabApi tutorTabService; @@ -184,7 +183,7 @@ public class UsersListActivity extends Fragment { .subscribeWith(new DisposableSingleObserver>() { @Override public void onSuccess(List users) { - toggleEmptyNotes(); + //toggleEmptyNotes(); tutorsList.clear(); tutorsList.addAll(users); mAdapter.notifyDataSetChanged(); @@ -218,13 +217,13 @@ public class UsersListActivity extends Fragment { snackbar.show(); } - private void toggleEmptyNotes() { +/* private void toggleEmptyNotes() { if (tutorsList.size() > 0) { noNotesView.setVisibility(View.GONE); } else { noNotesView.setVisibility(View.VISIBLE); } - } + }*/ @Override public void onDestroy() { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/RestApiHelper.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/RestApiHelper.java index ec27e2c..0a6bac4 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/RestApiHelper.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/RestApiHelper.java @@ -1,10 +1,19 @@ package com.uam.wmi.findmytutor.utils; +import android.app.Activity; +import android.graphics.Color; +import android.support.design.widget.Snackbar; +import android.view.View; +import android.widget.TextView; + +import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; +import com.uam.wmi.findmytutor.R; + import org.json.JSONObject; import okhttp3.ResponseBody; -public class RestApiHelper { +public class RestApiHelper extends Activity { public RestApiHelper() { } @@ -17,4 +26,20 @@ public class RestApiHelper { return e.getMessage(); } } + + + public void showError(Throwable e) { + String message = e.toString(); + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + } + + Snackbar snackbar = Snackbar.make(findViewById(R.id.activity_content), message, Snackbar.LENGTH_LONG); + View sbView = snackbar.getView(); + TextView textView = sbView.findViewById(android.support.design.R.id.snackbar_text); + textView.setTextColor(Color.BLUE); + snackbar.show(); + } } diff --git a/app/src/main/res/layout/users_list_main.xml b/app/src/main/res/layout/users_list_main.xml index f8945d4..fd7aafc 100644 --- a/app/src/main/res/layout/users_list_main.xml +++ b/app/src/main/res/layout/users_list_main.xml @@ -16,16 +16,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 258da37..1bd02fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -204,4 +204,5 @@ functionality. Notatka Dyżury: Dyżury: + Invalid format of login. Use s11111 format