1- #! /usr/bin/env python
1+ #!/usr/bin/env python3
22# ------------------------------------------------------------------------------
33# Script which adds new users from google spreadsheet into the the cgds
44# user table. The following properties must be specified in portal.properties:
3636from oauth2client .client import flow_from_clientsecrets
3737from oauth2client .tools import run_flow , argparser
3838
39- from email .MIMEMultipart import MIMEMultipart
40- from email .MIMEBase import MIMEBase
41- from email .MIMEText import MIMEText
42- from email .Header import Header
43- from email .Utils import COMMASPACE , formatdate
44- from email import Encoders
39+ from email .mime .multipart import MIMEMultipart
40+ from email .mime .text import MIMEText
41+ from email .header import Header
42+ from email .utils import COMMASPACE , formatdate
4543
4644from googleapiclient .discovery import build
4745# ------------------------------------------------------------------------------
@@ -138,7 +136,7 @@ def __init__(self, inst_email, google_email, name, enabled, authorities):
138136def send_mail (to , subject , body , gmail_username , gmail_password , sender = MESSAGE_FROM_CMO , bcc = MESSAGE_BCC_CMO , server = None ):
139137
140138 if server is None :
141- print >> ERROR_FILE , 'smtp server must be specified'
139+ print ( 'smtp server must be specified' , file = ERROR_FILE )
142140 sys .exit (2 )
143141
144142 assert type (to )== list
@@ -213,10 +211,10 @@ def get_sheet_records(client, ss, ws):
213211 new_record [header [index ]] = None
214212 sheet_records .append (new_record )
215213 except Exception as e :
216- print >> ERROR_FILE , "There was an error connecting to google."
217- print >> ERROR_FILE , e
214+ print ( "There was an error connecting to google." , file = ERROR_FILE )
215+ print ( e , file = ERROR_FILE )
218216 exit (0 )
219-
217+
220218 return sheet_records
221219
222220# ------------------------------------------------------------------------------
@@ -230,8 +228,8 @@ def get_spreadsheet_title(client, ss):
230228 data = response .get ('properties' , {})
231229 spreadsheet_title = data ["title" ]
232230 except Exception as e :
233- print >> ERROR_FILE , "There was an error connecting to google."
234- print >> ERROR_FILE , e
231+ print ( "There was an error connecting to google." , file = ERROR_FILE )
232+ print ( e , file = ERROR_FILE )
235233 exit (0 )
236234
237235 return spreadsheet_title
@@ -242,10 +240,8 @@ def insert_new_users(ch_client, new_user_list):
242240 added_user_rows = []
243241 added_authority_rows = []
244242 for user in new_user_list :
245- print >> OUTPUT_FILE , "new user: %s" % user .google_email
243+ print ( "new user: %s" % user .google_email , file = OUTPUT_FILE )
246244 user_name = user .name
247- if isinstance (user_name , unicode ):
248- user_name = user_name .encode ('utf-8' )
249245 user_email = user .google_email .lower ()
250246 added_user_rows .append ([user_email , user_name , user .enabled ])
251247 added_authority_rows += [[user_email , authority ] for authority in user .authorities ]
@@ -270,7 +266,7 @@ def get_current_user_map(ch_client):
270266 for row in result .result_rows :
271267 to_return [row [0 ].lower ()] = User (row [0 ].lower (), row [0 ].lower (), row [1 ], row [2 ], 'not_used_here' )
272268 except Exception as msg :
273- print >> ERROR_FILE , msg
269+ print ( msg , file = ERROR_FILE )
274270 return None
275271
276272 return to_return
@@ -291,7 +287,7 @@ def get_user_authorities(ch_client, google_email):
291287 for row in result .result_rows :
292288 to_return .append (row [1 ])
293289 except Exception as msg :
294- print >> ERROR_FILE , msg
290+ print ( msg , file = ERROR_FILE )
295291 return None
296292
297293 return to_return
@@ -373,7 +369,7 @@ def get_rejected_user_map(spreadsheet, sheet_records, current_user_map, portal_n
373369 else :
374370 to_return [google_email .lower ()] = User (inst_email , google_email , name , 0 ,
375371 [portal_name + ':' + au for au in authorities .split (';' )])
376- print >> OUTPUT_FILE , 'Rejected user added to list: %s' % google_email .lower ()
372+ print ( 'Rejected user added to list: %s' % google_email .lower (), file = OUTPUT_FILE )
377373 return to_return
378374
379375# ------------------------------------------------------------------------------
@@ -389,7 +385,7 @@ def get_clickhouse_client(portal_properties):
389385 database = portal_properties .clickhouse_db ,
390386 )
391387 except Exception as msg :
392- print >> ERROR_FILE , msg
388+ print ( msg , file = ERROR_FILE )
393389 return None
394390
395391
@@ -407,11 +403,11 @@ def get_portal_properties(portal_properties_filename):
407403 continue
408404 # store name/value
409405 property = line .split ('=' )
410- # spreadsheet url contains an '=' sign
411- if line .startswith (CGDS_USERS_SPREADSHEET ):
406+ # spreadsheet url / db pw may contain an '=' sign
407+ if line .startswith (CGDS_USERS_SPREADSHEET ) or line . startswith ( CLICKHOUSE_PW ) :
412408 property = [property [0 ], line [line .index ('=' )+ 1 :len (line )]]
413409 if (len (property ) != 2 ):
414- print >> ERROR_FILE , 'Skipping invalid entry in property file: ' + line
410+ print ( 'Skipping invalid entry in property file: ' + line , file = ERROR_FILE )
415411 continue
416412 properties [property [0 ]] = property [1 ].strip ()
417413 portal_properties_file .close ()
@@ -427,7 +423,7 @@ def get_portal_properties(portal_properties_filename):
427423 CGDS_USERS_SPREADSHEET not in properties or len (properties [CGDS_USERS_SPREADSHEET ]) == 0 or
428424 CGDS_USERS_WORKSHEET not in properties or len (properties [CGDS_USERS_WORKSHEET ]) == 0 or
429425 IMPORTER_SPREADSHEET not in properties or len (properties [IMPORTER_SPREADSHEET ]) == 0 ):
430- print >> ERROR_FILE , 'Missing one or more required properties, please check property file'
426+ print ( 'Missing one or more required properties, please check property file' , file = ERROR_FILE )
431427 return None
432428
433429 # return an instance of PortalProperties
@@ -449,25 +445,25 @@ def get_portal_properties(portal_properties_filename):
449445def manage_users (client , spreadsheet , ch_client , sheet_records , portal_name ):
450446
451447 # get map of current portal users
452- print >> OUTPUT_FILE , 'Getting list of current portal users'
448+ print ( 'Getting list of current portal users' , file = OUTPUT_FILE )
453449 current_user_map = get_current_user_map (ch_client )
454450 if current_user_map is not None :
455- print >> OUTPUT_FILE , 'We have found %s current portal users' % len (current_user_map )
451+ print ( 'We have found %s current portal users' % len (current_user_map ), file = OUTPUT_FILE )
456452 else :
457- print >> OUTPUT_FILE , 'Error reading user table'
453+ print ( 'Error reading user table' , file = OUTPUT_FILE )
458454 return None , None
459455
460456 # get list of new users and insert
461- print >> OUTPUT_FILE , 'Checking for new users'
457+ print ( 'Checking for new users' , file = OUTPUT_FILE )
462458 new_user_map = get_new_user_map (spreadsheet , sheet_records , current_user_map , portal_name )
463459 rejected_user_map = get_rejected_user_map (spreadsheet , sheet_records , current_user_map , portal_name )
464460
465461 if (len (new_user_map ) > 0 ):
466- print >> OUTPUT_FILE , 'We have %s new user(s) to add' % len (new_user_map )
462+ print ( 'We have %s new user(s) to add' % len (new_user_map ), file = OUTPUT_FILE )
467463 insert_new_users (ch_client , new_user_map .values ())
468464 return new_user_map , rejected_user_map
469465 else :
470- print >> OUTPUT_FILE , 'No new users to insert, exiting'
466+ print ( 'No new users to insert, exiting' , file = OUTPUT_FILE )
471467 return None , rejected_user_map
472468
473469# ------------------------------------------------------------------------------
@@ -476,11 +472,11 @@ def manage_users(client, spreadsheet, ch_client, sheet_records, portal_name):
476472def update_user_authorities (spreadsheet , ch_client , sheet_records , portal_name ):
477473
478474 # get map of current portal users
479- print >> OUTPUT_FILE , 'Getting list of current portal users from spreadsheet'
475+ print ( 'Getting list of current portal users from spreadsheet' , file = OUTPUT_FILE )
480476 all_user_map = get_new_user_map (spreadsheet , sheet_records , {}, portal_name )
481477 if all_user_map is None :
482478 return None
483- print >> OUTPUT_FILE , 'Updating authorities for each user in current portal user list'
479+ print ( 'Updating authorities for each user in current portal user list' , file = OUTPUT_FILE )
484480 new_authority_pairs = []
485481 for user in all_user_map .values ():
486482 sheet_authorities = set (user .authorities )
@@ -496,7 +492,7 @@ def add_rejected_users_to_worksheet(rejected_user_map, google_spreadsheet, clien
496492 if rejected_user_map is None or len (rejected_user_map ) == 0 :
497493 return
498494
499- print >> OUTPUT_FILE , 'Adding rejected users to rejected_users worksheet'
495+ print ( 'Adding rejected users to rejected_users worksheet' , file = OUTPUT_FILE )
500496
501497 # get existing records from the rejected_users worksheet
502498 # Note: get_sheet_records converts column names to lowercase with special chars removed
@@ -510,23 +506,22 @@ def add_rejected_users_to_worksheet(rejected_user_map, google_spreadsheet, clien
510506 existing_emails .add (record [REJECTED_EMAIL_KEY ].strip ().lower ())
511507 except Exception as e :
512508 # worksheet might not exist or be empty, start with empty set
513- print >> OUTPUT_FILE , 'Creating new rejected_users worksheet or worksheet is empty'
509+ print ( 'Creating new rejected_users worksheet or worksheet is empty' , file = OUTPUT_FILE )
514510 existing_emails = set ()
515511
516512 # remove any rejected users that are already in the worksheet
517- for user_email in rejected_user_map .keys ():
513+ for user_email in list ( rejected_user_map .keys () ):
518514 if user_email .lower () in existing_emails :
519515 rejected_user_map .pop (user_email , None )
520516
521517 # prepare new rows to append (only users not already in the worksheet)
522518 new_rows = []
523- import datetime
524519 current_utc_time = datetime .datetime .utcnow ().strftime ('%Y-%m-%d %H:%M:%S' )
525520
526521 for user_email in rejected_user_map .keys ():
527522 if user_email .lower () not in existing_emails :
528523 new_rows .append ([user_email , current_utc_time ])
529- print >> OUTPUT_FILE , 'Adding rejected user to worksheet: %s' % user_email
524+ print ( 'Adding rejected user to worksheet: %s' % user_email , file = OUTPUT_FILE )
530525
531526 # append new rows to the worksheet if there are any
532527 if len (new_rows ) > 0 :
@@ -542,11 +537,11 @@ def add_rejected_users_to_worksheet(rejected_user_map, google_spreadsheet, clien
542537 valueInputOption = 'RAW' ,
543538 body = body
544539 ).execute ()
545- print >> OUTPUT_FILE , 'Added %s rejected user(s) to worksheet' % len (new_rows )
540+ print ( 'Added %s rejected user(s) to worksheet' % len (new_rows ), file = OUTPUT_FILE )
546541 except Exception as e :
547- print >> ERROR_FILE , 'Error adding rejected users to worksheet: %s' % str (e )
542+ print ( 'Error adding rejected users to worksheet: %s' % str (e ), file = ERROR_FILE )
548543 else :
549- print >> OUTPUT_FILE , 'No new rejected users to add to worksheet'
544+ print ( 'No new rejected users to add to worksheet' , file = OUTPUT_FILE )
550545
551546# ------------------------------------------------------------------------------
552547# sends emails to users from a user map
@@ -569,8 +564,8 @@ def send_emails(user_map, google_spreadsheet, client, worksheet, gmail_username,
569564 error_subject = ERROR_EMAIL_SUBJECT_CMO
570565 error_body = ERROR_EMAIL_BODY_CMO
571566 if emails_to_remove is None or user_key not in emails_to_remove :
572- print >> OUTPUT_FILE , ('Sending confirmation or rejection email to user: %s at %s' %
573- (user .name , user .inst_email ))
567+ print ('Sending confirmation or rejection email to user: %s at %s' %
568+ (user .name , user .inst_email ), file = OUTPUT_FILE )
574569 send_mail ([user .inst_email ], subject , body , gmail_username , gmail_password , sender = from_field , bcc = bcc_field , server = smtp_server )
575570 else :
576571 send_mail ([user_key ], error_subject , error_body , gmail_username , gmail_password , sender = from_field , bcc = bcc_field , server = smtp_server )
@@ -581,7 +576,7 @@ def send_emails(user_map, google_spreadsheet, client, worksheet, gmail_username,
581576def get_email_parameters (google_spreadsheet ,client ,worksheet ):
582577 subject = ''
583578 body = ''
584- print >> OUTPUT_FILE , 'Getting email parameters from google spreadsheet'
579+ print ( 'Getting email parameters from google spreadsheet' , file = OUTPUT_FILE )
585580 email_sheet_records = get_sheet_records (client , google_spreadsheet , worksheet )
586581 for record in email_sheet_records :
587582 if record [SUBJECT_KEY ] is not None and record [BODY_KEY ] is not None :
@@ -591,7 +586,7 @@ def get_email_parameters(google_spreadsheet,client,worksheet):
591586
592587def get_portal_name_map (google_spreadsheet ,client ):
593588 portal_name = {}
594- print >> OUTPUT_FILE , 'Getting access control parameter from google spreadsheet'
589+ print ( 'Getting access control parameter from google spreadsheet' , file = OUTPUT_FILE )
595590 access_control_sheet = get_sheet_records (client ,google_spreadsheet ,ACCESS_CONTROL_WORKSHEET )
596591 for row in access_control_sheet :
597592 if row [PORTAL_NAME_KEY ] is not None and row [SPREADSHEET_NAME_KEY ] is not None :
@@ -600,10 +595,10 @@ def get_portal_name_map(google_spreadsheet,client):
600595
601596
602597def establish_clickhouse_client (portal_properties ):
603- print >> OUTPUT_FILE , 'Connecting to ClickHouse: ' + portal_properties .clickhouse_host
598+ print ( 'Connecting to ClickHouse: ' + portal_properties .clickhouse_host , file = OUTPUT_FILE )
604599 ch_client = get_clickhouse_client (portal_properties )
605600 if ch_client is None :
606- print >> OUTPUT_FILE , 'Error connecting to ClickHouse, exiting'
601+ print ( 'Error connecting to ClickHouse, exiting' , file = OUTPUT_FILE )
607602 sys .exit (2 )
608603 return ch_client
609604
@@ -612,7 +607,7 @@ def establish_clickhouse_client(portal_properties):
612607# displays program usage (invalid args)
613608
614609def usage ():
615- print >> OUTPUT_FILE , 'importUsers .py --secrets-file [google secrets.json] --creds-file [oauth creds filename] --properties-file [properties file] --send-email-confirm [true or false] --use-institutional-id [true or false] --sender [sender identifier - optional] --smtp-server [smtp server hostname - required when send-email-confirm is true]'
610+ print ( 'importUsersClickhouse .py --secrets-file [google secrets.json] --creds-file [oauth creds filename] --properties-file [properties file] --send-email-confirm [true or false] --use-institutional-id [true or false] --sender [sender identifier - optional] --smtp-server [smtp server hostname - required when send-email-confirm is true]', file = OUTPUT_FILE )
616611
617612# ------------------------------------------------------------------------------
618613# the big deal main.
@@ -622,8 +617,8 @@ def main():
622617 # parse command line options
623618 try :
624619 opts , args = getopt .getopt (sys .argv [1 :], '' , ['secrets-file=' , 'creds-file=' , 'properties-file=' , 'send-email-confirm=' , 'use-institutional-id=' , 'sender=' , 'gmail-username=' , 'gmail-password=' , 'smtp-server=' ])
625- except getopt .error , msg :
626- print >> ERROR_FILE , msg
620+ except getopt .error as msg :
621+ print ( msg , file = ERROR_FILE )
627622 usage ()
628623 sys .exit (2 )
629624
@@ -663,14 +658,14 @@ def main():
663658
664659 # check existence of file
665660 if not os .path .exists (properties_filename ):
666- print >> ERROR_FILE , 'properties file cannot be found: ' + properties_filename
661+ print ( 'properties file cannot be found: ' + properties_filename , file = ERROR_FILE )
667662 sys .exit (2 )
668663
669664 # parse/get relevant portal properties
670- print >> OUTPUT_FILE , 'Reading portal properties file: ' + properties_filename
665+ print ( 'Reading portal properties file: ' + properties_filename , file = OUTPUT_FILE )
671666 portal_properties = get_portal_properties (properties_filename )
672667 if not portal_properties :
673- print >> OUTPUT_FILE , 'Error reading %s, exiting' % properties_filename
668+ print ( 'Error reading %s, exiting' % properties_filename , file = OUTPUT_FILE )
674669 return
675670
676671 # create client for interacting with google sheets api
@@ -687,7 +682,7 @@ def main():
687682 portal_properties .google_worksheet )
688683 spreadsheet_title = get_spreadsheet_title (client , google_spreadsheet )
689684
690- print >> OUTPUT_FILE , 'Importing ' + spreadsheet_title + ' ...'
685+ print ( 'Importing ' + spreadsheet_title + ' ...' , file = OUTPUT_FILE )
691686 app_name = portal_name_map [spreadsheet_title ]
692687
693688 # the 'guts' of the script
@@ -706,9 +701,9 @@ def main():
706701
707702 # sending emails
708703 if send_email_confirm == 'true' :
709- print >> OUTPUT_FILE , "Sending confirmation emails to new users"
704+ print ( "Sending confirmation emails to new users" , file = OUTPUT_FILE )
710705 send_emails (new_user_map , google_spreadsheet , client , IMPORT_EMAIL_WORKSHEET , gmail_username , gmail_password , sender , smtp_server )
711- print >> OUTPUT_FILE , "Sending rejection emails to newly rejected users"
706+ print ( "Sending rejection emails to newly rejected users" , file = OUTPUT_FILE )
712707 send_emails (rejected_user_map , google_spreadsheet , client , REJECT_EMAIL_WORKSHEET , gmail_username , gmail_password , sender , smtp_server )
713708
714709# ------------------------------------------------------------------------------
0 commit comments