Skip to content
This repository has been archived by the owner on Apr 10, 2023. It is now read-only.

Commit

Permalink
pep8ify
Browse files Browse the repository at this point in the history
  • Loading branch information
tomgross committed Oct 31, 2014
1 parent 704e685 commit 47825ef
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 32 deletions.
58 changes: 39 additions & 19 deletions Products/PasswordResetTool/PasswordResetTool.py
Expand Up @@ -29,26 +29,35 @@

from interfaces.portal_password_reset import portal_password_reset as IPWResetTool

import datetime, time, socket
import datetime
import time
import socket
from DateTime import DateTime
from zope.interface import implements

module_security = ModuleSecurityInfo('Products.PasswordResetTool.PasswordResetTool')

module_security.declarePublic('InvalidRequestError')


class InvalidRequestError(Exception):
def __init__(self, value=''):
self.value = value

def __str__(self):
return repr(self.value)

module_security.declarePublic('ExpiredRequestError')


class ExpiredRequestError(Exception):
def __init__(self, value=''):
self.value = value

def __str__(self):
return repr(self.value)


class PasswordResetTool (UniqueObject, SimpleItem):
"""Provides a default implementation for a password reset scheme.
Expand All @@ -59,7 +68,6 @@ class PasswordResetTool (UniqueObject, SimpleItem):
The user visits that URL (the 'reset form') and enters their username,
"""

## other things needed for this to work
# skins:
# - handler script for forgotten password form (probably over-riding
Expand All @@ -75,40 +83,42 @@ class PasswordResetTool (UniqueObject, SimpleItem):

security = ClassSecurityInfo()

manage_options=(( { 'label' : 'Overview'
, 'action' : 'manage_overview'
manage_options = (({'label': 'Overview'
, 'action': 'manage_overview'
},
) + SimpleItem.manage_options
)

## ZMI methods
security.declareProtected(ManagePortal, 'manage_overview')
manage_overview = DTMLFile('dtml/explainPWResetTool', globals() )
manage_overview = DTMLFile('dtml/explainPWResetTool', globals())

security.declareProtected(ManagePortal, 'manage_setTimeout')

def manage_setTimeout(self, hours=168, REQUEST=None):
"""ZMI method for setting the expiration timeout in hours."""
self.setExpirationTimeout(int(hours))
return self.manage_overview(manage_tabs_message="Timeout set to %s hours" % hours)

security.declareProtected(ManagePortal, 'manage_toggleUserCheck')

def manage_toggleUserCheck(self, REQUEST=None):
"""ZMI method for toggling the flag for checking user names on return.
"""
self.toggleUserCheck()
m = self.checkUser() and 'on' or 'off'
return self.manage_overview(manage_tabs_message="Returning username check turned %s" % m)


def __init__(self):
self._requests = {}

## Internal attributes
_user_check = 1
_timedelta = 168 # misleading name, the number of hours are actually stored as int
_timedelta = 168 # misleading name, the number of hours are actually stored as int

## Interface fulfillment ##
security.declareProtected(ManagePortal, 'requestReset')

def requestReset(self, userid):
"""Ask the system to start the password reset procedure for
user 'userid'.
Expand All @@ -125,7 +135,7 @@ def requestReset(self, userid):
self._requests[randomstring] = (userid, expiry)

self.clearExpired(10) # clear out untouched records more than 10 days old
# this is a cheap sort of "automatic" clearing
# this is a cheap sort of "automatic" clearing
self._p_changed = 1

retval = {}
Expand All @@ -135,6 +145,7 @@ def requestReset(self, userid):
return retval

security.declarePublic('resetPassword')

def resetPassword(self, userid, randomstring, password):
"""Set the password (in 'password') for the user who maps to
the string in 'randomstring' iff the entered 'userid' is equal
Expand Down Expand Up @@ -187,13 +198,12 @@ def resetPassword(self, userid, randomstring, password):
# clean out the request
del self._requests[randomstring]
self._p_changed = 1


## Implementation ##

# external

security.declareProtected(ManagePortal, 'setExpirationTimeout')

def setExpirationTimeout(self, timedelta):
"""Set the length of time a reset request will be valid.
Expand All @@ -204,6 +214,7 @@ def setExpirationTimeout(self, timedelta):
self._timedelta = abs(timedelta)

security.declarePublic('getExpirationTimeout')

def getExpirationTimeout(self):
"""Get the length of time a reset request will be valid.
Expand All @@ -216,6 +227,7 @@ def getExpirationTimeout(self):
return self._timedelta

security.declareProtected(ManagePortal, 'toggleUserCheck')

def toggleUserCheck(self):
"""Changes whether or not the tool requires someone to give the uerid
they're trying to change on a 'password reset' page. Highly recommended
Expand All @@ -226,6 +238,7 @@ def toggleUserCheck(self):
self._user_check = not self._user_check

security.declarePublic('checkUser')

def checkUser(self):
"""Returns a boolean representing the state of 'user check' as described
in 'toggleUserCheck'. True means on, and is the default."""
Expand All @@ -235,6 +248,7 @@ def checkUser(self):
return self._user_check

security.declarePublic('verifyKey')

def verifyKey(self, key):
"""Verify a key. Raises an exception if the key is invalid or expired.
"""
Expand All @@ -250,6 +264,7 @@ def verifyKey(self, key):
raise InvalidRequestError('No such user')

security.declareProtected(ManagePortal, 'getStats')

def getStats(self):
"""Return a dictionary like so:
{"open":3, "expired":0}
Expand All @@ -258,25 +273,28 @@ def getStats(self):
good = 0
bad = 0
for stored_user, expiry in self._requests.values():
if self.expired(expiry): bad += 1
else: good += 1
if self.expired(expiry):
bad += 1
else:
good += 1

return {"open": good, "expired": bad}

security.declarePrivate('clearExpired')

def clearExpired(self, days=0):
"""Destroys all expired reset request records.
Parameter controls how many days past expired it must be to disappear.
"""
for key, record in self._requests.items():
stored_user, expiry = record
if self.expired(expiry, DateTime()-days):
if self.expired(expiry, DateTime() - days):
del self._requests[key]
self._p_changed = 1

# customization points

security.declarePrivate('uniqueString')

def uniqueString(self, userid):
"""Returns a string that is random and unguessable, or at
least as close as possible.
Expand All @@ -290,10 +308,10 @@ def uniqueString(self, userid):
# this is the informal UUID algorithm of
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/213761
# by Carl Free Jr
t = long( time.time() * 1000 )
t = long(time.time() * 1000)
r = django_random.get_random_string(64)
try:
a = socket.gethostbyname( socket.gethostname() )
a = socket.gethostbyname(socket.gethostname())
except:
# if we can't get a network address, just imagine one
a = django_random.get_random_string(64)
Expand All @@ -302,6 +320,7 @@ def uniqueString(self, userid):
return str(data)

security.declarePrivate('expirationDate')

def expirationDate(self):
"""Returns a DateTime for exipiry of a request from the
current time.
Expand All @@ -310,7 +329,7 @@ def expirationDate(self):
and stored in reset request records."""
if not hasattr(self, '_timedelta'):
self._timedelta = 168
if isinstance(self._timedelta,datetime.timedelta):
if isinstance(self._timedelta, datetime.timedelta):
expire = datetime.datetime.utcnow() + self._timedelta
return DateTime(expire.year,
expire.month,
Expand All @@ -319,10 +338,11 @@ def expirationDate(self):
expire.minute,
expire.second,
'UTC')
expire = time.time() + self._timedelta*3600 # 60 min/hr * 60 sec/min
expire = time.time() + self._timedelta * 3600 # 60 min/hr * 60 sec/min
return DateTime(expire)

security.declarePrivate('getValidUser')

def getValidUser(self, userid):
"""Returns the member with 'userid' if available and None otherwise."""
if get_member_by_login_name:
Expand All @@ -332,10 +352,10 @@ def getValidUser(self, userid):
self, userid, raise_exceptions=False)
membertool = getToolByName(self, 'portal_membership')
return membertool.getMemberById(userid)

# internal

security.declarePrivate('expired')

def expired(self, datetime, now=None):
"""Tells whether a DateTime or timestamp 'datetime' is expired
with regards to either 'now', if provided, or the current
Expand Down
7 changes: 4 additions & 3 deletions Products/PasswordResetTool/__init__.py
Expand Up @@ -5,10 +5,11 @@
from zope.i18nmessageid import MessageFactory
passwordresetMessageFactory = MessageFactory('passwordresettool')

tools = ( PasswordResetTool.PasswordResetTool, )
tools = (PasswordResetTool.PasswordResetTool, )


def initialize(context):
utils.ToolInit('Password Reset Tool',
tools = tools,
tools=tools,
icon='tool.gif'
).initialize( context )
).initialize(context)
5 changes: 3 additions & 2 deletions Products/PasswordResetTool/browser.py
Expand Up @@ -9,6 +9,7 @@
from Products.PasswordResetTool import passwordresetMessageFactory as _
from email.Header import Header


class PasswordResetToolView(BrowserView):
implements(IPasswordResetToolView)

Expand All @@ -35,15 +36,15 @@ def encoded_mail_sender(self):
""" returns encoded version of Portal name <portal_email> """
portal = self.portal_state().portal()
from_ = portal.getProperty('email_from_name')
mail = portal.getProperty('email_from_address')
mail = portal.getProperty('email_from_address')
return '"%s" <%s>' % (self.encode_mail_header(from_), mail)

def registered_notify_subject(self):
portal = self.portal_state().portal()
portal_name = portal.Title()
return translate(_(u"mailtemplate_user_account_info",
default=u"User Account Information for ${portal_name}",
mapping={'portal_name':safe_unicode(portal_name)}),
mapping={'portal_name': safe_unicode(portal_name)}),
context=self.request)

def mail_password_subject(self):
Expand Down
1 change: 0 additions & 1 deletion Products/PasswordResetTool/django_random.py
Expand Up @@ -42,7 +42,6 @@

import time


# generated when process started, hard to guess
SECRET = random.randint(0, 1000000)

Expand Down
1 change: 1 addition & 0 deletions Products/PasswordResetTool/interfaces/__init__.py
@@ -1,6 +1,7 @@
# Interface definitions
from zope.interface import Interface


class IPasswordResetToolView(Interface):
""" BrowserView with utility methods """

Expand Down
@@ -1,5 +1,6 @@
from zope.interface import Interface, Attribute


class portal_password_reset(Interface):
"""Defines an interface for a tool that provides a facility to
reset forgotten passwords.
Expand All @@ -9,7 +10,7 @@ class portal_password_reset(Interface):
process) The details of the process are in the implementation,
where they belong."""

id = Attribute('id','Must be set to "portal_password_reset"')
id = Attribute('id', 'Must be set to "portal_password_reset"')

def requestReset(userid):
"""Ask the system to start the password reset procedure for
Expand Down
Expand Up @@ -8,7 +8,7 @@
##parameters=randomstring
from zExceptions import Forbidden
if container.REQUEST.get('PUBLISHED') is script:
raise Forbidden('Script may not be published.')
raise Forbidden('Script may not be published.')

host = context.restrictedTraverse('@@plone_portal_state').navigation_root_url()
return "%s/passwordreset/%s" % (host, randomstring)
10 changes: 5 additions & 5 deletions Products/PasswordResetTool/tests/test_doctests.py
Expand Up @@ -17,9 +17,10 @@
doctest.NORMALIZE_WHITESPACE |
doctest.REPORT_ONLY_FIRST_FAILURE)


class MockMailFixture(testing.PloneSandboxLayer):

defaultBases = (testing.PLONE_FIXTURE,)
defaultBases = (testing.PLONE_FIXTURE, )

def setUpPloneSite(self, portal):
portal._original_MailHost = portal.MailHost
Expand All @@ -37,19 +38,18 @@ def tearDownPloneSite(self, portal):
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(aq_base(portal._original_MailHost), provided=IMailHost)


MOCK_MAIL_FIXTURE = MockMailFixture()
MM_FUNCTIONAL_TESTING = testing.FunctionalTesting(
bases=(MOCK_MAIL_FIXTURE,), name='PloneTestCase:Functional')
bases=(MOCK_MAIL_FIXTURE, ), name='PloneTestCase:Functional')


def test_suite():
return unittest.TestSuite((
layered(doctest.DocFileSuite('browser.txt',
optionflags=OPTIONFLAGS,
package='Products.PasswordResetTool.tests',),
package='Products.PasswordResetTool.tests', ),
layer=MM_FUNCTIONAL_TESTING),
layered(doctest.DocFileSuite('view.txt',
optionflags=OPTIONFLAGS,
package='Products.PasswordResetTool.tests',),
package='Products.PasswordResetTool.tests', ),
layer=MM_FUNCTIONAL_TESTING)))

0 comments on commit 47825ef

Please sign in to comment.