Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
cc53aab
Initial app and model for LinkedIn integration.
Dec 9, 2013
64887c6
Flesh out findusers script, except for LinkedIn API call, with tests.
Dec 11, 2013
a5d1cb3
pep8 and pylint
Dec 12, 2013
883563d
Test max_calls == 0
Dec 12, 2013
e34d131
Skeleton for emails script.
Dec 12, 2013
2d5c4da
Test coverage.
Dec 12, 2013
2468c99
Test grandfather path.
Dec 13, 2013
fc17ed2
Properly handle already emailed courses.
Dec 13, 2013
b2db05f
Initial stab at placeholder email template.
Dec 13, 2013
411d39d
Script to log in to LinkedIn API.
Dec 13, 2013
7a48e93
Did not mean to check in proof of concept script.
Dec 16, 2013
2f9e9e2
Refactor findusers script to be fully lazy, in hopes we don't run out…
Dec 16, 2013
dc9c52d
Pep8, pylint.
Dec 16, 2013
ec2678a
Refactor LinkedIn API code to common location for reuse.
Dec 17, 2013
bb43d4c
House cleaning.
Dec 17, 2013
5d7befd
Generate certificate URLs.
Dec 17, 2013
35fdbf3
Send mail.
Dec 17, 2013
9755216
Use whitelist for testing.
Dec 17, 2013
46657b8
Grandfather email.
Dec 17, 2013
76b15ea
Get json data.
Dec 18, 2013
dffa8c6
LinkedIn API finally works.
Dec 19, 2013
d7d7327
Allow force checking, disregarding LinkedIn's rules.
Dec 19, 2013
cf4ae16
Disambiguate script names. Unfortunately verbose.
Dec 19, 2013
5803b2e
Don't use linkedin app by default.
Dec 19, 2013
dc5dfe6
Some docs.
Dec 19, 2013
fd1d98f
Fix tests, one bug. Adopt a more Django-ish testing style.
Dec 19, 2013
0a5c25c
100% test coverage for mailusers.
Dec 20, 2013
38ad26d
Test --force.
Dec 20, 2013
cf98cb6
Squash warning.
Dec 20, 2013
c5c9554
Test LinkedinAPI
Dec 20, 2013
f286296
pep8
Dec 20, 2013
c265149
Pylint
Dec 20, 2013
33f7611
It looks like LinkedIn pfCertFuture as the date a certificate expires.
Dec 20, 2013
1a5eb08
Remove stray 'I' from generated URL.
Dec 30, 2013
a18bce8
Basic cleanup of code to determine whether a user has a LinkedIn acco…
Jan 9, 2014
a3f1f66
Integrate new LinkedIn e-mail template
dianakhuang Jan 9, 2014
f370012
Clean up the e-mail settings.
dianakhuang Jan 10, 2014
ed64817
Use correct linkedin button.
dianakhuang Jan 10, 2014
db7308a
Remove unused parts of LinkedIn API
Jan 13, 2014
469fab5
Update copy for LinkedIn e-mail.
dianakhuang Jan 13, 2014
fdf531a
Migrations for LinkedIn.
dianakhuang Jan 13, 2014
0726211
Use S3 uploaded image for e-mail button.
dianakhuang Jan 14, 2014
cc1d796
Add email send error checking.
Jan 15, 2014
2b66515
Add in test to test the transactions when we hit an unexpected error.
dianakhuang Jan 15, 2014
77a315c
Minor data collection tweaks after examining prod course data.
Jan 16, 2014
c971838
catch additional FEATURE['ENABLE_MKTG_SITE'] checks and make sure Mic…
Jan 15, 2014
f051e33
New copy and styling.
dianakhuang Jan 17, 2014
d220aac
Minor copy change requested by linkedin.
dianakhuang Jan 21, 2014
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
9 changes: 7 additions & 2 deletions common/djangoapps/edxmako/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ def marketing_link(name):
# link_map maps URLs from the marketing site to the old equivalent on
# the Django site
link_map = settings.MKTG_URL_LINK_MAP
if settings.FEATURES.get('ENABLE_MKTG_SITE') and name in settings.MKTG_URLS:
enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)

if enable_mktg_site and name in settings.MKTG_URLS:
# special case for when we only want the root marketing URL
if name == 'ROOT':
return settings.MKTG_URLS.get('ROOT')
return settings.MKTG_URLS.get('ROOT') + settings.MKTG_URLS.get(name)
# only link to the old pages when the marketing site isn't on
elif not settings.FEATURES.get('ENABLE_MKTG_SITE') and name in link_map:
elif not enable_mktg_site and name in link_map:
# don't try to reverse disabled marketing links
if link_map[name] is not None:
return reverse(link_map[name])
Expand Down
1 change: 1 addition & 0 deletions common/djangoapps/util/models.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# Create your models here.

5 changes: 4 additions & 1 deletion lms/djangoapps/branding/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ def courses(request):
to that. Otherwise, if subdomain branding is on, this is the university
profile page. Otherwise, it's the edX courseware.views.courses page
"""
enable_mktg_site = settings.FEATURES.get('ENABLE_MKTG_SITE') or MicrositeConfiguration.get_microsite_configuration_value('ENABLE_MKTG_SITE', False)
enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)

if enable_mktg_site:
return redirect(marketing_link('COURSES'), permanent=True)
Expand Down
8 changes: 7 additions & 1 deletion lms/djangoapps/courseware/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
from xmodule.course_module import CourseDescriptor
import shoppingcart

from microsite_configuration.middleware import MicrositeConfiguration

log = logging.getLogger("edx.courseware")

template_imports = {'urllib': urllib}
Expand Down Expand Up @@ -514,7 +516,11 @@ def registered_for_course(course, user):
@ensure_csrf_cookie
@cache_if_anonymous
def course_about(request, course_id):
if settings.FEATURES.get('ENABLE_MKTG_SITE', False):

if MicrositeConfiguration.get_microsite_configuration_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
):
raise Http404

course = get_course_with_access(request.user, course_id, 'see_exists')
Expand Down
121 changes: 121 additions & 0 deletions lms/djangoapps/linkedin/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
============================
LinkedIn Integration for edX
============================

This package provides a Django application for use with the edX platform which
allows users to post their earned certificates on their LinkedIn profiles. All
functionality is currently provided via a command line interface intended to be
used by a system administrator and called from other scripts.

Basic Flow
----------

The basic flow is as follows:

o A system administrator uses the 'linkedin_login' script to log in to LinkedIn
as a user with email lookup access in the People API. This provides an access
token that can be used by the 'linkedin_findusers' script to check for users
that have LinkedIn accounts.

o A system administrator (or cron job, etc...) runs the 'linkedin_findusers'
script to query the LinkedIn People API, looking for users of edX which have
accounts on LinkedIn.

o A system administrator (or cron job, etc...) runs the 'linkedin_mailusers'
script. This scripts finds all users with LinkedIn accounts who also have
certificates they've earned which they haven't already been emailed about.
Users are then emailed links to add their certificates to their LinkedIn
accounts.

Configuration
-------------

To use this application, first add it to your `INSTALLED_APPS` setting in your
environment config::

INSTALLED_APPS += ('linkedin',)

You will then also need to provide a new key in your settings, `LINKEDIN_API`,
which is a dictionary::

LINKEDIN_API = {
# Needed for API calls
'CLIENT_ID': "FJkdfj93kf93",
'CLIENT_SECRET': "FJ93oldj939rkfj39",
'REDIRECT_URI': "http://my.org.foo",

# Needed to generate certificate links
'COMPANY_NAME': 'Foo',
'COMPANY_ID': "1234567",

# Needed for sending emails
'EMAIL_FROM': "The Team <someone@org.foo>",
'EMAIL_WHITELIST': set(['fred@bedrock.gov', 'barney@bedrock.gov'])
}

`CLIENT_ID`, `CLIENT_SECRET`, and `REDIRECT_URI` all come from your registration
with LinkedIn for API access. `CLIENT_ID` and `CLIENT_SECRET` will be provied
to you by LinkedIn. You will choose `REDIRECT_URI`, and it will be the URI
users are directed to after handling the authorization flow for logging into
LinkedIn and getting an access token.

`COMPANY_NAME` is the name of the LinkedIn profile for the company issuing the
certificate, e.g. 'edX'. `COMPANY_ID` is the LinkedIn ID for the same profile.
This can be found in the URL for the company profile. For exampled, edX's
LinkedIn profile is found at the URL: http://www.linkedin.com/company/2746406
and their `COMPANY_ID` is 2746406.

`EMAIL_FROM` just sets the from address that is used for generated emails.

`EMAIL_WHITELIST` is optional and intended for use in testing. If
`EMAIL_WHITELIST` is given, only users whose email is in the whitelest will get
notification emails. All others will be skipped. Do not provide this in
production.

If you are adding this application to an already running instance of edX, you
will need to use the `syncdb` script to add the tables used by this application
to the database.

Logging into LinkedIn
---------------------

The management script, `linkedin_login`, interactively guides a user to log into
LinkedIn and obtain an access token. The script generates an authorization URL,
asks the user go to that URL in their web browser and log in via LinkedIn's web
UI. When the user has done that, they will be redirected to the configured
location with an authorization token embedded in the query string of the URL.
This authorization token is good for only 30 seconds. Within 30 seconds the
user should copy and paste the URL they were directed to back into the command
line script, which will then obtain and store an access token.

Access tokens are good for 60 days. There is currently no way to refresh an
access token without rerunning the `linkedin_login` script again.

Finding Users
-------------

Once you have logged in, the management script, `linkedin_findusers`, is used
to find out which users have LinkedIn accounts using LinkedIn's People API. By
default only users which have never been checked are checked. The `--recheck`
option can be provided to recheck all users, in case some users have joined
LinkedIn since the last time they were checked.

LinkedIn has provided guidance on what limits we should follow in accessing
their API based on time of the day and day of the week. The script attempts to
enforce that. To override its enforcement, you can provide the `--force` flag.

Send Emails
-----------

Once you have found users, you can email them links for their earned
certificates using the `linkedin_mailusers` script. The script will only mail
any particular user once for any particular certificate they have earned.

The emails come in two distinct flavors: triggered and grandfathered. Triggered
emails are the default. These comprise one email per earned certificate and are
intended for use when a user has recently earned a certificate, as will
generally be the case if this script is run regularly.

The grandfathered from of the email can be sent by adding the `--grandfather`
flag and is intended to bring users up to speed with all of their earned
certificates at once when this feature is first added to edX.
Empty file.
Empty file.
Empty file.
Loading