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