import traceback from typing import Union, List from zope import component from ..AbstractTransaction import AbstractTransaction from ceo_common.errors import UserAlreadySubscribedError from ceo_common.interfaces import IConfig, IMailService from ceo_common.logger_factory import logger_factory from ceod.model import User, Group import ceod.utils as utils logger = logger_factory(__name__) class AddMemberTransaction(AbstractTransaction): """Transaction to add a new club member.""" operations = [ 'add_user_to_ldap', 'add_group_to_ldap', 'add_user_to_kerberos', 'create_home_dir', 'set_forwarding_addresses', 'send_welcome_message', 'subscribe_to_mailing_list', 'announce_new_user', ] def __init__( self, uid: str, cn: str, given_name: str, sn: str, program: Union[str, None] = None, terms: Union[List[str], None] = None, non_member_terms: Union[List[str], None] = None, forwarding_addresses: Union[List[str], None] = None, ): super().__init__() cfg = component.getUtility(IConfig) self.uid = uid self.cn = cn self.given_name = given_name self.sn = sn self.program = program self.terms = terms self.non_member_terms = non_member_terms self.forwarding_addresses = forwarding_addresses self.user = None self.group = None self.new_member_list = cfg.get('mailman3_new_member_list') self.mail_srv = component.getUtility(IMailService) def child_execute_iter(self): user = User( uid=self.uid, cn=self.cn, given_name=self.given_name, sn=self.sn, program=self.program, terms=self.terms, non_member_terms=self.non_member_terms, ) self.user = user user.add_to_ldap() yield 'add_user_to_ldap' group = Group( cn=user.uid, gid_number=user.gid_number, ) self.group = group group.add_to_ldap() yield 'add_group_to_ldap' password = utils.gen_password() user.add_to_kerberos(password) yield 'add_user_to_kerberos' user.create_home_dir() yield 'create_home_dir' if self.forwarding_addresses: user.set_forwarding_addresses(self.forwarding_addresses) yield 'set_forwarding_addresses' # The following operations can't/shouldn't be rolled back because the # user has already seen the email try: self.mail_srv.send_welcome_message_to(user, password) yield 'send_welcome_message' except Exception as err: logger.warning('send_welcome_message failed:\n' + traceback.format_exc()) yield 'failed_to_send_welcome_message: ' + str(err) # don't subscribe club reps to csc-general if self.terms: try: user.subscribe_to_mailing_list(self.new_member_list) yield 'subscribe_to_mailing_list' except UserAlreadySubscribedError: pass except Exception as err: logger.warning('subscribe_to_mailing_list failed:\n' + traceback.format_exc()) yield 'failed_to_subscribe_to_mailing_list: ' + str(err) try: self.mail_srv.announce_new_user(user, self.finished_operations) yield 'announce_new_user' except Exception as err: logger.warning('announce_new_user failed:\n' + traceback.format_exc()) yield 'failed_to_announce_new_user: ' + str(err) user_json = user.to_dict(True) # insert the password into the JSON so that the client can see it user_json['password'] = password self.finish(user_json) def rollback(self): if 'create_home_dir' in self.finished_operations: self.user.delete_home_dir() if 'add_user_to_kerberos' in self.finished_operations: self.user.remove_from_kerberos() if 'add_group_to_ldap' in self.finished_operations: self.group.remove_from_ldap() if 'add_user_to_ldap' in self.finished_operations: self.user.remove_from_ldap()