From c021c547b7a42d6bd8367c91aabf95981fd9e720 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 19:22:40 -0400 Subject: [PATCH 1/9] Disable email controller for now. We should talk to somebody about interface before I turn it into a hideous monster :) --- fas/fas/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fas/fas/user.py b/fas/fas/user.py index 72b1bee..09648cc 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -19,7 +19,7 @@ from fas.model import EmailPurposes from fas.model import Log from fas.auth import * -from fas.user_email import Email, NonFedoraEmail +#from fas.user_email import Email, NonFedoraEmail from random import Random import sha @@ -148,7 +148,7 @@ def generate_salt(length=8): class User(controllers.Controller): - email = Email() + #email = Email() def __init__(self): '''Create a User Controller. From 2e7a2e643d0200d9cb0e508b85ae2b6abc86e4ec Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 19:32:39 -0400 Subject: [PATCH 2/9] Move NonFedoraEmail back to user.py, enable email validation for edit form too. --- fas/fas/user.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/fas/fas/user.py b/fas/fas/user.py index 09648cc..089f12f 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -25,7 +25,6 @@ from random import Random import sha from base64 import b64encode - class KnownUser(validators.FancyValidator): '''Make sure that a user already exists''' def _to_python(self, value, state): @@ -50,6 +49,14 @@ class UnknownUser(validators.FancyValidator): raise validators.Invalid(_("'%s' already exists.") % value, value, state) +class NonFedoraEmail(validators.FancyValidator): + '''Make sure that an email address is not @fedoraproject.org''' + def _to_python(self, value, state): + return value.strip() + def validate_python(self, value, state): + if value.endswith('@fedoraproject.org'): + raise validators.Invalid(_("To prevent email loops, your email address cannot be @fedoraproject.org."), value, state) + class ValidSSHKey(validators.FancyValidator): ''' Make sure the ssh key uploaded is valid ''' def _to_python(self, value, state): @@ -84,10 +91,10 @@ class UserSave(validators.Schema): validators.Regex(regex='^[^\n:<>]+$'), ) ssh_key = ValidSSHKey(max=5000) - #mail = validators.All( - # validators.Email(not_empty=True, strip=True, max=128), - # NonFedoraEmail(not_empty=True, strip=True, max=128), - #) + email = validators.All( + validators.Email(not_empty=True, strip=True, max=128), + NonFedoraEmail(not_empty=True, strip=True, max=128), + ) #fedoraPersonBugzillaMail = validators.Email(strip=True, max=128) #fedoraPersonKeyId- Save this one for later :) postal_address = validators.String(max=512) @@ -323,7 +330,7 @@ class User(controllers.Controller): session.flush() newpass = generate_password() - message = turbomail.Message(config.get('accounts_mail'), person.emails['primary'], _('Welcome to the Fedora Project!')) + message = turbomail.Message(config.get('accounts_email'), person.emails['primary'], _('Welcome to the Fedora Project!')) message.plain = _(''' You have created a new Fedora account! Your new password is: %s @@ -424,7 +431,7 @@ forward to working with you! turbogears.flash(_("username + email combo unknown.")) return dict() newpass = generate_password() - message = turbomail.Message(config.get('accounts_mail'), email, _('Fedora Project Password Reset')) + message = turbomail.Message(config.get('accounts_email'), email, _('Fedora Project Password Reset')) mail = _(''' You have requested a password reset! Your new password is: %s From b88082e238c5b87c0eb6c8f45a2ee23e1291d119 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 20:26:43 -0400 Subject: [PATCH 3/9] Add code to send CLA emails. --- fas/dev.cfg | 5 +++-- fas/fas/cla.py | 10 +++++++++- fas/fas/config/app.cfg | 11 ++++++++--- fas/fas/group.py | 15 +++++++-------- fas/fas/user_email.py | 2 +- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/fas/dev.cfg b/fas/dev.cfg index 1347860..e1ee1d7 100644 --- a/fas/dev.cfg +++ b/fas/dev.cfg @@ -53,8 +53,9 @@ autoreload.package="fas" tg.strict_parameters = True server.webpath='/accounts' -base_url_filter.on=True -base_url_filter.base_url = "https://publictest10.fedoraproject.org" +base_url_filter.on = True +base_url_filter.use_x_forwarded_host = True +base_url_filter.base_url = "http://localhost/accounts" # Make the session cookie only return to the host over an SSL link # Disabled for testing. diff --git a/fas/fas/cla.py b/fas/fas/cla.py index 46c4694..8782df6 100644 --- a/fas/fas/cla.py +++ b/fas/fas/cla.py @@ -9,6 +9,7 @@ import re import gpgme import StringIO import subprocess +import turbomail from fas.auth import * @@ -176,7 +177,14 @@ class CLA(controllers.Controller): person.remove(cilckgroup, person) except: pass - # TODO: Email legal-cla-archive@fedoraproject.org + message = turbomail.Message(config.get('accounts_email'), config.get('legal_cla_email'), 'Fedora ICLA completed') + 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']} + signature.file.seek(0) # For another read() + message.attach(signature.file, signature.filename) + turbomail.enqueue(message) turbogears.flash(_("You have successfully signed the CLA. You are now in the '%s' group.") % group.name) turbogears.redirect('/cla/') return dict() diff --git a/fas/fas/config/app.cfg b/fas/fas/config/app.cfg index 87c6abf..0e7f69d 100644 --- a/fas/fas/config/app.cfg +++ b/fas/fas/config/app.cfg @@ -153,9 +153,14 @@ identity.saprovider.model.group="fas.model.Groups" # identity.saprovider.encryption_algorithm=None -accounts_mail = "accounts@fedoraproject.org" -#email_host = "fedoraproject.org" -email_host = "publictest10.fedoraproject.org" +# CHANGE ME: +accounts_email = "nobody@fedoraproject.org" +#accounts_email = "accounts@fedoraproject.org" +legal_cla_email = "nobody@fedoraproject.org" +#legal_cla_email = "legal-cla-archive@fedoraproject.org" + +#email_host = "bastion.fedora.phx.redhat.com" +email_host = "localhost" gpgexec = "/usr/bin/gpg" gpghome = "/srv/fedora-infrastructure/fas/gnupg" diff --git a/fas/fas/group.py b/fas/fas/group.py index 19c1285..909a070 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -9,6 +9,7 @@ from fas.auth import * from fas.user import KnownUser import re +import turbomail class KnownGroup(validators.FancyValidator): '''Make sure that a group already exists''' @@ -287,11 +288,10 @@ class Group(controllers.Controller): {'user': target.username, 'group': group.name, 'error': e}) turbogears.redirect('/group/view/%s' % group.name) else: - import turbomail # TODO: How do we handle gettext calls for these kinds of emails? # TODO: CC to right place, put a bit more thought into how to most elegantly do this # TODO: Maybe that @fedoraproject.org (and even -sponsors) should be configurable somewhere? - message = turbomail.Message(config.get('accounts_mail'), '%(group)s-sponsors@%(host)s' % {'group': group.name, 'host': config.get('email_host')}, \ + message = turbomail.Message(config.get('accounts_email'), '%(group)s-sponsors@%(host)s' % {'group': group.name, 'host': config.get('email_host')}, \ "Fedora '%(group)s' sponsor needed for %(user)s" % {'user': target.username, 'group': group.name}) url = config.get('base_url_filter.base_url') + turbogears.url('/group/edit/%s' % groupname) @@ -331,7 +331,7 @@ Please go to %(url)s to take action. turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'], "Your Fedora '%s' membership has been sponsored" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "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 @@ -357,7 +357,7 @@ propagate into the e-mail aliases and CVS repository within an hour. group = Groups.by_name(groupname) if not canRemoveUser(person, group, target): - turbogears.flash(_("You cannot remove '%s'.") % target.username) + turbogears.flash(_("You cannot remove '%(user)s' from '%(group)s'.") % {'user': target.username, 'group': group.name}) turbogears.redirect('/group/view/%s' % group.name) return dict() else: @@ -368,8 +368,7 @@ 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: - import turbomail - message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'], "Your Fedora '%s' membership has been removed" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "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 @@ -406,7 +405,7 @@ aliases within an hour. turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'], "Your Fedora '%s' membership has been upgraded" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "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 @@ -445,7 +444,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_mail'), target.emails['primary'], "Your Fedora '%s' membership has been downgraded" % group.name) + message = turbomail.Message(config.get('accounts_email'), target.emails['primary'], "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 = _(''' diff --git a/fas/fas/user_email.py b/fas/fas/user_email.py index 5d4c89c..7fdfa6b 100644 --- a/fas/fas/user_email.py +++ b/fas/fas/user_email.py @@ -238,7 +238,7 @@ class Email(controllers.Controller): 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 = 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 From d2f0409f9e56c3b8df919e95bd787209967d2000 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 20:31:05 -0400 Subject: [PATCH 4/9] Wow, I didn't know that you could break stuff like this :) --- fas/dev.cfg | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fas/dev.cfg b/fas/dev.cfg index e1ee1d7..219aa9e 100644 --- a/fas/dev.cfg +++ b/fas/dev.cfg @@ -3,9 +3,6 @@ # Settings that are the same for both development and production # (such as template engine, encodings, etc.) all go in # fas/config/app.cfg -#mail.on = True -#mail.server = 'bastion.fedora.phx.redhat.com' -#base_url_filter.base_url = "http://192.168.2.101:8080" mail.on = True mail.server = 'localhost' @@ -13,8 +10,6 @@ mail.server = 'localhost' mail.debug = False mail.encoding = 'utf-8' -base_url_filter.use_x_forwarded_host = True - # DATABASE # pick the form for your database From 34fd2fb295c117c7d1705133f101dea00c66fa53 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Sun, 9 Mar 2008 19:31:17 -0500 Subject: [PATCH 5/9] Aliases now work. they work a little differently then previous though I don't think it will cause any problems as long as groupName-members remains intact, which it does. --- fas/client/fasClient.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fas/client/fasClient.py b/fas/client/fasClient.py index edf2b0d..e8d42df 100755 --- a/fas/client/fasClient.py +++ b/fas/client/fasClient.py @@ -201,7 +201,7 @@ class MakeShellAccounts(BaseClient): return '/sbin/nologin' def install_aliases_txt(self): - move(self.temp + '/aliases', '/tmp/aliases') + move(self.temp + '/aliases', '/etc/aliases') def passwd_text(self, people=None): i = 0 @@ -397,15 +397,21 @@ class MakeShellAccounts(BaseClient): for group in self.groups: name = group['name'] members = {} + members['member'] = [] for membership in self.memberships[name]: role_type = membership['role_type'] person = usernames[membership['person_id']] + if role_type == 'user': + ''' Legacy support ''' + members['member'].append(person) + continue + members['member'].append(person) try: members[role_type].append(person) except KeyError: members[role_type] = [person] for role in members: - print "%s-%s: %s" % (name, role, members[role]) + email_file.write("%s-%ss: %s\n" % (name, role, ','.join(members[role]))) email_file.close() def enable(): From e5a2dbda088cb5b502dbd7151324ab6ff4773b9e Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 20:37:22 -0400 Subject: [PATCH 6/9] Add note to user.py. --- fas/fas/user.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fas/fas/user.py b/fas/fas/user.py index 089f12f..08b0ffc 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -250,6 +250,9 @@ 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. target.emails['primary'] = email # target.emails['bugzilla'] = bugzilla target.ircnick = ircnick From 74b9fe869de88fe7f55ca1aa4d5af2f519da11bd Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 20:54:55 -0400 Subject: [PATCH 7/9] Remove take out a few extra calls in group view and prettify a bit. --- fas/fas/templates/group/view.html | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index 416139d..923a6ff 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -13,6 +13,8 @@ import pytz person = People.by_username(tg.identity.user.username) timezone = pytz.timezone(person.timezone) + can_admin = auth.canAdminGroup(person, group) + can_sponsor = auth.canSponsorGroup(person, group) ?>

${group.display_name} (${group.name})

@@ -29,7 +31,7 @@ ${_('Remove me')} -

Group Details ${_('(edit)')}

+

Group Details ${_('(edit)')}

${_('Name:')}
${group.name} 
@@ -49,14 +51,16 @@
${group.prerequisite.name} 
 
${_('Created:')}
${group.creation} 
-
${_('Add User:')}
-
+ +
${_('Add User:')}
+
+
- +
    -
  • - ${_('Sponsor')} - - ${_('Approve')} - +
  • + + ${_('Sponsor')} + + + + ${_('Approve')} + +
  • ${_('Remove')} From b75d949500872b6438cb24596353e5ec891a1258 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 21:05:28 -0400 Subject: [PATCH 8/9] Fix bad markup. --- fas/dev.cfg | 2 +- fas/fas/templates/group/view.html | 6 +- fas/fas2.sql | 118 +++++++++++++++--------------- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/fas/dev.cfg b/fas/dev.cfg index 219aa9e..a727262 100644 --- a/fas/dev.cfg +++ b/fas/dev.cfg @@ -20,7 +20,7 @@ mail.encoding = 'utf-8' # If you have sqlite, here's a simple default to get you started # in development sqlalchemy.dburi="postgres://fedora:bunbunbun@localhost/fas2" - +sqlalchemy.echo=True # if you are using a database or table type without transactions # (MySQL default, for example), you should turn off transactions diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index 923a6ff..747f988 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -4,7 +4,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude"> - ${_('Edit Group')} + ${_('View Group')} var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/group_sponsor')}'}); - ${_('Approve')} - + ${_('Approve')} +
  • diff --git a/fas/fas2.sql b/fas/fas2.sql index 9236aac..d92f887 100644 --- a/fas/fas2.sql +++ b/fas/fas2.sql @@ -282,65 +282,65 @@ create table visit_identity ( -- -- When a person's fedorabugs role is updated, add them to bugzilla queue. -- -create or replace function bugzilla_sync() returns trigger as $bz_sync$ - # Decide which row we are operating on and the action to take - if TD['event'] == 'DELETE': - # 'r' for removing an entry from bugzilla - newaction = 'r' - row = TD['old'] - else: - # insert or update - row = TD['new'] - if row['role_status'] == 'approved': - # approved so add an entry to bugzilla - newaction = 'a' - else: - # no longer approved so remove the entry from bugzilla - newaction = 'r' - - # Get the group id for fedorabugs - result = plpy.execute("select id from groups where name = 'fedorabugs'", 1) - if not result: - # Danger Will Robinson! A basic FAS group does not exist! - plpy.error('Basic FAS group fedorabugs does not exist') - # If this is not a fedorabugs role, no change needed - if row['group_id'] != result[0]['id']: - return None - - # Retrieve the bugzilla email address - plan = plpy.prepare("select email, purpose from person_emails as pee," - " email_purposes as epu" - " where epu.id = epu.email_id and pee.person_id = $1" - " and purpose in ('bugzilla', 'primary')", - ('text',)) - result = plpy.execute(plan, row['person_id']) - email = None - for record in result: - email = record['email'] - if record['purpose'] == 'bugzilla': - break - if not email: - raise plpy.error('Cannot approve fedorabugs for person_id(%s) because they have no email address to use with bugzilla' % row['person_id']) - - # If there is already a row in bugzilla_queue update, otherwise insert - plan = plpy.prepare("select email from bugzilla_queue where email = $1", - ('text',)) - result = plpy.execute(plan, (email,), 1) - if result: - plan = plpy.prepare("update bugzilla_queue set action = $1" - " where email = $2", ('char', 'text')) - plpy.execute(plan, (newaction, email)) - else: - plan = plpy.prepare("insert into bugzilla_queue (email, group_id" - ", person_id, action) values ($1, $2, $3, $4)", - ('text', 'text', 'text', 'char')) - plpy.execute(plan, (email, row['group_id'], row['person_id'], newaction)) - return None -$bz_sync$ language plpythonu; - -create trigger role_bugzilla_sync before update or insert or delete - on person_roles - for each row execute procedure bugzilla_sync(); +-- create or replace function bugzilla_sync() returns trigger as $bz_sync$ +-- # Decide which row we are operating on and the action to take +-- if TD['event'] == 'DELETE': +-- # 'r' for removing an entry from bugzilla +-- newaction = 'r' +-- row = TD['old'] +-- else: +-- # insert or update +-- row = TD['new'] +-- if row['role_status'] == 'approved': +-- # approved so add an entry to bugzilla +-- newaction = 'a' +-- else: +-- # no longer approved so remove the entry from bugzilla +-- newaction = 'r' +-- +-- # Get the group id for fedorabugs +-- result = plpy.execute("select id from groups where name = 'fedorabugs'", 1) +-- if not result: +-- # Danger Will Robinson! A basic FAS group does not exist! +-- plpy.error('Basic FAS group fedorabugs does not exist') +-- # If this is not a fedorabugs role, no change needed +-- if row['group_id'] != result[0]['id']: +-- return None +-- +-- # Retrieve the bugzilla email address +-- plan = plpy.prepare("select email, purpose from person_emails as pee," +-- " email_purposes as epu" +-- " where epu.id = epu.email_id and pee.person_id = $1" +-- " and purpose in ('bugzilla', 'primary')", +-- ('text',)) +-- result = plpy.execute(plan, row['person_id']) +-- email = None +-- for record in result: +-- email = record['email'] +-- if record['purpose'] == 'bugzilla': +-- break +-- if not email: +-- raise plpy.error('Cannot approve fedorabugs for person_id(%s) because they have no email address to use with bugzilla' % row['person_id']) +-- +-- # If there is already a row in bugzilla_queue update, otherwise insert +-- plan = plpy.prepare("select email from bugzilla_queue where email = $1", +-- ('text',)) +-- result = plpy.execute(plan, (email,), 1) +-- if result: +-- plan = plpy.prepare("update bugzilla_queue set action = $1" +-- " where email = $2", ('char', 'text')) +-- plpy.execute(plan, (newaction, email)) +-- else: +-- plan = plpy.prepare("insert into bugzilla_queue (email, group_id" +-- ", person_id, action) values ($1, $2, $3, $4)", +-- ('text', 'text', 'text', 'char')) +-- plpy.execute(plan, (email, row['group_id'], row['person_id'], newaction)) +-- return None +-- $bz_sync$ language plpythonu; +-- +-- create trigger role_bugzilla_sync before update or insert or delete +-- on person_roles +-- for each row execute procedure bugzilla_sync(); -- -- When an email address changes, check whether it needs to be changed in From ffe51a0b89a5cada5fdf4f05e169c898004d6185 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 9 Mar 2008 21:08:37 -0400 Subject: [PATCH 9/9] Grr, typo. --- fas/dev.cfg | 2 +- fas/fas/templates/group/view.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fas/dev.cfg b/fas/dev.cfg index a727262..5488681 100644 --- a/fas/dev.cfg +++ b/fas/dev.cfg @@ -50,7 +50,7 @@ tg.strict_parameters = True server.webpath='/accounts' base_url_filter.on = True base_url_filter.use_x_forwarded_host = True -base_url_filter.base_url = "http://localhost/accounts" +base_url_filter.base_url = "http://localhost:8088/accounts" # Make the session cookie only return to the host over an SSL link # Disabled for testing. diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index 747f988..8b52457 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -93,7 +93,7 @@
      -
    • +
    • ${_('Sponsor')}