prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Introduce a permission specifically to allow the creation of API tokens for other users
  ### NetBox version
  
  v3.4.7
  
  ### Feature type
  
  Change to existing functionality
  
  ### Proposed functionality
  
  This idea was [first proposed](https://github.com/netbox-community/netbox/issues/11091#issuecomment-1382039803) by @kkthxbye-code under #11091. This permission will control whether a specific user has the ability to create API tokens on behalf of other users.
  
  ### Use case
  
  Provides more granular control over the creation of API tokens.
  
  ### Database changes
  
  _No response_
  
  ### External dependencies
  
  _No response_
  
  </issue>
  <code>
  [start of netbox/users/api/serializers.py]
  1 from django.conf import settings
  2 from django.contrib.auth.models import Group, User
  3 from django.contrib.contenttypes.models import ContentType
  4 from rest_framework import serializers
  5 
  6 from netbox.api.fields import ContentTypeField, IPNetworkSerializer, SerializedPKRelatedField
  7 from netbox.api.serializers import ValidatedModelSerializer
  8 from users.models import ObjectPermission, Token
  9 from .nested_serializers import *
  10 
  11 
  12 __all__ = (
  13     'GroupSerializer',
  14     'ObjectPermissionSerializer',
  15     'TokenSerializer',
  16     'UserSerializer',
  17 )
  18 
  19 
  20 class UserSerializer(ValidatedModelSerializer):
  21     url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')
  22     groups = SerializedPKRelatedField(
  23         queryset=Group.objects.all(),
  24         serializer=NestedGroupSerializer,
  25         required=False,
  26         many=True
  27     )
  28 
  29     class Meta:
  30         model = User
  31         fields = (
  32             'id', 'url', 'display', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active',
  33             'date_joined', 'groups',
  34         )
  35         extra_kwargs = {
  36             'password': {'write_only': True}
  37         }
  38 
  39     def create(self, validated_data):
  40         """
  41         Extract the password from validated data and set it separately to ensure proper hash generation.
  42         """
  43         password = validated_data.pop('password')
  44         user = super().create(validated_data)
  45         user.set_password(password)
  46         user.save()
  47 
  48         return user
  49 
  50     def get_display(self, obj):
  51         if full_name := obj.get_full_name():
  52             return f"{obj.username} ({full_name})"
  53         return obj.username
  54 
  55 
  56 class GroupSerializer(ValidatedModelSerializer):
  57     url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')
  58     user_count = serializers.IntegerField(read_only=True)
  59 
  60     class Meta:
  61         model = Group
  62         fields = ('id', 'url', 'display', 'name', 'user_count')
  63 
  64 
  65 class TokenSerializer(ValidatedModelSerializer):
  66     url = serializers.HyperlinkedIdentityField(view_name='users-api:token-detail')
  67     key = serializers.CharField(
  68         min_length=40,
  69         max_length=40,
  70         allow_blank=True,
  71         required=False,
  72         write_only=not settings.ALLOW_TOKEN_RETRIEVAL
  73     )
  74     user = NestedUserSerializer()
  75     allowed_ips = serializers.ListField(
  76         child=IPNetworkSerializer(),
  77         required=False,
  78         allow_empty=True,
  79         default=[]
  80     )
  81 
  82     class Meta:
  83         model = Token
  84         fields = (
  85             'id', 'url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled', 'description',
  86             'allowed_ips',
  87         )
  88 
  89     def to_internal_value(self, data):
  90         if 'key' not in data:
  91             data['key'] = Token.generate_key()
  92         return super().to_internal_value(data)
  93 
  94 
  95 class TokenProvisionSerializer(serializers.Serializer):
  96     username = serializers.CharField()
  97     password = serializers.CharField()
  98 
  99 
  100 class ObjectPermissionSerializer(ValidatedModelSerializer):
  101     url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail')
  102     object_types = ContentTypeField(
  103         queryset=ContentType.objects.all(),
  104         many=True
  105     )
  106     groups = SerializedPKRelatedField(
  107         queryset=Group.objects.all(),
  108         serializer=NestedGroupSerializer,
  109         required=False,
  110         many=True
  111     )
  112     users = SerializedPKRelatedField(
  113         queryset=User.objects.all(),
  114         serializer=NestedUserSerializer,
  115         required=False,
  116         many=True
  117     )
  118 
  119     class Meta:
  120         model = ObjectPermission
  121         fields = (
  122             'id', 'url', 'display', 'name', 'description', 'enabled', 'object_types', 'groups', 'users', 'actions',
  123             'constraints',
  124         )
  125
  [end of netbox/users/api/serializers.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py
  --- a/netbox/users/api/serializers.py
  +++ b/netbox/users/api/serializers.py
  @@ -2,6 +2,7 @@
   from django.contrib.auth.models import Group, User
   from django.contrib.contenttypes.models import ContentType
   from rest_framework import serializers
  +from rest_framework.exceptions import PermissionDenied
   
   from netbox.api.fields import ContentTypeField, IPNetworkSerializer, SerializedPKRelatedField
   from netbox.api.serializers import ValidatedModelSerializer
  @@ -91,6 +92,16 @@
               data['key'] = Token.generate_key()
           return super().to_internal_value(data)
   
  +    def validate(self, data):
  +
  +        # If the Token is being created on behalf of another user, enforce the grant_token permission.
  +        request = self.context.get('request')
  +        token_user = data.get('user')
  +        if token_user and token_user != request.user and not request.user.has_perm('users.grant_token'):
  +            raise PermissionDenied("This user does not have permission to create tokens for other users.")
  +
  +        return super().validate(data)
  +
   
   class TokenProvisionSerializer(serializers.Serializer):
       username = serializers.CharField()
  
verification_info: {"golden_diff": "diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py\n--- a/netbox/users/api/serializers.py\n+++ b/netbox/users/api/serializers.py\n@@ -2,6 +2,7 @@\n from django.contrib.auth.models import Group, User\n from django.contrib.contenttypes.models import ContentType\n from rest_framework import serializers\n+from rest_framework.exceptions import PermissionDenied\n \n from netbox.api.fields import ContentTypeField, IPNetworkSerializer, SerializedPKRelatedField\n from netbox.api.serializers import ValidatedModelSerializer\n@@ -91,6 +92,16 @@\n             data['key'] = Token.generate_key()\n         return super().to_internal_value(data)\n \n+    def validate(self, data):\n+\n+        # If the Token is being created on behalf of another user, enforce the grant_token permission.\n+        request = self.context.get('request')\n+        token_user = data.get('user')\n+        if token_user and token_user != request.user and not request.user.has_perm('users.grant_token'):\n+            raise PermissionDenied(\"This user does not have permission to create tokens for other users.\")\n+\n+        return super().validate(data)\n+\n \n class TokenProvisionSerializer(serializers.Serializer):\n     username = serializers.CharField()\n", "issue": "Introduce a permission specifically to allow the creation of API tokens for other users\n### NetBox version\n\nv3.4.7\n\n### Feature type\n\nChange to existing functionality\n\n### Proposed functionality\n\nThis idea was [first proposed](https://github.com/netbox-community/netbox/issues/11091#issuecomment-1382039803) by @kkthxbye-code under #11091. This permission will control whether a specific user has the ability to create API tokens on behalf of other users.\n\n### Use case\n\nProvides more granular control over the creation of API tokens.\n\n### Database changes\n\n_No response_\n\n### External dependencies\n\n_No response_\n", "before_files": [{"content": "from django.conf import settings\nfrom django.contrib.auth.models import Group, User\nfrom django.contrib.contenttypes.models import ContentType\nfrom rest_framework import serializers\n\nfrom netbox.api.fields import ContentTypeField, IPNetworkSerializer, SerializedPKRelatedField\nfrom netbox.api.serializers import ValidatedModelSerializer\nfrom users.models import ObjectPermission, Token\nfrom .nested_serializers import *\n\n\n__all__ = (\n    'GroupSerializer',\n    'ObjectPermissionSerializer',\n    'TokenSerializer',\n    'UserSerializer',\n)\n\n\nclass UserSerializer(ValidatedModelSerializer):\n    url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')\n    groups = SerializedPKRelatedField(\n        queryset=Group.objects.all(),\n        serializer=NestedGroupSerializer,\n        required=False,\n        many=True\n    )\n\n    class Meta:\n        model = User\n        fields = (\n            'id', 'url', 'display', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active',\n            'date_joined', 'groups',\n        )\n        extra_kwargs = {\n            'password': {'write_only': True}\n        }\n\n    def create(self, validated_data):\n        \"\"\"\n        Extract the password from validated data and set it separately to ensure proper hash generation.\n        \"\"\"\n        password = validated_data.pop('password')\n        user = super().create(validated_data)\n        user.set_password(password)\n        user.save()\n\n        return user\n\n    def get_display(self, obj):\n        if full_name := obj.get_full_name():\n            return f\"{obj.username} ({full_name})\"\n        return obj.username\n\n\nclass GroupSerializer(ValidatedModelSerializer):\n    url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')\n    user_count = serializers.IntegerField(read_only=True)\n\n    class Meta:\n        model = Group\n        fields = ('id', 'url', 'display', 'name', 'user_count')\n\n\nclass TokenSerializer(ValidatedModelSerializer):\n    url = serializers.HyperlinkedIdentityField(view_name='users-api:token-detail')\n    key = serializers.CharField(\n        min_length=40,\n        max_length=40,\n        allow_blank=True,\n        required=False,\n        write_only=not settings.ALLOW_TOKEN_RETRIEVAL\n    )\n    user = NestedUserSerializer()\n    allowed_ips = serializers.ListField(\n        child=IPNetworkSerializer(),\n        required=False,\n        allow_empty=True,\n        default=[]\n    )\n\n    class Meta:\n        model = Token\n        fields = (\n            'id', 'url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled', 'description',\n            'allowed_ips',\n        )\n\n    def to_internal_value(self, data):\n        if 'key' not in data:\n            data['key'] = Token.generate_key()\n        return super().to_internal_value(data)\n\n\nclass TokenProvisionSerializer(serializers.Serializer):\n    username = serializers.CharField()\n    password = serializers.CharField()\n\n\nclass ObjectPermissionSerializer(ValidatedModelSerializer):\n    url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail')\n    object_types = ContentTypeField(\n        queryset=ContentType.objects.all(),\n        many=True\n    )\n    groups = SerializedPKRelatedField(\n        queryset=Group.objects.all(),\n        serializer=NestedGroupSerializer,\n        required=False,\n        many=True\n    )\n    users = SerializedPKRelatedField(\n        queryset=User.objects.all(),\n        serializer=NestedUserSerializer,\n        required=False,\n        many=True\n    )\n\n    class Meta:\n        model = ObjectPermission\n        fields = (\n            'id', 'url', 'display', 'name', 'description', 'enabled', 'object_types', 'groups', 'users', 'actions',\n            'constraints',\n        )\n", "path": "netbox/users/api/serializers.py"}]}