Example #1
0
def get_files_path():

    '''
    if default path is a possiblity,
    give the option. Otherwise, just 
    prompt for path.
    '''

    if DEFAULT_PATH and os.path.exists( DEFAULT_PATH ) :
        
        menu_title = "Where are the GQueues CSV files located?"
        
        
        IN_DEFAULT = ''.join([ 'The files are in the default location : ', 
                                DEFAULT_PATH  ])
    
        
        ELSEWHERE  = "I'd like to enter a path manually."
    
        
        ( index, choice ) = select_from_menu( menu_title, [ IN_DEFAULT, ELSEWHERE ] )
        
        print''
        
        ###############################
        
        '''
        if they chose the default location
        return that path
        '''
        
        if choice == IN_DEFAULT :   return DEFAULT_PATH
           
        '''
        otherwise, enter a path - much as if
        the default had not been an option
        '''
    
    
    ###################
    
    '''
    enter path to CSV files
    '''
    
    FILES_PATH = raw_input( 'Full Path To File(s): ')
    
    
    '''
    check the path is an
    existing directory
    '''
    
    while not os.path.exists( FILES_PATH ) \
       or not os.path.isdir ( FILES_PATH ) :
        
        print ''
        print 'you entered:', FILES_PATH
        print "I'm sorry, that path does not exist, or is not a folder."
        print ''
        
        FILES_PATH = raw_input( 'Full Path To File(s): ')
            
    
    
    ###################################
    
    '''
    we got past the while, and thus have
    a valid path to search for CSV files
    '''
    return FILES_PATH
Example #2
0
def add_project_to_toggl_workspace( p, ws_name ):
    
    '''
    get workspace id from name
    '''
    ws_id = ws_ids[ ws_name ]
    
    
    ##########################
        
    '''
    Should we flattern Queue hierarchy, 
    or should we emulate hierarchy with 
    a naming convention. 
    '''
    
    '''
    if there isn't any hierarchy, 
    don't need to ask
    '''
    if not p.has_hierarchy() :    
        
        gqueues_tasks = p.get_tasks()
    
    
    ###################
    
    else : 
        
        '''
        if there is some hierarchy, we must
        ask the user what to do about this
        '''
        
        menu_title = '\n'.join([ 'This Queue contains some nested tasks.',
                                 'Toggl allows only 1 level of task hierarchy.' ])
        
        EMULATE = 'Emulate hierarchy with naming,  e.g.  Child  [ Grandparent > Parent ]'
        
        FLATTEN = 'Flat hierarchy of leaf-names,   e.g.  Child'
        
        IGNORE  = 'Use top-level tasks only - discarding all nested tasks.'
        
        ( index, choice ) = select_from_menu( menu_title, [ EMULATE, FLATTEN, IGNORE ] )
        
        
        #############################
        
        if   choice == EMULATE :   
            
            gqueues_tasks = p.get_tasks( True )
            
            
        ######################
        
        elif choice == FLATTEN :   

            gqueues_tasks = p.get_tasks( False )
            
        
        ######################
        
        elif choice == IGNORE :   
            
            '''
            get root nodes only
            '''
            gqueues_tasks = p.get_root_tasks()
    
    
    
    
        
    ###############################################################
        
    '''
    see if there is a project with the
    same name in this workspace.
    
    start by getting all projects in 
    this workspace...
    '''
    projects_in_ws  = toggl_API.filter_data( projects, {  "workspace":  { 'name' : ws_name, 
                                                                          'id'   : ws_id     }   })
    
    '''
    Of the projects in the selected
    workspace, do any have the same 
    name as the one we're importing?
    '''
    existing = toggl_API.filter_data( projects_in_ws, {  "name":  p.project_title   }   )
    
    
    
    ########################################
    
    '''
    CASE 1 :  There is no pre-existing project
    '''
    
    if len( existing ) == 0 : 
        
        '''
        make a new project
        '''
        
        project_data = { 'project' : {
            "name"       : p.project_title,
            "is_private" : False,
            "billable"   : False,
            "workspace"  : {  "id": ws_id   }
            }}

        
        ''' create project
        '''
        toggl_project = toggl_API.send_data( "projects", data = project_data )
        
        
        ############################
        
        '''
        add this new project to the 
        rest of the toggle projects
        '''
        projects.append( toggl_project )
        
        
        ############################
        
        ''' notifiy user
        '''
        print ''
        print 'uploaded a new project to Toggl:', p.project_title
        print ''
    
        
        ##########################
        
        '''
        we need to add all of the 
        gqueues tasks, as the projct
        is currently empty
        '''
        new_tasks = gqueues_tasks
        
        ###########################
        
        '''
        if no tasks in this project, 
        inform the user
        '''
        
        if len( new_tasks ) == 0 : 
            
            print 'This project does not contain any tasks.'
        
        
          
    
    
    
    ##################################################################
    
    else : 
        
        '''
        CASE 2 :  a project with this name 
                  already exists
        
        merge the project with the existing one
        adding, but NOT deleting old tasks.
        
        This is because tasks that are completed
        may still have associated time records. 
        '''
        
        toggl_project = existing[0]
        
        
        ####################
        
        ''' notifiy user
        '''
        print ''
        print p.project_title, 'is already a project on Toggl. Merging new tasks...'
        print ''
        
        
        ###################################
        
        '''
        get names all tasks in the project
        on toggl. Match project with object like
        this : 
        
        
        { 'client_project_name': 'To Do', 
          'name': 'To Do', 
          'id'  : 1540962   }
        
        '''            
        toggl_tasks = set([ 
            
            t[ 'name' ] 
                               
            for t in 
                            
            toggl_API.filter_data( tasks, {  "project":  {
                                    
                        'client_project_name' : toggl_project[ 'client_project_name' ],
                                       'name' : toggl_project[ 'name' ],
                                         'id' : toggl_project[ 'id' ]       }}   )])
        
        
        ##########################
        
        '''
        add only the new tasks
        '''
        new_tasks = gqueues_tasks - toggl_tasks
        
        
        ##################
        
        ''' inform if none
        '''
        
        if len( new_tasks ) == 0 : 
            
            print 'There are no new tasks to add to this project.'
        
    
    
    
    #######################################
    
    '''
    add a new tasks to the toggle project
    (whether newly created or existing)
    '''
         
    for task_name in new_tasks :
        
        task_data = { 'task' : {
        "name"      : task_name,
        "is_active" : True,
        "project"   : {  "id": toggl_project[ 'id' ]  }
        }}
        
        ''' create task
        '''
        task = toggl_API.send_data( "tasks", data = task_data )
        
        ''' add to local collection
        '''
        tasks.append( task )
        
        print 'added task: ', task_name
        

     
    
    ###############
    
    '''
    space after project
    '''
    print ''
Example #3
0
 def populate_nodes( self ):
     
     
     '''
     throw a warning if there are more
     than one tasks with identical names
     '''
     
     all_nodes = deepcopy( self.parent_nodes )
     
     [  all_nodes.append( description ) 
      
        for ( description, parent ) 
       
        in  self.child_nodes            ]
     
     
     ###################
     
     '''
     compare a list of all the nodes to a 
     list of all unique nodes. 
     '''        
     
     uniq_nodes = DiffList(  list(set( all_nodes )) )
     
     all_nodes  = DiffList(  all_nodes  )
     
     '''
     get any 'leftover' nodes
     '''        
     duplicates = all_nodes - uniq_nodes
     
     '''
     stern warning if there are any!
     '''
     if len( duplicates ) != 0 :
         
         title = '\n'.join([ '!!!!!!!!!!!!!!!!!!',
                             '###########',
                             'WARNING!!! ',
                             'WARNING!!! ',
                             'WARNING!!! ',
                             '###########',
                             '!!!!!!!!!!!!!!!!!!',
                             '',
                             'This project contains duplicate task names!',
                             'If you continue, only one task with each name',
                             'will be saved in the project.',
                             '',
                             'In addition, if the duplicate tasks have any', 
                             'sub-tasks, some tasks may end up with incorrect',
                             'ancestors. ',
                             '',
                             'You may be planning to discard the repeated tasks',
                             'anyhow, e.g. because you only wish to import the',
                             'top-level tasks, and none of those are duplicates.',
                             '',
                             'But if not, you may wish to return to GQueues and',
                             'rename the offending duplicate tasks.',
                             '',
                             'The duplicated names are :',
                             '',
                             '\n'.join( set( duplicates )),
                             '',
                             'What would you like to do?'       ])
         
         
         ###########################
         
         QUIT     = 'Delete this CSV file and quit.'
         CONTINUE = 'Continue anyway.'
                     
         '''
         get the user's decision
         '''
         ( index, choice ) = select_from_menu( title, [ QUIT, CONTINUE ] )
         
         print ''
         
         '''
         if they choose quit, quit!
         '''
         if choice == QUIT : 
             
             print 'deleting CSV containing duplicate task-names'
             
             self.delete_file()
                             
             raise SystemExit()
             
         
         '''
         Otherwise, continue onwards.
         You have been warned!
         '''
             
             
     
     ###########################
     
     ''' put root nodes straight into nodes dictionary
     '''
     
     for description in self.parent_nodes : 
     
         self.nodes[ description ] = [ description ]
     
     
     ###########################################
     
     '''
     now parse the children into
     the nodes dictionary  
     '''    
     c_nodes = deepcopy( self.child_nodes )
     
     while len( c_nodes ) > 0 : 
         
         '''
         pop open a node
         '''
         ( description, parent ) = c_nodes.popleft()
         
         '''
         assume we won't find it's parent
         '''
         found = False
         
         
         ################################
         
         for n in self.nodes : 
             
             if n == parent :
                      
                 h_map = deepcopy( self.nodes[ n ] )
                 
                 h_map.append( description )
                 
                 '''
                 add new entry to the nodes dictionary
                 '''
                 self.nodes[ description ] = h_map
                 
                 found = True
                 
                 break
         
         
         ################################
         
         '''
         if we didn't find it's parent yet
         re-add to the end of temp child nodes
         '''
         if not found :   c_nodes.append(  ( description, parent )  )
Example #4
0
def import_projects():

    project_files = projects_from_csv()
    
    print ''
    print ''
    
    for p in project_files : 
        
        '''
        project file header
        '''
        print '***************************************'
        print '***************************************'
        print ''
        
        ##################################
        
        '''
        which workspace to import / merge
        this project (or sub-projects) into ? 
        '''
                
        menu_title = ''.join([ 'Choose workspace for  *', 
                                p.project_title,  '*  :'   ])
        
        '''
        choose from a list of worskspace names
        in the command shell
        '''
        ( index, selected_workspace ) = select_from_menu( menu_title, ws_names )
        
        
        print ''
        print 'Importing project data to workspace: ', selected_workspace
        print ''
        
        
        #########################
        
        '''
        now the user must decide whether to import this
        CSV file as a single project, or whether the root
        nodes of this Queue are themselves projects
        '''
        
        menu_title = 'Import this file as a single project, or multiple projects?'
        
        SINGLE     = 'This Queue is a single project.'
        MULTIPLE   = 'Top level nodes in this Queue each represent a project.'
        
        
        ''' choose in cmd
        '''
        ( index, choice ) = select_from_menu( menu_title, [ SINGLE, MULTIPLE ] )
        
        
        ####################
        
        ''' spacer before project imports
        '''      
        print ''
        
        
        #########################
                
        if   choice == SINGLE   : 
            
            '''
            add the current project to the 
            selected workspace
            '''
            
            add_project_to_toggl_workspace( p, selected_workspace )
        
        
        #########################
        
        elif choice == MULTIPLE :
              
            '''
            Add sub-projects to toggl
            one by one
            '''
            sub_projects = p.sub_projects()
            
            for sp in sub_projects :
                        
                add_project_to_toggl_workspace( sp, selected_workspace )
        
        
        #############################
        
        '''
        offer to delete the original file
        '''
        
        menu_title = '\n'.join([ 'File successfully exported to Toggl.',
                                 'Would you like to delete the file?'    ])
        
        DELETE = 'Yes'
        DONT   = 'No'
        
        ( index, choice ) = select_from_menu( menu_title, [ DELETE, DONT ] )
        
        
        ###########################
        
        if choice == DELETE : 
            
            p.delete_file()
            
            print ''
            print 'Deleted File.'
               
        
        ###############
        
        '''
        gap before next queue file
        '''        
        print ''
        print ''
        print ''