def main(inargs=None): """Find moderatorless groups, make a nice table and send it to drift""" try: import argparse except ImportError: from Cerebrum.extlib import argparse parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-r', '--recipient', dest='recipient', default=None, help='Recipient of the report') logutils.options.install_subparser(parser) argutils.add_commit_args(parser, default=False) args = parser.parse_args(inargs) logutils.autoconf('cronjob', args) logger.info('START %s', parser.prog) logger.info('Extracting adminless groups') abandoned_manual_groups = get_abandoned_manual_groups() logger.info('Creating table') table = make_table(abandoned_manual_groups) args = parser.parse_args(inargs) if args.recipient: logger.info('Sending email to %s', args.recipient) email.sendmail(args.recipient, '*****@*****.**', get_title(), table) else: logger.info('No email provided') logger.info('DONE %s', parser.prog)
def _send_mail(mail_to, mail_from, subject, body, mail_cc=None, debug_enabled=False): if debug_enabled: logger.debug("Sending mail to %s. Subject: %s", mail_to, subject) # logger.debug("Body: %s" % body) return True try: sendmail( toaddr=mail_to, fromaddr=mail_from, subject=subject, body=body, cc=mail_cc, debug=debug_enabled) except smtplib.SMTPRecipientsRefused as e: failed_recipients = e.recipients for mail, condition in failed_recipients.iteritems(): logger.exception("Failed when notifying %s (%s): %s", mail_to, mail, condition) return False except Exception as e: logger.error("Error when notifying %s: %s" % (mail_to, e)) return False return True
def mail_warning(self, person, account, reason): """Warn a person by sending an e-mail to all its accounts.""" msg = '\n'.join([ "Someone has tried to recover the password for your account: %s." % account.account_name, "This has failed, due to the following reason:", '', " %s" % reason, '', "If this was not you, please contact your local IT-department as " "soon as possible.", '', "-- ", "%s" % self.email_signature]) account2 = Factory.get('Account')(self.db) for row in person.get_accounts(): account2.clear() account2.find(row['account_id']) try: primary = account2.get_primary_mailaddress() except Errors.NotFoundError as e: logger.error("Couldn't warn user %r, no primary mail: %s", account.account_name, e) continue logger.debug("Emailing user %r (%r)", account2.account_name, account2.entity_id) try: sendmail(primary, self.email_from, self.email_subject, msg) except Exception as e: logger.error("Error for %r from sendmail: %s", primary, e)
def mail_warning(self, person, account, reason): """Warn a person by sending an e-mail to all its accounts.""" msg = '\n'.join([ "Someone has tried to recover the password for your account: %s." % account.account_name, "This has failed, due to the following reason:", '', " %s" % reason, '', "If this was not you, please contact your local IT-department as " "soon as possible.", '', "-- ", "%s" % self.email_signature ]) account2 = Factory.get('Account')(self.db) for row in person.get_accounts(): account2.clear() account2.find(row['account_id']) try: primary = account2.get_primary_mailaddress() except Errors.NotFoundError as e: logger.error("Couldn't warn user %r, no primary mail: %s", account.account_name, e) continue logger.debug("Emailing user %r (%r)", account2.account_name, account2.entity_id) try: sendmail(primary, self.email_from, self.email_subject, msg) except Exception as e: logger.error("Error for %r from sendmail: %s", primary, e)
def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'hsdf:', [ 'help', 'summary', 'detail', 'min=', 'max=', 'mail-to=', 'mail-from=', 'file=' ]) except getopt.GetoptError: usage("Argument error!", 1) detail = False minimum = 1 maxmum = None report_type = 'screen' outputstream = sys.stdout mail_to = None mail_from = None persons = 'person_id' for opt, val in opts: if opt in ('-h', '--help'): usage() elif opt in ('-s', '--summary'): pass elif opt in ('-d', '--detail'): detail = True elif opt in ('--min'): minimum = int(val) if minimum < 0: usage( "Error: the value of parameter --min should be at least 1", 2) elif opt in ('--max'): maxmum = int(val) if maxmum < 0: usage( "Error: the value of parameter --max should be at least 1", 3) elif opt in ('-f', '--file'): report_type = 'file' outputstream = open(val, 'w') outputstream.write( "==== Results of checking active accounts in Cerebrum ====\n") outputstream.write("person_id\tNr_accounts\taccount_names\n") elif opt in ('--mail-to'): report_type = 'mail' mail_to = val elif opt in ('--mail-from'): mail_from = val else: usage("Error: Unknown parameter '%s'" % opt, 4) persons += checkACaccount(minimum, maxmum, detail, report_type, outputstream) if mail_to: count = persons.count("\n") subject = "Warning: these following %s persons have more than %s active accounts." % ( count, minimum) sendmail(mail_to, mail_from, subject, persons)
def process(output, mail): db = Factory.get('Database')() co = Factory.get('Constants')(db) ac = Factory.get('Account')(db) pe = Factory.get('Person')(db) logger.info("Invoice stats started") logger.debug("Using database: %s", cereconf.CEREBRUM_DATABASE_NAME) last_event = None try: last_event = db.query_1(''' SELECT tstamp FROM [:table schema=cerebrum name=change_log] ORDER BY tstamp DESC LIMIT 1''') except Errors.NotFoundError: pass logger.debug("Last event found from db: %s", last_event) # Find active persons: affs = [] for a in ('STUDENT', 'ANSATT', 'TILKNYTTET', 'ELEV', 'MANUELL', 'PROJECT'): try: af = co.PersonAffiliation(a) int(af) affs.append(af) except Errors.NotFoundError: pass logger.debug("Active affiliations: %s" % ', '.join(text_type(a) for a in affs)) all_affiliated = set(r['person_id'] for r in pe.list_affiliations( affiliation=affs, include_deleted=False)) logger.debug("Found %d persons with active aff", len(all_affiliated)) # Find active accounts: quars = set(r['entity_id'] for r in ac.list_entity_quarantines(only_active=True, entity_types=co.entity_account)) logger.debug("Found %d quarantined accounts", len(quars)) active_accounts = set(r['account_id'] for r in ac.search(owner_type=co.entity_person) if (r['owner_id'] in all_affiliated and r['account_id'] not in quars)) logger.info("Found %d accounts for the active persons", len(active_accounts)) if output: csvw = csv.writer(output) csvw.writerow((time.strftime('%Y-%m-%d'), cereconf.CEREBRUM_DATABASE_NAME, len(active_accounts), last_event, )) if mail: body = """Found {} active accounts in {} from {}""".format( len(active_accounts), cereconf.CEREBRUM_DATABASE_NAME, last_event) sendmail(mail, mail_from, mail_subject, body) logger.info("Invoice stats finished")
def process(output, mail): db = Factory.get('Database')() co = Factory.get('Constants')(db) ac = Factory.get('Account')(db) pe = Factory.get('Person')(db) logger.info("Invoice stats started") logger.debug("Using database: %s", cereconf.CEREBRUM_DATABASE_NAME) last_event = None try: last_event = db.query_1(''' SELECT tstamp FROM [:table schema=cerebrum name=change_log] ORDER BY tstamp DESC LIMIT 1''') except Errors.NotFoundError: pass logger.debug("Last event found from db: %s", last_event) # Find active persons: affs = [] for a in ('STUDENT', 'ANSATT', 'TILKNYTTET', 'ELEV', 'MANUELL', 'PROJECT'): try: af = co.PersonAffiliation(a) int(af) affs.append(af) except Errors.NotFoundError: pass logger.debug("Active affiliations: %s" % ', '.join(text_type(a) for a in affs)) all_affiliated = set( r['person_id'] for r in pe.list_affiliations(affiliation=affs, include_deleted=False)) logger.debug("Found %d persons with active aff", len(all_affiliated)) # Find active accounts: quars = set(r['entity_id'] for r in ac.list_entity_quarantines( only_active=True, entity_types=co.entity_account)) logger.debug("Found %d quarantined accounts", len(quars)) active_accounts = set( r['account_id'] for r in ac.search(owner_type=co.entity_person) if (r['owner_id'] in all_affiliated and r['account_id'] not in quars)) logger.info("Found %d accounts for the active persons", len(active_accounts)) if output: csvw = csv.writer(output) csvw.writerow(( time.strftime('%Y-%m-%d'), cereconf.CEREBRUM_DATABASE_NAME, len(active_accounts), last_event, )) if mail: body = """Found {} active accounts in {} from {}""".format( len(active_accounts), cereconf.CEREBRUM_DATABASE_NAME, last_event) sendmail(mail, mail_from, mail_subject, body) logger.info("Invoice stats finished")
def handle_person(database, source_system, affiliations, send_notifications, email_config, data): pe = Factory.get('Person')(database) ac = Factory.get('Account')(database) et = EmailTarget(database) ef = EmailForward(database) ed = EmailDomain(database) if (data.get('resourceType') == 'persons' and 'affiliation' in data.get( 'urn:ietf:params:event:SCIM:modify', {}).get( 'attributes', [])): ident = int(data.get('sub').split('/')[-1]) if not pe.list_affiliations( person_id=ident, source_system=source_system, affiliation=affiliations): return pe.clear() pe.find(ident) removed_forwards = defaultdict(list) for account_id in map(lambda x: x['account_id'], pe.get_accounts( filter_expired=False)): try: et.clear() et.find_by_target_entity(account_id) except Errors.NotFoundError: continue ef.clear() ef.find(et.entity_id) for forward in map(lambda x: x['forward_to'], ef.get_forward()): try: ed.clear() ed.find_by_domain(forward.split('@')[-1]) except Errors.NotFoundError: ac.clear() ac.find(account_id) ef.delete_forward(forward) removed_forwards[ac.get_primary_mailaddress() ].append(forward) logger.info( 'Deleted forward {} from {}'.format( forward, ac.account_name)) if send_notifications: for k, v in removed_forwards.items(): sendmail( toaddr=k, fromaddr=email_config.sender, subject=email_config.subject, body=email_config.body_template.format('\n'.join(v))) database.commit()
def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'hsdf:', ['help', 'summary', 'detail', 'min=', 'max=', 'mail-to=', 'mail-from=', 'file=']) except getopt.GetoptError: usage("Argument error!", 1) detail = False minimum = 1 maxmum = None report_type = 'screen' outputstream = sys.stdout mail_to = None mail_from = None persons = 'person_id' for opt, val in opts: if opt in ('-h', '--help'): usage() elif opt in ('-s', '--summary'): pass elif opt in ('-d', '--detail'): detail = True elif opt in ('--min'): minimum = int(val) if minimum < 0: usage("Error: the value of parameter --min should be at least 1", 2) elif opt in ('--max'): maxmum = int(val) if maxmum < 0: usage("Error: the value of parameter --max should be at least 1", 3) elif opt in ('-f', '--file'): report_type = 'file' outputstream = open(val, 'w') outputstream.write("==== Results of checking active accounts in Cerebrum ====\n") outputstream.write("person_id\tNr_accounts\taccount_names\n") elif opt in ('--mail-to'): report_type = 'mail' mail_to = val elif opt in ('--mail-from'): mail_from = val else: usage("Error: Unknown parameter '%s'" % opt, 4) persons += checkACaccount(minimum,maxmum,detail,report_type,outputstream) if mail_to: count = persons.count("\n") subject = "Warning: these following %s persons have more than %s active accounts." % (count,minimum) sendmail(mail_to, mail_from, subject, persons)
def send_report(report): """Send email with import errors.""" recipient = cereconf.TELEFONIERRORS_RECEIVER sender = cereconf.SYSX_EMAIL_NOTFICATION_SENDER subject = 'Import telefoni errors from Cerebrum {0}'.format( datetime.date.today().strftime('%Y%m%d')) sendmail( toaddr=recipient, fromaddr=sender, subject=subject, body=report, )
def send_notify_email(new_cere_ous, to_email_addrs): """ Sends information about OUs to a set of mail_addresses. :type new_cere_ous: dict :param new_cere_ous: *ou_id* -> *sko* mapping, containing the OUs that has been added to the database. :type to_email_addrs: list :param to_email_addrs: List of email addresses that should be notified about the new OUs. """ if len(new_cere_ous) < 1: logger.warn('No new OUs to send notification about') return ous = OU_class(db) # Set up email sender = '*****@*****.**' subject = 'New OUs added to Cerebrum' body = '%(num)d OUs added to Cerebrum on %(time)s\n\n' % { 'num': len(new_cere_ous), 'time': mx.DateTime.now().strftime(), } for ou_id in new_cere_ous.keys(): names = ous.search_name_with_language(entity_id=ou_id, name_language=co.language_nb, name_variant=co.ou_name) body += ' Entity Id: %d\n' % ou_id body += ' Stedkode: %s\n' % new_cere_ous[ou_id] if len(names): body += ' Name : %s\n\n' % names[0]['name'] for to_email in to_email_addrs: try: sendmail(to_email, sender, subject, body) except SMTPRecipientsRefused as ref: for email, cond in ref.recipients.iteritems(): logger.info("Failed to notify '%s': %s", email, cond) continue except SMTPException as e: logger.warning("Failed to notify '%s': %s", to_email, e) continue logger.info("OUs added, '%s' notified", to_email)
def email_report(to_address, from_address, report): """Send the report by email.""" import smtplib try: sendmail(to_address, from_address, 'ePhorte role report', report, cc=None) except smtplib.SMTPRecipientsRefused, e: failed_recipients = e.recipients logger.info("Failed to notify <%d> users", len(failed_recipients)) for email, condition in failed_recipients.iteritems(): logger.info("Failed to notify: %s", condition)
def handle_person(database, source_system, affiliations, send_notifications, email_config, data): pe = Factory.get('Person')(database) ac = Factory.get('Account')(database) et = EmailTarget(database) ef = EmailForward(database) ed = EmailDomain(database) if (data.get('resourceType') == 'persons' and 'affiliation' in data.get( 'urn:ietf:params:event:SCIM:modify', {}).get('attributes', [])): ident = int(data.get('sub').split('/')[-1]) if not pe.list_affiliations(person_id=ident, source_system=source_system, affiliation=affiliations): return pe.clear() pe.find(ident) removed_forwards = defaultdict(list) for account_id in map(lambda x: x['account_id'], pe.get_accounts(filter_expired=False)): try: et.clear() et.find_by_target_entity(account_id) except Errors.NotFoundError: continue ef.clear() ef.find(et.entity_id) for forward in map(lambda x: x['forward_to'], ef.get_forward()): try: ed.clear() ed.find_by_domain(forward.split('@')[-1]) except Errors.NotFoundError: ac.clear() ac.find(account_id) ef.delete_forward(forward) removed_forwards[ac.get_primary_mailaddress()].append( forward) logger.info('Deleted forward {} from {}'.format( forward, ac.account_name)) if send_notifications: for k, v in removed_forwards.items(): sendmail(toaddr=k, fromaddr=email_config.sender, subject=email_config.subject, body=email_config.body_template.format('\n'.join(v))) database.commit()
def send_notify_email(new_cere_ous, to_email_addrs): """Sends information about OUs to a set of mail_addresses. @type new_cere_ous: dict @param new_cere_ous: ou_id -> sko (basestring) mapping, containing the OUs that has been added to the database. @type to_email_addrs: list @param to_email_addrs: List of email addresses that should be notified about the new OUs. """ if len(new_cere_ous) < 1: logger.warn('No new OUs to send notification about') return ous = OU_class(db) # Set up email sender = '*****@*****.**' subject = 'New OUs added to Cerebrum' body = '%(num)d OUs added to Cerebrum on %(time)s\n\n' % \ {'num': len(new_cere_ous), \ 'time': DateTime.now().strftime()} for ou_id in new_cere_ous.keys(): names = ous.search_name_with_language(entity_id=ou_id, name_language=co.language_nb, name_variant=co.ou_name) body += ' Entity Id: %d\n' % ou_id body += ' Stedkode: %s\n' % new_cere_ous[ou_id] if len(names): body += ' Name : %s\n\n' % names[0]['name'] for to_email in to_email_addrs: try: sendmail(to_email, sender, subject, body) except SMTPRecipientsRefused, ref: for email, cond in ref.recipients.iteritems(): logger.info('Failed to notify \'%s\': %s', email, cond) continue except SMTPException, e: logger.warn('Failed to notify \'%s\': %s', to_email, e) continue
def send_email(self, subject, message): """ Send an email to the email address associated with the account """ to_addr = self.get_address() if not self.trait_allows(): self.logger.warn("Account flooded, will not mail %r", to_addr) elif not self.dryrun: try: sendmail(to_addr, self.sender, subject, message) self.logger.debug("Sent message to %r", to_addr) except smtplib.SMTPRecipientsRefused, e: error = e.recipients.get(to_addr) self.logger.warn("Failed to send message to %s (SMTP %d: %s)", to_addr, error[0], error[1]) except smtplib.SMTPException: self.logger.exception("Failed to send message to %s", to_addr)
def send_email(requests, dryrun, database): """Send 'confirm you are still alive' e-mails. """ logger.debug("%d e-mails to dispatch.", len(requests)) for account_id in requests: attrs = requests[account_id] email = attrs.email uname = attrs.uname account_id = attrs.account_id magic_key = attrs.magic_key expire_date = attrs.expire_date.strftime("%Y-%m-%d") confirm_url = get_config("EXPIRE_CONFIRM_URL") + magic_key message = get_config("EXPIRE_MESSAGE_TEMPLATE") % { "uname": uname, "expire_date": expire_date, "url": confirm_url, } logger.debug("Generated a message for %s/%s (request key: %s). ", uname, email, magic_key) if not dryrun: try: sendmail(email, get_config("EXPIRE_MESSAGE_SENDER"), get_config("EXPIRE_MESSAGE_SUBJECT"), message) logger.debug("Message for %s/%s (request key: %s) sent", uname, email, magic_key) except smtplib.SMTPRecipientsRefused, e: error = e.recipients.get(email) logger.warn("Failed to send message to %s/%s (SMTP %d: %s)", uname, email, error[0], error[1]) if error[0] == 550: continue else: cancel_request(attrs, database) except smtplib.SMTPException: logger.exception( "Failed to send message to %s/%s", uname, email) cancel_request(attrs, database)
def send_email(requests, dryrun, database): """Send 'confirm you are still alive' e-mails. """ logger.debug("%d e-mails to dispatch.", len(requests)) for account_id in requests: attrs = requests[account_id] email = attrs.email uname = attrs.uname account_id = attrs.account_id magic_key = attrs.magic_key expire_date = attrs.expire_date.strftime("%Y-%m-%d") confirm_url = get_config("EXPIRE_CONFIRM_URL") + magic_key message = get_config("EXPIRE_MESSAGE_TEMPLATE") % { "uname": uname, "expire_date": expire_date, "url": confirm_url, } logger.debug("Generated a message for %s/%s (request key: %s). ", uname, email, magic_key) if not dryrun: try: sendmail(email, get_config("EXPIRE_MESSAGE_SENDER"), get_config("EXPIRE_MESSAGE_SUBJECT"), message) logger.debug("Message for %s/%s (request key: %s) sent", uname, email, magic_key) except smtplib.SMTPRecipientsRefused, e: error = e.recipients.get(email) logger.warn("Failed to send message to %s/%s (SMTP %d: %s)", uname, email, error[0], error[1]) if error[0] == 550: continue else: cancel_request(attrs, database) except smtplib.SMTPException: logger.exception("Failed to send message to %s/%s", uname, email) cancel_request(attrs, database)
def test_sendmail(cereconf): from Cerebrum.utils.email import sendmail mail = { 'toaddr': '[email protected],[email protected]', 'fromaddr': '*****@*****.**', 'cc': '[email protected],[email protected]', 'subject': 'Testing', 'body': 'hello this is dog' } result = sendmail(**mail) assert 'To: ' + mail['toaddr'] in result assert 'From: ' + mail['fromaddr'] in result assert 'Cc: ' + mail['cc'] in result assert 'Subject: ' + mail['subject'] in result assert base64.b64encode(mail['body']) in result
def test_sendmail(cereconf): from Cerebrum.utils.email import sendmail mail = { 'toaddr': '[email protected],[email protected]', 'fromaddr': '*****@*****.**', 'cc': '[email protected],[email protected]', 'subject': 'Testing', 'body': 'hello this is dog' } result = sendmail(**mail) assert 'To: ' + mail['toaddr'] in result assert 'From: ' + mail['fromaddr'] in result assert 'Cc: ' + mail['cc'] in result assert 'Subject: ' + mail['subject'] in result assert base64.b64encode(mail['body']) in result
def send_mail(mail_to, mail_from, subject, body, mail_cc=None): """Function for sending mail to users. Will respect dryrun, as that is given and handled by Cerebrum.utils.email.sendmail, which is then not sending the e-mail. @type mail_to: string @param mail_to: The recipient of the Email. @type mail_from: string @param mail_from: The senders address. @type subject: string @param subject: The messages subject. @type body: string @param body: The message body. @type mail_cc: string @param mail_cc: An optional address that the mail will be CCed to. @rtype: bool @return: A boolean that tells if the email was sent sucessfully or not. """ try: ret = sendmail(mail_to, mail_from, subject, body, cc=mail_cc, debug=dryrun) if debug_verbose: print("---- Mail: ---- \n" + ret) except smtplib.SMTPRecipientsRefused as e: failed_recipients = e.recipients logger.info("Failed to notify <%d> users", len(failed_recipients)) for _, condition in failed_recipients.iteritems(): logger.info("Failed to notify: %s", condition) except smtplib.SMTPException as msg: logger.warn("Error sending to %s: %s" % (mail_to, msg)) return False return True
def send_mail(mail_to, mail_from, subject, body, mail_cc=None): """Function for sending mail to users. Will respect dryrun, as that is given and handled by Cerebrum.utils.email.sendmail, which is then not sending the e-mail. @type mail_to: string @param mail_to: The recipient of the Email. @type mail_from: string @param mail_from: The senders address. @type subject: string @param subject: The messages subject. @type body: string @param body: The message body. @type mail_cc: string @param mail_cc: An optional address that the mail will be CCed to. @rtype: bool @return: A boolean that tells if the email was sent sucessfully or not. """ try: ret = sendmail(mail_to, mail_from, subject, body, cc=mail_cc, debug=dryrun) if debug_verbose: print("---- Mail: ---- \n" + ret) except smtplib.SMTPRecipientsRefused as e: failed_recipients = e.recipients logger.info("Failed to notify <%d> users", len(failed_recipients)) for _, condition in failed_recipients.iteritems(): logger.info("Failed to notify: %s", condition) except smtplib.SMTPException as msg: logger.warn("Error sending to %s: %s" % (mail_to, msg)) return False return True
def main(inargs=None): parser = argparse.ArgumentParser(description=__doc__) dryrun_arg = parser.add_argument('-d', '--dryrun', dest='dryrun', action='store_true', default=False, help='Dry-run (do not send report email)') parser.add_argument('-s', '--start-date', dest='start_date', type=ISO.ParseDate, default=now() + RelativeDateTime(days=-1), help='Start date (YYYY-MM-DD) for events,' ' defaults to %(default)s (1 day ago)') parser.add_argument('-c', '--change-program', dest='change_program', help='Only get events for %(metavar)s') mail_to_arg = parser.add_argument( '-t', '--mail-to', dest='mail_to', metavar='ADDR', help="Send an email report to %(metavar)s") mail_from_arg = parser.add_argument('-f', '--mail-from', dest='mail_from', metavar='ADDR', help="Send reports from %(metavar)s") Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(inargs) # Require mail_to and mail_from, or neither if bool(args.mail_from) ^ bool(args.mail_to): apply_to = mail_to_arg if args.mail_to else mail_from_arg missing = mail_from_arg if args.mail_to else mail_to_arg parser.error( argparse.ArgumentError( apply_to, "Must set {0} as well".format('/'.join( missing.option_strings)))) # Require mail_to or dryrun to be set if not any((args.mail_to, args.dryrun)): parser.error( argparse.ArgumentError( mail_to_arg, "Must set {0} if not sending mail".format( '/'.join(dryrun_arg.option_strings)))) Cerebrum.logutils.autoconf('cronjob', args) logger.info('Start of script %s', parser.prog) logger.debug("args: %r", args) db = Factory.get('Database')() new_persons = list( get_new_persons(db, args.start_date, change_program=args.change_program)) if args.change_program: subject = u'New persons from %s since %s' % (args.change_program, args.start_date.date) else: subject = u'New persons since %s' % (args.start_date.date, ) message = u'\n'.join(report_new_persons(new_persons)) if new_persons: if args.mail_to and not args.dryrun: sendmail(args.mail_to, args.mail_from, subject, message) logger.info("Sent report to %s", args.mail_to) else: print("To: {0}".format(args.mail_to)) print("From: {0}".format(args.mail_from)) print("Subject: {0}".format(subject)) print("") print(message) else: logger.info("Nothing to report") logger.info('Done with script %s', parser.prog)
def main(inargs=None): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__) parser.add_argument( '-o', '--output', metavar='FILE', type=argparse.FileType('w'), default='-', help='output file for report, defaults to stdout') parser.add_argument( '-e', '--encoding', dest='codec', default=DEFAULT_ENCODING, type=codec_type, help="output file encoding, defaults to %(default)s") parser.add_argument( '--min', dest='minimum', type=lambda x: abs(int(x)), default=1, metavar='MIN', help='Report persons with more than %(metavar)s users' ' (default: %(default)s)') parser.add_argument( '--max', dest='maximum', type=lambda x: abs(int(x)), default=None, metavar='MAX', help='Report persons with less than %(metavar)s users' ' (default: no limit)') source_arg = parser.add_argument( '--source_systems', default=DEFAULT_SOURCE, help="comma separated list of source systems to search through," " defaults to %(default)s") mail_to_arg = parser.add_argument( '-t', '--mail-to', dest='mail_to', metavar='ADDR', help="Send an email report to %(metavar)s") mail_from_arg = parser.add_argument( '-f', '--mail-from', dest='mail_from', metavar='ADDR', help="Send reports from %(metavar)s") Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(inargs) Cerebrum.logutils.autoconf('cronjob', args) # Require mail_to and mail_from, or neither if bool(args.mail_from) ^ bool(args.mail_to): apply_to = mail_to_arg if args.mail_to else mail_from_arg missing = mail_from_arg if args.mail_to else mail_to_arg parser.error(argparse.ArgumentError( apply_to, "Must set {0} as well".format('/'.join(missing.option_strings)))) db = Factory.get('Database')() co = Factory.get('Constants')(db) src = [get_constant(db, parser, co.AuthoritativeSystem, code, source_arg) for code in args.source_systems.split(',')] logger.info('Start of script %s', parser.prog) logger.debug("args: %r", args) logger.debug("source_systems: %r", src) stats = collections.defaultdict(int) persons = list(get_persons_by_sko(db, src, args.minimum, args.maximum, stats)) write_html_report(args.output, args.codec, persons, stats, args.minimum, args.maximum) args.output.flush() if args.output is not sys.stdout: args.output.close() logger.info('Report written to %s', args.output.name) if args.mail_to: subject = "Report from %s" % parser.prog body = make_email_report(persons, args.minimum, args.maximum, stats) logger.debug('Sending report to %r (%r)', args.mail_to, subject) sendmail(args.mail_to, args.mail_from, subject, body) logger.info('Done with script %s', parser.prog)
def main(inargs=None): parser = argparse.ArgumentParser() parser.add_argument( '-t', '--type', dest='config', type=eventconf_type, required=True, help="Sync type (a valid entry in eventconf.CONFIG)") parser.add_argument( '-f', '--file', dest='state', required=True, help="read and write state to %(metavar)s") parser.add_argument( '-m', '--mail', help="Send reports to %(metavar)s") parser.add_argument( '-s', '--sender', help="Send reports from %(metavar)s") parser.add_argument( '-r', '--report-file', dest='report', help="Write the report to %(metavar)s") Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(inargs) if bool(args.mail) ^ bool(args.sender): raise ValueError("Must give both mail and sender") Cerebrum.logutils.autoconf('cronjob', args) attr_config = args.config['state_check_conf'] mb_ou = args.config['mailbox_ou'] try: with open(args.state, 'r') as f: state = pickle.load(f) except IOError: logger.warn('No existing state file %s', args.state) state = None sc = StateChecker(args.config) # Collect group info from Cerebrum and Exchange sc.init_ldap() mb_info = sc.collect_exchange_mail_info(mb_ou) sc.close() # Collect mail-data from Cerebrum cere_mb_info = sc.collect_cerebrum_mail_info() # Compare mailbox state between Cerebrum and Exchange new_state, report = sc.compare_mailbox_state(mb_info, cere_mb_info, state, attr_config) try: rep = u'\n'.join(report) except UnicodeError as e: logger.warn('Bytestring data in report: %r', e) tmp = [] for x in report: tmp.append(x.decode('UTF-8')) rep = u'\n'.join(tmp) # Send a report by mail if args.mail and args.sender: sendmail(args.mail, args.sender, 'Exchange mailbox state report', rep.encode('utf-8')) # Write report to file if args.report: with open(args.report, 'w') as f: f.write(rep.encode('utf-8')) with open(args.state, 'w') as f: pickle.dump(new_state, f)
def main(inargs=None): parser = argparse.ArgumentParser( description="Change the name of an account", ) parser.add_argument( '-o', '--old', dest='old_name', required=True, help='Change account name from %(metavar)s', metavar='<name>', ) parser.add_argument( '-n', '--new', dest='new_name', required=True, help='Change account name to %(metavar)s', metavar='<name>', ) parser.add_argument( '-N', '--no-email', dest='notify_user', action='store_false', default=True, help='Do not notify user about change (default: notify)', ) add_commit_args(parser) Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(inargs) Cerebrum.logutils.autoconf('tee', args) logger.info('Start %s', parser.prog) logger.debug('args: %r', args) dryrun = not args.commit old_name = args.old_name new_name = args.new_name notify_user = args.notify_user db = Factory.get('Database')() db.cl_init(change_program='ren_acc') worker = Changer(db) co = Factory.get('Constants')(db) ac = Factory.get('Account')(db) pe = Factory.get('Person')(db) # Find person full name (old) ac.find_by_name(old_name) pe.find(ac.owner_id) old_person_name = pe.get_name(co.system_cached, co.name_full) ac.clear() pe.clear() print("old_name:%s" % old_name) print("new name:%s" % new_name) send_user_mail = worker.rename_account(old_name, new_name) and notify_user update_legacy(db, old_name, new_name) ac.find_by_name(new_name) pe.find(ac.owner_id) new_person_name = pe.get_name(co.system_cached, co.name_full) print("Old name:", new_person_name) print("New name:", old_person_name) print("Notify user:"******"Are you sure you want to write changes?") dryrun = not is_sure if dryrun: logger.info('Rolling back changes') db.rollback() else: logger.info('Commiting changes') db.commit() if not dryrun and enable_sut_email: logger.info("Not running in dryrun mode, sending SUT notification") # Sending email to SUT queue in RT account_expired = '' if ac.is_expired(): account_expired = (' Imidlertid er ikke kontoen aktiv, ' 'men kan reaktiveres når som helst.') # TBD : remove comment below when leetah is removed recipient = '*****@*****.**' sendmail( toaddr=recipient, fromaddr='*****@*****.**', subject=('Brukernavn endret (%s erstattes av %s)' % (old_name, new_name)), body=('Brukernavnet %s er endret til %s. Videresend ' 'e-post, flytt filer, e-post, osv. fra %s til ' '%s.%s' % (old_name, new_name, old_name, new_name, account_expired)), cc=None, charset='iso-8859-1', debug=dryrun) logger.info("Notified %r", recipient) if not dryrun and enable_rt_email: logger.info("Not running in dryrun mode, sending RT notification") # Sending email to PORTAL queue in RT # account_expired = '' # if ac.is_expired(): # account_expired = (' Imidlertid er ikke kontoen aktiv, ' # 'men kan reaktiveres når som helst.') recipient = '*****@*****.**' sendmail(toaddr=recipient, fromaddr='*****@*****.**', subject=('Brukernavn endret (%s erstattes av %s)' % (old_name, new_name)), body=('Brukernavnet %s er endret til %s.' % (old_name, new_name)), cc=None, charset='iso-8859-1', debug=False) logger.info("Notified %r", recipient) # Sending email to AD nybrukere if necessary mailto_ad = False try: spreads = ac.get_spread() for spread in spreads: if spread['spread'] == co.spread_uit_ad_account: mailto_ad = True break except Exception: logger.debug('No AD-spread on account') if not dryrun and enable_ad_email and mailto_ad: logger.info("Not running in dryrun mode, sending AD notification") riktig_brukernavn = ' Nytt brukernavn er %s.' % (new_name) if ac.is_expired(): riktig_brukernavn += (' Imidlertid er ikke kontoen aktiv, og ' 'vil kun sendes til AD når den blir ' 'reaktivert.') recipient = '*****@*****.**' sendmail(toaddr=recipient, fromaddr='*****@*****.**', subject='Brukernavn endret', body=('Brukernavnet %s er endret i BAS.%s' % (old_name, riktig_brukernavn)), cc=None, charset='iso-8859-1', debug=dryrun) logger.info("Notified %r", recipient) if not dryrun and enable_user_email and send_user_mail: logger.info("Not running in dryrun mode, sending user notification") # SEND MAIL TO OLD AND NEW ACCOUNT + "BCC" to bas-admin! sender = '*****@*****.**' # TBD: remove below comment when leetah is removed # recipient = send_user_mail['OLD_MAIL'] # cc = [send_user_mail['NEW_MAIL']] # template = os.path.join(cereconf.TEMPLATE_DIR, # 'rename_account.tmpl') # result = mail_template( # recipient=recipient, # template_file=template, # sender=sender, # cc=cc, # substitute=send_user_mail, # charset='utf-8', # debug=dryrun) # print("Mail sent to: %s" % (recipient)) # print("cc to %s" % (cc)) # if dryrun: # print("\nDRYRUN: mailmsg=\n%s" % result) # BCC recipient = '*****@*****.**' template = os.path.join(cereconf.TEMPLATE_DIR, 'rename_account.tmpl') mail_template(recipient=recipient, template_file=template, sender=sender, substitute=send_user_mail, charset='utf-8', debug=dryrun) logger.info("BCC sent to %r", recipient) logger.info('Done %s', parser.prog)
def main(argv=None): """Main processing hub for program.""" if argv is None: argv = sys.argv # Default values for command-line options options = { "vlanfile": None, "datafile": None, "force": False, "status_recipients": None, "error_recipients": None, "mail-from": None, "mail-cc": None } ###################################################################### # Option-gathering try: opts, args = getopt.getopt(argv[1:], "hd:v:fs:e:", [ "help", "datafile=", "vlanfile=", "force", "status_recipients=", "error_recipients=", "mail-from=", "mail-cc=" ]) except getopt.GetoptError as error: usage(message=error.msg) return 1 for opt, val in opts: if opt in ( '-h', '--help', ): usage() return 0 if opt in ( '-f', '--force', ): options["force"] = True if opt in ( '-v', '--vlanfile', ): options["vlanfile"] = val if opt in ( '-d', '--datafile', ): options["datafile"] = val if opt in ( '-s', '--status_recipients', ): options["status_recipients"] = val if opt in ( '-e', '--error_recipients', ): options["error_recipients"] = val if opt in ('--mail-from', ): options["mail-from"] = val if opt in ('--mail-cc', ): options["mail-cc"] = val logger.debug("VLAN-file: '%s'" % options["vlanfile"]) logger.debug("Datafile: '%s'" % options["datafile"]) if not options["datafile"]: usage("Error: need datafile specified.") return 2 ###################################################################### # Data-processing if options["vlanfile"]: subnet_to_vlan = parse_vlan_file(options["vlanfile"]) else: subnet_to_vlan = {} subnets_in_file = parse_data_file(options["datafile"], subnet_to_vlan) (changes, errors) = compare_file_to_db(subnets_in_file, options["force"]) ###################################################################### # Feedback to interested parties today = time.strftime("%Y-%m-%d") doc_info = "" if cereconf.DNS_SUBNETIMPORT_ERRORDOC_URL is not None: doc_info = ("For more information concerning this import and any " "errors that are reported, please direct your browser to " "%s\n\n" % cereconf.DNS_SUBNETIMPORT_ERRORDOC_URL) if errors: mail_to = options["error_recipients"] subject = "Errors from subnet-import %s" % today mail_body = doc_info mail_body += ("The following errors were encountered during the" " import:\n\n") mail_body += "\n\n".join(errors) if options["force"]: mail_body += ("\n\nImport forced - non-erronous " "changes made anyway.") mail_body += ("\nThe following changes were made:\n%s\n" % "\n".join(changes)) logger.info("Force-committing non-erronous changes to database.") logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) db.commit() return 0 else: mail_body += "\n\nImport not completed - no changes made." mail_body += "Fix the above problems, then rerun the import.\n" logger.error("Errors encountered. No changes made by import.") db.rollback() logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) return 3 else: mail_to = options["status_recipients"] subject = "Status from subnet-import %s" % today mail_body = doc_info mail_body += "Subnet-import completed without problems\n" if changes: mail_body += ("The following changes were made:\n%s\n" % "\n".join(changes)) logger.info("Committing all changes to database.") db.commit() else: logger.info("No changes needed to be done during this run. " "No mail sent") return 0 logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) return 0
def main(argv=None): """Main processing hub for program.""" if argv is None: argv = sys.argv # Default values for command-line options options = {"vlanfile": None, "datafile": None, "force": False, "status_recipients": None, "error_recipients": None, "mail-from": None, "mail-cc": None} ###################################################################### # Option-gathering try: opts, args = getopt.getopt(argv[1:], "hd:v:fs:e:", ["help", "datafile=", "vlanfile=", "force", "status_recipients=", "error_recipients=", "mail-from=", "mail-cc="]) except getopt.GetoptError as error: usage(message=error.msg) return 1 for opt, val in opts: if opt in ('-h', '--help',): usage() return 0 if opt in ('-f', '--force',): options["force"] = True if opt in ('-v', '--vlanfile',): options["vlanfile"] = val if opt in ('-d', '--datafile',): options["datafile"] = val if opt in ('-s', '--status_recipients',): options["status_recipients"] = val if opt in ('-e', '--error_recipients',): options["error_recipients"] = val if opt in ('--mail-from',): options["mail-from"] = val if opt in ('--mail-cc',): options["mail-cc"] = val logger.debug("VLAN-file: '%s'" % options["vlanfile"]) logger.debug("Datafile: '%s'" % options["datafile"]) if not options["datafile"]: usage("Error: need datafile specified.") return 2 ###################################################################### # Data-processing if options["vlanfile"]: subnet_to_vlan = parse_vlan_file(options["vlanfile"]) else: subnet_to_vlan = {} subnets_in_file = parse_data_file(options["datafile"], subnet_to_vlan) (changes, errors) = compare_file_to_db(subnets_in_file, options["force"]) ###################################################################### # Feedback to interested parties today = time.strftime("%Y-%m-%d") doc_info = "" if cereconf.DNS_SUBNETIMPORT_ERRORDOC_URL is not None: doc_info = ("For more information concerning this import and any " "errors that are reported, please direct your browser to " "%s\n\n" % cereconf.DNS_SUBNETIMPORT_ERRORDOC_URL) if errors: mail_to = options["error_recipients"] subject = "Errors from subnet-import %s" % today mail_body = doc_info mail_body += ("The following errors were encountered during the" " import:\n\n") mail_body += "\n\n".join(errors) if options["force"]: mail_body += ("\n\nImport forced - non-erronous " "changes made anyway.") mail_body += ("\nThe following changes were made:\n%s\n" % "\n".join(changes)) logger.info("Force-committing non-erronous changes to database.") logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) db.commit() return 0 else: mail_body += "\n\nImport not completed - no changes made." mail_body += "Fix the above problems, then rerun the import.\n" logger.error("Errors encountered. No changes made by import.") db.rollback() logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) return 3 else: mail_to = options["status_recipients"] subject = "Status from subnet-import %s" % today mail_body = doc_info mail_body += "Subnet-import completed without problems\n" if changes: mail_body += ("The following changes were made:\n%s\n" % "\n".join(changes)) logger.info("Committing all changes to database.") db.commit() else: logger.info("No changes needed to be done during this run. " "No mail sent") return 0 logger.info("Sending mail to '%s' (CC: '%s')", mail_to, options["mail-cc"]) sendmail(mail_to, options["mail-from"], subject, mail_body, cc=options["mail-cc"]) return 0
def send_mail(self, uname, user_info, nr, forward=False): """ Get template file based on user_info and expiring action number to create Subject and body of mail. Get mail addresses based on type of account and expiring action number. If a critical error occurs or sending the actual mail fails return False, else return True. """ logger.debug("send_mail(uname=%r, user_info=%r, nr=%r, forward=%r)", uname, user_info, nr, forward) ac = Factory.get('Account')(self.db) ac.find_by_name(uname) # Do not send mail to quarantined accounts if ac.get_entity_quarantine(): logger.info("Account is quarantened - no mail sent: %s", uname) return False # Assume that there exists template files for the mail texts # and that cereconf.py has the dict USER_EXPIRE_MAIL lines = email_templates.get_template(nr) if not lines: return False msg = [] for line in lines: if line.strip().startswith('From:'): email_from = line.split(':')[1] elif line.strip().startswith('Subject:'): subject = line.split(':', 1)[1] subject = subject.replace('$USER$', uname) else: msg.append(line) body = ''.join(msg) body = body.replace('$USER$', uname) body = body.replace('$EXPIRE_DATE$', user_info['expire_date'].strftime('%Y-%m-%d')) # OK, tenk på hvordan dette skal gjøres pent. if user_info['ou']: body = body.replace('ved $OU$', 'ved %s' % user_info['ou']) body = body.replace('at $OU$', 'at %s' % user_info['ou']) email_addrs = self.get_email_addresses(user_info['account_id'], nr, forward) if not email_addrs: logger.warning("No email addresses available for user_info=%s", repr(user_info)) return False try: logger.info("Sending %d. mail To: %s", nr, ', '.join(email_addrs)) sendmail( toaddr=', '.join(email_addrs), fromaddr=email_from, subject=subject, body=body.encode("iso8859-1"), debug=self.dryrun, ) if len(email_addrs) > 2: logger.warning("Multiple email addrs for account_id=%r (%r)", user_info['account_id'], email_addrs) # TODO: We return False, even though we sent emails? return False return True except Exception: logger.error("Could not send mail To: %s", ', '.join(email_addrs), exc_info=True) return False
def main(inargs=None): parser = argparse.ArgumentParser() parser.add_argument('-t', '--type', dest='config', type=eventconf_type, required=True, help="Sync type (a valid entry in eventconf.CONFIG)") parser.add_argument('-f', '--file', dest='state', required=True, help="read and write state to %(metavar)s") parser.add_argument('-m', '--mail', help="Send reports to %(metavar)s") parser.add_argument('-s', '--sender', help="Send reports from %(metavar)s") parser.add_argument('-r', '--report-file', dest='report', help="Write the report to %(metavar)s") Cerebrum.logutils.options.install_subparser(parser) args = parser.parse_args(inargs) if bool(args.mail) ^ bool(args.sender): raise ValueError("Must give both mail and sender") Cerebrum.logutils.autoconf('cronjob', args) attr_config = args.config['state_check_conf'] mb_ou = args.config['mailbox_ou'] try: with open(args.state, 'r') as f: state = pickle.load(f) except IOError: logger.warn('No existing state file %s', args.state) state = None sc = StateChecker(args.config) # Collect group info from Cerebrum and Exchange sc.init_ldap() mb_info = sc.collect_exchange_mail_info(mb_ou) sc.close() # Collect mail-data from Cerebrum cere_mb_info = sc.collect_cerebrum_mail_info() # Compare mailbox state between Cerebrum and Exchange new_state, report = sc.compare_mailbox_state(mb_info, cere_mb_info, state, attr_config) try: rep = u'\n'.join(report) except UnicodeError as e: logger.warn('Bytestring data in report: %r', e) tmp = [] for x in report: tmp.append(x.decode('UTF-8')) rep = u'\n'.join(tmp) # Send a report by mail if args.mail and args.sender: sendmail(args.mail, args.sender, 'Exchange mailbox state report', rep.encode('utf-8')) # Write report to file if args.report: with open(args.report, 'w') as f: f.write(rep.encode('utf-8')) with open(args.state, 'w') as f: pickle.dump(new_state, f)