Repository: mathesar-foundation/mathesar

Issue:
Password change and reset endpoints throw 500 instead of returning error messages
## Description
* Try updating a password with a common password such as `password`.
* The /password_reset and /password_change endpoints throw a 500
* They should return a 400 with formatted error messages

Related: 
* https://github.com/centerofci/mathesar/issues/1673


Discussion:
Hey @pavish ,
Can I work on this issue?
@Hatilar420 Sure, go ahead. I'm assigning it to you.
Hello i would love to contribute if it is not solved already can you please assign me please 
By the way am new to this contribution etc things but am good in solving problems that's why am here
Please guide me on the way and kindly please assign me
Hey @pavish, what is the default user_id to access this Endpoint?  When I am trying to access this route. It responds with 404(Not found)
My sample request
`http://localhost:8000/api/ui/v0/users/1/password_reset `

@Hatilar420 You can use Django's browsable APIs to access the endpoint.

Eg., visit: `http://localhost:8000/api/ui/v0/users/` directly on your browser and it'll provide you the list of all users, where you can find user ids for each of them.
Similarly `http://localhost:8000/api/ui/v0/users/password_change/` will provide you option to update password for the current user. Note that `password_reset` can only be done by a superuser.

You can check out https://github.com/centerofci/mathesar/issues/1673, which has all the PRs listed for the users APIs.

In your request,
`http://localhost:8000/api/ui/v0/users/1/password_reset`, add a trailing slash at the end i.e. 
`http://localhost:8000/api/ui/v0/users/1/password_reset/`.

This should work without a trailing slash, but it seems to throw a 404. Feel free to raise an issue for this.
@Aadijindal07 This issue is currently assigned to @Hatilar420. Feel feel free to look for an unassigned issue.
Thanks for Helping @pavish. I can use the API now.


Hey @pavish, How to catch errors caused by `MathesarErrorMessageMixin`. When i am trying to catch the `Exception`, i am getting an Error message  `'ValidationError' object has no attribute 'message'`. And further, i am unsure how some methods in `MathesarErrorMessageMixin` work since `FriendlyErrorMessagesMixin` is not very well documented.
Currently, I am getting this sample response.
![image](https://user-images.githubusercontent.com/29446639/216459996-9a9003cf-89d2-4ecb-9914-d3b845f7d94f.png)

@silentninja or @dmos62, perhaps one of you could help @Hatilar420 with this issue?
@Hatilar420 if you look at the error log, it is pointing to https://github.com/centerofci/mathesar/blob/8f47f3412467eee4a2e899845392194484e33232/mathesar/api/exceptions/mixins.py#L84 as the source of error. 

The current behavior in case the error object is an instance of `DjangoValidationError, RestValidationError`, we are looking for a field called `detail` or `messages` in the error object. 
But it looks like the error object, in this case, **does not** seem to contain the field called `detail` or `message`. So you would need to figure out the property of the `err` object that contains the error message.

In order to debug and look into the error object I would suggest setting up a [pdb breakpoint](https://docs.python.org/3/library/pdb.html) and inspecting the object.
Hi @silentninja , I tried setting up a Pdb breakpoint. But i wasn't able to access the debug console from the docker container. Are there any other ways to use it?
Also, I have tried catching the `Exception` object and `ValidationError`. Still I am not able to access the message that contains the message "The password is too common".
@silentninja might be aware of other ways to do this, but I'm only able to use `pdb` with pytest (e.g. this uses `ipdb`: `docker exec -it mathesar_service pytest --no-cov --pdb --pdbcls=IPython.terminal.debugger:TerminalPdb`), and, when debugging outside pytest, `docker-compose up`'s standard output doesn't display our logging calls, but does display basic `print('xyz')` calls, so I use that when debugging a running app.
@Hatilar420 I found an [article](https://joel-hanson.medium.com/how-to-use-pdb-for-django-inside-a-docker-12c424d880ec) that should guide with setting up pdb inside a docker container. 


> Also, I have tried catching the Exception object and ValidationError

@Hatilar420 Which `Exception` object did you catch? There is an exception happening inside the exception handler when dealing with a `ValidationError `Exception. The validation error informing the `password is too common` is thrown correctly, this validation error is then passed to the Exception handler to convert it to correct error response and but there seems to be an exception during the conversion process in the line https://github.com/centerofci/mathesar/blob/8f47f3412467eee4a2e899845392194484e33232/mathesar/api/exceptions/mixins.py#L84

So you would need to fix the error within the exception handler mixin inorder to return a `400` response status
Hi @silentninja, I tried to catch a general `Exception` and `AttributeError` . Both of which give me the same error message.
Maybe the MathesarErrorMesageMixin is causing the error. Will take a look and try to fix it.
The exception that contains the actual validation error is caught in https://github.com/centerofci/mathesar/blob/8f47f3412467eee4a2e899845392194484e33232/mathesar/api/exceptions/mixins.py#L83

The actual line that is causing the `AttributeError` is in https://github.com/centerofci/mathesar/blob/8f47f3412467eee4a2e899845392194484e33232/mathesar/api/exceptions/mixins.py#L84
You would need to make changes to this line to ensure it is not trying to look for a attribute that does not exist..


Resolving patch:
diff --git a/mathesar/api/exceptions/mixins.py b/mathesar/api/exceptions/mixins.py
--- a/mathesar/api/exceptions/mixins.py
+++ b/mathesar/api/exceptions/mixins.py
@@ -81,7 +81,12 @@ def _run_validator(self, validator, field, message):
                 args.append(field)
             validator(self.initial_data[field.field_name], *args)
         except (DjangoValidationError, RestValidationError) as err:
-            err_message = err.detail[0] if hasattr(err, 'detail') else err.message
+            if hasattr(err, 'detail'):
+                err_message = err.detail[0]
+            elif hasattr(err, 'message'):
+                err_message = err.message
+            elif hasattr(err, 'messages'):
+                err_message = err.messages[0]
             return err_message == message
 
     @property
diff --git a/mathesar/api/ui/serializers/users.py b/mathesar/api/ui/serializers/users.py
--- a/mathesar/api/ui/serializers/users.py
+++ b/mathesar/api/ui/serializers/users.py
@@ -69,7 +69,7 @@ def create(self, validated_data):
         return user
 
 
-class ChangePasswordSerializer(serializers.Serializer):
+class ChangePasswordSerializer(MathesarErrorMessageMixin, serializers.Serializer):
     password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
     old_password = serializers.CharField(write_only=True, required=True)
 


Test patch: