diff --git a/architecture/FedoraHosted.odg b/architecture/FedoraHosted.odg
new file mode 100644
index 0000000..460c457
Binary files /dev/null and b/architecture/FedoraHosted.odg differ
diff --git a/architecture/GlobalNetwork.dia b/architecture/GlobalNetwork.dia
index 91071a2..d11d52f 100644
Binary files a/architecture/GlobalNetwork.dia and b/architecture/GlobalNetwork.dia differ
diff --git a/architecture/GlobalNetwork.odg b/architecture/GlobalNetwork.odg
new file mode 100644
index 0000000..30aa835
Binary files /dev/null and b/architecture/GlobalNetwork.odg differ
diff --git a/architecture/Services.odg b/architecture/Services.odg
new file mode 100644
index 0000000..0e2bbc6
Binary files /dev/null and b/architecture/Services.odg differ
diff --git a/architecture/buildsys.flw b/architecture/buildsys.flw
new file mode 100644
index 0000000..1fb0f3a
Binary files /dev/null and b/architecture/buildsys.flw differ
diff --git a/architecture/buildsys.png b/architecture/buildsys.png
new file mode 100644
index 0000000..85c2855
Binary files /dev/null and b/architecture/buildsys.png differ
diff --git a/architecture/infrastructure.png b/architecture/infrastructure.png
index 63b1092..7cf6cbe 100644
Binary files a/architecture/infrastructure.png and b/architecture/infrastructure.png differ
diff --git a/fas/dev.cfg b/fas/dev.cfg
index cf029d2..3f500b7 100644
--- a/fas/dev.cfg
+++ b/fas/dev.cfg
@@ -7,8 +7,9 @@
#mail.server = 'bastion.fedora.phx.redhat.com'
#base_url_filter.base_url = "http://192.168.2.101:8080"
-mail.on = False
+mail.on = True
mail.server = 'bastion.fedora.phx.redhat.com'
+mail.testmode = True
mail.debug = False
mail.encoding = 'utf-8'
@@ -53,7 +54,7 @@ tg.strict_parameters = True
server.webpath='/fas'
base_url_filter.on=True
-base_url = "http://publictest1.fedoraproject.org"
+base_url_filter.base_url = "https://publictest1.fedoraproject.org/fas"
# Make the session cookie only return to the host over an SSL link
# Disabled for testing.
diff --git a/fas/fas/auth.py b/fas/fas/auth.py
index b58a338..33ed4f1 100644
--- a/fas/fas/auth.py
+++ b/fas/fas/auth.py
@@ -124,7 +124,7 @@ def canApplyGroup(userName, groupName, applyUserName, g=None):
try:
g[req].cn
except KeyError:
- return False
+ return { 'status': False, 'requires': req }
# A user can apply themselves, and FAS admins can apply other people.
if (userName == applyUserName) or \
isAdmin(userName, g):
diff --git a/fas/fas/cla.py b/fas/fas/cla.py
index 11c9073..d4dde82 100644
--- a/fas/fas/cla.py
+++ b/fas/fas/cla.py
@@ -4,7 +4,7 @@ from turbogears import controllers, expose, paginate, identity, redirect, widget
import ldap
import cherrypy
-import mx.DateTime
+from datetime import datetime
import re
import gpgme
import StringIO
@@ -69,7 +69,7 @@ class CLA(controllers.Controller):
return dict()
userName = turbogears.identity.current.user_name
user = Person.byUserName(userName)
- return dict(type=type, user=user, date=str(mx.DateTime.now()))
+ return dict(type=type, user=user, date=datetime.utcnow().ctime())
@identity.require(turbogears.identity.not_anonymous())
@error_handler(error)
@@ -78,7 +78,7 @@ class CLA(controllers.Controller):
'''Download CLA'''
userName = turbogears.identity.current.user_name
user = Person.byUserName(userName)
- return dict(user=user, date=str(mx.DateTime.now()))
+ return dict(user=user, date=datetime.utcnow().ctime())
@identity.require(turbogears.identity.not_anonymous())
@error_handler(error)
diff --git a/fas/fas/controllers.py b/fas/fas/controllers.py
index dcf3474..46f4823 100644
--- a/fas/fas/controllers.py
+++ b/fas/fas/controllers.py
@@ -24,6 +24,11 @@ import sys
reload(sys)
sys.setdefaultencoding('utf-8')
+def add_custom_stdvars(vars):
+ return vars.update({"gettext": _})
+
+turbogears.view.variable_providers.append(add_custom_stdvars)
+
# from fas import json
# import logging
# log = logging.getLogger("fas.controllers")
@@ -49,9 +54,7 @@ class Root(controllers.RootController):
@expose(template="fas.templates.home")
@identity.require(identity.not_anonymous())
def home(self):
- from feeds import Koji
- builds = Koji(turbogears.identity.current.user_name)
- return dict(builds=builds)
+ return dict()
@expose(template="fas.templates.login")
def login(self, forward_url=None, previous_url=None, *args, **kw):
@@ -60,6 +63,8 @@ class Root(controllers.RootController):
and identity.was_login_attempted() \
and not identity.get_identity_errors():
turbogears.flash(_('Welcome, %s') % Person.byUserName(turbogears.identity.current.user_name).givenName)
+ if not forward_url:
+ forward_url = config.get('base_url_filter.base_url') + '/'
raise redirect(forward_url)
forward_url=None
@@ -84,50 +89,4 @@ class Root(controllers.RootController):
def logout(self):
identity.current.logout()
turbogears.flash(_('You have successfully logged out.'))
- raise redirect("/")
-
- ## TODO: Invitation cleanup- move out and validate!
- @expose(template='fas.templates.inviteMember')
- @identity.require(identity.not_anonymous())
- def inviteMember(self, name=None, email=None, skills=None):
- if name and email:
- turbogears.flash(_('Invitation Sent to: "%(name)s" <%(email)s>') % {'name': name, 'email': email})
- if name or email:#FIXME
- turbogears.flash(_('Please provide both an email address and the persons name.'))
- return dict()
-
- @expose(format="json")
- def search(self, userName=None, groupName=None):
- people = Person.users('%s*' % userName)
- return dict(people=
- filter(lambda item: userName in item.lower(), people))
-
- @expose(template='fas.templates.invite')
- @identity.require(identity.not_anonymous())
- def invite(self, target=None):
- import turbomail
- user = Person.byUserName(turbogears.identity.current.user_name)
- if target:
- message = turbomail.Message(user.mail, target, _('Come join The Fedora Project!'))
- message.plain = _('''%(name)s <%(email)s> has invited you to join the Fedora
-Project! We are a community of users and developers who produce a
-complete operating system from entirely free and open source software
-(FOSS). %(name)s thinks that you have knowledge and skills
-that make you a great fit for the Fedora community, and that you might
-be interested in contributing.
-
-How could you team up with the Fedora community to use and develop your
-skills? Check out http://fedoraproject.org/wiki/Join for some ideas.
-Our community is more than just software developers -- we also have a
-place for you whether you're an artist, a web site builder, a writer, or
-a people person. You'll grow and learn as you work on a team with other
-very smart and talented people.
-
-Fedora and FOSS are changing the world -- come be a part of it!''') % {'name': user.givenName, 'email': user.mail}
- turbomail.enqueue(message)
- turbogears.flash(_('Message sent to: %s') % target)
- return dict(target=target, user=user)
-
-def relativeUser(realUser, sudoUser):
- ''' Takes user and sees if they are allow to sudo for remote group'''
- p = Person.byUserName('realUser')
+ raise redirect(request.headers.get("Referer", "/"))
diff --git a/fas/fas/fasLDAP.py b/fas/fas/fasLDAP.py
index 127069e..1e29f36 100644
--- a/fas/fas/fasLDAP.py
+++ b/fas/fas/fasLDAP.py
@@ -26,31 +26,81 @@ python-fedora, python module to interact with Fedora Infrastructure Services
import ldap
from ldap import modlist
-import datetime
+import time
from random import Random
import sha
from base64 import b64encode
import sys
-
+import os
+
+dbName = 'fastest'
class AuthError(Exception):
pass
+def retrieve_db_info(dbKey):
+ '''Retrieve information to connect to the db from the filesystem.
+
+ Arguments:
+ :dbKey: The string identifying the database entry in the config file.
+
+ Returns: A dictionary containing the values to use in connecting to the
+ database.
+
+ Exceptions:
+ :IOError: Returned if the config file is not on the system.
+ :AuthError: Returned if there is no record found for dbKey in the
+ config file.
+ '''
+ # Open a filehandle to the config file
+ if os.environ.has_key('HOME') and os.path.isfile(
+ os.path.join(os.environ.get('HOME'), '.fedora-db-access')):
+ fh = file(os.path.join(
+ os.environ.get('HOME'), '.fedora-db-access'), 'r')
+ elif os.path.isfile('/etc/sysconfig/fedora-db-access'):
+ fh = file('/etc/sysconfig/fedora-db-access', 'r')
+ else:
+ raise IOError, 'fedora-db-access file does not exist.'
+
+ # Read the file until we get the information for the requested db
+ dbInfo = None
+ for line in fh.readlines():
+ if not line:
+ break
+ line = line.strip()
+ if not line or line[0] == '#':
+ continue
+ pieces = line.split(None, 1)
+ if len(pieces) < 2:
+ continue
+ if pieces[0] == dbKey:
+ dbInfo = eval(pieces[1])
+ break
+
+ if fh:
+ fh.close()
+ if not dbInfo:
+ raise AuthError, 'Authentication source "%s" not configured' % (dbKey,)
+ return dbInfo
+
class Server(object):
def __init__(self, server=None, who=None, password=None):
- ### FIXME: Before deploy, get the default server, user, and password
- # from the fedora-db-access file.
- server = server or 'localhost'
- who = who or 'cn=directory manager'
- password = password or 'test'
+ try:
+ dbInfo = retrieve_db_info(dbName)
+ except IOError:
+ raise AuthError, 'Authentication config file fedora-db-access is' \
+ ' not available'
+ server = server or dbInfo['host'] or 'localhost'
+ who = 'cn=%s' % (who or dbInfo['user'])
+ # Some db connections have no password
+ password = password or dbInfo.get('password')
self.ldapConn = ldap.open(server)
self.ldapConn.simple_bind_s(who, password)
def add(self, base, attributes):
''' Add a new group record to LDAP instance '''
- attributes=[ (k, v) for k,v in attributes.items() ]
- self.ldapConn.add_s(base, attributes)
+ self.ldapConn.add_s(base, attributes.items())
def delete(self, base):
''' Delete target base '''
@@ -60,7 +110,7 @@ class Server(object):
''' Modify an attribute, requires write access '''
if new is None:
return None
- new = str(new)
+ new = unicode(new).encode('utf-8')
if new == old:
return None
@@ -130,17 +180,17 @@ class Group(object):
}
@classmethod
- def newGroup(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupRequires, fedoraGroupJoinMsg):
+ def newGroup(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupRequires, fedoraGroupJoinMsg):
''' Create a new group '''
- attributes = { 'cn' : cn,
+ attributes = { 'cn' : cn.encode('utf-8'),
'objectClass' : ('fedoraGroup'),
- 'fedoraGroupDesc' : fedoraGroupDesc,
- 'fedoraGroupOwner' : fedoraGroupOwner,
- 'fedoraGroupType' : '1',
- 'fedoraGroupNeedsSponsor' : fedoraGroupNeedsSponsor,
- 'fedoraGroupUserCanRemove' : fedoraGroupUserCanRemove,
- 'fedoraGroupRequires' : fedoraGroupRequires,
- 'fedoraGroupJoinMsg' : fedoraGroupJoinMsg,
+ 'fedoraGroupDesc' : fedoraGroupDesc.encode('utf-8'),
+ 'fedoraGroupOwner' : fedoraGroupOwner.encode('utf-8'),
+ 'fedoraGroupType' : fedoraGroupType.encode('utf-8'),
+ 'fedoraGroupNeedsSponsor' : fedoraGroupNeedsSponsor.encode('utf-8'),
+ 'fedoraGroupUserCanRemove' : fedoraGroupUserCanRemove.encode('utf-8'),
+ 'fedoraGroupRequires' : fedoraGroupRequires.encode('utf-8'),
+ 'fedoraGroupJoinMsg' : fedoraGroupJoinMsg.encode('utf-8'),
}
self.__server.add('cn=%s,%s' % (cn, self.__base), attributes)
@@ -271,17 +321,10 @@ class Groups(object):
except TypeError:
raise TypeError, 'Group "%s" does not exist' % groupName
- dt = datetime.datetime.now()
- now = '%.2i-%.2i-%.2i %.2i:%.2i:%.2i.%.2i' % (dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second,
- dt.microsecond)
+ now = time.time()
- attributes = { 'cn' : groupName,
- 'fedoraRoleApprovaldate' : 'NotApproved',
+ attributes = { 'cn' : groupName.encode('utf-8'),
+ 'fedoraRoleApprovaldate' : 'None',
'fedoraRoleCreationDate' : str(now),
'fedoraRoleDomain' : 'None',
'fedoraRoleSponsor' : 'None',
@@ -335,33 +378,27 @@ class Person(object):
@classmethod
def newPerson(self, cn, givenName, mail, telephoneNumber, postalAddress):
''' Create a new user '''
- dt = datetime.datetime.now()
- now = '%.2i-%.2i-%.2i %.2i:%.2i:%.2i.%.2i' % (dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second,
- dt.microsecond)
- attributes = { 'cn' : cn,
+ now = time.time()
+ attributes = { 'cn' : cn.encode('utf-8'),
'objectClass' : ('fedoraPerson', 'inetOrgPerson', 'organizationalPerson', 'person', 'top'),
- 'displayName' : cn,
- 'sn' : cn,
- 'cn' : cn,
+ 'displayName' : cn.encode('utf-8'),
+ 'sn' : cn.encode('utf-8'),
+ 'cn' : cn.encode('utf-8'),
'fedoraPersonSshKey' : '',
'facsimileTelephoneNumber' : '',
'fedoraPersonApprovalStatus' : 'approved',
- 'givenName' : givenName,
- 'mail' : mail,
+ 'givenName' : givenName.encode('utf-8'),
+ 'mail' : mail.encode('utf-8'),
'fedoraPersonKeyId' : '',
- 'fedoraPersonCertSerial' : -1,
+ 'fedoraPersonCertSerial' : '-1',
'description' : '',
'fedoraPersonCreationDate' : str(now),
- 'telephoneNumber' : telephoneNumber,
- 'fedoraPersonBugzillaMail' : mail,
- 'postalAddress' : postalAddress,
+ 'telephoneNumber' : telephoneNumber.encode('utf-8'),
+ 'fedoraPersonBugzillaMail' : mail.encode('utf-8'),
+ 'postalAddress' : postalAddress.encode('utf-8'),
'fedoraPersonIrcNick' : '',
- 'userPassword' : 'Disabled'
+ 'userPassword' : 'Disabled',
+ 'fedoraPersonTimeZone' : 'UTC',
}
self.__server.add('cn=%s,%s' % (cn, self.__base), attributes)
attributes = {
@@ -475,14 +512,7 @@ class Person(object):
base = 'cn=%s,ou=Roles,cn=%s,ou=People,dc=fedoraproject,dc=org' % (groupName, self.cn)
g = Groups.byGroupName(groupName, includeUnapproved=True)[self.cn]
group = Groups.groups(groupName)[groupName]
- dt = datetime.datetime.now()
- now = '%.2i-%.2i-%.2i %.2i:%.2i:%.2i.%.2i' % (dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second,
- dt.microsecond)
+ now = time.time()
self.__server.modify(base, 'fedoraRoleApprovalDate', now)
if group.fedoraGroupNeedsSponsor.lower() == 'true':
self.__server.modify(base, 'fedoraRoleSponsor', sponsor)
diff --git a/fas/fas/group.py b/fas/fas/group.py
index 323bc02..af6a2b7 100644
--- a/fas/fas/group.py
+++ b/fas/fas/group.py
@@ -64,6 +64,10 @@ class userNameGroupNameExists(validators.Schema):
class groupNameExists(validators.Schema):
groupName = validators.All(knownGroup(not_empty=True, max=10), validators.String(max=32, min=3))
+class groupInvite(validators.Schema):
+ groupName = validators.All(knownGroup(not_empty=True, max=10), validators.String(max=32, min=3))
+ target = validators.Email(not_empty=True, strip=True),
+
#class findUser(widgets.WidgetsList):
# userName = widgets.AutoCompleteField(label=_('Username'), search_controller='search', search_param='userName', result_name='people')
# action = widgets.HiddenField(default='apply', validator=validators.String(not_empty=True))
@@ -92,6 +96,22 @@ class Group(controllers.Controller):
turbogears.redirect('/')
return dict(tg_errors=tg_errors)
+ @expose(format="json")
+ def exportShellAccounts(self):
+ ''' Replaces old "exportShellAccounts.py" '''
+ userList = Groups.byGroupName('sysadmin-main')
+ user = Person.byUserName('mmcgrath').givenName
+ users = {}
+ for user in userList.keys():
+ u = Person.byUserName(user)
+ users[user] = {
+ 'userName' : u.cn,
+ 'password' : u.userPassword,
+ 'sshKey' : u.fedoraPersonSshKey,
+ }
+ groups = Groups.groups('*')
+ return dict(users=users, groups=groups)
+
@identity.require(turbogears.identity.not_anonymous())
@validate(validators=groupNameExists())
@error_handler(error)
@@ -118,7 +138,8 @@ class Group(controllers.Controller):
me = groups[userName]
except:
me = UserGroup()
- return dict(userName=userName, groups=groups, group=group, me=me)
+ u = Person.byUserName(userName)
+ return dict(userName=userName, u=u, groups=groups, group=group, me=me)
@identity.require(turbogears.identity.not_anonymous())
@expose(template="fas.templates.group.new")
@@ -134,7 +155,7 @@ class Group(controllers.Controller):
@validate(validators=createGroup())
@error_handler(error)
@expose(template="fas.templates.group.new")
- def create(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor='FALSE', fedoraGroupUserCanRemove='FALSE', fedoraGroupRequires='', fedoraGroupJoinMsg=''):
+ def create(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor='FALSE', fedoraGroupUserCanRemove='FALSE', fedoraGroupRequires='', fedoraGroupJoinMsg=''):
'''Create a group'''
userName = turbogears.identity.current.user_name
if not canCreateGroup(userName):
@@ -144,6 +165,7 @@ class Group(controllers.Controller):
fas.fasLDAP.Group.newGroup(groupName,
fedoraGroupDesc,
fedoraGroupOwner,
+ fedoraGroupType,
fedoraGroupNeedsSponsor,
fedoraGroupUserCanRemove,
fedoraGroupRequires,
@@ -182,7 +204,7 @@ class Group(controllers.Controller):
@validate(validators=editGroup())
@error_handler(error)
@expose()
- def save(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType=1, fedoraGroupNeedsSponsor="FALSE", fedoraGroupUserCanRemove="FALSE", fedoraGroupRequires="", fedoraGroupJoinMsg=""):
+ def save(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor="FALSE", fedoraGroupUserCanRemove="FALSE", fedoraGroupRequires="", fedoraGroupJoinMsg=""):
'''Edit a group'''
userName = turbogears.identity.current.user_name
if fedoraGroupRequires is None:
@@ -233,9 +255,9 @@ class Group(controllers.Controller):
applicant = turbogears.identity.current.user_name
if not userName:
userName = applicant
- if not canApplyGroup(applicant, groupName, userName):
- turbogears.flash(_('%(user)s could not apply to %(group)s!') % \
- {'user': userName, 'group': groupName})
+ if not canApplyGroup(applicant, groupName, userName)['status']:
+ turbogears.flash(_('%(user)s could not apply to %(group)s! This group requires membership in %(requires)s') % \
+ {'user': userName, 'group': groupName, 'requires': canApplyGroup(applicant, groupName, userName)['requires']})
turbogears.redirect('/group/view/%s' % groupName)
return dict()
else:
@@ -287,16 +309,13 @@ class Group(controllers.Controller):
group = Groups.groups(groupName)[groupName]
import turbomail
message = turbomail.Message(config.get('accounts_mail'), p.mail, "Your Fedora '%s' membership has been sponsored" % groupName)
- user = Person.byUserName(userName)
- name = user.givenName
- email = user.mail
message.plain = dedent('''
%(name)s <%(email)s> has sponsored you for membership in the %(group)s
group of the Fedora account system. If applicable, this change should
propagate into the e-mail aliases and CVS repository within an hour.
%(joinmsg)s
- ''') % {'group': groupName, 'name': name, 'email': email, 'joinmsg': group.fedoraGroupJoinMsg}
+ ''') % {'group': groupName, 'name': user.givenName, 'email': user.mail, 'joinmsg': group.fedoraGroupJoinMsg}
turbomail.enqueue(message)
turbogears.flash(_("'%s' has been sponsored!") % p.cn)
turbogears.redirect('/group/view/%s' % groupName)
@@ -322,18 +341,16 @@ class Group(controllers.Controller):
{'name': userName, 'group': groupName})
turbogears.redirect('/group/view/%s' % groupName)
else:
- user = Person.byUserName(sponsor)
import turbomail
- message = turbomail.Message(config.get('accounts_mail'), p.mail, "Your Fedora '%s' membership has been removed" % groupName)
+ sponsor = Person.byUserName(sponsor)
user = Person.byUserName(userName)
- name = user.givenName
- email = user.mail
+ message = turbomail.Message(config.get('accounts_mail'), user.mail, "Your Fedora '%s' membership has been removed" % groupName)
message.plain = dedent('''
%(name)s <%(email)s> has removed you from the '%(group)s'
group of the Fedora Accounts System This change is effective
immediately for new operations, and should propagate into the e-mail
aliases within an hour.
- ''') % {'group': groupName, 'name': name, 'email': email}
+ ''') % {'group': groupName, 'name': sponsor.name, 'email': sponsor.mail}
turbomail.enqueue(message)
turbogears.flash(_('%(name)s has been removed from %(group)s!') % \
{'name': userName, 'group': groupName})
@@ -367,8 +384,6 @@ class Group(controllers.Controller):
import turbomail
message = turbomail.Message(config.get('accounts_mail'), p.mail, "Your Fedora '%s' membership has been upgraded" % groupName)
user = Person.byUserName(userName)
- name = user.givenName
- email = user.mail
g = Groups.byUserName(userName)
status = g[groupName].fedoraRoleType.lower()
message.plain = dedent('''
@@ -376,7 +391,7 @@ class Group(controllers.Controller):
'%(group)s' group of the Fedora Accounts System This change is
effective immediately for new operations, and should propagate
into the e-mail aliases within an hour.
- ''') % {'group': groupName, 'name': name, 'email': email, 'status': status}
+ ''') % {'group': groupName, 'name': user.givenName, 'email': user.mail, 'status': status}
turbomail.enqueue(message)
turbogears.flash(_('%s has been upgraded!') % userName)
turbogears.redirect('/group/view/%s' % groupName)
@@ -438,3 +453,45 @@ class Group(controllers.Controller):
groups = Groups.byGroupName(groupName)
return dict(groups=groups, Person=Person)
+ @identity.require(identity.not_anonymous())
+ @validate(validators=groupNameExists())
+ @error_handler(error)
+ @expose(template='fas.templates.group.invite')
+ def invite(self, groupName):
+ userName = turbogears.identity.current.user_name
+ user = Person.byUserName(userName)
+ return dict(user=user, group=groupName)
+
+ @identity.require(identity.not_anonymous())
+ @validate(validators=groupNameExists())
+ @error_handler(error)
+ @expose(template='fas.templates.group.invite')
+ def sendinvite(self, groupName, target=None):
+ import turbomail
+ userName = turbogears.identity.current.user_name
+ user = Person.byUserName(userName)
+ if isApproved(userName, groupName):
+ message = turbomail.Message(user.mail, target, _('Come join The Fedora Project!'))
+ message.plain = _(dedent('''
+ %(name)s <%(email)s> has invited you to join the Fedora
+ Project! We are a community of users and developers who produce a
+ complete operating system from entirely free and open source software
+ (FOSS). %(name)s thinks that you have knowledge and skills
+ that make you a great fit for the Fedora community, and that you might
+ be interested in contributing.
+
+ How could you team up with the Fedora community to use and develop your
+ skills? Check out http://fedoraproject.org/join-fedora for some ideas.
+ Our community is more than just software developers -- we also have a
+ place for you whether you're an artist, a web site builder, a writer, or
+ a people person. You'll grow and learn as you work on a team with other
+ very smart and talented people.
+
+ Fedora and FOSS are changing the world -- come be a part of it!''')) % {'name': user.givenName, 'email': user.mail}
+ turbomail.enqueue(message)
+ turbogears.flash(_('Message sent to: %s') % target)
+ turbogears.redirect('/group/view/%s' % groupName)
+ else:
+ turbogears.flash(_("You are not in the '%s' group.") % groupName)
+ return dict(target=target, user=user)
+
diff --git a/fas/fas/static/css/style.css b/fas/fas/static/css/style.css
index 1cd33d7..b18378a 100644
--- a/fas/fas/static/css/style.css
+++ b/fas/fas/static/css/style.css
@@ -225,7 +225,7 @@ a
.userbox dd
{
- margin-left: 22ex;
+ margin-left: 24ex;
}
.account
@@ -324,6 +324,11 @@ a
background: url(/fas/static/images/queue.png) 0 50% no-repeat;
}
+#rolespanel .queue strong
+{
+ color: #222222;
+}
+
#footer
{
font-size: 1.6ex;
diff --git a/fas/fas/templates/cla/click.html b/fas/fas/templates/cla/click.html
index 09c09d4..648434e 100644
--- a/fas/fas/templates/cla/click.html
+++ b/fas/fas/templates/cla/click.html
@@ -4,19 +4,19 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
- There are two ways to sign the CLA... CLA Acceptance Hierarchies + ${Markup(_('There are two ways to sign the CLA. Most users will want to do a signed CLA as it will promote them to a full contributor in Fedora. The click-through CLA only grants partial access but may be preferred for those with special legal considerations. See: <a href="http://fedoraproject.org/wiki/Legal/CLAAcceptanceHierarchies">CLA Acceptance Hierarchies</a> for more information.'))}
- Congratulations, you have already sucessfully signed the CLA. + ${Markup(_('You have already sucessfully signed the <a href="%s">CLA</a>.') % tg.url('/cla/view'))}