Skip to content

Commit

Permalink
[Fixes #4428] refactor linkedin field extraction (#4435)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alessio Fabiani committed May 28, 2019
1 parent c86a17b commit 6e9e887
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 148 deletions.
67 changes: 67 additions & 0 deletions docs/tutorials/admin/admin_mgmt_commands/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,70 @@ Arguments::
Groups for which permissions will be assigned to.
Multiple choices can be typed with white space separator.
-d, --delete Delete permission if it exists.


setupsociallogins
=================

Setup login via social providers. This command can be used to automatically
setup login with social accounts (facebook, linkedin).

The usual way to configure these providers is to:

# Enable the providers by adding their apps to the ``INSTALLED_APPS`` setting

# Login to django's admin section and then manually add entries to
the Social accounts -> Social applications section

This command automates this manual setup by creating the necessary entries
programmatically. It needs to know, for each provider:

* client_id

* secret_key

As such, the command takes ``--{provider}-client-id`` and
``--{provider}-secret-key`` arguments for each enabled provider. Alternatively,
it may also get these parameters from the environment - it looks for variables
named ``{PROVIDER}_OAUTH2_CLIENT_ID`` and ``{PROVIDER}_OAUTH2_SECRET_KEY``.

This makes it possible to configure providers automatically by putting these
sensitive fields in the environment and then running::

export FACEBOOK_OAUTH2_CLIENT_ID=123456
export FACEBOOK_OAUTH2_SECRET_KEY=abcdef
export LINKEDIN_OAUTH2_CLIENT_ID=123456
export LINKEDIN_OAUTH2_SECRET_KEY=abcdef

python manage.py setupsociallogins


Usage::

manage.py setupsociallogins [-h] [--version] [-v {0,1,2,3}]
[--settings SETTINGS]
[--pythonpath PYTHONPATH] [--traceback]
[--no-color]

Setup login via social providers - You need to add the relevant apps to
`INSTALLED_APPS` in order to be able to use this command (e.g. add
`allauth.socialaccount.providers.facebook` in order to configure logins with
facebook credentials)


Arguments::

-h, --help show this help message and exit
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
Empty file.
Empty file.
117 changes: 117 additions & 0 deletions geonode/people/management/commands/setupsociallogins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import os

from django.conf import settings
from django.core.management.base import BaseCommand
from django.contrib.sites.models import Site

from allauth.socialaccount.models import SocialApp


class Command(BaseCommand):
help = (
"Setup login via social providers - You need to add the relevant apps "
"to ``INSTALLED_APPS`` in order to be able to use this command (e.g. "
"add ``allauth.socialaccount.providers.facebook`` in order to "
"configure logins with facebook credentials)"
)

@staticmethod
def _get_client_id_arg(provider):
return "{}-client-id".format(provider)

@staticmethod
def _get_client_secret_arg(provider):
return "{}-secret-key".format(provider)

@staticmethod
def _get_client_id_env(provider):
return "{}_OAUTH2_CLIENT_ID".format(provider.upper())

@staticmethod
def _get_client_secret_env(provider):
return "{}_OAUTH2_SECRET_KEY".format(provider.upper())

@staticmethod
def get_social_providers():
providers = []
for app_info in settings.INSTALLED_APPS:
if isinstance(app_info, basestring):
if app_info.startswith("allauth.socialaccount.providers"):
provider_module = app_info.rpartition(".")[-1]
provider_name = provider_module.partition("_")[0]
providers.append((provider_name, provider_module))
return providers

def add_arguments(self, parser):
for provider_name, provider_id in self.get_social_providers():
client_id_arg = self._get_client_id_arg(provider_name)
parser.add_argument(
"--{}".format(client_id_arg),
help=(
"Specify the client id for {}. You may also specify "
"the {} environment variable instead".format(
provider_name,
self._get_client_id_env(provider_name)
)
)
)
client_secret_arg = self._get_client_secret_arg(provider_name)
parser.add_argument(
"--{}".format(client_secret_arg),
help=(
"Specify the secret key for {}. You may also specify "
"the {} environment variable instead".format(
provider_name,
self._get_client_secret_env(provider_name)
)
)
)

def handle(self, *args, **options):
social_providers = self.get_social_providers()
if len(social_providers) > 0:
for provider_name, provider_id in social_providers:
client_id_arg = self._get_client_id_arg(
provider_name).replace("-", "_")
client_secret_arg = self._get_client_secret_arg(
provider_name).replace("-", "_")
client_id = (
options.get(client_id_arg) or
os.getenv(self._get_client_id_env(provider_name))
)
client_secret = (
options.get(client_secret_arg) or
os.getenv(self._get_client_secret_env(provider_name))
)
if all((client_id, client_secret)):
self.stdout.write(
"Configuring provider {}...".format(provider_name))
self._handle_provider(
provider_name, provider_id, client_id, client_secret)
else:
self.stdout.write(
"Provider {} not all params were specified, "
"skipping...".format(provider_name)
)
else:
self.stdout.write(
"No social providers are currently in use, skipping...")
self.stdout.write(
"Add the relevant apps to the SETTINGS.INSTALLED_APPS and "
"rerun this command."
)

def _handle_provider(self, name, id_, client_id, secret_key):
provider, created = SocialApp.objects.get_or_create(
name=name.lower(),
client_id=client_id,
secret=secret_key,
provider=id_
)
if created:
# associate with the first site
provider.sites.add(Site.objects.get_current())
provider.save()
else:
self.stdout.write(
"Provider {} already exists, skipping...".format(name))
47 changes: 26 additions & 21 deletions geonode/people/profileextractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

"""Profile extractor utilities for social account providers"""

from django.conf import settings


class BaseExtractor(object):
"""Base class for social account data extractors.
Expand Down Expand Up @@ -98,31 +100,34 @@ def extract_profile(self, data):
class LinkedInExtractor(BaseExtractor):

def extract_email(self, data):
return data.get("emailAddress", "")
try:
element = data.get("elements")[0]
except IndexError:
email = ""
else:
email = element.get("handle~", {}).get("emailAddress", "")
return email

def extract_first_name(self, data):
return data.get("firstName", "")
return self._extract_field("firstName", data)

def extract_last_name(self, data):
return data.get("lastName", "")

def extract_position(self, data):
latest = _get_latest_position(data)
return latest.get("title", "") if latest is not None else ""

def extract_organization(self, data):
latest = _get_latest_position(data)
if latest is not None:
organization = latest.get("company", {}).get("name", "")
else:
organization = ""
return organization

def extract_profile(self, data):
headline = data.get("headline", "")
summary = data.get("summary", "")
profile = "\n".join((headline, summary))
return profile.strip()
return self._extract_field("lastName", data)

def _extract_field(self, name, data):
current_language = settings.LANGUAGE_CODE
localized_field_values = data.get(name, {}).get("localized", {})
for locale, name in localized_field_values.items():
split_locale = locale.partition("_")[0]
if split_locale == current_language:
result = name
break
else: # try to return first one, if it exists
try:
result = localized_field_values.items()[0][-1]
except IndexError:
result = ""
return result


def _get_latest_position(data):
Expand Down

0 comments on commit 6e9e887

Please sign in to comment.