Start to use six for basestring.
[mediagoblin.git] / mediagoblin / plugins / piwigo / tools.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import logging
18
19 import six
20 import lxml.etree as ET
21 from werkzeug.exceptions import MethodNotAllowed
22
23 from mediagoblin.tools.response import Response
24
25
26 _log = logging.getLogger(__name__)
27
28
29 class PwgNamedArray(list):
30 def __init__(self, l, item_name, as_attrib=()):
31 self.item_name = item_name
32 self.as_attrib = as_attrib
33 list.__init__(self, l)
34
35 def fill_element_xml(self, el):
36 for it in self:
37 n = ET.SubElement(el, self.item_name)
38 if isinstance(it, dict):
39 _fill_element_dict(n, it, self.as_attrib)
40 else:
41 _fill_element(n, it)
42
43
44 def _fill_element_dict(el, data, as_attr=()):
45 for k, v in data.iteritems():
46 if k in as_attr:
47 if not isinstance(v, six.string_types):
48 v = str(v)
49 el.set(k, v)
50 else:
51 n = ET.SubElement(el, k)
52 _fill_element(n, v)
53
54
55 def _fill_element(el, data):
56 if isinstance(data, bool):
57 if data:
58 el.text = "1"
59 else:
60 el.text = "0"
61 elif isinstance(data, six.string_types):
62 el.text = data
63 elif isinstance(data, int):
64 el.text = str(data)
65 elif isinstance(data, dict):
66 _fill_element_dict(el, data)
67 elif isinstance(data, PwgNamedArray):
68 data.fill_element_xml(el)
69 else:
70 _log.warn("Can't convert to xml: %r", data)
71
72
73 def response_xml(result):
74 r = ET.Element("rsp")
75 r.set("stat", "ok")
76 _fill_element(r, result)
77 return Response(ET.tostring(r, encoding="utf-8", xml_declaration=True),
78 mimetype='text/xml')
79
80
81 class CmdTable(object):
82 _cmd_table = {}
83
84 def __init__(self, cmd_name, only_post=False):
85 assert not cmd_name in self._cmd_table
86 self.cmd_name = cmd_name
87 self.only_post = only_post
88
89 def __call__(self, to_be_wrapped):
90 assert not self.cmd_name in self._cmd_table
91 self._cmd_table[self.cmd_name] = (to_be_wrapped, self.only_post)
92 return to_be_wrapped
93
94 @classmethod
95 def find_func(cls, request):
96 if request.method == "GET":
97 cmd_name = request.args.get("method")
98 else:
99 cmd_name = request.form.get("method")
100 entry = cls._cmd_table.get(cmd_name)
101 if not entry:
102 return entry
103 _log.debug("Found method %s", cmd_name)
104 func, only_post = entry
105 if only_post and request.method != "POST":
106 _log.warn("Method %s only allowed for POST", cmd_name)
107 raise MethodNotAllowed()
108 return func