1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
17 from collections
import namedtuple
21 import lxml
.etree
as ET
22 from werkzeug
.exceptions
import MethodNotAllowed
, BadRequest
24 from mediagoblin
.tools
.request
import setup_user_in_request
25 from mediagoblin
.tools
.response
import Response
28 _log
= logging
.getLogger(__name__
)
31 PwgError
= namedtuple("PwgError", ["code", "msg"])
34 class PwgNamedArray(list):
35 def __init__(self
, l
, item_name
, as_attrib
=()):
36 self
.item_name
= item_name
37 self
.as_attrib
= as_attrib
38 list.__init
__(self
, l
)
40 def fill_element_xml(self
, el
):
42 n
= ET
.SubElement(el
, self
.item_name
)
43 if isinstance(it
, dict):
44 _fill_element_dict(n
, it
, self
.as_attrib
)
49 def _fill_element_dict(el
, data
, as_attr
=()):
50 for k
, v
in six
.iteritems(data
):
52 if not isinstance(v
, six
.string_types
):
56 n
= ET
.SubElement(el
, k
)
60 def _fill_element(el
, data
):
61 if isinstance(data
, bool):
66 elif isinstance(data
, six
.string_types
):
68 elif isinstance(data
, int):
70 elif isinstance(data
, dict):
71 _fill_element_dict(el
, data
)
72 elif isinstance(data
, PwgNamedArray
):
73 data
.fill_element_xml(el
)
75 _log
.warn("Can't convert to xml: %r", data
)
78 def response_xml(result
):
82 if isinstance(result
, PwgError
):
84 err
= ET
.SubElement(r
, "err")
85 err
.set("code", str(result
.code
))
86 err
.set("msg", result
.msg
)
87 if result
.code
>= 100 and result
.code
< 600:
90 _fill_element(r
, result
)
91 return Response(ET
.tostring(r
, encoding
="utf-8", xml_declaration
=True),
92 mimetype
='text/xml', status
=status
)
95 class CmdTable(object):
98 def __init__(self
, cmd_name
, only_post
=False):
99 assert not cmd_name
in self
._cmd
_table
100 self
.cmd_name
= cmd_name
101 self
.only_post
= only_post
103 def __call__(self
, to_be_wrapped
):
104 assert not self
.cmd_name
in self
._cmd
_table
105 self
._cmd
_table
[self
.cmd_name
] = (to_be_wrapped
, self
.only_post
)
109 def find_func(cls
, request
):
110 if request
.method
== "GET":
111 cmd_name
= request
.args
.get("method")
113 cmd_name
= request
.form
.get("method")
114 entry
= cls
._cmd
_table
.get(cmd_name
)
117 _log
.debug("Found method %s", cmd_name
)
118 func
, only_post
= entry
119 if only_post
and request
.method
!= "POST":
120 _log
.warn("Method %s only allowed for POST", cmd_name
)
121 raise MethodNotAllowed()
125 def check_form(form
):
126 if not form
.validate():
127 _log
.error("form validation failed for form %r", form
)
130 _log
.error("Errors for %s: %r", f
.name
, f
.errors
)
134 dump
.append("%s=%r" % (f
.name
, f
.data
))
135 _log
.debug("form: %s", " ".join(dump
))
138 class PWGSession(object):
139 session_manager
= None
141 def __init__(self
, request
):
142 self
.request
= request
143 self
.in_pwg_session
= False
147 self
.old_session
= self
.request
.session
148 self
.old_user
= self
.request
.user
149 # Load piwigo session into state
150 self
.request
.session
= self
.session_manager
.load_session_from_cookie(
152 setup_user_in_request(self
.request
)
153 self
.in_pwg_session
= True
156 def __exit__(self
, *args
):
158 self
.request
.session
= self
.old_session
159 self
.request
.user
= self
.old_user
160 self
.in_pwg_session
= False
162 def save_to_cookie(self
, response
):
163 assert self
.in_pwg_session
164 self
.session_manager
.save_session_to_cookie(self
.request
.session
,
165 self
.request
, response
)