Split user/group into separate files, convert to genshi for templates. TODO: Form validation
This commit is contained in:
parent
f62a04b427
commit
a1283c3a1c
36 changed files with 1031 additions and 765 deletions
52
fas/fas/auth.py
Normal file
52
fas/fas/auth.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from turbogears import config
|
||||
|
||||
from fas.fasLDAP import UserAccount
|
||||
from fas.fasLDAP import Person
|
||||
from fas.fasLDAP import Groups
|
||||
from fas.fasLDAP import UserGroup
|
||||
|
||||
ADMINGROUP = config.get('admingroup')
|
||||
|
||||
def isAdmin(userName, g=None):
|
||||
if not g:
|
||||
g = Groups.byUserName(userName)
|
||||
try:
|
||||
g[ADMINGROUP].cn
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def canAdminGroup(userName, groupName, g=None):
|
||||
# TODO: Allow the group owner to admin a group.
|
||||
if not g:
|
||||
g = Groups.byUserName(userName)
|
||||
try:
|
||||
if isAdmin(userName, g) or \
|
||||
(g[groupName].fedoraRoleType.lower() == 'administrator'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def canSponsorGroup(userName, groupName, g=None):
|
||||
if not g:
|
||||
g = Groups.byUserName(userName)
|
||||
try:
|
||||
if isAdmin(userName, g) or \
|
||||
canAdminGroup(userName, groupName, g) or \
|
||||
(g[groupName].fedoraRoleType.lower() == 'sponsor'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def canEditUser(userName, editUserName):
|
||||
if userName == editUserName:
|
||||
return True
|
||||
elif isAdmin(userName):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -13,6 +13,7 @@ admingroup = 'accounts'
|
|||
# which view (template engine) to use if one is not specified in the
|
||||
# template name
|
||||
# tg.defaultview = "kid"
|
||||
tg.defaultview = "genshi"
|
||||
|
||||
# The following kid settings determine the settings used by the kid serializer.
|
||||
|
||||
|
|
|
@ -10,106 +10,34 @@ from turbogears import exception_handler
|
|||
import turbogears
|
||||
import ldap
|
||||
import time
|
||||
from operator import itemgetter
|
||||
|
||||
from fas.user import User
|
||||
from fas.group import Group
|
||||
|
||||
# from fas import json
|
||||
# import logging
|
||||
# log = logging.getLogger("fas.controllers")
|
||||
|
||||
ADMINGROUP = config.get('admingroup')
|
||||
|
||||
class knownUser(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
p = Person.byUserName(value)
|
||||
if p.cn:
|
||||
raise validators.Invalid(_("'%s' already exists") % value, value, state)
|
||||
|
||||
class unknownUser(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
p = Person.byUserName(value)
|
||||
if not p.cn:
|
||||
raise validators.Invalid(_("'%s' does not exist") % value, value, state)
|
||||
|
||||
class unknownGroup(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
g = Groups.groups(groupName)
|
||||
if not g:
|
||||
raise validators.Invalid(_("'%s' does not exist") % value, value, state)
|
||||
|
||||
|
||||
class newPerson(widgets.WidgetsList):
|
||||
# cn = widgets.TextField(label='Username', validator=validators.PlainText(not_empty=True, max=10))
|
||||
cn = widgets.TextField(label=_('Username'), validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
givenName = widgets.TextField(label=_('Full Name'), validator=validators.String(not_empty=True, max=42))
|
||||
mail = widgets.TextField(label=_('Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
telephoneNumber = widgets.TextField(label=_('Telephone Number'), validator=validators.PhoneNumber(not_empty=True))
|
||||
postalAddress = widgets.TextArea(label=_('Postal Address'), validator=validators.NotEmpty)
|
||||
|
||||
newPersonForm = widgets.ListForm(fields=newPerson(), submit_text=_('Sign Up'))
|
||||
|
||||
class editPerson(widgets.WidgetsList):
|
||||
# cn = widgets.TextField(label='Username', validator=validators.PlainText(not_empty=True, max=10))
|
||||
userName = widgets.HiddenField(validator=validators.All(unknownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
givenName = widgets.TextField(label=_('Full Name'), validator=validators.String(not_empty=True, max=42))
|
||||
mail = widgets.TextField(label=_('Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
fedoraPersonBugzillaMail = widgets.TextField(label=_('Bugzilla Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
fedoraPersonIrcNick = widgets.TextField(label=_('IRC Nick'))
|
||||
fedoraPersonKeyId = widgets.TextField(label=_('PGP Key'))
|
||||
telephoneNumber = widgets.TextField(label=_('Telephone Number'), validator=validators.PhoneNumber(not_empty=True))
|
||||
postalAddress = widgets.TextArea(label=_('Postal Address'), validator=validators.NotEmpty)
|
||||
description = widgets.TextArea(label=_('Description'))
|
||||
|
||||
editPersonForm = widgets.ListForm(fields=editPerson(), submit_text=_('Update'))
|
||||
|
||||
class editGroup(widgets.WidgetsList):
|
||||
groupName = widgets.HiddenField(validator=validators.All(unknownGroup(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupDesc = widgets.TextField(label=_('Description'), validator=validators.NotEmpty)
|
||||
fedoraGroupOwner = widgets.TextField(label=_('Group Owner'), validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupNeedsSponsor = widgets.CheckBox(label=_('Needs Sponsor'))
|
||||
fedoraGroupUserCanRemove = widgets.CheckBox(label=_('Self Removal'))
|
||||
fedoraGroupJoinMsg = widgets.TextField(label=_('Group Join Message'))
|
||||
|
||||
editGroupForm = widgets.ListForm(fields=editGroup(), submit_text=_('Update'))
|
||||
|
||||
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))
|
||||
groupName = widgets.HiddenField(validator=validators.String(not_empty=True))
|
||||
|
||||
searchUserForm = widgets.ListForm(fields=findUser(), submit_text=_('Invite'))
|
||||
|
||||
|
||||
class Root(controllers.RootController):
|
||||
@expose(template="fas.templates.error")
|
||||
def errorMessage(self, tg_exceptions=None):
|
||||
''' Generic exception handler'''
|
||||
# Maybe add a popup or alert or some damn thing.
|
||||
message = '%s' % tg_exceptions
|
||||
return dict(handling_value=True,exception=message)
|
||||
|
||||
user = User()
|
||||
group = Group()
|
||||
|
||||
@expose(template="fas.templates.welcome")
|
||||
# @identity.require(identity.in_group("admin"))
|
||||
def index(self):
|
||||
# log.debug("Happy TurboGears Controller Responding For Duty")
|
||||
if turbogears.identity.not_anonymous():
|
||||
turbogears.redirect('home')
|
||||
return dict(now=time.ctime())
|
||||
|
||||
@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)
|
||||
|
||||
@expose(template="fas.templates.dump", format="plain", content_type="text/plain")
|
||||
def groupDump(self, groupName=None):
|
||||
groups = Groups.byGroupName(groupName)
|
||||
return dict(groups=groups, Person=Person)
|
||||
|
||||
@expose(template="fas.templates.login")
|
||||
def login(self, forward_url=None, previous_url=None, *args, **kw):
|
||||
|
||||
|
@ -143,408 +71,23 @@ class Root(controllers.RootController):
|
|||
turbogears.flash(_('You have successfully logged out.'))
|
||||
raise redirect("/")
|
||||
|
||||
@expose(template="fas.templates.viewAccount")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def viewAccount(self,userName=None, action=None):
|
||||
if not userName:
|
||||
userName = turbogears.identity.current.user_name
|
||||
if turbogears.identity.current.user_name == userName:
|
||||
personal = True
|
||||
else:
|
||||
personal = False
|
||||
try:
|
||||
Groups.byUserName(turbogears.identity.current.user_name)[ADMINGROUP].cn
|
||||
admin = True
|
||||
except KeyError:
|
||||
admin = False
|
||||
user = Person.byUserName(userName)
|
||||
groups = Groups.byUserName(userName)
|
||||
groupsPending = Groups.byUserName(userName, unapprovedOnly=True)
|
||||
groupdata={}
|
||||
for g in groups:
|
||||
groupdata[g] = Groups.groups(g)[g]
|
||||
for g in groupsPending:
|
||||
groupdata[g] = Groups.groups(g)[g]
|
||||
try:
|
||||
groups['cla_done']
|
||||
claDone=True
|
||||
except KeyError:
|
||||
claDone=None
|
||||
return dict(user=user, groups=groups, groupsPending=groupsPending, action=action, groupdata=groupdata, claDone=claDone, personal=personal, admin=admin)
|
||||
|
||||
@expose(template="fas.templates.editAccount")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def editAccount(self, userName=None, action=None):
|
||||
if userName:
|
||||
try:
|
||||
Groups.byUserName(turbogears.identity.current.user_name)[ADMINGROUP].cn
|
||||
if not userName:
|
||||
userName = turbogears.identity.current.user_name
|
||||
except KeyError:
|
||||
turbogears.flash(_('You cannot edit %s') % userName )
|
||||
userName = turbogears.identity.current.user_name
|
||||
else:
|
||||
userName = turbogears.identity.current.user_name
|
||||
user = Person.byUserName(userName)
|
||||
value = {'userName' : userName,
|
||||
'givenName' : user.givenName,
|
||||
'mail' : user.mail,
|
||||
'fedoraPersonBugzillaMail' : user.fedoraPersonBugzillaMail,
|
||||
'fedoraPersonIrcNick' : user.fedoraPersonIrcNick,
|
||||
'fedoraPersonKeyId' : user.fedoraPersonKeyId,
|
||||
'telephoneNumber' : user.telephoneNumber,
|
||||
'postalAddress' : user.postalAddress,
|
||||
'description' : user.description, }
|
||||
return dict(form=editPersonForm, value=value)
|
||||
|
||||
@expose(template="fas.templates.viewGroup")
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def viewGroup(self, groupName):
|
||||
try:
|
||||
groups = Groups.byGroupName(groupName, includeUnapproved=True)
|
||||
except KeyError:
|
||||
raise ValueError, _('Group: %s - Does not exist!') % groupName
|
||||
try:
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
except TypeError:
|
||||
raise ValueError, _('Group: %s - Does not exist!') % groupName
|
||||
userName = turbogears.identity.current.user_name
|
||||
try:
|
||||
myStatus = groups[userName].fedoraRoleStatus
|
||||
except KeyError:
|
||||
# Not in group
|
||||
myStatus = 'Not a Member' # This has say 'Not a Member'
|
||||
except TypeError:
|
||||
groups = {}
|
||||
try:
|
||||
me = groups[userName]
|
||||
except:
|
||||
me = UserGroup()
|
||||
#searchUserForm.groupName.display('group')
|
||||
#findUser.groupName.display(value='fff')
|
||||
value = {'groupName' : group.cn}
|
||||
return dict(groups=groups, group=group, me=me, searchUserForm=searchUserForm, value=value)
|
||||
|
||||
@expose(template="fas.templates.editGroup")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def editGroup(self, groupName, action=None):
|
||||
userName = turbogears.identity.current.user_name
|
||||
try:
|
||||
Groups.byUserName(userName)[ADMINGROUP].cn
|
||||
except KeyError:
|
||||
try:
|
||||
Groups.byUserName(userName)[groupName]
|
||||
if Groups.byUserName(userName)[groupName].fedoraRoleType.lower() != 'administrator':
|
||||
raise KeyError
|
||||
except KeyError:
|
||||
turbogears.flash(_('You cannot edit %s') % groupName)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % groupName)
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
value = {'groupName' : groupName,
|
||||
'fedoraGroupOwner' : group.fedoraGroupOwner,
|
||||
'fedoraGroupType' : group.fedoraGroupType,
|
||||
'fedoraGroupNeedsSponsor' : (group.fedoraGroupNeedsSponsor.upper() == 'TRUE'),
|
||||
'fedoraGroupUserCanRemove' : (group.fedoraGroupUserCanRemove.upper() == 'TRUE'),
|
||||
'fedoraGroupJoinMsg' : group.fedoraGroupJoinMsg,
|
||||
'fedoraGroupDesc' : group.fedoraGroupDesc, }
|
||||
#'fedoraGroupRequires' : group.fedoraGroupRequires, }
|
||||
return dict(form=editGroupForm, value=value)
|
||||
|
||||
@expose(template="fas.templates.groupList")
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def listGroup(self, search='*'):
|
||||
groups = Groups.groups(search)
|
||||
userName = turbogears.identity.current.user_name
|
||||
myGroups = Groups.byUserName(userName)
|
||||
try:
|
||||
groups.keys()
|
||||
except:
|
||||
turbogears.flash(_("No Groups found matching '%s'") % search)
|
||||
groups = {}
|
||||
return dict(groups=groups, search=search, myGroups=myGroups)
|
||||
|
||||
@expose(template="fas.templates.resetPassword")
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
def resetPassword(self, userName=None, password=None, passwordCheck=None, mail=None):
|
||||
import turbomail
|
||||
|
||||
# Logged in
|
||||
if turbogears.identity.current.user_name and not password:
|
||||
return dict()
|
||||
|
||||
# Not logged in
|
||||
if not (userName and mail) and not turbogears.identity.current.user_name:
|
||||
# turbogears.flash('Please provide your username and password')
|
||||
return dict()
|
||||
|
||||
if turbogears.identity.current.user_name:
|
||||
userName = turbogears.identity.current.user_name
|
||||
p = Person.byUserName(userName)
|
||||
|
||||
if password and passwordCheck:
|
||||
if not password == passwordCheck:
|
||||
turbogears.flash(_('Passwords do not match!'))
|
||||
return dict()
|
||||
if len(password) < 8:
|
||||
turbogears.flash(_('Password is too short. Must be at least 8 characters long'))
|
||||
return dict()
|
||||
newpass = p.generatePassword(password)
|
||||
|
||||
if userName and mail and not turbogears.identity.current.user_name:
|
||||
if not mail == p.mail:
|
||||
turbogears.flash(_("username + email combo unknown."))
|
||||
return dict()
|
||||
newpass = p.generatePassword()
|
||||
message = turbomail.Message('accounts@fedoraproject.org', p.mail, _('Fedora Project Password Reset'))
|
||||
message.plain = _("You have requested a password reset! Your new password is - %s \nPlease go to https://admin.fedoraproject.org/fas/ to change it") % newpass['pass']
|
||||
turbomail.enqueue(message)
|
||||
p.__setattr__('userPassword', newpass['hash'])
|
||||
|
||||
p.userPassword = newpass['hash']
|
||||
print "PASS: %s" % newpass['pass']
|
||||
|
||||
if turbogears.identity.current.user_name:
|
||||
turbogears.flash(_("Password Changed"))
|
||||
turbogears.redirect("viewAccount")
|
||||
else:
|
||||
turbogears.flash(_('Your password has been emailed to you'))
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.userList")
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@identity.require(identity.in_group("accounts"))
|
||||
def listUser(self, search='a*'):
|
||||
users = Person.users(search)
|
||||
try:
|
||||
users[0]
|
||||
except:
|
||||
turbogears.flash(_("No users found matching '%s'") % search)
|
||||
users = []
|
||||
cla_done = Groups.byGroupName('cla_done')
|
||||
claDone = {}
|
||||
for u in users:
|
||||
try:
|
||||
cla_done[u]
|
||||
claDone[u] = True
|
||||
except KeyError:
|
||||
claDone[u] = False
|
||||
return dict(users=users, claDone=claDone, search=search)
|
||||
|
||||
listUsers = listUser
|
||||
|
||||
# @expose(template='fas.templates.apply')
|
||||
# @exception_handler(errorMessage, rules="isinstance(tg_exceptions,ValueError)")
|
||||
# @identity.require(identity.not_anonymous())
|
||||
# def sudo(self, userName):
|
||||
# # This doesn't work
|
||||
# turbogears.identity.current.user_name=userName
|
||||
# turbogears.flash('Sudoed to %s' % userName)
|
||||
# turbogears.recirect('viewAccount')
|
||||
|
||||
# @error_handler(viewGroup)
|
||||
# @validate(form=newPersonForm)
|
||||
@expose(template='fas.templates.apply')
|
||||
@identity.require(identity.not_anonymous())
|
||||
def modifyGroup(self, groupName, action, userName, **kw):
|
||||
''' Modifies group based on action, groupName and userName '''
|
||||
try:
|
||||
userName = userName['text']
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
sponsor = turbogears.identity.current.user_name
|
||||
try:
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
except KeyError:
|
||||
turbogears.flash(_('Group Error: %s does not exist.') % groupName)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
try:
|
||||
p = Person.byUserName(userName)
|
||||
if not p.cn:
|
||||
raise KeyError, userName
|
||||
except KeyError:
|
||||
turbogears.flash(_('User Error: User %s does not exist.') % userName)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
g = Groups.byGroupName(groupName, includeUnapproved=True)
|
||||
|
||||
# Apply user to a group (as in application)
|
||||
if action == 'apply':
|
||||
try:
|
||||
Groups.apply(groupName, userName)
|
||||
except ldap.ALREADY_EXISTS:
|
||||
turbogears.flash(_('%s Already in group!') % p.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
else:
|
||||
turbogears.flash(_('%s Applied!') % p.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
# Some error checking for the sponsors
|
||||
if g[userName].fedoraRoleType.lower() == 'administrator' and g[sponsor].fedoraRoleType.lower() == 'sponsor':
|
||||
raise ValueError, _('Sponsors cannot alter administrators. End of story.')
|
||||
|
||||
try:
|
||||
userGroup = Groups.byGroupName(groupName)[userName]
|
||||
except KeyError:
|
||||
# User not already in the group (happens when users apply for a group)
|
||||
userGroup = UserGroup()
|
||||
pass
|
||||
|
||||
# Remove user from a group
|
||||
if action == 'remove':
|
||||
try:
|
||||
Groups.remove(group.cn, p.cn)
|
||||
except TypeError:
|
||||
turbogears.flash(_('%(name)s could not be removed from %(group)s!') % {'name' : p.cn, 'group' : group.cn})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
else:
|
||||
turbogears.flash(_('%(name)s removed from %(group)s!') % {'name' : p.cn, 'group' : group.cn})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
return dict()
|
||||
|
||||
# Upgrade user in a group
|
||||
elif action == 'upgrade':
|
||||
if g[userName].fedoraRoleType.lower() == 'sponsor' and g[sponsor].fedoraRoleType.lower() == 'sponsor':
|
||||
raise ValueError, _('Sponsors cannot admin other sponsors')
|
||||
try:
|
||||
p.upgrade(groupName)
|
||||
except TypeError, e:
|
||||
turbogears.flash(_('Cannot upgrade %(name)s - %(error)s!') % {'name' : p.cn, 'error' : e})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
turbogears.flash(_('%s Upgraded!') % p.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
|
||||
# Downgrade user in a group
|
||||
elif action == 'downgrade':
|
||||
if g[userName].fedoraRoleType.lower() == 'administrator' and g[sponsor].fedoraRoleType.lower() == 'sponsor':
|
||||
raise ValueError, _('Sponsors cannot downgrade admins')
|
||||
try:
|
||||
p.downgrade(groupName)
|
||||
except TypeError, e:
|
||||
turbogears.flash(_('Cannot downgrade %(name)s - %(error)s!') % {'name' : p.cn, 'error' : e})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
turbogears.flash(_('%s Downgraded!') % p.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
# Sponsor / Approve User
|
||||
elif action == 'sponsor' or action == 'apply':
|
||||
p.sponsor(groupName, sponsor)
|
||||
turbogears.flash(_('%s has been sponsored!') % p.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
turbogears.flash(_('Invalid action: %s') % action)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
return dict()
|
||||
|
||||
## TODO: Invitation cleanup- move out and validate!
|
||||
@expose(template='fas.templates.inviteMember')
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@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})
|
||||
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(template='fas.templates.apply')
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def applyForGroup(self, groupName, action=None, requestField=None):
|
||||
userName = turbogears.identity.current.user_name
|
||||
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
user = Person.byUserName(userName)
|
||||
if action != 'Remove':
|
||||
try:
|
||||
Groups.apply(groupName, userName)
|
||||
turbogears.flash(_('Application sent for %s') % user.cn)
|
||||
except ldap.ALREADY_EXISTS, e:
|
||||
turbogears.flash(_('Application Denied: %s') % e[0]['desc'])
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
|
||||
if action == 'Remove' and group.fedoraGroupUserCanRemove == 'TRUE':
|
||||
try:
|
||||
Groups.remove(group.cn, user.cn)
|
||||
except TypeError:
|
||||
turbogears.flash(_('%(user)s could not be removed from %(group)s!') % {'user' : user.cn, 'group' : group.cn})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
else:
|
||||
turbogears.flash(_('%(user)s removed from %(group)s!') % {'user' : user.cn, 'group' : group.cn})
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
else:
|
||||
turbogears.flash(_('%s does not allow self removal') % group.cn)
|
||||
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
|
||||
return dict()
|
||||
|
||||
@expose(template='fas.templates.signUp')
|
||||
def signUp(self):
|
||||
if turbogears.identity.not_anonymous():
|
||||
turbogears.flash(_('No need to sign up, You have an account!'))
|
||||
turbogears.redirect('viewAccount')
|
||||
return dict(form=newPersonForm)
|
||||
|
||||
@validate(form=newPersonForm)
|
||||
@error_handler(signUp)
|
||||
@expose(template='fas.templates.signUp')
|
||||
def newAccountSubmit(self, cn, givenName, mail, telephoneNumber, postalAddress):
|
||||
import turbomail
|
||||
try:
|
||||
Person.newPerson(cn.encode('utf8'), givenName.encode('utf8'), mail.encode('utf8'), telephoneNumber.encode('utf8'), postalAddress.encode('utf8'))
|
||||
p = Person.byUserName(cn.encode('utf8'))
|
||||
newpass = p.generatePassword()
|
||||
message = turbomail.Message('accounts@fedoraproject.org', p.mail, _('Fedora Project Password Reset'))
|
||||
message.plain = _("You have requested a password reset! Your new password is - %s \nPlease go to https://admin.fedoraproject.org/fas/ to change it") % newpass['pass']
|
||||
turbomail.enqueue(message)
|
||||
p.__setattr__('userPassword', newpass['hash'])
|
||||
turbogears.flash(_('Your password has been emailed to you. Please log in with it and change your password'))
|
||||
turbogears.redirect('/')
|
||||
|
||||
except ldap.ALREADY_EXISTS:
|
||||
turbogears.flash(_('%s Already Exists, Please pick a different name') % cn)
|
||||
turbogears.redirect('signUp')
|
||||
return dict()
|
||||
|
||||
@validate(form=editPersonForm)
|
||||
@error_handler(editAccount)
|
||||
@expose(template='fas.templates.editAccount')
|
||||
def editAccountSubmit(self, givenName, mail, fedoraPersonBugzillaMail, telephoneNumber, postalAddress, userName=None, fedoraPersonIrcNick='', fedoraPersonKeyId='', description=''):
|
||||
if userName:
|
||||
try:
|
||||
Groups.byUserName(turbogears.identity.current.user_name)[ADMINGROUP].cn
|
||||
if not userName:
|
||||
userName = turbogears.identity.current.user_name
|
||||
except KeyError:
|
||||
turbogears.flash(_('You cannot view %s') % userName)
|
||||
userName = turbogears.identity.current.user_name
|
||||
turbogears.redirect("editAccount")
|
||||
return dict()
|
||||
else:
|
||||
userName = turbogears.identity.current.user_name
|
||||
user = Person.byUserName(userName)
|
||||
user.__setattr__('givenName', givenName.encode('utf8'))
|
||||
user.__setattr__('mail', mail.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonBugzillaMail', fedoraPersonBugzillaMail.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonIrcNick', fedoraPersonIrcNick.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonKeyId', fedoraPersonKeyId.encode('utf8'))
|
||||
user.__setattr__('telephoneNumber', telephoneNumber.encode('utf8'))
|
||||
user.__setattr__('postalAddress', postalAddress.encode('utf8'))
|
||||
user.__setattr__('description', description.encode('utf8'))
|
||||
turbogears.flash(_('Your account has been updated.'))
|
||||
turbogears.redirect("viewAccount?userName=%s" % userName)
|
||||
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')
|
||||
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
|
||||
@identity.require(identity.not_anonymous())
|
||||
def invite(self, target=None):
|
||||
import turbomail
|
||||
|
@ -566,7 +109,7 @@ place for you whether you're an artist, a web site builder, a writer, or \
|
|||
a people person. You'll grow and learn as you work on a team with other \
|
||||
very smart and talented people. \n\
|
||||
\n\
|
||||
Fedora and FOSS are changing the world -- come be a part of it!") % {'name' : user.givenName, 'email' : user.mail}
|
||||
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)
|
||||
|
@ -574,4 +117,3 @@ Fedora and FOSS are changing the world -- come be a part of it!") % {'name' : us
|
|||
def relativeUser(realUser, sudoUser):
|
||||
''' Takes user and sees if they are allow to sudo for remote group'''
|
||||
p = Person.byUserName('realUser')
|
||||
|
||||
|
|
280
fas/fas/group.py
Normal file
280
fas/fas/group.py
Normal file
|
@ -0,0 +1,280 @@
|
|||
import turbogears
|
||||
from turbogears import controllers, expose, paginate, identity, redirect, widgets, validate, validators, error_handler
|
||||
|
||||
import ldap
|
||||
|
||||
from fas.fasLDAP import UserAccount
|
||||
from fas.fasLDAP import Person
|
||||
from fas.fasLDAP import Groups
|
||||
from fas.fasLDAP import UserGroup
|
||||
|
||||
from fas.auth import isAdmin, canAdminGroup, canSponsorGroup, canEditUser
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
from fas.user import knownUser
|
||||
|
||||
class knownGroup(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
g = Groups.groups(groupName)
|
||||
if g:
|
||||
raise validators.Invalid(_("The group '%s' already exists") % value, value, state)
|
||||
|
||||
class unknownGroup(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
g = Groups.groups(groupName)
|
||||
if not g:
|
||||
raise validators.Invalid(_("The group '%s' does not exist") % value, value, state)
|
||||
|
||||
class createGroup(widgets.WidgetsList):
|
||||
groupName = widgets.TextField(label=_('Group Name'), validator=validators.All(knownGroup(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupDesc = widgets.TextField(label=_('Description'), validator=validators.NotEmpty)
|
||||
fedoraGroupOwner = widgets.TextField(label=_('Group Owner'), validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupNeedsSponsor = widgets.CheckBox(label=_('Needs Sponsor'))
|
||||
fedoraGroupUserCanRemove = widgets.CheckBox(label=_('Self Removal'))
|
||||
fedoraGroupJoinMsg = widgets.TextField(label=_('Group Join Message'))
|
||||
|
||||
createGroupForm = widgets.ListForm(fields=createGroup(), submit_text=_('Create'))
|
||||
|
||||
class editGroup(widgets.WidgetsList):
|
||||
groupName = widgets.HiddenField(validator=validators.All(unknownGroup(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupDesc = widgets.TextField(label=_('Description'), validator=validators.NotEmpty)
|
||||
fedoraGroupOwner = widgets.TextField(label=_('Group Owner'), validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
fedoraGroupNeedsSponsor = widgets.CheckBox(label=_('Needs Sponsor'))
|
||||
fedoraGroupUserCanRemove = widgets.CheckBox(label=_('Self Removal'))
|
||||
fedoraGroupJoinMsg = widgets.TextField(label=_('Group Join Message'))
|
||||
|
||||
editGroupForm = widgets.ListForm(fields=editGroup(), submit_text=_('Update'))
|
||||
|
||||
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))
|
||||
groupName = widgets.HiddenField(validator=validators.String(not_empty=True))
|
||||
|
||||
findUserForm = widgets.ListForm(fields=findUser(), submit_text=_('Invite'))
|
||||
|
||||
class Group(controllers.Controller):
|
||||
|
||||
def __init__(self):
|
||||
'''Create a Group Controller.'''
|
||||
|
||||
def index(self):
|
||||
'''Perhaps show a nice explanatory message about groups here?'''
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.group.view")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def view(self, groupName):
|
||||
'''View group'''
|
||||
# FIXME: Cleaner checks
|
||||
try:
|
||||
groups = Groups.byGroupName(groupName, includeUnapproved=True)
|
||||
except KeyError:
|
||||
raise ValueError, _('Group: %s - Does not exist!') % groupName
|
||||
try:
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
except TypeError:
|
||||
raise ValueError, _('Group: %s - Does not exist!') % groupName
|
||||
userName = turbogears.identity.current.user_name
|
||||
try:
|
||||
myStatus = groups[userName].fedoraRoleStatus
|
||||
except KeyError:
|
||||
# Not in group
|
||||
myStatus = 'Not a Member' # This has say 'Not a Member'
|
||||
except TypeError:
|
||||
groups = {}
|
||||
try:
|
||||
me = groups[userName]
|
||||
except:
|
||||
me = UserGroup()
|
||||
#searchUserForm.groupName.display('group')
|
||||
#findUser.groupName.display(value='fff')
|
||||
value = {'groupName': group.cn}
|
||||
groups = sorted(groups.items(), key=itemgetter(0))
|
||||
return dict(userName=userName, groups=groups, group=group, me=me, value=value)
|
||||
|
||||
@expose(template="fas.templates.group.new")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def new(self, groupName):
|
||||
'''Create a group'''
|
||||
return dict()
|
||||
|
||||
#@validate(form=createGroupForm)
|
||||
@expose(template="fas.templates.group.new")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def create(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor=True, fedoraGroupUserCanRemove=True, fedoraGroupJoinMsg=""):
|
||||
userName = turbogears.identity.current.user_name
|
||||
if not isAdmin(userName):
|
||||
turbogears.flash(_('Only FAS adminstrators can create groups.'))
|
||||
# TODO: Create a general access denied/error page.
|
||||
turbogears.redirect('/')
|
||||
try:
|
||||
Groups.newGroup(groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupJoinMsg)
|
||||
turbogears.flash(_("The group: '%s' has been created.") % groupName)
|
||||
turbogears.redirect('/group/view/%s', groupName)
|
||||
except:
|
||||
turbogears.flash(_("The group: '%s' could not be created.") % groupName)
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.group.edit")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def edit(self, groupName):
|
||||
'''Edit a group'''
|
||||
#TODO: Handle the "no such group" case (or maybe create
|
||||
#a generic function to check user/group existence.
|
||||
userName = turbogears.identity.current.user_name
|
||||
if not canAdminGroup(userName, groupName):
|
||||
turbogears.flash(_('You cannot edit %s') % groupName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
value = {'groupName': groupName,
|
||||
'fedoraGroupOwner': group.fedoraGroupOwner,
|
||||
'fedoraGroupType': group.fedoraGroupType,
|
||||
'fedoraGroupNeedsSponsor': (group.fedoraGroupNeedsSponsor.upper() == 'TRUE'),
|
||||
'fedoraGroupUserCanRemove': (group.fedoraGroupUserCanRemove.upper() == 'TRUE'),
|
||||
'fedoraGroupJoinMsg': group.fedoraGroupJoinMsg,
|
||||
'fedoraGroupDesc': group.fedoraGroupDesc, }
|
||||
#'fedoraGroupRequires': group.fedoraGroupRequires, }
|
||||
return dict(value=value)
|
||||
|
||||
#@validate(form=editGroupForm)
|
||||
@expose(template="fas.templates.group.edit")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def save(self, stuff):
|
||||
#TODO
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.group.list")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def list(self, search='*'):
|
||||
groups = Groups.groups(search)
|
||||
userName = turbogears.identity.current.user_name
|
||||
myGroups = Groups.byUserName(userName)
|
||||
try:
|
||||
groups.keys()
|
||||
except:
|
||||
turbogears.flash(_("No Groups found matching '%s'") % search)
|
||||
groups = {}
|
||||
groups = sorted(groups.items(), key=itemgetter(0))
|
||||
return dict(groups=groups, search=search, myGroups=myGroups)
|
||||
|
||||
# TODO: Validate
|
||||
@expose(template='fas.templates.group.view')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def apply(self, groupName, userName):
|
||||
try:
|
||||
Groups.apply(groupName, userName)
|
||||
except ldap.ALREADY_EXISTS:
|
||||
turbogears.flash(_('%(user)s is already in %(group)s!') % {'user': userName, 'group': groupName})
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
else:
|
||||
turbogears.flash(_('%(user)s has applied to %(group)s!') % {'user': userName, 'group': groupName})
|
||||
turbogears.redirect('/group/view/%s' % group.cn)
|
||||
|
||||
# TODO: Validate (user doesn't exist case)
|
||||
@expose(template='fas.templates.group.view')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def sponsor(self, groupName, userName):
|
||||
'''Sponsor user'''
|
||||
sponsor = turbogears.identity.current.user_name
|
||||
if not canSponsorGroup(sponsor, groupName):
|
||||
turbogears.flash(_("You are not a sponsor for '%s'") % groupName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
try:
|
||||
group = Groups.groups(groupName)[groupName]
|
||||
except KeyError:
|
||||
turbogears.flash(_('Group Error: %s does not exist.') % groupName)
|
||||
# The following line is kind of pointless- any suggestions?
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
p = Person.byUserName(userName)
|
||||
g = Groups.byGroupName(groupName, includeUnapproved=True)
|
||||
# TODO: Check if the person actually applied to the group.
|
||||
p.sponsor(groupName, sponsor)
|
||||
turbogears.flash(_('%s has been sponsored!') % p.cn)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
|
||||
# TODO: Validate (user doesn't exist case)
|
||||
@expose(template='fas.templates.group.view')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def remove(self, groupName, userName):
|
||||
'''Remove user from group'''
|
||||
# TODO: Add confirmation?
|
||||
sponsor = turbogears.identity.current.user_name
|
||||
if not canSponsorGroup(sponsor, groupName) \
|
||||
and sponsor != userName: # Users can remove themselves
|
||||
turbogears.flash(_("You are not a sponsor for '%s'") % groupName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
if canAdminGroup(userName, groupName) \
|
||||
and (not canAdminGroup(sponsor, groupName)):
|
||||
turbogears.flash(_('Sponsors cannot remove administrators.') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
try:
|
||||
Groups.remove(groupName, userName)
|
||||
except TypeError:
|
||||
turbogears.flash(_('%(name)s could not be removed from %(group)s!') % {'name': userName, 'group': groupName})
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
else:
|
||||
turbogears.flash(_('%(name)s has been removed from %(group)s!') % {'name': userName, 'group': groupName})
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
return dict()
|
||||
|
||||
# TODO: Validate (user doesn't exist case)
|
||||
@expose(template='fas.templates.group.view')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def upgrade(self, groupName, userName):
|
||||
'''Upgrade user in group'''
|
||||
sponsor = turbogears.identity.current.user_name
|
||||
if not canSponsorGroup(sponsor, groupName):
|
||||
turbogears.flash(_("You are not a sponsor for '%s'") % groupName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
# This is already checked in fasLDAP.py
|
||||
#if canAdminGroup(userName, groupName):
|
||||
# turbogears.flash(_('Group administators cannot be upgraded any further.'))
|
||||
# turbogears.redirect('/group/view/%s' % groupName)
|
||||
elif canSponsorGroup(userName, groupName) \
|
||||
and (not canAdminGroup(sponsor, groupName)):
|
||||
turbogears.flash(_('Sponsors cannot upgrade other sponsors.') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
p = Person.byUserName(userName)
|
||||
try:
|
||||
p.upgrade(groupName)
|
||||
except:
|
||||
turbogears.flash(_('%(name)s could not be upgraded!') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
turbogears.flash(_('%s has been upgraded!') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
|
||||
# TODO: Validate (user doesn't exist case)
|
||||
@expose(template='fas.templates.group.view')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def downgrade(self, groupName, userName):
|
||||
'''Upgrade user in group'''
|
||||
sponsor = turbogears.identity.current.user_name
|
||||
if not canSponsorGroup(sponsor, groupName):
|
||||
turbogears.flash(_("You are not a sponsor for '%s'") % groupName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
if canAdminGroup(userName, groupName) \
|
||||
and (not canAdminGroup(sponsor, groupName)):
|
||||
turbogears.flash(_('Sponsors cannot downgrade group administrators.') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
p = Person.byUserName(userName)
|
||||
try:
|
||||
p.upgrade(groupName)
|
||||
except:
|
||||
turbogears.flash(_('%(name)s could not be downgraded!') % userName)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
turbogears.flash(_('%s has been downgraded!') % p.cn)
|
||||
turbogears.redirect('/group/view/%s' % groupName)
|
||||
|
||||
# TODO: Validate (group doesn't exist case)
|
||||
@expose(template="genshi-text:fas.templates.group.dump", content_type='text/plain; charset=utf-8')
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def dump(self, groupName=None):
|
||||
groups = Groups.byGroupName(groupName)
|
||||
groups = sorted(groups.items(), key=itemgetter(0))
|
||||
return dict(groups=groups, Person=Person)
|
||||
|
|
@ -407,30 +407,29 @@ pre
|
|||
font-size: 3ex;
|
||||
}
|
||||
|
||||
form ul
|
||||
form
|
||||
{
|
||||
list-style: none;
|
||||
margin: 1ex 0!important;
|
||||
}
|
||||
|
||||
form ul li
|
||||
form .field
|
||||
{
|
||||
margin: 0 0 1ex;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
form ul label
|
||||
form .field label
|
||||
{
|
||||
float: left;
|
||||
clear: left;
|
||||
width: 16ex;
|
||||
text-align: right;
|
||||
margin: 0;
|
||||
padding: 0 2ex 0 0;
|
||||
}
|
||||
|
||||
form ul input, form ul textarea
|
||||
form .field input, form .field textarea
|
||||
{
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#">
|
||||
<body>
|
||||
<div py:for="user in groups">${user},${Person.byUserName(user).mail},${Person.byUserName(user).givenName},${groups[user].fedoraRoleType},0
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Edit Account</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Edit Account</h2>
|
||||
${form(action='editAccountSubmit', method='post', value=value)}
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Edit Group</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Edit Group</h2>
|
||||
${form(action='editGroupSubmit', method='post', value=value)}
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Crap!</title>
|
||||
</head>
|
||||
<body>
|
||||
${exception}
|
||||
</body>
|
||||
</html>
|
0
fas/fas/templates/group/__init__.py
Normal file
0
fas/fas/templates/group/__init__.py
Normal file
BIN
fas/fas/templates/group/__init__.pyc
Normal file
BIN
fas/fas/templates/group/__init__.pyc
Normal file
Binary file not shown.
3
fas/fas/templates/group/dump.txt
Normal file
3
fas/fas/templates/group/dump.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
#for user in groups
|
||||
${user[0].decode('utf-8')},${Person.byUserName(user[0]).mail.decode('utf-8')},${Person.byUserName(user[0]).givenName.decode('utf-8')},${user[1].fedoraRoleType.decode('utf-8')}
|
||||
#end
|
39
fas/fas/templates/group/edit.html
Normal file
39
fas/fas/templates/group/edit.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!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 Group</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Edit Group</h2>
|
||||
<form action="${tg.url('/group/save/%s' % value['groupName'])}" method="post">
|
||||
<div class="field">
|
||||
<label for="fedoraGroupDesc">Description:</label>
|
||||
<input type="text" id="fedoraGroupDesc" name="fedoraGroupDesc" value="${value['fedoraGroupDesc']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupOwner">Group Owner:</label>
|
||||
<input type="text" id="fedoraGroupOwner" name="fedoraGroupOwner" value="${value['fedoraGroupOwner']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupNeedsSponsor">Needs Sponsor:</label>
|
||||
<input py:if="value['fedoraGroupNeedsSponsor']" type="checkbox" id="fedoraGroupNeedsSponsor" name="fedoraGroupNeedsSponsor" checked="checked" />
|
||||
<input py:if="not value['fedoraGroupNeedsSponsor']" type="checkbox" id="fedoraGroupNeedsSponsor" name="fedoraGroupNeedsSponsor" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupUserCanRemove">Self Removal:</label>
|
||||
<input py:if="value['fedoraGroupUserCanRemove']" type="checkbox" id="fedoraGroupUserCanRemove" name="fedoraGroupUserCanRemove" checked="checked" />
|
||||
<input py:if="not value['fedoraGroupUserCanRemove']" type="checkbox" id="fedoraGroupUserCanRemove" name="fedoraGroupUserCanRemove" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupJoinMsg">Group Join Message:</label>
|
||||
<input type="text" id="fedoraGroupJoinMsg" name="fedoraGroupJoinMsg" value="${value['fedoraGroupJoinMsg']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="submit" value="Save!" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
44
fas/fas/templates/group/list.html
Normal file
44
fas/fas/templates/group/list.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
<!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>Groups List</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>List (${search})</h2>
|
||||
<h3>Search Groups</h3>
|
||||
<form method="get" action="${tg.url('/group/list')}">
|
||||
<p>"*" is a wildcard (Ex: "cvs*")</p>
|
||||
<div>
|
||||
<input type="text" value="${search}" name="search" size="15 "/>
|
||||
<input type="submit" value="Search" />
|
||||
</div>
|
||||
</form>
|
||||
<h3>Results</h3>
|
||||
<ul class="letters">
|
||||
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="${tg.url('/group/list/%s*' % letter)}">${letter}</a></li>
|
||||
<li><a href="${tg.url('/group/list/*')}">All</a></li>
|
||||
</ul>
|
||||
|
||||
<table py:if="groups">
|
||||
<thead>
|
||||
<tr><th>Group</th><th>Description</th><th>Status</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr py:for="group in groups">
|
||||
<td><a href="${tg.url('/group/view/%s' % group[1].cn)}">${group[1].cn}</a></td>
|
||||
<td>${group[1].fedoraGroupDesc}</td>
|
||||
<td>
|
||||
<a py:if="group[1].cn in myGroups" href="${tg.url('/group/view/%s' % group[1].cn)}">
|
||||
<span class="approved" py:if="myGroups[group[1].cn].fedoraRoleStatus.lower() == 'approved'">Approved</span>
|
||||
<span class="unapproved" py:if="myGroups[group[1].cn].fedoraRoleStatus.lower() == 'unapproved'">Unapproved</span>
|
||||
</a>
|
||||
<a py:if="group[1].cn not in myGroups" href="${tg.url('/group/view/%s' % group[1].cn)}"><span>Not a Member</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
41
fas/fas/templates/group/new.html
Normal file
41
fas/fas/templates/group/new.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!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>Create a new FAS Group</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Create a new FAS Group</h2>
|
||||
<form action="${tg.url('/group/create')}" method="post">
|
||||
<div class="field">
|
||||
<label for="groupName">Group Name:</label>
|
||||
<input type="text" id="groupName" name="groupName" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupDesc">Description:</label>
|
||||
<input type="text" id="fedoraGroupDesc" name="fedoraGroupDesc" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupOwner">Group Owner:</label>
|
||||
<input type="text" id="fedoraGroupOwner" name="fedoraGroupOwner" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupNeedsSponsor">Needs Sponsor:</label>
|
||||
<input type="checkbox" id="fedoraGroupNeedsSponsor" name="fedoraGroupNeedsSponsor" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupUserCanRemove">Self Removal:</label>
|
||||
<input type="checkbox" id="fedoraGroupUserCanRemove" name="fedoraGroupUserCanRemove" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraGroupJoinMsg">Group Join Message:</label>
|
||||
<input type="text" id="fedoraGroupJoinMsg" name="fedoraGroupJoinMsg" value="${value['fedoraGroupJoinMsg']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="submit" value="Create!" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
87
fas/fas/templates/group/view.html
Normal file
87
fas/fas/templates/group/view.html
Normal file
|
@ -0,0 +1,87 @@
|
|||
<!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 Group</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>${group.fedoraGroupDesc} (${group.cn})</h2>
|
||||
<h3>
|
||||
My Status:
|
||||
<span py:if="me.fedoraRoleStatus.lower() == 'approved'" class="approved">Approved</span>
|
||||
<span py:if="me.fedoraRoleStatus.lower() == 'unapproved'" class="unapproved">Unapproved</span>
|
||||
<span py:if="'Not a Member' in me.fedoraRoleStatus">Not a Member</span>
|
||||
</h3>
|
||||
<form py:if="'Not a Member' in me.fedoraRoleStatus" action="${tg.url('/group/apply/%s/%s' % (group.cn, userName))}">
|
||||
<div>
|
||||
<!--<input type="text" name="requestField" value="Please let me join..." />-->
|
||||
<input type="submit" value="Join!" />
|
||||
</div>
|
||||
</form>
|
||||
<a py:if="'Not a Member' not in me.fedoraRoleStatus" href="${tg.url('/group/remove/%s/%s' % (group.cn, userName))}">Remove me</a>
|
||||
<h3>Group Details <a href="${tg.url('/group/edit/%s' % group.cn)}">(edit)</a></h3>
|
||||
<div class="userbox">
|
||||
<dl>
|
||||
<dt>Name:</dt><dd>${group.cn}</dd>
|
||||
<dt>Description:</dt><dd>${group.fedoraGroupDesc}</dd>
|
||||
<dt>Owner:</dt><dd>${group.fedoraGroupOwner}</dd>
|
||||
<dt>Type:</dt><dd>${group.fedoraGroupType}</dd>
|
||||
<dt>Needs Sponsor:</dt><dd>
|
||||
<span py:if="group.fedoraGroupNeedsSponsor == 'TRUE'" py:strip="">Yes</span>
|
||||
<span py:if="group.fedoraGroupNeedsSponsor == 'FALSE'" py:strip="">No</span>
|
||||
</dd>
|
||||
<dt>Self Removal</dt><dd>
|
||||
<span py:if="group.fedoraGroupUserCanRemove == 'TRUE'" py:strip="">Yes</span>
|
||||
<span py:if="group.fedoraGroupUserCanRemove == 'FALSE'" py:strip="">No</span>
|
||||
</dd>
|
||||
<dt>Join Message:</dt><dd>${group.fedoraGroupJoinMsg}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<!--
|
||||
TODO: Implement this :)
|
||||
<h3 py:if='me.fedoraRoleStatus == "approved"'>Invite</h3>
|
||||
<span py:if='me.fedoraRoleStatus == "approved"'>${form(action='modifyGroup', value=value, method='get')}</span>
|
||||
-->
|
||||
<h3>Members</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Sponsor</th>
|
||||
<th>Date Added</th>
|
||||
<th>Date Approved</th>
|
||||
<th>Approval</th>
|
||||
<th>Role Type</th>
|
||||
<th py:if='me.fedoraRoleType == "administrator" or me.fedoraRoleType == "sponsor"'>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr py:for="user in groups">
|
||||
<td><a href="${tg.url('/user/view/%s' % user[0])}">${user[0]}</a></td>
|
||||
<td py:if='not(user[1].fedoraRoleSponsor == "None")'><a href="%{tg.url('/user/view/%s' % user[1].fedoraRoleSponsor)}">${user[1].fedoraRoleSponsor}</a></td>
|
||||
<td py:if='user[1].fedoraRoleSponsor == "None"'>${user[1].fedoraRoleSponsor}</td>
|
||||
<td>${user[1].fedoraRoleCreationDate}</td>
|
||||
<td>${user[1].fedoraRoleApprovalDate}</td>
|
||||
<td>${user[1].fedoraRoleStatus}</td>
|
||||
<td>${user[1].fedoraRoleType}</td>
|
||||
<!--<td>${user[1].fedoraRoleDomain}</td>-->
|
||||
<!-- This section includes all action items -->
|
||||
<td py:if='me.fedoraRoleType == "administrator"'>
|
||||
<a py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'" href="${tg.url('/group/sponsor/%s/%s' % (user[1].cn, user[0]))}">Sponsor</a>
|
||||
<a py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE' and user[1].fedoraRoleStatus.lower() != 'approved'" href="${tg.url('/group/sponsor/%s/%s' % (user[1].cn, user[0]))}">Approve</a>
|
||||
<a href="${tg.url('/group/remove/%s/%s' % (user[1].cn, user[0]))}">Delete</a>
|
||||
<a href="${tg.url('/group/upgrade/%s/%s' % (user[1].cn, user[0]))}">Upgrade</a>
|
||||
<a href="${tg.url('/group/downgrade/%s/%s' % (user[1].cn, user[0]))}">Downgrade</a> Suspend
|
||||
</td>
|
||||
<td py:if='me.fedoraRoleType == "sponsor" and not user[1].fedoraRoleType == "administrator"'>
|
||||
<a href="${tg.url('/group/sponsor/%s/%s' % (user[1].cn, user[0]))}" py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Sponsor</a>
|
||||
<a href="${tg.url('/group/sponsor/%s/%s' % (user[1].cn, user[0]))}" py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Approve</a>
|
||||
<a href="${tg.url('/group/remove/%s/%s' % (user[1].cn, user[0]))}">Delete</a>
|
||||
<a py:if='user[1].fedoraRoleType' href="${tg.url('/group/upgrade/%s/%s' % (user[1].cn, user[0]))}">Upgrade</a>
|
||||
<a href="${tg.url('/group/downgrade/%s/%s' % (user[1].cn, user[0]))}">Downgrade</a> Suspend
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
|
||||
py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Groups List</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>List (${search})</h2>
|
||||
<h3>Search Groups</h3>
|
||||
<form method="GET" action="${tg.url('/listGroup')}">
|
||||
<p>"*" is a wildcard (Ex: "cvs*")</p>
|
||||
<div>
|
||||
<input type="text" value="${search}" name="search" size="15 "/>
|
||||
<input type="submit" value="Search" />
|
||||
</div>
|
||||
</form>
|
||||
<h3>Results</h3>
|
||||
<ul class="letters">
|
||||
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="${tg.url('/listGroup/%s*' % letter)}">${letter}</a></li>
|
||||
<li><a href="${tg.url('/listGroup/*')}">All</a></li>
|
||||
</ul>
|
||||
|
||||
<table py:if="groups">
|
||||
<thead>
|
||||
<tr><th>Group</th><th>Description</th><th>Status</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?python
|
||||
keys = groups.keys()
|
||||
keys.sort()
|
||||
?>
|
||||
<tr py:for="group in map(groups.get, keys)">
|
||||
<td><a href="${tg.url('/viewGroup/%s' % group.cn)}">${group.cn}</a></td>
|
||||
<td>${group.fedoraGroupDesc}</td>
|
||||
<td>
|
||||
<a py:if="group.cn in myGroups" href="${tg.url('/viewGroup/%s' % group.cn)}">
|
||||
<span class="approved" py:if="myGroups[group.cn].fedoraRoleStatus.lower() == 'approved'">Approved</span>
|
||||
<span class="unapproved" py:if="myGroups[group.cn].fedoraRoleStatus.lower() == 'unapproved'">Unapproved</span>
|
||||
</a>
|
||||
<a py:if="group.cn not in myGroups" href="${tg.url('/viewGroup/%s' % group.cn)}"><span>Not a Member</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,8 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<!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>Fedora Accounts System</title>
|
||||
</head>
|
||||
|
@ -18,6 +21,5 @@
|
|||
<td>${builds.builds[build]['pubDate']}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,11 +1,14 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<!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>Invite a new community member!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Invite a new community member!</h2>
|
||||
<form method="POST">
|
||||
<form method="post">
|
||||
<div>
|
||||
To email: <input type="text" value="" name="target" /><br />
|
||||
From: ${user.mail}<br />
|
33
fas/fas/templates/login.html
Normal file
33
fas/fas/templates/login.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<!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>Login to the Fedora Accounts System</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
#content ul
|
||||
{
|
||||
list-style: square;
|
||||
margin: 1ex 3ex;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h2>Login</h2>
|
||||
<p>${message}</p>
|
||||
<form action="${previous_url}" method="post">
|
||||
<div class="field"><label for="user_name">User Name:</label> <input type="text" id="user_name" name="user_name" /></div>
|
||||
<div class="field"><label for="password">Password:</label> <input type="password" id="password" name="password" /></div>
|
||||
<div class="field">
|
||||
<input type="submit" name="login" value="Login" />
|
||||
<input py:if="forward_url" type="hidden" name="forward_url" value="${tg.url(forward_url)}" />
|
||||
<input py:for="name,value in original_parameters.items()" type="hidden" name="${name}" value="${value}" />
|
||||
</div>
|
||||
</form>
|
||||
<ul>
|
||||
<li><a href="${tg.url('/user/resetpass')}">Forgot Password?</a></li>
|
||||
<li><a href="${tg.url('/user/new')}">Sign Up</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -1,33 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Login to the Fedora Accounts System</title>
|
||||
</head>
|
||||
<style type="text/css">
|
||||
#content ul
|
||||
{
|
||||
list-style: square;
|
||||
margin: 1ex 3ex;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h2>Login</h2>
|
||||
<p>${message}</p>
|
||||
<form action="${previous_url}" method="POST">
|
||||
<ul>
|
||||
<li><label for="user_name">User Name:</label> <input type="text" id="user_name" name="user_name" /></li>
|
||||
<li><label for="password">Password:</label> <input type="password" id="password" name="password" /></li>
|
||||
<li>
|
||||
<input type="submit" name="login" value="Login" />
|
||||
<input py:if="forward_url" type="hidden" name="forward_url" value="${tg.url(forward_url)}" />
|
||||
<input py:for="name,value in original_parameters.items()" type="hidden" name="${name}" value="${value}" />
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
<ul>
|
||||
<li><a href="${tg.url('/resetPassword')}">Forgot Password?</a></li>
|
||||
<li><a href="${tg.url('/signUp')}">Sign Up</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +1,13 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<?python import sitetemplate ?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="sitetemplate">
|
||||
<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
|
||||
<title py:replace="''">Title</title>
|
||||
<!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:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
py:strip="">
|
||||
<head>
|
||||
<title>${title}</title>
|
||||
<link href="${tg.url('/static/css/style.css')}" rel="stylesheet" type="text/css" />
|
||||
<meta py:replace="item[:]"/>
|
||||
</head>
|
||||
<body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
|
||||
<body py:match="body" py:attrs="select('@*')">
|
||||
<div id="wrapper">
|
||||
<div id="head">
|
||||
<h1><a href="http://fedoraproject.org/">Fedora</a></h1>
|
||||
|
@ -36,7 +37,7 @@
|
|||
</div>
|
||||
<div id="control">
|
||||
<ul>
|
||||
<li py:if="not tg.identity.anonymous"><a href="${tg.url('/viewAccount')}">My Account</a></li>
|
||||
<li py:if="not tg.identity.anonymous"><a href="${tg.url('/user/view/%s' % tg.identity.user.user_name)}">My Account</a></li>
|
||||
<li py:if="not tg.identity.anonymous"><a href="${tg.url('/logout')}">Log Out</a></li>
|
||||
<li py:if="tg.identity.anonymous"><a href="${tg.url('/login')}">Log In</a></li>
|
||||
</ul>
|
||||
|
@ -45,17 +46,17 @@
|
|||
<div id="main">
|
||||
<div id="sidebar">
|
||||
<ul>
|
||||
<li class="first"><a href="${tg.url('/listGroup')}">Group List</a></li>
|
||||
<li py:if="'accounts' in tg.identity.groups"><a href="${tg.url('/listUser')}">User List</a></li>
|
||||
<li class="first"><a href="${tg.url('/group/list')}">Group List</a></li>
|
||||
<li py:if="'accounts' in tg.identity.groups"><a href="${tg.url('/user/list')}">User List</a></li>
|
||||
<li><a href="http://fedoraproject.org/wiki/FWN/LatestIssue">News</a></li>
|
||||
<li><a href="${tg.url('/listGroup', search='A*')}">Apply For a new Group</a></li>
|
||||
<li><a href="${tg.url('/group/list/A*')}">Apply For a new Group</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id='content'>
|
||||
<div py:if="tg_flash" class="flash">
|
||||
${tg_flash}
|
||||
</div>
|
||||
<div py:replace="[item.text]+item[:]" />
|
||||
<div py:replace="select('*|text()')" />
|
||||
</div> <!-- End main -->
|
||||
<div id="footer">
|
||||
<ul id="footlinks">
|
|
@ -1,30 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Reset Password</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Reset Password</h2>
|
||||
<div py:if="tg.identity.anonymous" py:strip="">
|
||||
<form method="post">
|
||||
<ul>
|
||||
<li><label for="userName">Username:</label> <input type="text" id="userName" name="userName" /></li>
|
||||
<li><label for="mail">Primary Email:</label> <input type="password" id="mail" name="mail" /></li>
|
||||
<li><input type="submit" value="Reset Password" /></li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
<div py:if="not tg.identity.anonymous" py:strip="">
|
||||
<p>
|
||||
New password for ${tg.identity.user.user_name}
|
||||
</p>
|
||||
<form method="post">
|
||||
<ul>
|
||||
<li><label for="password">New Password:</label> <input type="password" name="password" /></li>
|
||||
<li><label for="password">Verify Password:</label> <input type="password" name="passwordCheck" /></li>
|
||||
<li><input type="submit" /></li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Sign up for a Fedora account</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Sign up for a Fedora account</h2>
|
||||
${form(action='newAccountSubmit', method='post')}
|
||||
</body>
|
||||
</html>
|
0
fas/fas/templates/user/__init__.py
Normal file
0
fas/fas/templates/user/__init__.py
Normal file
BIN
fas/fas/templates/user/__init__.pyc
Normal file
BIN
fas/fas/templates/user/__init__.pyc
Normal file
Binary file not shown.
20
fas/fas/templates/user/changepass.html
Normal file
20
fas/fas/templates/user/changepass.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!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>Change Password</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Change Password</h2>
|
||||
<form action="${tg.url('/user/setpass')}" method="post">
|
||||
<ul>
|
||||
<div class="field"><label for="currentPassword">Current Password:</label> <input type="password" id="currentPassword" name="currentPassword" /></div>
|
||||
<div class="field"><label for="password">New Password:</label> <input type="password" id="password" name="password" /></div>
|
||||
<div class="field"><label for="passwordCheck">Confirm Password:</label> <input type="password" id="passwordCheck" name="passwordCheck" /></div>
|
||||
<div class="field"><input type="submit" value="Change Password" /></div>
|
||||
</ul>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
51
fas/fas/templates/user/edit.html
Normal file
51
fas/fas/templates/user/edit.html
Normal file
|
@ -0,0 +1,51 @@
|
|||
<!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 Account</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Edit Account</h2>
|
||||
<form action="${tg.url('/user/save/%s' % value['userName'])}" method="post">
|
||||
<div class="field">
|
||||
<label for="givenName">Full Name:</label>
|
||||
<input type="text" id="givenName" name="givenName" value="${value['givenName']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="mail">Email:</label>
|
||||
<input type="text" id="mail" name="mail" value="${value['mail']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraPersonBugzillaMail">Bugzilla Email:</label>
|
||||
<input type="text" id="fedoraPersonBugzillaMail" name="fedoraPersonBugzillaMail" value="${value['fedoraPersonBugzillaMail']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraPersonIrcNick">IRC Nick:</label>
|
||||
<input type="text" id="fedoraPersonIrcNick" name="fedoraPersonIrcNick" value="${value['fedoraPersonIrcNick']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="fedoraPersonKeyId">PGP Key:</label>
|
||||
<input type="text" id="fedoraPersonKeyId" name="fedoraPersonKeyId" value="${value['fedoraPersonKeyId']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="telephoneNumber">Telephone Number:</label>
|
||||
<input type="text" id="telephoneNumber" name="telephoneNumber" value="${value['telephoneNumber']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="postalAddress">Postal Address:</label>
|
||||
<input type="text" id="postalAddress" name="postalAddress" value="${value['postalAddress']}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="description ">Description:</label>
|
||||
<textarea id="description" name="description">
|
||||
${value['description']}
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="submit" value="Save!" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,11 +1,14 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<!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>Users List</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>List (${search})</h2>
|
||||
<form method="GET" action="${tg.url('/listUser')}">
|
||||
<form method="get" action="${tg.url('/user/list')}">
|
||||
<p>"*" is a wildcard (Ex: "cvs*")</p>
|
||||
<div>
|
||||
<input type="text" value="${search}" name="search" size="15 "/>
|
||||
|
@ -14,8 +17,8 @@
|
|||
</form>
|
||||
<h3>Results</h3>
|
||||
<ul class="letters">
|
||||
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="${tg.url('/listUser/%s*' % letter)}">${letter}</a></li>
|
||||
<li><a href="${tg.url('/listUser/*')}">All</a></li>
|
||||
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="${tg.url('/user/list/%s*' % letter)}">${letter}</a></li>
|
||||
<li><a href="${tg.url('/user/list/*')}">All</a></li>
|
||||
</ul>
|
||||
<table>
|
||||
<thead>
|
||||
|
@ -25,11 +28,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?python
|
||||
users.sort()
|
||||
?>
|
||||
<tr py:for="user in users">
|
||||
<td><a href="${tg.url('/viewAccount/%s' % user)}">${user}</a></td>
|
||||
<td><a href="${tg.url('/user/view/%s' % user)}">${user}</a></td>
|
||||
<td>
|
||||
<span py:if="claDone[user]" class="approved"> Done</span>
|
||||
<span py:if="not claDone[user]" class="unapproved"> Done</span>
|
37
fas/fas/templates/user/new.html
Normal file
37
fas/fas/templates/user/new.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
<!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>Sign up for a Fedora account</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Sign up for a Fedora account</h2>
|
||||
<form action="${tg.url('/user/create')}" method="post">
|
||||
<div class="field">
|
||||
<label for="cn">Username:</label>
|
||||
<input type="text" id="cn" name="cn" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="givenName">Full Name:</label>
|
||||
<input type="text" id="givenName" name="givenName" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="mail">Email</label>
|
||||
<input type="text" id="mail" name="mail" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="telephoneNumber">Telephone Number</label>
|
||||
<input type="text" id="telephoneNumber" name="telephoneNumber" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="postalAddress">Postal Address</label>
|
||||
<input type="text" id="postalAddress" name="postalAddress" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<input type="submit" value="Sign up!" />
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
19
fas/fas/templates/user/resetpass.html
Normal file
19
fas/fas/templates/user/resetpass.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!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>Reset Password</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Reset Password</h2>
|
||||
<form action="${tg.url('/user/sendpass')}" method="post">
|
||||
<ul>
|
||||
<div class="field"><label for="userName">Username:</label> <input type="text" id="userName" name="userName" /></div>
|
||||
<div class="field"><label for="mail">Primary Email:</label> <input type="password" id="mail" name="mail" /></div>
|
||||
<div class="field"><input type="submit" value="Reset Password" /></div>
|
||||
</ul>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +1,15 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<!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>View Account</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 class="account" py:if="personal">Your Fedora Account</h2>
|
||||
<h2 class="account" py:if="not personal">${user.givenName}'s Fedora Account</h2>
|
||||
<h3>Account Details <a href="${tg.url('/editAccount', userName=user.cn)}" py:if="personal or admin">(edit)</a></h3>
|
||||
<h3>Account Details <a href="${tg.url('/user/edit/%s' % user.cn)}" py:if="personal or admin">(edit)</a></h3>
|
||||
<div class="userbox">
|
||||
<dl>
|
||||
<dt>Account Name</dt><dd>${user.cn}</dd>
|
||||
|
@ -18,30 +21,24 @@
|
|||
<dt>Telephone Number</dt><dd>${user.telephoneNumber}</dd>
|
||||
<dt>Postal Address</dt><dd>${user.postalAddress}</dd>
|
||||
<dt>Description</dt><dd>${user.description}</dd>
|
||||
<dt>Password</dt><dd><span class="approved">Valid</span> <a href="${tg.url('/resetPassword')}" py:if="personal">(change)</a></dd>
|
||||
<dt>Password</dt><dd><span class="approved">Valid</span> <a href="${tg.url('/user/changepass')}" py:if="personal">(change)</a></dd>
|
||||
<dt>Account Status</dt><dd><span class="approved">Approved</span>, Active</dd>
|
||||
<dt>CLA</dt><dd><span py:if="claDone" class="approved">Done</span><span py:if="not claDone" class="unapproved"> Not Done</span></dd>
|
||||
</dl>
|
||||
</div>
|
||||
<h3 py:if="personal">Your Roles</h3>
|
||||
<h3 py:if="not personal">${user.givenName}'s Roles</h3>
|
||||
<?python
|
||||
keys = groups.keys()
|
||||
keys.sort()
|
||||
keysPending = groupsPending.keys()
|
||||
keysPending.sort()
|
||||
?>
|
||||
<ul class="roleslist">
|
||||
<li py:for="group in map(groups.get, keys)"><span class="team approved">${groupdata[group.cn].fedoraGroupDesc} (${group.cn})</span></li>
|
||||
<li py:for="group in map(groupsPending.get, keysPending)"><span class="team unapproved">${groupdata[group.cn].fedoraGroupDesc} (${group.cn})</span></li>
|
||||
<li py:for="group in groups"><span class="team approved">${groupdata[group[0]].fedoraGroupDesc} (${group[0]})</span></li>
|
||||
<li py:for="group in groupsPending"><span class="team unapproved">${groupdata[group[0]].fedoraGroupDesc} (${group[0]})</span></li>
|
||||
</ul>
|
||||
<ul class="actions" py:if="personal">
|
||||
<li><a href="/">(Join another project)</a></li>
|
||||
<li><a href="/">(Create a new project)</a></li>
|
||||
</ul>
|
||||
<ul id="rolespanel" py:if="personal">
|
||||
<li py:for="group in map(groups.get, keys)" class="role">
|
||||
<h4>${groupdata[group.cn].fedoraGroupDesc}</h4>, ${group.fedoraRoleType}
|
||||
<li py:for="group in groups" class="role">
|
||||
<h4>${groupdata[group[0]].fedoraGroupDesc}</h4>, ${group[1].fedoraRoleType}
|
||||
<dl>
|
||||
<dt>Status:</dt>
|
||||
<dd>
|
||||
|
@ -51,12 +48,13 @@
|
|||
<dd>
|
||||
<ul class="tools">
|
||||
<li><a href="/">Invite a New Member...</a></li>
|
||||
<li py:if="group.fedoraRoleType.lower() in ('administrator', 'sponsor')"><a href="${tg.url('/viewGroup', groupName=group.cn)}">View All Pending Group Membership Requests...</a></li>
|
||||
<li><a href="${tg.url('/viewGroup', groupName=group.cn)}">Manage Group Membership...</a></li>
|
||||
<li py:if="group.fedoraRoleType.lower() == 'administrator'"><a href="${tg.url('/editGroup', groupName=group.cn)}">Manage Group Details...</a></li>
|
||||
<li py:if="group[1].fedoraRoleType.lower() in ('administrator', 'sponsor')"><a href="${tg.url('/group/view/%s' % group[0])}">View All Pending Group Membership Requests...</a></li>
|
||||
<li><a href="${tg.url('/group/view/%s' % group[0])}">Manage Group Membership...</a></li>
|
||||
<!-- Replace with canAdminGroup, etc. -->
|
||||
<li py:if="group[1].fedoraRoleType.lower() == 'administrator'"><a href="${tg.url('/group/edit/%s' % group[0])}">Manage Group Details...</a></li>
|
||||
</ul>
|
||||
</dd>
|
||||
<div py:if="group.fedoraRoleType.lower() in ('administrator', 'sponsor')" py:strip="">
|
||||
<div py:if="group[1].fedoraRoleType.lower() in ('administrator', 'sponsor')" py:strip="">
|
||||
<dt>Queue:</dt>
|
||||
<dd>
|
||||
<ul class="queue">
|
|
@ -1,84 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
|
||||
py:extends="'master.kid'">
|
||||
<head>
|
||||
<title>Edit Group</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>${group.fedoraGroupDesc} (${group.cn})</h2>
|
||||
<h3>
|
||||
My Status:
|
||||
<span py:if="me.fedoraRoleStatus.lower() == 'approved'" class="approved">Approved</span>
|
||||
<span py:if="me.fedoraRoleStatus.lower() == 'unapproved'" class="unapproved">Unapproved</span>
|
||||
<span py:if="'Not a Member' in me.fedoraRoleStatus">Not a Member</span>
|
||||
</h3>
|
||||
<form py:if="'Not a Member' in me.fedoraRoleStatus" action="${tg.url('/applyForGroup')}">
|
||||
<div>
|
||||
<input type="hidden" name="groupName" value="${group.cn}" />
|
||||
<input type="text" name="requestField" value="Please let me join.." />
|
||||
<input type="submit" name="action" value="Join" />
|
||||
</div>
|
||||
</form>
|
||||
<a py:if="'Not a Member' not in me.fedoraRoleStatus" href="${tg.url('/applyForGroup', groupName=group.cn, action='Remove')}">Remove me</a>
|
||||
<h3>Group Details <a href="${tg.url('editGroup', groupName=group.cn)}">(edit)</a></h3>
|
||||
<div class="userbox">
|
||||
<dl>
|
||||
<dt>Name:</dt><dd>${group.cn}</dd>
|
||||
<dt>Description:</dt><dd>${group.fedoraGroupDesc}</dd>
|
||||
<dt>Owner:</dt><dd>${group.fedoraGroupOwner}</dd>
|
||||
<dt>Type:</dt><dd>${group.fedoraGroupType}</dd>
|
||||
<dt>Needs Sponsor:</dt><dd>
|
||||
<span py:if="group.fedoraGroupNeedsSponsor == 'TRUE'" py:strip="">Yes</span>
|
||||
<span py:if="group.fedoraGroupNeedsSponsor == 'FALSE'" py:strip="">No</span>
|
||||
</dd>
|
||||
<dt>Self Removal</dt><dd>
|
||||
<span py:if="group.fedoraGroupUserCanRemove == 'TRUE'" py:strip="">Yes</span>
|
||||
<span py:if="group.fedoraGroupUserCanRemove == 'FALSE'" py:strip="">No</span>
|
||||
</dd>
|
||||
<dt>Join Message:</dt><dd>${group.fedoraGroupJoinMsg}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<h3 py:if='me.fedoraRoleStatus == "approved"'>Invite</h3>
|
||||
<span py:if='me.fedoraRoleStatus == "approved"'>${searchUserForm(action='modifyGroup', value=value, method='get')}</span>
|
||||
<h3>Members</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Sponsor</th>
|
||||
<th>Date Added</th>
|
||||
<th>Date Approved</th>
|
||||
<th>Approval</th>
|
||||
<th>Role Type</th>
|
||||
<th py:if='me.fedoraRoleType == "administrator" or me.fedoraRoleType == "sponsor"'>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr py:for="user in groups">
|
||||
<td><a href="${tg.url('viewAccount/%s' % user)}">${user}</a></td>
|
||||
<td py:if='not(groups[user].fedoraRoleSponsor == "None")'><a href="%{tg.url('viewAccount/%s' % groups[user].fedoraRoleSponsor)}">${groups[user].fedoraRoleSponsor}</a></td>
|
||||
<td py:if='groups[user].fedoraRoleSponsor == "None"'>${groups[user].fedoraRoleSponsor}</td>
|
||||
<td>${groups[user].fedoraRoleCreationDate}</td>
|
||||
<td>${groups[user].fedoraRoleApprovalDate}</td>
|
||||
<td>${groups[user].fedoraRoleStatus}</td>
|
||||
<td>${groups[user].fedoraRoleType}</td>
|
||||
<!--<td>${groups[user].fedoraRoleDomain}</td>-->
|
||||
<!-- This section includes all action items -->
|
||||
<td py:if='me.fedoraRoleType == "administrator"'>
|
||||
<a py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'" href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}">Sponsor</a>
|
||||
<a py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE' and groups[user].fedoraRoleStatus.lower() != 'approved'" href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}">Approve</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='remove')}">Delete</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='upgrade')}">Upgrade</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='downgrade')}">Downgrade</a> Suspend
|
||||
</td>
|
||||
<td py:if='me.fedoraRoleType == "sponsor" and not groups[user].fedoraRoleType == "administrator"'>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}" py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Sponsor</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}" py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Approve</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='remove')}">Delete</a>
|
||||
<a py:if='groups[user].fedoraRoleType' href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='upgrade')}">Upgrade</a>
|
||||
<a href="${tg.url('/modifyGroup', groupName=groups[user].cn, userName=user, action='downgrade')}">Downgrade</a> Suspend
|
||||
<div py:if="'not' in '%s' % tg_flash and user in '%s' % tg_flash"> -- Error!</div><!-- Clean this up -->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,8 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
|
||||
<!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>Welcome to FAS2</title>
|
||||
<style type="text/css">
|
||||
|
@ -16,7 +19,7 @@
|
|||
</p>
|
||||
<ul>
|
||||
<li><a href="${tg.url('/login')}">Log In</a></li>
|
||||
<li><a href="${tg.url('/signUp')}">New Account</a></li>
|
||||
<li><a href="${tg.url('/user/new')}">New Account</a></li>
|
||||
<li><a href="http://fedoraproject.org/wiki/Join">Why Join?</a></li>
|
||||
</ul>
|
||||
</body>
|
253
fas/fas/user.py
Normal file
253
fas/fas/user.py
Normal file
|
@ -0,0 +1,253 @@
|
|||
import turbogears
|
||||
from turbogears import controllers, expose, paginate, identity, redirect, widgets, validate, validators, error_handler
|
||||
|
||||
import ldap
|
||||
|
||||
from fas.fasLDAP import UserAccount
|
||||
from fas.fasLDAP import Person
|
||||
from fas.fasLDAP import Groups
|
||||
from fas.fasLDAP import UserGroup
|
||||
|
||||
from fas.auth import isAdmin, canAdminGroup, canSponsorGroup, canEditUser
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
class knownUser(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
p = Person.byUserName(value)
|
||||
if p.cn:
|
||||
raise validators.Invalid(_("'%s' already exists") % value, value, state)
|
||||
|
||||
class unknownUser(validators.FancyValidator):
|
||||
def _to_python(self, value, state):
|
||||
return value.strip()
|
||||
def validate_python(self, value, state):
|
||||
p = Person.byUserName(value)
|
||||
if not p.cn:
|
||||
raise validators.Invalid(_("'%s' does not exist") % value, value, state)
|
||||
|
||||
class editUser(widgets.WidgetsList):
|
||||
# cn = widgets.TextField(label='Username', validator=validators.PlainText(not_empty=True, max=10))
|
||||
userName = widgets.HiddenField(validator=validators.All(unknownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
givenName = widgets.TextField(label=_('Full Name'), validator=validators.String(not_empty=True, max=42))
|
||||
mail = widgets.TextField(label=_('Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
fedoraPersonBugzillaMail = widgets.TextField(label=_('Bugzilla Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
fedoraPersonIrcNick = widgets.TextField(label=_('IRC Nick'))
|
||||
fedoraPersonKeyId = widgets.TextField(label=_('PGP Key'))
|
||||
telephoneNumber = widgets.TextField(label=_('Telephone Number'), validator=validators.PhoneNumber(not_empty=True))
|
||||
postalAddress = widgets.TextArea(label=_('Postal Address'), validator=validators.NotEmpty)
|
||||
description = widgets.TextArea(label=_('Description'))
|
||||
|
||||
editUserForm = widgets.ListForm(fields=editUser(), submit_text=_('Update'))
|
||||
|
||||
class newUser(widgets.WidgetsList):
|
||||
#cn = widgets.TextField(label='Username', validator=validators.PlainText(not_empty=True, max=10))
|
||||
cn = widgets.TextField(label=_('Username'), validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
|
||||
givenName = widgets.TextField(label=_('Full Name'), validator=validators.String(not_empty=True, max=42))
|
||||
mail = widgets.TextField(label=_('Email'), validator=validators.Email(not_empty=True, strip=True))
|
||||
telephoneNumber = widgets.TextField(label=_('Telephone Number'), validator=validators.PhoneNumber(not_empty=True))
|
||||
postalAddress = widgets.TextArea(label=_('Postal Address'), validator=validators.NotEmpty)
|
||||
|
||||
newUserForm = widgets.ListForm(fields=newUser(), submit_text=_('Sign Up'))
|
||||
|
||||
class User(controllers.Controller):
|
||||
|
||||
def __init__(self):
|
||||
'''Create a User Controller.
|
||||
'''
|
||||
|
||||
def index(self):
|
||||
'''Redirect to view
|
||||
'''
|
||||
turbogears.redirect('view/%s' % turbogears.identity.current.user_name)
|
||||
|
||||
@expose(template="fas.templates.user.view")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def view(self, userName=None):
|
||||
'''View a User.
|
||||
'''
|
||||
# TODO: Validate- check if user actually exists
|
||||
if not userName:
|
||||
userName = turbogears.identity.current.user_name
|
||||
if turbogears.identity.current.user_name == userName:
|
||||
personal = True
|
||||
else:
|
||||
personal = False
|
||||
if isAdmin(turbogears.identity.current.user_name):
|
||||
admin = True
|
||||
else:
|
||||
admin = False
|
||||
user = Person.byUserName(userName)
|
||||
groups = Groups.byUserName(userName)
|
||||
groupsPending = Groups.byUserName(userName, unapprovedOnly=True)
|
||||
groupdata={}
|
||||
for g in groups:
|
||||
groupdata[g] = Groups.groups(g)[g]
|
||||
for g in groupsPending:
|
||||
groupdata[g] = Groups.groups(g)[g]
|
||||
try:
|
||||
groups['cla_done']
|
||||
claDone=True
|
||||
except KeyError:
|
||||
claDone=None
|
||||
groups = sorted(groups.items(), key=itemgetter(0))
|
||||
groupsPending = sorted(groupsPending.items(), key=itemgetter(0))
|
||||
return dict(user=user, groups=groups, groupsPending=groupsPending, groupdata=groupdata, claDone=claDone, personal=personal, admin=admin)
|
||||
|
||||
@expose(template="fas.templates.user.edit")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def edit(self, userName=None):
|
||||
'''Edit a user
|
||||
'''
|
||||
if not userName:
|
||||
userName = turbogears.identity.current.user_name
|
||||
if not canEditUser(turbogears.identity.current.user_name, userName):
|
||||
turbogears.flash(_('You cannot edit %s') % userName )
|
||||
userName = turbogears.identity.current.user_name
|
||||
user = Person.byUserName(userName)
|
||||
value = {'userName': userName,
|
||||
'givenName': user.givenName,
|
||||
'mail': user.mail,
|
||||
'fedoraPersonBugzillaMail': user.fedoraPersonBugzillaMail,
|
||||
'fedoraPersonIrcNick': user.fedoraPersonIrcNick,
|
||||
'fedoraPersonKeyId': user.fedoraPersonKeyId,
|
||||
'telephoneNumber': user.telephoneNumber,
|
||||
'postalAddress': user.postalAddress,
|
||||
'description': user.description, }
|
||||
return dict(value=value)
|
||||
|
||||
#@validate(form=editUserForm)
|
||||
@expose(template='fas.templates.editAccount')
|
||||
def save(self, userName, givenName, mail, fedoraPersonBugzillaMail, telephoneNumber, postalAddress, fedoraPersonIrcNick='', fedoraPersonKeyId='', description=''):
|
||||
if not canEditUser(turbogears.identity.current.user_name, userName):
|
||||
turbogears.flash(_("You do not have permission to edit '%s'", userName))
|
||||
turbogears.redirect('/user/edit/%s', turbogears.identity.current.user_name)
|
||||
user = Person.byUserName(userName)
|
||||
user.__setattr__('givenName', givenName.encode('utf8'))
|
||||
user.__setattr__('mail', mail.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonBugzillaMail', fedoraPersonBugzillaMail.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonIrcNick', fedoraPersonIrcNick.encode('utf8'))
|
||||
user.__setattr__('fedoraPersonKeyId', fedoraPersonKeyId.encode('utf8'))
|
||||
user.__setattr__('telephoneNumber', telephoneNumber.encode('utf8'))
|
||||
user.__setattr__('postalAddress', postalAddress.encode('utf8'))
|
||||
user.__setattr__('description', description.encode('utf8'))
|
||||
turbogears.flash(_('Your account has been updated.'))
|
||||
turbogears.redirect("/user/view/%s" % userName)
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.user.list")
|
||||
@identity.require(turbogears.identity.in_group("accounts"))
|
||||
def list(self, search="a*"):
|
||||
'''List users
|
||||
'''
|
||||
users = Person.users(search)
|
||||
try:
|
||||
users[0]
|
||||
except:
|
||||
turbogears.flash(_("No users found matching '%s'") % search)
|
||||
users = []
|
||||
cla_done = Groups.byGroupName('cla_done')
|
||||
claDone = {}
|
||||
users.sort()
|
||||
for u in users:
|
||||
try:
|
||||
cla_done[u]
|
||||
claDone[u] = True
|
||||
except KeyError:
|
||||
claDone[u] = False
|
||||
return dict(users=users, claDone=claDone, search=search)
|
||||
|
||||
@expose(template='fas.templates.user.new')
|
||||
def new(self):
|
||||
if turbogears.identity.not_anonymous():
|
||||
turbogears.flash(_('No need to sign up, You have an account!'))
|
||||
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
||||
return dict(form=newUserForm)
|
||||
|
||||
@validate(form=newUserForm) ## TODO: Use validate everywhere
|
||||
@expose(template='fas.templates.new')
|
||||
def create(self, cn, givenName, mail, telephoneNumber, postalAddress):
|
||||
# TODO: Ensure that e-mails are unique?
|
||||
# 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.newPerson(cn.encode('utf8'),
|
||||
givenName.encode('utf8'),
|
||||
mail.encode('utf8'),
|
||||
telephoneNumber.encode('utf8'),
|
||||
postalAddress.encode('utf8'))
|
||||
p = Person.byUserName(cn.encode('utf8'))
|
||||
newpass = p.generatePassword()
|
||||
message = turbomail.Message('accounts@fedoraproject.org', p.mail, _('Fedora Project Password Reset'))
|
||||
message.plain = _("You have created a new Fedora account! Your new password is: %s \nPlease go to https://admin.fedoraproject.org/fas/ to change it") % newpass['pass']
|
||||
turbomail.enqueue(message)
|
||||
p.__setattr__('userPassword', newpass['hash'])
|
||||
turbogears.flash(_('Your password has been emailed to you. Please log in with it and change your password'))
|
||||
turbogears.redirect('/login')
|
||||
except ldap.ALREADY_EXISTS:
|
||||
turbogears.flash(_("The username '%s' already Exists. Please choose a different username.") % cn)
|
||||
turbogears.redirect('/user/new')
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.user.changepass")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def changepass(self):
|
||||
return dict()
|
||||
|
||||
#TODO: Validate
|
||||
@expose(template="fas.templates.user.changepass")
|
||||
@identity.require(turbogears.identity.not_anonymous())
|
||||
def setpass(self, currentPassword, password, passwordCheck):
|
||||
# TODO: use @validate/check password length
|
||||
userName = turbogears.identity.current.user_name
|
||||
try:
|
||||
Person.auth(userName, currentPassword)
|
||||
except AuthError:
|
||||
turbogears.flash('Your current password did not match.')
|
||||
return dict()
|
||||
p = Person.byUserName(userName)
|
||||
newpass = p.generatePassword(password)
|
||||
try:
|
||||
p.__setattr__('userPassword', newpass['hash'])
|
||||
turbogears.flash(_("Your password has been changed."))
|
||||
except:
|
||||
turbogears.flash(_("Your password could not be changed."))
|
||||
return dict()
|
||||
|
||||
@expose(template="fas.templates.user.resetpass")
|
||||
def resetpass(self):
|
||||
if turbogears.identity.not_anonymous():
|
||||
turbogears.flash(_('You are already logged in!'))
|
||||
turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name)
|
||||
return dict()
|
||||
|
||||
# TODO: Validate
|
||||
@expose(template="fas.templates.user.resetpass")
|
||||
def sendpass(self, userName, mail):
|
||||
# TODO: Do validation and check the password is long enough
|
||||
import turbomail
|
||||
# Logged in
|
||||
if turbogears.identity.current.user_name:
|
||||
turbogears.flash(_("You are already logged in."))
|
||||
turbogears.redirect('/user/view/%s', turbogears.identity.current.user_name)
|
||||
p = Person.byUserName(userName)
|
||||
if userName and mail:
|
||||
if not mail == p.mail:
|
||||
turbogears.flash(_("username + email combo unknown."))
|
||||
return dict()
|
||||
newpass = p.generatePassword()
|
||||
message = turbomail.Message('accounts@fedoraproject.org', p.mail, _('Fedora Project Password Reset'))
|
||||
message.plain = _("You have requested a password reset! Your new password is - %s \nPlease go to https://admin.fedoraproject.org/fas/ to change it") % newpass['pass']
|
||||
turbomail.enqueue(message)
|
||||
try:
|
||||
p.__setattr__('userPassword', newpass['hash'])
|
||||
turbogears.flash(_('Your new password has been emailed to you.'))
|
||||
turbogears.redirect('/login')
|
||||
except:
|
||||
turbogears.flash(_('Your password could not be reset.'))
|
||||
return dict()
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue