Skip to content

Commit

Permalink
Added RFC 822 conform email field to z3c.schema
Browse files Browse the repository at this point in the history
Added unit tests
  • Loading branch information
projekt01 committed Nov 24, 2006
1 parent 393ea6d commit c31444f
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
82 changes: 82 additions & 0 deletions src/z3c/schema/email/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
==============
Special Fields
==============

1. E-Mail Field
---------------

Let's first generate an E-mail field:

>>> from z3c.schema.email import RFC822MailAddress
>>> email = RFC822MailAddress()

Check that the constraints of the value are fulfilled:

>>> email.constraint('foo\n')
False
>>> email.constraint('foo\r')
False
>>> email.constraint('foo')
True

Now make sure the E-mail addresses validate:

>>> email.validate('foo@bar.com')
Traceback (most recent call last):
...
WrongType: ('foo@bar.com', <type 'unicode'>)

>>> email.validate(u'foo@bar.')
Traceback (most recent call last):
...
NotValidRFC822MailAdress: foo@bar.

>>> email.validate(u'foo@bar.com')

Since the field uses a simple function to validate its E-mail fields, it is
easier to use it for the tests:

>>> from z3c.schema.email import isValidMailAddress
>>> isValidMailAddress(u'foo@bar.com')
True
>>> isValidMailAddress(u'foo.blah@bar.com')
True

# Name failures

>>> isValidMailAddress(u'foo\r@bar.com')
False
>>> isValidMailAddress(u'foo<@bar.com')
False
>>> isValidMailAddress(u'foo:@bar.com')
False

# Overall failures

>>> isValidMailAddress(u'')
False
>>> isValidMailAddress(u'foo.')
False
>>> isValidMailAddress(u'foo.@bar.com')
False
>>> isValidMailAddress(u'.foo@bar.com')
False
>>> isValidMailAddress(u'foo@bar.com.')
False

# Domain failures

>>> isValidMailAddress(u'foo@')
False
>>> isValidMailAddress(u'foo@bar.')
False
>>> isValidMailAddress(u'foo@bar')
False
>>> isValidMailAddress(u'foo@bar..com')
False
>>> isValidMailAddress(u'foo@bar\r.com')
False
>>> isValidMailAddress(u'foo@bar<.com')
False
>>> isValidMailAddress(u'foo@bar:.com')
False
19 changes: 19 additions & 0 deletions src/z3c/schema/email/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""

from z3c.schema.email.field import isValidMailAddress
from z3c.schema.email.field import RFC822MailAddress
88 changes: 88 additions & 0 deletions src/z3c/schema/email/field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
__docformat__ = "reStructuredText"

import zope.interface
import zope.schema

from z3c.schema.email import interfaces

rfc822_specials = '()<>@,;:\\"[]'


def isValidMailAddress(addr):
"""Returns True if the email address is valid and False if not."""

# First we validate the name portion (name@domain)
c = 0
while c < len(addr):
if addr[c] == '@':
break
# Make sure there are only ASCII characters
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127:
return False
# A RFC-822 address cannot contain certain ASCII characters
if addr[c] in rfc822_specials:
return False
c = c + 1

# check whether we have any input and that the name did not end with a dot
if not c or addr[c - 1] == '.':
return False

# check also starting and ending dots in (name@domain)
if addr.startswith('.') or addr.endswith('.'):
return False

# Next we validate the domain portion (name@domain)
domain = c = c + 1
# Ensure that the domain is not empty (name@)
if domain >= len(addr):
return False
count = 0
while c < len(addr):
# Make sure that domain does not end with a dot or has two dots in a row
if addr[c] == '.':
if c == domain or addr[c - 1] == '.':
return False
count = count + 1
# Make sure there are only ASCII characters
if ord(addr[c]) <= 32 or ord(addr[c]) >= 127:
return False
# A RFC-822 address cannot contain certain ASCII characters
if addr[c] in rfc822_specials:
return False
c = c + 1
if count >= 1:
return True
else:
return False


class RFC822MailAddress(zope.schema.TextLine):
"""A valid email address."""
__doc__ = interfaces.IRFC822MailAddress.__doc__

zope.interface.implements(interfaces.IRFC822MailAddress)

def constraint(self, value):
return '\n' not in value and '\r' not in value

def _validate(self, value):
super(RFC822MailAddress, self)._validate(value)
if not isValidMailAddress(value):
raise interfaces.NotValidRFC822MailAdress(value)
29 changes: 29 additions & 0 deletions src/z3c/schema/email/interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
__docformat__ = "reStructuredText"

import zope.schema
import zope.schema.interfaces
from z3c.i18n import MessageFactory as _


class IRFC822MailAddress(zope.schema.interfaces.ITextLine):
"""A valid RFC822 email address field."""


class NotValidRFC822MailAdress(zope.schema.ValidationError):
__doc__ = _("""Not a valid RFC822 email address""")
32 changes: 32 additions & 0 deletions src/z3c/schema/email/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
__docformat__ = "reStructuredText"

import unittest
from zope.testing import doctest
from zope.testing.doctestunit import DocFileSuite


def test_suite():
return unittest.TestSuite((
DocFileSuite('README.txt',
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,),
))


if __name__ == '__main__':
unittest.main(defaultTest='test_suite')

0 comments on commit c31444f

Please sign in to comment.