
    3fi                        d dl Zd dl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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ZdZdZdZdZ ej:                  e      ZdZ  G d de      Z! G d de!      Z" G d de      Z# G d de      Z$ G d de      Z% G d de&      Z' G d d      Z( G d  d!      Z) G d" d#      Z* G d$ d%      Z+ G d& d'e+      Z, G d( d)      Z-y)*    N)OrderedDict)Enum)DictUnion)parse)ZoneInfoZoneInfoNotFoundError   )QueryBuilder)to_snake_case)fluent)get_iana_tzget_windows_tzmeusersgroupssitesz@odata.nextLinki  c                   &    e Zd ZdZd Zed        Zy)CaseEnumz7 A Enum that converts the value to a snake_case casing c                 P    t         j                  |       }t        |      |_        |S N)object__new__r   _value_)clsvalueobjs      N/var/www/auto_recruiter/arenv/lib/python3.12/site-packages/O365/utils/utils.pyr   zCaseEnum.__new__   s!    nnS!#E*
    c                 D    	  | t        |            S # t        $ r Y yw xY w)z. Gets a member by a snaked-case provided valueN)r   
ValueError)r   r   s     r   
from_valuezCaseEnum.from_value$   s)    	}U+,, 		s    	N)__name__
__module____qualname____doc__r   classmethodr"    r   r   r   r      s    A
  r   r   c                       e Zd ZdZdZdZy)ImportanceLevelnormallowhighN)r#   r$   r%   NormalLowHighr(   r   r   r*   r*   -   s    F
CDr   r*   c                   L    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZy)OutlookWellKnowFolderNamesInbox	JunkEmailDeletedItemsDrafts	SentItemsOutboxArchiveclutter	conflictsconversationhistorylocalfailuresrecoverableitemsdeletions	scheduledsearchfoldersserverfailures
syncissuesN)r#   r$   r%   INBOXJUNKDELETEDDRAFTSSENTOUTBOXARCHIVECLUTTER	CONFLICTSCONVERSATIONHISTORYLOCALFAILURESRECOVERABLEITEMSDELETIONS	SCHEDULEDSEARCHFOLDERSSERVERFAILURES
SYNCISSUESr(   r   r   r2   r2   3   sT    EDGFDFGGI/#M ;I#M%NJr   r2   c                   $    e Zd ZdZdZdZdZdZdZy)OneDriveWellKnowFolderNames	documentsphotos
camerarollapprootmusicattachmentsN)	r#   r$   r%   	DOCUMENTSPHOTOSCAMERA_ROLLAPP_ROOTMUSICATTACHMENTSr(   r   r   rT   rT   F   s     IFKHEKr   rT   c                       e Zd ZdZdZy)ChainOperatorandorN)r#   r$   r%   ANDORr(   r   r   rb   rb   O   s    
C	Br   rb   c                   8     e Zd Zdd fd
Z fdZ fdZ xZS )
TrackerSetN)casingc                2    || _         t        |   |i | y)z A Custom Set that changes the casing of it's keys

        :param func casing: a function to convert into specified case
        N)ccsuper__init__)selfri   argskwargs	__class__s       r   rm   zTrackerSet.__init__U   s    
 $)&)r   c                 F    | j                  |      }t        | 	  |       y r   )rk   rl   addrn   r   rq   s     r   rs   zTrackerSet.add]   s    Er   c                 F    | j                  |      }t        | 	  |       y r   )rk   rl   removert   s     r   rv   zTrackerSet.removea   s    ur   )r#   r$   r%   rm   rs   rv   __classcell__rq   s   @r   rh   rh   T   s    %) * r   rh   c                       e Zd ZdZddZd Zd Zd Zd Ze	d        Z
e
j                  d	        Z
e	d
        Zej                  d        Zy)	Recipientz A single Recipient Nc                 L    |xs d| _         |xs d| _        || _        || _        y)a#   Create a recipient with provided information

        :param str address: email address of the recipient
        :param str name: name of the recipient
        :param HandleRecipientsMixin parent: parent recipients handler
        :param str field: name of the field to update back
         N)_address_name_parent_field)rn   addressnameparentfields        r   rm   zRecipient.__init__i   s(      2ZR
r   c                 ,    t        | j                        S r   )boolr   rn   s    r   __bool__zRecipient.__bool__v   s    DLL!!r   c                 "    | j                         S r   __repr__r   s    r   __str__zRecipient.__str__y       }}r   c                 ~    | j                   r&dj                  | j                   | j                        S | j                  S )Nz{} <{}>)r   formatr   r   s    r   r   zRecipient.__repr__|   s.    99##DIIt||<<<<r   c                     | j                   rIt        | j                  dd      	 0| j                  j                  j	                  | j                          yyy)Y Update the track_changes on the parent to reflect a
        needed update on this field _track_changesN)r   getattrr   r   rs   r   s    r   r   zRecipient._track_changes   sI     ;;74<<1A#')045LL''++DKK85;r   c                     | j                   S )z Email address of the recipient

        :getter: Get the email address
        :setter: Set and update the email address
        :type: str
        )r}   r   s    r   r   zRecipient.address   s     }}r   c                 2    || _         | j                          y r   )r}   r   rn   r   s     r   r   zRecipient.address   s    r   c                     | j                   S )zz Name of the recipient

        :getter: Get the name
        :setter: Set and update the name
        :type: str
        )r~   r   s    r   r   zRecipient.name   s     zzr   c                 2    || _         | j                          y r   )r~   r   r   s     r   r   zRecipient.name   s    
r   )NNNN)r#   r$   r%   r&   rm   r   r   r   r   propertyr   setterr   r(   r   r   rz   rz   f   sv    " 9   ^^    
[[ r   rz   c                   `    e Zd ZdZddZd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zy)
Recipientsz A Sequence of Recipients Nc                 p    || _         || _        g | _        d| _        |r| j	                  |       d| _        y)a   Recipients must be a list of either address strings or
        tuples (name, address) or dictionary elements

        :param recipients: list of either address strings or
         tuples (name, address) or dictionary elements
        :type recipients: list[str] or list[tuple] or list[dict]
         or list[Recipient]
        :param HandleRecipientsMixin parent: parent recipients handler
        :param str field: name of the field to update back
        TFN)r   r   _recipientsuntrackrs   )rn   
recipientsr   r   s       r   rm   zRecipients.__init__   s7     HHZ r   c                 ,    t        | j                        S r   )iterr   r   s    r   __iter__zRecipients.__iter__   s    D$$%%r   c                      | j                   |   S r   )r   )rn   keys     r   __getitem__zRecipients.__getitem__   s    $$r   c                 X    || j                   D ch c]  }|j                   c}v S c c}w r   r   r   )rn   item	recipients      r   __contains__zRecipients.__contains__   s'    4;K;KLi	))LLLLs   'c                 >    t        t        | j                              S r   )r   lenr   r   s    r   r   zRecipients.__bool__   s    C(()**r   c                 ,    t        | j                        S r   )r   r   r   s    r   __len__zRecipients.__len__   s    4##$$r   c                 "    | j                         S r   r   r   s    r   r   zRecipients.__str__   r   r   c                 J    dj                  t        | j                              S )NzRecipients count: {})r   r   r   r   s    r   r   zRecipients.__repr__   s    %,,S1A1A-BCCr   c                     | j                   rXt        | j                  dd      	 ?| j                  du r0| j                  j                  j                  | j                          yyyy)r   r   NF)r   r   r   r   r   rs   r   s    r   r   zRecipients._track_changes   s[     ;;74<<1A#')0459=9NLL''++DKK8 :O5;r   c                 2    g | _         | j                          y)z Clear the list of recipients N)r   r   r   s    r   clearzRecipients.clear   s    r   c                 ,   |rt        |t              r<| j                  j                  t	        || j
                  | j                               nt        |t              r| j                  j                  |       nt        |t              rD|\  }}|rq| j                  j                  t	        ||| j
                  | j                               n4t        |t              r|D ]  }| j                  |        nt        d      | j                          yy)z Add the supplied recipients to the exiting list

        :param recipients: list of either address strings or
         tuples (name, address) or dictionary elements
        :type recipients: list[str] or list[tuple] or list[dict]
        )r   r   r   r   r   r   r   z]Recipients must be an address string, a Recipient instance, a (name, address) tuple or a listN)
isinstancestrr   appendrz   r   r   tuplelistrs   r!   r   )rn   r   r   r   r   s        r   rs   zRecipients.add   s     *c*  ''j$(KK12 J	2  ''
3J. *g$$++!')-T[[JK J-!+ (IHHY'( ! "3 4 4 !) r   c                 D   g }t        |t              r|h}n!t        |t        t        f      rt	        |      }| j
                  D ]"  }|j                  |vs|j                  |       $ t        |      t        | j
                        k7  r| j                          || _        y)z Remove an address or multiple addresses

        :param address: list of addresses to remove
        :type address: str or list[str]
        N)
r   r   r   r   setr   r   r   r   r   )rn   r   r   r   s       r   rv   zRecipients.remove   s     
gs#iG$/'lG)) 	-I  /!!),	- z?c$"2"233!%r   c                 f    | j                   D cg c]  }|j                  r| }}|r|d   S yc c}w )z Returns the first recipient found with a non blank address

        :return: First Recipient
        :rtype: Recipient
        r   Nr   )rn   r   recipients_with_addresss      r    get_first_recipient_with_addressz+Recipients.get_first_recipient_with_address  sG     ?C>N>N #9&/&7&7 $- #9 #9"*1--#9s   .)NNN)r#   r$   r%   r&   rm   r   r   r   r   r   r   r   r   r   rs   rv   r   r(   r   r   r   r      sH    $&&%M+%D9
"<&&r   r   c                   "    e Zd ZddZddZd Zy)HandleRecipientsMixinNc                 t    g }|D ]$  }|j                  | j                  ||             & t        || |      S )6 Transform a recipient from cloud data to object data )r   )r   r   )r   _recipient_from_cloudr   )rn   r   r   recipients_datar   s        r   _recipients_from_cloudz,HandleRecipientsMixin._recipients_from_cloud"  sK    # 	DI""**9E*BD	D /$eDDr   c                 "   |r|j                  | j                  d      t        |t              r|ni       }|j                  | j                  d      d      }|j                  | j                  d      d      }t	        ||| |      S t	               S )r   emailAddressr   r|   r   r   )get_ccr   dictrz   )rn   r   r   r   r   s        r   r   z+HandleRecipientsMixin._recipient_from_cloud*  s     !dhh~&>3=i>B4DiIKMI  mmDHHY$7<G==&!126DW4#(* * ;r   c                     d}|rj| j                  d      | j                  d      |j                  ii}|j                  r0|j                  || j                  d         | j                  d      <   |S )z/ Transforms a Recipient object to a cloud dict Nr   r   r   )r   r   r   )rn   r   datas      r   _recipient_to_cloudz)HandleRecipientsMixin._recipient_to_cloud8  sm    HH^,#Y%6%6/8 9D~~(1 TXXn-.HHV$&r   r   )r#   r$   r%   r   r   r   r(   r   r   r   r      s    E	r   r   c            	            e Zd ZdZdZi Zddd fd
Zd Zd Ze	d        Z
d	 Zd
 Zd Zd Zd Z	 ddeeef   dedeej*                  df   fdZdej*                  deeef   fdZdefdZeZ xZS )ApiComponentz Base class for all object interactions with the Cloud Service API

    Exposes common access methods to the api protocol within all Api objects
    __cloud_data__Nprotocolmain_resourcec                    t        |t              r |       n|| _        | j                  t        d      | j	                  |      \  }}|| _        || _        t        | !          y)z Object initialization

        :param Protocol protocol: A protocol class or instance to be used with
         this connection
        :param str main_resource: main_resource to be used in these API
         communications
        Nz&Protocol not provided to Api Component)	r   typer   r!   build_base_urlr   	_base_urlrl   rm   )rn   r   r   rp   mrburq   s         r   rm   zApiComponent.__init__M  s]     '14&@
h== EFF$$]3Br   c                 "    | j                         S r   r   r   s    r   r   zApiComponent.__str___  r   r   c                 8    dj                  | j                        S )NzApi Component on resource: {})r   r   r   s    r   r   zApiComponent.__repr__b  s    .55d6H6HIIr   c                 *   | r| j                         n| } | r(t        t        d | j                  d                  d   n| }d|vrd|vr| S d|v rdj	                  t
        |       S | j                  d      r)| j                  ddd	      } dj	                  t
        |       S | j                  d
      r)| j                  d
dd	      } dj	                  t        |       S | j                  d      r)| j                  ddd	      } dj	                  t        |       S | S )z+ Parses and completes resource information c                     | S r   r(   )parts    r   <lambda>z.ApiComponent._parse_resource.<locals>.<lambda>i  s    $ r   /r   :@z{}/{}zuser:r|   r
   zgroup:zsite:)
stripr   filtersplitr   USERS_RESOURCE
startswithreplaceGROUPS_RESOURCESITES_RESOURCE)resourceresource_starts     r   _parse_resourcezApiComponent._parse_resourcee  s    (08>>#XT\f%6s8KLMaPbjn$N)BO. 
 >>.(;;  )''Q7H>>.(;;  *''"a8H>>/8<<  )''Q7H>>.(;;Or   c                     | j                  ||n| j                  j                        }dj                  | j                  j                  |      }|j                  d      r|dd }||fS )zz
        Builds the base url of this ApiComponent
        :param str resource: the resource to build the base url
        N{}{}r   )r   r   default_resourcer   service_urlendswith)rn   r   r   base_urls       r   r   zApiComponent.build_base_url  sf    
 ,,9MXSWS`S`SqSqr==!:!:MJS!}Hh&&r   c                 @    | j                  |      \  | _        | _        y)zz
        Sets the base urls for this ApiComponent
        :param str resource: the resource to build the base url
        N)r   r   r   )rn   r   s     r   set_base_urlzApiComponent.set_base_url  s    
 .2-@-@-J*DNr   c                 :    dj                  | j                  |      S )z Returns a url for a given endpoint using the protocol
        service url

        :param str endpoint: endpoint to build the url for
        :return: final url
        :rtype: str
        r   )r   r   )rn   endpoints     r   	build_urlzApiComponent.build_url  s     }}T^^X66r   c                 8    | j                   j                  |      S )z( Alias for protocol.get_service_keyword )r   get_service_keyword)rn   keywords     r   _gkzApiComponent._gk  s    }}0099r   c                 8    | j                   j                  |      S )z! Alias for protocol.convert_case )r   convert_case)rn   dict_keys     r   r   zApiComponent._cc  s    }}))(33r   date_time_time_zone
is_all_dayreturnc                    |y| j                   j                  }t        |t              r	 t	        |j                  | j                  d      d            }|j                  | j                  d      d      }	 |rt        |      j                  |      nd}|r,||k7  r'|s|j                  |      }|S |j                  |      }|S 	 |rt        |      j                  |      }|S d}|S # t        $ r t        j                  d       |}Y w xY w# t        $ r'}t        j                  d| d|        d}Y d}~d}~ww xY w# t        $ r(}t        j                  d| d|        d}Y d}~|S d}~ww xY w)	a7  
        Parses and convert to protocol timezone a dateTimeTimeZone resource
        This resource is a dict with a date time and a windows timezone
        This is a common structure on Microsoft apis so it's included here.

        Returns a dt.datetime with the datime converted to protocol timezone
        NtimeZoneUTCz4TimeZone not found. Using protocol timezone instead.dateTimetzinfoz"Could not parse dateTimeTimeZone: z	. Error: )r   timezoner   r   r   r   r   r	   logdebugr   r   OverflowError
astimezone	Exception)rn   r  r  local_tzr  	date_timees          r   _parse_date_time_time_zonez'ApiComponent._parse_date_time_time_zone  s    &==)))40$&':'>'>txx
?SUZ'[\ ,//0DdKI!IRE),44H4EX\	
 X1! ) 4 4X >I  !* 1 1 1 BI !SfE"56>>h>O	
  mq	
 / ) $		PQ#$ ! !		>?R>SS\]^\_`a 	!  !		>?R>SS\]^\_`a 		!sG   *C* 7D E &E * DD	E D;;E 	E4E//E4r  c                 J   d}|j                   |t        |j                   t              r|j                   }nUt        |j                   t        j                         r&	 t        |j                   j	                  |            }nt        d      t        |xs | j                  j                        }| j                  d      |j                  d      | j                  d      |iS # t
        $ r8}t        j                  d|j                   j	                  |              |d}~ww xY w)zU Converts a datetime to a dateTimeTimeZone resource Dict[datetime, windows timezone] Nz4Error while converting datetime.tzinfo to Zoneinfo: z3Unexpected tzinfo class. Can't convert to ZoneInfo.r	  z%Y-%m-%dT%H:%M:%Sr  )r  r   r   dttznamer	   r  errorr!   r   r   r  r   strftime)rn   r  r  r  s       r   _build_date_time_time_zonez'ApiComponent._build_date_time_time_zone  s    ')**H5$++I,,bii8'	(8(8(?(?	(JKH !!VWW "("Ddmm.D.DE HHZ )"4"45H"IHHZ (
 	
 - II T!*!1!1!8!8!C DF GGs   $C! !	D"*3DD"c                 .    t        | j                        S )z Create a new query to filter results

        :param str attribute: attribute to apply the query for
        :return: new QueryBuilder
        :rtype: QueryBuilder
        )r   )r   r   r   s    r   	new_queryzApiComponent.new_query  s     T]]33r   F)r#   r$   r%   r&   _cloud_data_key
_endpointsrm   r   r   staticmethodr   r   r   r   r   r   r   r   r   r   r  datetimer  r   r  r   r  qrw   rx   s   @r   r   r   D  s    
 'OJ#'t $J  :'K7:4 7<(8=dCi8H(/3(@EbkkSWFW@X(T
BKK 
DcN 
44< 4 	Ar   r   c                   N     e Zd ZdZdddddd fd
Zd Zd Zd Zd Zd	 Z	 xZ
S )

Paginationz; Utility class that allows batching requests to the server N)r   r   constructor	next_linklimitc                j   |t        d      t        | 	  |j                  |j                         || _        |j                  | _        || _        || _        || _	        |rt        |      ng x| _        }t        |      }|r||k  r|| _        || _        n|| _        || _        d| _        || _        y)a  Returns an iterator that returns data until it's exhausted.
        Then will request more data (same amount as the original request)
        to the server until this data is exhausted as well.
        Stops when no more data exists or limit is reached.

        :param parent: the parent class. Must implement attributes:
         con, api_version, main_resource
        :param data: the start data to be return
        :param constructor: the data constructor for the next batch.
         It can be a function.
        :param str next_link: the link to request more data to
        :param int limit: when to stop retrieving more data
        :param kwargs: any extra key-word arguments to pass to the
         constructor.
        Nz$Parent must be another Api Componentr   r   )r!   rl   rm   r   r   r   conr&  r'  r(  r   r   r   
data_counttotal_countstate
extra_args)	rn   r   r   r&  r'  r(  rp   r+  rq   s	           r   rm   zPagination.__init__  s    " >CDD&//'-';'; 	 	= ::&"
)-4:25	DY
UZ'#DO$D(DO)D
 r   c                 "    | j                         S r   r   r   s    r   r   zPagination.__str__-  r   r   c                     t        | j                        rt        | j                  t              sydj	                  | j                  r| j                  j
                        S d      S )NzPagination Iteratorz'{}' IteratorUnknown)callabler&  r   r   r   r#   r   s    r   r   zPagination.__repr__0  s`    D$$%j  $/(("))-1-=-=  ))N NCLN Nr   c                 Z    t        | j                        xs t        | j                        S r   )r   r   r'  r   s    r   r   zPagination.__bool__8  s    DII6$t~~"66r   c                     | S r   r(   r   s    r   r   zPagination.__iter__;  s    r   c                 ~   | j                   | j                  k  r0| j                  | j                      }| xj                   dz  c_         |S | j                  r#| j                  | j                  k\  r
t               | j                  
t               | j                  j                  | j                        }|s
t               |j                         }|j                  t        d       xs d | _        |j                  dg       }| j                  rg | _        i }|j                  | j                         t        | j                        rmt        | j                  t               sS|D ]M  }||| j"                  <   | j                  j%                   | j                  |      dd| j&                  i|       O nU|D ]H  }||| j"                  <   | j                  j%                   | j                  dd| j&                  i|       J n|| _        t)        |      }| j                  rA| j                  | j                  |z   z
  }|dk  r | j                  d | | _        d | _        ||z   }|rS|| _        | xj                  |z  c_        d| _         | j                  | j                      }| xj                   dz  c_         |S t               )Nr
   r   r   r   r(   )r-  r+  r   r(  r,  StopIterationr'  r*  r   jsonNEXT_LINK_KEYWORDr&  updater.  r2  r   r   r  r   r   r   )rn   r   responser   rp   items_countdifs          r   __next__zPagination.__next__>  sI   ::'IIdjj)EJJ!OJLzzd..$**<#o%>>!/!88<<//!}}"3T:Bdxx$DIFMM$//*(()*T=M=Mt2T! \E38F4//0II$$%<T%5%5e%<%ZDKK%ZSY%Z[\ " UE38F4//0II$$%5T%5%5%ST[[%SF%STU DI$i::** 0 0; >?CQw IIdsO	!%)C/)DO+DJIIdjj)EJJ!OJL/!r   )r#   r$   r%   r&   rm   r   r   r   r   r=  rw   rx   s   @r   r%  r%    s2    E!%Ddt/!bN73"r   r%  c            	          e Zd ZdZdddddddd	d
Zd@dZd Zd Zed        Z	ed        Z
ed        Zd Zed        Zed        Zed        Zed        Zd Zd Zd Zd Zd Zd Zeej2                  fd       Zd Zd Zed         Zed!        Zeej2                  fd"       Zed#        Z ed$        Z!d% Z"d& Z#d' Z$e%dAd)       Z&ed*        Z'ed+        Z(ed,        Z)ed-        Z*ed.        Z+ed/        Z,ed0        Z-e%dAd1       Z.ed2        Z/ed3        Z0ed4        Z1ed5        Z2edddd(d6d7       Z3edddd(d6d8       Z4edddd(d6d9       Z5ed@d:d;d<       Z6d= Z7d> Z8d? Z9y)BQueryz! Helper to conform OData filters zfrom/emailAddress/addressz!toRecipients/emailAddress/addresszstart/DateTimezend/DateTimezduedatetime/DateTimezreminderdatetime/DateTimezflag/flagStatuszbody/content)fromtostartendduereminderflagbodyNc                   t        |t              r |       n|| _        d| _        d| _        | j                  |       d| _        g | _        t               | _	        t               | _        t               | _        d| _        g | _        g | _        y)z Build a query to apply OData filters
        https://docs.microsoft.com/en-us/graph/query-parameters

        :param str attribute: attribute to apply the query for
        :param Protocol protocol: protocol to use for connecting
        NF)r   r   r   
_attribute_chainnew	_negation_filtersr   	_order_byr   _selects_expands_search_open_group_flag_close_group_flag)rn   	attributer   s      r   rm   zQuery.__init__  sr     '14&@
h$ "!#r   c                     dj                  | j                         | j                         | j                         | j	                         | j
                        S )Nz5Filter: {}
Order: {}
Select: {}
Expand: {}
Search: {})r   get_filters	get_orderget_selectsget_expandsrQ  r   s    r   r   zQuery.__str__  sP    JQQRVRbRbRdRVR`R`RbRVRbRbRdRVRbRbRdRVR^R^	` 	`r   c                 "    | j                         S r   )r   r   s    r   r   zQuery.__repr__  s    ||~r   c                 j   |r|D ]x  }|r+t        |t              r| j                  j                  |      nd}|s5d|v r|j	                  d      d   }| j                  |      }| j                  j                  |       z | S | j                  r%| j                  j                  | j                         | S )z Adds the attribute to the $select parameter

        :param str attributes: the attributes tuple to select.
         If empty, the on_attribute previously set is added.
        :rtype: Query
        Nr   r   )	r   r   r   r  r   _get_select_mappingrO  rs   rI  )rn   
attributesrT  s      r   selectzQuery.select  s     ' 	1	"+
9;>1@ !MM66EI  i'$-OOC$8$;	 $ 8 8 CIMM%%i0	1  !!$//2r   c                     |D ]L  }|dk(  r*dj                  | j                  j                  d            }| j                  j	                  |       N | S )a  
        Adds the relationships (e.g. "event" or "attachments")
        that should be expanded with the $expand parameter
        Important: The ApiComponent using this should know how to handle this relationships.

            eg: Message knows how to handle attachments, and event (if it's an EventMessage)

        Important: When using expand on multi-value relationships a max of 20 items will be returned.

        :param str relationships: the relationships tuple to expand.
        :rtype: Query
        eventz{}/eventevent_message_type)r   r   r   rP  rs   )rn   relationshipsrelationships      r   expandzQuery.expand  sY     * 	,Lw&)00MM556JK  MMl+	, r   c                     |	d| _         | S | j                          | j                          dj                  |      | _         | S )aP  
        Perform a search.
        Not from graph docs:

         You can currently search only message and person collections.
         A $search request returns up to 250 results.
         You cannot use $filter or $orderby in a search request.

        :param str text: the text to search
        :return: the Query instance
        Nz"{}")rQ  clear_filtersclear_orderr   )rn   texts     r   searchzQuery.search  sF     <DL 	  !==.DLr   c                 B   i }| j                   r| j                         |d<   | j                  r| j                         |d<   | j                  r| j
                  s| j                         |d<   | j
                  r| j                  s| j                         |d<   | j                  r=| j
                  r1dj                  | j                         | j                               |d<   | j                  r3| j                  |d<   |j                  dd       |j                  dd       |S )zk Returns the filters, orders, select, expands and search as query parameters

        :rtype: dict
        z$filterz$orderbyz$expandz$selectz{}($select={})z$searchN)has_filtersrV  	has_orderrW  has_expandshas_selectsrY  rX  r   rQ  pop)rn   paramss     r   	as_paramszQuery.as_params  s    
  $ 0 0 2F9>>!%!1F:D$4$4 $ 0 0 2F9D$4$4 $ 0 0 2F9 0 0 0 7 78H8H8JDL\L\L^ _F9<< $F9JJy$'JJz4(r   c                 ,    t        | j                        S )zD Whether the query has filters or not

        :rtype: bool
        )r   rM  r   s    r   rk  zQuery.has_filters       DMM""r   c                 ,    t        | j                        S )zE Whether the query has order_by or not

        :rtype: bool
        )r   rN  r   s    r   rl  zQuery.has_order  s     DNN##r   c                 ,    t        | j                        S )zK Whether the query has select filters or not

        :rtype: bool
        )r   rO  r   s    r   rn  zQuery.has_selects  rs  r   c                 ,    t        | j                        S )zc Whether the query has relationships that should be expanded or not

         :rtype: bool
        )r   rP  r   s    r   rm  zQuery.has_expands  rs  r   c           	         | j                   r| j                   }t        |d   t              r|dd }dj                  |D cg c]#  }t        |t              r|j                  n|d   % c}      j                         }t        | j                  D cg c]	  }|du s| c}      }t        |t        | j                        z
        D ]  }|dz  }	 |S yc c}w c c}w )zA Returns the result filters

        :rtype: str or None
        r   N r
   F))
rM  r   r   joinr   r   r   rR  rangerS  )rn   filters_listfsfiltersxopen_groupsis          r   rV  zQuery.get_filters  s    
 ====L,r*D1+CR0hhGSTZD1r!u<Teg 
 $*?*?NQ1:qNOK;T-C-C)DDE 3 N U Os    (C	CCc                     | j                   sydj                  | j                  j                         D cg c])  \  }}dj	                  ||xs d      j                         + c}}      S c c}}w )zJ Returns the result order by clauses

        :rtype: str or None
        N,z{} {}r|   )rl  rz  rN  itemsr   r   )rn   rT  	directions      r   rW  zQuery.get_order4  sh     ~~xx59^^5I5I5KM1Y	 !	9?CIIK M N 	N Ms   .A,
c                 R    | j                   rdj                  | j                         S y)zG Returns the result select clause

        :rtype: str or None
        r  N)rO  rz  r   s    r   rX  zQuery.get_selectsA  !    
 ==88DMM**r   c                 R    | j                   rdj                  | j                         S y)zH Returns the result expand clause

         :rtype: str or None
        r  N)rP  rz  r   s    r   rY  zQuery.get_expandsK  r  r   c                    |r| j                   j                  |      }|rIdj                  |j                  d      D cg c]  }| j                  j                  |       c}      }|S | j                  j                  |      }|S y c c}w )Nr   )_mappingr   rz  r   r   r  )rn   rT  mappingsteps       r   _get_mappingzQuery._get_mappingU  s    mm''	2GHH]]3')$T]]//5 )*	
  !MM66yA	)s   "Bc                 f    |j                         dv r| j                  j                  d    d| S |S )N)meetingMessageTypera  r   )lowerr   keyword_data_storern   rT  s     r   r\  zQuery._get_select_mappinga  s>    ?? 66==334HIJ!I;W r   c                     t        |t              rt        |      }|| _        |r| j	                  |      nd| _        d| _        | S )z Combine with a new query

        :param str attribute: attribute of new query
        :param ChainOperator operation: operation to combine to new query
        :rtype: Query
        NF)r   r   rb   rJ  r  rI  rL  )rn   rT  	operations      r   rK  z	Query.newh  sA     i%%i0I:C$++I6r   c                     g | _         y)z Clear filters N)rM  r   s    r   rf  zQuery.clear_filtersw  s	    r   c                 "    t               | _        y)z Clears any order commands N)r   rN  r   s    r   rg  zQuery.clear_order{  s    $r   c                     g | _         t               | _        t               | _        d| _        d| _        d| _        d| _        g | _	        g | _
        | S )z1 Clear everything

        :rtype: Query
        FN)rM  r   rN  r   rO  rL  rI  rJ  rQ  rR  rS  r   s    r   r   zQuery.clear  sN     $ "!#r   c                 *    | j                    | _         | S )z5 Apply a not operator

        :rtype: Query
        )rL  r   s    r   negatezQuery.negate  s     "^^+r   c                 J    t        |t              rt        |      }|| _        | S )z Start a chain operation

        :param ChainOperator, str operation: how to combine with a new one
        :rtype: Query
        )r   r   rb   rJ  )rn   r  s     r   chainzQuery.chain  s$     i%%i0Ir   c                 2    | j                  |      | _        | S )z Apply query on attribute, to be used along with chain()

        :param str attribute: attribute name
        :rtype: Query
        )r  rI  r  s     r   on_attributezQuery.on_attribute  s     ++I6r   c                     d|z   | _         | S )z Apply query on a list field, to be used along with chain()

        :param str field: field name (note: name is case sensitive)
        :rtype: Query
        zfields/)rI  )rn   r   s     r   on_list_fieldzQuery.on_list_field  s     $e+r   c                     | j                  |      }g }d}| j                  D ]G  }t        |t              r|d   |k(  rd}|j	                  |       0|du r|j	                  |       Fd}I || _        y)z+ Removes a filter given the attribute name Fr   TN)r  rM  r   r   r   )rn   filter_attrnew_filtersremove_chainflts        r   remove_filterzQuery.remove_filter  s~    ''4== 	)C#t$q6[(#'L&&s+  5(&&s+#(L	) $r   c                    | j                   r| j                  rBt        | j                  d   t              s%| j                  j	                  | j
                         |\  }}t        | j                        D ]*  \  }}|du s||du rd|z   }nd|z   }d| j                  |<   , | j                  j	                  | j                   ||g       y t        d      )Nr   T(znot (FIAttribute property needed. call on_attribute(attribute) or new(attribute))	rI  rM  r   rb   r   rJ  	enumeraterR  r!   )rn   filter_datasentenceattrsr  groups         r   _add_filterzQuery._add_filter  s    ??}}Zb0A0=&?$$T[[1)OHe%d&;&;< 55D=EM}#&>#*X#5/4D))!,5 MM  $//8U!CD$% %r   c                    t        |t              rdj                  |      }|S t        |t        j                        rt        |t        j
                        r2|j                  &|j                  | j                  j                        }d| j                  v r!dj                  |j                               }|S dj                  |j                               }|S t        |t              rt        |      j                         }|S |d}|S )z5 Converts the word parameter into the correct format z'{}'r
  r   z{}null)r   r   r   r  dater"  r  r   r   r  rI  	isoformatr   r  rn   words     r   _parse_filter_wordzQuery._parse_filter_word  s    dC ==&D. - bgg&$,;;&<<t}}/E/E<FDdoo% }}NN$&  {{NN$& 	 d#t9??$D  \Dr   Fc                 f    |rdnd}|| ||f}dj                  || ||      j                         }||fS )Nnotr|   z{} {} {} {}r   r   )rT  r  r  negationr  r  s         r   _prepare_sentencezQuery._prepare_sentence  sB    $5"9i6 '')YMSSUr   c                     | j                  |      }| j                  }|rd| _         | j                  | j                  | j                  |||        | S )z Apply a logical operator

        :param str operation: how to combine with a new one
        :param word: other parameter for the operation
         (a = b) would be like a.logical_operator('eq', 'b')
        :rtype: Query
        F)r  rL  r  r  rI  )rn   r  r  r  s       r   logical_operatorzQuery.logical_operator  sV     &&t,>>"DN##DOOYhO	
 r   c                 &    | j                  d|      S )z^ Add an equals check

        :param word: word to compare with
        :rtype: Query
        eqr  r  s     r   equalszQuery.equals       $$T400r   c                 &    | j                  d|      S )z` Add an unequals check

        :param word: word to compare with
        :rtype: Query
        ner  r  s     r   unequalzQuery.unequal"  r  r   c                 &    | j                  d|      S )zc Add a greater than check

        :param word: word to compare with
        :rtype: Query
        gtr  r  s     r   greaterzQuery.greater+  r  r   c                 &    | j                  d|      S )zo Add a greater than or equal to check

        :param word: word to compare with
        :rtype: Query
        ger  r  s     r   greater_equalzQuery.greater_equal4  r  r   c                 &    | j                  d|      S )z` Add a less than check

        :param word: word to compare with
        :rtype: Query
        ltr  r  s     r   lessz
Query.less=  r  r   c                 &    | j                  d|      S )zl Add a less than or equal to check

        :param word: word to compare with
        :rtype: Query
        ler  r  s     r   
less_equalzQuery.less_equalF  r  r   c                 b    |rdnd}||| |f}dj                  || ||      j                         |fS )Nr  r|   z{} {}({}, {})r  )function_namerT  r  r  r  s        r   _prepare_functionzQuery._prepare_functionO  s?    $5"9mT:%%hy$OUUWY^^^r   c                     | j                  |      }| j                  }|rd| _         | j                  | j                  || j                  ||        | S )z Apply a function on given word

        :param str function_name: function to apply
        :param str word: word to apply function on
        :rtype: Query
        F)r  rL  r  r  rI  )rn   r  r  r  s       r   functionzQuery.functionU  sU     &&t,>>"DN##M4??D(S	Ur   c                 &    | j                  d|      S )zb Adds a contains word check

        :param str word: word to check
        :rtype: Query
        containsr  r  s     r   r  zQuery.containsf       }}Z..r   c                 &    | j                  d|      S )zd Adds a startswith word check

        :param str word: word to check
        :rtype: Query
        r   r  r  s     r   r   zQuery.startswitho  s     }}\400r   c                 &    | j                  d|      S )zb Adds a endswith word check

        :param str word: word to check
        :rtype: Query
        r   r  r  s     r   r   zQuery.endswithx  r  r   )rT  funcr  r  c                   ||t        d      ||t        d      | j                  }|| _        | j                  |      }| j                  |      }| j                  |      }|d}ndj	                  |      }|| j                  ||||      }	n| j                  ||||      }	|	\  }
}| j                  rdnd}| j                  rd| _        dj	                  ||||
      j                         |f} | j                  |  || _        | S )	a   Performs a filter with the OData 'iterable_name' keyword
        on the collection

        For example:
        q.iterable('any', collection='email_addresses', attribute='address',
        operation='eq', word='george@best.com')

        will transform to a filter such as:
        emailAddresses/any(a:a/address eq 'george@best.com')

        :param str iterable_name: the OData name of the iterable
        :param str collection: the collection to apply the 'any' keyword on
        :param str word: the word to check
        :param str attribute: the attribute of the collection to check
        :param str func: the logical function to apply to the attribute inside
         the collection
        :param str operation: the logical operation to apply to the attribute
         inside the collection
        :param bool negation: negate the function or operation inside the iterable
        :rtype: Query
        z+Provide a function or an operation to applyz6Provide either a function or an operation but not bothaza/{}r  r|   Fz{} {}/{}(a:{}))
r!   rI  r  r  r   r  r  rL  r   r  )rn   iterable_name
collectionr  rT  r  r  r  current_attr  
filter_strr  r  s                r   iterablezQuery.iterable  s%   2 <I-JKK)"7UVVoo'&&t,&&z2
%%i0	Ii0I--dItXNH--iD(SH$
E !NN5>>"DN&--h
MS]^ddfhmm+&%r   c          	      2    | j                  d||||||      S )a9   Performs a filter with the OData 'any' keyword on the collection

        For example:
        q.any(collection='email_addresses', attribute='address',
        operation='eq', word='george@best.com')

        will transform to a filter such as:

        emailAddresses/any(a:a/address eq 'george@best.com')

        :param str collection: the collection to apply the 'any' keyword on
        :param str word: the word to check
        :param str attribute: the attribute of the collection to check
        :param str func: the logical function to apply to the attribute
         inside the collection
        :param str operation: the logical operation to apply to the
         attribute inside the collection
        :param bool negation: negates the function or operation inside the iterable
        :rtype: Query
        anyr  r  rT  r  r  r  r  rn   r  r  rT  r  r  r  s          r   r  z	Query.any  *    . }}Uz'0ty&.  0 	0r   c          	      2    | j                  d||||||      S )a6   Performs a filter with the OData 'all' keyword on the collection

        For example:
        q.any(collection='email_addresses', attribute='address',
        operation='eq', word='george@best.com')

        will transform to a filter such as:

        emailAddresses/all(a:a/address eq 'george@best.com')

        :param str collection: the collection to apply the any keyword on
        :param str word: the word to check
        :param str attribute: the attribute of the collection to check
        :param str func: the logical function to apply to the attribute
         inside the collection
        :param str operation: the logical operation to apply to the
         attribute inside the collection
        :param bool negation: negate the function or operation inside the iterable
        :rtype: Query
        allr  r  r  s          r   r  z	Query.all  r  r   T)	ascendingc                    | j                  |      xs | j                  }|r|rdnd| j                  |<   | S t        d      )z Applies a order_by clause

        :param str attribute: attribute to apply on
        :param bool ascending: should it apply ascending order or descending
        :rtype: Query
        Ndescr  )r  rI  rN  r!   )rn   rT  r  s      r   order_byzQuery.order_by  sM     %%i0CDOO	09vDNN9%
  $% %r   c                     | j                   r$d| _         | j                  j                  d       | S | j                  j                  d       | S )z3 Applies a precedence grouping in the next filters FNT)rL  rR  r   r   s    r   
open_groupzQuery.open_group  sH     >>"DN!!((.  !!((.r   c                 j   | j                   rt        | j                        t        | j                        dz   k  rt	        d      t        | j                   d   t              r| j                   d   }n| j                   d   }|d   dz   |d<   | j                  j                  d       | S t	        d      )z( Closes a grouping for previous filters r
   z Not enough open groups to close.r   ry  Fz'No filters present. Can't close a group)rM  r   rR  rS  RuntimeErrorr   rb   r   )rn   flt_sentences     r   close_groupzQuery.close_group  s    ==4(()S1G1G-H1-LM"#EFF$--+];#}}R0#}}R0*1o3LO""))%0  HIIr   c                     |j                         }| j                  D ]C  }t        |t              s|d   }|d   d   }|j                         j	                  |      sA|c S  y)a"  
        Returns a filter value by attribute name. It will match the attribute to the start of each filter attribute
        and return the first found.
        
        :param attribute: the attribute you want to search
        :return: The value applied to that attribute or None
        r         N)r  rM  r   r   r   )rn   rT  
query_datafilter_attributer  s        r   get_filter_by_attributezQuery.get_filter_by_attribute  sm     OO%	 -- 		Jj$/)!} a=#D%%'229=		 r   r   r  ):r#   r$   r%   r&   r  rm   r   r   r   r^  rd  ri  rq  r   rk  rl  rn  rm  rV  rW  rX  rY  r  r\  rb   re   rK  rf  rg  r   r  r  r  r  r  r  r  r!  r  r  r  r  r  r  r  r  r  r  r  r   r   r  r  r  r  r  r  r  r(   r   r   r?  r?  t  s   ++1!%/!	H$*`  0  .  ,, # # $ $ # # # #,N
 '4'8'8  '  "   +// 	 	    $*%(8    $ 1 1 1 1 1 1 1 1 1 1 1 1 _ _
    / / 1 1 / / EIPT%: :x 15DD[` 0 04 15DD[` 0 04 D    r   r?  ).r"  r  loggingcollectionsr   enumr   typingr   r   dateutil.parserr   zoneinfor   r	   queryr   ri   r   
decoratorsr   
windows_tzr   r   ME_RESOURCEr   r   r   r8  	getLoggerr#   r  MAX_RECIPIENTS_PER_MESSAGEr   r*   r2   rT   rb   r   rh   rz   r   r   r   r%  r?  r(   r   r   <module>r	     s      #   ! 4  !  3 & g!  t "h  & $  D 
 $@ @Ft tn! !Hr rjx" x"vA Ar   