o
    hp\                     @   s,  d dl Z d dlZd dlZd dlmZmZ d dlZd dlmZ d dl	m
Z
mZ d dlmZ d dlmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZ ddlmZ ddlmZ ddlmZ ddlm Z m!Z!m"Z" ddlm#Z#m$Z$ ddl%m&Z&m'Z'm(Z( e)e*Z+e,dZ-G dd deZG dd de.Z/dS )    N)OrderedDictdefaultdict)urlparse)
URLPatternURLResolver)
versioning)SchemaGenerator)EndpointEnumerator)endpoint_orderingget_pk_name)get_pk_description)api_settings   )openapi)swagger_settings)SwaggerGenerationError)get_basic_type_infoget_queryset_fieldget_queryset_from_view)ReferenceResolverSwaggerDict)force_real_strget_consumesget_producesz{(?P<parameter>\w+)}c                       sZ   e Zd Zd fdd	Z fddZd fdd	Zd	d
 ZdddZdd Zdd Z	  Z
S )r	   Nc                    s   t t| || || _d S N)superr	   __init__request)selfpatternsurlconfr   	__class__ [/var/www/html/magazine_api/magazine_env/lib/python3.10/site-packages/drf_yasg/generators.pyr      s   
zEndpointEnumerator.__init__c                    s,   | drtd| | tt| |S )N)zEurl pattern does not end in $ ('%s') - unexpected things might happen)endswithloggerwarningunescape_pathr   r	   get_path_from_regex)r   
path_regexr!   r#   r$   r*   !   s   
z&EndpointEnumerator.get_path_from_regex c                    sx   t t| ||sdS t| jdd }t|jdd }|d ur.t|tjr.|r.||	dvr.dS t|jdt
 d u r:dS dS )NFversionversioning_class:swagger_schemaT)r   r	   should_include_endpointgetattrr   cls
issubclassr   ZNamespaceVersioningsplitobject)r   pathcallbackapp_name	namespaceurl_namer-   r.   r!   r#   r$   r1   &   s   z*EndpointEnumerator.should_include_endpointc                 C   sv   t |jdd}|dur9t|tjr9t | jdd}|r9t |dd}d| }||vr3td|j||f  |||}|S )a"  If ``request.version`` is not ``None`` and `callback` uses ``URLPathVersioning``, this function replaces
        the ``version`` parameter in `path` with the actual version.

        :param str path: the templated path
        :param callback: the view callback
        :rtype: str
        r.   Nr-   version_param{%s}z9view %s uses URLPathVersioning but URL %s has no param %s)	r2   r3   r4   r   ZURLPathVersioningr   r'   inforeplace)r   r7   r8   r.   r-   r<   r#   r#   r$   replace_version5   s   
z"EndpointEnumerator.replace_versionc              	   C   sV  |du r| j }g }|du rt }|D ]}|t|j }t|trnz=| |}	|j}
|j}| 	|	|
|p3d|p6d|r\| 
|	|
}	|	|v rEW q||	 | |
D ]}|	||
f}|| qOW q tym   tjddd Y qw t|tr| j|j||rd||jf n|j|rd||jf n|j|d}|| qtdt| qt|td	}|S )
z
        Return a list of all available API endpoints by inspecting the URL conf.

        Copied entirely from super.
        Nr,   zfailed to enumerate viewT)exc_infoz%s:%s)r   prefixr9   r:   ignored_endpointszunknown pattern type {}key)r   setstrpattern
isinstancer   r*   r8   namer1   r@   addZget_allowed_methodsappend	Exceptionr'   r(   r   get_api_endpointsZurl_patternsr9   r:   extendformattypesortedr
   )r   r   rB   r9   r:   rC   Zapi_endpointsrH   r+   r7   r8   r;   methodZendpointZnested_endpointsr#   r#   r$   rN   J   sH   




z$EndpointEnumerator.get_api_endpointsc                 C   s   t dd|S )zzUnescape all backslash escapes from `s`.

        :param str s: string with backslash escapes
        :rtype: str
        z\\(.)z\1)resub)r   sr#   r#   r$   unescape}   s   zEndpointEnumerator.unescapec                 C   sh   d}|r2t |}|s|| |7 }	 |S || |d|  7 }|| 7 }|| d }|s|S )a  Remove backslashe escapes from all path components outside {parameters}. This is needed because
        ``simplify_regex`` does not handle this correctly.

        **NOTE:** this might destructively affect some url regex patterns that contain metacharacters (e.g. \w, \d)
        outside path parameter groups; if you are in this category, God help you

        :param str path: path possibly containing
        :return: the unescaped path
        :rtype: str
        r,   N)PATH_PARAMETER_REsearchrW   startgroupend)r   r7   Z
clean_pathmatchr#   r#   r$   r)      s   
	z EndpointEnumerator.unescape_path)NNN)r,   r,   N)Nr,   NNN)__name__
__module____qualname__r   r*   r1   r@   rN   rW   r)   __classcell__r#   r#   r!   r$   r	      s    
3	r	   c                   @   s   e Zd ZdZeZeZd'ddZe	dd Z
dd	 Zd
d Zd(ddZd)ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& ZdS )*OpenAPISchemaGeneratorz
    This class iterates over all registered API endpoints and returns an appropriate OpenAPI 2.0 compliant schema.
    Method implementations shamelessly stolen and adapted from rest-framework ``SchemaGenerator``.
    r,   Nc                 C   s   t |j||dd||| _|| _|| _g | _g | _|du r&tj	dur&tj	}|rEt

|}|jdvs5|js9td|jrGtd|  dS dS dS )a  

        :param openapi.Info info: information about the API
        :param str version: API version string; if omitted, `info.default_version` will be used
        :param str url: API scheme, host and port; if ``None`` is passed and ``DEFAULT_API_URL`` is not set, the url
            will be inferred from the request made against the schema view, so you should generally not need to set
            this parameter explicitly; if the empty string is passed, no host and scheme will be emitted

            If `url` is not ``None`` or the empty string, it must be a scheme-absolute uri (i.e. starting with http://
            or https://), and any path component is ignored;

            See also: :ref:`documentation on base URL construction <custom-spec-base-url>`
        :param patterns: if given, only these patterns will be enumerated for inclusion in the API spec
        :param urlconf: if patterns is not given, use this urlconf to enumerate patterns;
            if not given, the default urlconf is used
        descriptionr,   N)httphttpsz%`url` must be an absolute HTTP(S) urlzKpath component of api base URL %s is ignored; use FORCE_SCRIPT_NAME instead)r   titleget_genr>   r-   consumesproducesr   ZDEFAULT_API_URLr   schemenetlocr   r7   r'   r(   )r   r>   r-   urlr   r    
parsed_urlr#   r#   r$   r      s   
zOpenAPISchemaGenerator.__init__c                 C   s   | j jS r   )rh   rm   )r   r#   r#   r$   rm      s   zOpenAPISchemaGenerator.urlc                 C   s   t j}|durt|i }|S )a  Get the security schemes for this API. This determines what is usable in security requirements,
        and helps clients configure their authorization credentials.

        :return: the security schemes usable with this API
        :rtype: dict[str,dict] or None
        N)r   ZSECURITY_DEFINITIONSr   	_as_odict)r   security_definitionsr#   r#   r$   get_security_definitions   s   z/OpenAPISchemaGenerator.get_security_definitionsc                 C   s:   t j}|du rdd |D }dd |D }t|td}|S )aj  Get the base (global) security requirements of the API. This is never called if
        :meth:`.get_security_definitions` returns `None`.

        :param security_definitions: security definitions as returned by :meth:`.get_security_definitions`
        :return: the security schemes accepted by default
        :rtype: list[dict[str,list[str]]] or None
        Nc                 S   s   g | ]}|g iqS r#   r#   ).0Zsecurity_schemer#   r#   r$   
<listcomp>   s    zDOpenAPISchemaGenerator.get_security_requirements.<locals>.<listcomp>c                 S   s   g | ]}t |i qS r#   )r   ro   )rr   srr#   r#   r$   rs      s    rD   )r   ZSECURITY_REQUIREMENTSrR   list)r   rp   security_requirementsr#   r#   r$   get_security_requirements   s   z0OpenAPISchemaGenerator.get_security_requirementsFc           
      C   s   |  |}| jtjdd}ttj| _ttj	| _
| ||||\}}|  }|r/| |}nd}| j}	|	du r@|dur@| }	tjd| j|| jpJd| j
pNd|||	|| jd	t|S )a  Generate a :class:`.Swagger` object representing the API schema.

        :param request: the request used for filtering accessible endpoints and finding the spec URI
        :type request: rest_framework.request.Request or None
        :param bool public: if True, all endpoints are included regardless of access through `request`

        :return: the generated Swagger specification
        :rtype: openapi.Swagger
        T)Z
force_initN)	r>   pathsri   rj   rp   security_url_prefix_versionr#   )get_endpointsreference_resolver_classr   ZSCHEMA_DEFINITIONSr   r   ZDEFAULT_PARSER_CLASSESri   r   ZDEFAULT_RENDERER_CLASSESrj   	get_pathsrq   rw   rm   Zbuild_absolute_uriZSwaggerr>   r-   dict)
r   r   public	endpoints
componentsrx   rB   rp   rv   rm   r#   r#   r$   
get_schema   s&   

z!OpenAPISchemaGenerator.get_schemac                 C   sh   | j |||}t|dd}|dur,| D ]\}}t||d}|dur+t|jd| qt|dd |S )aP  Create a view instance from a view callback as registered in urlpatterns.

        :param callback: view callback registered in urlpatterns
        :param str method: HTTP method
        :param request: request to bind to the view
        :type request: rest_framework.request.Request or None
        :return: the view instance
        _swagger_auto_schemaNZswagger_fake_viewT)rh   create_viewr2   itemssetattr__func__)r   r8   rS   r   view	overrides_Zview_methodr#   r#   r$   r     s   	z"OpenAPISchemaGenerator.create_viewc                 C   s>   d|vr|S t t|dd}|rt|}nd}|dd| S )aK  Coerce {pk} path arguments into the name of the model field, where possible. This is cleaner for an
        external representation (i.e. "this is an identifier", not "this is a database primary key").

        :param str path: the path
        :param rest_framework.views.APIView view: associated view
        :rtype: str
        z{pk}modelNidr=   )r2   r   r   r?   )r   r7   r   r   
field_namer#   r#   r$   coerce_path  s   
z"OpenAPISchemaGenerator.coerce_pathc           	         s   | j | jj| jj|d}| }tt}i  |D ] \}}}| |||}| ||}|| 	||f |j
 |< q fdd| D S )a  Iterate over all the registered endpoints in the API and return a fake view with the right parameters.

        :param request: request to bind to the endpoint views
        :type request: rest_framework.request.Request or None
        :return: {path: (view_class, list[(http_method, view_instance)])
        :rtype: dict[str,(type,list[(str,rest_framework.views.APIView)])]
        )r   c                    s   i | ]\}}| | |fqS r#   r#   )rr   r7   methodsview_clsr#   r$   
<dictcomp>A  s    z8OpenAPISchemaGenerator.get_endpoints.<locals>.<dictcomp>)endpoint_enumerator_classrh   r   r    rN   r   ru   r   r   rL   r3   r   )	r   r   Z
enumeratorr   Z
view_pathsr7   rS   r8   r   r#   r   r$   r}   /  s   z$OpenAPISchemaGenerator.get_endpointsc                 C   s   | j |||S )aX  Return a list of keys that should be used to group an operation within the specification. ::

          /users/                   ("users", "list"), ("users", "create")
          /users/{pk}/              ("users", "read"), ("users", "update"), ("users", "delete")
          /users/enabled/           ("users", "enabled")  # custom viewset list action
          /users/{pk}/star/         ("users", "star")     # custom viewset detail action
          /users/{pk}/groups/       ("users", "groups", "list"), ("users", "groups", "create")
          /users/{pk}/groups/{pk}/  ("users", "groups", "read"), ("users", "groups", "update")

        :param str subpath: path to the operation with any common prefix/base path removed
        :param str method: HTTP method
        :param view: the view associated with the operation
        :rtype: list[str]
        )rh   Zget_keys)r   subpathrS   r   r#   r#   r$   get_operation_keysC  s   z)OpenAPISchemaGenerator.get_operation_keysc                 C   s   | j |S )a  
        Given a list of all paths, return the common prefix which should be
        discounted when generating a schema structure.

        This will be the longest common string that does not include that last
        component of the URL, or the last component before a path parameter.

        For example: ::

            /api/v1/users/
            /api/v1/users/{pk}/

        The path prefix is ``/api/v1/``.

        :param list[str] paths: list of paths
        :rtype: str
        )rh   determine_path_prefixr   rx   r#   r#   r$   r   T  s   z,OpenAPISchemaGenerator.determine_path_prefixc                 C   s   |p	| j |||S )a  Check if a given endpoint should be included in the resulting schema.

        :param str path: request path
        :param str method: http request method
        :param view: instantiated view callback
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: true if the view should be excluded
        :rtype: bool
        )rh   Zhas_view_permissions)r   r7   rS   r   r   r#   r#   r$   r1   h  s   
z.OpenAPISchemaGenerator.should_include_endpointc                 C   s   t j|dS )zConstruct the Swagger Paths object.

        :param OrderedDict[str,openapi.PathItem] paths: mapping of paths to :class:`.PathItem` objects
        :returns: the :class:`.Paths` object
        :rtype: openapi.Paths
        rx   )r   Pathsr   r#   r#   r$   get_paths_objectt  s   z'OpenAPISchemaGenerator.get_paths_objectc              
   C   s   |s
t ji ddfS | t| pd}d|vsJ dt }t| D ]H\}\}}	i }
|	D ]!\}}| ||||s=q0| 	||||||}|durQ||
|
 < q0|
rn|t|d }|dsed| }| |||
||< q&| ||fS )a+  Generate the Swagger Paths for the API from the given endpoints.

        :param dict endpoints: endpoints as returned by get_endpoints
        :param ReferenceResolver components: resolver/container for Swagger References
        :param Request request: the request made against the schema view; can be None
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: the :class:`.Paths` object and the longest common path prefix, as a 2-tuple
        :rtype: tuple[openapi.Paths,str]
        r   r,   {z,base path cannot be templated in swagger 2.0N/)r   r   r   ru   keysr   rR   r   r1   get_operationlowerlen
startswithget_path_itemr   )r   r   r   r   r   rB   rx   r7   r   r   
operationsrS   r   	operationZpath_suffixr#   r#   r$   r   }  s*   

z OpenAPISchemaGenerator.get_pathsc                 C   s   |  |t|d ||}| ||}tj}	t|d|	}	|d|	}	|	du r(dS |	|||||||}
|
|}|du r=dS d|v rMt|j	t| j	krM|`	d|v r]t|j
t| j
kr]|`
|S )a  Get an :class:`.Operation` for the given API endpoint (path, method). This method delegates to
        :meth:`~.inspectors.ViewInspector.get_operation` of a :class:`~.inspectors.ViewInspector` determined
        according to settings and :func:`@swagger_auto_schema <.swagger_auto_schema>` overrides.

        :param view: the view associated with this endpoint
        :param str path: the path component of the operation URL
        :param str prefix: common path prefix among all endpoints
        :param str method: the http method of the operation
        :param openapi.ReferenceResolver components: referenceable components
        :param Request request: the request made against the schema view; can be None
        :rtype: openapi.Operation
        Nr0   Zauto_schemari   rj   )r   r   get_overridesr   ZDEFAULT_AUTO_SCHEMA_CLASSr2   rg   r   rF   ri   rj   )r   r   r7   rB   rS   r   r   Zoperation_keysr   Zview_inspector_clsZview_inspectorr   r#   r#   r$   r     s    
z$OpenAPISchemaGenerator.get_operationc                 C   s    |  ||}tjdd|i|S )a  Get a :class:`.PathItem` object that describes the parameters and operations related to a single path in the
        API.

        :param str path: the path
        :param type view_cls: the view that was bound to this path in urlpatterns
        :param dict[str,openapi.Operation] operations: operations defined on this path, keyed by lowercase HTTP method
        :rtype: openapi.PathItem
        
parametersNr#   )get_path_parametersr   ZPathItem)r   r7   r   r   Zpath_parametersr#   r#   r$   r     s   	z$OpenAPISchemaGenerator.get_path_itemc                 C   sF   |  }t|d|}t||d}t|di }||v r|| }t|S )a"  Get overrides specified for a given operation.

        :param view: the view associated with the operation
        :param str method: HTTP method
        :return: a dictionary containing any overrides set by :func:`@swagger_auto_schema <.swagger_auto_schema>`
        :rtype: dict
        actionNr   )r   r2   copydeepcopy)r   r   rS   r   Zaction_methodr   r#   r#   r$   r     s   
z$OpenAPISchemaGenerator.get_overridesc                 C   s   g }t |}tt|D ]^}t||\}}t|pdtji}t|dd|kr:|d tjkr:t|d|	dd|d< |rFt|ddrF|j
}	n|rTt|ddrTt||}	nd}	tjd|t|	d	tjd
|}
||
 q|S )a  Return a list of Parameter instances corresponding to any templated path variables.

        :param str path: templated request path
        :param type view_cls: the view class associated with the path
        :return: path parameters
        :rtype: list[openapi.Parameter]
        rQ   Zlookup_fieldNZlookup_value_regexrH   	help_textFZprimary_keyT)rJ   rc   requiredin_r#   )r   rR   uritemplate	variablesr   r   r   ZTYPE_STRINGr2   rg   r   r   	Parameterr   ZIN_PATHrL   )r   r7   r   r   Zquerysetvariabler   Zmodel_fieldattrsrc   fieldr#   r#   r$   r     s,   z*OpenAPISchemaGenerator.get_path_parameters)r,   NNN)NFr   )r^   r_   r`   __doc__r	   r   r   r~   r   propertyrm   rq   rw   r   r   r   r}   r   r   r1   r   r   r   r   r   r   r#   r#   r#   r$   rb      s,    
!


 	%&rb   )0r   loggingrT   collectionsr   r   r   Zcoreapi.compatr   Zdjango.urlsr   r   Zrest_frameworkr   Zrest_framework.schemasr   Z!rest_framework.schemas.generatorsr	   Z_EndpointEnumeratorr
   r   Zrest_framework.schemas.utilsr   Zrest_framework.settingsr   r,   r   Zapp_settingsr   errorsr   Zinspectors.fieldr   r   r   r   r   utilsr   r   r   	getLoggerr^   r'   compilerX   r6   rb   r#   r#   r#   r$   <module>   s0    

 