def email_rt_delete(self, operator, queuename): """ Delete RT list. """ queue, host = self._resolve_rt_name(queuename) rt_dom = self._get_email_domain_from_str(host) self.ba.can_rt_delete(operator.get_entity_id(), domain=rt_dom) et = Email.EmailTarget(self.db) ea = Email.EmailAddress(self.db) epat = Email.EmailPrimaryAddressTarget(self.db) result = [] for target_id in self.__get_all_related_rt_targets(queuename): try: et.clear() et.find(target_id) except Errors.NotFoundError: continue epat.clear() try: epat.find(et.entity_id) except Errors.NotFoundError: pass else: epat.delete() for r in et.get_addresses(): addr = '%(local_part)s@%(domain)s' % r ea.clear() ea.find_by_address(addr) ea.delete() result.append({'address': addr}) et.delete() return result
def _get_person_owner_attributes(self, owner): """Return a dict with person tidbits for LDAP. FIXME: THIS MUST NOT FAIL with NotFoundError. """ def extract_email_from_account(account_id): try: et = Email.EmailTarget(self._db) et.find_by_target_entity(account_id) return [ "%s@%s" % (r['local_part'], r['domain']) for r in et.get_addresses(special=False) ] except Errors.NotFoundError: return [] # end extract_email_from_account result = dict() # uid try: account_id = owner.get_primary_account() acc = Factory.get("Account")(self._db) acc.find(account_id) result["uid"] = acc.account_name except Errors.NotFoundError: result["uid"] = None # ALL unames must go into 'voipSipUri'. And so must all e-mail # addresses. result["voipSipUri"] = list() for row in acc.search(owner_id=owner.entity_id): result["voipSipUri"].append(self._voipify(row["name"], None)) for address in extract_email_from_account(row["account_id"]): mangled = self._voipify(address, None) result["voipSipUri"].append(mangled) # mail - primary e-mail address. if result['uid']: try: et = Email.EmailTarget(self._db) et.find_by_target_entity(acc.entity_id) epat = Email.EmailPrimaryAddressTarget(self._db) epat.find(et.entity_id) ea = Email.EmailAddress(self._db) ea.find(epat.get_address_id()) result["mail"] = ea.get_address() except Errors.NotFoundError: result["mail"] = None # cn - grab system cached try: p_name = owner.get_name( self.const.system_cached, getattr(self.const, cereconf.DEFAULT_GECOS_NAME)) except Errors.NotFoundError: p_name = None result["cn"] = p_name return result
def _create_distgroup_mailaddr(self, et): ea = Email.EmailAddress(self._db) # move this to a variable # no need to wash the address, group will not be created # if the name is not valid for Exchange lp = "%s%s" % (cereconf.DISTGROUP_PRIMARY_ADDR_PREFIX, self.group_name) dom = Email.EmailDomain(self._db) dom.find_by_domain(cereconf.DISTGROUP_DEFAULT_DOMAIN) addr_str = lp + '@' + cereconf.DISTGROUP_DEFAULT_DOMAIN try: ea.find_by_local_part_and_domain(lp, dom.entity_id) if ea.email_addr_target_id != et.entity_id: raise self._db.IntegrityError("Address %s is already taken!" % addr_str) except Errors.NotFoundError: ea.populate(lp, dom.entity_id, et.entity_id, expire=None) ea.write_db() epat = Email.EmailPrimaryAddressTarget(self._db) try: epat.find(ea.email_addr_target_id) epat.populate(ea.entity_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db()
def delete(self): """Delete the group, along with its EmailTarget.""" et = Email.EmailTarget(self._db) ea = Email.EmailAddress(self._db) epat = Email.EmailPrimaryAddressTarget(self._db) # If there is not associated an EmailTarget with the group, call delete # from the superclass. try: et.find_by_target_entity(self.entity_id) except Errors.NotFoundError: return super(GroupUiOMixin, self).delete() # An EmailTarget exists, so we try to delete its primary address. try: epat.find(et.entity_id) epat.delete() except Errors.NotFoundError: pass # We remove all the EmailTargets addresses. try: for row in et.get_addresses(): ea.clear() ea.find(row['address_id']) ea.delete() except Errors.NotFoundError: pass # Delete the EmailTarget et.delete() # Finally! Delete the group! super(GroupUiOMixin, self).delete()
def email_move_domain_addresses(self, operator, source_uname, dest_uname, domain_str, move_primary): """Move an account's e-mail addresses to another account :param domain_str: email domain to be affected :param move_primary: move primary email address """ if not self.ba.is_superuser(operator.get_entity_id()): raise PermissionDenied("Currently limited to superusers") move_primary = self._get_boolean(move_primary) source_account = self._get_account(source_uname) source_et = self._get_email_target_for_account(source_account) dest_account = self._get_account(dest_uname) dest_et = self._get_email_target_for_account(dest_account) epat = Email.EmailPrimaryAddressTarget(self.db) try: epat.find(source_et.entity_id) except Errors.NotFoundError: epat.clear() reassigned_addresses = [] for address in source_et.get_addresses(): if address['domain'] == domain_str: if address['address_id'] == epat.email_primaddr_id: if move_primary: self._move_primary_email_address(address, reassigned_addresses, dest_et, epat) else: self._move_email_address(address, reassigned_addresses, dest_et) # Managing ad_email ad_emails_added = "" if domain_str == cereconf.NO_MAILBOX_DOMAIN_EMPLOYEES: ad = ad_email.AdEmail(self.db) if move_primary: ad_emails = ad.search_ad_email(account_name=source_uname) if len(ad_emails) == 1: ad_emails_added = self._move_ad_email(ad_emails[0], dest_uname) # TODO: # If this command is called with move_primary=False, # the source account's primary email address will be left # intact, but it's corresponding ad_email will be deleted. # This mimics the functionality of the uit-script move_emails.py, # but is it really what we want? ad.delete_ad_email(account_name=source_uname) return ("OK, reassigned {}. ".format(reassigned_addresses) + ad_emails_added)
def test_phonenumberchange_delay(self): """Fresh phone numbers should not be used if config says so.""" cereconf.INDIVIDUATION_PHONE_TYPES['system_fs']['types']['contact_mobile_phone']['delay'] = 7 cereconf.INDIVIDUATION_PHONE_TYPES['system_fs']['types']['contact_private_mobile']['delay'] = 7 ou = Factory.get('OU')(self.db) co = Factory.get('Constants')(self.db) ou.find_stedkode(0, 0, 0, 0) pe = self.createPerson(first_name='Miss', last_name='Test', studnr='007') ac = self.createAccount(pe, 'mstest') pe.populate_affiliation(source_system=co.system_fs, ou_id=ou.entity_id, affiliation=co.affiliation_student, status=co.affiliation_status_student_aktiv) pe.write_db() pe.populate_contact_info(source_system=co.system_fs, type=co.contact_mobile_phone, value='98012345') pe.write_db() # Create e-mail address for user ed = Email.EmailDomain(self.db) ed.populate('example.com', 'For testing') ed.write_db() et = Email.EmailTarget(self.db) et.populate(co.email_target_account, ac.entity_id, co.entity_account) et.write_db() ea = Email.EmailAddress(self.db) ea.populate('test', ed.entity_id, et.entity_id) ea.write_db() epa = Email.EmailPrimaryAddressTarget(self.db) epa.populate(ea.entity_id, et) epa.write_db() self.db.commit() # hack the create_date in change_log self.db.execute(""" UPDATE [:table schema=cerebrum name=change_log] SET tstamp = :tid WHERE subject_entity = :s_id AND change_type_id = :ct_id""", {'s_id': pe.entity_id, 'ct_id': co.person_create, 'tid': DateTime(2009, 10, 4),}) self.db.commit() d = self.client.callRemote('generate_token', id_type="externalid_studentnr", ext_id='007', username='******', phone_no='98012345', browser_token='a') d = self.assertFailure(d, error.Error) # TODO: test that sendmail is called with the correct to-address return d
def _get_email_target_and_address(self, address): # Support DistributionGroup email target lookup try: return super(EmailCommands, self)._get_email_target_and_address(address) except CerebrumError as e: # Not found, maybe distribution group? try: dlgroup = Utils.Factory.get("DistributionGroup")(self.db) dlgroup.find_by_name(address) et = Email.EmailTarget(self.db) et.find_by_target_entity(dlgroup.entity_id) epa = Email.EmailPrimaryAddressTarget(self.db) epa.find(et.entity_id) ea = Email.EmailAddress(self.db) ea.find(epa.email_primaddr_id) return et, ea except Errors.NotFoundError: raise e
def delete_email_address(address): et, ea = get_email_target_and_address(address) if et is None: logger.debug("Would delete <%s>", address) return logger.info("Deleting <%s>", address) # We can't delete this EA, if there is an epat attached to it. # Before we can drop ea, remove epat (or we'll get constraint violation # from the db) try: epat = Email.EmailPrimaryAddressTarget(db) epat.find(ea.email_addr_target_id) epat.delete() logger.debug("Deleted *primary* address <%s>", address) except Errors.NotFoundError: pass ea.delete() for r in et.get_addresses(): logger.info("There are addresses left") return logger.debug("Deleting target as well") et.delete()
def update_email_addresses(self): # Find, create or update a proper EmailTarget for this # account. et = Email.EmailTarget(self._db) old_server = None target_type = self.const.email_target_account if self.is_deleted() or self.is_reserved(): target_type = self.const.email_target_deleted try: et.find_by_email_target_attrs(target_entity_id = self.entity_id) et.email_target_type = target_type except Errors.NotFoundError: # We don't want to create e-mail targets for reserved or # deleted accounts, but we do convert the type of existing # e-mail targets above. if target_type == self.const.email_target_deleted: return et.populate(target_type, self.entity_id, self.const.entity_account) et.write_db() # For deleted/reserved users, set expire_date for all of the # user's addresses, and don't allocate any new addresses. ea = Email.EmailAddress(self._db) if target_type == self.const.email_target_deleted: expire_date = self._db.DateFromTicks(time.time() + 60 * 60 * 24 * 180) for row in et.get_addresses(): ea.clear() ea.find(row['address_id']) if ea.email_addr_expire_date is None: ea.email_addr_expire_date = expire_date ea.write_db() return # if an account without email_server_target is found assign # the appropriate server old_server = et.email_server_id acc_types = self.get_account_types() entity = Factory.get("Entity")(self._db) try: entity.clear() entity.find(self.owner_id) except Errors.NotFoundError: pass if not old_server: # we should update servers for employees as well, but we # cannot do that for now as there are no clear criteria # for when we should consider someone av f*g-employee or # adm-employee. we will therefore update servers for students # only # if self.is_fag_employee(): # self._update_email_server('mail.f*g.hiof.no') # elif self.is_adm_employee(): # self._update_email_server('mail.adm.hiof.no') if entity.entity_type != self.const.entity_group: if self.is_student(): self._update_email_server('epost.hiof.no') else: # do not set email_server_target until account_type is registered return # Figure out which domain(s) the user should have addresses # in. Primary domain should be at the front of the resulting # list. # if the only address found is in EMAIL_DEFAULT_DOMAIN # don't set default address. This is done in order to prevent # adresses in default domain being sat as primary # TODO: account_types affiliated to OU's without connected # email domain don't get a default address primary_set = False ed = Email.EmailDomain(self._db) ed.find(self.get_primary_maildomain()) domains = [ed.email_domain_name] if cereconf.EMAIL_DEFAULT_DOMAIN not in domains: domains.append(cereconf.EMAIL_DEFAULT_DOMAIN) # Iterate over the available domains, testing various # local_parts for availability. Set user's primary address to # the first one found to be available. try: self.get_primary_mailaddress() except Errors.NotFoundError: pass epat = Email.EmailPrimaryAddressTarget(self._db) for domain in domains: if ed.email_domain_name != domain: ed.clear() ed.find_by_domain(domain) # Check for 'cnaddr' category before 'uidaddr', to prefer # 'cnaddr'-style primary addresses for users in # maildomains that have both categories. ctgs = [int(r['category']) for r in ed.get_categories()] local_parts = [] if int(self.const.email_domain_category_cnaddr) in ctgs: local_parts.append(self.get_email_cn_local_part(given_names=1, max_initials=1)) local_parts.append(self.account_name) elif int(self.const.email_domain_category_uidaddr) in ctgs: local_parts.append(self.account_name) for lp in local_parts: lp = self.wash_email_local_part(lp) # Is the address taken? ea.clear() try: ea.find_by_local_part_and_domain(lp, ed.entity_id) if ea.email_addr_target_id != et.entity_id: # Address already exists, and points to a # target not owned by this Account. continue # Address belongs to this account; make sure # there's no expire_date set on it. ea.email_addr_expire_date = None except Errors.NotFoundError: # Address doesn't exist; create it. ea.populate(lp, ed.entity_id, et.entity_id, expire=None) ea.write_db() # HiØ do not want the primary adress to change automatically if not primary_set: epat.clear() try: epat.find(ea.email_addr_target_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() primary_set = True
def _register_sympa_list_addresses(self, listname, local_part, domain, delivery_host): """ Register all neccessary sympa addresses. Add list, request, editor, owner, subscribe and unsubscribe addresses to a sympa mailing list. @type listname: basestring @param listname: Sympa listname that the operation is about. listname is typically different from local_part@domain when we are creating an alias. local_part@domain is the alias, listname is the original listname. And since aliases should point to the 'original' ETs, we have to use listname to locate the ETs. @type local_part: basestring @param local_part: See domain @type domain: basestring @param domain: L{local_part} and domain together represent a new list address that we want to create. @type delivery_host: EmailServer instance. @param delivery_host: EmailServer where e-mail to L{listname} is to be delivered through. """ if (delivery_host.email_server_type != self.const.email_server_type_sympa): raise CerebrumError( "Delivery host %s has wrong type (%s) for sympa list %s" % (delivery_host.get_name(self.const.host_namespace), self.const.EmailServerType( delivery_host.email_server_type), listname)) ed = Email.EmailDomain(self.db) ed.find_by_domain(domain) et = Email.EmailTarget(self.db) ea = Email.EmailAddress(self.db) epat = Email.EmailPrimaryAddressTarget(self.db) try: ea.find_by_local_part_and_domain(local_part, ed.entity_id) except Errors.NotFoundError: pass else: raise CerebrumError("The address %s@%s is already in use" % (local_part, domain)) sympa = self._get_account('sympa', idtype='name', actype='PosixUser') primary_ea_created = False listname_lp, listname_domain = listname.split("@") # For each of the addresses we are supposed to create... for pattern, pipe_destination in self._sympa_addr2alias: address = pattern % locals() address_lp, address_domain = address.split("@") # pipe has to be derived from the original listname, since it's # used to locate the ET. pipe = pipe_destination % { 'local_part': listname_lp, 'domain': listname_domain, 'listname': listname } # First check whether the address already exist. It should not. try: ea.clear() ea.find_by_local_part_and_domain(address_lp, ed.entity_id) raise CerebrumError("Can't add list %s as the address %s " "is already in use" % (listname, address)) except Errors.NotFoundError: pass # Then find the target for this particular email address. The # target may already exist, though. et.clear() try: et.find_by_alias_and_account(pipe, sympa.entity_id) except Errors.NotFoundError: et.populate(self.const.email_target_Sympa, alias=pipe, using_uid=sympa.entity_id, server_id=delivery_host.entity_id) et.write_db() # Then create the email address and associate it with the ET. ea.clear() ea.populate(address_lp, ed.entity_id, et.entity_id) ea.write_db() # And finally, the primary address. The first entry in # _sympa_addr2alias will match. Do not reshuffle that tuple! if not primary_ea_created: epat.clear() try: epat.find(et.entity_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() primary_ea_created = True
def sympa_remove_list(self, operator, run_host, listname, force_yes_no): """ Remove a sympa list from cerebrum. @type force_request: bool @param force_request: Controls whether a bofhd request should be issued. This may come in handy, if we want to delete a sympa list from Cerebrum only and not issue any requests. misc cancel_request would have worked too, but it's better to merge this into one command. """ force_request = self._is_yes(force_yes_no) # Check that the command exec host is sane if run_host not in cereconf.SYMPA_RUN_HOSTS: raise CerebrumError("run-host '%s' for list '%s' is not valid" % (run_host, listname)) et, ea = self._get_email_target_and_address(listname) self.ba.can_email_list_delete(operator.get_entity_id(), ea) if et.email_target_type != self.const.email_target_Sympa: raise CerebrumError( "'%s' is not a sympa list (type: %s)" % (listname, self.const.EmailTarget(et.email_target_type))) epat = Email.EmailPrimaryAddressTarget(self.db) list_id = ea.entity_id # Now, there are *many* ETs/EAs associated with one sympa list. We # have to wipe them all out. if not self._validate_sympa_list(listname): raise CerebrumError("Illegal sympa list name: '%s'", listname) deleted_EA = self.email_info(operator, listname) # needed for pattern interpolation below (these are actually used) local_part, domain = self._split_email_address(listname) for pattern, pipe_destination in self._sympa_addr2alias: address = pattern % locals() # For each address, find the target, and remove all email # addresses for that target (there may be many addresses for the # same target). try: ea.clear() ea.find_by_address(address) et.clear() et.find(ea.get_target_id()) epat.clear() try: epat.find(et.entity_id) except Errors.NotFoundError: pass else: epat.delete() # Wipe all addresses... for row in et.get_addresses(): addr = '%(local_part)s@%(domain)s' % row ea.clear() ea.find_by_address(addr) ea.delete() et.delete() except Errors.NotFoundError: pass if cereconf.INSTITUTION_DOMAIN_NAME == 'uio.no': self._report_deleted_EA(deleted_EA) if not force_request: return {'listname': listname, 'request': False} br = BofhdRequests(self.db, self.const) state = {'run_host': run_host, 'listname': listname} br.add_request( operator.get_entity_id(), # IVR 2008-08-04 +1 hour to allow changes to spread to # LDAP. This way we'll have a nice SMTP-error, rather # than a confusing error burp from sympa. DateTime.now() + DateTime.DateTimeDelta(0, 1), self.const.bofh_sympa_remove, list_id, None, state_data=pickle.dumps(state)) return {'listname': listname, 'request': True}
def email_rt_create(self, operator, queuename, addr, force="No"): """ Create rt queue. """ queue, host = self._resolve_rt_name(queuename) rt_dom = self._get_email_domain_from_str(host) op = operator.get_entity_id() self.ba.can_rt_create(op, domain=rt_dom) try: self._get_rt_email_target(queue, host) except CerebrumError: pass else: raise CerebrumError("RT queue %s already exists" % queuename) addr_lp, addr_domain_name = self._split_email_address(addr) addr_dom = self._get_email_domain_from_str(addr_domain_name) if addr_domain_name != host: self.ba.can_email_address_add(operator.get_entity_id(), domain=addr_dom) replaced_lists = [] # Unusual characters will raise an exception, a too short name # will return False, which we ignore for the queue name. self._is_ok_mailing_list_name(queue) # The submission address is only allowed to be short if it is # equal to the queue name, or the operator is a global # postmaster. if not (self._is_ok_mailing_list_name(addr_lp) or addr == queue + "@" + host or self.ba.is_postmaster(op)): raise CerebrumError("Illegal address for submission: %s" % addr) # Check if list exists and is replaceable try: et, ea = self._get_email_target_and_address(addr) except CerebrumError: pass else: raise CerebrumError("Address <{}> is in use".format(addr)) acc = self._get_account("exim") et = Email.EmailTarget(self.db) ea = Email.EmailAddress(self.db) cmd = self._rt_pipe % { 'action': "correspond", 'queue': queue, 'host': host } et.populate(self.const.email_target_RT, alias=cmd, using_uid=acc.entity_id) et.write_db() # Add primary address ea.populate(addr_lp, addr_dom.entity_id, et.entity_id) ea.write_db() epat = Email.EmailPrimaryAddressTarget(self.db) epat.populate(ea.entity_id, parent=et) epat.write_db() for alias in replaced_lists: if alias == addr: continue lp, dom = self._split_email_address(alias) alias_dom = self._get_email_domain_from_str(dom) ea.clear() ea.populate(lp, alias_dom.entity_id, et.entity_id) ea.write_db() # Add RT internal address if addr_lp != queue or addr_domain_name != host: ea.clear() ea.populate(queue, rt_dom.entity_id, et.entity_id) ea.write_db() # Moving on to the comment address et.clear() cmd = self._rt_pipe % { 'queue': queue, 'action': "comment", 'host': host } et.populate(self.const.email_target_RT, alias=cmd, using_uid=acc.entity_id) et.write_db() ea.clear() ea.populate("%s-comment" % queue, rt_dom.entity_id, et.entity_id) ea.write_db() msg = "RT queue %s on %s added" % (queue, host) if replaced_lists: msg += ", replacing mailing list(s) %s" % ", ".join(replaced_lists) addr = queue + "@" + host self._register_spam_settings(addr, self.const.email_target_RT) self._register_filter_settings(addr, self.const.email_target_RT) return msg
def _get_sympa_list(self, listname): """ Try to return the 'official' sympa mailing list name, if it can at all be derived from listname. The problem here is that some lists are actually called foo-admin@domain (and their admin address is foo-admin-admin@domain). Since the 'official' names are not tagged in any way, we try to guess. The guesswork proceeds as follows: 1) if listname points to a sympa ET that has a primary address, we are done, listname *IS* the official list name 2) if not, then there must be a prefix/suffix (like -request) and if we chop it off, we can checked the chopped off part for being an official sympa list. The chopping off continues until we run out of special prefixes/suffixes. """ ea = Email.EmailAddress(self.db) et = Email.EmailTarget(self.db) epat = Email.EmailPrimaryAddressTarget(self.db) def has_prefix(address): local_part, domain = self._split_email_address(address) return True in [ local_part.startswith(x) for x in self._sympa_address_prefixes ] def has_suffix(address): local_part, domain = self._split_email_address(address) return True in [ local_part.endswith(x) for x in self._sympa_address_suffixes ] def has_primary_to_me(address): try: ea.clear() ea.find_by_address(address) epat.clear() epat.find(ea.get_target_id()) return True except Errors.NotFoundError: return False def I_am_sympa(address, check_suffix_prefix=True): try: ea.clear() ea.find_by_address(address) except Errors.NotFoundError: # If it does not exist, it cannot be sympa return False et.clear() et.find(ea.get_target_id()) if ((not et.email_target_alias) or et.email_target_type != self.const.email_target_Sympa): # if it's not a Sympa ET, address cannot be sympa return False return True not_sympa_error = CerebrumError("%s is not a Sympa list" % listname) # Simplest case -- listname is actually a sympa ML directly. It does # not matter whether it has a funky prefix/suffix. if I_am_sympa(listname) and has_primary_to_me(listname): return listname # However, if listname does not have a prefix/suffix AND it is not a # sympa address with a primary address, them it CANNOT be a sympa # address. if not (has_prefix(listname) or has_suffix(listname)): raise not_sympa_error # There is a funky suffix/prefix. Is listname actually such a # secondary address? Try to chop off the funky part and test. local_part, domain = self._split_email_address(listname) for prefix in self._sympa_address_prefixes: if not local_part.startswith(prefix): continue lp_tmp = local_part[len(prefix):] addr_to_test = lp_tmp + "@" + domain try: self._get_sympa_list(addr_to_test) return addr_to_test except CerebrumError: pass for suffix in self._sympa_address_suffixes: if not local_part.endswith(suffix): continue lp_tmp = local_part[:-len(suffix)] addr_to_test = lp_tmp + "@" + domain try: self._get_sympa_list(addr_to_test) return addr_to_test except CerebrumError: pass raise not_sympa_error
def update_email_addresses(self, set_primary=False): # check if an e-mail spread is registered yet, if not don't # update email_spreads = (self.const.spread_exchange_account, self.const.spread_exchange_acc_old, self.const.spread_hia_email, self.const.spread_uia_office_365, self.const.spread_uia_forward) if not any([self.has_spread(spread) for spread in email_spreads]): # CRB-742: If spread_uia_office_365 is removed # MailTarget targettype should be set as "deleted" try: et = Email.EmailTarget(self._db) et.find_by_email_target_attrs(target_entity_id=self.entity_id) if et.email_target_type != self.const.email_target_deleted: et.email_target_type = self.const.email_target_deleted et.write_db() except Errors.NotFoundError: pass return # Find, create or update a proper EmailTarget for this # account. et = Email.EmailTarget(self._db) target_type = self.const.email_target_account if self.has_spread(self.const.spread_uia_forward): target_type = self.const.email_target_forward if self.is_deleted() or self.is_reserved(): target_type = self.const.email_target_deleted try: et.find_by_email_target_attrs(target_entity_id=self.entity_id) et.email_target_type = target_type except Errors.NotFoundError: # We don't want to create e-mail targets for reserved or # deleted accounts, but we do convert the type of existing # e-mail targets above. if target_type == self.const.email_target_deleted: return et.populate(target_type, self.entity_id, self.const.entity_account) et.write_db() # For deleted/reserved users, set expire_date for all of the # user's addresses, and don't allocate any new addresses. ea = Email.EmailAddress(self._db) if target_type == self.const.email_target_deleted: expire_date = self._db.DateFromTicks(time.time() + 60 * 60 * 24 * 1) for row in et.get_addresses(): ea.clear() ea.find(row['address_id']) if ea.email_addr_expire_date is None: ea.email_addr_expire_date = expire_date ea.write_db() return # if an account email_target without email_server is found assign # the appropriate server based on spread and account_type spread = None if not et.email_server_id: if self.get_account_types() or \ self.owner_type == self.const.entity_group: for s in self.get_spread(): if s['spread'] in (int(self.const.spread_exchange_account), int(self.const.spread_exchange_acc_old), int(self.const.spread_hia_email)): spread = s['spread'] et = self._update_email_server(spread) else: # do not set email_server_target # until account_type is registered return # Figure out which domain(s) the user should have addresses # in. Primary domain should be at the front of the resulting # list. # if the only address found is in EMAIL_DEFAULT_DOMAIN # don't set default address. This is done in order to prevent # adresses in default domain being sat as primary # TODO: account_types affiliated to OU's without connected # email domain don't get a default address primary_set = False ed = Email.EmailDomain(self._db) ed.find(self.get_primary_maildomain()) domains = [ed.email_domain_name] if ed.email_domain_name == cereconf.EMAIL_DEFAULT_DOMAIN: if not self.owner_type == self.const.entity_group: primary_set = True if cereconf.EMAIL_DEFAULT_DOMAIN not in domains: domains.append(cereconf.EMAIL_DEFAULT_DOMAIN) # Iterate over the available domains, testing various # local_parts for availability. Set user's primary address to # the first one found to be available. # Never change any existing email addresses try: self.get_primary_mailaddress() primary_set = True except Errors.NotFoundError: pass epat = Email.EmailPrimaryAddressTarget(self._db) for domain in domains: if ed.email_domain_name != domain: ed.clear() ed.find_by_domain(domain) # Check for 'cnaddr' category before 'uidaddr', to prefer # 'cnaddr'-style primary addresses for users in # maildomains that have both categories. ctgs = [int(r['category']) for r in ed.get_categories()] local_parts = [] if int(self.const.email_domain_category_cnaddr) in ctgs: local_parts.append( self.get_email_cn_local_part(given_names=1, max_initials=1)) local_parts.append(self.account_name) elif int(self.const.email_domain_category_uidaddr) in ctgs: local_parts.append(self.account_name) for lp in local_parts: lp = self.wash_email_local_part(lp) # Is the address taken? ea.clear() try: ea.find_by_local_part_and_domain(lp, ed.entity_id) if ea.email_addr_target_id != et.entity_id: # Address already exists, and points to a # target not owned by this Account. continue # Address belongs to this account; make sure # there's no expire_date set on it. ea.email_addr_expire_date = None except Errors.NotFoundError: # Address doesn't exist; create it. ea.populate(lp, ed.entity_id, et.entity_id, expire=None) ea.write_db() if not primary_set: epat.clear() try: epat.find(ea.email_addr_target_id) epat.populate(ea.entity_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() primary_set = True self.update_email_quota()
def process_mail(account_id, type, addr): et = Email.EmailTarget(db) ea = Email.EmailAddress(db) edom = Email.EmailDomain(db) epat = Email.EmailPrimaryAddressTarget(db) addr = string.lower(addr) fld = addr.split('@') if len(fld) != 2: logger.error("Bad address: %s. Skipping", addr) return None # fi lp, dom = fld try: edom.find_by_domain(dom) logger.debug("Domain found: %s: %d", dom, edom.entity_id) except Errors.NotFoundError: edom.populate(dom, "Generated by import_uname_mail.") edom.write_db() logger.debug("Domain created: %s: %d", dom, edom.entity_id) # yrt try: et.find_by_target_entity(int(account_id)) logger.debug("EmailTarget found(accound): %s: %d", account_id, et.entity_id) except Errors.NotFoundError: et.populate(constants.email_target_account, entity_id=int(account_id), entity_type=constants.entity_account) et.write_db() logger.debug("EmailTarget created: %s: %d", account_id, et.entity_id) # yrt try: ea.find_by_address(addr) logger.debug("EmailAddress found: %s: %d", addr, ea.entity_id) except Errors.NotFoundError: ea.populate(lp, edom.entity_id, et.entity_id) ea.write_db() logger.debug("EmailAddress created: %s: %d", addr, ea.entity_id) # yrt if type == "defaultmail": try: epat.find(et.entity_id) logger.debug("EmailPrimary found: %s: %d", addr, epat.entity_id) except Errors.NotFoundError: if ea.email_addr_target_id == et.entity_id: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() logger.debug("EmailPrimary created: %s: %d", addr, epat.entity_id) else: logger.error("EmailTarget mismatch: ea: %d, et: %d", ea.email_addr_target_id, et.entity_id) # fi # yrt # fi et.clear() ea.clear() edom.clear() epat.clear()
def read_prim(self): mail_prim = Email.EmailPrimaryAddressTarget(self._db) for row in mail_prim.list_email_primary_address_targets(): self.targ2prim[int(row['target_id'])] = int(row['address_id'])
def _update_email_address_domains(self, et): # Figure out which domain(s) the user should have addresses # in. Primary domain should be at the front of the resulting # list. ed = Email.EmailDomain(self._db) ea = Email.EmailAddress(self._db) try: ed.find(self.get_primary_maildomain(use_default_domain=False)) except Errors.NotFoundError: # no appropriate primary domain was found, no valid address may # be generated return domains = self.get_prospect_maildomains(use_default_domain=False) # Iterate over the available domains, testing various # local_parts for availability. Set user's primary address to # the first one found to be available. primary_set = False # Never change any existing email addresses try: self.get_primary_mailaddress() primary_set = True except Errors.NotFoundError: pass epat = Email.EmailPrimaryAddressTarget(self._db) if not domains: # no valid domain has been found and no e-mail address # can be assigned return for domain in domains: if ed.entity_id != domain: ed.clear() ed.find(domain) # Check for 'cnaddr' category before 'uidaddr', to prefer # 'cnaddr'-style primary addresses for users in # maildomains that have both categories. ctgs = [int(r['category']) for r in ed.get_categories()] local_parts = [] if int(self.const.email_domain_category_cnaddr) in ctgs: local_parts.append(self.get_email_cn_local_part()) local_parts.append(self.account_name) elif int(self.const.email_domain_category_uidaddr) in ctgs: local_parts.append(self.account_name) for lp in local_parts: lp = self.wash_email_local_part(lp) # Is the address taken? ea.clear() try: ea.find_by_local_part_and_domain(lp, ed.entity_id) if ea.email_addr_target_id != et.entity_id: # Address already exists, and points to a # target not owned by this Account. # # TODO: An expired address gets removed by a # database cleaning job, and when it's gone, # the address will eventually be recreated # connected to this target. continue except Errors.NotFoundError: # Address doesn't exist; create it. ea.populate(lp, ed.entity_id, et.entity_id, expire=None) ea.write_db() if not primary_set: epat.clear() try: epat.find(ea.email_addr_target_id) epat.populate(ea.entity_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() primary_set = True
def update_email_addresses(self): # Find, create or update a proper EmailTarget for this # account. et = Email.EmailTarget(self._db) target_type = self.const.email_target_account if self.is_expired(): target_type = self.const.email_target_deleted changed = False try: et.find_by_email_target_attrs(target_entity_id=self.entity_id) if et.email_target_type != target_type: changed = True et.email_target_type = target_type except Errors.NotFoundError: # We don't want to create e-mail targets for reserved or # deleted accounts, but we do convert the type of existing # e-mail targets above. if target_type == self.const.email_target_deleted: return et.populate(target_type, self.entity_id, self.const.entity_account) et.write_db() # For deleted/reserved users, set expire_date for all of the # user's addresses, and don't allocate any new addresses. ea = Email.EmailAddress(self._db) if changed and cereconf.EMAIL_EXPIRE_ADDRESSES is not False: if target_type == self.const.email_target_deleted: seconds = cereconf.EMAIL_EXPIRE_ADDRESSES * 86400 expire_date = self._db.DateFromTicks(time.time() + seconds) else: expire_date = None for row in et.get_addresses(): ea.clear() ea.find(row['address_id']) ea.email_addr_expire_date = expire_date ea.write_db() # Active accounts shouldn't have an alias value (it is used # for failure messages) if changed and target_type == self.const.email_target_account: if et.email_target_alias is not None: et.email_target_alias = None et.write_db() if target_type == self.const.email_target_deleted: return # Figure out which domain(s) the user should have addresses # in. Primary domain should be at the front of the resulting # list. ed = Email.EmailDomain(self._db) ed.find(self.get_primary_maildomain()) domains = [ed.email_domain_name] # Add the default domains if missing for domain in Email.get_default_email_domains(): if domain not in domains: domains.append(domain) # Iterate over the available domains, testing various # local_parts for availability. Set user's primary address to # the first one found to be available. primary_set = False epat = Email.EmailPrimaryAddressTarget(self._db) for domain in domains: if ed.email_domain_name != domain: ed.clear() ed.find_by_domain(domain) # Check for 'uidaddr' category before 'cnaddr', to prefer # 'uidaddr'-style primary addresses for users in # maildomains that have both categories. ctgs = [int(r['category']) for r in ed.get_categories()] local_parts = [] if int(self.const.email_domain_category_uidaddr) in ctgs: local_parts.append(self.account_name) elif int(self.const.email_domain_category_cnaddr) in ctgs: local_parts.append(self.get_email_cn_local_part()) local_parts.append(self.account_name) for lp in local_parts: lp = self.wash_email_local_part(lp) # Is the address taken? ea.clear() try: ea.find_by_local_part_and_domain(lp, ed.entity_id) if ea.email_addr_target_id != et.entity_id: # Address already exists, and points to a # target not owned by this Account. # # TODO: An expired address gets removed by a # database cleaning job, and when it's gone, # the address will eventually be recreated # connected to this target. continue except Errors.NotFoundError: # Address doesn't exist; create it. ea.populate(lp, ed.entity_id, et.entity_id, expire=None) ea.write_db() if not primary_set: epat.clear() try: epat.find(ea.email_addr_target_id) epat.populate(ea.entity_id) except Errors.NotFoundError: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() primary_set = True
def process_mail(account, mtype, addr, spread=None, homemdb=None): et = Email.EmailTarget(db) ea = Email.EmailAddress(db) edom = Email.EmailDomain(db) epat = Email.EmailPrimaryAddressTarget(db) addr = addr.lower() account_id = account.entity_id fld = addr.split('@') if len(fld) != 2: logger.error("Bad address: %s. Skipping", addr) return None lp, dom = fld try: edom.find_by_domain(dom) except Errors.NotFoundError: logger.error("Domain non-existent: %s", lp + '@' + dom) return None try: et.find_by_target_entity(int(account_id)) except Errors.NotFoundError: et.populate(constants.email_target_account, target_entity_id=int(account_id), target_entity_type=constants.entity_account) et.write_db() logger.debug("EmailTarget created: %s: %d", account_id, et.entity_id) try: ea.find_by_address(addr) except Errors.NotFoundError: ea.populate(lp, edom.entity_id, et.entity_id) ea.write_db() logger.debug("EmailAddress created: %s: %d", addr, ea.entity_id) # if specified, add an email spread for users with email address if spread and not account.has_spread(spread): account.add_spread(spread) logger.debug("Added spread %s for account %s", spread, account_id) if mtype == "defaultmail": try: epat.find(et.entity_id) logger.debug("EmailPrimary found: %s: %d", addr, epat.entity_id) except Errors.NotFoundError: if ea.email_addr_target_id == et.entity_id: epat.clear() epat.populate(ea.entity_id, parent=et) epat.write_db() logger.debug("EmailPrimary created: %s: %d", addr, epat.entity_id) else: logger.error("EmailTarget mismatch: ea: %d, et: %d", ea.email_addr_target_id, et.entity_id) if homemdb: logger.info("Added exchange-mbd %s\n", homemdb) account.populate_trait(constants.trait_exchange_mdb, strval=homemdb) account.write_db() et.clear() ea.clear() edom.clear() epat.clear()
def get_distgroup_attributes_and_targetdata(self, display_name_lang='nb', roomlist=False): all_data = {} ea = Email.EmailAddress(self._db) ed = Email.EmailDomain(self._db) et = Email.EmailTarget(self._db) epat = Email.EmailPrimaryAddressTarget(self._db) primary_address = "" display_name = "" name_language = "" addrs = [] name_variant = self.const.dl_group_displ_name if display_name_lang == 'nb' or \ not hasattr(self.const, 'dl_group_displ_name'): # code that uses this methos should probably take # care of getting the language right? name_language = self.const.language_nb else: name_language = int(_LanguageCode(display_name_lang)) display_name = self.get_name_with_language(name_variant, name_language, default=self.group_name) # in roomlists we only care about name, description, # displayname and the roomlist-status, the other attributes # don't need to be set in Exchange if roomlist: all_data = { 'name': self.group_name, 'description': self.description, 'displayname': display_name, 'group_id': self.entity_id, 'roomlist': self.roomlist } return all_data try: et.find_by_target_entity(self.entity_id) except Errors.NotFoundError: # could not find e-mail target for group. this should # normally not happen return None try: epat.find(et.entity_id) except Errors.NotFoundError: # could not find primary address for the e-mail target # this happens from time to time, and we should be able # to identify the error raise self._db.IntegrityError( "No primary address registered for {}".format(self.group_name)) ea.clear() ea.find(epat.email_primaddr_id) ed.clear() ed.find(ea.email_addr_domain_id) primary_address = "%s@%s" % (ea.email_addr_local_part, ed.email_domain_name) for r in et.get_addresses(special=True): ad = "%s@%s" % (r['local_part'], r['domain']) addrs.append(ad) # name is expanded with prefix 'dl-' by the export all_data = { 'name': self.group_name, 'description': self.description, 'displayname': display_name, 'group_id': self.entity_id, 'roomlist': self.roomlist, 'hidden': self.hidden, 'primary': primary_address, 'aliases': addrs } return all_data