1 # -*- coding: utf-8 -*-
6 from openerp.osv import osv, fields
7 from openerp.addons.web import http
8 from openerp.addons.web.http import request
10 from urlparse import urljoin
13 from openerp.tools.safe_eval import safe_eval
14 from openerp.exceptions import AccessError, AccessDenied
18 logger = logging.getLogger(__name__)
20 def route(routes, *route_args, **route_kwargs):
22 new_routes = routes if isinstance(routes, list) else [routes]
23 f.multilang = route_kwargs.get('multilang', False)
25 route_kwargs.pop('multilang')
26 for r in list(new_routes):
27 new_routes.append('/<string(length=5):lang_code>' + r)
28 @http.route(new_routes, *route_args, **route_kwargs)
29 @functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',))
30 def wrap(*args, **kwargs):
31 request.route_lang = kwargs.get('lang_code', None)
32 if not hasattr(request, 'website'):
33 request.multilang = f.multilang
34 request.website = request.registry['website'].get_current()
35 if request.route_lang:
36 lang_ok = [lg.code for lg in request.website.language_ids if lg.code == request.route_lang]
38 return request.not_found()
39 request.website.preprocess_request(*args, **kwargs)
40 return f(*args, **kwargs)
44 def auth_method_public():
45 registry = openerp.modules.registry.RegistryManager.get(request.db)
46 if not request.session.uid:
47 request.uid = registry['website'].get_public_user().id
49 request.uid = request.session.uid
50 http.auth_methods['public'] = auth_method_public
52 def url_for(path, lang=None):
54 path = urljoin(request.httprequest.path, path)
55 langs = request.context.get('langs')
56 if path[0] == '/' and len(langs) > 1:
58 lang = lang or request.context.get('lang')
66 def urlplus(url, params):
70 for k,v in params.items():
71 url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
74 class website(osv.osv):
75 _name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
76 _description = "Website"
78 'name': fields.char('Domain'),
79 'company_id': fields.many2one('res.company', string="Company"),
80 'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
81 'default_lang_id': fields.many2one('res.lang', string="Default language"),
82 'social_twitter': fields.char('Twitter Account'),
83 'social_facebook': fields.char('Facebook Account'),
84 'social_github': fields.char('GitHub Account'),
85 'social_linkedin': fields.char('LinkedIn Account'),
86 'social_youtube': fields.char('Youtube Account'),
87 'social_googleplus': fields.char('Google+ Account'),
92 def get_public_user(self):
93 if not self.public_user:
94 ref = request.registry['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'website', 'public_user')
95 self.public_user = request.registry[ref[0]].browse(request.cr, openerp.SUPERUSER_ID, ref[1])
96 return self.public_user
99 website = request.registry['website'].get_current()
101 if hasattr(request, 'route_lang'):
102 lang = request.route_lang
104 lang = request.params.get('lang', None) or request.httprequest.cookies.get('lang', None)
106 if lang not in [lg.code for lg in website.language_ids]:
107 lang = website.default_lang_id.code
111 def preprocess_request(self, cr, uid, ids, *args, **kwargs):
113 return werkzeug.utils.redirect(url_for(url))
114 request.redirect = redirect
116 is_public_user = request.uid == self.get_public_user().id
117 lang = self.get_lang()
118 is_master_lang = lang == request.website.default_lang_id.code
119 request.context.update({
121 'lang_selected': [lg for lg in request.website.language_ids if lg.code == lang],
122 'langs': [lg.code for lg in request.website.language_ids],
123 'multilang': request.multilang,
124 'is_public_user': is_public_user,
125 'is_master_lang': is_master_lang,
126 'editable': not is_public_user,
127 'translatable': not is_public_user and not is_master_lang and request.multilang,
130 def get_current(self):
131 # WIP, currently hard coded
132 return self.browse(request.cr, request.uid, 1)
134 def render(self, cr, uid, ids, template, values=None):
135 view = request.registry.get("ir.ui.view")
136 IMD = request.registry.get("ir.model.data")
137 user = request.registry.get("res.users")
139 qweb_context = request.context.copy()
142 qweb_context.update(values)
146 registry=request.registry,
148 website=request.website,
150 res_company=request.website.company_id,
151 user_id=user.browse(cr, uid, uid),
154 context = request.context.copy()
156 inherit_branding=qweb_context.setdefault('editable', False),
159 # check if xmlid of the template exists
161 module, xmlid = template.split('.', 1)
162 IMD.get_object_reference(cr, uid, module, xmlid)
163 except ValueError: # catches both unpack errors and gor errors
164 module, xmlid = 'website', template
166 IMD.get_object_reference(cr, uid, module, xmlid)
168 logger.error("Website Rendering Error.\n\n%s" % traceback.format_exc())
169 return self.render(cr, uid, ids, 'website.404', qweb_context)
172 return view.render(cr, uid, "%s.%s" % (module, xmlid),
173 qweb_context, context=context)
174 except (AccessError, AccessDenied), err:
176 qweb_context['error'] = err[1]
177 logger.warn("Website Rendering Error.\n\n%s" % traceback.format_exc())
178 return self.render(cr, uid, ids, 'website.401', qweb_context)
180 logger.exception("Website Rendering Error.")
181 qweb_context['traceback'] = traceback.format_exc()
184 'website.500' if qweb_context['editable'] else 'website.404',
185 qweb_context, context=context)
187 def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None):
189 page_count = int(math.ceil(float(total) / step))
191 page = max(1, min(int(page), page_count))
194 pmin = max(page - int(math.floor(scope/2)), 1)
195 pmax = min(pmin + scope, page_count)
197 if pmax - pmin < scope:
198 pmin = pmax - scope if pmax - scope > 0 else 1
201 _url = "%spage/%s/" % (url, page)
203 _url = "%s?%s" % (_url, urllib.urlencode(url_args))
207 "page_count": page_count,
208 "offset": (page - 1) * step,
209 "page": {'url': get_url(page), 'num': page},
210 "page_start": {'url': get_url(pmin), 'num': pmin},
211 "page_end": {'url': get_url(min(pmax, page + 1)),
212 'num': min(pmax, page + 1)},
214 {'url': get_url(page), 'num': page}
215 for page in xrange(pmin, pmax+1)
219 def list_pages(self, cr, uid, ids, context=None):
220 """ Available pages in the website/CMS. This is mostly used for links
221 generation and can be overridden by modules setting up new HTML
222 controllers for dynamic pages (e.g. blog).
224 By default, returns template views marked as pages.
226 :returns: a list of mappings with two keys: ``name`` is the displayable
227 name of the resource (page), ``url`` is the absolute URL
229 :rtype: list({name: str, url: str})
231 View = self.pool['ir.ui.view']
232 views = View.search_read(cr, uid, [['page', '=', True]],
233 fields=['name'], order='name', context=context)
234 xids = View.get_external_id(cr, uid, [view['id'] for view in views], context=context)
237 {'name': view['name'], 'url': '/page/' + xids[view['id']]}
242 def kanban(self, cr, uid, ids, model, domain, column, template, step=None, scope=None, orderby=None):
243 step = step and int(step) or 10
244 scope = scope and int(scope) or 5
245 orderby = orderby or "name"
247 get_args = dict(request.httprequest.args or {})
248 model_obj = request.registry[model]
249 relation = model_obj._columns.get(column)._obj
250 relation_obj = request.registry[relation]
252 get_args.setdefault('kanban', "")
253 kanban = get_args.pop('kanban')
254 kanban_url = "?%s&kanban=" % urllib.urlencode(get_args)
257 for col in kanban.split(","):
260 pages[int(col[0])] = int(col[1])
263 for group in model_obj.read_group(cr, uid, domain, ["id", column], groupby=column):
267 relation_id = group[column][0]
268 obj['column_id'] = relation_obj.browse(cr, uid, relation_id)
270 obj['kanban_url'] = kanban_url
271 for k, v in pages.items():
273 obj['kanban_url'] += "%s-%s" % (k, v)
276 number = model_obj.search(cr, uid, group['__domain'], count=True)
277 obj['page_count'] = int(math.ceil(float(number) / step))
278 obj['page'] = pages.get(relation_id) or 1
279 if obj['page'] > obj['page_count']:
280 obj['page'] = obj['page_count']
281 offset = (obj['page']-1) * step
282 obj['page_start'] = max(obj['page'] - int(math.floor((scope-1)/2)), 1)
283 obj['page_end'] = min(obj['page_start'] + (scope-1), obj['page_count'])
286 obj['domain'] = group['__domain']
289 obj['orderby'] = orderby
292 object_ids = model_obj.search(cr, uid, group['__domain'], limit=step, offset=offset, order=orderby)
293 obj['object_ids'] = model_obj.browse(cr, uid, object_ids)
300 'template': template,
302 return request.website.render("website.kanban_contain", values)
304 def kanban_col(self, cr, uid, ids, model, domain, page, template, step, orderby):
306 model_obj = request.registry[model]
307 domain = safe_eval(domain)
309 offset = (int(page)-1) * step
310 object_ids = model_obj.search(cr, uid, domain, limit=step, offset=offset, order=orderby)
311 object_ids = model_obj.browse(cr, uid, object_ids)
312 for object_id in object_ids:
313 html += request.website.render(template, {'object_id': object_id})
316 class ir_attachment(osv.osv):
317 _inherit = "ir.attachment"
318 def _website_url_get(self, cr, uid, ids, name, arg, context=None):
319 context = context or {}
321 for attach in self.browse(cr, uid, ids, context=context):
322 if attach.type=='url':
323 result[attach.id] = attach.url
325 result[attach.id] = "/website/attachment/"+str(attach.id)
328 'website_url': fields.function(_website_url_get, string="Attachment URL", type='char')
331 class res_partner(osv.osv):
332 _inherit = "res.partner"
334 def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
335 partner = self.browse(cr, uid, ids[0], context=context)
337 'center': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
338 'size': "%sx%s" % (height, width),
342 return urlplus('http://maps.googleapis.com/maps/api/staticmap' , params)
344 def google_map_link(self, cr, uid, ids, zoom=8, context=None):
345 partner = self.browse(cr, uid, ids[0], context=context)
347 'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
349 return urlplus('https://maps.google.be/maps' , params)
351 class base_language_install(osv.osv):
352 _inherit = "base.language.install"
354 'website_ids': fields.many2many('website', string='Websites to translate'),
357 def lang_install(self, cr, uid, ids, context=None):
360 action = super(base_language_install, self).lang_install(cr, uid, ids, context)
361 language_obj = self.browse(cr, uid, ids)[0]
362 website_ids = [website.id for website in language_obj['website_ids']]
363 lang_id = self.pool['res.lang'].search(cr, uid, [('code', '=', language_obj['lang'])])
364 if website_ids and lang_id:
365 data = {'language_ids': [(4, lang_id[0])]}
366 self.pool['website'].write(cr, uid, website_ids, data)
367 params = context.get('params', {})
368 if 'url_return' in params:
370 'url': params['url_return'].replace('[lang]', language_obj['lang']),
371 'type': 'ir.actions.act_url',