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
12 from openerp.tools.safe_eval import safe_eval
13 from openerp.exceptions import AccessError, AccessDenied
16 logger = logging.getLogger(__name__)
18 def route(*route_args, **route_kwargs):
20 @http.route(*route_args, **route_kwargs)
21 @functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',))
22 def wrap(*args, **kwargs):
23 request.route_lang = None # WIP: decorator will support lang argument
24 if not hasattr(request, 'website'):
25 request.website = request.registry['website'].get_current()
26 request.website.preprocess_request(*args, **kwargs)
27 return f(*args, **kwargs)
31 def auth_method_public():
32 registry = openerp.modules.registry.RegistryManager.get(request.db)
33 if not request.session.uid:
34 request.uid = registry['website'].get_public_user().id
36 request.uid = request.session.uid
37 http.auth_methods['public'] = auth_method_public
40 def urlplus(url, params):
44 for k,v in params.items():
45 url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
48 class website(osv.osv):
49 _name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
50 _description = "Website"
52 'name': fields.char('Domain'),
53 'company_id': fields.many2one('res.company', string="Company"),
54 'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
55 'default_lang_id': fields.many2one('res.lang', string="Default language"),
60 def get_public_user(self):
61 if not self.public_user:
62 ref = request.registry['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'website', 'public_user')
63 self.public_user = request.registry[ref[0]].browse(request.cr, openerp.SUPERUSER_ID, ref[1])
64 return self.public_user
67 website = request.registry['website'].get_current()
69 if hasattr(request, 'route_lang'):
70 lang = request.route_lang
72 lang = request.params.get('lang', None) or request.httprequest.cookies.get('lang', None)
74 if lang not in [lg.code for lg in website.language_ids]:
75 lang = website.default_lang_id.code
79 def preprocess_request(self, cr, uid, ids, *args, **kwargs):
80 is_public_user = request.uid == self.get_public_user().id
81 request.context.update({
82 'is_public_user': is_public_user,
83 'editable': not is_public_user, # TODO: check perms
85 request.context['lang'] = self.get_lang()
87 def get_current(self):
88 # WIP, currently hard coded
89 return self.browse(request.cr, request.uid, 1)
91 def render(self, cr, uid, ids, template, values=None):
92 view = request.registry.get("ir.ui.view")
93 IMD = request.registry.get("ir.model.data")
95 qweb_context = request.context.copy()
102 'registry': request.registry,
104 'website': request.website,
105 'res_company': request.website.company_id,
108 qweb_context.update(values)
110 'inherit_branding': qweb_context.get('editable', False),
113 # check if xmlid of the template exists
115 model, xmlid = template.split('.', 1)
116 model, id = IMD.get_object_reference(cr, uid, model, xmlid)
118 logger.error("Website Rendering Error.\n\n%s" % traceback.format_exc())
119 return self.render('website.404', qweb_context)
121 # render template and catch error
123 return view.render(cr, uid, template, qweb_context, context=context)
124 except (AccessError, AccessDenied), err:
126 qweb_context['error'] = err[1]
127 logger.warn("Website Rendering Error.\n\n%s" % traceback.format_exc())
128 return self.render('website.401', qweb_context)
130 qweb_context['traceback'] = traceback.format_exc()
131 logger.error("Website Rendering Error.\n\n%s" % qweb_context['traceback'])
132 if qweb_context['editable']:
133 return view.render(cr, uid, 'website.500', qweb_context, context=context)
135 return view.render(cr, uid, 'website.404', qweb_context, context=context)
137 def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None):
139 page_count = int(math.ceil(float(total) / step))
141 page = max(1, min(int(page), page_count))
144 pmin = max(page - int(math.floor(scope/2)), 1)
145 pmax = min(pmin + scope, page_count)
147 if pmax - pmin < scope:
148 pmin = pmax - scope if pmax - scope > 0 else 1
151 _url = "%spage/%s/" % (url, page)
153 _url = "%s?%s" % (_url, urllib.urlencode(url_args))
157 "page_count": page_count,
158 "offset": (page - 1) * step,
159 "page": {'url': get_url(page), 'num': page},
160 "page_start": {'url': get_url(pmin), 'num': pmin},
161 "page_end": {'url': get_url(min(pmax, page + 1)),
162 'num': min(pmax, page + 1)},
164 {'url': get_url(page), 'num': page}
165 for page in xrange(pmin, pmax+1)
169 def list_pages(self, cr, uid, context=None):
170 """ Available pages in the website/CMS. This is mostly used for links
171 generation and can be overridden by modules setting up new HTML
172 controllers for dynamic pages (e.g. blog).
174 By default, returns template views marked as pages.
176 :returns: a list of mappings with two keys: ``name`` is the displayable
177 name of the resource (page), ``url`` is the absolute URL
179 :rtype: list({name: str, url: str})
181 View = self.pool['ir.ui.view']
182 views = View.search_read(cr, uid, [['page', '=', True]],
183 fields=['name'], order='name', context=context)
184 xids = View.get_external_id(cr, uid, [view['id'] for view in views], context=context)
187 {'name': view['name'], 'url': '/page/' + xids[view['id']]}
192 def kanban(self, cr, uid, ids, model, domain, column, template, step=None, scope=None, orderby=None):
193 step = step and int(step) or 10
194 scope = scope and int(scope) or 5
195 orderby = orderby or "name"
197 get_args = dict(request.httprequest.args or {})
198 model_obj = request.registry[model]
199 relation = model_obj._columns.get(column)._obj
200 relation_obj = request.registry[relation]
202 get_args.setdefault('kanban', "")
203 kanban = get_args.pop('kanban')
204 kanban_url = "?%s&kanban=" % urllib.urlencode(get_args)
207 for col in kanban.split(","):
210 pages[int(col[0])] = int(col[1])
213 for group in model_obj.read_group(cr, uid, domain, ["id", column], groupby=column):
217 relation_id = group[column][0]
218 obj['column_id'] = relation_obj.browse(cr, uid, relation_id)
220 obj['kanban_url'] = kanban_url
221 for k, v in pages.items():
223 obj['kanban_url'] += "%s-%s" % (k, v)
226 number = model_obj.search(cr, uid, group['__domain'], count=True)
227 obj['page_count'] = int(math.ceil(float(number) / step))
228 obj['page'] = pages.get(relation_id) or 1
229 if obj['page'] > obj['page_count']:
230 obj['page'] = obj['page_count']
231 offset = (obj['page']-1) * step
232 obj['page_start'] = max(obj['page'] - int(math.floor((scope-1)/2)), 1)
233 obj['page_end'] = min(obj['page_start'] + (scope-1), obj['page_count'])
236 obj['domain'] = group['__domain']
239 obj['orderby'] = orderby
242 object_ids = model_obj.search(cr, uid, group['__domain'], limit=step, offset=offset, order=orderby)
243 obj['object_ids'] = model_obj.browse(cr, uid, object_ids)
250 'template': template,
252 return request.website.render("website.kanban_contain", values)
254 def kanban_col(self, cr, uid, ids, model, domain, page, template, step, orderby):
256 model_obj = request.registry[model]
257 domain = safe_eval(domain)
259 offset = (int(page)-1) * step
260 object_ids = model_obj.search(cr, uid, domain, limit=step, offset=offset, order=orderby)
261 object_ids = model_obj.browse(cr, uid, object_ids)
262 for object_id in object_ids:
263 html += request.website.render(template, {'object_id': object_id})
266 class res_partner(osv.osv):
267 _inherit = "res.partner"
269 def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
270 partner = self.browse(cr, uid, ids[0], context=context)
272 'center': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
273 'size': "%sx%s" % (height, width),
277 return urlplus('http://maps.googleapis.com/maps/api/staticmap' , params)
279 def google_map_link(self, cr, uid, ids, zoom=8, context=None):
280 partner = self.browse(cr, uid, ids[0], context=context)
282 'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
284 return urlplus('https://maps.google.be/maps' , params)