class NewEmailForm(Form): to = StringField(validators=[ DataRequired(i8n.EMAIL_TO_REQUIRED), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID) ]) cc = StringField(validators=[ DataOptional(), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID) ]) bcc = StringField(validators=[ DataOptional(), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID) ]) subject = StringField(validators=[DataOptional()]) body = HtmlTextAreaField(validators=[DataOptional()]) attachments = FileField(validators=[DataOptional()], render_kw={'multiple': True}) submit = SubmitField() def as_dict(self, attachment_encoder: AttachmentEncoder) -> dict: attachments = request.files.getlist(self.attachments.name) form = {key: value for (key, value) in self.data.items() if value} form.pop('submit', None) form['sent_at'] = None form['read'] = True form['from'] = current_user.email form['to'] = _split_emails(form.get('to')) form['cc'] = _split_emails(form.get('cc')) form['bcc'] = _split_emails(form.get('bcc')) form['body'] = form.get('body') form['attachments'] = list( _attachments_as_dict(attachments, attachment_encoder)) return form def _populate(self, email: dict): pass @classmethod def _new_instance_for(cls, action_name: Optional[str]): if not action_name: return cls(request.form) try: clazz = next(clazz for clazz in NewEmailForm.__subclasses__() if getattr(clazz, 'action_name', None) == action_name) except StopIteration: return None else: return clazz(request.form) @classmethod def from_request(cls, email_store: EmailStore): action_name = request.args.get('action') form = cls._new_instance_for(action_name) if not form: return None uid = request.args.get('uid') if uid: reference = email_store.get(uid) if not reference or not current_user.can_access(reference): return None form._populate(reference) return form
def verify(cls, delimiter, field_value): validator = Emails(delimiter) validator(form=None, field=DummyField(field_value))
class NewEmailForm(FlaskForm): to = StringField(validators=[ DataRequired(i8n.EMAIL_TO_REQUIRED), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID), ]) cc = StringField(validators=[ DataOptional(), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID), ]) bcc = StringField(validators=[ DataOptional(), Emails(AppConfig.EMAIL_ADDRESS_DELIMITER, i8n.EMAIL_ADDRESS_INVALID), ]) subject = StringField(validators=[DataOptional()]) body = HtmlTextAreaField(validators=[ DataOptional(), ]) forwarded_attachments = SelectMultipleField(choices=[], validators=[ DataOptional(), ]) attachments = FileField(validators=[ DataOptional(), ], render_kw={ 'multiple': True, }) submit = SubmitField() def as_dict(self, email_store: EmailStore) -> dict: form = {key: value for (key, value) in self.data.items() if value} form.pop('submit', None) attachments = request.files.getlist(self.attachments.name) to = _split_emails(form.get('to')) cc = _split_emails(form.get('cc')) bcc = _split_emails(form.get('bcc')) sent_at = None if all(_is_local_message(address) for address in chain(to, cc, bcc)): sent_at = datetime.utcnow().strftime('%Y-%m-%d %H:%M') form['sent_at'] = sent_at form['read'] = True form['from'] = current_user.email form['to'] = to form['cc'] = cc form['bcc'] = bcc form['body'] = form.get('body') form['subject'] = form.get('subject', i8n.EMAIL_NO_SUBJECT) form['attachments'] = list(_attachments_as_dict(attachments)) return form def _populate(self, user, email_store: EmailStore): pass @classmethod def _new_instance_for(cls, action_name: Optional[str]): if not action_name: return cls(request.form) try: clazz = next(clazz for clazz in NewEmailForm.__subclasses__() if getattr(clazz, 'action_name', None) == action_name) except StopIteration: return None else: return clazz(request.form) def _get_reference_email(self, email_store: EmailStore) -> Optional[dict]: uid = request.args.get('uid', '') if not uid: return None reference = email_store.get(uid) if not self._can_access(current_user, reference): return None return reference @classmethod def _can_access(cls, user, email: dict) -> bool: actors = set() actors.add(email.get('from')) actors.update(email.get('to', [])) actors.update(email.get('cc', [])) actors.update(email.get('bcc', [])) return user.email in actors @classmethod def from_request(cls, user, email_store: EmailStore): action_name = request.args.get('action') form = cls._new_instance_for(action_name) if not form: return None form._populate(user, email_store) return form