def main(string_args: Optional[List[str]] = None) -> None: """Parse command line arguments and send mails.""" parser = argparse.ArgumentParser( description='Send focus emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( 'action', choices=('dry-run', 'list', 'send'), default='dry-run', help='Whether to process to a dry run, list all concerned users, or really send emails.') parser.add_argument( '--dry-run-email', default='*****@*****.**', help='Process a dry run and send email to this email address.') parser.add_argument( '--disable-sentry', action='store_true', help='Disable logging to Sentry.') args = parser.parse_args(string_args) logging.basicConfig(level='INFO') if args.action == 'send' and not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option') return if args.action == 'send' and auth.SECRET_SALT == auth.FAKE_SECRET_SALT: raise ValueError('Set the prod SECRET_SALT env var before continuing.') if args.action == 'list': logging.info('Potential focus emails: %s', sorted(_FOCUS_CAMPAIGNS.keys())) _send_focus_emails(args.action, args.dry_run_email)
def main(string_args: Optional[List[str]] = None) -> None: """Parse command line arguments and trigger the clean_guest_users function.""" parser = argparse.ArgumentParser(description='Clean guests user from the database.') parser.add_argument( '--disable-sentry', action='store_true', help='Disable logging to Sentry.') registered_to_group = parser.add_mutually_exclusive_group() registered_to_group.add_argument( '--registered-to', help='Consider only users who registered before \ this date.') registered_to_group.add_argument( '--registered-to-days-ago', default=7, type=int, help='Consider only users who registered more than N days ago.') parser.add_argument( '--no-dry-run', dest='dry_run', action='store_false', help='No dry run really store in DB.') args = parser.parse_args(string_args) logging.basicConfig(level='INFO') if not args.dry_run and not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option') return if args.registered_to: to_date = args.registered_to else: to_date = (now.get() - datetime.timedelta(days=args.registered_to_days_ago))\ .strftime('%Y-%m-%dT%H:%M:%S') logging.info( 'Cleaned %d users and got %d errors', *clean_guest_users(_DB, to_date, args.dry_run))
def main(string_args: Optional[List[str]] = None, out: TextIO = sys.stdout) \ -> None: """Parse command line arguments and trigger _compute_assessment_report function. docker-compose run --rm -e MONGO_URL="$PROD_MONGO" frontend-flask \ python /work/bob_emploi/frontend/server/asynchronous/assess_assessment.py -s 2017-11-01 """ parser = argparse.ArgumentParser( description='Statistics on users whith or whithout assessment.') since_group = parser.add_mutually_exclusive_group() since_group.add_argument( '-d', '--since-days-ago', type=int, help='Process use cases registered in the last given days.') since_group.add_argument( '-s', '--since', default='2018', help='Process use cases registered since the given date.') parser.add_argument( '-u', '--until', help='Process use cases registered before (but not including) the given date.') parser.add_argument( '-e', '--examples', default='1', type=int, help='Show the given number of examples of use cases whithout assessment.') parser.add_argument('--verbose', '-v', action='store_true', help='More detailed output.') parser.add_argument( '--no-dry-run', dest='dry_run', action='store_false', help='No dry run really send reports.') args = parser.parse_args(string_args) if not args.dry_run: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) logging.basicConfig(level='DEBUG' if args.verbose else 'INFO') present = now.get() from_date = args.since if args.since_days_ago: from_date = present - datetime.timedelta(days=args.since_days_ago) to_date = present if args.since_days_ago or not args.until else args.until report_text = _compute_assessment_report( args.examples, from_date, to_date) if args.dry_run: out.write(report_text) return if _SLACK_ASSESSER_URL: requests.post(_SLACK_ASSESSER_URL, json={'attachments': [{ 'mrkdwn_in': ['text'], 'title': f'Assessment coverage from {from_date} to {to_date}', 'text': report_text, }]})
def main(string_args: Optional[list[str]] = None) -> None: """Parse command line arguments and send mails.""" parser = argparse.ArgumentParser( description='Send focus emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( 'action', choices=('dry-run', 'list', 'send'), default='dry-run', help='Whether to process to a dry run, list all concerned users, or really send emails.') parser.add_argument( '--dry-run-email', default='*****@*****.**', help='Process a dry run and send email to this email address.') parser.add_argument( '--restrict-campaigns', help='IDs of campaigns to send.', choices=sorted(_FOCUS_CAMPAIGNS.keys()), nargs='*') report.add_report_arguments(parser, setup_dry_run=False) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args, dry_run=args.action != 'send'): return if args.action == 'send' and auth_token.SECRET_SALT == auth_token.FAKE_SECRET_SALT: raise ValueError('Set the prod SECRET_SALT env var before continuing.') if args.action == 'list': logging.info('Potential focus emails: %s', sorted(_FOCUS_CAMPAIGNS.keys())) _send_focus_emails( args.action, args.dry_run_email, restricted_campaigns=args.restrict_campaigns)
def main(string_args: Optional[list[str]] = None) -> None: """Parse command line arguments and trigger the update_users_client_metrics function.""" parser = argparse.ArgumentParser( description='Synchronize MongoDB client metrics fields from Amplitude') parser.add_argument( '--registered-from', help='Consider only users who registered after this date.') yesterday = str((now.get() - datetime.timedelta(days=1)).date()) parser.add_argument( '--registered-to', default=yesterday, help='Consider only users who registered before this date.') report.add_report_arguments(parser) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args): return user_db = mongo.get_connections_from_env().user_db update_users_client_metrics(user_db.user, from_date=args.registered_from, to_date=args.registered_to, dry_run=args.dry_run)
def main(string_args: Optional[list[str]] = None) -> None: """Clean all support tickets marked for deletion.""" user_db = mongo.get_connections_from_env().user_db parser = argparse.ArgumentParser( description='Clean support tickets from the database.') report.add_report_arguments(parser) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args): return instant = proto.datetime_to_json_string(now.get()) result = user_db.user.update_many( {}, {'$pull': { 'supportTickets': { 'deleteAfter': { '$lt': instant } } }}) logging.info('Removed deprecated support tickets for %d users.', result.modified_count) clean_result = user_db.user.update_many({'supportTickets': { '$size': 0 }}, {'$unset': { 'supportTickets': '' }}) if clean_result.matched_count: logging.info('Removed empty support ticket list for %d users.', clean_result.modified_count)
def main(es_client: elasticsearch.Elasticsearch, string_args: Optional[list[str]] = None) -> None: """Parse command line arguments and trigger sync_employment_status function.""" parser = argparse.ArgumentParser( description= 'Synchronize mongodb employement status fields retrieving typeform data.' ) parser.add_argument('-r', '--registered-from', default='2017-06-01', help='Process users registered from the given date') parser.add_argument( '--force-recreate', action='store_true', help= 'If set, completely cleanup the index, rather than updating existing documents.' ) parser.add_argument('--index', default='bobusers', help='Elasticsearch index to write to') report.add_report_arguments(parser) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args): return export_user_to_elasticsearch(es_client, args.index, args.registered_from, force_recreate=args.force_recreate, dry_run=args.dry_run)
def main(string_args: Optional[List[str]] = None, out: TextIO = sys.stdout) -> None: """Parse command line arguments, computes a report and send it.""" parser = argparse.ArgumentParser( description= 'Compute a report of user feedbacks and send it through Slack or email' ) parser.add_argument('--no-dry-run', dest='dry_run', action='store_false', help='No dry run really send reports.') parser.add_argument('report', choices=_REPORTS.keys(), help='Report type to send.') from_group = parser.add_mutually_exclusive_group(required=True) from_group.add_argument( '--from', dest='from_date', help='Only consider feedback sent after this date.') from_group.add_argument( '--from-days-ago', help='Only consider feedback sent in the last days.', type=int) parser.add_argument('--to', dest='to_date', help='Only consider feedback sent before this date.') args = parser.parse_args(string_args) if not args.dry_run: report_helper.setup_sentry_logging(os.getenv('SENTRY_DSN')) if args.from_date: from_date = args.from_date else: from_date = (datetime.datetime.now() - datetime.timedelta(days=args.from_days_ago))\ .strftime('%Y-%m-%d') _compute_and_send_report(args.report, from_date, args.to_date, out, dry_run=args.dry_run)
def main(es_client: elasticsearch.Elasticsearch, string_args: Optional[List[str]] = None) -> None: """Parse command line arguments and trigger sync_employment_status function.""" parser = argparse.ArgumentParser( description= 'Synchronize mongodb employement status fields retrieving typeform data.' ) parser.add_argument('-r', '--registered-from', default='2017-06-01', help='Process users registered from the given date') parser.add_argument('--no-dry-run', dest='dry_run', action='store_false', help='No dry run really store in elasticsearch.') parser.add_argument('--index', default='bobusers', help='Elasticsearch index to write to') parser.add_argument('--verbose', '-v', action='store_true', help='More detailed output.') parser.add_argument('--disable-sentry', action='store_true', help='Disable logging to Sentry.') args = parser.parse_args(string_args) logging.basicConfig(level='DEBUG' if args.verbose else 'INFO') if not args.dry_run and not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' ) return export_user_to_elasticsearch(es_client, args.index, args.registered_from, dry_run=args.dry_run)
def main(string_args: Optional[List[str]] = None) -> None: """Clean all support tickets marked for deletion.""" parser = argparse.ArgumentParser( description='Clean support tickets from the database.') parser.add_argument('--disable-sentry', action='store_true', help='Disable logging to Sentry.') args = parser.parse_args(string_args) logging.basicConfig(level='INFO') if not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' ) return instant = proto.datetime_to_json_string(now.get()) result = _DB.user.update_many( {}, {'$pull': { 'supportTickets': { 'deleteAfter': { '$lt': instant } } }}) logging.info('Removed deprecated support tickets for %d users.', result.modified_count) clean_result = _DB.user.update_many({'supportTickets': { '$size': 0 }}, {'$unset': { 'supportTickets': '' }}) if clean_result.matched_count: logging.info('Removed empty support ticket list for %d users.', clean_result.modified_count)
def main(string_args=None): """Parse command line arguments and trigger the update_users_client_metrics function.""" parser = argparse.ArgumentParser( description='Synchronize MongoDB client metrics fields from Amplitude') parser.add_argument('--disable-sentry', action='store_true', help='Disable logging to Sentry.') parser.add_argument( '--registered-from', help='Consider only users who registered after this date.') yesterday = str((now.get() - datetime.timedelta(days=1)).date()) parser.add_argument( '--registered-to', default=yesterday, help='Consider only users who registered before this date.') parser.add_argument('--no-dry-run', dest='dry_run', action='store_false', help='No dry run really store in DB.') args = parser.parse_args(string_args) logging.basicConfig(level='INFO') if not args.dry_run and not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' ) return update_users_client_metrics(_DB.user, from_date=args.registered_from, to_date=args.registered_to, dry_run=args.dry_run)
def main(string_args: Optional[list[str]] = None) -> None: """Parse command line arguments and trigger the clean_guest_users function.""" parser = argparse.ArgumentParser( description='Clean guests and inactive users from the database.') parser.add_argument( '--max-users', help='Only consider a maximum of this number of users.', type=int) report.add_report_arguments(parser) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args): return user_db = mongo.get_connections_from_env().user_db logging.info( 'Cleaned %d users, set check date for %d users and got %d errors', *clean_users(user_db, args.dry_run, args.max_users))
def main(string_args: Optional[list[str]] = None) -> None: """Check the status of sent emails on MailJet and update our Database. """ parser = argparse.ArgumentParser( description='Update email status on sent emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) report.add_report_arguments(parser) parser.add_argument( '--campaigns', choices=mail_blast.campaign.list_all_campaigns(), nargs='*', help='Campaign IDs to check. If not specified, run for all campaigns.') parser.add_argument('--mongo-collection', default='user', help='Name of the mongo collection to update.') args = parser.parse_args(string_args) if not report.setup_sentry_logging(args): return email_mongo_filter = { 'mailjetMessageId': { '$exists': True }, } if args.campaigns: email_mongo_filter['campaignId'] = {'$in': args.campaigns} yesterday = proto.datetime_to_json_string(now.get() - datetime.timedelta(days=1)) mongo_filter = { '$or': [ # Emails that we've never checked. { 'emailsSent': { '$elemMatch': dict({ 'lastStatusCheckedAt': { '$exists': False }, }, **email_mongo_filter), }, }, # Emails checked less than two weeks after they have been sent and # that we haven't checked today. { 'emailsSent': { '$elemMatch': dict( { 'lastStatusCheckedAt': { '$lt': yesterday }, 'lastStatusCheckedAfterDays': { '$not': { '$gte': 14 } }, }, **email_mongo_filter), }, }, # Emails sent less than 24 hours ago. { 'emailsSent': { '$elemMatch': dict({ 'sentAt': { '$gt': yesterday }, }, **email_mongo_filter), }, }, ], } user_db = mongo.get_connections_from_env().user_db mongo_collection = user_db.get_collection(args.mongo_collection) selected_users = mongo_collection.find(mongo_filter, {'emailsSent': 1}) treated_users = 0 # TODO(cyrille): Make sure errors are logged to sentry. # TODO(cyrille): If it fails on a specific user, keep going. for user in selected_users: emails_sent = user.get('emailsSent', []) updated_emails_sent = [ _update_email_sent_status(email, yesterday, campaign_ids=args.campaigns) for email in emails_sent ] mongo_collection.update_one( {'_id': user['_id']}, {'$set': { 'emailsSent': updated_emails_sent }}) treated_users += 1 if not treated_users % 100: logging.info('Treated %d users', treated_users)
def main(string_args: Optional[list[str]] = None) -> None: """Parse command line arguments and send mails.""" parser = argparse.ArgumentParser( description='Send focus emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter, epilog='''ROME info by prefix file can be downloaded at \ https://airtable.com/tbl5jBDdG3vnYPWNu/viwz9GaBDHEpjTCU9 ''') parser.add_argument('campaign', choices=campaign.list_all_campaigns(), help='Campaign type to send.') parser.add_argument( 'action', choices=('dry-run', 'list', 'send'), default='dry-run', help= 'Whether to process to a dry run, list all concerned users, or really send emails.' ) parser.add_argument( '--dry-run-email', default='*****@*****.**', help='Process a dry run and send email to this email address.') parser.add_argument( '--user-hash', help='Only send to users whose ID hash starts with this given hash. \ Hashing the ID ensures a uniform distribution, so this gives a consistent sample of users.' ) # TODO(cyrille): Replace with option to select only one user_id. parser.add_argument( '--user-id-start', help='Only send to users whose ID starts with this given hash. WARNING: \ hash distribution is not uniform for old users, do not use this to get a sample.' ) parser.add_argument( '--user-collection-prefix', default='', help='Send to users in the collection whose name is "{prefix}user"') registered_from_group = parser.add_mutually_exclusive_group() registered_from_group.add_argument( '--registered-from', default='2017-04-01', help='Consider only users who registered after \ this date.') registered_from_group.add_argument( '--registered-from-days-ago', type=int, help='Consider only users who registered less than N days ago.') registered_to_group = parser.add_mutually_exclusive_group() registered_to_group.add_argument( '--registered-to', default='2017-11-10', help='Consider only users who registered before \ this date.') registered_to_group.add_argument( '--registered-to-days-ago', type=int, help='Consider only users who registered more than N days ago.') parser.add_argument( '--days-since-any-email', default='2', type=int, help= "Consider only users who haven't received any email in the last given number of days." ) parser.add_argument( '--days-since-same-campaign', default='0', type=int, help= "Consider only users who haven't had the same email in the last given number of \ days. If default or 0, will not resend the same campaign to anyone.") parser.add_argument( '--days-since-same-campaign-unread', default='0', type=int, help= "Must be smaller than --days-since-same-campaign. Users who received an email between \ --days-since-same-campaign and --days-since-same-campaign-unread will only be sent a new \ one if they haven't read it.") parser.add_argument( '--log-reason-on-error', action='store_true', help='Show the reason why users are rejected from the blast') report.add_report_arguments(parser, setup_dry_run=False) args = parser.parse_args(string_args) if not report.setup_sentry_logging(args, dry_run=args.action != 'send'): return if args.days_since_same_campaign < args.days_since_same_campaign_unread: logging.error('Please use coherent values in the policy durations.') return policy = EmailPolicy(args.days_since_any_email, args.days_since_same_campaign_unread, args.days_since_same_campaign) registered_from = _date_from_today(args.registered_from, args.registered_from_days_ago) registered_to = _date_from_today(args.registered_to, args.registered_to_days_ago) logging.info( '%d emails sent.', blast_campaign(args.campaign, args.action, registered_from, registered_to, dry_run_email=args.dry_run_email, user_id_start=args.user_id_start, user_hash=args.user_hash, email_policy=policy, collection_prefix=args.user_collection_prefix, log_reason_on_error=args.log_reason_on_error))
def main(string_args: Optional[List[str]] = None) -> None: """Check the status of sent emails on MailJet and update our Database. """ parser = argparse.ArgumentParser( description='Update email status on sent emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '--campaigns', choices=mail_blast.campaign.list_all_campaigns(), nargs='*', help='Campaign IDs to check. If not specified, run for all campaigns.') parser.add_argument('--mongo-collection', default='user', help='Name of the mongo collection to update.') parser.add_argument('--disable-sentry', action='store_true', help='Disable logging to Sentry.') args = parser.parse_args(string_args) if not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' ) return email_mongo_filter = { 'mailjetMessageId': { '$exists': True }, } if args.campaigns: email_mongo_filter['campaignId'] = {'$in': args.campaigns} yesterday = proto.datetime_to_json_string(now.get() - datetime.timedelta(days=1)) mongo_filter = { '$or': [ # Emails that we've never checked. { 'emailsSent': { '$elemMatch': dict({ 'lastStatusCheckedAt': { '$exists': False }, }, **email_mongo_filter), }, }, # Emails checked less than two weeks after they have been sent and # that we haven't checked today. { 'emailsSent': { '$elemMatch': dict( { 'lastStatusCheckedAt': { '$lt': yesterday }, 'lastStatusCheckedAfterDays': { '$not': { '$gte': 14 } }, }, **email_mongo_filter), }, }, # Emails sent less than 24 hours ago. { 'emailsSent': { '$elemMatch': dict({ 'sentAt': { '$gt': yesterday }, }, **email_mongo_filter), }, }, ], } mongo_collection = _DB.get_collection(args.mongo_collection) selected_users = mongo_collection.find(mongo_filter, {'emailsSent': 1}) treated_users = 0 for user in selected_users: emails_sent = user.get('emailsSent', []) updated_emails_sent = [ _update_email_sent_status(email, yesterday, campaign_ids=args.campaigns) for email in emails_sent ] mongo_collection.update_one( {'_id': user['_id']}, {'$set': { 'emailsSent': updated_emails_sent }}) treated_users += 1 if not treated_users % 100: logging.info('Treated %d users', treated_users)
def main(string_args=None): """Parse command line arguments and send mails.""" parser = argparse.ArgumentParser( description='Send focus emails.', formatter_class=argparse.ArgumentDefaultsHelpFormatter, epilog='''ROME info by prefix file can be downloaded at \ https://airtable.com/tbl5jBDdG3vnYPWNu/viwz9GaBDHEpjTCU9 ''') parser.add_argument('campaign', choices=campaign.list_all_campaigns(), help='Campaign type to send.') parser.add_argument( 'action', choices=('dry-run', 'list', 'send'), default='dry-run', help= 'Whether to process to a dry run, list all concerned users, or really send emails.' ) parser.add_argument( '--dry-run-email', default='*****@*****.**', help='Process a dry run and send email to this email adress.') parser.add_argument( '--user-hash', help='Only send to users whose ID starts with this given hash. WARNING: \ hash distribution is not uniform for old users, do not use this to get a sample.' ) registered_from_group = parser.add_mutually_exclusive_group() registered_from_group.add_argument( '--registered-from', default='2017-04-01', help='Consider only users who registered after \ this date.') registered_from_group.add_argument( '--registered-from-days-ago', type=int, help='Consider only users who registered less than N days ago.') registered_to_group = parser.add_mutually_exclusive_group() registered_to_group.add_argument( '--registered-to', default='2017-11-10', help='Consider only users who registered before \ this date.') registered_to_group.add_argument( '--registered-to-days-ago', type=int, help='Consider only users who registered more than N days ago.') parser.add_argument('--disable-sentry', action='store_true', help='Disable logging to Sentry.') parser.add_argument( '--days-since-any-email', default='2', type=int, help= "Consider only users who haven't received any email in the last given number of days." ) parser.add_argument( '--days-since-same-campaign', default='0', type=int, help= "Consider only users who haven't had the same email in the last given number of \ days. If default or 0, will not resend the same campaign to anyone.") parser.add_argument( '--days-since-same-campaign-unread', default='0', type=int, help= "Must be smaller than --days-since-same-campaign. Users who received an email between \ --days-since-same-campaign and --days-since-same-campaign-unread will only be sent a new \ one if they haven't read it.") args = parser.parse_args(string_args) logging.basicConfig(level='INFO') if args.action == 'send' and not args.disable_sentry: try: report.setup_sentry_logging(os.getenv('SENTRY_DSN')) except ValueError: logging.error( 'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option' ) return if args.days_since_same_campaign < args.days_since_same_campaign_unread: logging.error('Please use coherent values in the policy durations.') return policy = EmailPolicy(args.days_since_any_email, args.days_since_same_campaign_unread, args.days_since_same_campaign) registered_from = _date_from_today(args.registered_from, args.registered_from_days_ago) registered_to = _date_from_today(args.registered_to, args.registered_to_days_ago) logging.info( '%d emails sent.', blast_campaign(args.campaign, args.action, registered_from, registered_to, dry_run_email=args.dry_run_email, user_hash=args.user_hash, email_policy=policy))