Merge branch 'master' of ssh://git.fedorahosted.org/git/fedora-infrastructure
Fix conflicts in fas2.sql. Conflicts: fas/fas2.sql
This commit is contained in:
commit
4a7f7f6ef7
24 changed files with 373 additions and 2089 deletions
|
@ -436,7 +436,7 @@ class MakeShellAccounts(BaseClient):
|
||||||
|
|
||||||
def create_ssh_keys(self):
|
def create_ssh_keys(self):
|
||||||
''' Create ssh keys '''
|
''' Create ssh keys '''
|
||||||
home_base = config.get('users', 'home').strip('"')
|
home_base = prefix + config.get('users', 'home').strip('"')
|
||||||
for person in self.people:
|
for person in self.people:
|
||||||
username = person['username']
|
username = person['username']
|
||||||
if self.valid_user(username):
|
if self.valid_user(username):
|
||||||
|
|
|
@ -62,6 +62,7 @@ for person in c.fetchall():
|
||||||
p.internal_comments = internal_comments
|
p.internal_comments = internal_comments
|
||||||
p.ircnick = ircnick
|
p.ircnick = ircnick
|
||||||
p.status = 'active'
|
p.status = 'active'
|
||||||
|
p.email = email
|
||||||
try:
|
try:
|
||||||
session.flush()
|
session.flush()
|
||||||
except IntegrityError, e:
|
except IntegrityError, e:
|
||||||
|
@ -69,25 +70,6 @@ for person in c.fetchall():
|
||||||
session.close()
|
session.close()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
person_email = PersonEmails()
|
|
||||||
try:
|
|
||||||
person_email.email = email
|
|
||||||
except AttributeError:
|
|
||||||
print "\tERROR - Could not create email for %s (%s)" % (username, email)
|
|
||||||
session.close()
|
|
||||||
continue
|
|
||||||
person_email.person = p
|
|
||||||
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 = p
|
|
||||||
email_purpose.person_email = person_email
|
|
||||||
email_purpose.purpose = 'primary'
|
|
||||||
session.flush()
|
|
||||||
|
|
||||||
c.execute('select id, name, owner_id, group_type, needs_sponsor, user_can_remove, prerequisite_id, joinmsg from project_group;')
|
c.execute('select id, name, owner_id, group_type, needs_sponsor, user_can_remove, prerequisite_id, joinmsg from project_group;')
|
||||||
bool_dict = {0 : False, 1 : True}
|
bool_dict = {0 : False, 1 : True}
|
||||||
print "Creating Groups..."
|
print "Creating Groups..."
|
||||||
|
|
|
@ -135,7 +135,7 @@ class CLA(controllers.Controller):
|
||||||
emails = [];
|
emails = [];
|
||||||
for uid in key.uids:
|
for uid in key.uids:
|
||||||
emails.extend([uid.email])
|
emails.extend([uid.email])
|
||||||
if person.emails['primary'] in emails:
|
if person.email in emails:
|
||||||
verified = True
|
verified = True
|
||||||
else:
|
else:
|
||||||
turbogears.flash(_('Your key did not match your email.'))
|
turbogears.flash(_('Your key did not match your email.'))
|
||||||
|
@ -181,7 +181,7 @@ class CLA(controllers.Controller):
|
||||||
message.plain = '''
|
message.plain = '''
|
||||||
Fedora user %(username)s has signed a completed ICLA using their published GPG key, ID %(gpg_keyid)s,
|
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.
|
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()
|
signature.file.seek(0) # For another read()
|
||||||
message.attach(signature.file, signature.filename)
|
message.attach(signature.file, signature.filename)
|
||||||
turbomail.enqueue(message)
|
turbomail.enqueue(message)
|
||||||
|
|
|
@ -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.
|
membership for %(applicant)s (%(applicant_name)s) in the %(group)s group and needs a sponsor.
|
||||||
|
|
||||||
Please go to %(url)s to take action.
|
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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%(user)s has applied to %(group)s!') % \
|
turbogears.flash(_('%(user)s has applied to %(group)s!') % \
|
||||||
{'user': target.username, 'group': group.name})
|
{'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)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
else:
|
else:
|
||||||
import turbomail
|
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 = _('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has sponsored you for membership in the %(group)s
|
%(name)s <%(email)s> has sponsored you for membership in the %(group)s
|
||||||
group of the Fedora account system. If applicable, this change should
|
group of the Fedora account system. If applicable, this change should
|
||||||
propagate into the e-mail aliases and CVS repository within an hour.
|
propagate into the e-mail aliases and CVS repository within an hour.
|
||||||
|
|
||||||
%(joinmsg)s
|
%(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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_("'%s' has been sponsored!") % target.human_name)
|
turbogears.flash(_("'%s' has been sponsored!") % target.human_name)
|
||||||
turbogears.redirect('/group/view/%s' % group.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})
|
{'user': target.username, 'group': group.name, 'error': e})
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
else:
|
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 = _('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has removed you from the '%(group)s'
|
%(name)s <%(email)s> has removed you from the '%(group)s'
|
||||||
group of the Fedora Accounts System This change is effective
|
group of the Fedora Accounts System This change is effective
|
||||||
immediately for new operations, and should propagate into the e-mail
|
immediately for new operations, and should propagate into the e-mail
|
||||||
aliases within an hour.
|
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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%(name)s has been removed from %(group)s') % \
|
turbogears.flash(_('%(name)s has been removed from %(group)s') % \
|
||||||
{'name': target.username, 'group': group.name})
|
{'name': target.username, 'group': group.name})
|
||||||
|
@ -413,7 +413,7 @@ aliases within an hour.
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
else:
|
else:
|
||||||
import turbomail
|
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?
|
# Should we make person.upgrade return this?
|
||||||
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
||||||
status = role.role_type
|
status = role.role_type
|
||||||
|
@ -422,7 +422,7 @@ aliases within an hour.
|
||||||
'%(group)s' group of the Fedora Accounts System This change is
|
'%(group)s' group of the Fedora Accounts System This change is
|
||||||
effective immediately for new operations, and should propagate
|
effective immediately for new operations, and should propagate
|
||||||
into the e-mail aliases within an hour.
|
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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%s has been upgraded!') % target.username)
|
turbogears.flash(_('%s has been upgraded!') % target.username)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
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)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
else:
|
else:
|
||||||
import turbomail
|
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()
|
role = PersonRoles.query.filter_by(group=group, member=target).one()
|
||||||
status = role.role_type
|
status = role.role_type
|
||||||
message.plain = _('''
|
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
|
'%(group)s' group of the Fedora Accounts System This change is
|
||||||
effective immediately for new operations, and should propagate
|
effective immediately for new operations, and should propagate
|
||||||
into the e-mail aliases within an hour.
|
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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('%s has been downgraded!') % target.username)
|
turbogears.flash(_('%s has been downgraded!') % target.username)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
@ -504,7 +504,7 @@ into the e-mail aliases within an hour.
|
||||||
group = Groups.by_name(groupname)
|
group = Groups.by_name(groupname)
|
||||||
|
|
||||||
if isApproved(person, group):
|
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 = _('''
|
message.plain = _('''
|
||||||
%(name)s <%(email)s> has invited you to join the Fedora
|
%(name)s <%(email)s> has invited you to join the Fedora
|
||||||
Project! We are a community of users and developers who produce a
|
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
|
a people person. You'll grow and learn as you work on a team with other
|
||||||
very smart and talented people.
|
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)
|
turbomail.enqueue(message)
|
||||||
turbogears.flash(_('Message sent to: %s') % target)
|
turbogears.flash(_('Message sent to: %s') % target)
|
||||||
turbogears.redirect('/group/view/%s' % group.name)
|
turbogears.redirect('/group/view/%s' % group.name)
|
||||||
|
|
|
@ -4,10 +4,11 @@ from turbogears.database import session
|
||||||
|
|
||||||
from fas.auth import *
|
from fas.auth import *
|
||||||
|
|
||||||
|
# TODO: gettext like crazy.
|
||||||
class Help(controllers.Controller):
|
class Help(controllers.Controller):
|
||||||
help = { 'none' : ['Error', '<p>We could not find that help item</p>'],
|
help = { 'none' : ['Error', '<p>We could not find that help item</p>'],
|
||||||
'user_ircnick' : ['IRC Nick (Optional)', '<p>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</p>'],
|
'user_ircnick' : ['IRC Nick (Optional)', '<p>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</p>'],
|
||||||
'user_primary_email' : ['Primary Email (Required)', '<p>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</p>'],
|
'user_email' : ['Email (Required)', '<p>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</p>'],
|
||||||
'user_human_name' : ['Full Name (Required)', '<p>Your Human Name or "real life" name</p>'],
|
'user_human_name' : ['Full Name (Required)', '<p>Your Human Name or "real life" name</p>'],
|
||||||
'user_gpg_keyid' : ['GPG Key', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. 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 <a href="http://fedoraproject.org/wiki/Infrastructure/AccountSystem/CLAHowTo">CLAHowTo</a> for more information</p>'],
|
'user_gpg_keyid' : ['GPG Key', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. 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 <a href="http://fedoraproject.org/wiki/Infrastructure/AccountSystem/CLAHowTo">CLAHowTo</a> for more information</p>'],
|
||||||
'user_telephone' : ['Telephone', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. Sometimes during a time of emergency someone from the Fedora Project may need to contact you. For more information see our <a href="http://fedoraproject.org/wiki/Legal/PrivacyPolicy">Privacy Policy</a></p>'],
|
'user_telephone' : ['Telephone', '<p>Only required for users signing the <a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">CLA</a>. Sometimes during a time of emergency someone from the Fedora Project may need to contact you. For more information see our <a href="http://fedoraproject.org/wiki/Legal/PrivacyPolicy">Privacy Policy</a></p>'],
|
||||||
|
|
|
@ -56,14 +56,10 @@ get_engine()
|
||||||
#
|
#
|
||||||
|
|
||||||
PeopleTable = Table('people', metadata, autoload=True)
|
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)
|
PersonRolesTable = Table('person_roles', metadata, autoload=True)
|
||||||
|
|
||||||
ConfigsTable = Table('configs', metadata, autoload=True)
|
ConfigsTable = Table('configs', metadata, autoload=True)
|
||||||
GroupsTable = Table('groups', 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)
|
GroupRolesTable = Table('group_roles', metadata, autoload=True)
|
||||||
BugzillaQueueTable = Table('bugzilla_queue', metadata, autoload=True)
|
BugzillaQueueTable = Table('bugzilla_queue', metadata, autoload=True)
|
||||||
LogTable = Table('log', 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
|
A class method that can be used to search users
|
||||||
based on their email addresses since it is unique.
|
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
|
@classmethod
|
||||||
def by_username(cls, username):
|
def by_username(cls, username):
|
||||||
|
@ -250,8 +246,12 @@ class People(SABase):
|
||||||
if not identity.in_group('admin'):
|
if not identity.in_group('admin'):
|
||||||
# Only admins can see internal_comments
|
# Only admins can see internal_comments
|
||||||
del props['internal_comments']
|
del props['internal_comments']
|
||||||
|
del props['emailtoken']
|
||||||
if identity.current.anonymous:
|
if identity.current.anonymous:
|
||||||
# Anonymous users can't see any of these
|
# Anonymous users can't see any of these
|
||||||
|
del props['email']
|
||||||
|
del props['emailtoken']
|
||||||
|
del props['unverified_email']
|
||||||
del props['ssh_key']
|
del props['ssh_key']
|
||||||
del props['gpg_keyid']
|
del props['gpg_keyid']
|
||||||
del props['affiliation']
|
del props['affiliation']
|
||||||
|
@ -262,8 +262,10 @@ class People(SABase):
|
||||||
del props['postal_address']
|
del props['postal_address']
|
||||||
del props['telephone']
|
del props['telephone']
|
||||||
del props['facsimile']
|
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:
|
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
|
# Only an admin or the user themselves can see these fields
|
||||||
|
del props['unverified_email']
|
||||||
del props['password']
|
del props['password']
|
||||||
del props['passwordtoken']
|
del props['passwordtoken']
|
||||||
del props['postal_address']
|
del props['postal_address']
|
||||||
|
@ -277,19 +279,6 @@ class People(SABase):
|
||||||
approved_memberships = association_proxy('approved_roles', 'group')
|
approved_memberships = association_proxy('approved_roles', 'group')
|
||||||
unapproved_memberships = association_proxy('unapproved_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):
|
class PersonRoles(SABase):
|
||||||
'''Record people that are members of groups.'''
|
'''Record people that are members of groups.'''
|
||||||
def __repr__(cls):
|
def __repr__(cls):
|
||||||
|
@ -317,7 +306,7 @@ class Groups(SABase):
|
||||||
A class method that can be used to search groups
|
A class method that can be used to search groups
|
||||||
based on their email addresses since it is unique.
|
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
|
@classmethod
|
||||||
|
@ -338,21 +327,6 @@ class Groups(SABase):
|
||||||
# Groups that this group belongs to
|
# Groups that this group belongs to
|
||||||
memberships = association_proxy('group_roles', 'group')
|
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):
|
class GroupRoles(SABase):
|
||||||
'''Record groups that are members of other groups.'''
|
'''Record groups that are members of other groups.'''
|
||||||
pass
|
pass
|
||||||
|
@ -420,12 +394,6 @@ mapper(UnApprovedRoles, UnApprovedRolesSelect, properties = {
|
||||||
})
|
})
|
||||||
|
|
||||||
mapper(People, PeopleTable, 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.
|
# 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,
|
'group_roles': relation(PersonRoles,
|
||||||
collection_class = attribute_mapped_collection('groupname'),
|
collection_class = attribute_mapped_collection('groupname'),
|
||||||
|
@ -435,11 +403,6 @@ mapper(People, PeopleTable, properties = {
|
||||||
'unapproved_roles': relation(UnApprovedRoles, backref='member',
|
'unapproved_roles': relation(UnApprovedRoles, backref='member',
|
||||||
primaryjoin = PeopleTable.c.id==UnApprovedRoles.c.person_id)
|
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 = {
|
mapper(PersonRoles, PersonRolesTable, properties = {
|
||||||
'member': relation(People, backref = 'roles', lazy = False,
|
'member': relation(People, backref = 'roles', lazy = False,
|
||||||
primaryjoin=PersonRolesTable.c.person_id==PeopleTable.c.id),
|
primaryjoin=PersonRolesTable.c.person_id==PeopleTable.c.id),
|
||||||
|
@ -454,20 +417,9 @@ mapper(Configs, ConfigsTable, properties = {
|
||||||
mapper(Groups, GroupsTable, properties = {
|
mapper(Groups, GroupsTable, properties = {
|
||||||
'owner': relation(People, uselist=False,
|
'owner': relation(People, uselist=False,
|
||||||
primaryjoin = GroupsTable.c.owner_id==PeopleTable.c.id),
|
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,
|
'prerequisite': relation(Groups, uselist=False,
|
||||||
primaryjoin = GroupsTable.c.prerequisite_id==GroupsTable.c.id)
|
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
|
# GroupRoles are complex because the group is a member of a group and thus
|
||||||
# is referencing the same table.
|
# is referencing the same table.
|
||||||
mapper(GroupRoles, GroupRolesTable, properties = {
|
mapper(GroupRoles, GroupRolesTable, properties = {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Release information about the Fedora Accounts System
|
Release information about the Fedora Accounts System
|
||||||
'''
|
'''
|
||||||
|
|
||||||
VERSION = '0.1'
|
VERSION = '0.5'
|
||||||
NAME = 'fas'
|
NAME = 'fas'
|
||||||
DESCRIPTION = 'The Fedora Account System'
|
DESCRIPTION = 'The Fedora Account System'
|
||||||
LONG_DESCRIPTION = '''
|
LONG_DESCRIPTION = '''
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Full name: ${person.human_name}<br />
|
Full name: ${person.human_name}<br />
|
||||||
E-Mail: ${person.emails['primary']}<br />
|
E-Mail: ${person.email}<br />
|
||||||
Address: ${person.postal_address}<br />
|
Address: ${person.postal_address}<br />
|
||||||
Telephone: ${person.telephone}
|
Telephone: ${person.telephone}
|
||||||
<!-- Facsimile: ${person.facsimile} -->
|
<!-- Facsimile: ${person.facsimile} -->
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
fedora-legal@redhat.com. Please read this document carefully before
|
fedora-legal@redhat.com. Please read this document carefully before
|
||||||
signing and keep a copy for your records.
|
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:
|
Address:
|
||||||
${person.postal_address}
|
${person.postal_address}
|
||||||
|
@ -150,5 +150,5 @@ ${person.postal_address}
|
||||||
|
|
||||||
If you agree to these terms and conditions, type "I agree" here:
|
If you agree to these terms and conditions, type "I agree" here:
|
||||||
Enter your full name here:
|
Enter your full name here:
|
||||||
E-mail: ${person.emails['primary']}
|
E-mail: ${person.email}
|
||||||
Date: ${date}
|
Date: ${date}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div>
|
<div>
|
||||||
${_('If you agree to these terms and conditions, type "%s" here:') % 'I agree'} <input type="text" id="agree" name="agree" /><br />
|
${_('If you agree to these terms and conditions, type "%s" here:') % 'I agree'} <input type="text" id="agree" name="agree" /><br />
|
||||||
${_('Full Name:')} ${person.human_name}<br />
|
${_('Full Name:')} ${person.human_name}<br />
|
||||||
${_('E-mail:')} ${person.emails['primary']}<br />
|
${_('E-mail:')} ${person.email}<br />
|
||||||
${_('Date:')} ${date}<br />
|
${_('Date:')} ${date}<br />
|
||||||
<input type="submit" value="${_('Submit CLA')}" />
|
<input type="submit" value="${_('Submit CLA')}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#for role in sorted(group.approved_roles)
|
#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
|
#end
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
<div>
|
<div>
|
||||||
<!--TODO: Make the email translatable -->
|
<!--TODO: Make the email translatable -->
|
||||||
${_('To email:')} <input type="text" value="" name="target" /><br />
|
${_('To email:')} <input type="text" value="" name="target" /><br />
|
||||||
${_('From:')} ${person.emails['primary']}<br />
|
${_('From:')} ${person.email}<br />
|
||||||
${_('Subject:')} Invitation to join the Fedora Team!<br />
|
${_('Subject:')} Invitation to join the Fedora Team!<br />
|
||||||
${_('Message:')}
|
${_('Message:')}
|
||||||
<div class="message">
|
<div class="message">
|
||||||
<p>
|
<p>
|
||||||
${person.human_name} <<a href="mailto: ${person.emails['primary']}">${person.emails['primary']}</a>> has invited you to join the Fedora
|
${person.human_name} <<a href="mailto: ${person.email}">${person.email}</a>> has invited you to join the Fedora
|
||||||
Project! We are a community of users and developers who produce a
|
Project! We are a community of users and developers who produce a
|
||||||
complete operating system from entirely free and open source software
|
complete operating system from entirely free and open source software
|
||||||
(FOSS). ${person.human_name} thinks that you have knowledge and skills
|
(FOSS). ${person.human_name} thinks that you have knowledge and skills
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<!--Need to figure out what the interface should be for emails. -->
|
<!--Need to figure out what the interface should be for emails. -->
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="mail">${_('Email')}:</label>
|
<label for="mail">${_('Email')}:</label>
|
||||||
<input type="text" id="email" name="email" value="${target.emails['primary']}" />
|
<input type="text" id="email" name="email" value="${target.email}" />
|
||||||
<script type="text/javascript">var hb2 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/user_primary_email')}'});</script>
|
<script type="text/javascript">var hb2 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/user_email')}'});</script>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="field">
|
<!-- <div class="field">
|
||||||
<label for="fedoraPersonBugzillaMail">${_('Bugzilla Email')}:</label>
|
<label for="fedoraPersonBugzillaMail">${_('Bugzilla Email')}:</label>
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="../../master.html" />
|
|
||||||
<head>
|
|
||||||
<title>${_('Add Email')}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h2>${_('Add Email')}</h2>
|
|
||||||
<form action="${tg.url('/user/email/create/%s' % target.username)}" method="post">
|
|
||||||
<div class="field">
|
|
||||||
<label for="email">${_('Email:')}</label>
|
|
||||||
<input type="text" id="email" name="email" />
|
|
||||||
<!-- TODO: More generic documentation for adding an email -->
|
|
||||||
<script type="text/javascript">var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/user_primary_email')}'});</script>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label for="description">${_('Description:')}</label>
|
|
||||||
<input type="text" id="description" name="description" />
|
|
||||||
<!-- TODO: Correct documentation for this -->
|
|
||||||
<script type="text/javascript">var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/user_primary_email')}'});</script>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<input type="submit" value="${_('Save!')}" />
|
|
||||||
<a href="${tg.url('/user/email/manage')}">${_('Cancel')}</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,28 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="../../master.html" />
|
|
||||||
<head>
|
|
||||||
<title>${_('Edit Email')}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h2>${_('Edit Email')}</h2>
|
|
||||||
<form action="${tg.url('/user/email/save/%s' % target.username)}" method="post">
|
|
||||||
<div class="field">
|
|
||||||
<label for="email">${_('Email:')}</label> <span>${email}</span>
|
|
||||||
<input type="hidden" id="email" name="email" value="${email}" />
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label for="description">${_('Description:')}</label>
|
|
||||||
<input type="text" id="description" name="description" value="${target.person_emails[email].description}" />
|
|
||||||
<!-- TODO: Correct documentation for this -->
|
|
||||||
<script type="text/javascript">var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/user_primary_email')}'});</script>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<input type="submit" value="${_('Save!')}" />
|
|
||||||
<a href="${tg.url('/user/email/manage')}">${_('Cancel')}</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,56 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="../../master.html" />
|
|
||||||
<head>
|
|
||||||
<title>${_('Manage Emails')}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h2>${_('Managing Emails for %s') % target.username}</h2>
|
|
||||||
<h3>Available Emails</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>${_('Email')}</th>
|
|
||||||
<th>${_('Description')}</th>
|
|
||||||
<th>${_('Verified')}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr py:for="email in target.person_emails.values()">
|
|
||||||
<td><a href="mailto:${email.email}">${email.email}</a></td>
|
|
||||||
<td>${email.description}</td>
|
|
||||||
<td py:if="email.verified"><span class="approved">${_('Verified')}</span></td>
|
|
||||||
<td py:if="not email.verified"><span class="unapproved">${_('Unverified')}</span> (<a href="${tg.url('/email/verify')}">${_('Resend Verification')}</a>)</td>
|
|
||||||
<td py:if="len(target.person_emails) > 1"><a href="${tg.url('/user/email/remove/%s/%s') % (target.username, email.email)}">${_('Remove')}</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<h3>Set Emails</h3>
|
|
||||||
<form action="${tg.url('/user/email/map/%s' % target.username)}">
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>${_('Email')}</th>
|
|
||||||
<th>${_('Description')}</th>
|
|
||||||
<th>${_('Purpose')}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr py:for="purpose in target.email_purposes.values()">
|
|
||||||
<td>
|
|
||||||
<select id="email" name="email">
|
|
||||||
<py:for each="person_email in target.person_emails.values()">
|
|
||||||
<option py:if="person_email.verified" value="person_email.email" py:attrs="{'selected': purpose.email == person_email.email and 'selected' or None}">${person_email.email} (${person_email.description})</option>
|
|
||||||
</py:for>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>${purpose.person_email.description}</td>
|
|
||||||
<td>${purpose.purpose}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -11,7 +11,7 @@
|
||||||
<form action="${tg.url('/user/sendpass')}" method="post">
|
<form action="${tg.url('/user/sendpass')}" method="post">
|
||||||
<ul>
|
<ul>
|
||||||
<div class="field"><label for="username">${_('Username:')}</label> <input type="text" id="username" name="username" /></div>
|
<div class="field"><label for="username">${_('Username:')}</label> <input type="text" id="username" name="username" /></div>
|
||||||
<div class="field"><label for="email">${_('Primary Email:')}</label> <input type="text" id="email" name="email" /></div>
|
<div class="field"><label for="email">${_('Email:')}</label> <input type="text" id="email" name="email" /></div>
|
||||||
<div class="field"><input type="checkbox" id="encrypted" name="encrypted" /> <label style="width: auto; float: none; margin-left: 1ex;" for="encrypted">${_('Encrypt/Sign password reset email')}</label></div>
|
<div class="field"><input type="checkbox" id="encrypted" name="encrypted" /> <label style="width: auto; float: none; margin-left: 1ex;" for="encrypted">${_('Encrypt/Sign password reset email')}</label></div>
|
||||||
<div class="field"><input type="submit" value="${_('Reset Password')}" /></div>
|
<div class="field"><input type="submit" value="${_('Reset Password')}" /></div>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<dl>
|
<dl>
|
||||||
<dt>${_('Account Name:')}</dt><dd>${person.username}</dd>
|
<dt>${_('Account Name:')}</dt><dd>${person.username}</dd>
|
||||||
<dt>${_('Real Name:')}</dt><dd>${person.human_name}</dd>
|
<dt>${_('Real Name:')}</dt><dd>${person.human_name}</dd>
|
||||||
<dt>${_('Email:')}</dt><dd>${person.emails['primary']}</dd>
|
<dt>${_('Email:')}</dt><dd>${person.email}</dd>
|
||||||
<!--<dt>${_('Bugzilla Email:')}</dt><dd>${person.username}</dd>-->
|
<!--<dt>${_('Bugzilla Email:')}</dt><dd>${person.username}</dd>-->
|
||||||
<dt>${_('IRC Nick:')}</dt><dd>${person.ircnick} </dd>
|
<dt>${_('IRC Nick:')}</dt><dd>${person.ircnick} </dd>
|
||||||
<dt>${_('PGP Key:')}</dt><dd>${person.gpg_keyid} </dd>
|
<dt>${_('PGP Key:')}</dt><dd>${person.gpg_keyid} </dd>
|
||||||
|
|
|
@ -17,13 +17,10 @@ import subprocess
|
||||||
from OpenSSL import crypto
|
from OpenSSL import crypto
|
||||||
|
|
||||||
from fas.model import People
|
from fas.model import People
|
||||||
from fas.model import PersonEmails
|
|
||||||
from fas.model import EmailPurposes
|
|
||||||
from fas.model import Log
|
from fas.model import Log
|
||||||
|
|
||||||
from fas import openssl_fas
|
from fas import openssl_fas
|
||||||
from fas.auth import *
|
from fas.auth import *
|
||||||
#from fas.user_email import Email, NonFedoraEmail
|
|
||||||
|
|
||||||
from random import Random
|
from random import Random
|
||||||
import sha
|
import sha
|
||||||
|
@ -159,8 +156,6 @@ def generate_salt(length=8):
|
||||||
|
|
||||||
class User(controllers.Controller):
|
class User(controllers.Controller):
|
||||||
|
|
||||||
#email = Email()
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
'''Create a User Controller.
|
'''Create a User Controller.
|
||||||
'''
|
'''
|
||||||
|
@ -254,16 +249,11 @@ class User(controllers.Controller):
|
||||||
return dict()
|
return dict()
|
||||||
try:
|
try:
|
||||||
target.human_name = human_name
|
target.human_name = human_name
|
||||||
# FIXME: WARNING! This is deceptive. Remember that it
|
if target.email != email:
|
||||||
# changes the email object itself, not the email attached
|
|
||||||
# to the purpose.
|
|
||||||
if not target.emails['primary'] == email:
|
|
||||||
''' Log this '''
|
''' Log this '''
|
||||||
oldEmail = target.emails['primary']
|
oldEmail = target.email
|
||||||
Log(author_id=person.id, description='Email changed from %s to %s' % (oldEmail, email))
|
Log(author_id=person.id, description='Email changed from %s to %s' % (oldEmail, email))
|
||||||
target.emails['primary'] = email
|
target.email = email
|
||||||
|
|
||||||
# target.emails['bugzilla'] = bugzilla
|
|
||||||
target.ircnick = ircnick
|
target.ircnick = ircnick
|
||||||
target.gpg_keyid = gpg_keyid
|
target.gpg_keyid = gpg_keyid
|
||||||
target.telephone = telephone
|
target.telephone = telephone
|
||||||
|
@ -311,7 +301,7 @@ class User(controllers.Controller):
|
||||||
people = People.query.filter(People.username.like(re_search)).order_by('username')
|
people = People.query.filter(People.username.like(re_search)).order_by('username')
|
||||||
emails = {}
|
emails = {}
|
||||||
for person in people:
|
for person in people:
|
||||||
emails[person.username] = person.emails['primary']
|
emails[person.username] = person.email
|
||||||
return dict(emails=emails)
|
return dict(emails=emails)
|
||||||
|
|
||||||
@expose(template='fas.templates.user.new')
|
@expose(template='fas.templates.user.new')
|
||||||
|
@ -334,26 +324,12 @@ class User(controllers.Controller):
|
||||||
person.username = username
|
person.username = username
|
||||||
person.human_name = human_name
|
person.human_name = human_name
|
||||||
person.telephone = telephone
|
person.telephone = telephone
|
||||||
|
person.email = email
|
||||||
person.password = '*'
|
person.password = '*'
|
||||||
person.status = 'active'
|
person.status = 'active'
|
||||||
session.flush()
|
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()
|
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 = _('''
|
message.plain = _('''
|
||||||
You have created a new Fedora account!
|
You have created a new Fedora account!
|
||||||
Your new password is: %s
|
Your new password is: %s
|
||||||
|
@ -436,6 +412,7 @@ forward to working with you!
|
||||||
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
#TODO: Validate
|
||||||
@expose(template="fas.templates.user.resetpass")
|
@expose(template="fas.templates.user.resetpass")
|
||||||
def sendpass(self, username, email, encrypted=False):
|
def sendpass(self, username, email, encrypted=False):
|
||||||
import turbomail
|
import turbomail
|
||||||
|
@ -449,8 +426,7 @@ forward to working with you!
|
||||||
except InvalidRequestError:
|
except InvalidRequestError:
|
||||||
turbogears.flash(_('Username email combo does not exist!'))
|
turbogears.flash(_('Username email combo does not exist!'))
|
||||||
turbogears.redirect('/user/resetpass')
|
turbogears.redirect('/user/resetpass')
|
||||||
if username and email:
|
if email != person.email:
|
||||||
if not email == person.emails['primary']:
|
|
||||||
turbogears.flash(_("username + email combo unknown."))
|
turbogears.flash(_("username + email combo unknown."))
|
||||||
return dict()
|
return dict()
|
||||||
newpass = generate_password()
|
newpass = generate_password()
|
||||||
|
@ -470,12 +446,8 @@ Please go to https://admin.fedoraproject.org/fas/ to change it.
|
||||||
ret = subprocess.call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', keyid])
|
ret = subprocess.call([config.get('gpgexec'), '--keyserver', config.get('gpg_keyserver'), '--recv-keys', keyid])
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
turbogears.flash(_("Your key could not be retrieved from subkeys.pgp.net"))
|
turbogears.flash(_("Your key could not be retrieved from subkeys.pgp.net"))
|
||||||
turbogears.redirect('/cla/view/sign')
|
turbogears.redirect('/user/resetpass')
|
||||||
return dict()
|
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:
|
else:
|
||||||
try:
|
try:
|
||||||
plaintext = StringIO.StringIO(mail)
|
plaintext = StringIO.StringIO(mail)
|
||||||
|
@ -502,10 +474,10 @@ Please go to https://admin.fedoraproject.org/fas/ to change it.
|
||||||
try:
|
try:
|
||||||
person.password = newpass['hash']
|
person.password = newpass['hash']
|
||||||
turbogears.flash(_('Your new password has been emailed to you.'))
|
turbogears.flash(_('Your new password has been emailed to you.'))
|
||||||
|
turbogears.redirect('/login')
|
||||||
|
return dict()
|
||||||
except:
|
except:
|
||||||
turbogears.flash(_('Your password could not be reset.'))
|
turbogears.flash(_('Your password could not be reset.'))
|
||||||
else:
|
|
||||||
turbogears.redirect('/login')
|
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
@identity.require(turbogears.identity.not_anonymous())
|
@identity.require(turbogears.identity.not_anonymous())
|
||||||
|
@ -533,7 +505,7 @@ Please go to https://admin.fedoraproject.org/fas/ to change it.
|
||||||
O=config.get('openssl_o'),
|
O=config.get('openssl_o'),
|
||||||
OU=config.get('openssl_ou'),
|
OU=config.get('openssl_ou'),
|
||||||
CN=person.username,
|
CN=person.username,
|
||||||
emailAddress=person.emails['primary'],
|
emailAddress=person.email,
|
||||||
)
|
)
|
||||||
|
|
||||||
cert = openssl_fas.createCertificate(req, (cacert, cakey), person.certificate_serial, (0, expire), digest='md5')
|
cert = openssl_fas.createCertificate(req, (cacert, cakey), person.certificate_serial, (0, expire), digest='md5')
|
||||||
|
|
|
@ -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()
|
|
||||||
|
|
10
fas/fas2.sql
10
fas/fas2.sql
|
@ -257,7 +257,7 @@ create or replace function bugzilla_sync() returns trigger as $bz_sync$
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Retrieve the bugzilla email address
|
# Retrieve the bugzilla email address
|
||||||
### FIXME: Once we implement it, we'll want to add a check for an email
|
### FIXME: Once we implement it, we will want to add a check for an email
|
||||||
# address in configs::application='bugzilla',person_id=person_id,
|
# address in configs::application='bugzilla',person_id=person_id,
|
||||||
# attribute='login'
|
# attribute='login'
|
||||||
plan = plpy.prepare("select email from people where id = $1", ('int4',))
|
plan = plpy.prepare("select email from people where id = $1", ('int4',))
|
||||||
|
@ -575,10 +575,10 @@ create trigger role_bugzilla_sync before update or insert or delete
|
||||||
-- for each row execute procedure bugzilla_sync_email();
|
-- for each row execute procedure bugzilla_sync_email();
|
||||||
|
|
||||||
-- For Fas to connect to the database
|
-- For Fas to connect to the database
|
||||||
GRANT ALL ON TABLE people, groups, person_roles, person_emails, email_purposes, group_roles, group_emails, group_email_purposes, bugzilla_queue, configs, person_seq, visit, visit_identity, log, log_id_seq, TO GROUP fedora;
|
GRANT ALL ON TABLE people, groups, person_roles, group_roles, bugzilla_queue, configs, person_seq, visit, visit_identity, log, log_id_seq, person_emails_id_seq, group_emails_id_seq TO GROUP fedora;
|
||||||
|
|
||||||
-- Create default admin user - Default Password "admin"
|
-- Create default admin user - Default Password "admin"
|
||||||
INSERT INTO people (id, username, human_name, password) VALUES (100001, 'admin', 'Admin User', '$1$djFfnacd$b6NFqFlac743Lb4sKWXj4/');
|
INSERT INTO people (id, username, human_name, password, email) VALUES (100001, 'admin', 'Admin User', '$1$djFfnacd$b6NFqFlac743Lb4sKWXj4/', 'root@localhost');
|
||||||
|
|
||||||
-- Create default groups and populate
|
-- Create default groups and populate
|
||||||
INSERT INTO groups (id, name, display_name, owner_id, group_type) VALUES (100002, 'cla_sign', 'Signed CLA Group', (SELECT id from people where username='admin'), 'tracking');
|
INSERT INTO groups (id, name, display_name, owner_id, group_type) VALUES (100002, 'cla_sign', 'Signed CLA Group', (SELECT id from people where username='admin'), 'tracking');
|
||||||
|
@ -589,7 +589,3 @@ INSERT INTO groups (name, display_name, owner_id, group_type) VALUES ('fas-syste
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO person_roles (person_id, group_id, role_type, role_status, internal_comments, sponsor_id) VALUES ((SELECT id from people where username='admin'), (select id from groups where name='accounts'), 'administrator', 'approved', 'created at install time', (SELECT id from people where username='admin'));
|
INSERT INTO person_roles (person_id, group_id, role_type, role_status, internal_comments, sponsor_id) VALUES ((SELECT id from people where username='admin'), (select id from groups where name='accounts'), 'administrator', 'approved', 'created at install time', (SELECT id from people where username='admin'));
|
||||||
|
|
||||||
-- Give admin user his email address
|
|
||||||
INSERT INTO person_emails (email, person_id, verified) VALUES ('root@localhost', (SELECT id from people where username='admin'), true);
|
|
||||||
INSERT INTO email_purposes (email_id, person_id, purpose) VALUES ((SELECT id from person_emails where email='root@localhost'), (SELECT id from people where username='admin'), 'primary');
|
|
||||||
|
|
527
fas/po/fas.pot
527
fas/po/fas.pot
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue