Added role based access to android login

- Admin has access to everything
- Staff has limited access to what they can edit in listfragment
- Customers cannot login to app
- added validations to pets, supplier and services in their detailed view
This commit is contained in:
Alex
2026-03-25 19:44:56 -06:00
parent b1fe03410c
commit 2a9d7145be
5 changed files with 85 additions and 31 deletions

View File

@@ -39,11 +39,17 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
// Check if user is already logged in
if (TokenManager.getInstance(this).isLoggedIn()) {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
finish();
return;
TokenManager tokenManager = TokenManager.getInstance(this);
if (tokenManager.isLoggedIn()) {
if ("CUSTOMER".equalsIgnoreCase(tokenManager.getRole())) {
// If a customer somehow remained logged in, clear them out
tokenManager.clearLoginData();
} else {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
finish();
return;
}
}
EdgeToEdge.enable(this);
@@ -83,11 +89,20 @@ public class MainActivity extends AppCompatActivity {
@Override
public void onResponse(Call<AuthDTO.LoginResponse> call, Response<AuthDTO.LoginResponse> response) {
if (response.isSuccessful() && response.body() != null) {
String role = response.body().getRole();
// Check if the user is a CUSTOMER and deny login if so
if ("CUSTOMER".equalsIgnoreCase(role)) {
Toast.makeText(MainActivity.this, "Access denied: Customers are not allowed to log in.", Toast.LENGTH_LONG).show();
tvLoginStatus.setText("Customers are not allowed to log in");
return;
}
//save login data in shared preferences
TokenManager.getInstance(MainActivity.this).saveLoginData(
response.body().getToken(),
response.body().getUsername(),
response.body().getRole()
role
);
//fetch user id from api then login to home activity

View File

@@ -14,6 +14,7 @@ import android.widget.LinearLayout;
import com.example.petstoremobile.R;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.fragments.listfragments.PetFragment;
import com.example.petstoremobile.fragments.listfragments.ServiceFragment;
import com.example.petstoremobile.fragments.listfragments.SupplierFragment;
@@ -49,6 +50,13 @@ public class ListFragment extends Fragment {
drawerInventory = view.findViewById(R.id.drawerInventory);
drawerProducts = view.findViewById(R.id.drawerProducts);
// Check user role and restrict access for STAFF
String role = TokenManager.getInstance(requireContext()).getRole();
if ("STAFF".equalsIgnoreCase(role)) {
drawerSuppliers.setVisibility(View.GONE);
drawerInventory.setVisibility(View.GONE);
}
//needed to disable touches on the innerContainer while the drawer is open
touchBlocker = view.findViewById(R.id.touchBlocker);
@@ -142,4 +150,4 @@ public class ListFragment extends Fragment {
.addToBackStack(null)
.commit();
}
}
}

View File

@@ -25,6 +25,8 @@ import com.example.petstoremobile.api.RetrofitClient;
import com.example.petstoremobile.dtos.PetDTO;
import com.example.petstoremobile.fragments.ListFragment;
import com.example.petstoremobile.fragments.listfragments.PetFragment;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.InputValidator;
import retrofit2.Call;
import retrofit2.Callback;
@@ -65,26 +67,27 @@ public class PetDetailFragment extends Fragment {
//Method to Update or Add a pet
private void savePet() {
// Validates all fields using InputValidator
if (!InputValidator.isNotEmpty(etPetName, "Pet Name")) return;
if (!InputValidator.isNotEmpty(etPetSpecies, "Species")) return;
if (!InputValidator.isNotEmpty(etPetBreed, "Breed")) return;
if (!InputValidator.isPositiveInteger(etPetAge, "Age")) return;
if (!InputValidator.isPositiveDecimal(etPetPrice, "Price")) return;
//get all the values from the fields
String name = etPetName.getText().toString().trim();
String species = etPetSpecies.getText().toString().trim();
String breed = etPetBreed.getText().toString().trim();
String ageStr = etPetAge.getText().toString().trim();
int age = Integer.parseInt(etPetAge.getText().toString().trim());
String priceStr = etPetPrice.getText().toString().trim();
String status = spinnerPetStatus.getSelectedItem().toString();
//check if all the fields are filled
if (name.isEmpty() || species.isEmpty() || breed.isEmpty() || ageStr.isEmpty() || priceStr.isEmpty()) {
Toast.makeText(getContext(), "Please fill in all fields", Toast.LENGTH_SHORT).show();
return;
}
//create a pet object to send to the API
PetDTO petDTO = new PetDTO();
petDTO.setPetName(name);
petDTO.setPetSpecies(species);
petDTO.setPetBreed(breed);
petDTO.setPetAge(Integer.parseInt(ageStr));
petDTO.setPetAge(age);
petDTO.setPetPrice(priceStr);
petDTO.setPetStatus(status);
@@ -98,6 +101,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onResponse(Call<PetDTO> call, Response<PetDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", petId);
Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -107,6 +111,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onFailure(Call<PetDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "PetDetailFragment.updatePet", new Exception(t));
Log.e("PetDetailFragment", "Error updating pet", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -117,6 +122,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onResponse(Call<PetDTO> call, Response<PetDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.log(requireContext(), "Added new Pet: " + name);
Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -126,6 +132,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onFailure(Call<PetDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "PetDetailFragment.createPet", new Exception(t));
Log.e("PetDetailFragment", "Error adding pet", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -146,6 +153,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId);
Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -155,6 +163,7 @@ public class PetDetailFragment extends Fragment {
@Override
public void onFailure(Call<Void> call, Throwable t) {
ActivityLogger.logException(requireContext(), "PetDetailFragment.deletePet", new Exception(t));
Log.e("PetDetailFragment", "Error deleting pet", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}

View File

@@ -20,6 +20,8 @@ import com.example.petstoremobile.api.ServiceApi;
import com.example.petstoremobile.dtos.ServiceDTO;
import com.example.petstoremobile.fragments.ListFragment;
import com.example.petstoremobile.fragments.listfragments.ServiceFragment;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.InputValidator;
import retrofit2.Call;
import retrofit2.Callback;
@@ -58,24 +60,24 @@ public class ServiceDetailFragment extends Fragment {
//Method to Update or Add a service
private void saveService() {
// Validates all fields using InputValidator
if (!InputValidator.isNotEmpty(etServiceName, "Service Name")) return;
if (!InputValidator.isNotEmpty(etServiceDesc, "Description")) return;
if (!InputValidator.isPositiveInteger(etServiceDuration, "Duration")) return;
if (!InputValidator.isPositiveDecimal(etServicePrice, "Price")) return;
//get all the values from the fields
String name = etServiceName.getText().toString().trim();
String desc = etServiceDesc.getText().toString().trim();
String durationStr = etServiceDuration.getText().toString().trim();
String priceStr = etServicePrice.getText().toString().trim();
//check if all the fields are filled (desc is optional)
if (name.isEmpty() || durationStr.isEmpty() || priceStr.isEmpty()) {
Toast.makeText(getContext(), "Please fill in all fields", Toast.LENGTH_SHORT).show();
return;
}
int duration = Integer.parseInt(etServiceDuration.getText().toString().trim());
double price = Double.parseDouble(etServicePrice.getText().toString().trim());
//create a service object to send to the API
ServiceDTO serviceDTO = new ServiceDTO();
serviceDTO.setServiceName(name);
serviceDTO.setServiceDesc(desc);
serviceDTO.setServiceDuration(Integer.parseInt(durationStr));
serviceDTO.setServicePrice(Double.parseDouble(priceStr));
serviceDTO.setServiceDuration(duration);
serviceDTO.setServicePrice(price);
ServiceApi serviceApi = RetrofitClient.getServiceApi(requireContext());
@@ -87,6 +89,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Service", "UPDATED", serviceId);
Toast.makeText(getContext(), "Service updated successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -96,6 +99,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onFailure(Call<ServiceDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "ServiceDetailFragment.updateService", new Exception(t));
Log.e("ServiceDetailFragment", "Error updating service", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -106,6 +110,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.log(requireContext(), "Added new Service: " + name);
Toast.makeText(getContext(), "Service added successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -115,6 +120,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onFailure(Call<ServiceDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "ServiceDetailFragment.createService", new Exception(t));
Log.e("ServiceDetailFragment", "Error adding service", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -134,6 +140,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId);
Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -143,6 +150,7 @@ public class ServiceDetailFragment extends Fragment {
@Override
public void onFailure(Call<Void> call, Throwable t) {
ActivityLogger.logException(requireContext(), "ServiceDetailFragment.deleteService", new Exception(t));
Log.e("ServiceDetailFragment", "Error deleting service", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}

View File

@@ -20,6 +20,8 @@ import com.example.petstoremobile.api.SupplierApi;
import com.example.petstoremobile.dtos.SupplierDTO;
import com.example.petstoremobile.fragments.ListFragment;
import com.example.petstoremobile.fragments.listfragments.SupplierFragment;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.InputValidator;
import retrofit2.Call;
import retrofit2.Callback;
@@ -58,6 +60,13 @@ public class SupplierDetailFragment extends Fragment {
//Method to Update or Add a supplier
private void saveSupplier() {
// Validates all fields using InputValidator
if (!InputValidator.isNotEmpty(etSupCompany, "Company Name")) return;
if (!InputValidator.isNotEmpty(etSupContactFirstName, "First Name")) return;
if (!InputValidator.isNotEmpty(etSupContactLastName, "Last Name")) return;
if (!InputValidator.isValidEmail(etSupEmail)) return;
if (!InputValidator.isValidPhone(etSupPhone)) return;
//get all the values from the fields
String company = etSupCompany.getText().toString().trim();
String firstName = etSupContactFirstName.getText().toString().trim();
@@ -65,12 +74,6 @@ public class SupplierDetailFragment extends Fragment {
String email = etSupEmail.getText().toString().trim();
String phone = etSupPhone.getText().toString().trim();
//check if all the fields are filled
if (company.isEmpty() || firstName.isEmpty() || lastName.isEmpty() || email.isEmpty() || phone.isEmpty()) {
Toast.makeText(getContext(), "Please fill in all fields", Toast.LENGTH_SHORT).show();
return;
}
//create a supplier object to send to the API
SupplierDTO supplierDTO = new SupplierDTO();
supplierDTO.setSupCompany(company);
@@ -89,6 +92,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Supplier", "UPDATED", supId);
Toast.makeText(getContext(), "Supplier updated successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -98,6 +102,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onFailure(Call<SupplierDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "SupplierDetailFragment.updateSupplier", new Exception(t));
Log.e("SupplierDetailFragment", "Error updating supplier", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -108,6 +113,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> response) {
if (response.isSuccessful()) {
ActivityLogger.log(requireContext(), "Added new Supplier: " + company);
Toast.makeText(getContext(), "Supplier added successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -117,6 +123,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onFailure(Call<SupplierDTO> call, Throwable t) {
ActivityLogger.logException(requireContext(), "SupplierDetailFragment.createSupplier", new Exception(t));
Log.e("SupplierDetailFragment", "Error adding supplier", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -136,6 +143,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId);
Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show();
navigateBack();
} else {
@@ -145,6 +153,7 @@ public class SupplierDetailFragment extends Fragment {
@Override
public void onFailure(Call<Void> call, Throwable t) {
ActivityLogger.logException(requireContext(), "SupplierDetailFragment.deleteSupplier", new Exception(t));
Log.e("SupplierDetailFragment", "Error deleting supplier", t);
Toast.makeText(getContext(), "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
@@ -197,6 +206,11 @@ public class SupplierDetailFragment extends Fragment {
etSupContactLastName = view.findViewById(R.id.etSupContactLastName);
etSupEmail = view.findViewById(R.id.etSupEmail);
etSupPhone = view.findViewById(R.id.etSupPhone);
// Add phone number formatting (CA) and limit length to 14 characters
etSupPhone.addTextChangedListener(new android.telephony.PhoneNumberFormattingTextWatcher("CA"));
etSupPhone.setFilters(new android.text.InputFilter[]{new android.text.InputFilter.LengthFilter(14)});
btnSaveSupplier = view.findViewById(R.id.btnSaveSupplier);
btnDeleteSupplier = view.findViewById(R.id.btnDeleteSupplier);
btnBack = view.findViewById(R.id.btnBack);