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
...
@@ -16,13 +16,13 @@ import json
import
logging
import
logging
from
pytz
import
UTC
from
pytz
import
UTC
import
uuid
import
uuid
from
collections
import
defaultdict
from
collections
import
defaultdict
,
OrderedDict
import
dogstats_wrapper
as
dog_stats_api
import
dogstats_wrapper
as
dog_stats_api
from
django.db.models
import
Q
from
django.db.models
import
Q
import
pytz
import
pytz
from
urllib
import
urlencode
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.conf
import
settings
from
django.utils
import
timezone
from
django.utils
import
timezone
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
...
@@ -1442,28 +1442,56 @@ class DashboardConfiguration(ConfigurationModel):
...
@@ -1442,28 +1442,56 @@ class DashboardConfiguration(ConfigurationModel):
class
LinkedInAddToProfileConfiguration
(
ConfigurationModel
):
class
LinkedInAddToProfileConfiguration
(
ConfigurationModel
):
"""
"""
LinkedIn Add to Profile Configuration
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
(
MODE_TO_CERT_NAME
=
{
blank
=
True
,
"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
(
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_"
u"e.g 0_0dPSPyS070e0HsE9HNz_13_d11_"
)
)
)
)
@classmethod
def
add_to_profile_url
(
self
,
course_name
,
enrollment_mode
,
cert_url
,
source
=
"o"
):
def
linked_in_dashboard_tracking_code_url
(
cls
,
params
):
"""Construct the URL for the "add to profile" button.
"""
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
__unicode__
(
self
):
Arguments:
return
self
.
dashboard_tracking_code
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
...
@@ -9,6 +9,7 @@ from datetime import datetime, timedelta
import
logging
import
logging
import
pytz
import
pytz
import
unittest
import
unittest
import
ddt
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
,
AnonymousUser
from
django.contrib.auth.models
import
User
,
AnonymousUser
...
@@ -44,9 +45,17 @@ from config_models.models import cache
...
@@ -44,9 +45,17 @@ from config_models.models import cache
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
@ddt.ddt
class
CourseEndingTest
(
TestCase
):
class
CourseEndingTest
(
TestCase
):
"""Test things related to course endings: certificates, surveys, etc"""
"""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
):
def
test_process_survey_link
(
self
):
username
=
"fred"
username
=
"fred"
user
=
Mock
(
username
=
username
)
user
=
Mock
(
username
=
username
)
...
@@ -194,8 +203,11 @@ class CourseEndingTest(TestCase):
...
@@ -194,8 +203,11 @@ class CourseEndingTest(TestCase):
user
=
Mock
(
username
=
"fred"
)
user
=
Mock
(
username
=
"fred"
)
survey_url
=
"http://a_survey.com"
survey_url
=
"http://a_survey.com"
course
=
Mock
(
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
)
course
=
Mock
(
course
.
display_name
=
u'edx/abc/courseregisters®'
end_of_course_survey_url
=
survey_url
,
certificates_display_behavior
=
'end'
,
display_name
=
u'edx/abc/courseregisters®'
)
download_url
=
'http://s3.edx/cert'
download_url
=
'http://s3.edx/cert'
cert_status
=
{
cert_status
=
{
...
@@ -204,25 +216,28 @@ class CourseEndingTest(TestCase):
...
@@ -204,25 +216,28 @@ class CourseEndingTest(TestCase):
'mode'
:
'honor'
'mode'
:
'honor'
}
}
LinkedInAddToProfileConfiguration
(
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
enabled
=
True
)
.
save
()
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
self
.
assertIn
(
expected_url
=
(
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
'http://www.linkedin.com/profile/add'
status_dict
[
'linked_in_url'
]
'?_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
.
assertEqual
(
expected_url
,
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'
])
def
test_linked_in_url_not_exists_without_config
(
self
):
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"
)
user
=
Mock
(
username
=
"fred"
)
survey_url
=
"http://a_survey.com"
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'
download_url
=
'http://s3.edx/cert'
cert_status
=
{
cert_status
=
{
...
@@ -246,16 +261,54 @@ class CourseEndingTest(TestCase):
...
@@ -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
(
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
enabled
=
True
)
.
save
()
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
status_dict
=
_cert_info
(
user
,
course
,
cert_status
,
'honor'
)
self
.
assertIn
(
expected_url
=
(
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
'http://www.linkedin.com/profile/add'
status_dict
[
'linked_in_url'
]
'?_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
):
class
DashboardTest
(
ModuleStoreTestCase
):
...
@@ -511,8 +564,10 @@ class DashboardTest(ModuleStoreTestCase):
...
@@ -511,8 +564,10 @@ class DashboardTest(ModuleStoreTestCase):
"""
"""
self
.
client
.
login
(
username
=
"jack"
,
password
=
"test"
)
self
.
client
.
login
(
username
=
"jack"
,
password
=
"test"
)
tracking_code
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
LinkedInAddToProfileConfiguration
(
LinkedInAddToProfileConfiguration
(
dashboard_tracking_code
=
tracking_code
,
enabled
=
True
)
.
save
()
company_identifier
=
'0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9'
,
enabled
=
True
)
.
save
()
CourseModeFactory
.
create
(
CourseModeFactory
.
create
(
course_id
=
self
.
course
.
id
,
course_id
=
self
.
course
.
id
,
...
@@ -542,14 +597,14 @@ class DashboardTest(ModuleStoreTestCase):
...
@@ -542,14 +597,14 @@ class DashboardTest(ModuleStoreTestCase):
self
.
assertEquals
(
response
.
status_code
,
200
)
self
.
assertEquals
(
response
.
status_code
,
200
)
self
.
assertIn
(
'Add Certificate to LinkedIn'
,
response
.
content
)
self
.
assertIn
(
'Add Certificate to LinkedIn'
,
response
.
content
)
response
_url
=
(
expected
_url
=
(
'http://www.linkedin.com/profile/add
?_ed=
'
'http://www.linkedin.com/profile/add'
'
{tracking_code}&pfCertificationUrl={download}&pfCertificationName=
'
'
?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&
'
'
Honor+Code+Certificate+for+{name}
'
'
pfCertificationName=edX+Honor+Code+Certificate+for+Omega&
'
)
.
format
(
'pfCertificationUrl=www.edx.org&'
tracking_code
=
tracking_code
,
download
=
download_url
,
name
=
'Omega
'
'source=o
'
)
)
self
.
assertContains
(
response
,
response
_url
)
self
.
assertContains
(
response
,
expected
_url
)
class
EnrollInCourseTest
(
TestCase
):
class
EnrollInCourseTest
(
TestCase
):
...
...
common/djangoapps/student/views.py
View file @
62b91d6f
...
@@ -354,30 +354,16 @@ def _cert_info(user, course, cert_status, course_mode):
...
@@ -354,30 +354,16 @@ def _cert_info(user, course, cert_status, course_mode):
else
:
else
:
status_dict
[
'download_url'
]
=
cert_status
[
'download_url'
]
status_dict
[
'download_url'
]
=
cert_status
[
'download_url'
]
# getting linkedin URL and then pass the params which appears
# If enabled, show the LinkedIn "add to profile" button
# on user profile. if linkedin config is empty don't show the button.
# Clicking this button sends the user to LinkedIn where they
# can add the certificate information to their profile.
modes_dict
=
{
linkedin_config
=
LinkedInAddToProfileConfiguration
.
current
()
"honor"
:
"Honor Code Certificate"
,
if
linkedin_config
.
enabled
:
"verified"
:
"Verified Certificate"
,
status_dict
[
'linked_in_url'
]
=
linkedin_config
.
add_to_profile_url
(
"professional"
:
"Professional Certificate"
,
course
.
display_name
,
}
cert_status
.
get
(
'mode'
),
cert_status
[
'download_url'
]
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
status
in
(
'generating'
,
'ready'
,
'notpassing'
,
'restricted'
):
if
status
in
(
'generating'
,
'ready'
,
'notpassing'
,
'restricted'
):
if
'grade'
not
in
cert_status
:
if
'grade'
not
in
cert_status
:
...
...
lms/static/sass/multicourse/_dashboard.scss
View file @
62b91d6f
...
@@ -901,11 +901,51 @@
...
@@ -901,11 +901,51 @@
}
}
&
.course-status-certavailable
{
&
.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
;
@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 @@
...
@@ -6,7 +6,7 @@
cert_name_short =
course.cert_name_short
cert_name_short =
course.cert_name_short
if
cert_name_short =
=
""
:
if
cert_name_short =
=
""
:
cert_name_short =
settings.CERT_NAME_SHORT
cert_name_short =
settings.CERT_NAME_SHORT
cert_name_long =
course.cert_name_long
cert_name_long =
course.cert_name_long
if
cert_name_long =
=
""
:
if
cert_name_long =
=
""
:
cert_name_long =
settings.CERT_NAME_LONG
cert_name_long =
settings.CERT_NAME_LONG
...
@@ -53,13 +53,13 @@ else:
...
@@ -53,13 +53,13 @@ else:
<li
class=
"action action-certificate"
>
<li
class=
"action action-certificate"
>
<a
class=
"btn"
href=
"${cert_status['download_url']}"
<a
class=
"btn"
href=
"${cert_status['download_url']}"
title=
"${_('This link will open/download a PDF document')}"
>
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']:
% 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']}"
<a
class=
"btn"
target=
"_blank"
href=
"${cert_status['linked_in_url']}"
title=
"${_('Add to LinkedIn Profile')}"
>
title=
"${_('Add
Certificate
to LinkedIn Profile')}"
>
${_("
Add Certificate to LinkedIn.
")}
</a></li>
${_("
Share on LinkedIn
")}
</a></li>
% endif
% endif
% elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
% 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