1"""
2Return salt data via pushover (http://www.pushover.net)
3
4.. versionadded:: 2016.3.0
5
6The following fields can be set in the minion conf file::
7
8    pushover.user (required)
9    pushover.token (required)
10    pushover.title (optional)
11    pushover.device (optional)
12    pushover.priority (optional)
13    pushover.expire (optional)
14    pushover.retry (optional)
15    pushover.profile (optional)
16
17.. note::
18    The ``user`` here is your **user key**, *not* the email address you use to
19    login to pushover.net.
20
21Alternative configuration values can be used by prefacing the configuration.
22Any values not found in the alternative configuration will be pulled from
23the default location::
24
25    alternative.pushover.user
26    alternative.pushover.token
27    alternative.pushover.title
28    alternative.pushover.device
29    alternative.pushover.priority
30    alternative.pushover.expire
31    alternative.pushover.retry
32
33PushOver settings may also be configured as::
34
35    pushover:
36        user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
37        token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
38        title: Salt Returner
39        device: phone
40        priority: -1
41        expire: 3600
42        retry: 5
43
44    alternative.pushover:
45        user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
46        token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
47        title: Salt Returner
48        device: phone
49        priority: 1
50        expire: 4800
51        retry: 2
52
53    pushover_profile:
54        pushover.token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
55
56    pushover:
57        user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
58        profile: pushover_profile
59
60    alternative.pushover:
61        user: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62        profile: pushover_profile
63
64  To use the PushOver returner, append '--return pushover' to the salt command. ex:
65
66  .. code-block:: bash
67
68    salt '*' test.ping --return pushover
69
70  To use the alternative configuration, append '--return_config alternative' to the salt command. ex:
71
72    salt '*' test.ping --return pushover --return_config alternative
73
74To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command.
75
76.. code-block:: bash
77
78    salt '*' test.ping --return pushover --return_kwargs '{"title": "Salt is awesome!"}'
79
80"""
81
82import logging
83import pprint
84import urllib.parse
85
86import salt.returners
87import salt.utils.pushover
88from salt.exceptions import SaltInvocationError
89
90log = logging.getLogger(__name__)
91
92__virtualname__ = "pushover"
93
94
95def _get_options(ret=None):
96    """
97    Get the pushover options from salt.
98    """
99
100    defaults = {"priority": "0"}
101
102    attrs = {
103        "pushover_profile": "profile",
104        "user": "user",
105        "device": "device",
106        "token": "token",
107        "priority": "priority",
108        "title": "title",
109        "api_version": "api_version",
110        "expire": "expire",
111        "retry": "retry",
112        "sound": "sound",
113    }
114
115    profile_attr = "pushover_profile"
116
117    profile_attrs = {
118        "user": "user",
119        "device": "device",
120        "token": "token",
121        "priority": "priority",
122        "title": "title",
123        "api_version": "api_version",
124        "expire": "expire",
125        "retry": "retry",
126        "sound": "sound",
127    }
128
129    _options = salt.returners.get_returner_options(
130        __virtualname__,
131        ret,
132        attrs,
133        profile_attr=profile_attr,
134        profile_attrs=profile_attrs,
135        __salt__=__salt__,
136        __opts__=__opts__,
137        defaults=defaults,
138    )
139    return _options
140
141
142def __virtual__():
143    """
144    Return virtual name of the module.
145
146    :return: The virtual name of the module.
147    """
148    return __virtualname__
149
150
151def _post_message(
152    user,
153    device,
154    message,
155    title,
156    priority,
157    expire,
158    retry,
159    sound,
160    api_version=1,
161    token=None,
162):
163    """
164    Send a message to a Pushover user or group.
165    :param user:        The user or group to send to, must be key of user or group not email address.
166    :param message:     The message to send to the PushOver user or group.
167    :param title:       Specify who the message is from.
168    :param priority     The priority of the message, defaults to 0.
169    :param api_version: The PushOver API version, if not specified in the configuration.
170    :param notify:      Whether to notify the room, default: False.
171    :param token:       The PushOver token, if not specified in the configuration.
172    :return:            Boolean if message was sent successfully.
173    """
174
175    user_validate = salt.utils.pushover.validate_user(user, device, token)
176    if not user_validate["result"]:
177        return user_validate
178
179    parameters = dict()
180    parameters["user"] = user
181    parameters["device"] = device
182    parameters["token"] = token
183    parameters["title"] = title
184    parameters["priority"] = priority
185    parameters["expire"] = expire
186    parameters["retry"] = retry
187    parameters["message"] = message
188
189    if sound:
190        sound_validate = salt.utils.pushover.validate_sound(sound, token)
191        if sound_validate["res"]:
192            parameters["sound"] = sound
193
194    result = salt.utils.pushover.query(
195        function="message",
196        method="POST",
197        header_dict={"Content-Type": "application/x-www-form-urlencoded"},
198        data=urllib.parse.urlencode(parameters),
199        opts=__opts__,
200    )
201
202    return result
203
204
205def returner(ret):
206    """
207    Send an PushOver message with the data
208    """
209
210    _options = _get_options(ret)
211
212    user = _options.get("user")
213    device = _options.get("device")
214    token = _options.get("token")
215    title = _options.get("title")
216    priority = _options.get("priority")
217    expire = _options.get("expire")
218    retry = _options.get("retry")
219    sound = _options.get("sound")
220
221    if not token:
222        raise SaltInvocationError("Pushover token is unavailable.")
223
224    if not user:
225        raise SaltInvocationError("Pushover user key is unavailable.")
226
227    if priority and priority == 2:
228        if not expire and not retry:
229            raise SaltInvocationError(
230                "Priority 2 requires pushover.expire and pushover.retry options."
231            )
232
233    message = "id: {}\r\nfunction: {}\r\nfunction args: {}\r\njid: {}\r\nreturn: {}\r\n".format(
234        ret.get("id"),
235        ret.get("fun"),
236        ret.get("fun_args"),
237        ret.get("jid"),
238        pprint.pformat(ret.get("return")),
239    )
240
241    result = _post_message(
242        user=user,
243        device=device,
244        message=message,
245        title=title,
246        priority=priority,
247        expire=expire,
248        retry=retry,
249        sound=sound,
250        token=token,
251    )
252
253    log.debug("pushover result %s", result)
254    if not result["res"]:
255        log.info("Error: %s", result["message"])
256    return
257