Beispiel #1
0
def getTagsFromInput(query):
	'''Retrieves the task tags from the user's input.

----------
	@param str query: The user's input.
	'''
	if DEBUG > 0:
		log.debug('[ getTagsFromInput() ] ')
	inputTags = []
	if getConfigValue(confNames['confDefaultTag']):
		inputTags.append(getConfigValue(confNames['confDefaultTag']))

	# Find first occurrence of '#' - from here, retrieve labels.
	if query.find(' #') > -1: # Char was found
		# From first occurrence until end of input # [u'', u'123 ', u'456']
		for tag in query[query.find(' #'):].split(' #'):
			# First element when splitting is always going to be empty ('') - as this is the left side of the first '#' which is not relevant for the tag
			if tag != '' and tag not in inputTags: # Do not add duplicate labels:
				tagValue = tag.split(':', 2)[0].split(' @', 2)[0].split(' !', 2)[0].split(" +", 1)[0].strip().replace(' ', ' ')
				inputTags.append(tagValue.strip())
	if DEBUG > 1:
		log.debug('inputTags: ' + str(inputTags))

	if (isTicketURL(query)):
		inputTags.append('ticket')

	return inputTags
Beispiel #2
0
def getCurrentUser():
	'''If not yet stored, retrieves the current user Id to assign tasks to by default (so they appear in Inbox).'''
	if DEBUG > 0:
		log.debug('[ Calling API to create task ]')
	
	if not getConfigValue(confNames['confUser']):
		url = 'https://api.clickup.com/api/v2/user'
		params = None
		headers = {}
		headers['Authorization'] = getConfigValue(confNames['confApi'])
		headers['Content-Type'] = 'application/json'
		
		if DEBUG > 1:
			log.debug(url)
			log.debug(headers)
		
		try:
			request = web.get(url, params = params, headers = headers)
			request.raise_for_status()
		except:
			log.debug('Error on HTTP request')
			wf3.add_item(title = 'Error connecting to ClickUp.', subtitle = 'Open configuration to check your parameters?', valid = True, arg = 'cu:config ', icon = 'error.png')
			wf3.send_feedback()
			exit()
		result = request.json()
		if DEBUG > 1:
			log.debug('Response: ' + str(result))
		
		wf.settings['userId'] = result['user']['id']
Beispiel #3
0
def retrieveLabelsFromAPI():
	'''Retrieves list of available Labels from ClickUp.
	'''
	if DEBUG > 0:
		log.debug('[ Calling API to receive labels ]')
	url = 'https://api.clickup.com/api/v2/space/' + getConfigValue(confNames['confSpace']) + '/tag'
	params = None
	headers = {}
	headers['Authorization'] = getConfigValue(confNames['confApi'])
	headers['Content-Type'] = 'application/json'
	headers['format'] = 'json'
	try:
		request = web.get(url, params, headers)
		request.raise_for_status()
	except:
		log.debug('Error on HTTP request.')
		wf3.add_item(title = 'Error connecting to ClickUp.', subtitle = 'Open configuration to check your parameters?', valid = True, arg = 'cu:config ', icon = 'error.png')
		wf3.send_feedback()
		exit()
	result = request.json()
	if DEBUG > 1:
		log.debug('Response: ' + str(result))

	if 'tags' in result:
		return result['tags']
	else:
		return None
Beispiel #4
0
def getLists(input, doPrintResults):
    '''Returns list of available Lists from ClickUp and caches them. Initiates `retrieveListsFromAPI()` if cache has been cleared.

----------
	@param str input: The user's input for a List.
	@param bool doPrintResults: Whether to generate list items.
	'''
    if DEBUG > 0:
        log.debug('[ Displaying lists (' + str(doPrintResults) +
                  ') ] - input: ' + input)
    global query
    global availableLists
    availableLists = wf.cached_data('availableLists',
                                    retrieveListsFromAPI,
                                    max_age=7200)

    isUserEndedInput = query[-1] == ' '
    if not isUserEndedInput and doPrintResults:
        allListTitles = []
        for singleList in availableLists:
            # Limit results on SpaceId - as getting *all* lists for the Team is overkill and does not make much sense as the user already specified a Space in Alfred workflow variables.
            if singleList['space']['id'] == getConfigValue(
                    confNames['confSpace']):
                # Store association of name to Id, as Id needs to be passed to API
                # Hidden lists are outside of a Folder, only connected to a Space
                folderName = '[' + singleList['folder']['name'] + '] ' if (
                    singleList['folder']['name'] != 'hidden') else ''
                global availableListsIdName
                availableListsIdName[
                    singleList['id']] = folderName + singleList['name']
                availableListsNameId[folderName +
                                     singleList['name']] = singleList['id']
                allListTitles.append(folderName + singleList['name'])
        filteredItems = wf.filter(input, allListTitles)
        global hasFoundMatch
        for item in filteredItems:
            hasFoundMatch = True
            wf3.add_item(
                title=item,
                valid=False,
                #arg = 'cu ' + query.replace(input, '') + item + ' ',
                autocomplete=query.replace(input, '') + item + ' ',
                icon='./note.png')
        if doPrintResults and hasFoundMatch:
            wf3.send_feedback()
    else:  # Even when nothing is entered, we need to fill our dictionaries.
        for singleList in availableLists:
            if singleList['space']['id'] == getConfigValue(
                    confNames['confSpace']):
                folderName = '[' + singleList['folder']['name'] + '] ' if (
                    singleList['folder']['name'] != 'hidden') else ''
                availableListsIdName[
                    singleList['id']] = folderName + singleList['name']
                availableListsNameId[folderName +
                                     singleList['name']] = singleList['id']
Beispiel #5
0
 def setLogFile(self):
     """Set :data:`logFile`. Default is sys.stderr
     """
     global logFile
     fileName = config.getConfigValue("server","logFile")
     logLevel = eval("logging."+config.getConfigValue("server","logLevel").upper())
     format = "PyWPS [%(asctime)s] %(levelname)s: %(message)s"
     if not fileName:
         logging.basicConfig(level=logLevel,format=format)
     else:
         logging.basicConfig(filename=fileName,level=logLevel,format=format)
         logFile = open(fileName, "a")
Beispiel #6
0
def checkConfig(wf3):
	'''Checks whether the required configuration parameters have been set. If not, asks the user to configure.

----------
	@param Workflow wf3: Workflow 3 object.
	'''
	if DEBUG > 0:
		log.debug('[ checkConfig() ]')
	if getConfigValue(confNames['confApi']) == None or getConfigValue(confNames['confList']) == None or getConfigValue(confNames['confSpace']) == None or getConfigValue(confNames['confTeam']) == None: # or getConfigValue(confNames['confProject']) == None: Project/Folder is now optional.
		log.debug('Missing essential variables')
		wf3.add_item(title = 'We are missing some settings for ClickUp.', subtitle = 'Let\'s set it up?', valid = True, arg = 'cu:config ', icon = ICON_WARNING)
		wf3.send_feedback()
		exit()
Beispiel #7
0
 def setLogFile(self):
     """Set :data:`logFile`. Default is sys.stderr
     """
     global logFile
     fileName = config.getConfigValue("server", "logFile")
     logLevel = eval(
         "logging." + config.getConfigValue("server", "logLevel").upper())
     format = "PyWPS [%(asctime)s] %(levelname)s: %(message)s"
     if not fileName:
         logging.basicConfig(level=logLevel, format=format)
     else:
         logging.basicConfig(filename=fileName,
                             level=logLevel, format=format)
         logFile = open(fileName, "a")
Beispiel #8
0
def addCreateTaskItem(inputName, inputContent, inputDue, inputPriority, inputTags, inputList):
	'''Displays a 'Create Task?' list item.

----------
	@param str inputName: The user's input for the task title.
	@param str inputContent: The user's input for the task decsription.
	@param str inputDue: The user's input for the task due date.
	@param str inputPriority: The user's input for the task priority.
	@param str inputTags: The user's input for the task tags.
	@param str inputList: The user's input for the task list.
	'''
	if DEBUG > 0:
		log.debug('[ addCreateTaskItem() ]')

	import json
	inputParameters = {'inputName': inputName, 'inputContent': inputContent, 'inputDue': str(inputDue), 'inputPriority': inputPriority, 'inputTags': inputTags}
	inputParameters['inputList'] = None
	if inputList != getConfigValue(confNames['confList']): # Non-default list specified
		if inputList in availableListsIdName:
			# For display: Use Name. For passing to Create Task: Use Id.
			inputParameters['inputList'] = {availableListsIdName[inputList]: inputList} # ListId : ListName

	outputTaskValues = json.dumps(inputParameters)
	createTaskItem = wf3.add_item(
		title = 'Create task "' + str(inputName).strip() + '"?',
		subtitle = formatNotificationText(inputContent, inputDue, inputTags, inputPriority, inputParameters['inputList']),
		valid = True,
		arg = outputTaskValues # Passed to Run Script as JSON - which will use it to call the ClickUp API.
	)
	createTaskItem.setvar('isSubmitted', 'true')
Beispiel #9
0
    def getCity(self, location):
        longitude = location[0]
        latitude = location[1]

        key = getConfigValue(configWeather)
        url = "https://search.heweather.com/find?key=" + key + "&location=" + longitude + "," + latitude

        print('Request:', url)
        with request.urlopen(url) as f:
            data = f.read()
            print('Status:', f.status, f.reason)
            # for k, v in f.getheaders():
            #     print('%s: %s' % (k, v))
            print('Data:', data.decode('utf-8'))
            jsonObject = json.loads(data.decode("utf-8"))

            basic = jsonObject['HeWeather6'][0]['basic'][0]

            cid = basic["cid"]
            location = basic["location"]
            parent_city = basic["parent_city"]
            admin_area = basic["admin_area"]
            cnty = basic["cnty"]

        return basic
Beispiel #10
0
    def __init__(self, method=METHOD_GET, configFiles=None):
        """Class constructor
        """

        # get settings
        self._setLogFile()

        self.languages = config.getConfigValue("wps","lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps","version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = method
Beispiel #11
0
    def __init__(self, method=METHOD_GET, configFiles=None):
        """Class constructor
        """

        # get settings
        self.setLogFile()
        self.UUID = uuid.uuid1().__str__()

        self.languages = config.getConfigValue("wps", "lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps", "version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = method
Beispiel #12
0
    def setLogFile(self, clear_handlers=False):
        """Set :data:`logFile`. Default is sys.stderr
        """
        global logFile
        fileName = config.getConfigValue("server","logFile")
        logLevel = eval("logging."+config.getConfigValue("server","logLevel").upper())
        format = "PyWPS [%(asctime)s] %(levelname)s: %(message)s"

        if clear_handlers and len(logging.root.handlers) > 0:
            # somehow need to clear handlers for async processes
            logging.root.handlers[:] = []
        
        if not fileName:
            logging.basicConfig(level=logLevel,format=format)
        else:
            logging.basicConfig(filename=fileName,level=logLevel,format=format)
            logFile = open(fileName, "a")
Beispiel #13
0
    def __init__(self, environ, configFiles=None):
        """Class constructor
        """

        # get settings
        config.loadConfiguration(configFiles, environ)
        self.setLogFile()
        self.UUID = uuid.uuid1().__str__()

        self.languages = config.getConfigValue("wps","lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps","version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = environ["REQUEST_METHOD"]
Beispiel #14
0
    def __init__(self, environ, configFiles=None):
        """Class constructor
        """

        # get settings
        config.loadConfiguration(configFiles, environ)
        self.setLogFile()
        self.UUID = uuid.uuid1().__str__()

        self.languages = config.getConfigValue("wps", "lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps", "version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = environ["REQUEST_METHOD"]
Beispiel #15
0
    def __init__(self, method=METHOD_GET, configFiles=None):
        """Class constructor
        """

        # get settings, if not already loaded
        if not config.config:
            config.loadConfiguration(configFiles)
        self.setLogFile()
        self.UUID = uuid.uuid1().__str__()

        self.languages = config.getConfigValue("wps","lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps","version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = method

        # create configured output path if it does not exist and ensure it 
        # is accessible
        try:
            outputPath = config.getConfigValue("server","outputPath")
            os.makedirs(outputPath)
        except OSError:
            if not os.path.isdir(outputPath):
                raise

        # create configured temp path if it does not exist and ensure it
        # is accessible
        try:
            tempPath = config.getConfigValue("server","tempPath")
            os.makedirs(tempPath)
        except OSError:
            if not os.path.isdir(tempPath):
                raise
Beispiel #16
0
    def __init__(self, method=METHOD_GET, configFiles=None):
        """Class constructor
        """

        # get settings, if not already loaded
        if not config.config:
            config.loadConfiguration(configFiles)
        self.setLogFile()
        self.UUID = uuid.uuid1().__str__()

        self.languages = config.getConfigValue("wps", "lang").split(",")
        DEFAULT_LANG = self.languages[0]

        # set default version
        self.versions = config.getConfigValue("wps", "version").split(",")
        DEFAULT_VERSION = self.versions[0]

        # find out the request method
        self.method = method

        # create configured output path if it does not exist and ensure it
        # is accessible
        try:
            outputPath = config.getConfigValue("server", "outputPath")
            os.makedirs(outputPath)
        except OSError:
            if not os.path.isdir(outputPath):
                raise

        # create configured temp path if it does not exist and ensure it
        # is accessible
        try:
            tempPath = config.getConfigValue("server", "tempPath")
            os.makedirs(tempPath)
        except OSError:
            if not os.path.isdir(tempPath):
                raise
Beispiel #17
0
    def getWeatherBy(self, location):
        longitude = location[0]
        latitude = location[1]

        key = getConfigValue(configWeather)
        url = "https://free-api.heweather.com/s6/weather/now?key=" + key + "&location=" + longitude + "," + latitude

        with request.urlopen(url) as f:
            data = f.read()
            print('Status:', f.status, f.reason)
            # for k, v in f.getheaders():
            #     print('%s: %s' % (k, v))
            print('Data:', data.decode('utf-8'))
            jsonObject = json.loads(data.decode("utf-8"))
            weatherStatus = jsonObject['HeWeather6'][0]['now']
        return weatherStatus
Beispiel #18
0
def getListFromInput(query):
	'''Retrieves the task list from the user's input.

----------
	@param str query: The user's input.
	'''
	if DEBUG > 0:
		log.debug('[ getListFromInput() ] ')
	inputList = getConfigValue(confNames['confList'])
	global availableListsIdName
	hasList = len(query.split('+')) > 1
	if hasList:
		# If user is typing, the current list name - e.g. 'tes' for 'cu X +tes' - will not match anything in the dict. Until we found a complete match, do not attempt to update inputList
		listName = query.split('+', 1)[1].split(' #', 1)[0].split(' @', 1)[0].split(' !', 1)[0].strip()
		if listName in availableListsNameId:
			inputList = availableListsNameId[query.split('+', 1)[1].split(' #', 1)[0].split(' @', 1)[0].split(' !', 1)[0].strip()]
	if DEBUG > 1:
		log.debug('inputList: ' + str(inputList))
		log.debug(availableListsIdName)

	return inputList
def updateTask(strTaskId):
    '''Updates an existing Task and sets its status to 'Closed'.

----------
	@param str strTaskId: Id of the Task to update.
	'''
    from workflow.notify import notify
    if DEBUG > 0:
        log.debug('[ Calling API to close task ]')
    wf3 = Workflow3()
    url = 'https://api.clickup.com/api/v2/task/' + strTaskId

    headers = {}
    headers['Authorization'] = getConfigValue(confNames['confApi'])
    headers['Content-Type'] = 'application/json'
    data = {}
    data['status'] = 'Closed'
    if DEBUG > 1:
        log.debug(url)
        log.debug(headers)
        log.debug(data)

    try:
        import requests
        request = requests.put(url, json=data, headers=headers)
        request.raise_for_status()
        result = request.json()
        if DEBUG > 1:
            log.debug('Response: ' + str(result))
            notify('Closed Task', result['name'])
    except Exception as exc:
        log.debug('Error on HTTP request:' + str(exc))
        wf3.add_item(title='Error connecting to ClickUp.',
                     subtitle='Open configuration to check your parameters?',
                     valid=True,
                     arg='cu:config ',
                     icon='error.png')
        wf3.send_feedback()
        exit()
Beispiel #20
0
def getDueFromInput(query):
	'''Retrieves the task due date from the user's input.

----------
	@param str query: The user's input.
	'''
	if isTicketURL(query):
		return None 

	if DEBUG > 0:
		log.debug('[ getDueFromInput() ] ')

	naturalLanguageWeekdays = {'mon': 0, 'monday': 0, 'tue': 1, 'tuesday': 1, 'wed': 2, 'wednesday': 2, 'thu': 3, 'thursday': 3, 'fri': 4, 'friday': 4, 'sat': 5, 'saturday': 5, 'sun': 6, 'sunday': 6}
	naturalLanguageRelativeDays = {'tod': 0, 'today': 0, 'tom': 1, 'tomorrow': 1}
	# 'in X days/weeks': Handled via dX/wx
	# 'next mon': Same as 'mon'

	inputMinHourDayWeek = ''
	# passedDue = ''
	isUseDefault = True
	isNoDueDate = False
	hasTime = len(query.split(' @', 2)) > 1
	hasDefault = (getConfigValue(confNames['confDue']) is not None and getConfigValue(confNames['confDue']) != '')
	naturalValue = ''
	timeValue = ''
 	hasValue = False
	isInputInteger = False
	if hasTime or hasDefault:
		inputDue = 0
		hasTime = len(query.split(' @')) > 1
		if hasTime:
			hasValue = len(query.split(' @')[1]) > 0 and query.split(' @')[1][0] != ' ' # [1] = First element in array (h3 (+ any text after)). [0] = First character of array (h). Ensure that first character is not a space, otherwise "cu Test @ someText" will be true
			timeValue = query.split(' @')[1][1:].split(' ')[0] # cu Task @h2 some other text -> h2

		if hasTime and hasValue:
			isUseDefault = False
			# if DEBUG > 1:
			# 	passedDue = getConfigValue(confNames['confDue']) if isUseDefault else query.split(' @')[1][1:].split(' ')[0]
			# 	log.debug('passedDue: ' + str(passedDue))

		inputMinHourDayWeek = ''
		if (isUseDefault and getConfigValue(confNames['confDue'])):
			inputMinHourDayWeek = getConfigValue(confNames['confDue'])[0]
		elif len(query.split(' @', 2)[1]) > 0:
			value = query.split(' @', 2)[1]
			if value.split(' ')[0].lower() in naturalLanguageWeekdays.keys(): # Get date of next x-day
				naturalValue = nextWeekday(datetime.datetime.today(), naturalLanguageWeekdays[value.split(' ')[0].lower()])
				if DEBUG > 1:
					log.debug('Received weekday: ' + str(naturalValue))
				log.debug(nextWeekday(datetime.datetime.today(), naturalLanguageWeekdays[value.split(' ')[0].lower()]))
			elif value.split(' ')[0].lower() in naturalLanguageRelativeDays.keys(): # Get date of today/tomorrow
				naturalValue = datetime.datetime.today() + datetime.timedelta(naturalLanguageRelativeDays[value.split(' ')[0].lower()])
				time = re.search(r'(2[0-3]|[01]?[0-9])\.[0-5]?[0-9](\.[0-5]?[0-9])?', value)

				h = 0
				m = 0
				if (time and time.group()) or len(value.split(' ')) > 1:
					if time and '.' in time.group():
						if DEBUG > 1:
							log.debug('Found time: ' + str(time.group()))
						# e.g. @today 14.00
						h = int(time.group().split('.')[0])
						m = int(time.group().split('.')[1])
					elif len(value.split(' ')) > 1:
						if not isInteger(value.split(' ')[1]):
							wf3.add_item(
								title = 'Not a valid time.',
								subtitle = 'Please use 24h time format with a dot - example: 15.00',
								valid = False,
								autocomplete = query + ' ',
								icon = ICON_WARNING
							)
							wf3.send_feedback()
							exit()
						h = int(value.split(' ')[1])
					naturalValue = (datetime.datetime.today() + datetime.timedelta(naturalLanguageRelativeDays[value.split(' ')[0].lower()])).replace(hour = h, minute = m)
				if DEBUG > 1:
					log.debug('Received relative date: ' + str(naturalValue))
				log.debug(datetime.datetime.today() + datetime.timedelta(naturalLanguageRelativeDays[value.split(' ')[0].lower()]))
			elif re.search(r'\d{4}-\d?\d-\d?\d', value) or re.search(r'(2[0-3]|[01]?[0-9])\.[0-5]?[0-9](\.[0-5]?[0-9])?', value): # Get date or date-time as specified
				date = ''
				dateTime = ''
				if len(sys.argv) == 2 or len(sys.argv) == 3:
					date = re.search(r'\d{4}-\d?\d-\d?\d', value) # Matches 2000-01-01
				if len(sys.argv) == 3:
					dateTime = re.search(r'(2[0-3]|[01]?[0-9])\.[0-5]?[0-9](\.[0-5]?[0-9])?', value) # Matches 12:00:00 or 12:00 # TODO: Split on Space?
				if date:
					if DEBUG > 1:
						log.debug('Found date: ' + str(date.group()))
					try:
						naturalValue = datetime.datetime.strptime(date.group() + 'T' + datetime.datetime.now().strftime("%H.%M.%S"), '%Y-%m-%dT%H.%M.%S') # Convert string 'date + current time' to dateTime
					except ValueError: # Incorrect format, e.g. 2020-01-1
						naturalValue = ''
						pass
				if dateTime:
					if DEBUG > 1:
						log.debug('Found date time: ' + str(dateTime.group()))
					theDate = str(datetime.datetime.today().strftime('%Y-%m-%d')) if not date else date.group()
					if len(dateTime.group()) == 5 or len(dateTime.group()) == 8: # 12:00, 12:00:00
						try:
							time = dateTime.group() if len(dateTime.group()) != 8 else dateTime.group()[:5]
							naturalValue = datetime.datetime.strptime(theDate + 'T' + time, '%Y-%m-%dT%H.%M')
						except ValueError: # Incorrect format, e.g. used : instead of . for hour.min.sec
							naturalValue = ''
							pass

				# Note: If only time given, e.g. @20:00:00 - then I need to add the current date.
			else:
				inputMinHourDayWeek = value[0] # First character: m, h, d, w
				if DEBUG > 1:
					log.debug('inputMinHourDayWeek: ' + str(inputMinHourDayWeek))
		if not naturalValue:
			isDefaultInteger = getConfigValue(confNames['confDue']) and int(getConfigValue(confNames['confDue'])[1:])
			if hasTime:
				isInputInteger = timeValue.isnumeric() #query.split(' @', 2)[1].strip()[1:].isnumeric()
			if isUseDefault and isDefaultInteger:
				inputDue = int(getConfigValue(confNames['confDue'])[1:])
			elif isInputInteger:
				inputDue = int(timeValue) #int(query.split(' @', 2)[1].strip()[1:])
			else: # Invalid input
				inputDue = 0 # No longer default of 2h - can now be set via configuration if desired, if not no due date will be added
				isNoDueDate = True
				inputMinHourDayWeek = 'h'

			if inputMinHourDayWeek == 'm':
				inputDue *= 1000 * 60
			elif inputMinHourDayWeek == 'h':
				inputDue *= 1000 * 60 * 60
			elif inputMinHourDayWeek == 'd':
				inputDue *= 1000 * 60 * 60 * 24
			elif inputMinHourDayWeek == 'w':
				inputDue *= 1000 * 60 * 60 * 24 * 7
	else:
		inputDue = 0 # No longer default of 2h if no other value specified and no default context variable specified - can now be set via configuration if desired, if not no due date will be added
		isNoDueDate = True
	if not naturalValue:
		inputDue = datetime.datetime.now() + datetime.timedelta(milliseconds = inputDue) # Add to whatever buffer has been selected
	else:
		inputDue = naturalValue
	if DEBUG > 1:
		log.debug('inputDue: ' + str(inputDue))

	if isNoDueDate:
		return None
	else:
		return inputDue
Beispiel #21
0
def getTasks():
    '''Retrieves a list of Tasks from the ClickUp API.

----------
	'''
    # For mode = search: ClickUp does not offer a parameter 'filter_by' - therefore we receive all tasks, and use Alfred/fuzzy to filter.
    if DEBUG > 0:
        log.debug('[ Calling API to list tasks ]')
    url = 'https://api.clickup.com/api/v2/team/' + getConfigValue(
        confNames['confTeam']) + '/task'
    params = {}
    wf3 = Workflow3()

    if getConfigValue(confNames['confHierarchyLimit']):
        if 'space' in getConfigValue(confNames['confHierarchyLimit']):
            params['space_ids[]'] = getConfigValue(
                confNames['confSpace'])  # Use [] instead of %5B%5D
        if 'folder' in getConfigValue(confNames['confHierarchyLimit']):
            params['project_ids[]'] = getConfigValue(confNames['confProject'])
        if 'list' in getConfigValue(confNames['confHierarchyLimit']):
            params['list_ids[]'] = getConfigValue(confNames['confList'])
    params['order_by'] = 'due_date'
    # Differentiates between listing all Alfred-created tasks and searching for all tasks (any)
    if DEBUG > 0 and len(wf.args) > 1 and wf.args[1] == 'search':
        log.debug('[ Mode: Search (cus) ]')
    elif DEBUG > 0 and len(wf.args) > 1 and wf.args[1] == 'open':
        log.debug('[ Mode: Open tasks (cuo) ]')
        # from datetime import date, datetime, timezone, timedelta

        today = datetime.date.today()
        todayEndOfDay = datetime.datetime(today.year, today.month, today.day,
                                          23, 59, 59)
        epoch = datetime.datetime(1970, 1, 1)
        todayEndOfDayMs = int(
            (todayEndOfDay - epoch).total_seconds() /
            datetime.timedelta(microseconds=1).total_seconds() / 1000)

        params['due_date_lt'] = todayEndOfDayMs
    else:
        log.debug('[ Mode: List tasks (cul) ]')
        params['tags[]'] = getConfigValue(confNames['confDefaultTag'])
    headers = {}
    headers['Authorization'] = getConfigValue(confNames['confApi'])
    headers['Content-Type'] = 'application/json'
    if DEBUG > 1:
        log.debug(url)
        log.debug(headers)
        log.debug(params)
    try:
        request = web.get(url, params=params, headers=headers)
        request.raise_for_status()
    except:
        log.debug('Error on HTTP request')
        wf3.add_item(title='Error connecting to ClickUp.',
                     subtitle='Open configuration to check your parameters?',
                     valid=True,
                     arg='cu:config ',
                     icon='error.png')
        wf3.send_feedback()
        exit()
    result = request.json()
    if DEBUG > 1:
        log.debug('Response: ' + str(result))

    for task in result['tasks']:
        tags = ''
        if task['tags']:
            for allTaskTags in task['tags']:
                tags += allTaskTags['name'] + ' '

        wf3.add_item(
         title = '[' + task['status']['status'] + '] ' + task['name'],
         subtitle = (emoji.emojize(':calendar:') + \
                      str(datetime.datetime.fromtimestamp(int(task['due_date'])/1000)) if task['due_date'] else '') + (emoji.emojize(
         ':exclamation_mark:') + task['priority']['priority'].title() if task['priority'] else '') + (' ' + emoji.emojize(':label:') + tags if task['tags'] else ''),
         valid = True,
         arg = task['url']
        )
    wf3.send_feedback()
Beispiel #22
0
def createTask(inputName, inputContent, inputDue, inputPriority, inputTags, inputList):
	'''Creates a Task by sending it to the ClickUp API.

----------
	@param str inputName: The user's input for the task title.
	@param str inputContent: The user's input for the task decsription.
	@param str inputDue: The user's input for the task due date.
	@param str inputPriority: The user's input for the task priority.
	@param str inputTags: The user's input for the task tags.
	@param str inputList: The user's input for the task list.
	'''
	if DEBUG > 0:
		log.debug('[ Calling API to create task ]')
	
	if not inputList:
		inputListId = getConfigValue(confNames['confList'])
	else:
		# Get value of first key in dictionary {Name, Id} by converting to List. The dict will always contain a single list name+Id the user specified.
		inputListId = next(iter(inputList.items()))[1] # Get value for first key of dict
	
	if inputDue != 'None':
		if len(inputDue) == 26: # 2020-01-01T12:00:00.000000
			inputDue = datetime.datetime.strptime(str(inputDue)[:len(inputDue) - 10], '%Y-%m-%d %H:%M') # Convert String to datetime. Remove seconds.milliseconds (e.g. :26.614286) from string
		else: # 2020-01-01T12:00:00
			inputDue = datetime.datetime.strptime(str(inputDue)[:len(inputDue)], '%Y-%m-%d %H:%M:%S')
		inputDueMs = (inputDue - datetime.datetime.fromtimestamp(0)).total_seconds() * 1000.0 # Convert datetime into ms. Use fromtimestamp() to get local timezone instead of utcfromtimestamp()
	
	url = 'https://api.clickup.com/api/v2/list/' + inputListId + '/task'
	params = None
	headers = {}
	headers['Authorization'] = getConfigValue(confNames['confApi'])
	headers['Content-Type'] = 'application/json'
	data = {}
	data['name'] = inputName
	data['content'] = inputContent
	if inputDue != 'None':
		data['due_date'] = int(inputDueMs)
		data['due_date_time'] = True # Translated into true
	data['priority'] = inputPriority if inputPriority is not None else None # Translated into 'null'
	data['tags'] = inputTags
	if getConfigValue(confNames['confUser']): # Default assignee = current user
		data['assignees'] = [getConfigValue(confNames['confUser'])]
	
	if DEBUG > 1:
		log.debug(url)
		log.debug(headers)
		log.debug(data)
	
	try:
		import json
		request = web.post(url, params = params, data = json.dumps(data), headers = headers)
		request.raise_for_status()
	except:
		log.debug('Error on HTTP request')
		wf.add_item(title = 'Error connecting to ClickUp.', subtitle = 'Open configuration to check your parameters?', valid = True, arg = 'cu:config ', icon = 'error.png')
		wf.send_feedback()
		exit()
	result = request.json()
	if DEBUG > 1:
		log.debug('Response: ' + str(result))
	
	# If user pressed 'opt' (optInput == true), we do not want to show a notification, as the task is opened in the browser
	hasUserNotPressedOpt = 'optInput' not in os.environ or os.environ['optInput'] == 'false'
	if getConfigValue(confNames['confNotification']) == 'true' and (hasUserNotPressedOpt):
		notify('Created: ' + inputName, formatNotificationText(inputContent, inputDue, inputTags, inputPriority, inputList, True))
	elif os.environ['optInput'] and os.environ['optInput'] == 'true':
		print(result['url'])