o
    !iG                     @   s  d Z ddlZddlZddlmZmZmZ ddlmZmZ ddl	m
Z
 ddlZddlZedddejdZedddd	ejdZed
ejZedejZedZdd Zddde_dd Zddde_dd Zddde_G dd deZeddddddZG dd deZG dd deZdd Zd d! Zd"d# Z d?d%d&Z!dd'de!_d(d) Z"dd)de"_d*d+ Z#d?d,d-Z$d.dd/e$_d?d0d1Z%d.ddd2e%_G d3d4 d4eZ&d5d6 Z'd7d6ie'_d8d9 Z(d:d; Z)dd<de)_d=d> Z*dd)de*_dS )@a  
This module provide some helpers for advanced types parsing.

You can define you own parser using the same pattern:

.. code-block:: python

    def my_type(value):
        if not condition:
            raise ValueError('This is not my type')
        return parse(value)

    # Swagger documentation
    my_type.__schema__ = {'type': 'string', 'format': 'my-custom-format'}

The last line allows you to document properly the type in the Swagger documentation.
    N)datetimetime	timedelta)parsedate_tz	mktime_tz)urlparsetzinfo   ;   i?B a  (?:(?P<auth>[^:@]+?(?::[^:@]*?)?)@)?(?:(?P<localhost>localhost)|(?P<ipv4>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:\[?(?P<ipv6>[A-F0-9]*:[A-F0-9:]+)\]?)|(?P<domain>(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)))(?::(?P<port>\d+))?$z9^(?P<local>[^@]*[^@.])@(?P<server>[^@\.]+(?:\.[^@\.]+)*)$z\d{2}:\d{2}c                 C   sF   zt |  | ddkr| W S W n
 t jy   Y nw td| )zValidate an IPv4 address.   {0} is not a valid ipv4 address)socket	inet_atoncounterror
ValueErrorformatvalue r   W/var/www/html/crm_dreinet/venv_linux/lib/python3.10/site-packages/flask_restx/inputs.pyipv48   s   
r   stringtyper   c                 C   s4   z
t t j|  | W S  t jy   td| w )zValidate an IPv6 addressr   )r   	inet_ptonAF_INET6r   r   r   r   r   r   r   ipv6F   s   r   c                 C   sF   zt | W S  ty   Y nw zt| W S  ty"   td| w )z+Validate an IP address (both IPv4 and IPv6)z{0} is not a valid ip)r   r   r   r   r   r   r   r   ipR   s   

r    c                   @   sH   e Zd ZdZ								dddZdddZdd	 Zed
d ZdS )URLaP  
    Validate an URL.

    Example::

        parser = reqparse.RequestParser()
        parser.add_argument('url', type=inputs.URL(schemes=['http', 'https']))

    Input to the ``URL`` argument will be rejected
    if it does not match an URL with specified constraints.
    If ``check`` is True it will also be rejected if the domain does not exists.

    :param bool check: Check the domain exists (perform a DNS resolution)
    :param bool ip: Allow IP (both ipv4/ipv6) as domain
    :param bool local: Allow localhost (both string or ip) as domain
    :param bool port: Allow a port to be present
    :param bool auth: Allow authentication to be present
    :param list|tuple schemes: Restrict valid schemes to this list
    :param list|tuple domains: Restrict valid domains to this list
    :param list|tuple exclude: Exclude some domains
    FNc	           	      C   s4   || _ || _|| _|| _|| _|| _|| _|| _d S N)checkr    localportauthschemesdomainsexclude)	selfr#   r    r$   r%   r&   r'   r(   r)   r   r   r   __init__x   s   
zURL.__init__c                 C   s$   d}|rd ||f}t||)Nz{0} is not a valid URLz. )joinr   r   )r*   r   detailsmsgr   r   r   r      s   z	URL.errorc              
   C   st  t |}t|j}t|j|jfs2t|jp%|jddd ddd r-| |d | | |jrD| j	rD|j| j	vrD| |d |sK| | |
 }|d sW|d r| jsa| |d	 n'zt|d pj|d  W n ty } z| |t| W Y d }~nd }~ww | js|d r|d d
r| |d n|d dkr| |d | jr	 |d r| js| |d |d r| js| |d |d r| js| |d nt|d }d|  k rdk sn | |d |d r8| jr|d | jvr| |d n| jr|d | jv r| |d | jr8zt|d d  W |S  tjy7   | |d Y |S w |S )N/   r   ?zDid you mean: http://{0}zProtocol is not allowedr   r   zIP is not allowed127.zLocalhost is not allowed::1r&   zAuthentication is not allowed	localhostr%   zCustom port is not allowedi  zPort is out of rangedomainzDomain is not allowedzDomain does not exists)r   netloc_regexmatchnetlocallschemepathsplitr   r'   	groupdictr    r   strr$   
startswithr#   r&   r%   intr(   r)   r   getaddrinfo)r*   r   parsednetloc_matchdataer%   r   r   r   __call__   sj   "


zURL.__call__c                 C   
   dddS )Nr   urlr   r   r*   r   r   r   
__schema__      zURL.__schema__)FFFFFNNNr"   )	__name__
__module____qualname____doc__r+   r   rF   propertyrJ   r   r   r   r   r!   a   s    

4r!   T)httphttpsftpftps)r    r&   r%   r$   r'   c                   @   s@   e Zd ZdZdddZdddZdd	 Zd
d Zedd Z	dS )emailaN  
    Validate an email.

    Example::

        parser = reqparse.RequestParser()
        parser.add_argument('email', type=inputs.email(dns=True))

    Input to the ``email`` argument will be rejected if it does not match an email
    and if domain does not exists.

    :param bool check: Check the domain exists (perform a DNS resolution)
    :param bool ip: Allow IP (both ipv4/ipv6) as domain
    :param bool local: Allow localhost (both string or ip) as domain
    :param list|tuple domains: Restrict valid domains to this list
    :param list|tuple exclude: Exclude some domains
    FNc                 C   s"   || _ || _|| _|| _|| _d S r"   )r#   r    r$   r(   r)   )r*   r#   r    r$   r(   r)   r   r   r   r+      s
   
zemail.__init__c                 C   s   |pd}t ||)Nz{0} is not a valid email)r   r   r*   r   r.   r   r   r   r      s   zemail.errorc                 C   s$   zt | W dS  ty   Y dS w )NTF)r    r   )r*   r   r   r   r   is_ip   s   zemail.is_ipc                 C   s   t |}|rd|v r| | |d}| jr0zt|d  W n tjy/   | | Y nw | jr>|| jvr>| |d | jrL|| jv rL| |d | j	s]|dv sX|
dr]| | | |rj| jsj| | |S )Nz..serverz-{0} does not belong to the authorized domainsz!{0} belongs to a forbidden domain)r4   r3   r2   )email_regexr7   r   groupr#   r   rA   r(   r)   r$   r?   rW   r    )r*   r   r7   rX   r   r   r   rF      s(   




zemail.__call__c                 C   rG   )Nr   rU   r   r   rI   r   r   r   rJ     rK   zemail.__schema__)FFFNNr"   )
rL   rM   rN   rO   r+   r   rW   rF   rP   rJ   r   r   r   r   rU      s    

rU   c                   @   s4   e Zd ZdZdd Zdd Zdd Zedd	 Zd
S )regexa`  
    Validate a string based on a regular expression.

    Example::

        parser = reqparse.RequestParser()
        parser.add_argument('example', type=inputs.regex('^[0-9]+$'))

    Input to the ``example`` argument will be rejected if it contains anything
    but numbers.

    :param str pattern: The regular expression the input must match
    c                 C   s   || _ t|| _d S r"   )patternrecompile)r*   r\   r   r   r   r+   )  s   zregex.__init__c                 C   s$   | j |sd| j}t||S )Nz#Value does not match pattern: "{0}")r]   searchr   r\   r   )r*   r   messager   r   r   rF   -  s   zregex.__call__c                 C   s
   t | jS r"   )r[   r\   )r*   memor   r   r   __deepcopy__3  s   
zregex.__deepcopy__c                 C   s   d| j dS )Nr   )r   r\   )r\   rI   r   r   r   rJ   6  s   zregex.__schema__N)	rL   rM   rN   rO   r+   rF   rb   rP   rJ   r   r   r   r   r[     s    r[   c                 C   sl   t | tst| t} t|t}| jdu r&tj| } tj|}| |fS | tj} |tj}| |fS )a  
    Normalize datetime intervals.

    Given a pair of datetime.date or datetime.datetime objects,
    returns a 2-tuple of tz-aware UTC datetimes spanning the same interval.

    For datetime.date objects, the returned interval starts at 00:00:00.0
    on the first date and ends at 00:00:00.0 on the second.

    Naive datetimes are upgraded to UTC.

    Timezone-aware datetimes are normalized to the UTC tzdata.

    Params:
        - start: A date or datetime
        - end: A date or datetime
    N)	
isinstancer   combineSTART_OF_DAYr	   pytzUTClocalize
astimezone)startendr   r   r   r   _normalize_interval>  s   

rl   c                 C   s   t | ts| tdd }|S |dd }tdd|}|d}|dkr.| tdd }|S |dkr;| tdd	 }|S | tdd
 }|S )Nr0   )daysTz[+-].+ :r   )hours)minutes)seconds)rc   r   r   r<   r]   subr   )rj   r   rk   r   time_without_offsetnum_separatorsr   r   r   _expand_datetime^  s   

rw   c                 C   sZ   zt t| W S  ty,   z
t| dfW  Y S  ty+   t| df Y  Y S w w )zg
    Do some nasty try/except voodoo to get some sort of datetime
    object(s) out of the string.
    N)sorted	aniso8601parse_intervalr   parse_datetime
parse_dater   r   r   r   _parse_intervalv  s   r}   argumentc                 C   sj   | st dzt| \}}|du rt|| }t||| \}}W ||fS  t y4   d}t |j|| dw )aG  
    Parses ISO 8601-formatted datetime intervals into tuples of datetimes.

    Accepts both a single date(time) or a full interval using either start/end
    or start/duration notation, with the following behavior:

    - Intervals are defined as inclusive start, exclusive end
    - Single datetimes are translated into the interval spanning the
      largest resolution not specified in the input value, up to the day.
    - The smallest accepted resolution is 1 second.
    - All timezones are accepted as values; returned datetimes are
      localized to UTC. Naive inputs and date inputs will are assumed UTC.

    Examples::

        "2013-01-01" -> datetime(2013, 1, 1), datetime(2013, 1, 2)
        "2013-01-01T12" -> datetime(2013, 1, 1, 12), datetime(2013, 1, 1, 13)
        "2013-01-01/2013-02-28" -> datetime(2013, 1, 1), datetime(2013, 2, 28)
        "2013-01-01/P3D" -> datetime(2013, 1, 1), datetime(2013, 1, 4)
        "2013-01-01T12:00/PT30M" -> datetime(2013, 1, 1, 12), datetime(2013, 1, 1, 12, 30)
        "2013-01-01T06:00/2013-01-01T12:00" -> datetime(2013, 1, 1, 6), datetime(2013, 1, 1, 12)

    :param str value: The ISO8601 date time as a string
    :return: Two UTC datetimes, the start and the end of the specified interval
    :rtype: A tuple (datetime, datetime)
    :raises ValueError: if the interval is invalid.
    z,Expected a valid ISO8601 date/time interval.NzIInvalid {arg}: {value}. {arg} must be a valid ISO8601 date/time interval.argr   )r   r}   rw   rl   r   )r   r~   rj   rk   r.   r   r   r   iso8601interval  s   
r   ziso8601-intervalc                 C   s   t | d}|S )z3Parse a valid looking date in the format YYYY-mm-ddz%Y-%m-%d)r   strptimer   dater   r   r   r     s   r   c              	   C   s,   zt | W S  ttfy   td| w )Nz{0} is not a valid integer)r@   	TypeErrorr   r   r   r   r   r   _get_integer  s
   
r   c                 C   *   t | } | dk rd}t|j|| d| S )z:Restrict input type to the natural numbers (0, 1, 2, 3...)r   z<Invalid {arg}: {value}. {arg} must be a non-negative integerr   r   r   r   r   r~   r.   r   r   r   natural  
   r   integer)r   minimumc                 C   r   )z9Restrict input type to the positive integers (1, 2, 3...)r0   z8Invalid {arg}: {value}. {arg} must be a positive integerr   r   r   r   r   r   positive  r   r   )r   r   exclusiveMinimumc                   @   s.   e Zd ZdZd
ddZdd Zedd Zd	S )	int_rangez3Restrict input to an integer in a range (inclusive)r~   c                 C   s   || _ || _|| _d S r"   )lowhighr~   )r*   r   r   r~   r   r   r   r+     s   
zint_range.__init__c                 C   s@   t |}|| jk s|| jkrd}t|j| j|| j| jd|S )Nz@Invalid {arg}: {val}. {arg} must be within the range {lo} - {hi})r   vallohi)r   r   r   r   r   r~   rV   r   r   r   rF     s   zint_range.__call__c                 C   s   d| j | jdS )Nr   )r   r   maximum)r   r   rI   r   r   r   rJ     s   zint_range.__schema__Nr~   )rL   rM   rN   rO   r+   rF   rP   rJ   r   r   r   r   r     s    
	r   c                 C   sX   t | tr| S | du rtd| sdS t|  } | dv rdS | dv r%dS td| )ap  
    Parse the string ``"true"`` or ``"false"`` as a boolean (case insensitive).

    Also accepts ``"1"`` and ``"0"`` as ``True``/``False`` (respectively).

    If the input is from the request JSON body, the type is already a native python boolean,
    and will be passed through without further parsing.

    :raises ValueError: if the boolean value is invalid
    Nzboolean type must be non-nullF)true1onT)false0z"Invalid literal for boolean(): {0})rc   boolr   r>   lowerr   r   r   r   r   boolean  s   
r   r   c                 C   s|   | }t | sd| df} z!t| }t|}|d du r(t|jtj	dW S t|tj	W S  t
y=   td|w )aH  
    Turns an RFC822 formatted date into a datetime object.

    Example::

        inputs.datetime_from_rfc822('Wed, 02 Oct 2002 08:00:00 EST')

    :param str value: The RFC822-complying string to transform
    :return: The parsed datetime
    :rtype: datetime
    :raises ValueError: if value is an invalid date literal

     z00:00:00Nr   Invalid date literal "{0}")
time_regexr_   r,   r   r   r   fromtimestampreplacerf   utc	Exceptionr   r   )r   raw	timetuple	timestampr   r   r   datetime_from_rfc822  s   
r   c                 C   s^   z zt | W W S  ty    t | }t|j|j|j Y W S w  ty.   td	| w )a>  
    Turns an ISO8601 formatted date into a datetime object.

    Example::

        inputs.datetime_from_iso8601("2012-01-01T23:30:00+02:00")

    :param str value: The ISO8601-complying string to transform
    :return: A datetime
    :rtype: datetime
    :raises ValueError: if value is an invalid date literal

    r   )
ry   r{   r   r|   r   yearmonthdayr   r   r   r   r   r   datetime_from_iso86019  s   
r   z	date-timec                 C   s   t |  S )a!  
    Turns an ISO8601 formatted date into a date object.

    Example::

        inputs.date_from_iso8601("2012-01-01")



    :param str value: The ISO8601-complying string to transform
    :return: A date
    :rtype: date
    :raises ValueError: if value is an invalid date literal

    )r   r   r   r   r   r   date_from_iso8601T  s   r   r   )+rO   r]   r   r   r   r   email.utilsr   r   urllib.parser   ry   rf   rg   re   
END_OF_DAYr^   
IGNORECASEr6   rY   r   r   rJ   r   r    objectr!   rH   rU   r[   rl   rw   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sf    	
	q
C$ 
0
	
	
!