o
    .jQ                     @  s   d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	 ddl
mZmZmZmZmZmZmZmZ ddlmZmZmZmZmZmZmZ ddlmZ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)m*Z* e+dZ,G dd deZ-dS )u   
Asynchronous JMAP client.

Mirrors JMAPClient with all public methods as coroutines.
Uses niquests.AsyncSession for HTTP — niquests is a core dependency.
    )annotationsN)AsyncSession)build_calendar_getparse_calendar_get)build_event_changesbuild_event_getbuild_event_set_createbuild_event_set_destroybuild_event_set_updateparse_event_changesparse_event_getparse_event_set)build_task_getbuild_task_list_getbuild_task_set_createbuild_task_set_destroybuild_task_set_updateparse_task_list_getparse_task_set)_DEFAULT_USING_TASK_USING_JMAPClientBase)ical_to_jscal)JMAPAuthErrorJMAPMethodError)JMAPCalendarJMAPCalendarObject)Sessionasync_fetch_sessionzcaldav.jmapc                   @  s   e Zd ZdZdGddZdHddZdId	d
ZdJdKddZdLddZdMddZ	dNddZ
dOdd Z					dPdQd(d)Z				dRdSd*d+ZdTd,d-ZdUd0d1ZdVd2d3Z	dWdXd5d6ZdYd8d9ZdZd<d=Zd[d@dAZd\dCdDZd]dEdFZdS )^AsyncJMAPClientaw  Asynchronous JMAP client for calendar operations.

    **The JMAP support is experimental, the API may change in minor-releases**

    Usage::

        from caldav.jmap import get_async_jmap_client
        async with get_async_jmap_client(url="https://jmap.example.com/.well-known/jmap",
                                          username="alice", password="secret") as client:
            calendars = await client.get_calendars()

    Args:
        url: URL of the JMAP session endpoint (``/.well-known/jmap``).
        username: Username for Basic auth.
        password: Password for Basic auth, or bearer token if no username.
        auth: A pre-built niquests-compatible auth object. Takes precedence
              over username/password if provided.
        auth_type: Force a specific auth type: ``"basic"`` or ``"bearer"``.
        timeout: HTTP request timeout in seconds.
    returnc                   s   | S N selfr#   r#   M/home/thesage/.local/lib/python3.10/site-packages/caldav/jmap/async_client.py
__aenter__C      zAsyncJMAPClient.__aenter__Nonec                   s   d S r"   r#   )r%   exc_typeexc_valexc_tbr#   r#   r&   	__aexit__F   r(   zAsyncJMAPClient.__aexit__r   c                   s.   | j du rt| j| j| jdI dH | _ | j S )z5Return the cached Session, fetching it on first call.N)authtimeout)_session_cacher   url_authr/   r$   r#   r#   r&   _get_sessionI   s   
zAsyncJMAPClient._get_sessionNmethod_callslist[tuple]usinglist[str] | Nonelistc              	     s  |   I dH }|dur|ntt|d}td|jt| t 4 I dH }|j|j|| j	ddd| j
dI dH }W d  I dH  n1 I dH sJw   Y  |jdv r`t|jd|j d	d
|  | }|dg }|D ]}	|	\}
}}|
dkr|dd}t|jd| |dqp|S )aM  POST a batch of JMAP method calls and return the methodResponses.

        Args:
            method_calls: List of 3-tuples ``(method_name, args_dict, call_id)``.
            using: Capability URN list for the ``using`` field. Defaults to
                ``_DEFAULT_USING`` (core + calendars).

        Returns:
            List of 3-tuples ``(method_name, response_args, call_id)`` from
            the server's ``methodResponses`` array.

        Raises:
            JMAPAuthError: On HTTP 401 or 403.
            JMAPMethodError: If any methodResponse is an ``error`` response.
        N)r6   methodCallsz"JMAP POST to %s: %d method call(s)zapplication/json)zContent-TypeAccept)jsonr.   headersr/   )i  i  zHTTP z from API endpointr1   reasonmethodResponseserrortypeserverErrorzMethod call failed: r1   r>   
error_type)r3   r   r8   logdebugapi_urllenr   postr2   r/   status_coder   raise_for_statusr;   getr   )r%   r4   r6   sessionpayloadhttpresponsedatamethod_responsesrespmethod_name	resp_argscall_idrD   r#   r#   r&   _requestQ   sD   (
	
zAsyncJMAPClient._requestlist[JMAPCalendar]c           	        sn   |   I dH }t|j}| |gI dH }|D ]\}}}|dkr4t|}|D ]}| |_d|_q'|  S qg S )zFetch all calendars for the authenticated account.

        Returns:
            List of :class:`~caldav.jmap.objects.calendar.JMAPCalendar` objects.
        NzCalendar/getT)r3   r   
account_idrW   r   _client	_is_async)	r%   rM   call	responsesrT   rU   _	calendarscalr#   r#   r&   get_calendars   s   
zAsyncJMAPClient.get_calendarscalendar_idstrical_strc                   s   |   I dH }t||d}t|jd|i}| |gI dH }|D ]2\}}}	|dkrSt|\}
}	}	}}	}	d|v r@| ||d  d|
vrKt|jdd|
d d   S q!t|jdd)	ai  Create a calendar event from an iCalendar string.

        Args:
            calendar_id: The JMAP calendar ID to create the event in.
            ical_str: A VCALENDAR string representing the event.

        Returns:
            The server-assigned JMAP event ID.

        Raises:
            JMAPMethodError: If the server rejects the create request.
        N)rb   new-0CalendarEvent/setz:CalendarEvent/set response missing created entry for new-0r=   idNo CalendarEvent/set response)	r3   r   r   rY   rW   r   _raise_set_errorr   rG   )r%   rb   rd   rM   jscalr\   r]   rT   rU   r^   creatednot_createdr#   r#   r&   create_event   s$   zAsyncJMAPClient.create_eventevent_idr   c           	        s   |   I dH }t|j|gd}| |gI dH }|D ]$\}}}|dkr?t|}|s5t|jd| ddt|d dd  S qt|jd	d
)a  Fetch a calendar event as an iCalendar string.

        Args:
            event_id: The JMAP event ID to retrieve.

        Returns:
            A :class:`~caldav.jmap.objects.calendar_object.JMAPCalendarObject`
            wrapping the raw JSCalendar dict.  ``parent`` is ``None`` since
            no :class:`~caldav.jmap.objects.calendar.JMAPCalendar` is available
            at the client level.

        Raises:
            JMAPMethodError: If the event is not found.
        NidsCalendarEvent/getzEvent not found: notFoundrC   r   rQ   parentNo CalendarEvent/get responser=   )r3   r   rY   rW   r   r   rG   r   )	r%   rn   rM   r\   r]   rT   rU   r^   itemsr#   r#   r&   	get_event   s    
zAsyncJMAPClient.get_eventc                   s   |   I dH }t|}|dd t|j||i}| |gI dH }|D ]"\}}}	|dkrGt|\}	}	}	}	}
}	||
v rD| ||
|   dS q%t|j	dd)a  Update a calendar event from an iCalendar string.

        Args:
            event_id: The JMAP event ID to update.
            ical_str: A VCALENDAR string with the updated event data.

        Raises:
            JMAPMethodError: If the server rejects the update.
        Nuidrf   rh   r=   )
r3   r   popr
   rY   rW   r   ri   r   rG   )r%   rn   rd   rM   patchr\   r]   rT   rU   r^   not_updatedr#   r#   r&   update_event   s   
zAsyncJMAPClient.update_event
str | Nonestartendtextrt   JMAPCalendar | Nonelist[JMAPCalendarObject]c                   sj   |   I d H }| |j||||}| |I d H }|D ]\}	}
}|	dkr2 fddt|
D   S qg S )Nrq   c                   s   g | ]}t | d qS )rs   r   ).0itemrt   r#   r&   
<listcomp>  s    
z+AsyncJMAPClient._search.<locals>.<listcomp>)r3   _build_event_search_callsrY   rW   r   )r%   rb   r~   r   r   rt   rM   callsr]   rT   rU   r^   r#   r   r&   _search   s   

zAsyncJMAPClient._searchc                   s   | j ||||dI dH S )aP  Search for calendar events.

        All parameters are optional; omitting all returns every event in the account.
        Results are fetched in a single batched JMAP request using a result reference
        from ``CalendarEvent/query`` into ``CalendarEvent/get``.

        Args:
            calendar_id: Limit results to this calendar.
            start: Only events ending after this datetime (``YYYY-MM-DDTHH:MM:SS``).
            end: Only events starting before this datetime (``YYYY-MM-DDTHH:MM:SS``).
            text: Free-text search across title, description, locations, and participants.

        Returns:
            List of :class:`~caldav.jmap.objects.calendar_object.JMAPCalendarObject`
            instances.  ``parent`` is ``None`` on these objects; use
            :meth:`JMAPCalendar.search` if you need ``parent`` set.
        )rb   r~   r   r   N)r   )r%   rb   r~   r   r   r#   r#   r&   search_events  s   zAsyncJMAPClient.search_eventsc                   sf   |   I dH }t|jg d}| |gI dH }|D ]\}}}|dkr+|dd  S qt|jdd)uy  Return the current CalendarEvent state string for use as a sync token.

        Calls ``CalendarEvent/get`` with an empty ID list — no event data is
        transferred, only the ``state`` field from the response.

        Returns:
            Opaque state string. Pass to :meth:`get_objects_by_sync_token` to
            retrieve only what changed since this point.
        Nro   rq   state ru   r=   )r3   r   rY   rW   rL   r   rG   r%   rM   r\   r]   rT   rU   r^   r#   r#   r&   get_sync_token&  s   
zAsyncJMAPClient.get_sync_token
sync_tokenDtuple[list[JMAPCalendarObject], list[JMAPCalendarObject], list[str]]c                   s  |   I dH }t|j|}| |gI dH }g }g }g }|D ]\}}	}
|dkr<t|	\}
}
}}}}|r<t|jdddq|| }|sHg g |fS t|j|d}| |gI dH }i  |D ]\}}	}
|dkrvt|	D ]}t	|dd |d	 < qiq\ fd
d|D } fdd|D }|||fS )a  Fetch events changed since a previous sync token.

        Calls ``CalendarEvent/changes`` to discover which events were created,
        modified, or destroyed since ``sync_token`` was issued. Created and
        modified events are returned as
        :class:`~caldav.jmap.objects.calendar_object.JMAPCalendarObject` instances;
        destroyed events are returned as IDs (the objects no longer exist on the server).

        Args:
            sync_token: A state string previously returned by :meth:`get_sync_token`
                or by a prior call to this method.

        Returns:
            A 3-tuple ``(added, modified, deleted)``:

            - ``added``: objects for newly created events (``parent`` is ``None``).
            - ``modified``: objects for updated events (``parent`` is ``None``).
            - ``deleted``: Event IDs that were destroyed.

        Raises:
            JMAPMethodError: If the server reports ``hasMoreChanges: true``.
        NzCalendarEvent/changeszCalendarEvent/changes response was truncated by the server (hasMoreChanges=true). Call get_sync_token() to obtain a fresh baseline and re-sync.serverPartialFailrC   ro   rq   rs   rg   c                      g | ]
}| v r | qS r#   r#   r   ievents_by_idr#   r&   r   t      z=AsyncJMAPClient.get_objects_by_sync_token.<locals>.<listcomp>c                   r   r#   r#   r   r   r#   r&   r   u  r   )
r3   r   rY   rW   r   r   rG   r   r   r   )r%   r   rM   changes_callr]   created_idsupdated_ids	destroyedrT   rU   r^   has_more	fetch_idsget_callget_responsesr   addedmodifiedr#   r   r&   get_objects_by_sync_token8  s>   


z)AsyncJMAPClient.get_objects_by_sync_tokenc           	        s   |   I dH }t|j|g}| |gI dH }|D ]"\}}}|dkr<t|\}}}}}}||v r9| |||   dS qt|jdd)zDelete a calendar event.

        Args:
            event_id: The JMAP event ID to delete.

        Raises:
            JMAPMethodError: If the server rejects the delete.
        Nrf   rh   r=   )r3   r	   rY   rW   r   ri   r   rG   )	r%   rn   rM   r\   r]   rT   rU   r^   not_destroyedr#   r#   r&   delete_eventx  s   	zAsyncJMAPClient.delete_eventrx   c                   sV   | j ||dI d H D ]}|jd|kr|  S q|  I d H }t|jd| d)N)rb   rt   rx   z#No calendar object found with UID: r=   )r   rQ   rL   r3   r   rG   )r%   rx   rb   rt   objrM   r#   r#   r&   _get_object_by_uid  s   z"AsyncJMAPClient._get_object_by_uid
list[dict]c                   sX   |   I dH }t|j}| j|gtdI dH }|D ]\}}}|dkr)t|  S qg S )zFetch all task lists for the authenticated account.

        Returns:
            List of raw JMAP TaskList dicts as returned by the server.
        Nr6   zTaskList/get)r3   r   rY   rW   r   r   r   r#   r#   r&   get_task_lists  s   
zAsyncJMAPClient.get_task_liststask_list_idtitlec                   s   |   I dH }dtt ||dddd}|| t|jd|i}| j|gtdI dH }|D ]'\}}	}
|dkrWt	|	\}}
}
}}
}
d|v rO| 
||d  |d d	   S q0t|jd
d)a,  Create a task in a task list.

        Args:
            task_list_id: The JMAP task list ID to create the task in.
            title: Task title (maps to VTODO ``SUMMARY``).
            **kwargs: Optional JMAP Task fields using wire names: ``description``,
                ``due``, ``start``, ``timeZone``, ``estimatedDuration``,
                ``percentComplete``, ``progress``, ``priority``.

        Returns:
            The server-assigned JMAP task ID.

        Raises:
            JMAPMethodError: If the server rejects the create request.
        NTaskr   zneeds-action)z@typerx   
taskListIdr   percentCompleteprogresspriorityre   r   Task/setrg   No Task/set responser=   )r3   rc   uuiduuid4updater   rY   rW   r   r   ri   r   rG   )r%   r   r   kwargsrM   	task_dictr\   r]   rT   rU   r^   rk   rl   r#   r#   r&   create_task  s*   

	zAsyncJMAPClient.create_tasktask_iddictc           	        s   |   I dH }t|j|gd}| j|gtdI dH }|D ]"\}}}|dkr?|dg }|s9t|jd| dd|d	   S qt|jd
d)zFetch a task by ID.

        Args:
            task_id: The JMAP task ID to retrieve.

        Returns:
            Raw JMAP Task dict as returned by the server.

        Raises:
            JMAPMethodError: If the task is not found.
        Nro   r   zTask/getr8   zTask not found: rr   rC   r   zNo Task/get responser=   )r3   r   rY   rW   r   rL   r   rG   )	r%   r   rM   r\   r]   rT   rU   r^   rv   r#   r#   r&   get_task  s    
zAsyncJMAPClient.get_taskrz   c           
        s   |   I dH }t|j||i}| j|gtdI dH }|D ]"\}}}|dkr?t|\}}}}}	}||	v r<| ||	|   dS qt|jdd)a  Update a task with a partial patch.

        Args:
            task_id: The JMAP task ID to update.
            patch: Partial patch dict mapping property names to new values.

        Raises:
            JMAPMethodError: If the server rejects the update.
        Nr   r   r   r=   )	r3   r   rY   rW   r   r   ri   r   rG   )
r%   r   rz   rM   r\   r]   rT   rU   r^   r{   r#   r#   r&   update_task  s   
zAsyncJMAPClient.update_taskc           	        s   |   I dH }t|j|g}| j|gtdI dH }|D ]"\}}}|dkr>t|\}}}}}}||v r;| |||   dS qt|jdd)zDelete a task.

        Args:
            task_id: The JMAP task ID to delete.

        Raises:
            JMAPMethodError: If the server rejects the delete.
        Nr   r   r   r=   )	r3   r   rY   rW   r   r   ri   r   rG   )	r%   r   rM   r\   r]   rT   rU   r^   r   r#   r#   r&   delete_task  s   	zAsyncJMAPClient.delete_task)r!   r    )r!   r)   )r!   r   r"   )r4   r5   r6   r7   r!   r8   )r!   rX   )rb   rc   rd   rc   r!   rc   )rn   rc   r!   r   )rn   rc   rd   rc   r!   r)   )NNNNN)rb   r}   r~   r}   r   r}   r   r}   rt   r   r!   r   )NNNN)
rb   r}   r~   r}   r   r}   r   r}   r!   r   )r!   rc   )r   rc   r!   r   )rn   rc   r!   r)   )NN)rx   rc   rb   r}   rt   r   r!   r   )r!   r   )r   rc   r   rc   r!   rc   )r   rc   r!   r   )r   rc   rz   r   r!   r)   )r   rc   r!   r)   )__name__
__module____qualname____doc__r'   r-   r3   rW   ra   rm   rw   r|   r   r   r   r   r   r   r   r   r   r   r   r#   r#   r#   r&   r    -   s>    



9

 
 


@


'
r    ).r   
__future__r   loggingr   niquestsr   caldav.jmap._methods.calendarr   r   caldav.jmap._methods.eventr   r   r   r	   r
   r   r   r   caldav.jmap._methods.taskr   r   r   r   r   r   r   caldav.jmap.clientr   r   r   caldav.jmap.convertr   caldav.jmap.errorr   r   caldav.jmap.objects.calendarr   #caldav.jmap.objects.calendar_objectr   caldav.jmap.sessionr   r   	getLoggerrE   r    r#   r#   r#   r&   <module>   s     ($
	
