o
    54g7,                     @   s   d Z ddlZddlm  mZ ddlmZ ddlm	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZ G d	d
 d
eZG dd deZG dd deZd!ddZd"ddZdd Z	d#ddZ	d#ddZdd Zdd Zdd  ZdS )$z
Windows Notification Service

Documentation is available on the Windows Dev Center:
https://msdn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-windows-push-notification-services--wns--overview
    N)ImproperlyConfigured   )	HTTPErrorRequest	urlencodeurlopen)get_manager)NotificationError)PUSH_NOTIFICATIONS_SETTINGSc                   @      e Zd ZdS )WNSErrorN__name__
__module____qualname__ r   r   \/var/www/html/notificationserver/venv/lib/python3.10/site-packages/push_notifications/wns.pyr          r   c                   @   r   )WNSAuthenticationErrorNr   r   r   r   r   r      r   r   c                   @   r   )WNSNotificationResponseErrorNr   r   r   r   r   r      r   r   notify.windows.comc              
   C   s   t  |}t  |}|std|stdddi}d||| d}t|d}ttd ||d	}zt|}W n t	yP }	 z|	j
d
krJtd|	d}	~	ww | d}
zt|
}
W n tyj   tdw |
d}|svtd|S )z
	Requests an Access token for WNS communication.

	:return: dict: {'access_token': <str>, 'expires_in': <int>, 'token_type': 'bearer'}
	zRYou need to set PUSH_NOTIFICATIONS_SETTINGS["WNS_PACKAGE_SECURITY_ID"] to use WNS.zIYou need to set PUSH_NOTIFICATIONS_SETTINGS["WNS_SECRET_KEY"] to use WNS.Content-Typez!application/x-www-form-urlencodedclient_credentials)
grant_type	client_idclient_secretscopeutf-8WNS_ACCESS_URL)dataheaders  z/Authentication failed, check your WNS settings.Nz$Received invalid JSON data from WNS.access_tokenz'Access token missing from WNS response.)r   get_wns_package_security_idget_wns_secret_keyr   r   encoder   SETTINGSr   r   coder   readdecodejsonloads	Exceptionget)r   application_idr   r   r    paramsr   requestresponseerr
oauth_datar"   r   r   r   _wns_authenticate   sJ   

r4   	wns/toastc              
   C   s6  t |d}d}|dkrd}|d| |d}t|tu r |d}t| ||}zt|}W ng ty }	 z[|	jdkr<d	}
nJ|	jd
krDd}
nB|	jdkrLd}
n:|	jdkrTd}
n2|	jdkr\d}
n*|	jdkrdd}
n"|	jdkrld}
n|	jdkrtd}
n|	jdkr|d}
n
|	jdkrd}
n|	td|	j|
f d}	~	ww |	 
dS )z
	Sends a notification data and authentication to WNS.

	:param uri: str: The device's unique notification URI
	:param data: dict: The notification data to be sent.
	:return:
	)r.   ztext/xmlwns/rawzapplication/octet-streamz	Bearer %s)r   Authorizationz
X-WNS-Typer   r!   zOOne or more headers were specified incorrectly or conflict with another header.i  z@The cloud service did not present a valid authentication ticket.i  zGThe cloud service is not authorized to send a notification to this URI.i  z9The channel URI is not valid or is not recognized by WNS.i  z/Invalid method. Only POST or DELETE is allowed.i  z-The cloud service exceeded its throttle limiti  zThe channel expired.i  z4The notification payload exceeds the 500 byte limit.i  z9An internal failure caused notification delivery to fail.i  z$The server is currently unavailable.zHTTP %i: %sN)r4   typestrr%   r   r   r   r'   r   r(   r)   )urir   wns_typer.   r"   content_typer    r0   r1   r2   msgr   r   r   	_wns_sendU   sN   











r>   c                 K   s   t d}t |d}t |d}|dd|jd< d| v r;t| d ddD ]\}}t |d}||_t||jd	< q&d
| v r^t| d
 ddD ]\}}t |d}||jd< t||jd	< qGt |S )z
	Creates the xml tree for a `toast` notification

	:param data: dict: The notification data to be converted to an xml tree.

	{
		"text": ["Title text", "Message Text", "Another message!"],
		"image": ["src1", "src2"],
	}

	:return: str
	toastvisualbindingtemplateToastText01textr   )startidimageimgsrc)	ETElement
SubElementpopattrib	enumeraterD   r9   tostring)r   kwargsrootr@   rA   countitemelemr   r   r   _wns_prepare_toast   s   


rV   c           	      K   sx   |rd}t |trd|gi}td	d|i|}n|r)t|}d|j }t|}n|r0d}|}ntdt| |||dS )
a  
	Sends a notification request to WNS.
	There are four notification types that WNS can send: toast, tile, badge and raw.
	Toast, tile, and badge can all be customized to use different
	templates/icons/sounds/launch params/etc.
	See docs for more information:
	https://msdn.microsoft.com/en-us/library/windows/apps/br212853.aspx

	There are multiple ways to input notification data:

	1. The simplest and least custom notification to send is to just pass a string
	to `message`. This will create a toast notification with one text element. e.g.:
		"This is my notification title"

	2. You can also pass a dictionary to `message`: it can only contain one or both
	keys: ["text", "image"]. The value of each key must be a list with the text and
	src respectively. e.g.:
		{
			"text": ["text1", "text2"],
			"image": ["src1", "src2"],
		}

	3. Passing a dictionary to `xml_data` will create one of three types of
	notifications depending on the dictionary data (toast, tile, badge).
	See `dict_to_xml_schema` docs for more information on dictionary formatting.

	4. Passing a value to `raw_data` will create a `raw` notification and send the
	input data as is.

	:param uri: str: The device's unique notification uri.
	:param message: str|dict: The notification data to be sent.
	:param xml_data: dict: A dictionary containing data to be converted to an xml tree.
	:param raw_data: str: Data to be sent via a `raw` notification.
	r5   rD   r   zwns/%sr6   zVAt least one of the following parameters must be set:`message`, `xml_data`, `raw_data`)r:   r   r;   r.   Nr   )	
isinstancer9   rV   dict_to_xml_schematagrJ   rP   	TypeErrorr>   )	r:   messagexml_dataraw_datar.   rQ   r;   prepared_dataxmlr   r   r   wns_send_message   s&   &

r`   c           	   	   K   s:   g }| r| D ]}t d|||||d|}|| q|S )a_  
	WNS doesn't support bulk notification, so we loop through each uri.

	:param uri_list: list: A list of uris the notification will be sent to.
	:param message: str: The notification data to be sent.
	:param xml_data: dict: A dictionary containing data to be converted to an xml tree.
	:param raw_data: str: Data to be sent via a `raw` notification.
	)r:   r[   r\   r]   r.   Nr   )r`   append)	uri_listr[   r\   r]   r.   rQ   resr:   rr   r   r   wns_send_bulk_message   s   re   c                 C   sT   |   D ]#\}}tt||di }|dd}t|tr$t|| |  S dS )a  
	Input a dictionary to be converted to xml. There should be only one key at
	the top level. The value must be a dict with (required) `children` key and
	(optional) `attrs` key. This will be called the `sub-element dictionary`.

	The `attrs` value must be a dictionary; each value will be added to the
	element's xml tag as attributes. e.g.:
		{"example": {
			"attrs": {
				"key1": "value1",
				...
			},
			...
		}}

	would result in:
		<example key1="value1" key2="value2"></example>

	If the value is a dict it must contain one or more keys which will be used
	as the sub-element names. Each sub-element must have a value of a sub-element
	dictionary(see above) or a list of sub-element dictionaries.
	If the value is not a dict, it will be the value of the element.
	If the value is a list, multiple elements of the same tag will be created
	from each sub-element dict in the list.

	:param data: dict: Used to create an XML tree. e.g.:
		example_data = {
			"toast": {
				"attrs": {
					"launch": "param",
					"duration": "short",
				},
				"children": {
					"visual": {
						"children": {
							"binding": {
								"attrs": {"template": "ToastText01"},
								"children": {
									"text": [
										{
											"attrs": {"id": "1"},
											"children": "text1",
										},
										{
											"attrs": {"id": "2"},
											"children": "text2",
										},
									],
								},
							},
						},
					},
				},
			},
		}
	:return: ElementTree.Element
	attrschildrenN)items_add_element_attrsrJ   rK   r-   rW   dict_add_sub_elements_from_dict)r   keyvaluerR   rg   r   r   r   rX     s   :

rX   c                 C   s   |  D ]_\}}t|tr;|D ]*}t| |}t||di  |dd}t|tr1t|| qt|t	r9||_
qqt| |}t||di  |dd}t|tr[t|| qt|t	rc||_
qdS )aS  
	Add SubElements to the parent element.

	:param parent: ElementTree.Element: The parent element for the newly created SubElement.
	:param sub_dict: dict: Used to create a new SubElement. See `dict_to_xml_schema`
	method docstring for more information. e.g.:
		{"example": {
			"attrs": {
				"key1": "value1",
				...
			},
			...
		}}
	rf   rg   N)rh   rW   listrJ   rL   ri   r-   rj   rk   r9   rD   )parentsub_dictrl   rm   repeated_elementsub_elementrg   r   r   r   rk   E  s*   


	

rk   c                 C   s    |  D ]	\}}|| j|< q| S )a  
	Add attributes to the given element.

	:param elem: ElementTree.Element: The element the attributes are being added to.
	:param attrs: dict: A dictionary of attributes. e.g.:
		{"attribute1": "value", "attribute2": "another"}
	:return: ElementTree.Element
	)rh   rN   )rU   rf   attrrm   r   r   r   ri   h  s   	ri   )r   N)r5   N)NNNN)__doc__r*   xml.etree.ElementTreeetreeElementTreerJ   django.core.exceptionsr   compatr   r   r   r   confr   
exceptionsr	   settingsr
   r&   r   r   r   r4   r>   rV   r`   re   rX   rk   ri   r   r   r   r   <module>   s*    

69
B
B#