def job_search(api, since=3, **kwargs): """Produce list of job posted after given date.""" debug = log.debug url = 'https://www.odesk.com/api/profiles/v1/search/jobs.xml' dp = days_ago_to_dp(since) keys = kwargs.keys() params = [('dp', dp)] for keyword in keys: param = valid_job_search_parameter(keyword) if param: params.append((param, kwargs[keyword])) offset=0 count = 200 joblist = [] while 1: params.append(('page', '{0:d};{1:d}'.format(offset, count))) xml = send_GET(api, url, params) if xml is None: e = "Error, request failed: send_GET(api, {0:s}, {1!s}".format(url, params) stderr("{0:s}\n".format(e)) log.error(e) return joblist jl = list_from_xml(xml, 'job') if len(jl) == 0: break joblist.extend(jl) if len(jl) < count: break params.pop() offset += count return joblist
def teams(api, request=None, save_xml=None): """Retrieve a list of all teams this process (user) has access to. Parameters: request - List which limits the amount of information returned. Must be a subset of: ['parent_team__id', 'is_hidden', 'status', 'name', 'company_name', 'parent_team__name', 'company__reference', 'parent_team__reference', 'reference' , 'id'] The teams may be from different companies. Results of this GET depend on the permissions granted to the authenticated user of this process- the oDesk user and password used to access the API. Returns: List of dict objects- one per team. """ url = urls.get_API_URL('teams') if save_xml: save_xml = 'teams.xml' response = send_GET(api, url, save_xml=save_xml) if response is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return [] teams = list_from_xml(response, 'team') all_info = ['parent_team__id', 'is_hidden', 'status', 'name', 'company_name', 'parent_team__name', 'company__reference', 'parent_team__reference', 'reference' , 'id'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(list(request), all_info) return dict_subset(teams, requested_info)
def show_return(data, caller=None, extra=None): """Log the data returned as the result of a query. This was written to allow inspection of data returned from the API server. The data parameter is a dict object containing keys 'ret', 'inf', 'url' and 'err'. The data of interest are 'ret' and 'err' con- taining the response text and error information. """ from os import environ from logger import getLogLevel from logging import DEBUG if getLogLevel() > DEBUG: return #data = {'ret','inf','url','err'} if not caller: caller = 'send_request' if extra: log.info("{0:s}: information about this request: {1:s}".format(caller,extra)) ret = data['ret'].encode('utf-8') try: wid = environ['COLUMNS'] except KeyError: wid = 80 ret = format_lines(ret, margin=' ret >', col=wid) log.info(" >> 'ret':\n{0:s}".format(ret)) if data['inf']: lines = " 'inf' > " + str(data['inf']) else: lines = " 'inf' > None" log.info("{0:s}".format(lines)) log.info(" >> 'redirect' : {0:s}".format(str(data['url']))) log.info(" >> 'error': {0:s}".format(str(data['err'])))
def login(self, user, password): params = [('login',user), ('password',password), ('action','login')] url = get_auth_URL('login') + self.merge_params_to_uri(None, params, False) data = self.send_request(url, 'post', caller=func()) self.user_authorized = self.request_ok(data) if self.user_authorized: log.info("Logged in as {0:s}".format(user)) self.set_user_and_password(user, password) return self.user_authorized
def get_api_keys_uri(self, api_sig, caller): """ get_api_keys_uri: Return API's URI with signature and app key param string api_sig Signature return string """ val = '?api_key=' + self.api_key + '&api_sig=' + api_sig dmesg = "get_api_keys_uri(from {0:s}): {1:s}".format(caller, val) log.debug(dmesg) return val
def _verify_sort(sort_string): valid_field_names = '' field_names = to_str(sort_string).split(';') for name in field_names: if valid_provider_search_parameter(name): valid_field_names = valid_field_names + name + ';' else: log.warn("{0:s}: not a valid field_name") if valid_field_names: return valid_field_names.rstrip(';') return None
def install_opener(self, user=None, passwd=None): """Install (add) an opener which handles authentication and cookies.""" if not (user and passwd): (user, passwd) = self.get_user_and_password() pm = urllib2.HTTPPasswordMgrWithDefaultRealm() pm.add_password(None, get_auth_URL('login'), user, passwd) self.cookie_jar = cookielib.LWPCookieJar() try: self.set_cookie_file(self.cookie_file) except OpenerError, e: e += "Unable to open cookie file" log.warn("{0:s}".format(str(e)))
def provider_search(api, save_xml=False, **kwargs): """Use the provider search API to search all public providers on oDesk. Parameter kwargs is expected to contain key-value pairs where the key is one of the keys, or the 'field_name', from the dict 'params' defined in valid_provider_search_parameter(). The utility function str2kwargs() from api.util.utility can be used to generate 'kwargs'. """ node_name = 'providers' url = get_API_URL('providers') if save_xml: save_xml = 'providers.xml' params = [] for keyword in kwargs.keys(): parameter = valid_provider_search_parameter(keyword) if not parameter: continue if kwargs[keyword]: # could be 'None' if parameter == 'sort': stderr('\nkwargs[keyword] = {0:s}\n'.format(kwargs[keyword])) value = _verify_sort(kwargs[keyword]) else: value = kwargs[keyword] if value: params.append((parameter, value)) else: params.append((parameter)) # HERE #stderr('\nquery/provider.py:provider_search() params = {0!r}\n\n'.format(params)) # offset=0 count = 200 providers = [] while 1: # extrac parens needed, param to append is a tuple params.append(('page', '{0:d};{1:d}'.format(offset, count))) # HERE #stderr('send_GET params: {0:s}\n'.format(params)) # xml = send_GET(api, url, params, save_xml) if xml is None: e = "Error, request failed: send_GET(api, {0:s}, {1!s}".format(url, params) stderr("{0:s}\n".format(e)) log.error(e) return None pl = list_from_xml(xml, node_name) if len(pl) == 0: break providers.extend(pl) if len(pl) < count: break params.pop() offset += count return providers
def find_team(api, company_name, team_name): """Retrun reference Id and status of a team.""" teamlist = company_teams(api, company_name) reference, status = None, None if not teamlist: e = 'Failed to find anything for company {0:s}'.format(company_name) log.error(e) return (reference, status) for team in teamlist: if team['name'] == team_name: reference = team['reference'] status = team['status'] break return (reference, status)
def install_opener(cookie_file, user=None, passwd=None): """Install (add) an opener which handles authentication and cookies.""" if not (user and passwd): auth_file = path.join(path.expanduser('~'),'.auth/odesk/odesk_user') (user, passwd) = user_auth_from_file(auth_file) pm = urllib2.HTTPPasswordMgrWithDefaultRealm() pm.add_password(None, get_auth_URL('login'), user, passwd) cookie_jar = cookielib.LWPCookieJar() if cookie_file is None: cookie_file = 'cookies.txt' try: set_cookie_file(cookie_file) except OpenerError, e: e += "Unable to open cookie file" log.warn("{0:s}".format(str(e)))
def team_users(api, team_name, request=None, eid=None, save_xml=None, debug=False): """Retrieve details of team members. Parameters: team_name - Name of team. Should be identical to a team returned by company_teams(api, 'company name') request - List which limits the amount of information returned. Must be a subset of: ['last_name', 'first_name', 'status', 'id', 'reference', 'is_provider', 'timezone', 'timezone_offset'] These are the keys in the dict object(s) returned. eid - oDesk user id. This is the same as the 'id' above. If given a list of one dict object for a team member matching 'id' is returned. Return: A list of one dict object if 'eid' parameter is given, or a list of N dict objects where N equals the number of people on the named team. If 'request' is not given the dict object contains all information for each team member. Otherwise each item in 'request' which exactly matchs one of the valid identifiers given above is returned in each dict object generated. """ userlist = [] (team_ref, parent_team_ref, company_ref) = \ team_reference_IDs(api, team_name, save_xml) if not team_ref: log.warning("No results from team_users(api, '{0:s}')".format(team_name)) return userlist log.info("fetching team {0:s} users".format(team_name)) url = urls.get_API_URL('team_users', team_ref=team_ref) log.debug('URL: {0:s}'.format(url)) if save_xml: save_xml = 'team_users.xml' response = send_GET(api, url, save_xml=save_xml) if response is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return userlist tmplist = list_from_xml(response, 'user', debug=debug) if eid: for user in tmplist: if user['id'] == eid: userlist.append(user) break else: userlist = tmplist[:] all_info = ['last_name', 'first_name', 'status', 'id', 'reference', 'is_provider', 'timezone', 'timezone_offset'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(list(request), all_info) return dict_subset(userlist, requested_info)
def jobs_managed(api, company, team, request=None, **kwargs): """Compile a list of open jobs managed under 'company'.""" # Need team reference for 'buyer_team_reference' parameter to Jobs HR API bad_result = (0, None) (ref, status) = find_team(api, company, team) if not ref: log.error("Failed to find team {0:s} (company {1:s})".format(team, company)) return bad_result node_name = 'job' params = [('buyer_team__reference', ref)] if kwargs: keys = kwargs.keys() for key in keys: param = valid_jobs_managed_parameter(key) if param: params.append((param, kwargs[key])) elif key == 'save_xml': save_xml = 'jobs_managed' if kwargs[key] else None url = get_API_URL('jobs_hr') xml = send_GET(api, url, params, save_xml=save_xml) if xml is None: e = "Error, request failed: send_GET(api, {0:s}, {1!s}".format(url, params) stderr("{0:s}\n".format(e)) log.error(e) return bad_result total_items = int(xml_get_tag(xml, 'total_items')) all_info = ['buyer_company__name','buyer_company__reference','buyer_team__id', 'buyer_team__name','buyer_team__reference','category','company__reference', 'company_name','created_by','created_by_name','created_time','description', 'duration','end_date','filled_date','id','job_type','name', 'num_active_candidates','num_candidates','num_new_candidates', 'owner_user_id','parent_team__id','parent_team__name', 'parent_team__reference','public_url','reference','start_date','status', 'subcategory','title','visibility'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) if total_items > 0: result = dict_subset(list_from_xml(xml, node_name), requested_info) else: result = [] return (total_items, result)
def provider_profile(api, provider_keys, request=None, brief_listing=True, save_xml=False): """Fetch provider profile(s) associated with provider key(s). Parameter 'provider_keys' is interpreted as a string of one or more keys, or a tuple or list of two or more keys. 'ciphertext' returned from provider_search() above is the 'provider_key'. """ url = get_API_URL('profiles') url_suffix = '/brief.xml' if brief_listing else '.xml' node_name = 'profile' # 'Parameters: Accepts a provider key or list of keys' # E.g. "~~d4080e9142d610ea;~~d4080e9142d610ea;~~9eaf4d98034b5bd8" # Note: as of 2011-04-08 the list of keys format does not work? Perms? if isinstance(provider_keys, basestring): provider_keys = provider_keys.replace(' ', ';') provider_keys = provider_keys.split(';') elif isinstance(provider_keys, list) or isinstance(provider_keys, tuple): provider_keys = list(provider_keys) else: e = "provider_profile(api, provider_keys): provider_keys parmeter must\n" e += "be a string, tuple, or list." raise ParamFmtError(e) assert isinstance(provider_keys,list) params = '' for pk in provider_keys: params += pk + ';' params = params.rstrip(';') # quoting multiple strings does not work either # url += "'" + params + "'"+ url_suffix url += params + url_suffix xml = send_GET(api, url, params=None, save_xml=save_xml) if xml is None: e = "Error, request failed: send_GET(api, {0:s})".format(url) stderr("{0:s}\n".format(e)) log.error(e) return None result = list_from_xml(xml, node_name) return result
def company_teams(api, company_name, request=None, save_xml=None): """Retrieve a list of teams within a company. Parameters: api - Instance of class oDeskAPI company_name - Target company of query. Should be identical to a name returned by api.query.organization:companies(api, request) request - List which limits the amount of information returned for each team. Must be a subset of: ['parent_team__id', 'is_hidden', 'status', 'name', 'company_name', 'parent_team__name', 'company__reference, 'parent_team__reference', 'reference', 'id'] Return: A list of dictionary objects describing each team in the company. Default is to return all information. Results depend on the access permission of the currently authorized user. """ node_tag_name = 'team' details = company_details(api, company_name, request=['reference'], save_xml=save_xml) if not details: return None refId = details['reference'] url = urls.get_API_URL('company_teams', company_ref=refId) if save_xml: save_xml = 'company_teams.xml' xml = send_GET(api, url, save_xml=save_xml) if xml is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return None team_list = list_from_xml(xml, node_tag_name) all_info = ['parent_team__id', 'is_hidden', 'status', 'name', 'company_name', 'parent_team__name', 'company__reference', 'parent_team__reference', 'reference', 'id'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) return dict_subset(team_list, requested_info)
def normalize_params(self, params, rkey = ''): """Sort params into ascending alpabetical order and convert to string. 'params' is a list or tuple of 2-tuples representing parameter-value pairs which are sorted on parameter token. """ line = '' if isinstance(params, tuple): params = list(params) if not isinstance(params, list): return line # sort keys and reassemble as string cmpkeys=lambda x,y: cmp(x[0], y[0]) params.sort(cmpkeys) for p in params: if isinstance(p[1], list): line += self.normalize_params(p[1], p[0]) else: line += rkey + p[0] + p[1] log.debug("normalized: {0:s}".format(line)) return line
def engagement_details(api, reference_no, request=None, save_xml=None): """Fetch details on one engagements. Parameter 'reference_no' is the engagement reference number- same as 'reference' returned from the query api.query.engagements(api, team) Parameter 'request' if given limits the information returned to a subset of: [buyer_team__id, buyer_team__reference, created_time, engagement_job_type, engagement_start_date, engagement_title, estimated_duration, estimated_duration_id, hourly_charge_rate, hourly_pay_rate, job__reference, job__title, modified_time, offer__reference, provider__id, provider__reference, reference, role, status, weekly_hours_limit, weekly_salary_charge_amount, weekly_salary_pay_amount] Return value is a list of dicionary objects, one for each 'engagement' the query returns. """ all_info = ['buyer_team__id', 'buyer_team__reference', 'created_time', 'engagement_job_type', 'engagement_start_date', 'engagement_title', 'estimated_duration', 'estimated_duration_id', 'hourly_charge_rate', 'hourly_pay_rate', 'job__reference', 'job__title', 'modified_time', 'offer__reference', 'provider__id', 'provider__reference', 'reference', 'role', 'status', 'weekly_hours_limit', 'weekly_salary_charge_amount', 'weekly_salary_pay_amount'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) node_name = 'engagement' url = get_API_URL('engagement', engagement_ref=reference_no) xml = send_GET(api, url) if xml is None: e = "Error, request failed: send_GET(api, {0:s})".format(url) stderr("{0:s}\n".format(e)) log.error(e) return None result = list_from_xml(xml, node_name) details = dict_subset(result, requested_info) return details[0]
def _send_request(api, url, request='get', params=None, save_xml=None): """Call api.xxxx_request and optionally save XML response to file. Parameter 'api' is an instance of class oDeskAPI """ save_file = None pcopy = params[:] if params else None log.debug("send_{0:s} params: {1!r}".format(pcopy, request.upper())) request = request.lower() try: if request == 'get': response = api.get_request(url, pcopy) elif request == 'post': response = api.post_request(url, pcopy) elif request == 'put': response = api.put_request(url, pcopy) elif request == 'delete': response = api.delete_request(url, pcopy) else: e = "Unknown request type '{0:s}'".format(request) stderr("{0:s}\n".format(e)) log.error(e) return None except RequestError, e: # api.last_error is the error code returned by server stderr(e) log.exception(e) # Do not change this return value. # Some callers may check 'if response is None: ...' return None
def user_roles(api, request=None, save_xml=None): """Retrieve permission information of user. For the currently authenticated user return a list of permission information for each company/team the user has access to. Parameter 'request' is a list which limits the information returned. Must be a subset of: ['affiliation_status', 'company__name', 'company__reference', 'engagement__reference', 'has_team_room_access', 'parent_team__id', 'parent_team__name', 'parent_team__reference', 'permission', 'reference', 'role', 'team__id', 'team__name', 'team__reference', 'user__first_name', 'user__id', 'user__is_provider', 'user__last_name', 'user__reference'] """ url = urls.get_API_URL('user_roles') xmlnode = 'userrole' if save_xml: save_xml = 'user_roles' xml = send_GET(api, url, save_xml=save_xml) if xml is None: e = "Error, request failed: send_GET(api, {0:s}".format(url) stderr("{0:s}\n".format(e)) log.error(e) return None roles = list_from_xml(xml, xmlnode) all_info = ['affiliation_status', 'company__name', 'company__reference', 'engagement__reference', 'has_team_room_access', 'parent_team__id', 'parent_team__name', 'parent_team__reference', 'permission', 'reference', 'role', 'team__id', 'team__name', 'team__reference', 'user__first_name', 'user__id', 'user__is_provider', 'user__last_name', 'user__reference'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(list(request), all_info) return dict_subset(roles, requested_info)
def company_details(api, company_name, request=None, save_xml=None): """Retrieve details of a specific company. Return a dictionary object containing the details for 'company_name'. If currently authenticated user (this process) does not have access to this company return None. Parameters: company_name - 'My Company', not company id or reference request - List which limits the amount of information returned. Must be a subset of: ['reference', 'status', 'name', 'owner_user_id'] Return: A dictionary object describing the company. Default is to return all information. """ refId = company_reference_ID(api, company_name, save_xml=save_xml) if refId == -1: return None node_name = 'company' url = urls.get_API_URL('company_details', company_ref=refId) if save_xml: save_xml = 'company_details.xml' xml = send_GET(api, url, save_xml=save_xml) if xml is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return None details = list_from_xml(xml, node_name) if len(details) != 1: return None all_info = ('reference', 'status', 'name', 'owner_user_id') if not request: requested_info = all_info log.debug('requested_info: {0!r}') else: requested_info = list_intersect(request, all_info) details = dict_subset(details, requested_info) return details[0]
def job_details(api, job_reference, request=None, **kwargs): """Find all available information for a particular job.""" # Need team reference for 'buyer_team_reference' parameter to Jobs HR API (ref, status) = find_team(api, company, team) if not ref: log.error("Failed to find team {0:s} (company {1:s})".format(team, company)) return None node_name = 'job' save_xml = None params = [('buyer_team__reference', ref)] if kwargs: keys = kwargs.keys() for key in keys: param = valid_jobs_managed_parameter(key) if param: params.append((param, kwargs[key])) elif key == 'save_xml': save_xml = kwargs[key] url = get_API_URL('jobs_hr') xml = send_GET(api, url, params, save_xml=save_xml) if xml is None: e = "Error, request failed: send_GET(api, {0:s}, {1!s}".format(url, params) stderr("{0:s}\n".format(e)) log.error(e) return None result = list_from_xml(xml, node_name) all_info= ['reference','title','job_type','description','public_url', 'created_time','created_by','start_date','end_date','filled_date', 'cancelled_date','buyer_team__reference','buyer_team__id', 'buyer_team__name','buyer_company__reference','buyer_company__name', 'visibility','budget','duration','category','subcategory','num_candidates', 'num_active_candidates','num_new_candidates','last_candidacy_access_time', 'status'] if not rquest: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) return dict_subset(result, all_info)
def get_api_token(self, frob): """Retrieve the API token needed for odesk.com server communication. This is the token appended to all server requests. The 'frob' token must be available to aquire this token from the server. """ iam = func() self.api_token = self.get_token() if self.api_token: return self.api_token assert frob is not None params = [('frob', self.frob)] api_sig = self.get_signature(params, caller=iam) url = get_auth_URL('tokens') + \ self.merge_params_to_uri(self.get_api_keys_uri(api_sig, iam), params) log.debug("get_api_token(): url: {0:s}".format(url)) data = self.send_request(url, 'get', caller=iam) if self.request_ok(data): self.api_token = xml_get_tag(data['ret'], 'token') else: log.error("Unable to get API token.") if not self.api_token: raise AppAPITokenError("Unable to get API token.") return self.api_token
def companies(api, request=None, save_xml=None): """Retrieve a list of all companies this process (user) has access to. Parameters: request - List which limits the amount of information returned for each company the user has access to. Must be a subset of: [reference, status, name, owner_user_id] """ node_name = 'company' url = urls.get_API_URL('companies') if save_xml: save_xml = 'companies.xml' xml = send_GET(api, url, save_xml=save_xml) if xml is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return None company_list = list_from_xml(xml, node_name) all_info = ['reference', 'status', 'name', 'owner_user_id'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) return dict_subset(company_list, requested_info)
def team_reference_IDs(api, team_name, save_xml=None): """Retrieve reference ID numbers associated with a team. If team given by 'team_name' can be found by api.query.teams() three reference identification numbers are returned; 'team_name', the parent team of 'team_name', and company to which 'team_name' belongs. """ team_dict = None team_ref, parent_team_ref, company_ref = None, None, None myreq = ['name', 'reference', 'parent_team__reference', 'company__reference'] team_list = teams(api, request=myreq, save_xml=save_xml) for team in team_list: if team_name == team['name']: team_dict = team break if team_dict: team_ref = team_dict['reference'] parent_team_ref = team_dict['parent_team__reference'] company_ref = team_dict['company__reference'] else: # This is not necessarily an error- See team_visable() below. log.debug("Unable to find team by name '{0:s}'".format(team_name)) return (team_ref, parent_team_ref, company_ref)
def send_request(self, url, reqtype='get', caller=None): """Send request to server. Add appropriate headers to HTTP request and open given 'url'. """ iam, caller, debug = func(), str(caller), log.debug data = {'ret':None,'inf':None, 'url':None,'err':None, 'code':None} reqdata = None user_agent = 'Python oDeskAPI library client/{0:s}'.format(self.api_version) headers = {'User-Agent':user_agent} headers['connection'] = 'Keep-Alive' headers['Content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8' if reqtype != 'get': if url.find('?') > 0: (url, reqdata) = url.split('?', 1) req = urllib2.Request(url, reqdata, headers) dmesg = '\n\turl: {0:s}\n\treqdata: {1:s}\n\theaders: {2:s}\n\tmethod: {3:s}' log.debug(dmesg.format(url, reqdata, headers, req.get_method())) try: #reply = urllib2.urlopen(req) reply = self.opener.open(req) except urllib2.HTTPError, e: preamble = "(called by {0:s})-".format(caller) data['code'] = e.code data['err'] = e.reason if e.code == 304: log.debug("{0:s}: return code 304".format(preamble)) return data if e.code != 200: from BaseHTTPServer import BaseHTTPRequestHandler responses = BaseHTTPRequestHandler.responses crit = log.critical crit("{0:s} Server couldn't fulfill the request.".format(preamble)) crit('{0:s} >> {1:d} ({2:s}) {3:s}'.format(preamble, e.code, responses[e.code][0], responses[e.code][1])) #crit('{0:s} >> Reason: {1:s}'.format(preamble,str(e.reason))) raise
def request(reqtype, url, api_key, api_token, params): """Construct and send a request to the server. Parameters: reqtype - string indicating the type of request url - URL to which request information is appended params - string, list or tuple of parameter-value pairs ex. string 'param1;param2;etc' ex. list [(param1, val), (param2, val)] ex. tuple ((paramq, val), (param2,val)) If a tuple is passed it is converted to list. Raises RequestError on failure. """ iam = func() debug = log.debug assert api_token is not None if not params: params = [] elif isinstance(params, tuple): params = list(params) elif isinstance(params, basestring): params = [params] params.append(('api_token', api_token)) if reqtype == 'put' or reqtype == 'delete': params.append(('http_method', reqtype)) api_sig = get_signature(params, caller=iam) api_keys_str = api_keys_uri(api_key, api_sig) merged_params = merge_params_to_uri(api_keys_str, params) log.debug("merged_params: {0:s}".format(merged_params)) url = url + merged_params data = send_request(url, reqtype, caller=iam) if not request_ok(data): e = 'Can not execute request due to error: {0!s}'.format(data['err']) raise RequestError(e) return data['ret']
def get_auth_URL(auth, fmt='xml'): e = "Expected a string identifier, i.e. 'login' or 'auth'.".format(auth) if not isinstance(auth, basestring): log.error(e) raise AppParameterError(e) authorization = { 'login':'******', 'auth':'https://www.odesk.com/services/api/auth', # origional authorization 'tokens':'https://www.odesk.com/api/auth/v1/keys/tokens.xml', 'frobs':'https://www.odesk.com/api/auth/v1/keys/frobs.xml', # OAuth 'access':'https://www.odesk.com/api/auth/v1/oauth/token/access', 'request':'https://www.odesk.com/api/auth/v1/oauth/token/request', } try: url = authorization[auth] except KeyError: log.error("unknow URL request '{0:s}'".format(auth)) raise AppParameterError(e) if fmt == 'json': url = url.replace('.xml', '.json') return url
def company_users(api, company_name, request=None, save_xml=None, debug=False): """Retrieve list of contractors working for 'company_name' Parameters: company_name - Target company of query. Should be identical to a name returned by odesk.api.query.organization:companies(api, request) request - List which limits the amount of information returned for each user. Must be a subset of: [timezone, reference, status, timezone_offset, id, is_provider, last_name, first_name] This ultimately depends on the success of api.query.company_details(). That GET depends on the permissions granted to the authenticated user of this process- the oDesk user and password used to access the API. Return: List of dictionary objects- one per employee. """ userlist = [] details = company_details(api, company_name, save_xml=False) if not details: warn = "No results from company_details(api, '{0:s}')" log.warning(warn.format(company_name)) return userlist log.info("fetching company {0:s} users".format(company_name)) url = urls.get_API_URL('company_users', company_ref=details['reference']) log.debug('URL: {0:s}'.format(url)) if save_xml: save_xml = 'company_users.xml' response = send_GET(api, url, save_xml=save_xml) if response is None: log.error("request failed: send_GET(api, {0:s}".format(url)) return userlist userlist = list_from_xml(response, 'user', debug=debug) all_info = ['timezone', 'reference', 'status', 'timezone_offset', 'id', 'is_provider', 'last_name', 'first_name'] if not request: requested_info = all_info[:] else: requested_info = list_intersect(request, all_info) return dict_subset(userlist, requested_info)
def get_api_frob(self, api_sig): """Retrieve the 'frob' token from the odesk server. This token lives 600s. """ iam = func() assert self.user_authorized assert api_sig if self.frob: return frob url = get_auth_URL('frobs') + self.get_api_keys_uri(api_sig, iam) log.debug('{0:s}: frob URI: {1:s}'.format(iam,url)) data = self.send_request(url, 'post', caller=iam) if not self.request_ok(data): return None frob = xml_get_tag(data['ret'], 'frob', unicode=False) log.debug("frob: {0:s}".format(frob)) if not frob: log.error("Failed to parse 'frob' from server response") else: self.frob = frob return frob
# convert 0..5 to logger levels pylevel = toLogLevel(n) if pylevel != log_levels[n]: stderr("toLogLevel({0:s}) ({1:d}) failed, got {2:d} ({3:s})\n".format( user_levels[n], n, pylevel, user_levels[pylevel/10])) errors += 1 tests += 1 stdout("tests converting back and forth between strings and integer log levels:\n") stdout("{0:d} tests, {1:d} failures\n\n".format(tests, errors)) stdout("initializing logging, level debug, console on, log file off.\n") initLogger(logLevel=1, logConsole=True, logDisk=False) stdout("should see debug message test 1\n") log.debug("log test 1") if test_fileobj('{0:s}'.format(pgm)) != 1: stdout('log file \"{0:s}\" should not have been created\n', pgm) errors += 1 else: stdout('Should see "Parameter not a file or file object."\n') tests += 1 print stdout("testing setLogLevel('warn'), should see only WARN: log test 2\n") setLogLevel("warn") log.debug("log test 2") log.warn("log test 2") print
kwargs = {'app_auth_file': auth} if alias: kwargs['app_alias'] = alias try: api = oDeskAPI(config=config, **kwargs) except AppInitError, e: stderr(e) stderr("Failed to initialize oDeskAPI instance...\n") exit(1) if popts['debug']: api.debug = True init_logging(api, popts) # Authorize this process with odesk.com developer API if not api.authorize(): assert api.api_token == None log.error('failed to authorize client-- no api token') api.clean_exit(1) log.debug("app_main() returning {0!s}".format(argv2)) return (api, argv2) # This is intended only for testing. if __name__ == '__main__': from odapi.logger import initLogger usage = """ usage: $ {0:s} [OPTIONS] [OPTIONS]""" initLogger(logLevel='debug',logDisk=False, logConsole=True) (api, argv) = app_main(sys.argv[0], sys.argv, usage)