Merge branch 'master' of ssh://git.fedorahosted.org/git/fedora-infrastructure

This commit is contained in:
Michael McGrath 2008-03-06 23:28:46 -06:00
commit 486f631b27
10 changed files with 203 additions and 41 deletions

View file

@ -1,14 +1,6 @@
Things to Fix in FAS2 before declaring it done
Things to Fix in FAS2 before declaring it done:
* fasClient.py: Proper logging
safasprovider.py
----------------
validate_password():
We'll want to change this to something that allows for longer passwords
(like md5). The one thing about that is we have to figure out how system
passwords use salt, etc. That way we'll be able to use this with
make_shell_accounts.
fasClient.py
---------------
Proper logging
Nice-to-have things:
* fas/group.py: Easy searching within groups (and sponsor/admin interface)

View file

@ -54,7 +54,7 @@ tg.strict_parameters = True
server.webpath='/accounts'
base_url_filter.on=True
base_url_filter.base_url = "https://publictest10.fedoraproject.org/accounts"
base_url_filter.base_url = "https://publictest10.fedoraproject.org"
# Make the session cookie only return to the host over an SSL link
# Disabled for testing.

View file

@ -314,7 +314,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(['group_email_purposes', 'group_email']).filter_by(email=email).one()
return cls.query.join(['email_purposes', 'group_email']).filter_by(email=email).one()
by_email_address = classmethod(by_email_address)
@ -423,15 +423,15 @@ 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)),
'approved_roles': relation(ApprovedRoles, backref='member',
primaryjoin = PeopleTable.c.id==ApprovedRoles.c.person_id),
'unapproved_roles': relation(UnApprovedRoles, backref='member',
primaryjoin = PeopleTable.c.id==UnApprovedRoles.c.person_id)
})
mapper(PersonEmails, PersonEmailsTable, properties = {
'person': relation(People, backref = 'person_emails', uselist = False,
primaryjoin = PeopleTable.c.id==PersonEmailsTable.c.person_id)
})
mapper(PersonEmails, PersonEmailsTable)
mapper(EmailPurposes, EmailPurposesTable, properties = {
'person_email': relation(PersonEmails, uselist = False,
primaryjoin = PersonEmailsTable.c.id==EmailPurposesTable.c.email_id)
@ -452,13 +452,13 @@ mapper(Groups, GroupsTable, properties = {
'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, properties = {
'group': relation(Groups, backref = 'group_emails', uselist = False,
primaryjoin = GroupsTable.c.id==GroupEmailsTable.c.group_id)
})
mapper(GroupEmails, GroupEmailsTable)
mapper(GroupEmailPurposes, GroupEmailPurposesTable, properties = {
'group_email': relation(GroupEmails, uselist = False,
primaryjoin = GroupEmailsTable.c.id==GroupEmailPurposesTable.c.email_id)

View file

@ -2,7 +2,7 @@
<h3>The Fedora Project
Individual Contributor License Agreement (CLA)
</h3>
<a href="http://www.fedora.redhat.com/licenses/">http://www.fedora.redhat.com/licenses/</a>
<a href="http://fedoraproject.org/wiki/Legal/Licenses/CLA">http://fedoraproject.org/wiki/Legal/Licenses/CLA</a>
<p>
Thank you for your interest in The Fedora Project (the "Project"). In order to clarify the intellectual property license granted with Contributions from any person or entity, Red hat, Inc. ("Red Hat"), as maintainer of the Project, must have a Contributor License Agreement (CLA) on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for Your protection as a Contributor as well as the protection of the Project and its users; it does not change your rights to use your own Contributions for any other purpose.
</p>

View file

@ -1,6 +1,6 @@
The Fedora Project
Individual Contributor License Agreement (CLA)
http://www.fedora.redhat.com/licenses/
http://fedoraproject.org/wiki/Legal/Licenses/CLA
Thank you for your interest in The Fedora Project (the
"Project"). In order to clarify the intellectual property license

View file

@ -0,0 +1,30 @@
<!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/save/%s' % target.username)}" method="post" enctype="multipart/form-data">
<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>

View file

@ -7,7 +7,7 @@
<title>${_('Manage Emails')}</title>
</head>
<body>
<h2>${_('Managing Emails for %s') % person.username}</h2>
<h2>${_('Managing Emails for %s') % target.username}</h2>
<h3>Available Emails</h3>
<table>
<thead>
@ -18,7 +18,7 @@
</tr>
</thead>
<tbody>
<tr py:for="email in person.person_emails">
<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>
@ -36,7 +36,7 @@
</tr>
</thead>
<tbody>
<tr py:for="purpose in person.email_purposes.values()">
<tr py:for="purpose in target.email_purposes.values()">
<td><a href="mailto:${purpose.email}">${purpose.email}</a></td>
<td>${purpose.person_email.description}</td>
<td>${purpose.purpose}</td>

View file

@ -3,6 +3,8 @@ from turbogears import controllers, expose, paginate, identity, redirect, widget
from turbogears.database import session
import cherrypy
import turbomail
import os
import re
import gpgme
@ -221,7 +223,8 @@ class User(controllers.Controller):
target = person
if not canEditUser(person, target):
turbogears.flash(_('You cannot edit %s') % target.username )
username = turbogears.identity.current.username
turbogears.redirect('/user/view/%s', target.username)
return dict()
return dict(target=target)
@identity.require(turbogears.identity.not_anonymous())
@ -236,7 +239,7 @@ class User(controllers.Controller):
if not canEditUser(person, target):
turbogears.flash(_("You do not have permission to edit '%s'") % target.username)
turbogears.redirect('/user/edit/%s', target.username)
turbogears.redirect('/user/view/%s', target.username)
return dict()
try:
target.human_name = human_name
@ -286,7 +289,6 @@ class User(controllers.Controller):
# Also, perhaps implement a timeout- delete account
# if the e-mail is not verified (i.e. the person changes
# their password) withing X days.
import turbomail
try:
person = People()
person.username = username
@ -296,6 +298,7 @@ class User(controllers.Controller):
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

View file

@ -3,11 +3,16 @@ from turbogears import controllers, expose, paginate, identity, redirect, widget
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):
@ -16,13 +21,20 @@ class NonFedoraEmail(validators.FancyValidator):
if value.endswith('@fedoraproject.org'):
raise validators.Invalid(_("To prevent email loops, your email address cannot be @fedoraproject.org."), value, state)
class EmailCreate(validators.Schema):
class EmailSave(validators.Schema):
email = validators.All(
validators.Email(not_empty=True, strip=True),
NonFedoraEmail(not_empty=True, strip=True),
)
#fedoraPersonBugzillaMail = validators.Email(strip=True)
postal_address = validators.String(max=512)
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
class Email(controllers.Controller):
@ -34,7 +46,7 @@ class Email(controllers.Controller):
def index(self):
'''Redirect to manage
'''
turbogears.redirect('/user/email/manage/%s' % turbogears.identity.current.user_name)
turbogears.redirect('/user/email/manage')
@expose(template="fas.templates.error")
@ -48,12 +60,135 @@ class Email(controllers.Controller):
#@validate(validators=UserView())
@error_handler(error)
@expose(template="fas.templates.user.email.manage", allow_json=True)
def manage(self, username=None):
def manage(self, targetname=None):
'''
Manage a person's emails.
Manage a person's emails
'''
if not username:
username = turbogears.identity.current.user_name
# 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)
return dict(person=person)
if targetname:
target = People.by_username(targetname)
else:
target = person
return dict(target=target)
@identity.require(turbogears.identity.not_anonymous())
#@validate(validators=UserView())
@error_handler(error)
@expose(template="fas.templates.user.email.add", allow_json=True)
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())
@validate(validators=EmailSave())
@error_handler(error)
@expose(template="fas.templates.user.email.add", allow_json=True)
def save(self, targetname, email, description):
'''
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()
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_mail'), 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.'))
return dict(target=target)
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()

View file

@ -71,11 +71,12 @@ cluster people_status_idx on people;
CREATE TABLE person_emails (
id serial primary key,
email text not null unique,
email text not null,
person_id INTEGER NOT NULL references people(id),
validtoken text,
description text,
verified boolean NOT NULL DEFAULT false
unique (email, verified) --You can't "claim" an email before you verify it first
);
create index person_emails_person_id_idx on person_emails(person_id);
@ -141,11 +142,12 @@ cluster groups_group_type_idx on groups;
--
CREATE TABLE group_emails (
id serial primary key,
email text not null unique,
email text not null,
group_id INTEGER NOT NULL references groups(id),
validtoken text,
description text,
verified boolean NOT NULL DEFAULT false
unique (email, verified) --You can't "claim" an email before you verify it first
);
create index group_emails_group_id_idx on group_emails(group_id);