1"""
2 Namecheap Management library of common functions used by
3 all the namecheap execution modules
4
5 Installation Prerequisites
6 --------------------------
7
8 - This module uses the following python libraries to communicate to
9   the namecheap API:
10
11        * ``requests``
12        .. code-block:: bash
13
14            pip install requests
15
16"""
17
18
19import logging
20import xml.dom.minidom
21
22import salt.loader
23
24try:
25    import requests
26
27    HAS_REQUESTS = True
28except ImportError:
29    HAS_REQUESTS = False
30
31# Get logging started
32log = logging.getLogger(__name__)
33
34__salt__ = None
35
36
37def __virtual__():
38    if not HAS_REQUESTS:
39        return (
40            False,
41            "Missing dependency: 'requests'. The namecheap utils module "
42            "cannot be loaded. ",
43        )
44    global __salt__
45    if not __salt__:
46        __salt__ = salt.loader.minion_mods(__opts__)
47    return True
48
49
50def post_request(opts):
51    namecheap_url = __salt__["config.option"]("namecheap.url")
52    return _handle_request(requests.post(namecheap_url, data=opts, timeout=45))
53
54
55def get_request(opts):
56    namecheap_url = __salt__["config.option"]("namecheap.url")
57    return _handle_request(requests.get(namecheap_url, params=opts, timeout=45))
58
59
60def _handle_request(r):
61    r.close()
62
63    if r.status_code > 299:
64        log.error(str(r))
65        raise Exception(str(r))
66
67    response_xml = xml.dom.minidom.parseString(r.text)
68    apiresponse = response_xml.getElementsByTagName("ApiResponse")[0]
69
70    if apiresponse.getAttribute("Status") == "ERROR":
71        data = []
72        errors = apiresponse.getElementsByTagName("Errors")[0]
73        for e in errors.getElementsByTagName("Error"):
74            data.append(e.firstChild.data)
75        error = "".join(data)
76        log.info(apiresponse)
77        log.error(error)
78        raise Exception(error)
79
80    return response_xml
81
82
83def xml_to_dict(xml):
84    if xml.nodeType == xml.CDATA_SECTION_NODE:
85        return xml.data
86    result = atts_to_dict(xml)
87    if len([n for n in xml.childNodes if n.nodeType != xml.TEXT_NODE]) == 0:
88        if len(result) > 0:
89            if xml.firstChild is not None and len(xml.firstChild.data) > 0:
90                result["data"] = xml.firstChild.data
91        elif xml.firstChild is not None and len(xml.firstChild.data) > 0:
92            return xml.firstChild.data
93        else:
94            return None
95    elif (
96        xml.childNodes.length == 1
97        and xml.childNodes[0].nodeType == xml.CDATA_SECTION_NODE
98    ):
99        return xml.childNodes[0].data
100    else:
101        for n in xml.childNodes:
102            if n.nodeType == xml.CDATA_SECTION_NODE:
103
104                if xml.tagName.lower() in result:
105                    val = result[xml.tagName.lower()]
106                    if not isinstance(val, list):
107                        temp = [val]
108                        val = temp
109                    val.append(n.data)
110                    result[xml.tagName.lower()] = val
111                else:
112                    result[xml.tagName.lower()] = n.data
113
114            elif n.nodeType != xml.TEXT_NODE:
115
116                if n.tagName.lower() in result:
117                    val = result[n.tagName.lower()]
118
119                    if not isinstance(val, list):
120                        temp = [val]
121                        val = temp
122                    val.append(xml_to_dict(n))
123                    result[n.tagName.lower()] = val
124                else:
125                    result[n.tagName.lower()] = xml_to_dict(n)
126    return result
127
128
129def atts_to_dict(xml):
130    result = {}
131    if xml.attributes is not None:
132        for key, value in xml.attributes.items():
133            result[key.lower()] = string_to_value(value)
134    return result
135
136
137def string_to_value(value):
138    temp = value.lower()
139    result = None
140    if temp == "true":
141        result = True
142    elif temp == "false":
143        result = False
144    else:
145        try:
146            result = int(value)
147        except ValueError:
148            try:
149                result = float(value)
150            except ValueError:
151                result = value
152
153    return result
154
155
156def get_opts(command):
157    opts = {}
158    opts["ApiUser"] = __salt__["config.option"]("namecheap.name")
159    opts["UserName"] = __salt__["config.option"]("namecheap.user")
160    opts["ApiKey"] = __salt__["config.option"]("namecheap.key")
161    opts["ClientIp"] = __salt__["config.option"]("namecheap.client_ip")
162    opts["Command"] = command
163    return opts
164