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
62b91d6f
Commit
62b91d6f
authored
Feb 13, 2015
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6982 from edx/will/update-linkedin-field-name
LinkedIn Add to Profile source parameter
parents
052fa8ea
a18e0c6b
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
380 additions
and
80 deletions
+380
-80
common/djangoapps/student/migrations/0044_rename_linkedin_config_field.py
+191
-0
common/djangoapps/student/models.py
+48
-20
common/djangoapps/student/tests/tests.py
+84
-29
common/djangoapps/student/views.py
+10
-24
lms/static/sass/multicourse/_dashboard.scss
+42
-2
lms/templates/dashboard/_dashboard_certificate_information.html
+5
-5
No files found.
common/djangoapps/student/migrations/0044_rename_linkedin_config_field.py
0 → 100644
View file @
62b91d6f
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Deleting field 'LinkedInAddToProfileConfiguration.dashboard_tracking_code'
db
.
delete_column
(
'student_linkedinaddtoprofileconfiguration'
,
'dashboard_tracking_code'
)
# Adding field 'LinkedInAddToProfileConfiguration.company_identifier'
db
.
add_column
(
'student_linkedinaddtoprofileconfiguration'
,
'company_identifier'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
default
=
''
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Adding field 'LinkedInAddToProfileConfiguration.dashboard_tracking_code'
db
.
add_column
(
'student_linkedinaddtoprofileconfiguration'
,
'dashboard_tracking_code'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
default
=
''
,
blank
=
True
),
keep_default
=
False
)
# Deleting field 'LinkedInAddToProfileConfiguration.company_identifier'
db
.
delete_column
(
'student_linkedinaddtoprofileconfiguration'
,
'company_identifier'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
'student.anonymoususerid'
:
{
'Meta'
:
{
'object_name'
:
'AnonymousUserId'
},
'anonymous_user_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'32'
}),
'course_id'
:
(
'xmodule_django.models.CourseKeyField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.courseaccessrole'
:
{
'Meta'
:
{
'unique_together'
:
"(('user', 'org', 'course_id', 'role'),)"
,
'object_name'
:
'CourseAccessRole'
},
'course_id'
:
(
'xmodule_django.models.CourseKeyField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'org'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'64'
,
'blank'
:
'True'
}),
'role'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'db_index'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.courseenrollment'
:
{
'Meta'
:
{
'ordering'
:
"('user', 'course_id')"
,
'unique_together'
:
"(('user', 'course_id'),)"
,
'object_name'
:
'CourseEnrollment'
},
'course_id'
:
(
'xmodule_django.models.CourseKeyField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'mode'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'honor'"
,
'max_length'
:
'100'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.courseenrollmentallowed'
:
{
'Meta'
:
{
'unique_together'
:
"(('email', 'course_id'),)"
,
'object_name'
:
'CourseEnrollmentAllowed'
},
'auto_enroll'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'course_id'
:
(
'xmodule_django.models.CourseKeyField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'email'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
})
},
'student.dashboardconfiguration'
:
{
'Meta'
:
{
'object_name'
:
'DashboardConfiguration'
},
'change_date'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'changed_by'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'on_delete'
:
'models.PROTECT'
}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'recent_enrollment_time_delta'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'default'
:
'0'
})
},
'student.linkedinaddtoprofileconfiguration'
:
{
'Meta'
:
{
'object_name'
:
'LinkedInAddToProfileConfiguration'
},
'change_date'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'changed_by'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'on_delete'
:
'models.PROTECT'
}),
'company_identifier'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
})
},
'student.loginfailures'
:
{
'Meta'
:
{
'object_name'
:
'LoginFailures'
},
'failure_count'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'lockout_until'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.passwordhistory'
:
{
'Meta'
:
{
'object_name'
:
'PasswordHistory'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'time_set'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.pendingemailchange'
:
{
'Meta'
:
{
'object_name'
:
'PendingEmailChange'
},
'activation_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'new_email'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.pendingnamechange'
:
{
'Meta'
:
{
'object_name'
:
'PendingNameChange'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'new_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'rationale'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'1024'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.registration'
:
{
'Meta'
:
{
'object_name'
:
'Registration'
,
'db_table'
:
"'auth_registration'"
},
'activation_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'unique'
:
'True'
})
},
'student.userprofile'
:
{
'Meta'
:
{
'object_name'
:
'UserProfile'
,
'db_table'
:
"'auth_userprofile'"
},
'allow_certificate'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'city'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'country'
:
(
'django_countries.fields.CountryField'
,
[],
{
'max_length'
:
'2'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'courseware'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'course.xml'"
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'gender'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'6'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'goals'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'language'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'level_of_education'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'6'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'location'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'mailing_address'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'meta'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'db_index'
:
'True'
,
'max_length'
:
'255'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'related_name'
:
"'profile'"
,
'unique'
:
'True'
,
'to'
:
"orm['auth.User']"
}),
'year_of_birth'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'db_index'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
'student.usersignupsource'
:
{
'Meta'
:
{
'object_name'
:
'UserSignupSource'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'site'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'student.userstanding'
:
{
'Meta'
:
{
'object_name'
:
'UserStanding'
},
'account_status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'31'
,
'blank'
:
'True'
}),
'changed_by'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'standing_last_changed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"'standing'"
,
'unique'
:
'True'
,
'to'
:
"orm['auth.User']"
})
},
'student.usertestgroup'
:
{
'Meta'
:
{
'object_name'
:
'UserTestGroup'
},
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'users'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.User']"
,
'db_index'
:
'True'
,
'symmetrical'
:
'False'
})
}
}
complete_apps
=
[
'student'
]
\ No newline at end of file
common/djangoapps/student/models.py
View file @
62b91d6f
...
...
@@ -16,13 +16,13 @@ import json
import
logging
from
pytz
import
UTC
import
uuid
from
collections
import
defaultdict
from
collections
import
defaultdict
,
OrderedDict
import
dogstats_wrapper
as
dog_stats_api
from
django.db.models
import
Q
import
pytz
from
urllib
import
urlencode
from
django.utils.translation
import
ugettext_lazy
from
django.utils.translation
import
ugettext
as
_
,
ugettext
_lazy
from
django.conf
import
settings
from
django.utils
import
timezone
from
django.contrib.auth.models
import
User
...
...
@@ -1442,28 +1442,56 @@ class DashboardConfiguration(ConfigurationModel):
class
LinkedInAddToProfileConfiguration
(
ConfigurationModel
):
"""
LinkedIn Add to Profile Configuration
This configuration enables the "Add to Profile" LinkedIn
button on the student dashboard. The button appears when
users have a certificate available; when clicked,
users are sent to the LinkedIn site with a pre-filled
form allowing them to add the certificate to their
LinkedIn profile.
"""
# tracking code field
dashboard_tracking_code
=
models
.
TextField
(
blank
=
True
,
MODE_TO_CERT_NAME
=
{
"honor"
:
ugettext_lazy
(
u"{platform_name} Honor Code Certificate for {course_name}"
),
"verified"
:
ugettext_lazy
(
u"{platform_name} Verified Certificate for {course_name}"
),
"professional"
:
ugettext_lazy
(
u"{platform_name} Professional Certificate for {course_name}"
),
}
company_identifier
=
models
.
TextField
(
help_text
=
ugettext_lazy
(
u"
A dashboard tracking code field for LinkedIn Add-to-profile Certificates.
"
u"
The company identifier for the LinkedIn Add-to-Profile button
"
u"e.g 0_0dPSPyS070e0HsE9HNz_13_d11_"
)
)
@classmethod
def
linked_in_dashboard_tracking_code_url
(
cls
,
params
):
"""
Get the linked-in Configuration.
"""
config
=
cls
.
current
()
if
config
.
enabled
:
return
u'http://www.linkedin.com/profile/add?_ed={tracking_code}&{params}'
.
format
(
tracking_code
=
config
.
dashboard_tracking_code
,
params
=
urlencode
(
params
)
)
return
None
def
add_to_profile_url
(
self
,
course_name
,
enrollment_mode
,
cert_url
,
source
=
"o"
):
"""Construct the URL for the "add to profile" button.
def
__unicode__
(
self
):
return
self
.
dashboard_tracking_code
Arguments:
course_name (unicode): The display name of the course.
enrollment_mode (str): The enrollment mode of the user (e.g. "verified", "honor", "professional")
cert_url (str): The download URL for the certificate.
Keyword Arguments:
source (str): Either "o" (for onsite/UI), "e" (for emails), or "m" (for mobile)
"""
params
=
OrderedDict
([
(
'_ed'
,
self
.
company_identifier
),
(
'pfCertificationName'
,
self
.
_cert_name
(
course_name
,
enrollment_mode
)
.
encode
(
'utf-8'
)),
(
'pfCertificationUrl'
,
cert_url
),
(
'source'
,
source
)
])
return
u'http://www.linkedin.com/profile/add?{params}'
.
format
(
params
=
urlencode
(
params
)
)
def
_cert_name
(
self
,
course_name
,
enrollment_mode
):
"""Name of the certification, for display on LinkedIn. """
return
self
.
MODE_TO_CERT_NAME
.
get
(
enrollment_mode
,
_
(
u"{platform_name} Certificate for {course_name}"
)
)
.
format
(
platform_name
=
settings
.
PLATFORM_NAME
,
course_name
=
course_name
)
common/djangoapps/student/tests/tests.py
View file @
62b91d6f
...
...
@@ -9,6 +9,7 @@ from datetime import datetime, timedelta
import
logging
import
pytz
import
unittest
import
ddt
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
,
AnonymousUser
...
...
@@ -44,9 +45,17 @@ from config_models.models import cache
log
=
logging
.
getLogger
(
__name__
)
@ddt.ddt
class
CourseEndingTest
(
TestCase
):
"""Test things related to course endings: certificates, surveys, etc"""
def
setUp
(
self
):
super
(
CourseEndingTest
,
self
)
.
setUp
()
# Clear the model-based config cache to avoid
# interference between tests.
cache
.
clear
()
def
test_process_survey_link
(
self
):
username
=
"fred"
user
=
Mock
(
username
=
username
)
...
...
@@ -194,8 +203,11 @@ class CourseEndingTest(TestCase):
user
=
Mock
(
username
=
"fred"
)
survey_url
=
"http://a_survey.com"
course
=
Mock
(
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
)
course
.
display_name
=
u'edx/abc/courseregisters®'
course
=
Mock
(
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
,
display_name
=
u'edx/abc/courseregisters®'
)
download_url
=
'http://s3.edx/cert'
cert_status
=
{
...
...
@@ -204,25 +216,28 @@ class CourseEndingTest(TestCase):
'mode'
:
'honor'
}
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
self
.
assertIn
(
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
status_dict
[
'linked_in_url'
]
expected_url
=
(
'http://www.linkedin.com/profile/add'
'?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'pfCertificationName=edX+Honor+Code+Certificate+for+edx
%2
Fabc
%2
Fcourseregisters
%
C2
%
AE&'
'pfCertificationUrl=http
%3
A
%2
F
%2
Fs3.edx
%2
Fcert&'
'source=o'
)
self
.
assertIn
(
'pfCertificationName'
,
status_dict
[
'linked_in_url'
])
self
.
assertIn
(
'pfCertificationUrl'
,
status_dict
[
'linked_in_url'
])
self
.
assertIn
(
'courseregisters'
,
status_dict
[
'linked_in_url'
])
self
.
assertIn
(
'Honor+Code+Certificate'
,
status_dict
[
'linked_in_url'
])
self
.
assertEqual
(
expected_url
,
status_dict
[
'linked_in_url'
])
def
test_linked_in_url_not_exists_without_config
(
self
):
# Test case with Linked-In URL empty with if linked-in-config is none.
cache
.
clear
()
user
=
Mock
(
username
=
"fred"
)
survey_url
=
"http://a_survey.com"
course
=
Mock
(
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
)
course
=
Mock
(
display_name
=
"Demo Course"
,
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
)
download_url
=
'http://s3.edx/cert'
cert_status
=
{
...
...
@@ -246,16 +261,54 @@ class CourseEndingTest(TestCase):
}
)
# adding config. linked-in-url will be return
# Enabling the configuration will cause the LinkedIn
# "add to profile" button to appear.
# We need to clear the cache again to make sure we
# pick up the modified configuration.
cache
.
clear
()
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
self
.
assertIn
(
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
status_dict
[
'linked_in_url'
]
expected_url
=
(
'http://www.linkedin.com/profile/add'
'?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'pfCertificationName=edX+Verified+Certificate+for+Demo+Course&'
'pfCertificationUrl=http
%3
A
%2
F
%2
Fs3.edx
%2
Fcert&'
'source=o'
)
self
.
assertEqual
(
expected_url
,
status_dict
[
'linked_in_url'
])
@ddt.data
(
(
'honor'
,
'edX Honor Code Certificate for DemoX'
),
(
'verified'
,
'edX Verified Certificate for DemoX'
),
(
'professional'
,
'edX Professional Certificate for DemoX'
),
(
'default_mode'
,
'edX Certificate for DemoX'
)
)
@ddt.unpack
def
test_linked_in_url_certificate_types
(
self
,
cert_mode
,
cert_name
):
user
=
Mock
(
username
=
"fred"
)
course
=
Mock
(
display_name
=
'DemoX'
,
end_of_course_survey_url
=
'http://example.com'
,
certificates_display_behavior
=
'end'
)
cert_status
=
{
'status'
:
'downloadable'
,
'grade'
:
'67'
,
'download_url'
:
'http://edx.org'
,
'mode'
:
cert_mode
}
LinkedInAddToProfileConfiguration
(
company_identifier
=
"abcd123"
,
enabled
=
True
)
.
save
()
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
cert_mode
)
self
.
assertIn
(
cert_name
.
replace
(
' '
,
'+'
),
status_dict
[
'linked_in_url'
])
class
DashboardTest
(
ModuleStoreTestCase
):
...
...
@@ -511,8 +564,10 @@ class DashboardTest(ModuleStoreTestCase):
"""
self
.
client
.
login
(
username
=
"jack"
,
password
=
"test"
)
tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
tracking_code
,
enabled
=
True
)
.
save
()
LinkedInAddToProfileConfiguration
(
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
CourseModeFactory
.
create
(
course_id
=
self
.
course
.
id
,
...
...
@@ -542,14 +597,14 @@ class DashboardTest(ModuleStoreTestCase):
self
.
assertEquals
(
response
.
status_code
,
200
)
self
.
assertIn
(
'Add Certificate to LinkedIn'
,
response
.
content
)
response
_url
=
(
'http://www.linkedin.com/profile/add
?_ed=
'
'
{tracking_code}&pfCertificationUrl={download}&pfCertificationName=
'
'
Honor+Code+Certificate+for+{name}
'
)
.
format
(
tracking_code
=
tracking_code
,
download
=
download_url
,
name
=
'Omega
'
expected
_url
=
(
'http://www.linkedin.com/profile/add'
'
?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&
'
'
pfCertificationName=edX+Honor+Code+Certificate+for+Omega&
'
'pfCertificationUrl=www.edx.org&'
'source=o
'
)
self
.
assertContains
(
response
,
response
_url
)
self
.
assertContains
(
response
,
expected
_url
)
class
EnrollInCourseTest
(
TestCase
):
...
...
common/djangoapps/student/views.py
View file @
62b91d6f
...
...
@@ -354,30 +354,16 @@ def _cert_info(user, course, cert_status, course_mode):
else
:
status_dict
[
'download_url'
]
=
cert_status
[
'download_url'
]
# getting linkedin URL and then pass the params which appears
# on user profile. if linkedin config is empty don't show the button.
modes_dict
=
{
"honor"
:
"Honor Code Certificate"
,
"verified"
:
"Verified Certificate"
,
"professional"
:
"Professional Certificate"
,
}
certification_name
=
u'{type} for {course_name}'
.
format
(
type
=
modes_dict
.
get
(
course_mode
,
"Certificate"
),
course_name
=
course
.
display_name
)
.
encode
(
'utf-8'
)
params_dict
=
{
'pfCertificationName'
:
certification_name
,
'pfCertificationUrl'
:
cert_status
[
'download_url'
],
}
# following method will construct and return url if current enabled config exists otherwise return None
# In case of None linked-in-button will not appear on dashboard.
status_dict
[
'linked_in_url'
]
=
LinkedInAddToProfileConfiguration
.
linked_in_dashboard_tracking_code_url
(
params_dict
)
# If enabled, show the LinkedIn "add to profile" button
# Clicking this button sends the user to LinkedIn where they
# can add the certificate information to their profile.
linkedin_config
=
LinkedInAddToProfileConfiguration
.
current
()
if
linkedin_config
.
enabled
:
status_dict
[
'linked_in_url'
]
=
linkedin_config
.
add_to_profile_url
(
course
.
display_name
,
cert_status
.
get
(
'mode'
),
cert_status
[
'download_url'
]
)
if
status
in
(
'generating'
,
'ready'
,
'notpassing'
,
'restricted'
):
if
'grade'
not
in
cert_status
:
...
...
lms/static/sass/multicourse/_dashboard.scss
View file @
62b91d6f
...
...
@@ -901,11 +901,51 @@
}
&
.course-status-certavailable
{
background-color
:
$gray-l5
;
border
:
0
;
.action-certificate
{
.message-copy
{
width
:
flex-grid
(
6
,
12
);
position
:
relative
;
float
:
left
;
}
.btn
{
.actions
{
width
:
flex-grid
(
6
,
12
);
position
:
relative
;
@include
float
(
right
);
.action
{
@include
margin
(
0
,
0
,
(
$baseline
/
2
)
,
(
$baseline
*.
75
));
float
:
none
;
text-align
:
center
;
&
:last-child
{
margin-bottom
:
0
;
}
.btn
{
float
:
none
;
}
}
.action-certificate
.btn
{
@extend
%btn-inherited-primary
;
@include
box-sizing
(
border-box
);
float
:
none
;
border-radius
:
3px
;
display
:
block
;
@include
padding
(
7px
,
(
$baseline
*.
75
)
,
7px
,
(
$baseline
*.
75
));
text-align
:
center
;
a
:link
,
a
:visited
{
color
:
#fff
;
}
}
.action-share
.btn
{
display
:
inline
;
letter-spacing
:
0
;
}
}
}
...
...
lms/templates/dashboard/_dashboard_certificate_information.html
View file @
62b91d6f
...
...
@@ -6,7 +6,7 @@
cert_name_short =
course.cert_name_short
if
cert_name_short =
=
""
:
cert_name_short =
settings.CERT_NAME_SHORT
cert_name_long =
course.cert_name_long
if
cert_name_long =
=
""
:
cert_name_long =
settings.CERT_NAME_LONG
...
...
@@ -53,13 +53,13 @@ else:
<li
class=
"action action-certificate"
>
<a
class=
"btn"
href=
"${cert_status['download_url']}"
title=
"${_('This link will open/download a PDF document')}"
>
${_("Download
Your
{cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}
</a></li>
${_("Download {cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}
</a></li>
% if cert_status['linked_in_url']:
<li
class=
"action action-
certificat
e"
>
<li
class=
"action action-
shar
e"
>
<a
class=
"btn"
target=
"_blank"
href=
"${cert_status['linked_in_url']}"
title=
"${_('Add to LinkedIn Profile')}"
>
${_("
Add Certificate to LinkedIn.
")}
</a></li>
title=
"${_('Add
Certificate
to LinkedIn Profile')}"
>
${_("
Share on LinkedIn
")}
</a></li>
% endif
% elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
...
...
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