import datetime import os import re import subprocess from unittest.mock import patch from ceo_common.model import Term import ceo_common.utils from tests.utils import create_php_file_for_club def create_website_config_for_club(sites_available_dir, cn, filename=None): if filename is None: filename = f'club-{cn}.conf' filepath = os.path.join(sites_available_dir, filename) with open(filepath, 'w') as fo: fo.write(f""" ServerName {cn}.uwaterloo.internal ServerAdmin {cn}@{cn}.uwaterloo.internal DocumentRoot /users/{cn}/www/ """) def get_enabled_sites(webhosting_srv): return [ club_name for club_name, club_info in webhosting_srv.clubs.items() if not club_info['disabled'] ] def test_disable_club_sites(webhosting_srv, webhosting_srv_resources, new_club_gen): sites_available_dir = webhosting_srv.sites_available_dir with new_club_gen() as group1, new_club_gen() as group2: create_website_config_for_club(sites_available_dir, group1.cn) create_website_config_for_club(sites_available_dir, group2.cn, 'club-somerandomname.conf') with webhosting_srv.begin_transaction(): enabled_clubs = get_enabled_sites(webhosting_srv) assert sorted(enabled_clubs) == [group1.cn, group2.cn] webhosting_srv.disable_club_site(group1.cn) # Make sure that if we don't call commit(), nothing gets saved with webhosting_srv.begin_transaction(): enabled_clubs = get_enabled_sites(webhosting_srv) assert sorted(enabled_clubs) == [group1.cn, group2.cn] webhosting_srv.disable_club_site(group1.cn) webhosting_srv.commit() # Now that we committed the changes, they should be persistent with webhosting_srv.begin_transaction(): enabled_clubs = get_enabled_sites(webhosting_srv) assert enabled_clubs == [group2.cn] def test_disable_inactive_club_sites( cfg, webhosting_srv, webhosting_srv_resources, g_admin_ctx, new_club_gen, new_user_gen, mock_mail_server, ): sites_available_dir = webhosting_srv.sites_available_dir term = Term.current() clubs_home = cfg.get('clubs_home') with patch.object(ceo_common.utils, 'get_current_datetime') as now_mock: now_mock.return_value = datetime.datetime.now() with new_club_gen() as group1, \ new_club_gen() as group2, \ new_user_gen() as user1, \ new_user_gen() as user2: create_website_config_for_club(sites_available_dir, group1.cn) create_website_config_for_club(sites_available_dir, group2.cn) create_php_file_for_club(clubs_home, group1.cn) with g_admin_ctx(): # group1 has no club reps so it should be disabled # group2 has no club reps but it doesn't use PHP assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [group1.cn] user1.add_non_member_terms([str(Term.current())]) group1.add_member(user1.uid) with g_admin_ctx(): # group1 has an active club rep, so it shouldn't be disabled anymore assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [] now_mock.return_value = (term + 3).to_datetime() with g_admin_ctx(): # club reps are allowed to be inactive for up to 3 terms assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [] now_mock.return_value = (term + 4).to_datetime() with g_admin_ctx(): # club site should be disabled now that club rep is inactive assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [group1.cn] user2.add_non_member_terms([str(Term.current())]) group1.add_member(user2.uid) with g_admin_ctx(): # group1 has a new club rep, so it shouldn't be disabled anymore assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [] create_php_file_for_club(clubs_home, group2.cn) group2.add_member(user2.uid) with g_admin_ctx(): # user2 is an active club rep for both group1 and group2 assert webhosting_srv.disable_sites_for_inactive_clubs(dry_run=True) == [] now_mock.return_value = (term + 8).to_datetime() mock_mail_server.messages.clear() subprocess.run(['git', 'init'], cwd=webhosting_srv.apache_dir, check=True) with g_admin_ctx(): disabled_sites = webhosting_srv.disable_sites_for_inactive_clubs() # user2 expired and both sites use PHP, so they should both be disabled assert sorted(disabled_sites) == [group1.cn, group2.cn] # since each club had a ServerAdmin directive, they should both have received # notification emails assert len(mock_mail_server.messages) == 2 with open(webhosting_srv.conf_available_dir + '/disable-club.conf') as fi: disable_club_conf_content = fi.read() print(disable_club_conf_content) for group in [group1, group2]: pat = re.compile( ( rf'^\n' r'\s*Include snippets/disable-club\.conf\n' r'$' ), re.MULTILINE ) assert pat.search(disable_club_conf_content) is not None with g_admin_ctx(): # Club sites should only be disabled once assert webhosting_srv.disable_sites_for_inactive_clubs() == [] mock_mail_server.messages.clear() def test_remove_inactive_club_reps( cfg, webhosting_srv, webhosting_srv_resources, g_admin_ctx, new_club_gen, new_user_gen, ldap_srv_session, ): term = Term.current() clubs_home = cfg.get('clubs_home') with patch.object(ceo_common.utils, 'get_current_datetime') as now_mock: now_mock.return_value = datetime.datetime.now() with new_club_gen() as group, \ new_user_gen() as user1, \ new_user_gen() as user2: create_php_file_for_club(clubs_home, group.cn) for user in [user1, user2]: user.add_non_member_terms([str(Term.current())]) group.add_member(user.uid) now_mock.return_value = (term + 4).to_datetime() with g_admin_ctx(): webhosting_srv.disable_sites_for_inactive_clubs(remove_inactive_club_reps=True) group = ldap_srv_session.get_group(group.cn) assert group.members == [] # Make sure that inactive club reps get removed even if the site # has already been disabled group.add_member(user1.uid) with g_admin_ctx(): webhosting_srv.disable_sites_for_inactive_clubs(remove_inactive_club_reps=True) group = ldap_srv_session.get_group(group.cn) assert group.members == []