diff --git a/fas/fas/cla.py b/fas/fas/cla.py index 8782df6..69001cf 100644 --- a/fas/fas/cla.py +++ b/fas/fas/cla.py @@ -135,7 +135,7 @@ class CLA(controllers.Controller): emails = []; for uid in key.uids: emails.extend([uid.email]) - if person.emails['primary'] in emails: + if person.email in emails: verified = True else: turbogears.flash(_('Your key did not match your email.')) @@ -181,7 +181,7 @@ class CLA(controllers.Controller): message.plain = ''' Fedora user %(username)s has signed a completed ICLA using their published GPG key, ID %(gpg_keyid)s, that is associated with e-mail address %(email)s. The full signed ICLA is attached. -''' % {'username': person.username, 'gpg_keyid': person.gpg_keyid, 'email': person.emails['primary']} +''' % {'username': person.username, 'gpg_keyid': person.gpg_keyid, 'email': person.email} signature.file.seek(0) # For another read() message.attach(signature.file, signature.filename) turbomail.enqueue(message) diff --git a/fas/fas/group.py b/fas/fas/group.py index ba88f8b..3fc4b1b 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -308,7 +308,7 @@ Fedora user %(user)s, aka %(name)s <%(email)s> has requested membership for %(applicant)s (%(applicant_name)s) in the %(group)s group and needs a sponsor. Please go to %(url)s to take action. -''') % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.emails['primary'], 'url': url, 'group': group.name} +''') % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.email, 'url': url, 'group': group.name} turbomail.enqueue(message) turbogears.flash(_('%(user)s has applied to %(group)s!') % \ {'user': target.username, 'group': group.name}) @@ -339,14 +339,14 @@ Please go to %(url)s to take action. turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "Your Fedora '%s' membership has been sponsored" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.email, "Your Fedora '%s' membership has been sponsored" % group.name) message.plain = _(''' %(name)s <%(email)s> has sponsored you for membership in the %(group)s group of the Fedora account system. If applicable, this change should propagate into the e-mail aliases and CVS repository within an hour. %(joinmsg)s -''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'], 'joinmsg': group.joinmsg} +''') % {'group': group.name, 'name': person.human_name, 'email': person.email, 'joinmsg': group.joinmsg} turbomail.enqueue(message) turbogears.flash(_("'%s' has been sponsored!") % target.human_name) turbogears.redirect('/group/view/%s' % group.name) @@ -376,13 +376,13 @@ propagate into the e-mail aliases and CVS repository within an hour. {'user': target.username, 'group': group.name, 'error': e}) turbogears.redirect('/group/view/%s' % group.name) else: - message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "Your Fedora '%s' membership has been removed" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.email, "Your Fedora '%s' membership has been removed" % group.name) message.plain = _(''' %(name)s <%(email)s> has removed you from the '%(group)s' group of the Fedora Accounts System This change is effective immediately for new operations, and should propagate into the e-mail aliases within an hour. -''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary']} +''') % {'group': group.name, 'name': person.human_name, 'email': person.email} turbomail.enqueue(message) turbogears.flash(_('%(name)s has been removed from %(group)s') % \ {'name': target.username, 'group': group.name}) @@ -413,7 +413,7 @@ aliases within an hour. turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "Your Fedora '%s' membership has been upgraded" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.email, "Your Fedora '%s' membership has been upgraded" % group.name) # Should we make person.upgrade return this? role = PersonRoles.query.filter_by(group=group, member=target).one() status = role.role_type @@ -422,7 +422,7 @@ aliases within an hour. '%(group)s' group of the Fedora Accounts System This change is effective immediately for new operations, and should propagate into the e-mail aliases within an hour. -''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'], 'status': status} +''') % {'group': group.name, 'name': person.human_name, 'email': person.email, 'status': status} turbomail.enqueue(message) turbogears.flash(_('%s has been upgraded!') % target.username) turbogears.redirect('/group/view/%s' % group.name) @@ -452,7 +452,7 @@ into the e-mail aliases within an hour. turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "Your Fedora '%s' membership has been downgraded" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.email, "Your Fedora '%s' membership has been downgraded" % group.name) role = PersonRoles.query.filter_by(group=group, member=target).one() status = role.role_type message.plain = _(''' @@ -460,7 +460,7 @@ into the e-mail aliases within an hour. '%(group)s' group of the Fedora Accounts System This change is effective immediately for new operations, and should propagate into the e-mail aliases within an hour. -''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'], 'status': status} +''') % {'group': group.name, 'name': person.human_name, 'email': person.email, 'status': status} turbomail.enqueue(message) turbogears.flash(_('%s has been downgraded!') % target.username) turbogears.redirect('/group/view/%s' % group.name) @@ -504,7 +504,7 @@ into the e-mail aliases within an hour. group = Groups.by_name(groupname) if isApproved(person, group): - message = turbomail.Message(person.emails['primary'], target, _('Come join The Fedora Project!')) + message = turbomail.Message(person.email, target, _('Come join The Fedora Project!')) message.plain = _(''' %(name)s <%(email)s> has invited you to join the Fedora Project! We are a community of users and developers who produce a @@ -520,7 +520,7 @@ place for you whether you're an artist, a web site builder, a writer, or a people person. You'll grow and learn as you work on a team with other very smart and talented people. -Fedora and FOSS are changing the world -- come be a part of it!''') % {'name': person.human_name, 'email': person.emails['primary']} +Fedora and FOSS are changing the world -- come be a part of it!''') % {'name': person.human_name, 'email': person.email} turbomail.enqueue(message) turbogears.flash(_('Message sent to: %s') % target) turbogears.redirect('/group/view/%s' % group.name) diff --git a/fas/fas/help.py b/fas/fas/help.py index 3f3d229..80afefd 100644 --- a/fas/fas/help.py +++ b/fas/fas/help.py @@ -4,10 +4,11 @@ from turbogears.database import session from fas.auth import * +# TODO: gettext like crazy. class Help(controllers.Controller): help = { 'none' : ['Error', '

We could not find that help item

'], 'user_ircnick' : ['IRC Nick (Optional)', '

IRC Nick is used to identify yourself on irc.freenode.net. Please register your nick on irc.freenode.net first, then fill this in so people can find you online when they need to

'], - 'user_primary_email' : ['Primary Email (Required)', '

This email address should be your prefered email contact and will be used to send various official emails to. This is also where your @fedoraproject.org email will get forwarded

'], + 'user_email' : ['Email (Required)', '

This email address should be your prefered email contact and will be used to send various official emails to. This is also where your @fedoraproject.org email will get forwarded

'], 'user_human_name' : ['Full Name (Required)', '

Your Human Name or "real life" name

'], 'user_gpg_keyid' : ['GPG Key', '

Only required for users signing the CLA. It is generally used to prove that a message or email came from you or to encrypt information so that only the recipients can read it. See the CLAHowTo for more information

'], 'user_telephone' : ['Telephone', '

Only required for users signing the CLA. Sometimes during a time of emergency someone from the Fedora Project may need to contact you. For more information see our Privacy Policy

'], diff --git a/fas/fas/model.py b/fas/fas/model.py index 4f39024..c345665 100644 --- a/fas/fas/model.py +++ b/fas/fas/model.py @@ -56,14 +56,10 @@ get_engine() # PeopleTable = Table('people', metadata, autoload=True) -PersonEmailsTable = Table('person_emails', metadata, autoload=True) -EmailPurposesTable = Table('email_purposes', metadata, autoload=True) PersonRolesTable = Table('person_roles', metadata, autoload=True) ConfigsTable = Table('configs', metadata, autoload=True) GroupsTable = Table('groups', metadata, autoload=True) -GroupEmailsTable = Table('group_emails', metadata, autoload=True) -GroupEmailPurposesTable = Table('group_email_purposes', metadata, autoload=True) GroupRolesTable = Table('group_roles', metadata, autoload=True) BugzillaQueueTable = Table('bugzilla_queue', metadata, autoload=True) LogTable = Table('log', metadata, autoload=True) @@ -116,7 +112,7 @@ class People(SABase): A class method that can be used to search users based on their email addresses since it is unique. ''' - return cls.query.join(['email_purposes', 'person_email']).filter_by(email=email).one() + return cls.query.filter_by(email=email).one() @classmethod def by_username(cls, username): @@ -250,8 +246,12 @@ class People(SABase): if not identity.in_group('admin'): # Only admins can see internal_comments del props['internal_comments'] + del props['emailtoken'] if identity.current.anonymous: # Anonymous users can't see any of these + del props['email'] + del props['emailtoken'] + del props['unverified_email'] del props['ssh_key'] del props['gpg_keyid'] del props['affiliation'] @@ -262,8 +262,10 @@ class People(SABase): del props['postal_address'] del props['telephone'] del props['facsimile'] + # TODO: Are we still doing the fas-system thing? I think I saw a systems users somewhere... elif not identity.current.user.username == self.username and 'fas-system' not in identity.current.groups: # Only an admin or the user themselves can see these fields + del props['unverified_email'] del props['password'] del props['passwordtoken'] del props['postal_address'] @@ -277,19 +279,6 @@ class People(SABase): approved_memberships = association_proxy('approved_roles', 'group') unapproved_memberships = association_proxy('unapproved_roles', 'group') - emails = association_proxy('email_purposes', 'email') - -class PersonEmails(SABase): - '''Map a person to an email address.''' - def __repr__(cls): - return "PersonEmails(%s,%s,%s,%s)" % (cls.person.username, cls.email, cls.description, cls.verified) - -class EmailPurposes(SABase): - '''Map a person to an email (with a purpose).''' - def __repr__(cls): - return "EmailPurposes(%s,%s,%s)" % (cls.person.username, cls.email, cls.purpose) - email = association_proxy('person_email', 'email') - class PersonRoles(SABase): '''Record people that are members of groups.''' def __repr__(cls): @@ -317,7 +306,7 @@ class Groups(SABase): A class method that can be used to search groups based on their email addresses since it is unique. ''' - return cls.query.join(['email_purposes', 'group_email']).filter_by(email=email).one() + return cls.query.filter_by(email=email).one() @classmethod @@ -338,21 +327,6 @@ class Groups(SABase): # Groups that this group belongs to memberships = association_proxy('group_roles', 'group') - emails = association_proxy('email_purposes', 'email') - -class GroupEmails(SABase): - '''Map a group to an email address.''' - def __repr__(cls): - return "GroupEmails(%s,%s,%s,%s)" % (cls.group.name, cls.email, cls.description, cls.verified) - -class GroupEmailPurposes(SABase): - '''Map a group to an email (with a purpose).''' - def __repr__(cls): - return "GroupEmailPurposes(%s,%s,%s)" % (cls.group.name, cls.email, cls.purpose) - - email = association_proxy('group_email', 'email') - - class GroupRoles(SABase): '''Record groups that are members of other groups.''' pass @@ -420,12 +394,6 @@ mapper(UnApprovedRoles, UnApprovedRolesSelect, properties = { }) mapper(People, PeopleTable, properties = { - 'email_purposes': relation(EmailPurposes, backref = 'person', - collection_class = column_mapped_collection( - EmailPurposesTable.c.purpose)), - 'person_emails': relation(PersonEmails, backref = 'person', - collection_class = column_mapped_collection( - PersonEmailsTable.c.email)), # This name is kind of confusing. It's to allow person.group_roles['groupname'] in order to make auth.py (hopefully) slightly faster. 'group_roles': relation(PersonRoles, collection_class = attribute_mapped_collection('groupname'), @@ -435,11 +403,6 @@ mapper(People, PeopleTable, properties = { 'unapproved_roles': relation(UnApprovedRoles, backref='member', primaryjoin = PeopleTable.c.id==UnApprovedRoles.c.person_id) }) -mapper(PersonEmails, PersonEmailsTable) -mapper(EmailPurposes, EmailPurposesTable, properties = { - 'person_email': relation(PersonEmails, uselist = False, - primaryjoin = PersonEmailsTable.c.id==EmailPurposesTable.c.email_id) - }) mapper(PersonRoles, PersonRolesTable, properties = { 'member': relation(People, backref = 'roles', lazy = False, primaryjoin=PersonRolesTable.c.person_id==PeopleTable.c.id), @@ -454,20 +417,9 @@ mapper(Configs, ConfigsTable, properties = { mapper(Groups, GroupsTable, properties = { 'owner': relation(People, uselist=False, primaryjoin = GroupsTable.c.owner_id==PeopleTable.c.id), - 'email_purposes': relation(GroupEmailPurposes, backref = 'group', - collection_class = column_mapped_collection( - GroupEmailPurposesTable.c.purpose)), - 'group_emails': relation(GroupEmails, backref = 'group', - collection_class = column_mapped_collection( - GroupEmailsTable.c.email)), 'prerequisite': relation(Groups, uselist=False, primaryjoin = GroupsTable.c.prerequisite_id==GroupsTable.c.id) }) -mapper(GroupEmails, GroupEmailsTable) -mapper(GroupEmailPurposes, GroupEmailPurposesTable, properties = { - 'group_email': relation(GroupEmails, uselist = False, - primaryjoin = GroupEmailsTable.c.id==GroupEmailPurposesTable.c.email_id) - }) # GroupRoles are complex because the group is a member of a group and thus # is referencing the same table. mapper(GroupRoles, GroupRolesTable, properties = { diff --git a/fas/fas/release.py b/fas/fas/release.py index a1d54fd..5ebac71 100644 --- a/fas/fas/release.py +++ b/fas/fas/release.py @@ -2,7 +2,7 @@ Release information about the Fedora Accounts System ''' -VERSION = '0.1' +VERSION = '0.5' NAME = 'fas' DESCRIPTION = 'The Fedora Account System' LONG_DESCRIPTION = ''' diff --git a/fas/fas/templates/cla/cla.html b/fas/fas/templates/cla/cla.html index 5a5b0e8..34643a3 100644 --- a/fas/fas/templates/cla/cla.html +++ b/fas/fas/templates/cla/cla.html @@ -20,7 +20,7 @@

Full name: ${person.human_name}
- E-Mail: ${person.emails['primary']}
+ E-Mail: ${person.email}
Address: ${person.postal_address}
Telephone: ${person.telephone} diff --git a/fas/fas/templates/cla/cla.txt b/fas/fas/templates/cla/cla.txt index 68e0a18..38451aa 100644 --- a/fas/fas/templates/cla/cla.txt +++ b/fas/fas/templates/cla/cla.txt @@ -27,7 +27,7 @@ fedora-legal@redhat.com. Please read this document carefully before signing and keep a copy for your records. - Full name: ${'%28s' % person.human_name} E-Mail: ${'%17s' % person.emails['primary']} + Full name: ${'%28s' % person.human_name} E-Mail: ${'%17s' % person.email} Address: ${person.postal_address} @@ -150,5 +150,5 @@ ${person.postal_address} If you agree to these terms and conditions, type "I agree" here: Enter your full name here: - E-mail: ${person.emails['primary']} + E-mail: ${person.email} Date: ${date} diff --git a/fas/fas/templates/cla/view.html b/fas/fas/templates/cla/view.html index b084fe6..6c2c1a5 100644 --- a/fas/fas/templates/cla/view.html +++ b/fas/fas/templates/cla/view.html @@ -19,7 +19,7 @@

${_('If you agree to these terms and conditions, type "%s" here:') % 'I agree'}
${_('Full Name:')} ${person.human_name}
- ${_('E-mail:')} ${person.emails['primary']}
+ ${_('E-mail:')} ${person.email}
${_('Date:')} ${date}
diff --git a/fas/fas/templates/group/dump.txt b/fas/fas/templates/group/dump.txt index 565811b..d417d81 100644 --- a/fas/fas/templates/group/dump.txt +++ b/fas/fas/templates/group/dump.txt @@ -1,3 +1,3 @@ #for role in sorted(group.approved_roles) -${role.member.username},${role.member.emails['primary']},${role.member.human_name},${role.role_type},0 +${role.member.username},${role.member.email},${role.member.human_name},${role.role_type},0 #end diff --git a/fas/fas/templates/group/invite.html b/fas/fas/templates/group/invite.html index ab9fd7f..0c537a8 100644 --- a/fas/fas/templates/group/invite.html +++ b/fas/fas/templates/group/invite.html @@ -12,12 +12,12 @@
${_('To email:')}
- ${_('From:')} ${person.emails['primary']}
+ ${_('From:')} ${person.email}
${_('Subject:')} Invitation to join the Fedora Team!
${_('Message:')}

- ${person.human_name} <${person.emails['primary']}> has invited you to join the Fedora + ${person.human_name} <${person.email}> has invited you to join the Fedora Project! We are a community of users and developers who produce a complete operating system from entirely free and open source software (FOSS). ${person.human_name} thinks that you have knowledge and skills diff --git a/fas/fas/templates/user/edit.html b/fas/fas/templates/user/edit.html index c79578b..af32575 100644 --- a/fas/fas/templates/user/edit.html +++ b/fas/fas/templates/user/edit.html @@ -17,8 +17,8 @@

- - + +
- -
-
- - - - -
-
- - ${_('Cancel')} -
- - - diff --git a/fas/fas/templates/user/email/edit.html b/fas/fas/templates/user/email/edit.html deleted file mode 100644 index 3ba8e3a..0000000 --- a/fas/fas/templates/user/email/edit.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - ${_('Edit Email')} - - -

${_('Edit Email')}

-
-
- ${email} - -
-
- - - - -
- -
- - diff --git a/fas/fas/templates/user/email/manage.html b/fas/fas/templates/user/email/manage.html deleted file mode 100644 index 96669a0..0000000 --- a/fas/fas/templates/user/email/manage.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - ${_('Manage Emails')} - - -

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

-

Available Emails

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

Set Emails

-
- - - - - - - - - - - - - - - -
${_('Email')}${_('Description')}${_('Purpose')}
- - ${purpose.person_email.description}${purpose.purpose}
-
- - diff --git a/fas/fas/templates/user/resetpass.html b/fas/fas/templates/user/resetpass.html index 232f04b..12c1a9e 100644 --- a/fas/fas/templates/user/resetpass.html +++ b/fas/fas/templates/user/resetpass.html @@ -11,7 +11,7 @@
    -
    +
diff --git a/fas/fas/templates/user/view.html b/fas/fas/templates/user/view.html index 4c0afd5..1920c38 100644 --- a/fas/fas/templates/user/view.html +++ b/fas/fas/templates/user/view.html @@ -19,7 +19,7 @@
${_('Account Name:')}
${person.username}
${_('Real Name:')}
${person.human_name}
-
${_('Email:')}
${person.emails['primary']}
+
${_('Email:')}
${person.email}
${_('IRC Nick:')}
${person.ircnick} 
${_('PGP Key:')}
${person.gpg_keyid} 
diff --git a/fas/fas/user.py b/fas/fas/user.py index b6c9f57..03b83cd 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -23,7 +23,6 @@ from fas.model import Log from fas import openssl_fas from fas.auth import * -#from fas.user_email import Email, NonFedoraEmail from random import Random import sha @@ -159,8 +158,6 @@ def generate_salt(length=8): class User(controllers.Controller): - #email = Email() - def __init__(self): '''Create a User Controller. ''' @@ -254,16 +251,11 @@ class User(controllers.Controller): return dict() try: target.human_name = human_name - # FIXME: WARNING! This is deceptive. Remember that it - # changes the email object itself, not the email attached - # to the purpose. - if not target.emails['primary'] == email: + if target.email != email: ''' Log this ''' - oldEmail = target.emails['primary'] + oldEmail = target.email Log(author_id=person.id, description='Email changed from %s to %s' % (oldEmail, email)) - target.emails['primary'] = email - -# target.emails['bugzilla'] = bugzilla + target.email = email target.ircnick = ircnick target.gpg_keyid = gpg_keyid target.telephone = telephone @@ -311,7 +303,7 @@ class User(controllers.Controller): people = People.query.filter(People.username.like(re_search)).order_by('username') emails = {} for person in people: - emails[person.username] = person.emails['primary'] + emails[person.username] = person.email return dict(emails=emails) @expose(template='fas.templates.user.new') @@ -334,26 +326,12 @@ class User(controllers.Controller): person.username = username person.human_name = human_name person.telephone = telephone + person.email = email person.password = '*' person.status = 'active' session.flush() - - # TODO: Handle properly if email has already been used. This might be painful, since the person already exists, at this point. - person_email = PersonEmails() - person_email.email = email - person_email.person = person - person_email.description = 'Fedora Email' - person_email.verified = True # The first email is verified for free, since this is where their password is sent. - session.flush() - - email_purpose = EmailPurposes() - email_purpose.person = person - email_purpose.person_email = person_email - email_purpose.purpose = 'primary' - session.flush() - newpass = generate_password() - message = turbomail.Message(config.get('accounts_email'), person.emails['primary'], _('Welcome to the Fedora Project!')) + message = turbomail.Message(config.get('accounts_email'), person.email, _('Welcome to the Fedora Project!')) message.plain = _(''' You have created a new Fedora account! Your new password is: %s @@ -436,6 +414,7 @@ forward to working with you! turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name) return dict() + #TODO: Validate @expose(template="fas.templates.user.resetpass") def sendpass(self, username, email, encrypted=False): import turbomail @@ -449,64 +428,59 @@ forward to working with you! except InvalidRequestError: turbogears.flash(_('Username email combo does not exist!')) turbogears.redirect('/user/resetpass') - if username and email: - if not email == person.emails['primary']: - turbogears.flash(_("username + email combo unknown.")) - return dict() - newpass = generate_password() - message = turbomail.Message(config.get('accounts_email'), email, _('Fedora Project Password Reset')) - mail = _(''' + if email != person.email: + turbogears.flash(_("username + email combo unknown.")) + return dict() + newpass = generate_password() + message = turbomail.Message(config.get('accounts_email'), email, _('Fedora Project Password Reset')) + mail = _(''' You have requested a password reset! Your new password is: %s Please go to https://admin.fedoraproject.org/fas/ to change it. ''') % newpass['pass'] - if encrypted: - # TODO: Move this out to a single function (same as - # CLA one), think of how to make sure this doesn't get - # full of random keys (keep a clean Fedora keyring) - # TODO: MIME stuff? - keyid = re.sub('\s', '', person.gpg_keyid) - ret = subprocess.call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', keyid]) - if ret != 0: - turbogears.flash(_("Your key could not be retrieved from subkeys.pgp.net")) - turbogears.redirect('/cla/view/sign') + if encrypted: + # TODO: Move this out to a single function (same as + # CLA one), think of how to make sure this doesn't get + # full of random keys (keep a clean Fedora keyring) + # TODO: MIME stuff? + keyid = re.sub('\s', '', person.gpg_keyid) + ret = subprocess.call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', keyid]) + if ret != 0: + turbogears.flash(_("Your key could not be retrieved from subkeys.pgp.net")) + turbogears.redirect('/user/resetpass') + return dict() + else: + try: + plaintext = StringIO.StringIO(mail) + ciphertext = StringIO.StringIO() + ctx = gpgme.Context() + ctx.armor = True + signer = ctx.get_key(re.sub('\s', '', config.get('gpg_fingerprint'))) + ctx.signers = [signer] + recipient = ctx.get_key(keyid) + def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd): + os.write(fd, '%s\n' % config.get('gpg_passphrase')) + ctx.passphrase_cb = passphrase_cb + ctx.encrypt_sign([recipient], + gpgme.ENCRYPT_ALWAYS_TRUST, + plaintext, + ciphertext) + message.plain = ciphertext.getvalue() + except: + turbogears.flash(_('Your password reset email could not be encrypted. Your password has not been changed.')) return dict() - #try: - # subprocess.check_call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', keyid]) - #except subprocess.CalledProcessError: - # turbogears.flash(_("Your key could not be retrieved from subkeys.pgp.net")) - else: - try: - plaintext = StringIO.StringIO(mail) - ciphertext = StringIO.StringIO() - ctx = gpgme.Context() - ctx.armor = True - signer = ctx.get_key(re.sub('\s', '', config.get('gpg_fingerprint'))) - ctx.signers = [signer] - recipient = ctx.get_key(keyid) - def passphrase_cb(uid_hint, passphrase_info, prev_was_bad, fd): - os.write(fd, '%s\n' % config.get('gpg_passphrase')) - ctx.passphrase_cb = passphrase_cb - ctx.encrypt_sign([recipient], - gpgme.ENCRYPT_ALWAYS_TRUST, - plaintext, - ciphertext) - message.plain = ciphertext.getvalue() - except: - turbogears.flash(_('Your password reset email could not be encrypted. Your password has not been changed.')) - return dict() - else: - message.plain = mail; - turbomail.enqueue(message) - try: - person.password = newpass['hash'] - turbogears.flash(_('Your new password has been emailed to you.')) - except: - turbogears.flash(_('Your password could not be reset.')) - else: - turbogears.redirect('/login') - return dict() + else: + message.plain = mail; + turbomail.enqueue(message) + try: + person.password = newpass['hash'] + turbogears.flash(_('Your new password has been emailed to you.')) + except: + turbogears.flash(_('Your password could not be reset.')) + else: + turbogears.redirect('/login') + return dict() @identity.require(turbogears.identity.not_anonymous()) @expose(template="genshi-text:fas.templates.user.cert", format="text", content_type='text/plain; charset=utf-8') @@ -533,7 +507,7 @@ Please go to https://admin.fedoraproject.org/fas/ to change it. O=config.get('openssl_o'), OU=config.get('openssl_ou'), CN=person.username, - emailAddress=person.emails['primary'], + emailAddress=person.email, ) cert = openssl_fas.createCertificate(req, (cacert, cakey), person.certificate_serial, (0, expire), digest='md5') diff --git a/fas/fas/user_email.py b/fas/fas/user_email.py deleted file mode 100644 index 7fdfa6b..0000000 --- a/fas/fas/user_email.py +++ /dev/null @@ -1,294 +0,0 @@ -import turbogears -from turbogears import controllers, expose, paginate, identity, redirect, widgets, validate, validators, error_handler, config -from turbogears.database import session -import cherrypy - -import turbomail -import random - -from fas.model import People -from fas.model import PersonEmails -from fas.model import EmailPurposes -from fas.model import Log - -from fas.auth import * - -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 EmailSave(validators.Schema): - email = validators.All( - validators.Email(not_empty=True, strip=True), - NonFedoraEmail(not_empty=True, strip=True), - ) - description = validators.String(not_empty=True, max=512) - -def generate_validtoken(length=32): - ''' Generate Validation Token ''' - chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - token = '' - for i in xrange(length): - token += random.choice(chars) - return token - -# Note: I'm making some of these controllers really, really hideous -# (in the interest of allowing admins to modify pretty much everything) -# Is this really necessary (as in, can tg-admin shell be "good enough?" -# (I'm pretty much referring to passing the username around every -# instead of just using the current logged on person.) - -# I hope all of this doesn't end up being too convoluted for most users... -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') - - - @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, targetname=None): - ''' - Manage a person's emails - ''' - # TODO: Some sort of auth checking - other people should - # probably be limited to looking at a person's email through - # /user/view, although admins should probably be able to set - # emails (with/without verification?) - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - return dict(target=target) - - @identity.require(turbogears.identity.not_anonymous()) - # TODO: Validate! - #@validate(validators=UserView()) - @error_handler(error) - @expose(template="fas.templates.user.email.edit") - # TODO: Should the purpose-setting part be moved in into user/save? - def edit(self, targetname, email): - ''' - Display the form to edit an email - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - return dict(email=email, target=target) - - @identity.require(turbogears.identity.not_anonymous()) - # TODO: Validate! - #@validate(validators=UserView()) - @error_handler(error) - @expose() - # TODO: Should the purpose-setting part be moved in into user/save? - def save(self, targetname, email, description): - ''' - Save an email entry - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - - try: - person.person_emails[email].description = description - except KeyError: - turbogears.flash(_('No such email is associated with your user.')) - turbogears.redirect('/user/email/manage') - return dict() - else: - turbogears.flash(_('Your email has been saved.')) - turbogears.redirect('/user/email/manage') - return dict() - - @identity.require(turbogears.identity.not_anonymous()) - # TODO: Validate! - #@validate(validators=UserView()) - @error_handler(error) - @expose(template="fas.templates.user.email.add") - def add(self, targetname=None): - ''' - Display the form to add an email - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - - return dict(target=target) - - @identity.require(turbogears.identity.not_anonymous()) - # TODO: Validate! - #@validate(validators=UserView()) - @error_handler(error) - @expose(allow_json=True) - def remove(self, targetname, email): - ''' - Remove an email - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - - try: - session.delete(target.person_emails[email]) - session.flush() - except IntegrityError: - turbogears.flash(_('You cannot delete an email that is in use.')) - turbogears.redirect('/user/email/manage') - return dict() - else: - turbogears.flash(_('The email \'%s\' has been removed.') % email ) - turbogears.redirect('/user/email/manage') - return dict() - - @identity.require(turbogears.identity.not_anonymous()) - @validate(validators=EmailSave()) - @error_handler(error) - @expose(template="fas.templates.user.email.add", allow_json=True) - def create(self, targetname, email, description): - ''' - Create an email entry. - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - - validtoken = generate_validtoken() - - try: - person_email = PersonEmails() - person_email.email = email - person_email.person = target - person_email.description = description - person_email.validtoken = validtoken - session.flush() - # Hmm, should this be checked in the validator or here? - except IntegrityError: - turbogears.flash(_('The email \'%s\' is already in used.') % email) - return dict(target=target) - else: - # TODO: Make this email more friendly. Maybe escape the @ in email too? - validurl = config.get('base_url_filter.base_url') + turbogears.url('/user/email/verify/%s/%s/%s') % (target.username, email, validtoken) - message = turbomail.Message(config.get('accounts_email'), email, _('Confirm this email address')) - message.plain = _(''' -Go to this URL to verify that you own this email address: %s -''') % validurl - turbomail.enqueue(message) - turbogears.flash(_('Your email has been added. Before you can use this email, you must verify it. The email you added should receive a message with instructions shortly.')) - turbogears.redirect('/user/email/manage') - return dict() - - return dict(target=target) - - @identity.require(turbogears.identity.not_anonymous()) - # TODO: Validation! - #@validate(validators=UserView()) - @error_handler(error) - @expose(allow_json=True) - def verify(self, targetname, email, validtoken): - ''' - Verify an email - ''' - username = turbogears.identity.current.user_name - person = People.by_username(username) - - if targetname: - target = People.by_username(targetname) - else: - target = person - - if not canEditUser(person, target): - turbogears.flash(_('You cannot edit %s') % target.username ) - turbogears.redirect('/user/email/manage') - return dict() - - if target.person_emails[email].verified: - turbogears.flash(_('The email provided has already been verified.')) - turbogears.redirect('/user/email/manage') - return dict() - - try: - if target.person_emails[email].validtoken == validtoken: - target.person_emails[email].validtoken = '' - target.person_emails[email].verified = True - turbogears.flash(_('Your email has been successfully verified.')) - turbogears.redirect('/user/email/manage') - return dict() - else: - turbogears.flash(_('The verification string did not match.')) - turbogears.redirect('/user/email/manage') - return dict() - except KeyError: - turbogears.flash(_('No such email is associated with your user.')) - turbogears.redirect('/user/email/manage') - return dict() -