From 8d421b864a740ec3a07e9351eccdb033295e32b6 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 6 Mar 2008 17:24:03 -0500 Subject: [PATCH 1/5] Add by_id for person. --- fas/fas/model.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fas/fas/model.py b/fas/fas/model.py index 749aa83..601a951 100644 --- a/fas/fas/model.py +++ b/fas/fas/model.py @@ -101,6 +101,14 @@ visit_identity_table = Table('visit_identity', metadata, class People(SABase): '''Records for all the contributors to Fedora.''' + + def by_id(cls, id): + ''' + A class method that can be used to search users + based on their unique id + ''' + return cls.query.filter_by(id=id).one() + by_id = classmethod(by_id) def by_email_address(cls, email): ''' From 4477c5a22944b1f21925c58596ba9131abe1587c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricky=20Zhou=20=28=E5=91=A8=E5=AE=B6=E6=9D=B0=29?= Date: Thu, 6 Mar 2008 22:39:46 +0000 Subject: [PATCH 2/5] Import right stuff from model, remove testing thing. --- fas/fas/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fas/fas/user.py b/fas/fas/user.py index 3318393..ff4251e 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -13,6 +13,7 @@ import subprocess from fas.model import People from fas.model import PersonEmails +from fas.model import EmailPurposes from fas.model import Log from fas.auth import * @@ -316,7 +317,6 @@ class User(controllers.Controller): newpass = generate_password() message = turbomail.Message(config.get('accounts_mail'), person.emails['primary'], _('Welcome to the Fedora Project!')) - HERE message.plain = _(''' You have created a new Fedora account! Your new password is: %s From d2f770d47d62ef306f63e3e8f4a67c721c5753d8 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 6 Mar 2008 18:49:33 -0500 Subject: [PATCH 3/5] Clean up key validation - allow non- stuff@stuff comments, etc. --- fas/fas/user.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fas/fas/user.py b/fas/fas/user.py index ff4251e..1aa8fbb 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -63,15 +63,14 @@ class ValidSSHKey(validators.FancyValidator): def validate_python(self, value, state): # value = value.file.read() print dir(value) - email_pattern = "[a-zA-Z0-9\.\+\-_]+@[a-zA-Z0-9\.\-]+" keylines = value.split('\n') print "KEYLINES: %s" % keylines for keyline in keylines: if not keyline: continue keyline = keyline.strip() - m = re.match('ssh-[dr]s[as] [^ ]+ ' + email_pattern, keyline) - if not m or m.end() < len(keyline): + m = re.match('^(rsa|dsa|ssh-rsa|ssh-dss) [ \t]*[^ \t]+.*$', keyline) + if not m: raise validators.Invalid(_('Error - Not a valid ssh key: %s') % keyline, value, state) class ValidUsername(validators.FancyValidator): From 660594dd132ba612483891ea17f12ddf31ce89a8 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 6 Mar 2008 20:14:33 -0500 Subject: [PATCH 4/5] Fix by_email_address (now for users/groups), add by_id for groups. --- fas/fas/model.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/fas/fas/model.py b/fas/fas/model.py index 601a951..565a324 100644 --- a/fas/fas/model.py +++ b/fas/fas/model.py @@ -109,13 +109,13 @@ class People(SABase): ''' return cls.query.filter_by(id=id).one() by_id = classmethod(by_id) - + def by_email_address(cls, email): ''' A class method that can be used to search users based on their email addresses since it is unique. ''' - return cls.query.join('emails').filter_by(email=email).first() + return cls.query.join(['email_purposes', 'person_email']).filter_by(email=email).one() by_email_address = classmethod(by_email_address) @@ -141,7 +141,7 @@ class People(SABase): role.role_type = 'user' role.member = cls role.group = group - + def approve(cls, group, requester): ''' Approve a person in a group - requester for logging purposes @@ -151,7 +151,7 @@ class People(SABase): else: role = PersonRoles.query.filter_by(member=cls, group=group).one() role.role_status = 'approved' - + def upgrade(cls, group, requester): ''' Upgrade a user in a group - requester for logging purposes @@ -166,7 +166,7 @@ class People(SABase): role.role_type = 'administrator' elif role.role_type == 'user': role.role_type = 'sponsor' - + def downgrade(cls, group, requester): ''' Downgrade a user in a group - requester for logging purposes @@ -181,7 +181,7 @@ class People(SABase): role.role_type = 'user' elif role.role_type == 'administrator': role.role_type = 'sponsor' - + def sponsor(cls, group, requester): # If we want to do logging, this might be the place. if not group in cls.unapproved_memberships: @@ -300,6 +300,24 @@ class Configs(SABase): class Groups(SABase): '''Group that people can belong to.''' + + def by_id(cls, id): + ''' + A class method that can be used to search groups + based on their unique id + ''' + return cls.query.filter_by(id=id).one() + by_id = classmethod(by_id) + + def by_email_address(cls, email): + ''' + A class method that can be used to search groups + based on their email addresses since it is unique. + ''' + return cls.query.join(['group_email_purposes', 'group_email']).filter_by(email=email).one() + + by_email_address = classmethod(by_email_address) + def by_name(cls, name): ''' A class method that permits to search groups @@ -372,7 +390,7 @@ class UnApprovedRoles(PersonRoles): class Visit(SABase): '''Track how many people are visiting the website. - + It doesn't currently make sense for us to track this here so we clear this table of stale records every hour. ''' @@ -382,7 +400,7 @@ class Visit(SABase): class VisitIdentity(SABase): '''Associate a user with a visit cookie. - + This allows users to log in to app. ''' pass From 6a3ebfc34546fdaaad4e3e858bcaf1bacef52885 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 6 Mar 2008 20:44:08 -0500 Subject: [PATCH 5/5] Groundwork for managing user emails. --- fas/fas/model.py | 4 +- fas/fas/templates/user/email/__init__.py | 0 fas/fas/templates/user/email/manage.html | 47 +++++++++++++++++++ fas/fas/user.py | 11 ++--- fas/fas/user_email.py | 59 ++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 fas/fas/templates/user/email/__init__.py create mode 100644 fas/fas/templates/user/email/manage.html create mode 100644 fas/fas/user_email.py diff --git a/fas/fas/model.py b/fas/fas/model.py index 565a324..c108d1b 100644 --- a/fas/fas/model.py +++ b/fas/fas/model.py @@ -429,7 +429,7 @@ mapper(People, PeopleTable, properties = { primaryjoin = PeopleTable.c.id==UnApprovedRoles.c.person_id) }) mapper(PersonEmails, PersonEmailsTable, properties = { - 'person': relation(People, uselist = False, + 'person': relation(People, backref = 'person_emails', uselist = False, primaryjoin = PeopleTable.c.id==PersonEmailsTable.c.person_id) }) mapper(EmailPurposes, EmailPurposesTable, properties = { @@ -456,7 +456,7 @@ mapper(Groups, GroupsTable, properties = { primaryjoin = GroupsTable.c.prerequisite_id==GroupsTable.c.id) }) mapper(GroupEmails, GroupEmailsTable, properties = { - 'group': relation(Groups, uselist = False, + 'group': relation(Groups, backref = 'group_emails', uselist = False, primaryjoin = GroupsTable.c.id==GroupEmailsTable.c.group_id) }) mapper(GroupEmailPurposes, GroupEmailPurposesTable, properties = { diff --git a/fas/fas/templates/user/email/__init__.py b/fas/fas/templates/user/email/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fas/fas/templates/user/email/manage.html b/fas/fas/templates/user/email/manage.html new file mode 100644 index 0000000..0d449b1 --- /dev/null +++ b/fas/fas/templates/user/email/manage.html @@ -0,0 +1,47 @@ + + + + + ${_('Manage Emails')} + + +

${_('Managing Emails for %s') % person.username}

+

Available Emails

+ + + + + + + + + + + + + + + + +
${_('Email')}${_('Description')}${_('Verified')}
${email.email}${email.description}${_('Verified')}${_('Unverified')} ${_('Resend Verification')}
+

Set Emails

+ + + + + + + + + + + + + + + +
${_('Email')}${_('Description')}${_('Purpose')}
${purpose.email}${purpose.person_email.description}${purpose.purpose}
+ + diff --git a/fas/fas/user.py b/fas/fas/user.py index 1aa8fbb..a86173b 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -17,6 +17,7 @@ from fas.model import EmailPurposes from fas.model import Log from fas.auth import * +from fas.user_email import Email, NonFedoraEmail from random import Random import sha @@ -33,14 +34,6 @@ class KnownUser(validators.FancyValidator): except InvalidRequestError: raise validators.Invalid(_("'%s' does not exist.") % value, value, state) -class NonFedoraEmail(validators.FancyValidator): - '''Make sure that an email address is not @fedoraproject.org''' - def _to_python(self, value, state): - return value.strip() - def validate_python(self, value, state): - if value.endswith('@fedoraproject.org'): - raise validators.Invalid(_("To prevent email loops, your email address cannot be @fedoraproject.org."), value, state) - class UnknownUser(validators.FancyValidator): '''Make sure that a user doesn't already exist''' def _to_python(self, value, state): @@ -153,6 +146,8 @@ def generate_salt(length=8): class User(controllers.Controller): + email = Email() + def __init__(self): '''Create a User Controller. ''' diff --git a/fas/fas/user_email.py b/fas/fas/user_email.py new file mode 100644 index 0000000..2ef95c7 --- /dev/null +++ b/fas/fas/user_email.py @@ -0,0 +1,59 @@ +import turbogears +from turbogears import controllers, expose, paginate, identity, redirect, widgets, validate, validators, error_handler, config +from turbogears.database import session +import cherrypy + +from fas.model import People +from fas.model import PersonEmails +from fas.model import EmailPurposes +from fas.model import Log + +class NonFedoraEmail(validators.FancyValidator): + '''Make sure that an email address is not @fedoraproject.org''' + def _to_python(self, value, state): + return value.strip() + def validate_python(self, value, state): + if value.endswith('@fedoraproject.org'): + raise validators.Invalid(_("To prevent email loops, your email address cannot be @fedoraproject.org."), value, state) + +class EmailCreate(validators.Schema): + email = validators.All( + validators.Email(not_empty=True, strip=True), + NonFedoraEmail(not_empty=True, strip=True), + ) + #fedoraPersonBugzillaMail = validators.Email(strip=True) + postal_address = validators.String(max=512) + +class Email(controllers.Controller): + + def __init__(self): + '''Create an Email Controller. + ''' + + @identity.require(turbogears.identity.not_anonymous()) + def index(self): + '''Redirect to manage + ''' + turbogears.redirect('/user/email/manage/%s' % turbogears.identity.current.user_name) + + + @expose(template="fas.templates.error") + def error(self, tg_errors=None): + '''Show a friendly error message''' + if not tg_errors: + turbogears.redirect('/') + return dict(tg_errors=tg_errors) + + @identity.require(turbogears.identity.not_anonymous()) + #@validate(validators=UserView()) + @error_handler(error) + @expose(template="fas.templates.user.email.manage", allow_json=True) + def manage(self, username=None): + ''' + Manage a person's emails. + ''' + if not username: + username = turbogears.identity.current.user_name + person = People.by_username(username) + return dict(person=person) +