Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
64887c68
Commit
64887c68
authored
Dec 11, 2013
by
Chris Rossi
Committed by
Diana Huang
Jan 16, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Flesh out findusers script, except for LinkedIn API call, with tests.
parent
cc53aab4
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
230 additions
and
1 deletions
+230
-1
lms/djangoapps/linkedin/management/commands/findusers.py
+87
-1
lms/djangoapps/linkedin/management/commands/tests/__init__.py
+0
-0
lms/djangoapps/linkedin/management/commands/tests/test_findusers.py
+143
-0
No files found.
lms/djangoapps/linkedin/management/commands/findusers.py
View file @
64887c68
import
datetime
import
pytz
import
time
from
django.contrib.auth.models
import
User
from
django.core.management.base
import
BaseCommand
,
CommandError
from
django.utils
import
timezone
from
optparse
import
make_option
FRIDAY
=
4
def
get_call_limits
():
"""
Returns a tuple of: (max_checks, checks_per_call, time_between_calls)
Here are the parameters provided by LinkedIn:
Please note: in order to ensure a successful call, please run the calls
between Friday 6pm PST and Monday 5am PST.
During the week, calls are limited to very low volume (500 profiles/day)
and must be run after 6pm and before 5am. This should only be used to do
subsequent trigger emails. Please contact the developer support alias for
more information.
Use 80 emails per API call and 1 call per second.
"""
now
=
timezone
.
now
()
.
astimezone
(
pytz
.
timezone
(
'US/Pacific'
))
lastfriday
=
now
while
lastfriday
.
weekday
()
!=
FRIDAY
:
lastfriday
-=
datetime
.
timedelta
(
days
=
1
)
safeharbor_begin
=
lastfriday
.
replace
(
hour
=
18
,
minute
=
0
)
safeharbor_end
=
safeharbor_begin
+
datetime
.
timedelta
(
days
=
2
,
hours
=
11
)
if
safeharbor_begin
<
now
<
safeharbor_end
:
return
-
1
,
80
,
1
elif
now
.
hour
>=
18
or
now
.
hour
<
5
:
return
500
,
80
,
1
else
:
return
0
,
0
,
0
class
Command
(
BaseCommand
):
args
=
''
help
=
'Checks LinkedIn for students that are on LinkedIn'
option_list
=
BaseCommand
.
option_list
+
(
make_option
(
'--recheck'
,
action
=
'store_true'
,
dest
=
'recheck'
,
default
=
False
,
help
=
'Check users that have been checked in the past to see if '
'they have joined or left LinkedIn since the last check'
),
)
def
handle
(
self
,
*
args
,
**
options
):
print
"Hello World!"
api
=
LinkedinAPI
()
recheck
=
options
.
pop
(
'recheck'
,
False
)
max_checks
,
checks_per_call
,
time_between_calls
=
get_call_limits
()
if
not
max_checks
:
raise
CommandError
(
"No checks allowed during this time."
)
check_users
=
[]
for
user
in
User
.
objects
.
all
():
checked
=
(
hasattr
(
user
,
'linkedin'
)
and
user
.
linkedin
.
has_linkedin_account
is
not
None
)
if
recheck
or
not
checked
:
check_users
.
append
(
user
)
if
max_checks
!=
-
1
and
len
(
check_users
)
>
max_checks
:
self
.
stderr
.
write
(
"WARNING: limited to checking only
%
d users today."
%
max_checks
)
check_users
=
check_users
[:
max_checks
]
batches
=
[
check_users
[
i
:
i
+
checks_per_call
]
for
i
in
xrange
(
0
,
len
(
check_users
),
checks_per_call
)]
def
do_batch
(
batch
):
emails
=
[
u
.
email
for
u
in
batch
]
for
user
,
has_account
in
zip
(
batch
,
api
.
batch
(
emails
)):
user
.
linkedin
.
has_linkedin_account
=
has_account
if
batches
:
do_batch
(
batches
.
pop
(
0
))
for
batch
in
batches
:
time
.
sleep
(
time_between_calls
)
do_batch
(
batch
)
class
LinkedinAPI
(
object
):
def
batch
(
self
,
emails
):
pass
lms/djangoapps/linkedin/management/commands/tests/__init__.py
0 → 100644
View file @
64887c68
lms/djangoapps/linkedin/management/commands/tests/test_findusers.py
0 → 100644
View file @
64887c68
import
datetime
import
mock
import
pytz
import
StringIO
import
unittest
from
linkedin.management.commands
import
findusers
class
FindUsersTests
(
unittest
.
TestCase
):
@mock.patch
(
'linkedin.management.commands.findusers.timezone'
)
def
test_get_call_limits_in_safe_harbor
(
self
,
timezone
):
fut
=
findusers
.
get_call_limits
tz
=
pytz
.
timezone
(
'US/Eastern'
)
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
14
,
0
,
0
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
-
1
,
80
,
1
))
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
13
,
21
,
1
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
-
1
,
80
,
1
))
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
15
,
7
,
59
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
-
1
,
80
,
1
))
@mock.patch
(
'linkedin.management.commands.findusers.timezone'
)
def
test_get_call_limits_in_business_hours
(
self
,
timezone
):
fut
=
findusers
.
get_call_limits
tz
=
pytz
.
timezone
(
'US/Eastern'
)
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
11
,
11
,
3
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
0
,
0
,
0
))
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
13
,
20
,
59
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
0
,
0
,
0
))
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
16
,
8
,
1
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
0
,
0
,
0
))
@mock.patch
(
'linkedin.management.commands.findusers.timezone'
)
def
test_get_call_limits_on_weeknights
(
self
,
timezone
):
fut
=
findusers
.
get_call_limits
tz
=
pytz
.
timezone
(
'US/Eastern'
)
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
11
,
21
,
3
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
500
,
80
,
1
))
timezone
.
now
.
return_value
=
datetime
.
datetime
(
2013
,
12
,
11
,
7
,
59
,
tzinfo
=
tz
)
self
.
assertEqual
(
fut
(),
(
500
,
80
,
1
))
@mock.patch
(
'linkedin.management.commands.findusers.time'
)
@mock.patch
(
'linkedin.management.commands.findusers.User'
)
@mock.patch
(
'linkedin.management.commands.findusers.LinkedinAPI'
)
@mock.patch
(
'linkedin.management.commands.findusers.get_call_limits'
)
def
test_command_success_recheck_no_limits
(
self
,
get_call_limits
,
API
,
User
,
time
):
fut
=
findusers
.
Command
()
.
handle
get_call_limits
.
return_value
=
(
-
1
,
6
,
42
)
api
=
API
.
return_value
users
=
[
mock
.
Mock
(
email
=
i
)
for
i
in
xrange
(
10
)]
User
.
objects
.
all
.
return_value
=
users
def
dummy_batch
(
emails
):
return
[
email
%
2
==
0
for
email
in
emails
]
api
.
batch
=
dummy_batch
fut
(
recheck
=
True
)
time
.
sleep
.
assert_called_once_with
(
42
)
self
.
assertEqual
([
u
.
linkedin
.
has_linkedin_account
for
u
in
users
],
[
i
%
2
==
0
for
i
in
xrange
(
10
)])
@mock.patch
(
'linkedin.management.commands.findusers.time'
)
@mock.patch
(
'linkedin.management.commands.findusers.User'
)
@mock.patch
(
'linkedin.management.commands.findusers.LinkedinAPI'
)
@mock.patch
(
'linkedin.management.commands.findusers.get_call_limits'
)
def
test_command_success_no_recheck_no_limits
(
self
,
get_call_limits
,
API
,
User
,
time
):
fut
=
findusers
.
Command
()
.
handle
get_call_limits
.
return_value
=
(
-
1
,
6
,
42
)
api
=
API
.
return_value
users
=
[
mock
.
Mock
(
email
=
i
)
for
i
in
xrange
(
10
)]
for
user
in
users
[:
6
]:
user
.
linkedin
.
has_linkedin_account
=
user
.
email
%
2
==
0
for
user
in
users
[
6
:]:
user
.
linkedin
.
has_linkedin_account
=
None
User
.
objects
.
all
.
return_value
=
users
def
dummy_batch
(
emails
):
self
.
assertEqual
(
len
(
emails
),
4
)
return
[
email
%
2
==
0
for
email
in
emails
]
api
.
batch
=
dummy_batch
fut
()
time
.
sleep
.
assert_not_called
()
self
.
assertEqual
([
u
.
linkedin
.
has_linkedin_account
for
u
in
users
],
[
i
%
2
==
0
for
i
in
xrange
(
10
)])
@mock.patch
(
'linkedin.management.commands.findusers.time'
)
@mock.patch
(
'linkedin.management.commands.findusers.User'
)
@mock.patch
(
'linkedin.management.commands.findusers.LinkedinAPI'
)
@mock.patch
(
'linkedin.management.commands.findusers.get_call_limits'
)
def
test_command_success_no_recheck_no_users
(
self
,
get_call_limits
,
API
,
User
,
time
):
fut
=
findusers
.
Command
()
.
handle
get_call_limits
.
return_value
=
(
-
1
,
6
,
42
)
api
=
API
.
return_value
users
=
[
mock
.
Mock
(
email
=
i
)
for
i
in
xrange
(
10
)]
for
user
in
users
:
user
.
linkedin
.
has_linkedin_account
=
user
.
email
%
2
==
0
User
.
objects
.
all
.
return_value
=
users
def
dummy_batch
(
emails
):
self
.
assertTrue
(
False
)
# shouldn't be called
api
.
batch
=
dummy_batch
fut
()
time
.
sleep
.
assert_not_called
()
self
.
assertEqual
([
u
.
linkedin
.
has_linkedin_account
for
u
in
users
],
[
i
%
2
==
0
for
i
in
xrange
(
10
)])
@mock.patch
(
'linkedin.management.commands.findusers.time'
)
@mock.patch
(
'linkedin.management.commands.findusers.User'
)
@mock.patch
(
'linkedin.management.commands.findusers.LinkedinAPI'
)
@mock.patch
(
'linkedin.management.commands.findusers.get_call_limits'
)
def
test_command_success_recheck_with_limit
(
self
,
get_call_limits
,
API
,
User
,
time
):
command
=
findusers
.
Command
()
command
.
stderr
=
StringIO
.
StringIO
()
fut
=
command
.
handle
get_call_limits
.
return_value
=
(
9
,
6
,
42
)
api
=
API
.
return_value
users
=
[
mock
.
Mock
(
email
=
i
)
for
i
in
xrange
(
10
)]
for
user
in
users
:
user
.
linkedin
.
has_linkedin_account
=
None
User
.
objects
.
all
.
return_value
=
users
def
dummy_batch
(
emails
):
return
[
email
%
2
==
0
for
email
in
emails
]
api
.
batch
=
dummy_batch
fut
()
time
.
sleep
.
assert_called_once_with
(
42
)
self
.
assertEqual
([
u
.
linkedin
.
has_linkedin_account
for
u
in
users
[:
9
]],
[
i
%
2
==
0
for
i
in
xrange
(
9
)])
self
.
assertEqual
(
users
[
9
]
.
linkedin
.
has_linkedin_account
,
None
)
self
.
assertTrue
(
command
.
stderr
.
getvalue
()
.
startswith
(
"WARNING"
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment