Repository: pulp/pulpcore

Issue:
As a user, I want to see role details for roles that are assigned to users and groups
**Is your feature request related to a problem? Please describe.**
The group and user role lists currently look like this:

```json
{
    "pulp_href": "/pulp/api/v3/groups/3/roles/6205b617-b825-4d89-a87f-433795bb6248/",
    "pulp_created": "2022-05-24T18:31:33.683333Z",
    "role": "_permission:container.add_containernamespace",
    "content_object": null,
},
```

The role name is included, but the permissions and description for the role are missing. It would be nice to be able to browse the API and see exactly what permissions a user or group has for each role.

**Describe the solution you'd like**
Add the role description and permissions to the serializer.
```json
{
    "pulp_href": "/pulp/api/v3/groups/3/roles/6205b617-b825-4d89-a87f-433795bb6248/",
    "pulp_created": "2022-05-24T18:31:33.683333Z",
    "role": "_permission:container.add_containernamespace",
    "content_object": null,
    "description": "Auto generated role for permission container.add_containernamespace.",
    "permissions": [
        "container.add_containernamespace"
    ]
},
```



Discussion:

Resolving patch:
diff --git a/pulpcore/app/serializers/user.py b/pulpcore/app/serializers/user.py
--- a/pulpcore/app/serializers/user.py
+++ b/pulpcore/app/serializers/user.py
@@ -1,3 +1,5 @@
+import typing
+
 from gettext import gettext as _
 
 from django.contrib.auth import get_user_model
@@ -239,6 +241,15 @@ class UserRoleSerializer(ModelSerializer, NestedHyperlinkedModelSerializer):
         allow_null=True,
     )
 
+    description = serializers.SerializerMethodField()
+    permissions = serializers.SerializerMethodField()
+
+    def get_description(self, obj):
+        return obj.role.description
+
+    def get_permissions(self, obj) -> typing.List[str]:
+        return [f"{p.content_type.app_label}.{p.codename}" for p in obj.role.permissions.all()]
+
     def validate(self, data):
         data = super().validate(data)
         data["user"] = User.objects.get(pk=self.context["request"].resolver_match.kwargs["user_pk"])
@@ -268,7 +279,12 @@ def validate(self, data):
 
     class Meta:
         model = UserRole
-        fields = ModelSerializer.Meta.fields + ("role", "content_object")
+        fields = ModelSerializer.Meta.fields + (
+            "role",
+            "content_object",
+            "description",
+            "permissions",
+        )
 
 
 class GroupRoleSerializer(ModelSerializer, NestedHyperlinkedModelSerializer):
@@ -289,6 +305,15 @@ class GroupRoleSerializer(ModelSerializer, NestedHyperlinkedModelSerializer):
         allow_null=True,
     )
 
+    description = serializers.SerializerMethodField()
+    permissions = serializers.SerializerMethodField()
+
+    def get_description(self, obj):
+        return obj.role.description
+
+    def get_permissions(self, obj) -> typing.List[str]:
+        return [f"{p.content_type.app_label}.{p.codename}" for p in obj.role.permissions.all()]
+
     def validate(self, data):
         data = super().validate(data)
         data["group"] = Group.objects.get(
@@ -320,7 +345,12 @@ def validate(self, data):
 
     class Meta:
         model = GroupRole
-        fields = ModelSerializer.Meta.fields + ("role", "content_object")
+        fields = ModelSerializer.Meta.fields + (
+            "role",
+            "content_object",
+            "description",
+            "permissions",
+        )
 
 
 class NestedRoleSerializer(serializers.Serializer):
diff --git a/pulpcore/app/viewsets/user.py b/pulpcore/app/viewsets/user.py
--- a/pulpcore/app/viewsets/user.py
+++ b/pulpcore/app/viewsets/user.py
@@ -365,6 +365,14 @@ def content_object_filter_function(self, queryset, name, value):
             obj_type = ContentType.objects.get_for_model(obj, for_concrete_model=False)
             return queryset.filter(content_type_id=obj_type.id, object_id=obj.pk)
 
+    sort = filters.OrderingFilter(
+        fields=(
+            ("role__name", "role"),
+            ("pulp_created", "pulp_created"),
+            ("role__description", "description"),
+        )
+    )
+
     class Meta:
         fields = (
             "role",


Test patch: