Ciaran Farrell avatar Ciaran Farrell committed e5528fc

Creating and sending appointments now works - at least kind of

Comments (0)

Files changed (3)

 from getpass import getuser,getpass
 from termine.genericlogger import logger
 from termine.genericargparse import parser as parentparser
-
+from datetime import timedelta,datetime
 import sys,logging,ConfigParser,argparse,re
 action = None # used to determine which subcommand action to follow
 config = ConfigParser.SafeConfigParser()
   defaultwindow = config.get('Global','defaultwindow')
 except Exception,e:
   raise GWConfigFileException, 'You should remove %s and re-run the script'%CONFIGFILE
-
+try:
+  deflen = config.getint('Global','defaultappointmentlen')
+except Exception,e:
+  logger.warn('Could not get default appointment length from config')
+  deflen = 60
+else:
+  logger.debug('Obtained default appointment length %d minutes from config'%deflen)
+defdelta = timedelta(minutes=deflen)
+df = "%Y-%m-%d#%H:%M"
 termine_desc = '''termine is a command line program that uses the Groupwise
 SOAP API to connect to your Groupwise server and retrieve your appointments'''
 termine_prog = 'termine'
 help_message = '''The message is the body of the appointment. Groupwise will
 attach this as the first attachment to the item. Use this to type longer texts
 and to include e.g. dial-in details. Note that text entered here will not be
-shown in the summary list view (only the subject is shown there)'''
+shown in the summary list view (only the subject is shown there). If you do not
+enter anything here the default will be an empty string'''
 help_subject = '''Analog to the subject of an email - use this field to enter
 a short, concise description of the event. This field is shown in the main list
 overview of appointments'''
 help_cc = '''Analog to cc recipients of an email. All cc recipients can see who
-the 'to' recipients as well as the other cc recipients are'''
+the 'to' recipients as well as the other cc recipients are. Enter a comma
+separated list of cc recipients'''
 help_place = '''If the appointment is taking place at a particular place, enter
 the place here. Groupwise reserves this field specially - i.e. it is not simply
-a free text addition'''
-help_begin = '''Start time of the appointment using ISO format YYYY-MM-DD HH:MM
-where HH:MM is the hours and minutes in 24 hour format'''
+a free text addition. The default is an empty string'''
+help_begin = '''Start time of the appointment using format yyyy-mm-dd#hh:mm
+where hh:mm is the hours and minutes in 24 hour format. The reason for the hash
+in the required formatting is to make it easier to enter it on the command line'''
 help_end = '''End time of the appointment using ISO format YYYY-MM-DD HH:MM
-where HH:MM is the hours and minutes in 24 hour format'''
+where HH:MM is the hours and minutes in 24 hour format. If you do not enter 
+anything here the default will be %d minutes after the start time. You can change
+this default in the ~/.gwise.cfg file'''%deflen
 help_to = '''Analog to the 'to' recipients of an email. All to recipients can
 see who the other 'to' recipients as well as the other cc recipients are'''
 parser = argparse.ArgumentParser(parents=[parentparser],
 tbusy.add_argument('recip', nargs='*', help=help_busy)
 tcreate = subparsers.add_parser('create', help='Create and send an appointment')
 tcreate.add_argument('-m','--message',dest='message',help=help_message,
-                    default=None)
+                    default='')
 tcreate.add_argument('-s','--subject',dest='subject',help=help_subject,
-                    default=None)
+                    default=None,required=True)
 tcreate.add_argument('-c','--cc',dest='cc',help=help_cc,
                     default=None)
 tcreate.add_argument('-p','--place',dest='place',help=help_place,
-                    default=None)                    
+                    default="")                    
 tcreate.add_argument('-b','--begin',dest='begin',help=help_begin,
-                    default=None)                    
+                    default=None,required=True)                    
 tcreate.add_argument('-e','--end',dest='end',help=help_end,
                     default=None)                    
 
   action = 'create'
 else:
   # this will probably never be reached as the parser will catch the error
-  parser.error('Could not determine whether you want to show or list')
+  parser.error('Could not determine what action you want to take')
 
 ok=False
 fl = args.forcelogin
         sys.stderr.write("%s\n"%str(e))
         sys.exit(1) # no point in looping
       except Exception,e:
+        logger.error("%s\n"%str(e))
         sys.stderr.write("%s\n"%str(e))
         sys.exit(1) # get out - something went wrong
       else:
         ok=True
   elif action == 'create':
     logger.debug('action is create')
-    print "NOT IMPLEMENTED - COME BACK LATER"
+    try:
+      st = datetime.strptime(args.begin,df)
+    except ValueError,e:
+      logger.error("start time %s did not match required format %s\n"%(args.begin,df))
+      sys.stderr.write("start time %s did not match required format %s\n"%(args.begin,df))
+      sys.exit(1)
+    else:
+      logger.debug("Parsed %s to %s"%(args.begin,st))
+    if args.end:
+      try:
+        et = datetime.strptime(args.end,df)
+      except ValueError,e:
+        logger.error('end time %s did not match required format %s\n'%(args.end,df))
+        sys.stderr.write('end time %s did not match required format %s\n'%(args.end,df))
+        sys.exit(1)
+      else:
+        logger.debug("Parsed %s to %s"%(args.end,et))
+    else:
+      et = st+defdelta
+      logger.debug("Parsed end time to be st(%s) + default delta (%d mins): %s"%(st,
+          deflen,et))
+    cc = []
+    if args.cc:
+      cc1 = args.cc.split(',')
+      if len(cc1):
+        for val in cc1:
+          if val != "":
+            cc.append(val)
+    # following 3 lines needed to avoid UnicodeEncodingError
+    message = args.message.decode('utf-8')
+    subject = args.subject.decode('utf-8')
+    place = args.subject.decode('utf-8')
+    try:
+      gw = Groupwise(fl=fl)
+      soapstring = gw.createAppointment(args.to,subject,message,
+                   st,et,cc=cc,place=place)
+    except GWForceLoginException,e:
+      logger.warn(str(e))
+      logger.debug('Setting fl to False to avoid loop')
+      fl = False
+    except GWItemSendException,e:
+      logger.error(str(e))
+      sys.exit(1)
+    except GWInitException,e:
+      logger.warn(str(e))
+    except GWSessionException,e:
+      logger.warn(str(e))
+    except GWFatalException,e:
+      logger.error(str(e))
+      sys.exit(1)
+    else:
+      print "Your appointment was sent!"
     ok = True
   elif action == 'busy':
     logger.debug('action is busy')

termine/gwexceptions.py

 class GWItemFetchException(BaseException):
   pass
 
+class GWItemSendException(BaseException):
+  pass
+
 class GWForceLoginException(BaseException):
   pass
   
 from time import sleep,timezone
 from operator import itemgetter
 import sys,os,json,logging,ConfigParser,base64,pkgutil,tempfile
-
+gwtimeformat = "%Y-%m-%dT%H:%M:%SZ"
 utcoffset = timezone / -(60*60)
 gdelta = timedelta(hours=utcoffset)
 try:
   config.set('Global','start_date_fmt','%a %d/%m %H:%M')
   config.set('Global','end_date_fmt','%H:%M')
   config.set('Global','uname', uname)
+  config.set('Global','uuid','')
+  config.set('Global','email','')
   config.set('Global','attempts','0')
   config.set('Global','DEFAULT_FMT','raw')
   config.set('Global','defaultwindow','thisweek')
   config.set('Global','coloring','True')
   config.set('Global','defaultdomain','suse.com')
   config.set('Global','cachetimeoutdays','300')
+  config.set('Global','defaultappointmentlength','60')
   fd = open(cfg,'w')
   config.write(fd)
   fd.close()
     self.gwVersion = None
     self.build = None
     self.serverUTCTime = None
-    self.uuid = None
+    self.uuid = self.config.get('Global','uuid')
+    self.email = self.config.get('Global','email')
     self.name= None
     self.addressbookid = None
     try:
     self.config.write(fd)
     fd.close()
 
-  def __setUser__(self,user):
-    ''' Once a user successfully logs in, write the username used to the config
+  def __setUser__(self):
+    ''' Once a user successfully logs in, write uuid and email used to the config
         file so it will be automatically offered as default the next time '''
     fd = open(self.cfg,'w')
-    self.config.set('Global','uname',user)
+    self.config.set('Global','uuid',self.uuid)
+    self.config.set('Global','email',self.email)
     self.config.write(fd)
-    self.uname = user # just in case?
     fd.close()
 
   def __login__(self):
     self.session = resp.session
     self.config.set('Global','session',self.session)
     self.config.write(open(self.cfg,'w'))
+    self.email = resp.userinfo.email
     self.name = resp.userinfo.name
     self.build = resp.build
     self.gwVersion = resp.gwVersion
     self.uuid = resp.userinfo.uuid
+    self.userid = resp.userinfo.userid
     self.serverUTCTime = resp.serverUTCTime
+    self.__setUser__()
     utcnow = datetime.utcnow()
     if utcnow.hour != self.serverUTCTime.hour:
       logger.warn("Warning: server UTC is %s and local UTC is %s"%(self.serverUTCTime.strftime(self.dtime),
 
   def getBusyTimeRequestId(self,users,s=datetime.utcnow(),e=None):
     logger.debug('Groupwise.getBusyTimeRequestId with %s'%users)
-    fmt = "%Y-%m-%dT%H:%M:%SZ"
+    fmt = gwtimeformat
     delta = timedelta(days=7)
     if not e:
       e = s+delta
       return u
     else:
       raise GWFatalException,'Get me out of here!'
+      
+  def createAppointment(self,to,subject,message,st,et,cc=None,place=""):
+    logger.debug('''Groupwise.createAppointment with to=%s,subject=%s,message=%s,
+      st=%s,et=%s,cc=%s,place=%s'''%(to,subject,message,st,et,cc,place))
+    logger.debug('Getting user list for %s'%to)
+    users = self.getUserList(to)
+    app = self.client.factory.create('ns2:Appointment')
+    logger.debug('Setting appointment start date to %s'%st)
+    app.startDate = st.strftime(gwtimeformat)
+    logger.debug('Setting appointment end date to %s'%et)
+    app.endDate = et.strftime(gwtimeformat)
+    logger.debug('Setting appointment place to %s'%place)
+    app.place = place
+    logger.debug('Setting appointment subject to %s'%subject)
+    app.subject = subject
+    logger.debug('Setting appointment message to %s'%message)
+    mp = self.client.factory.create('ns2:MessagePart')
+    mp.value = message
+    mb = self.client.factory.create('ns2:MessageBody')
+    mb.part = mp
+    app.message = mb
+    dist = self.client.factory.create('ns2:Distribution')
+    f = self.client.factory.create('ns2:From')
+    #f.displayName = self.name
+    logger.debug('Setting distribution email to %s'%self.email)
+    f.email = self.email
+    logger.debug('Setting distribution uuid to %s'%self.uuid)
+    f.uuid = self.uuid
+    logger.debug('Setting distribution replyTo to %s'%self.email)
+    f.replyTo = self.email
+    dist.__dict__['from'] = f
 
+    dist.to = ",".join(to)
+    if cc:
+      dist.cc = ",".join(cc)
+    reciplist = self.client.factory.create('ns2:RecipientList')
+    for k in users.keys():
+      logger.debug('Adding %s to RecipientList'%k)
+      recip = self.client.factory.create('ns2:Recipient')
+      recip.email = users[k]['email']
+      recip.uuid = users[k]['uuid']
+      recip.displayName = users[k]['displayName']
+      reciplist.recipient.append(recip)
+    dist.recipients = reciplist
+    app.distribution = dist
+    logger.debug('Sending service request sendItemRequest')
+    sir = self.client.service.sendItemRequest(app)
+    if int(sir.status.code)==0:
+      logger.debug('Groupwise returned status 0 for sendItemRequest')
+      print sir
+      return True
+    else:
+      logger.warn('Groupwise returned status %d for sendItemRequest'%int(sir.status.code))
+      print sir
+      raise GWItemSendException("GWItemSendException - oh noes") 
 
 class GWIdCache:
   def __init__(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.