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
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']
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
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']
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")
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()
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")
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')
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
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
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
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")
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"]
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"]
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
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
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
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()
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
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()
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'])