def planpdf(self, product_id): """ Download the plan of a product - used in the fractions table """ if not product_id: return request.not_found() res = request.env['product.product'].browse(product_id) if not res or not res.exists(): _logger.warning('Someone tried to fetch the plan product #%i which was not found. Returning 404.', product_id) return request.not_found() if not res.plan_visible_in_website: _logger.warning('Someone tried to fetch the plan of product #%i that has the `plan_visible_in_website` set to False. Returning 404.', res.id) return request.not_found() filecontent = base64.b64decode(res.plan_pdf_file) if not filecontent: _logger.warning('Could not retrieve the plan of product #%i - filecontent is empty.', res.id) return request.not_found() filename = res.plan_pdf_filename if not filename: filename = 'plan.pdf' return request.make_response(filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', 'attachment; filename={0}'.format(filename))])
def download_attachment(self, attachment_id): # Check if this is a valid attachment id attachment = request.env['ir.attachment'].sudo().search_read([ ('id', '=', int(attachment_id)) ], [ "name", "datas", "file_type", "res_model", "res_id", "type", "url" ]) if attachment: attachment = attachment[0] else: return redirect('/shop') if attachment["type"] == "url": if attachment["url"]: return redirect(attachment["url"]) else: return request.not_found() elif attachment["datas"]: data = StringIO(base64.standard_b64decode(attachment["datas"])) return http.send_file(data, filename=attachment['name'], as_attachment=True) else: return request.not_found()
def saveas(self, model, record_id, method, encoded=False, filename=None, **kw): """ Download link for files generated on the fly. :param str model: name of the model to fetch the data from :param str record_id: id of the record from which to fetch the data :param str method: name of the method used to fetch data, decorated with @api.one :param bool encoded: whether the data is encoded in base64 :param str filename: the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context datas = getattr(Model, method)(cr, uid, int(record_id), context) if not datas: return request.not_found() filecontent = datas[0] if not filecontent: return request.not_found() if encoded: filecontent = base64.b64decode(filecontent) if not filename: filename = '%s_%s' % (model.replace('.', '_'), record_id) return request.make_response( filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def infrastructure_odoo(self, instance, key, **post): (instance_name, instance_id) = unslug(instance) odoo_instance = request.env['odoo.instance'].sudo().search( [('id', '=', instance_id), ('key', '=', key)], limit=1) if not odoo_instance: return request.not_found('Instance data not found') method = request.httprequest.method if method == 'GET': res = odoo_instance.get_instance_data() elif method == 'POST': # Get post vars docker_image = post.get('docker_image', None) docker_image_tag = post.get('docker_image_tag', None) build_status = post.get('build_status', None) if not all((docker_image, docker_image_tag, build_status)): return request.not_found('Parameters missing') docker_image_tag_obj = request.env['docker.image.tag'].sudo() docker_image_tag_obj.set_docker_image_state( docker_image, docker_image_tag, build_status) res = {'result': 'OK'} else: return request.not_found('Method not found') return request.make_response( json.dumps(res, sort_keys=True, indent=4, separators=(', ', ': ')), headers=[('Content-Type', 'application/json')], )
def return_image(self, sku=None, **args): product_template = request.env['product.template'] product_template_ids = product_template.search([('sku', '=', sku)]) if not product_template_ids: result = request.not_found() elif len(product_template_ids.ids) > 1: result = request.not_found() else: image = product_template_ids.image if not image: result = request.not_found() else: image_type = 'jpg' try: tmp_filename = '/tmp/' + sku open(tmp_filename, 'wb').write(base64.b64decode(image)) image_type = imghdr.what(tmp_filename) os.remove(tmp_filename) except OSError: pass result = request.make_response( base64.b64decode(image), [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition('{}.{}'.format(sku, image_type)))]) return result
def download_document(self, model, field, id, filename=None, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context fields = [field] res = Model.read(cr, uid, [int(id)], fields, context)[0] filecontent = base64.b64decode(res.get(field) or '') if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response( filecontent, [ ('Content-Disposition', content_disposition(filename)), # ('Content-Type', 'application/vnd.ms-excel'), ('Content-Type', 'application/octet-stream'), ('Content-Length', len(filecontent)) ])
def report_productivity(self, course_id=None, report_type=None, parameter_id=None, direction_work_id=None, **kw): local_tz = pytz.timezone('America/Guayaquil') utc_dt = datetime.datetime.utcnow() local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) flag = 0 filename = '' full_path = '' p_report = productivity_report.ProductivityReport(local_tz, local_dt, course_id, parameter_id, direction_work_id) if report_type == 'D': flag = 1 filename, full_path = p_report.get_detail_productivity() elif report_type == 'S': flag = 1 filename, full_path = p_report.get_summary_productivity() if flag: file_content = self.print_report(full_path, filename) if not file_content: return request.not_found() else: if not filename: filename = '%s.pdf' % 'report' return request.make_response(file_content, headers=[('Content-Disposition', 'attachment; filename=%s Export' % filename), ('Content-Type', 'application/pdf')])
def new_order(self, claim_id, **post): partner = self._get_partner_company() claim = request.env['crm.claim'].browse(int(claim_id)) if not partner or not claim.exists() \ or claim.partner_sat_id.id != partner.id: return request.not_found() if not request.params.get('mode', '') == 'write': return request.website.render('website_myaccount_sat.new_order', {'claim': claim, 'partner': partner}) lines = {} for k, v in request.params.iteritems(): if 'product_id-' in k and int(v) > 0: lines[int(k.split('-')[1])] = int(v) if lines: products = request.env['product.product'].search( [('id', 'in', lines.keys())]) order = request.env['sale.order'].create( {'partner_id': partner.id}) for p in products: request.env['sale.order.line'].create({ 'product_id': p.id, 'name': p.name, 'product_uom_qty': lines[p.id], 'order_id': order.id}) claim.order_ids = [(4, order.id)] return request.redirect('/myaccount/sat/claim/%s' % claim_id)
def acme_challenge(self, filename): try: with file(os.path.join(get_challenge_dir(), filename)) as key: return key.read() except IOError: pass return request.not_found()
def download(self, id, format='xml', **kw): """ Download a mandat. Calls are made using the old api. This sucks. """ logger.debug('Download sepa mandat id:{0}'.format(id)) cr, uid, context = request.cr, request.uid, request.context sepa = request.registry['alkivi.sepa'].browse(cr, uid, int(id), context=context) date = datetime.datetime.strptime(sepa['date'], '%Y-%m-%d %H:%M:%S') if format == 'xml': filename = 'mandat_{0}.xml'.format(date.strftime('%Y_%m_%d')) logger.debug(filename) data = sepa.generate_xml() content_type = 'text/xml' if not data: return request.not_found() return request.make_response( data, [('Content-Type', content_type), ('Content-Disposition', content_disposition(filename))])
def report_academic_achievement(self, course_id=None, report_type=None, subject_id=None, student_id=None, **kw): local_tz = pytz.timezone('America/Guayaquil') utc_dt = datetime.datetime.utcnow() local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) flag = 0 filename = '' full_path = '' s_report = student_score_report.StudentScoreReport(local_tz, local_dt, subject_id, course_id, student_id) if report_type == 'D': flag = 1 filename, full_path = s_report.get_detail_academic_achievement() elif report_type == 'S': flag = 1 filename, full_path = s_report.get_summary_academic_achievement() elif report_type == 'F': flag = 1 filename, full_path = s_report.get_summary_academic_final() if flag: file_content = self.print_report(full_path, filename) if not file_content: return request.not_found() else: if not filename: filename = '%s.pdf' % 'report' return request.make_response(file_content, headers=[('Content-Disposition', 'attachment; filename=%s Export' % filename), ('Content-Type', 'application/pdf')])
def download_attachment(self, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :return: :class:`werkzeug.wrappers.Response` """ ir_attachment_domain = [('id', '=', int(kw['id']))] ir_attachment_obj = request.env['ir.attachment'] ir_attachment_set = ir_attachment_obj.search(ir_attachment_domain) filename = ir_attachment_set.datas_fname filecontent = base64.b64decode(ir_attachment_set.datas or '') if not filecontent: return request.not_found() return request.make_response(filecontent, \ [('Content-Type', ir_attachment_set.mimetype), \ ('Content-Disposition', content_disposition(filename))])
def report_integrator(self, course_id=None, report_type=None, parameter_id=None, war_games_report=None, war_games_id=None, judge_id=None, student_id=None, **kw): local_tz = pytz.timezone('America/Guayaquil') utc_dt = datetime.datetime.utcnow() local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) flag = 0 filename = '' full_path = '' i_report = student_integrator_report.StudentIntegratorReport(local_tz, local_dt,course_id, parameter_id, war_games_report, war_games_id, judge_id, student_id) if report_type == 'D': flag = 1 filename, full_path = i_report.get_detail_integrator() elif report_type == 'S': flag = 1 filename, full_path = i_report.get_summary_integrator() if flag: file_content = self.print_report(full_path, filename) if not file_content: return request.not_found() else: if not filename: filename = '%s.pdf' % 'report' return request.make_response(file_content, headers=[('Content-Disposition', 'attachment; filename=%s Export' % filename), ('Content-Type', 'application/pdf')])
def html_page(self, model, field, id=None, filename_field=None, **kw): """ Download link for files stored as binary fields. If the ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename_field: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context fields = [field] if filename_field: fields.append(filename_field) if id: res = Model.read(cr, uid, [int(id)], fields, context)[0] else: res = Model.default_get(cr, uid, fields, context) filecontent = base64.b64decode(res.get(field) or '') if not filecontent: return request.not_found() else: filename = '%s_%s' % (model.replace('.', '_'), id) if filename_field: filename = res.get(filename_field, '') or filename return request.make_response(filecontent, [('Content-Type', 'text/html')])
def download_document(self, model, field, id, filename=None, **kw): """ :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context fields = [field] res = Model.read(cr, uid, [int(id)], fields, context)[0] # filecontent = base64.b64decode(res.get(field) or '') filecontent = res.get(field) print(filecontent) if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) headers = [ ('Content-Type', 'application/xml'), ('Content-Disposition', content_disposition(filename)), ('charset', 'utf-8'), ] return request.make_response(filecontent, headers=headers, cookies=None)
def open_rating(self, token, rate, **kwargs): rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating.consumed: return request.render('rating.rating_external_page_submit', {'rating': rate, 'token': token}) else: return request.render('rating.rating_external_page_view', {'is_rated': True}) return request.not_found()
def open_rating(self, token, rate, **kwargs): assert rate in (1, 5, 10), "Incorrect rating" rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() rate_names={ 5: _("not satisfied"), 1: _("highly dissatisfied"), 10: _("satisfied") } rating.sudo().write({'rating': rate, 'consumed': True}) return request.render('rating.rating_external_page_submit', { 'rating': rating, 'token': token, 'rate_name': rate_names[rate], 'rate': rate }) return request.not_found()
def download_document(self, file, filename): if not file: return request.not_found() else: return request.make_response(file, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def download_document(self,model,field,id,filename=None, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry['labpal.experiment'] cr, uid, context = request.cr, request.uid, request.context fields = [field] res = Model.read(cr, uid, [int(id)], fields, context)[0] csv_file = StringIO() csv_writer = csv.writer(csv_file) csv_writer.writerow(["1","a","b","c"]) filecontent = base64.b64decode(csv_file) if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response(filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def download_document(self, model, field, id, filename=None, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry['labpal.experiment'] cr, uid, context = request.cr, request.uid, request.context fields = [field] res = Model.read(cr, uid, [int(id)], fields, context)[0] csv_file = StringIO() csv_writer = csv.writer(csv_file) csv_writer.writerow(["1", "a", "b", "c"]) filecontent = base64.b64decode(csv_file) if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response( filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def sitemap_xml_index(self): cr, uid, context = request.cr, openerp.SUPERUSER_ID, request.context ira = request.registry['ir.attachment'] iuv = request.registry['ir.ui.view'] mimetype ='application/xml;charset=utf-8' content = None def create_sitemap(url, content): ira.create(cr, uid, dict( datas=content.encode('base64'), mimetype=mimetype, type='binary', name=url, url=url, ), context=context) sitemap = ira.search_read(cr, uid, [('url', '=' , '/sitemap.xml'), ('type', '=', 'binary')], ('datas', 'create_date'), context=context) if sitemap: # Check if stored version is still valid server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT create_date = datetime.datetime.strptime(sitemap[0]['create_date'], server_format) delta = datetime.datetime.now() - create_date if delta < SITEMAP_CACHE_TIME: content = sitemap[0]['datas'].decode('base64') if not content: # Remove all sitemaps in ir.attachments as we're going to regenerated them sitemap_ids = ira.search(cr, uid, [('url', '=like' , '/sitemap%.xml'), ('type', '=', 'binary')], context=context) if sitemap_ids: ira.unlink(cr, uid, sitemap_ids, context=context) pages = 0 first_page = None locs = request.website.enumerate_pages() while True: start = pages * LOC_PER_SITEMAP loc_slice = islice(locs, start, start + LOC_PER_SITEMAP) urls = iuv.render(cr, uid, 'website.sitemap_locs', dict(locs=loc_slice), context=context) if urls.strip(): page = iuv.render(cr, uid, 'website.sitemap_xml', dict(content=urls), context=context) if not first_page: first_page = page pages += 1 create_sitemap('/sitemap-%d.xml' % pages, page) else: break if not pages: return request.not_found() elif pages == 1: content = first_page else: # Sitemaps must be split in several smaller files with a sitemap index content = iuv.render(cr, uid, 'website.sitemap_index_xml', dict( pages=range(1, pages + 1), url_root=request.httprequest.url_root, ), context=context) create_sitemap('/sitemap.xml', content) return request.make_response(content, [('Content-Type', mimetype)])
def css_bundle(self, xmlid, version=None, **kw): try: bundle = AssetsBundle(xmlid) except QWebTemplateNotFound: return request.not_found() response = request.make_response(bundle.css(), [('Content-Type', 'text/css')]) return make_conditional(response, bundle.last_modified, max_age=BUNDLE_MAXAGE)
def order(self, claim_id, order_id, **post): partner = self._get_partner_company() claim = request.env['crm.claim'].browse(int(claim_id)) order = request.env['sale.order'].browse(int(order_id)) if not partner or not claim.exists() or not order.exists(): return request.not_found() return request.website.render('website_myaccount_sat.order', {'claim': claim, 'order': order})
def claim_to(self, claim_id, state, **post): env = request.env partner = self._get_partner_company() if not partner: return request.not_found() claim = env['crm.claim'].browse(int(claim_id)) if claim.exists() and claim.partner_sat_id.id == partner.id: if state == 'progress': claim.to_progress() elif state == 'pending_material': claim.to_pending_material() elif state == 'exception': claim.to_exception() elif state == 'done': claim.to_done() return request.redirect('/myaccount/sat/claim/%s' % claim_id) return request.not_found()
def sitemap_xml_index(self): cr, uid, context = request.cr, openerp.SUPERUSER_ID, request.context ira = request.registry['ir.attachment'] iuv = request.registry['ir.ui.view'] mimetype ='application/xml;charset=utf-8' content = None def create_sitemap(url, content): return ira.create(cr, uid, dict( datas=content.encode('base64'), mimetype=mimetype, type='binary', name=url, url=url, ), context=context) sitemap = ira.search_read(cr, uid, [('url', '=' , '/sitemap.xml'), ('type', '=', 'binary')], ('datas', 'create_date'), context=context) if sitemap: # Check if stored version is still valid server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT create_date = datetime.datetime.strptime(sitemap[0]['create_date'], server_format) delta = datetime.datetime.now() - create_date if delta < SITEMAP_CACHE_TIME: content = sitemap[0]['datas'].decode('base64') if not content: # Remove all sitemaps in ir.attachments as we're going to regenerated them sitemap_ids = ira.search(cr, uid, [('url', '=like' , '/sitemap%.xml'), ('type', '=', 'binary')], context=context) if sitemap_ids: ira.unlink(cr, uid, sitemap_ids, context=context) pages = 0 locs = request.website.sudo(user=request.website.user_id.id).enumerate_pages() while True: values = { 'locs': islice(locs, 0, LOC_PER_SITEMAP), 'url_root': request.httprequest.url_root[:-1], } urls = iuv.render_template(cr, uid, 'website.sitemap_locs', values, context=context) if urls.strip(): content = iuv.render_template(cr, uid, 'website.sitemap_xml', dict(content=urls), context=context) pages += 1 last = create_sitemap('/sitemap-%d.xml' % pages, content) else: break if not pages: return request.not_found() elif pages == 1: ira.write(cr, uid, last, dict(url="/sitemap.xml", name="/sitemap.xml"), context=context) else: # Sitemaps must be split in several smaller files with a sitemap index content = iuv.render_template(cr, uid, 'website.sitemap_index_xml', dict( pages=range(1, pages + 1), url_root=request.httprequest.url_root, ), context=context) create_sitemap('/sitemap.xml', content) return request.make_response(content, [('Content-Type', mimetype)])
def snippet_form(self, module, **kwargs): module = request.env['builder.ir.module.module'].search([ ('name', '=', module) ]) if not module: return request.not_found() return request.website.render("builder.snippet_form")
def set_claim_stage(self, claim_id, claim_stage_id, **post): env = request.env claim = env['crm.claim'].browse(claim_id) claim_stage = env['crm.claim.stage'].browse(claim_stage_id) partner = self._get_partner_company() if claim.exists() and claim_stage.exists() \ and claim.partner_sat_id.id == partner.id: return request.redirect('/myaccount/sat/claim/%s' % claim_id) return request.not_found()
def attachment_saveas(self, model, field, id=None, filename_field=None, **kw): Model = request.session.model(model) filename, outfile = Model.get_attachment_file(int(id), request.context) if not outfile: return request.not_found() else: return request.make_response(outfile, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def submit_rating(self, token, rate, **kwargs): rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id) record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback')) # redirect to the form view if logged person if request.session.uid: return werkzeug.utils.redirect('/web#model=%s&id=%s&view_type=form' % (record_sudo._name, record_sudo.id)) return request.render('rating.rating_external_page_view')
def download_document(self,model,field,id,filename=None, **kw): print('----------------- download_document ------------------') registration_id = id wizard_obj = request.registry['event.export_registration'] wizards = wizard_obj.read(request.cr, request.uid, [int(registration_id)], ['registration_ids'], context=None) wizard = wizards[0] registration_ids = wizard['registration_ids'] print('----') print(registration_ids) Model = request.registry[model] # vamos a jalar los registros registration_obj = request.registry['event.registration'] registrations = registration_obj.read(request.cr, request.uid, registration_ids, ['id', 'name', 'display_name', 'partner_id', 'partner_function', 'credential_printed', 'state'], context=None) # iniciemos un objeto partner para busquedas partner_obj = request.registry['res.partner'] # cabeceras fc = '' for registration in registrations: if (not (registration['credential_printed'])) and (registration['state'] != 'cancel'): # si el partner_id corresponde a un ejecutivo, podemos extraer sus nombres y apellidos partner = partner_obj.read(request.cr, request.uid, registration['partner_id'][0], ['is_company', 'name', 'names', 'last_name', 'mother_name', 'gender_suffix', 'title', 'parent_id'], context=None) if partner['is_company']: # no tenemos un ejecutivo en la BD, solamente lo escrito en el registro names = registration['name'] if registration['name'] else "" apellido_p = '' apellido_m = '' cargo = registration['partner_function'] if registration['partner_function'] else "" company = partner['name'] else: # es un ejecutivo de la BD, tenemos sus datos desagregados names = partner['names'] if partner['names'] else "" apellido_p = partner['last_name'] if partner['last_name'] else "" apellido_m = partner['mother_name'] if partner['mother_name'] else "" cargo = registration['partner_function'] if registration['partner_function'] else "" company = partner['parent_id'][1] fc = fc + prep_barras(names) + prep_barras(apellido_p) + prep_barras(apellido_m) + prep_barras(cargo) + prep_barras(company) + '\n' if not fc: print('not fc') return request.not_found() else: print(' si fc') print(filename) if not filename: print('not filename') filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response(fc, #[('Content-Type', 'application/octet-stream'),('Content-Disposition', content_disposition(filename))]) [('Content-Type', 'application/octet-stream;charset=utf-8'),('Content-Disposition', content_disposition(filename))])
def index(self, mod=None, **kwargs): ms = module.get_modules() manifests = dict( (name, desc) for name, desc in zip(ms, map(self.load_manifest, ms)) if desc # remove not-actually-openerp-modules ) if not mod: return NOMODULE_TEMPLATE.render(modules=( (manifest['name'], name) for name, manifest in manifests.iteritems() if any(testfile.endswith('.js') for testfile in manifest['test']) )) sorted_mods = module_topological_sort(dict( (name, manifest.get('depends', [])) for name, manifest in manifests.iteritems() )) # to_load and to_test should be zippable lists of the same length. # A falsy value in to_test indicate nothing to test at that index (just # load the corresponding part of to_load) to_test = sorted_mods if mod != '*': if mod not in manifests: return request.not_found(NOTFOUND.render(module=mod)) idx = sorted_mods.index(mod) to_test = [None] * len(sorted_mods) to_test[idx] = mod tests_candicates = [ filter(lambda path: path.endswith('.js'), manifests[mod]['test'] if mod else []) for mod in to_test] # remove trailing test-less modules tests = reversed(list( itertools.dropwhile( operator.not_, reversed(tests_candicates)))) files = [ (mod, manifests[mod]['js'], tests, manifests[mod]['qweb']) for mod, tests in itertools.izip(sorted_mods, tests) ] # if all three db_info parameters are present, send them to the page db_info = dict((k, v) for k, v in kwargs.iteritems() if k in ['source', 'supadmin', 'password']) if len(db_info) != 3: db_info = None return TESTING.render(files=files, dependencies=json.dumps( [name for name in sorted_mods if module.get_module_resource(name, 'static') if manifests[name]['js']]), db_info=json.dumps(db_info))
def css_bundle(self, xmlid, version=None, page=None, **kw): try: bundle = AssetsBundle(xmlid) except QWebTemplateNotFound: return request.not_found() e_tag = request.httprequest.headers.get('If-None-Match') if e_tag and e_tag == bundle.checksum: return werkzeug.wrappers.Response(status=304) else: response = request.make_response(bundle.css(page), [('Content-Type', 'text/css')]) return make_conditional(response, bundle.last_modified, etag=bundle.checksum, max_age=BUNDLE_MAXAGE)
def open_rating(self, token, rate, **kwargs): assert rate in (1, 5, 10), "Incorrect rating" rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() rate_names = { 5: _("not satisfied"), 1: _("highly dissatisfied"), 10: _("satisfied") } rating.sudo().write({'rating': rate, 'consumed': True}) return request.render( 'rating.rating_external_page_submit', { 'rating': rating, 'token': token, 'rate_name': rate_names[rate], 'rate': rate }) return request.not_found()
def index(self, mod=None, **kwargs): ms = module.get_modules() manifests = dict((name, desc) for name, desc in zip(ms, map(self.load_manifest, ms)) if desc # remove not-actually-openerp-modules ) if not mod: return NOMODULE_TEMPLATE.render( modules=((manifest['name'], name) for name, manifest in manifests.iteritems() if any( testfile.endswith('.js') for testfile in manifest['test']))) sorted_mods = module_topological_sort( dict((name, manifest.get('depends', [])) for name, manifest in manifests.iteritems())) # to_load and to_test should be zippable lists of the same length. # A falsy value in to_test indicate nothing to test at that index (just # load the corresponding part of to_load) to_test = sorted_mods if mod != '*': if mod not in manifests: return request.not_found(NOTFOUND.render(module=mod)) idx = sorted_mods.index(mod) to_test = [None] * len(sorted_mods) to_test[idx] = mod tests_candicates = [ filter(lambda path: path.endswith('.js'), manifests[mod]['test'] if mod else []) for mod in to_test ] # remove trailing test-less modules tests = reversed( list(itertools.dropwhile(operator.not_, reversed(tests_candicates)))) files = [(mod, manifests[mod]['js'], tests, manifests[mod]['qweb']) for mod, tests in itertools.izip(sorted_mods, tests)] # if all three db_info parameters are present, send them to the page db_info = dict((k, v) for k, v in kwargs.iteritems() if k in ['source', 'supadmin', 'password']) if len(db_info) != 3: db_info = None return TESTING.render( files=files, dependencies=json.dumps([ name for name in sorted_mods if module.get_module_resource(name, 'static') if manifests[name]['js'] ]), db_info=json.dumps(db_info))
def download_attachment(self, model, id, method, attachment_id, **kw): # FIXME use /web/binary/saveas directly Model = request.registry.get(model) res = getattr(Model, method)(request.cr, request.uid, int(id), int(attachment_id)) if res: filecontent = base64.b64decode(res.get('base64')) filename = res.get('filename') if filecontent and filename: return request.make_response( filecontent, headers=[('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))]) return request.not_found()
def add_rating(self, token, rate, **kwargs): Rating = request.env["rating.rating"] rating = Rating.search([("access_token", "=", token)]) if rating: is_rated = bool(rating.rating != -1) if not is_rated: request.env["rating.rating"].apply_rating(rate, token=token) # redirect to the form view if logged person if request.session.uid and not is_rated: record = request.env[rating.res_model].browse(rating.res_id) return werkzeug.utils.redirect("/web#model=%s&id=%s&view_type=form" % (record._name, record.id)) return request.render("rating.rating_external_page_view", {"rating": rate, "is_rated": is_rated}) return request.not_found()
def get_acme_challenge(self, filename, **kw): local_folder = request.env['ir.config_parameter'].get_param( 'acme.challenge.webroot.folder') if local_folder: local_filename = local_folder.rstrip( '/') + BASE_PATH + '/' + filename try: with open(local_filename, 'r') as f: return f.read() except: pass return request.not_found()
def add_rating(self, token, rate, **kwargs): Rating = request.env['rating.rating'] rating = Rating.search([('access_token', '=', token)]) if rating: is_rated = bool(rating.rating != -1) if not is_rated: request.env['rating.rating'].sudo().apply_rating(rate, token=token) # redirect to the form view if logged person if request.session.uid and not is_rated: record = request.env[rating.res_model].browse(rating.res_id) return werkzeug.utils.redirect('/web#model=%s&id=%s&view_type=form' % (record._name, record.id)) return request.render('rating.rating_external_page_view', {'rating': rate, 'is_rated': is_rated}) return request.not_found()
def download_document(self, model, record_id, binary_field, filename_field, token=None): if not record_id: return request.not_found() else: status, headers, content = binary_content( model=model, id=record_id, field=binary_field, filename_field=filename_field, download=True) if status != 200: response = request.not_found() else: headers.append(('Content-Length', len(content))) response = request.make_response(content, headers) if token: response.set_cookie('fileToken', token) return response
def download_document(self, model, field, id, filename=None, **kw): """Download link for excel files stored as binary fields.""" record = request.env[model].browse([int(id)]) res = record.read([field])[0] filecontent = base64.b64decode(res.get(field) or '') if not filecontent: return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), id) return request.make_response( filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def download_attachment(self, model, id, method, attachment_id, **kw): # FIXME use /web/binary/saveas directly Model = request.registry.get(model) res = getattr(Model, method)(request.cr, request.uid, int(id), int(attachment_id)) if res: filecontent = base64.b64decode(res.get('base64')) filename = res.get('filename') content_type = mimetypes.guess_type(filename) if filecontent and filename: return request.make_response( filecontent, headers=[('Content-Type', content_type[0] or 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))]) return request.not_found()
def build(self, build_id=None, search=None, **post): registry, cr, uid, context = request.registry, request.cr, request.uid, request.context Build = registry['runbot.build'] build = Build.browse(cr, uid, [int(build_id)])[0] if not build.exists(): return request.not_found() context = { 'introspection': build.introspection, 'introspection_html': self.build_html(build), 'repo': build.repo_id, 'bu': self.build_info(build), 'br': {'branch': build.branch_id}, } return request.render("vauxooci.build_button", context)
def view(self, product, **post): """print product to pdf Arguments: product {[model]} -- product.template model **post {[dict]} -- other parameter Returns: [application/pdf] -- print pdf or http status code 404 """ if product: pdf = http.request.env['report'].sudo().with_context( set_viewport_size=True).get_pdf( product, 'product_report_template.product_report_print') pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) return request.not_found()
def submit_rating(self, token, rate, **kwargs): rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() record_sudo = request.env[rating.res_model].sudo().browse( rating.res_id) record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback')) # redirect to the form view if logged person if request.session.uid: return werkzeug.utils.redirect( '/web#model=%s&id=%s&view_type=form' % (record_sudo._name, record_sudo.id)) return request.render('rating.rating_external_page_view')
def download_attachment(self, model, id, method, attachment_id, **kw): # FIXME use /web/binary/saveas directly Model = request.registry.get(model) res = getattr(Model, method)(request.cr, request.uid, int(id), int(attachment_id)) if res: filecontent = base64.b64decode(res.get("base64")) filename = res.get("filename") content_type = mimetypes.guess_type(filename) if filecontent and filename: return request.make_response( filecontent, headers=[ ("Content-Type", content_type[0] or "application/octet-stream"), ("Content-Disposition", content_disposition(filename)), ], ) return request.not_found()
def claim(self, claim_id, **post): env = request.env partner = self._get_partner_company() claim = env['crm.claim'].browse(int(claim_id)) if not partner or not claim.exists() \ and claim.partner_sat_id.id != partner.id: return request.not_found() if not claim.access_date: claim.print_date = datetime.now() params = request.params if params.get('mode', '') == 'write': claim.user_fault = params.get('user_fault', '') claim.sat_observations = params.get('sat_observations', '') elif params.get('mode', '') == 'send': claim.with_context(mail_post_autofollow=False).message_post( body=params.get('body_html', ''), partner_ids=claim.message_follower_ids.ids) elif params.get('mode', '') == 'upload': files = request.httprequest.files.getlist('attachment') c_file = files[0] data = c_file.read() env['ir.attachment'].create({ 'res_model': 'crm.claim', 'res_id': claim.id, 'datas_fname': c_file.filename, 'datas': data.encode('base64'), 'name': c_file.filename }) return request.website.render( 'website_myaccount_sat.claim', { 'claim': claim, 'orders': env['sale.order'].search([]), 'tab': params.get('tab', 'data'), 'attachments': env['ir.attachment'].search([('res_model', '=', 'crm.claim'), ('res_id', '=', claim.id)], order='create_date desc'), 'mail_messages': env['mail.message'].search( [('model', '=', 'crm.claim'), ('res_id', '=', claim.id), ('type', 'in', ['email', 'notification'])], order='date desc') })
def report_certificate(self, course_id=None, **kw): local_tz = pytz.timezone('America/Guayaquil') utc_dt = datetime.datetime.utcnow() local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz) cert_report = certificate_report.CertificateReport(local_tz, local_dt, course_id) flag = 1 filename, full_path = cert_report.get_certificate_report() if flag: file_content = self.print_report(full_path, filename) if not file_content: return request.not_found() else: if not filename: filename = '%s.pdf' % 'report' return request.make_response(file_content, headers=[('Content-Disposition', 'attachment; filename=%s Export' % filename), ('Content-Type', 'application/pdf')])
def build(self, build_id=None, search=None, **post): registry, cr, uid, context = request.registry, request.cr, request.uid, request.context Build = registry['runbot.build'] build = Build.browse(cr, uid, [int(build_id)])[0] if not build.exists(): return request.not_found() context = { 'introspection': build.introspection, 'introspection_html': self.build_html(build), 'repo': build.repo_id, 'bu': self.build_info(build), 'br': { 'branch': build.branch_id }, } return request.render("vauxooci.build_button", context)
def download_document(self, model, field, ids, filename=None, **kw): """ Download link for files stored as binary fields. :param str model: name of the model to fetch the binary from :param str field: binary field :param str id: id of the record from which to fetch the binary :param str filename: field holding the file's name, if any :returns: :class:`werkzeug.wrappers.Response` """ Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context fields = [field] # res = Model.read(cr, uid, ids, ['rollno', 'length', 'weight'], context)[0] print ids # tids = [int(s) for s in ids] # print tids list_str = [] for s in ids: list_str.append(s) print ids.split(',') # res = Model.read(cr, uid, ids, ['rollno', 'length', 'weight'], context)[0] res = Model.search(cr, uid, [('id', 'in', ids.split(','))], context) # self.search(cr, uid, [('state', '=', 'inprogress')], context=context) print res print field print res.get("rollno") print '123123' # filecontent = base64.b64decode(res.get("rollno") or '') filecontent = res.get("rollno") print 'zzzzzzzzzzzzzz' print filecontent if not filecontent: print 'aasssssssssssssssssssss' return request.not_found() else: if not filename: filename = '%s_%s' % (model.replace('.', '_'), ids.replace(',', '-')) return request.make_response(filecontent, [('Content-Type', 'application/octet-stream'), ('Content-Disposition', content_disposition(filename))])
def custom_report(self, model, method, data_ids): Model = request.registry[model] cr, uid, context = request.cr, request.uid, request.context try: ids = eval(data_ids) except: ids = data_ids filecontent, content_type, filename = getattr(Model, method)(cr, uid, ids, context=context) # print "==========",filecontent #filecontent = base64.b64decode( file_datas or '') if filename and filecontent: return request.make_response( filecontent, [('Content-Type', content_type), ('Content-Disposition', content_disposition(filename))]) return request.not_found()
def snippet_save(self, module, **kwargs): project = request.env['builder.ir.module.module'].search([ ('name', '=', module) ]) if not project: return request.not_found() xml_id = request.httprequest.form.get('name').lower().replace(' ', '_').replace('.', '_') if request.httprequest.form.get('name') else '' request.env['builder.website.snippet'].create({ 'module_id': project.id, 'category': 'custom', # this must be set by the default! 'name': request.httprequest.form.get('name'), 'xpath': request.httprequest.form.get('xpath'), 'source_url': request.httprequest.form.get('url'), 'content': request.httprequest.form.get('html'), 'snippet_id': xml_id, }) return request.redirect('/builder/{module}/snippet/add'.format(module=module))
def content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename_field='datas_fname', unique=None, filename=None, mimetype=None, download=None, width=0, height=0): status, headers, content = binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype='image/png') if status == 403:# This allows chat to load an image instead of nothing in Corebook Website Chat (loads corebook logo) return werkzeug.utils.redirect('https://s3-us-west-1.amazonaws.com/cbkpublic/images/56155c7e7f54fd584df8cbc1.png', code=301) if status == 304: return werkzeug.wrappers.Response(status=304, headers=headers) elif status == 301: return werkzeug.utils.redirect(content, code=301) elif status != 200 and download: return request.not_found() if content and (width or height): # resize maximum 500*500 if width > 500: width = 500 if height > 500: height = 500 content = openerp.tools.image_resize_image(base64_source=content, size=(width or None, height or None), encoding='base64', filetype='PNG') image_base64 = content and base64.b64decode(content) or self.placeholder() headers.append(('Content-Length', len(image_base64))) response = request.make_response(image_base64, headers) response.status_code = status return response
def download_document(self, model, field, id, filename=None, **kw): print("----------------- download_document ------------------") partner_id = id wizard_obj = request.registry["mail.mass_export_partner"] wizards = wizard_obj.read(request.cr, request.uid, [int(partner_id)], ["partner_ids"], context=None) wizard = wizards[0] partner_ids = wizard["partner_ids"] print("----") print(partner_ids) Model = request.registry[model] partner_obj = request.registry["res.partner"] # los ejecutivos partners = partner_obj.read( request.cr, request.uid, partner_ids, [ "is_company", "name", "names", "last_name", "mother_name", "gender", "gender_suffix", "title", "function", "street", "state_id", "province_id", "district_id", "parent_id", ], context=None, ) # cabeceras fc = "" for partner in partners: if partner["is_company"] == False: name = partner["name"] if partner["name"] else "" names = partner["names"] if partner["names"] else "" last_name = partner["last_name"] if partner["last_name"] else "" mother_name = partner["mother_name"] if partner["mother_name"] else "" function = partner["function"] if partner["function"] else "" suffix = partner["gender_suffix"] if partner["gender_suffix"] else "o" gender = partner["gender"] if partner["gender"] else "" estimado = "Estimad" + suffix title = partner["title"][1] if partner["title"] else "" street = partner["street"] if partner["street"] else "" state = partner["state_id"][1] if partner["state_id"] else "" province = partner["province_id"][1] if partner["province_id"] else "" district = partner["district_id"][1] if partner["district_id"] else "" empresa = partner["parent_id"][1] if partner["parent_id"] else "" fc = ( fc + prep_csv(empresa) + "," + prep_csv(names) + "," + prep_csv(last_name) + "," + prep_csv(mother_name) + "," + prep_csv(function) + "," + prep_csv(street) + "," + prep_csv(district) + "," + prep_csv(province) + "," + prep_csv(state) + "," + prep_csv(estimado) + "," + prep_csv(name) + "," + prep_csv(title) + "," + prep_csv(suffix) + "\n" ) if not fc: print("not fc") return request.not_found() else: print(" si fc") print(filename) if not filename: print("not filename") filename = "%s_%s" % (model.replace(".", "_"), id) return request.make_response( fc, # [('Content-Type', 'application/octet-stream'),('Content-Disposition', content_disposition(filename))]) [ ("Content-Type", "application/octet-stream;charset=utf-8"), ("Content-Disposition", content_disposition(filename)), ], )
def badge(self, repo, branch, theme='default'): domain = [('repo_id', '=', repo.id), ('branch_id.branch_name', '=', branch), ('branch_id.sticky', '=', True), ('state', 'in', ['testing', 'running', 'done']), ('result', '!=', 'skipped'), ] last_update = '__last_update' builds = request.registry['runbot.build'].search_read( request.cr, request.uid, domain, ['state', 'result', 'job_age', last_update], order='id desc', limit=1) if not builds: return request.not_found() build = builds[0] etag = request.httprequest.headers.get('If-None-Match') retag = hashlib.md5(build[last_update]).hexdigest() if etag == retag: return werkzeug.wrappers.Response(status=304) if build['state'] == 'testing': state = 'testing' cache_factor = 1 else: cache_factor = 2 if build['result'] == 'ok': state = 'success' elif build['result'] == 'warn': state = 'warning' else: state = 'failed' # from https://github.com/badges/shields/blob/master/colorscheme.json color = { 'testing': "#dfb317", 'success': "#4c1", 'failed': "#e05d44", 'warning': "#fe7d37", }[state] def text_width(s): fp = FontProperties(family='DejaVu Sans', size=11) w, h, d = TextToPath().get_text_width_height_descent(s, fp, False) return int(w + 1) class Text(object): __slot__ = ['text', 'color', 'width'] def __init__(self, text, color): self.text = text self.color = color self.width = text_width(text) + 10 data = { 'left': Text(branch, '#555'), 'right': Text(state, color), } five_minutes = 5 * 60 headers = [ ('Content-Type', 'image/svg+xml'), ('Cache-Control', 'max-age=%d' % (five_minutes * cache_factor,)), ('ETag', retag), ] return request.render("runbot.badge_" + theme, data, headers=headers)
def images(self, slug, max_width=None, max_height=None, *args, **kwargs): cr, context = request.cr, request.context # buscamos imagen por slug img, model = self._get_image_gallery(slug) if not img: return request.not_found() # leemos imagen [record] = model.read( cr, SUPERUSER_ID, [img[0]], ['name', 'last_update_img'], context=context) path_file = os.path.join(_filestorage(cr), record.get('name')) if not path_file: return request.not_found() # generamos respuesta server_format = misc.DEFAULT_SERVER_DATETIME_FORMAT response = Response(mimetype='image/jpg') response.last_modified = datetime.datetime.strptime( record.get('last_update_img'), server_format) response.make_conditional(request.httprequest) if response.status_code == 304: return response # si no hay tamaƱo la original if (not max_width) and (not max_height): data = self._read_image_data(path_file) response.set_etag(hashlib.sha1(data).hexdigest()) response.data = data return response # creamos thumb si no existe path, file_name = os.path.split(path_file) path_file_thumb = os.path.join(path, '{}x{}'.format(max_width, max_height)) if not os.path.exists(path_file_thumb): try: os.makedirs(path_file_thumb) except: _log.error(u"ERROR creando directorio para galerias <{}>" .format(slug)) return response path_file_thumb = os.path.join(path_file_thumb, file_name) if os.path.exists(path_file_thumb): data = self._read_image_data(path_file_thumb) response.set_etag(hashlib.sha1(data).hexdigest()) response.data = data return response # creamos thumb data = self._read_image_data(path_file) response.set_etag(hashlib.sha1(data).hexdigest()) image = Image.open(cStringIO.StringIO(data)) response.mimetype = Image.MIME[image.format] w, h = image.size max_w = int(max_width) if max_width else maxint max_h = int(max_height) if max_height else maxint # guardamos en disco image.thumbnail((max_w, max_h), Image.ANTIALIAS) image.save(path_file_thumb, image.format) response.data = self._read_image_data(path_file_thumb) return response
def sitemap_xml_index(self): cr, uid, context = request.cr, openerp.SUPERUSER_ID, request.context ira = request.registry["ir.attachment"] iuv = request.registry["ir.ui.view"] mimetype = "application/xml;charset=utf-8" content = None def create_sitemap(url, content): ira.create( cr, uid, dict(datas=content.encode("base64"), mimetype=mimetype, type="binary", name=url, url=url), context=context, ) sitemap = ira.search_read( cr, uid, [("url", "=", "/sitemap.xml"), ("type", "=", "binary")], ("datas", "create_date"), context=context ) if sitemap: # Check if stored version is still valid server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT create_date = datetime.datetime.strptime(sitemap[0]["create_date"], server_format) delta = datetime.datetime.now() - create_date if delta < SITEMAP_CACHE_TIME: content = sitemap[0]["datas"].decode("base64") if not content: # Remove all sitemaps in ir.attachments as we're going to regenerated them sitemap_ids = ira.search( cr, uid, [("url", "=like", "/sitemap%.xml"), ("type", "=", "binary")], context=context ) if sitemap_ids: ira.unlink(cr, uid, sitemap_ids, context=context) pages = 0 first_page = None locs = request.website.enumerate_pages() while True: start = pages * LOC_PER_SITEMAP values = { "locs": islice(locs, start, start + LOC_PER_SITEMAP), "url_root": request.httprequest.url_root[:-1], } urls = iuv.render(cr, uid, "website.sitemap_locs", values, context=context) if urls.strip(): page = iuv.render(cr, uid, "website.sitemap_xml", dict(content=urls), context=context) if not first_page: first_page = page pages += 1 create_sitemap("/sitemap-%d.xml" % pages, page) else: break if not pages: return request.not_found() elif pages == 1: content = first_page else: # Sitemaps must be split in several smaller files with a sitemap index content = iuv.render( cr, uid, "website.sitemap_index_xml", dict(pages=range(1, pages + 1), url_root=request.httprequest.url_root), context=context, ) create_sitemap("/sitemap.xml", content) return request.make_response(content, [("Content-Type", mimetype)])
def download_document(self, model, field, id, filename=None, **kw): print("----------------- download_document ------------------") partner_id = id wizard_obj = request.registry["mail.mass_export_partner"] wizards = wizard_obj.read(request.cr, request.uid, [int(partner_id)], ["partner_ids"], context=None) wizard = wizards[0] partner_ids = wizard["partner_ids"] print("----") print(partner_ids) Model = request.registry[model] activities_obj = request.registry["sead.activity.child"] partner_obj = request.registry["res.partner"] # los ejecutivos partners = partner_obj.read( request.cr, request.uid, partner_ids, [ "is_company", "name", "names", "last_name", "gender_suffix", "title", "email", "email_exclude", "email_gracias", "hierarchy_level", ], context=None, ) # cabeceras fc = "" for partner in partners: if partner["is_company"] == False: name = partner["name"] if partner["name"] else "" names = partner["names"] if partner["names"] else "" last_name = partner["last_name"] if partner["last_name"] else "" suffix = partner["gender_suffix"] if partner["gender_suffix"] else "o" estimado = "Estimad" + suffix nivel = prep_csv(partner["hierarchy_level"] if partner["hierarchy_level"] else "") title = partner["title"][1] if partner["title"] else "" email = "" if ( (partner["email_exclude"] == False) and (partner["email_gracias"] == False) and (partner["email"] != False) ): email = partner["email"] fc = ( fc + prep_csv(email) + "," + prep_csv(estimado) + "," + prep_csv(title) + "," + prep_csv(names) + "," + prep_csv(last_name) + "," + prep_csv(suffix) + "," + prep_csv(email) + "," ) fc = fc + nivel + "," + prep_csv(name) + "\n" if not fc: print("not fc") return request.not_found() else: print(" si fc") print(filename) if not filename: print("not filename") filename = "%s_%s" % (model.replace(".", "_"), id) return request.make_response( fc, # [('Content-Type', 'application/octet-stream'),('Content-Disposition', content_disposition(filename))]) [ ("Content-Type", "application/octet-stream;charset=utf-8"), ("Content-Disposition", content_disposition(filename)), ], )