Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/authentication.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import print_function
from linkedin.linkedin import (LinkedInAuthentication, LinkedInApplication,
PERMISSIONS)

Expand All @@ -7,6 +8,6 @@
API_SECRET = 'daJDa6_8UcnGMw1yuq9TjoO_PMKukXMo8vEMo7Qv5J-G3SPgrAV0FqFCd0TNjQyG'
RETURN_URL = 'http://localhost:8000'
authentication = LinkedInAuthentication(API_KEY, API_SECRET, RETURN_URL,
PERMISSIONS.enums.values())
print authentication.authorization_url
list(PERMISSIONS.enums.values()))
print(authentication.authorization_url)
application = LinkedInApplication(authentication)
2 changes: 1 addition & 1 deletion linkedin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = '4.1'
VERSION = tuple(map(int, __version__.split('.')))
VERSION = tuple(int(version_part) for version_part in __version__.split('.'))
40 changes: 25 additions & 15 deletions linkedin/linkedin.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
# -*- coding: utf-8 -*-
from future.builtins import str
from future.builtins import map
from future import standard_library
standard_library.install_hooks()
from future.builtins import object
import contextlib
import hashlib
import random
import urllib
import urllib.request
import urllib.parse
import urllib.error
from io import StringIO

import requests
from requests_oauthlib import OAuth1

from .exceptions import LinkedInError
from .models import AccessToken, LinkedInInvitation, LinkedInMessage
from .utils import enum, to_utf8, raise_for_error, json, StringIO
from .utils import enum, raise_for_error, json


__all__ = ['LinkedInAuthentication', 'LinkedInApplication', 'PERMISSIONS']
Expand Down Expand Up @@ -94,7 +102,7 @@ def authorization_url(self):
'redirect_uri': self.redirect_uri}
# urlencode uses quote_plus when encoding the query string so,
# we ought to be encoding the qs by on our own.
qsl = ['%s=%s' % (urllib.quote(k), urllib.quote(v)) for k, v in qd.items()]
qsl = ['%s=%s' % (urllib.parse.quote(k), urllib.parse.quote(v)) for k, v in qd.items()]
return '%s?%s' % (self.AUTHORIZATION_URL, '&'.join(qsl))

@property
Expand Down Expand Up @@ -123,28 +131,30 @@ class LinkedInSelector(object):
@classmethod
def parse(cls, selector):
with contextlib.closing(StringIO()) as result:
if type(selector) == dict:
if isinstance(selector, dict):
for k, v in selector.items():
result.write('%s:(%s)' % (to_utf8(k), cls.parse(v)))
elif type(selector) in (list, tuple):
result.write('%s:(%s)' % (str(k), cls.parse(v)))
elif isinstance(selector, (list, tuple)):
result.write(','.join(map(cls.parse, selector)))
else:
result.write(to_utf8(selector))
result.write(str(selector))
return result.getvalue()


class LinkedInApplication(object):
BASE_URL = 'https://api.linkedin.com'

def __init__(self, authentication=None, token=None):
assert authentication or token, 'Either authentication instance or access token is required'
assert authentication or token, (
'Either authentication instance or access token is required')
self.authentication = authentication
if not self.authentication:
self.authentication = LinkedInAuthentication('', '', '')
self.authentication.token = AccessToken(token, None)

def make_request(self, method, url, data=None, params=None, headers=None,
timeout=60):
print(url)
if headers is None:
headers = {'x-li-format': 'json', 'Content-Type': 'application/json'}
else:
Expand All @@ -170,7 +180,7 @@ def get_profile(self, member_id=None, member_url=None, selectors=None,
if member_id:
url = '%s/id=%s' % (ENDPOINTS.PEOPLE, str(member_id))
elif member_url:
url = '%s/url=%s' % (ENDPOINTS.PEOPLE, urllib.quote_plus(member_url))
url = '%s/url=%s' % (ENDPOINTS.PEOPLE, urllib.parse.quote_plus(member_url))
else:
url = '%s/~' % ENDPOINTS.PEOPLE
if selectors:
Expand All @@ -196,7 +206,7 @@ def get_picture_urls(self, member_id=None, member_url=None,
url = '%s/id=%s/picture-urls::(original)' % (ENDPOINTS.PEOPLE, str(member_id))
elif member_url:
url = '%s/url=%s/picture-urls::(original)' % (ENDPOINTS.PEOPLE,
urllib.quote_plus(member_url))
urllib.parse.quote_plus(member_url))
else:
url = '%s/~/picture-urls::(original)' % ENDPOINTS.PEOPLE

Expand All @@ -210,7 +220,7 @@ def get_connections(self, member_id=None, member_url=None, selectors=None,
url = '%s/id=%s/connections' % (ENDPOINTS.PEOPLE, str(member_id))
elif member_url:
url = '%s/url=%s/connections' % (ENDPOINTS.PEOPLE,
urllib.quote_plus(member_url))
urllib.parse.quote_plus(member_url))
else:
url = '%s/~/connections' % ENDPOINTS.PEOPLE
if selectors:
Expand All @@ -226,7 +236,7 @@ def get_memberships(self, member_id=None, member_url=None, group_id=None,
url = '%s/id=%s/group-memberships' % (ENDPOINTS.PEOPLE, str(member_id))
elif member_url:
url = '%s/url=%s/group-memberships' % (ENDPOINTS.PEOPLE,
urllib.quote_plus(member_url))
urllib.parse.quote_plus(member_url))
else:
url = '%s/~/group-memberships' % ENDPOINTS.PEOPLE

Expand Down Expand Up @@ -292,7 +302,7 @@ def like_post(self, post_id, action):
url = '%s/%s/relation-to-viewer/is-liked' % (ENDPOINTS.POSTS, str(post_id))
try:
self.make_request('PUT', url, data=json.dumps(action))
except (requests.ConnectionError, requests.HTTPError), error:
except (requests.ConnectionError, requests.HTTPError) as error:
raise LinkedInError(error.message)
else:
return True
Expand All @@ -304,7 +314,7 @@ def comment_post(self, post_id, comment):
url = '%s/%s/comments' % (ENDPOINTS.POSTS, str(post_id))
try:
self.make_request('POST', url, data=json.dumps(post))
except (requests.ConnectionError, requests.HTTPError), error:
except (requests.ConnectionError, requests.HTTPError) as error:
raise LinkedInError(error.message)
else:
return True
Expand All @@ -321,7 +331,7 @@ def get_companies(self, company_ids=None, universal_names=None, selectors=None,
identifiers = []
url = ENDPOINTS.COMPANIES
if company_ids:
identifiers += map(str, company_ids)
identifiers.extend(map(str, company_ids))

if universal_names:
identifiers += ['universal-name=%s' % un for un in universal_names]
Expand Down
190 changes: 96 additions & 94 deletions linkedin/models.py
Original file line number Diff line number Diff line change
@@ -1,94 +1,96 @@
# -*- coding: utf-8 -*-
import collections

AccessToken = collections.namedtuple('AccessToken', ['access_token', 'expires_in'])


class LinkedInRecipient(object):
def __init__(self, member_id, email, first_name, last_name):
assert member_id or email, 'Either member ID or email must be given'
if member_id:
self.member_id = str(member_id)
else:
self.member_id = None
self.email = email
self.first_name = first_name
self.last_name = last_name

@property
def json(self):
result = {'person': None}
if self.member_id:
result['person'] = {'_path': '/people/id=%s' % self.member_id}
else:
result['person'] = {'_path': '/people/email=%s' % self.email}

if self.first_name:
result['person']['first-name'] = self.first_name

if self.last_name:
result['person']['last-name'] = self.last_name

return result


class LinkedInInvitation(object):
def __init__(self, subject, body, recipients, connect_type, auth_name=None,
auth_value=None):
self.subject = subject
self.body = body
self.recipients = recipients
self.connect_type = connect_type
self.auth_name = auth_name
self.auth_value = auth_value

@property
def json(self):
result = {
'recipients': {
'values': []
},
'subject': self.subject,
'body': self.body,
'item-content': {
'invitation-request': {
'connect-type': self.connect_type
}
}
}
for recipient in self.recipients:
result['recipients']['values'].append(recipient.json)

if self.auth_name and self.auth_value:
auth = {'name': self.auth_name, 'value': self.auth_value}
result['item-content']['invitation-request']['authorization'] = auth

return result


class LinkedInMessage(object):
def __init__(self, subject, body, recipients, auth_name=None,
auth_value=None):
self.subject = subject
self.body = body
self.recipients = recipients
self.auth_name = auth_name
self.auth_value = auth_value

@property
def json(self):
result = {
'recipients': {
'values': []
},
'subject': self.subject,
'body': self.body,
}
for recipient in self.recipients:
result['recipients']['values'].append(recipient.json)

if self.auth_name and self.auth_value:
auth = {'name': self.auth_name, 'value': self.auth_value}
result['item-content']['invitation-request']['authorization'] = auth

return result
# -*- coding: utf-8 -*-
from future.builtins import str
from future.builtins import object
import collections

AccessToken = collections.namedtuple('AccessToken', ['access_token', 'expires_in'])


class LinkedInRecipient(object):
def __init__(self, member_id, email, first_name, last_name):
assert member_id or email, 'Either member ID or email must be given'
if member_id:
self.member_id = str(member_id)
else:
self.member_id = None
self.email = email
self.first_name = first_name
self.last_name = last_name

@property
def json(self):
result = {'person': None}
if self.member_id:
result['person'] = {'_path': '/people/id=%s' % self.member_id}
else:
result['person'] = {'_path': '/people/email=%s' % self.email}

if self.first_name:
result['person']['first-name'] = self.first_name

if self.last_name:
result['person']['last-name'] = self.last_name

return result


class LinkedInInvitation(object):
def __init__(self, subject, body, recipients, connect_type, auth_name=None,
auth_value=None):
self.subject = subject
self.body = body
self.recipients = recipients
self.connect_type = connect_type
self.auth_name = auth_name
self.auth_value = auth_value

@property
def json(self):
result = {
'recipients': {
'values': []
},
'subject': self.subject,
'body': self.body,
'item-content': {
'invitation-request': {
'connect-type': self.connect_type
}
}
}
for recipient in self.recipients:
result['recipients']['values'].append(recipient.json)

if self.auth_name and self.auth_value:
auth = {'name': self.auth_name, 'value': self.auth_value}
result['item-content']['invitation-request']['authorization'] = auth

return result


class LinkedInMessage(object):
def __init__(self, subject, body, recipients, auth_name=None,
auth_value=None):
self.subject = subject
self.body = body
self.recipients = recipients
self.auth_name = auth_name
self.auth_value = auth_value

@property
def json(self):
result = {
'recipients': {
'values': []
},
'subject': self.subject,
'body': self.body,
}
for recipient in self.recipients:
result['recipients']['values'].append(recipient.json)

if self.auth_name and self.auth_value:
auth = {'name': self.auth_name, 'value': self.auth_value}
result['item-content']['invitation-request']['authorization'] = auth

return result
Loading