import logging from odoo import http from odoo.exceptions import UserError from odoo.http import request _logger = logging.getLogger(__name__) class FamilyLawSignature(http.Controller): """ Public signing portal — one-time per-token URL with an HTML5 canvas pad. No login required; access is gated by the unguessable token on the request. """ @http.route(['/familylaw/sign/'], type='http', auth='public', methods=['GET'], website=True, csrf=False) def sign_page(self, token, **kw): req = self._lookup(token) if not req: return request.render('activeblue_familylaw.fl_signature_invalid', {}) if req.state == 'signed': return request.render('activeblue_familylaw.fl_signature_done', {'req': req}) if req.state in ('declined', 'expired'): return request.render('activeblue_familylaw.fl_signature_closed', {'req': req}) pdf_url = (f'/web/content/{req.unsigned_attachment_id.id}' if req.unsigned_attachment_id else '') return request.render('activeblue_familylaw.fl_signature_pad', { 'req': req, 'pdf_url': pdf_url, 'token': token, }) @http.route(['/familylaw/sign//submit'], type='http', auth='public', methods=['POST'], website=True, csrf=False) def sign_submit(self, token, signature='', **kw): req = self._lookup(token) if not req: return request.render('activeblue_familylaw.fl_signature_invalid', {}) if not signature: return request.render('activeblue_familylaw.fl_signature_pad', { 'req': req, 'pdf_url': (f'/web/content/{req.unsigned_attachment_id.id}' if req.unsigned_attachment_id else ''), 'token': token, 'error': 'Please draw your signature before submitting.', }) try: req.sudo().apply_signature( signature, signer_ip=request.httprequest.headers.get( 'X-Forwarded-For', request.httprequest.remote_addr or ''), ) except UserError as exc: return request.render('activeblue_familylaw.fl_signature_pad', { 'req': req, 'pdf_url': (f'/web/content/{req.unsigned_attachment_id.id}' if req.unsigned_attachment_id else ''), 'token': token, 'error': str(exc), }) return request.render('activeblue_familylaw.fl_signature_done', {'req': req}) @http.route(['/familylaw/sign//decline'], type='http', auth='public', methods=['POST'], website=True, csrf=False) def sign_decline(self, token, reason='', **kw): req = self._lookup(token) if not req: return request.render('activeblue_familylaw.fl_signature_invalid', {}) try: req.sudo().action_decline(reason=reason) except UserError: pass return request.render('activeblue_familylaw.fl_signature_closed', {'req': req}) @staticmethod def _lookup(token): return request.env['fl.signature.request'].sudo().search( [('token', '=', token)], limit=1)