I'm not sure if there's a patch review procedure for FAS, so rather than dumping this in a ticket I've elected to post it here. If a ticket would be better, please let me know. After wishing for some time that we could make the packager group closed to applications by users, I went ahead and (with help from Ricky and Toshio) set up a local FAS instance and hacked up the following patch. All it does is provide an additional group property, invite_only, with the necessary interface to view and change it, along with a help string. When set, the "Apply" links and buttons are hidden. This is just a first-pass hack from someone who doesn't know what they're doing. It might not be enough to just hide the links, but it's a start. I'm not really satisfied with how long the extra conditionals make some of the bits in the templates, and I'm not sure it's good interface policy to leave the position in the group list completely blank when the user is not a member and the group is invite only. (I don't know how to do nested conditionals in genshi, if that's even possible, so....) I included a change to the README file which would have smoothed the setup process a bit for me, but I did not delete the sqlalchemy section. An error in the fas2.sql file was also fixed (an index was being created on a column that didn't exist). Suggestions welcome. Commit if you like. None of this warrants copyright on any of the files. I removed my local fas.cfg changes so the diffstat is wrong. - J< README | 4 ++-- fas.cfg | 14 +++++++------- fas/group.py | 5 +++-- fas/help.py | 1 + fas/templates/group/edit.html | 6 ++++++ fas/templates/group/list.html | 4 ++-- fas/templates/group/members.html | 2 +- fas/templates/group/view.html | 6 +++++- fas2.sql | 2 +- 9 files changed, 28 insertions(+), 16 deletions(-) diff --git a/README b/README index db648e7..da61da3 100644 --- a/README +++ b/README @@ -82,14 +82,14 @@ Before you can get started, make sure to have the following packages installed yum install git-core postgresql-plpython postgresql-server postgresql-python \ python-TurboMail TurboGears pygpgme python-sqlalchemy python-genshi \ python-psycopg2 pytz python-babel babel python-GeoIP python-openid \ - python-fedora python-migrate python-memcached python-tgcaptcha + python-fedora python-migrate python-memcached python-tgcaptcha pyOpenSSL gettext # Note: on RHEL5 you need postgresql-pl instead of postgresql-plpython yum install git-core postgresql-pl postgresql-server postgresql-python \ python-TurboMail TurboGears pygpgme python-sqlalchemy python-genshi \ python-psycopg2 pytz python-babel babel python-GeoIP python-openid \ - python-fedora python-migrate python-memcached python-tgcaptcha + python-fedora python-migrate python-memcached python-tgcaptcha pyOpenSSL gettext At present, the database needs to be a postgres database since we use triggers to manage some of the data (like syncing accounts with bugzilla). diff --git a/fas/group.py b/fas/group.py index cda2265..6c6cd52 100644 --- a/fas/group.py +++ b/fas/group.py @@ -290,8 +290,8 @@ class Group(controllers.Controller): @expose(template="fas.templates.group.edit") def save(self, groupname, display_name, owner, group_type, needs_sponsor=0, user_can_remove=1, prerequisite='', - url='', mailing_list='', mailing_list_url='', irc_channel='', - irc_network='', joinmsg='', apply_rules="None"): + url='', mailing_list='', mailing_list_url='', invite_only=0, + irc_channel='', irc_network='', joinmsg='', apply_rules="None"): '''Edit a group''' username = turbogears.identity.current.user_name person = People.by_username(username) @@ -316,6 +316,7 @@ class Group(controllers.Controller): group.url = url group.mailing_list = mailing_list group.mailing_list_url = mailing_list_url + group.invite_only = invite_only group.irc_channel = irc_channel group.irc_network = irc_network group.joinmsg = joinmsg diff --git a/fas/help.py b/fas/help.py index 41acde2..09b88c1 100644 --- a/fas/help.py +++ b/fas/help.py @@ -54,6 +54,7 @@ class Help(controllers.Controller): 'group_url': [_('Group URL (Optional)'), _('''<p>A URL or wiki page for the group (for example, <a href="https://fedoraproject.org/wiki/Infrastructure">https://fedoraproject.org/wiki/Infrastructure</a>).</p>''')], 'group_mailing_list': [_('Group Mailing List (Optional)'), _('''<p>A mailing list for the group (for example, fedora-infrastructure-list@xxxxxxxxxx).</p>''')], 'group_mailing_list_url': [_('Group Mailing List URL (Optional)'), _('''<p>A URL for the group's mailing list (for example, <a href="http://www.redhat.com/mailman/listinfo/fedora-infrastructure-list">http://www.redhat.com/mailman/listinfo/fedora-infrastructure-list</a>).</p>''')], + 'group_invite_only': [_('Invite Only'), _('''<p>If users should not normally be able to apply to the group, setting this will hide the usual "Apply!" links and buttons. Users can still be added to a group directly by an admin or sponsor.</p>''')], 'group_irc_channel': [_('Group IRC Channel (Optional)'), _('''<p>An IRC channel for the group (for example, #fedora-admin).</p>''')], 'group_irc_network': [_('Group IRC Network (Optional)'), _('''<p>The IRC Network for the group's IRC channel (for example, Freenode).</p>''')], 'group_needs_sponsor': [_('Needs Sponsor'), _('''<p>If your group requires sponsorship (recommended), this means that when a user is approved by a sponsor. That relationship is recorded in the account system. If user A sponsors user N, then in viewing the members of this group, people will know to contact user A about user N if something goes wrong. If this box is unchecked, this means that only approval is needed and no relationship is recorded about who did the approving</p>''')], diff --git a/fas/templates/group/edit.html b/fas/templates/group/edit.html index 2ab9b33..2dcbcc4 100644 --- a/fas/templates/group/edit.html +++ b/fas/templates/group/edit.html @@ -50,6 +50,12 @@ <script type="text/javascript">var group_owner = new HelpBalloon({dataURL: '${tg.url('/help/get_help/group_owner')}'});</script> </div> <div class="field"> + <label for="invite_only">${_('Invite Only:')}</label> + <input py:if="group.invite_only" type="checkbox" id="invite_only" name="invite_only" value="1" checked="checked" /> + <input py:if="not group.invite_only" type="checkbox" id="invite_only" name="invite_only" value="1" /> + <script type="text/javascript">var group_invite_only = new HelpBalloon({dataURL: '${tg.url('/help/get_help/group_invite_only')}'});</script> + </div> + <div class="field"> <label for="needs_sponsor">${_('Needs Sponsor:')}</label> <input py:if="group.needs_sponsor" type="checkbox" id="needs_sponsor" name="needs_sponsor" value="1" checked="checked" /> <input py:if="not group.needs_sponsor" type="checkbox" id="needs_sponsor" name="needs_sponsor" value="1" /> diff --git a/fas/templates/group/list.html b/fas/templates/group/list.html index 9c45055..99f1e18 100644 --- a/fas/templates/group/list.html +++ b/fas/templates/group/list.html @@ -40,8 +40,8 @@ <span class="approved" py:if="group in person.approved_memberships">${_('Approved')}</span> <span class="unapproved" py:if="group in person.unapproved_memberships">${_('Unapproved')}</span> </a> - <a py:if="group not in person.memberships" href="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"><span>${_('Apply')}</span></a> - <script py:if="group not in person.memberships" type="text/javascript">var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/group_apply')}'});</script> + <a py:if="not group.invite_only and group not in person.memberships" href="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"><span>${_('Apply')}</span></a> + <script py:if="not group.invite_only and group not in person.memberships" type="text/javascript">var hb1 = new HelpBalloon({dataURL: '${tg.url('/help/get_help/group_apply')}'});</script> </td> </tr> </tbody> diff --git a/fas/templates/group/members.html b/fas/templates/group/members.html index 0339ebb..d13b41d 100644 --- a/fas/templates/group/members.html +++ b/fas/templates/group/members.html @@ -25,7 +25,7 @@ <span py:if="group in person.memberships and not group in person.approved_memberships" class="unapproved">${_('Unapproved')}</span> <span py:if="not group in person.memberships">${_('Not a Member')}</span> </h3> - <form py:if="not group in person.memberships" action="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"> + <form py:if="not group.invite_only and not group in person.memberships" action="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"> <div> <!--<input type="text" name="requestField" value="${_('Please let me join...')}" />--> <input type="submit" value="${('Apply!')}" /> diff --git a/fas/templates/group/view.html b/fas/templates/group/view.html index 62f7f22..17629af 100644 --- a/fas/templates/group/view.html +++ b/fas/templates/group/view.html @@ -23,7 +23,7 @@ <span py:if="group in person.memberships and not group in person.approved_memberships" class="unapproved">${_('Unapproved')}</span> <span py:if="not group in person.memberships">${_('Not a Member')}</span> </h3> - <form py:if="not group in person.memberships" action="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"> + <form py:if="not group.invite_only and not group in person.memberships" action="${tg.url('/group/application_screen/%s/%s' % (group.name, person.username))}"> <div> <!--<input type="text" name="requestField" value="${_('Please let me join...')}" />--> <input type="submit" value="${('Apply!')}" /> @@ -61,6 +61,10 @@ </dd> </py:if> + <dt>${_('Invite Only:')}</dt><dd> + <py:if test="group.invite_only">${_('Yes')}</py:if> + <py:if test="not group.invite_only">${_('No')}</py:if> + </dd> <dt>${_('Needs Sponsor:')}</dt><dd> <py:if test="group.needs_sponsor">${_('Yes')}</py:if> <py:if test="not group.needs_sponsor">${_('No')}</py:if> diff --git a/fas2.sql b/fas2.sql index c91cb19..d55be60 100644 --- a/fas2.sql +++ b/fas2.sql @@ -110,6 +110,7 @@ CREATE TABLE groups ( group_type VARCHAR(16), needs_sponsor BOOLEAN DEFAULT FALSE, user_can_remove BOOLEAN DEFAULT TRUE, + invite_only BOOLEAN DEFAULT FALSE, prerequisite_id INTEGER REFERENCES groups(id), joinmsg TEXT NULL DEFAULT '', apply_rules TEXT, @@ -120,7 +121,6 @@ CREATE TABLE groups ( ); create index groups_group_type_idx on groups(group_type); -create index groups_email_idx on groups(email); cluster groups_group_type_idx on groups; CREATE TABLE person_roles ( _______________________________________________ infrastructure mailing list infrastructure@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/infrastructure