# -*- coding: utf-8 -*- import functools import simplejson import openerp from openerp.osv import osv, fields from openerp.addons.web import http from openerp.addons.web.http import request import urllib import math import traceback from openerp.tools.safe_eval import safe_eval from openerp.exceptions import AccessError, AccessDenied import logging logger = logging.getLogger(__name__) def route(*route_args, **route_kwargs): def decorator(f): @http.route(*route_args, **route_kwargs) @functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',)) def wrap(*args, **kwargs): request.route_lang = None # WIP: decorator will support lang argument if not hasattr(request, 'website'): request.website = request.registry['website'].get_current() request.website.preprocess_request(*args, **kwargs) return f(*args, **kwargs) return wrap return decorator def auth_method_public(): registry = openerp.modules.registry.RegistryManager.get(request.db) if not request.session.uid: request.uid = registry['website'].get_public_user().id else: request.uid = request.session.uid http.auth_methods['public'] = auth_method_public def urlplus(url, params): if not params: return url url += "?" for k,v in params.items(): url += "%s=%s&" % (k, urllib.quote_plus(str(v))) return url class website(osv.osv): _name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco _description = "Website" _columns = { 'name': fields.char('Domain'), 'company_id': fields.many2one('res.company', string="Company"), 'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'), 'default_lang_id': fields.many2one('res.lang', string="Default language"), } public_user = None def get_public_user(self): if not self.public_user: ref = request.registry['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'website', 'public_user') self.public_user = request.registry[ref[0]].browse(request.cr, openerp.SUPERUSER_ID, ref[1]) return self.public_user def get_lang(self): website = request.registry['website'].get_current() if hasattr(request, 'route_lang'): lang = request.route_lang else: lang = request.params.get('lang', None) or request.httprequest.cookies.get('lang', None) if lang not in [lg.code for lg in website.language_ids]: lang = website.default_lang_id.code return lang def preprocess_request(self, cr, uid, ids, *args, **kwargs): is_public_user = request.uid == self.get_public_user().id request.context.update({ 'is_public_user': is_public_user, 'editable': not is_public_user, # TODO: check perms }) request.context['lang'] = self.get_lang() def get_current(self): # WIP, currently hard coded return self.browse(request.cr, request.uid, 1) def render(self, cr, uid, ids, template, values=None): view = request.registry.get("ir.ui.view") IMD = request.registry.get("ir.model.data") qweb_context = request.context.copy() if values is None: values = {} values.update({ 'request': request, 'registry': request.registry, 'json': simplejson, 'website': request.website, 'res_company': request.website.company_id, }) qweb_context.update(values) context = { 'inherit_branding': qweb_context.get('editable', False), } # check if xmlid of the template exists try: model, xmlid = template.split('.', 1) model, id = IMD.get_object_reference(cr, uid, model, xmlid) except ValueError: logger.error("Website Rendering Error.\n\n%s" % traceback.format_exc()) return self.render('website.404', qweb_context) # render template and catch error try: return view.render(cr, uid, template, qweb_context, context=context) except (AccessError, AccessDenied), err: logger.error(err) qweb_context['error'] = err[1] logger.warn("Website Rendering Error.\n\n%s" % traceback.format_exc()) return self.render('website.401', qweb_context) except Exception: qweb_context['traceback'] = traceback.format_exc() logger.error("Website Rendering Error.\n\n%s" % qweb_context['traceback']) if qweb_context['editable']: return view.render(cr, uid, 'website.500', qweb_context, context=context) else: return view.render(cr, uid, 'website.404', qweb_context, context=context) def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None): # Compute Pager page_count = int(math.ceil(float(total) / step)) page = max(1, min(int(page), page_count)) scope -= 1 pmin = max(page - int(math.floor(scope/2)), 1) pmax = min(pmin + scope, page_count) if pmax - pmin < scope: pmin = pmax - scope if pmax - scope > 0 else 1 def get_url(page): _url = "%spage/%s/" % (url, page) if url_args: _url = "%s?%s" % (_url, urllib.urlencode(url_args)) return _url return { "page_count": page_count, "offset": (page - 1) * step, "page": {'url': get_url(page), 'num': page}, "page_start": {'url': get_url(pmin), 'num': pmin}, "page_end": {'url': get_url(min(pmax, page + 1)), 'num': min(pmax, page + 1)}, "pages": [ {'url': get_url(page), 'num': page} for page in xrange(pmin, pmax+1) ] } def list_pages(self, cr, uid, context=None): """ Available pages in the website/CMS. This is mostly used for links generation and can be overridden by modules setting up new HTML controllers for dynamic pages (e.g. blog). By default, returns template views marked as pages. :returns: a list of mappings with two keys: ``name`` is the displayable name of the resource (page), ``url`` is the absolute URL of the same. :rtype: list({name: str, url: str}) """ View = self.pool['ir.ui.view'] views = View.search_read(cr, uid, [['page', '=', True]], fields=['name'], order='name', context=context) xids = View.get_external_id(cr, uid, [view['id'] for view in views], context=context) return [ {'name': view['name'], 'url': '/page/' + xids[view['id']]} for view in views if xids[view['id']] ] def kanban(self, cr, uid, ids, model, domain, column, template, step=None, scope=None, orderby=None): step = step and int(step) or 10 scope = scope and int(scope) or 5 orderby = orderby or "name" get_args = dict(request.httprequest.args or {}) model_obj = request.registry[model] relation = model_obj._columns.get(column)._obj relation_obj = request.registry[relation] get_args.setdefault('kanban', "") kanban = get_args.pop('kanban') kanban_url = "?%s&kanban=" % urllib.urlencode(get_args) pages = {} for col in kanban.split(","): if col: col = col.split("-") pages[int(col[0])] = int(col[1]) objects = [] for group in model_obj.read_group(cr, uid, domain, ["id", column], groupby=column): obj = {} # browse column relation_id = group[column][0] obj['column_id'] = relation_obj.browse(cr, uid, relation_id) obj['kanban_url'] = kanban_url for k, v in pages.items(): if k != relation_id: obj['kanban_url'] += "%s-%s" % (k, v) # pager number = model_obj.search(cr, uid, group['__domain'], count=True) obj['page_count'] = int(math.ceil(float(number) / step)) obj['page'] = pages.get(relation_id) or 1 if obj['page'] > obj['page_count']: obj['page'] = obj['page_count'] offset = (obj['page']-1) * step obj['page_start'] = max(obj['page'] - int(math.floor((scope-1)/2)), 1) obj['page_end'] = min(obj['page_start'] + (scope-1), obj['page_count']) # view data obj['domain'] = group['__domain'] obj['model'] = model obj['step'] = step obj['orderby'] = orderby # browse objects object_ids = model_obj.search(cr, uid, group['__domain'], limit=step, offset=offset, order=orderby) obj['object_ids'] = model_obj.browse(cr, uid, object_ids) objects.append(obj) values = { 'objects': objects, 'range': range, 'template': template, } return request.website.render("website.kanban_contain", values) def kanban_col(self, cr, uid, ids, model, domain, page, template, step, orderby): html = "" model_obj = request.registry[model] domain = safe_eval(domain) step = int(step) offset = (int(page)-1) * step object_ids = model_obj.search(cr, uid, domain, limit=step, offset=offset, order=orderby) object_ids = model_obj.browse(cr, uid, object_ids) for object_id in object_ids: html += request.website.render(template, {'object_id': object_id}) return html class res_partner(osv.osv): _inherit = "res.partner" def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None): partner = self.browse(cr, uid, ids[0], context=context) params = { 'center': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''), 'size': "%sx%s" % (height, width), 'zoom': zoom, 'sensor': 'false', } return urlplus('http://maps.googleapis.com/maps/api/staticmap' , params) def google_map_link(self, cr, uid, ids, zoom=8, context=None): partner = self.browse(cr, uid, ids[0], context=context) params = { 'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''), } return urlplus('https://maps.google.be/maps' , params)