Commit b78bb976 by Nimisha Asthagiri

Merge pull request #5531 from edx/release

Merge Release
parents 37625e8e 4b122f31
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -394,7 +394,7 @@ CREATE TABLE `auth_permission` (
UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
KEY `auth_permission_e4470c6e` (`content_type_id`),
CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=370 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=391 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `auth_registration`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
......@@ -515,6 +515,8 @@ CREATE TABLE `bulk_email_courseemail` (
`course_id` varchar(255) NOT NULL,
`to_option` varchar(64) NOT NULL,
`text_message` longtext,
`template_name` varchar(255),
`from_addr` varchar(255),
PRIMARY KEY (`id`),
KEY `bulk_email_courseemail_901f59e9` (`sender_id`),
KEY `bulk_email_courseemail_36af87d1` (`slug`),
......@@ -529,8 +531,10 @@ CREATE TABLE `bulk_email_courseemailtemplate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`html_template` longtext,
`plain_template` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
`name` varchar(255),
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `bulk_email_optout`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
......@@ -946,7 +950,7 @@ CREATE TABLE `django_content_type` (
`model` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `app_label` (`app_label`,`model`)
) ENGINE=InnoDB AUTO_INCREMENT=123 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=130 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `django_openid_auth_association`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
......@@ -1108,6 +1112,82 @@ CREATE TABLE `djcelery_workerstate` (
KEY `djcelery_workerstate_eb8ac7e4` (`last_heartbeat`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `edxval_coursevideo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `edxval_coursevideo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`course_id` varchar(255) NOT NULL,
`video_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `edxval_coursevideo_course_id_42cecee05cff2d8c_uniq` (`course_id`,`video_id`),
KEY `edxval_coursevideo_fa26288c` (`video_id`),
CONSTRAINT `video_id_refs_id_586418447520c050` FOREIGN KEY (`video_id`) REFERENCES `edxval_video` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `edxval_encodedvideo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `edxval_encodedvideo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`url` varchar(200) NOT NULL,
`file_size` int(10) unsigned NOT NULL,
`bitrate` int(10) unsigned NOT NULL,
`profile_id` int(11) NOT NULL,
`video_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `edxval_encodedvideo_141c6eec` (`profile_id`),
KEY `edxval_encodedvideo_fa26288c` (`video_id`),
CONSTRAINT `video_id_refs_id_7813fe29176ce1a0` FOREIGN KEY (`video_id`) REFERENCES `edxval_video` (`id`),
CONSTRAINT `profile_id_refs_id_3fd6b88b0692d754` FOREIGN KEY (`profile_id`) REFERENCES `edxval_profile` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `edxval_profile`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `edxval_profile` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_name` varchar(50) NOT NULL,
`extension` varchar(10) NOT NULL,
`width` int(10) unsigned NOT NULL,
`height` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `profile_name` (`profile_name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `edxval_subtitle`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `edxval_subtitle` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`video_id` int(11) NOT NULL,
`fmt` varchar(20) NOT NULL,
`language` varchar(8) NOT NULL,
`content` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `edxval_subtitle_fa26288c` (`video_id`),
KEY `edxval_subtitle_306df28f` (`fmt`),
KEY `edxval_subtitle_8a7ac9ab` (`language`),
CONSTRAINT `video_id_refs_id_73eaa5f6788bc3d3` FOREIGN KEY (`video_id`) REFERENCES `edxval_video` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `edxval_video`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `edxval_video` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`edx_video_id` varchar(50) NOT NULL,
`client_video_id` varchar(255) NOT NULL,
`duration` double NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `edx_video_id` (`edx_video_id`),
KEY `edxval_video_de3f5709` (`client_video_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `embargo_embargoedcourse`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
......@@ -1370,6 +1450,89 @@ CREATE TABLE `notify_subscription` (
CONSTRAINT `settings_id_refs_id_2b8d6d653b7225d5` FOREIGN KEY (`settings_id`) REFERENCES `notify_settings` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `oauth2_accesstoken`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `oauth2_accesstoken` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`token` varchar(255) NOT NULL,
`client_id` int(11) NOT NULL,
`expires` datetime NOT NULL,
`scope` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `oauth2_accesstoken_fbfc09f1` (`user_id`),
KEY `oauth2_accesstoken_4a4e8ffb` (`client_id`),
KEY `oauth2_accesstoken_bfac9f99` (`token`),
CONSTRAINT `client_id_refs_id_12f62e33e566ebcc` FOREIGN KEY (`client_id`) REFERENCES `oauth2_client` (`id`),
CONSTRAINT `user_id_refs_id_55b335adc740ddb9` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `oauth2_client`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `oauth2_client` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11),
`url` varchar(200) NOT NULL,
`redirect_uri` varchar(200) NOT NULL,
`client_id` varchar(255) NOT NULL,
`client_secret` varchar(255) NOT NULL,
`client_type` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `oauth2_client_fbfc09f1` (`user_id`),
CONSTRAINT `user_id_refs_id_61238461c2e3e9a0` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `oauth2_grant`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `oauth2_grant` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`client_id` int(11) NOT NULL,
`code` varchar(255) NOT NULL,
`expires` datetime NOT NULL,
`redirect_uri` varchar(255) NOT NULL,
`scope` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `oauth2_grant_fbfc09f1` (`user_id`),
KEY `oauth2_grant_4a4e8ffb` (`client_id`),
CONSTRAINT `client_id_refs_id_728e499fb2f66ded` FOREIGN KEY (`client_id`) REFERENCES `oauth2_client` (`id`),
CONSTRAINT `user_id_refs_id_75389f4e37f50fe6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `oauth2_provider_trustedclient`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `oauth2_provider_trustedclient` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`client_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `oauth2_provider_trustedclient_4a4e8ffb` (`client_id`),
CONSTRAINT `client_id_refs_id_12df66c5f6dfcacc` FOREIGN KEY (`client_id`) REFERENCES `oauth2_client` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `oauth2_refreshtoken`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `oauth2_refreshtoken` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`token` varchar(255) NOT NULL,
`access_token_id` int(11) NOT NULL,
`client_id` int(11) NOT NULL,
`expired` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `access_token_id` (`access_token_id`),
KEY `oauth2_refreshtoken_fbfc09f1` (`user_id`),
KEY `oauth2_refreshtoken_4a4e8ffb` (`client_id`),
CONSTRAINT `client_id_refs_id_40eff42b798730c8` FOREIGN KEY (`client_id`) REFERENCES `oauth2_client` (`id`),
CONSTRAINT `access_token_id_refs_id_18e29982df7961b9` FOREIGN KEY (`access_token_id`) REFERENCES `oauth2_accesstoken` (`id`),
CONSTRAINT `user_id_refs_id_7d0e6f3678216905` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `psychometrics_psychometricdata`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
......@@ -1456,12 +1619,15 @@ CREATE TABLE `shoppingcart_courseregistrationcode` (
`created_by_id` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`invoice_id` int(11),
`order_id` int(11),
PRIMARY KEY (`id`),
UNIQUE KEY `shoppingcart_courseregistrationcode_code_6614bad3cae62199_uniq` (`code`),
KEY `shoppingcart_courseregistrationcode_65da3d2c` (`code`),
KEY `shoppingcart_courseregistrationcode_ff48d8e5` (`course_id`),
KEY `shoppingcart_courseregistrationcode_b5de30be` (`created_by_id`),
KEY `shoppingcart_courseregistrationcode_59f72b12` (`invoice_id`),
KEY `shoppingcart_courseregistrationcode_8337030b` (`order_id`),
CONSTRAINT `order_id_refs_id_6378d414be36d837` FOREIGN KEY (`order_id`) REFERENCES `shoppingcart_order` (`id`),
CONSTRAINT `created_by_id_refs_id_7eaaed0838397037` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`),
CONSTRAINT `invoice_id_refs_id_6e8c54da995f0ae8` FOREIGN KEY (`invoice_id`) REFERENCES `shoppingcart_invoice` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
......@@ -1575,7 +1741,7 @@ DROP TABLE IF EXISTS `shoppingcart_registrationcoderedemption`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `shoppingcart_registrationcoderedemption` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`order_id` int(11),
`registration_code_id` int(11) NOT NULL,
`redeemed_by_id` int(11) NOT NULL,
`redeemed_at` datetime DEFAULT NULL,
......@@ -1583,8 +1749,8 @@ CREATE TABLE `shoppingcart_registrationcoderedemption` (
KEY `shoppingcart_registrationcoderedemption_8337030b` (`order_id`),
KEY `shoppingcart_registrationcoderedemption_d25b37dc` (`registration_code_id`),
KEY `shoppingcart_registrationcoderedemption_e151467a` (`redeemed_by_id`),
CONSTRAINT `redeemed_by_id_refs_id_2c29fd0d4e320dc9` FOREIGN KEY (`redeemed_by_id`) REFERENCES `auth_user` (`id`),
CONSTRAINT `order_id_refs_id_3e4c388753a8a5c9` FOREIGN KEY (`order_id`) REFERENCES `shoppingcart_order` (`id`),
CONSTRAINT `redeemed_by_id_refs_id_2c29fd0d4e320dc9` FOREIGN KEY (`redeemed_by_id`) REFERENCES `auth_user` (`id`),
CONSTRAINT `registration_code_id_refs_id_2b7812ae4d01e47b` FOREIGN KEY (`registration_code_id`) REFERENCES `shoppingcart_courseregistrationcode` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
......@@ -1650,7 +1816,7 @@ CREATE TABLE `south_migrationhistory` (
`migration` varchar(255) NOT NULL,
`applied` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=179 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=180 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `splash_splashconfig`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
......@@ -2003,88 +2169,6 @@ CREATE TABLE `verify_student_softwaresecurephotoverification` (
CONSTRAINT `window_id_refs_id_30f70c30fce8f38a` FOREIGN KEY (`window_id`) REFERENCES `reverification_midcoursereverificationwindow` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `waffle_flag`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `waffle_flag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`everyone` tinyint(1) DEFAULT NULL,
`percent` decimal(3,1) DEFAULT NULL,
`superusers` tinyint(1) NOT NULL,
`staff` tinyint(1) NOT NULL,
`authenticated` tinyint(1) NOT NULL,
`rollout` tinyint(1) NOT NULL,
`note` longtext NOT NULL,
`testing` tinyint(1) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
`languages` longtext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `waffle_flag_3216ff68` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `waffle_flag_groups`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `waffle_flag_groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`flag_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `waffle_flag_groups_flag_id_582896076571ab8b_uniq` (`flag_id`,`group_id`),
KEY `waffle_flag_groups_9bca17e2` (`flag_id`),
KEY `waffle_flag_groups_bda51c3c` (`group_id`),
CONSTRAINT `group_id_refs_id_66545bd34ea49f34` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`),
CONSTRAINT `flag_id_refs_id_6f1b152a8e6a807d` FOREIGN KEY (`flag_id`) REFERENCES `waffle_flag` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `waffle_flag_users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `waffle_flag_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`flag_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `waffle_flag_users_flag_id_3bb77386107938a3_uniq` (`flag_id`,`user_id`),
KEY `waffle_flag_users_9bca17e2` (`flag_id`),
KEY `waffle_flag_users_fbfc09f1` (`user_id`),
CONSTRAINT `user_id_refs_id_1fe1cfb8bae2dfc2` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`),
CONSTRAINT `flag_id_refs_id_5034023d8fef0c12` FOREIGN KEY (`flag_id`) REFERENCES `waffle_flag` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `waffle_sample`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `waffle_sample` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`percent` decimal(4,1) NOT NULL,
`note` longtext NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `waffle_sample_3216ff68` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `waffle_switch`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `waffle_switch` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`active` tinyint(1) NOT NULL,
`note` longtext NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `waffle_switch_3216ff68` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `wiki_article`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
......
......@@ -23,7 +23,7 @@ class CourseEmailTemplateAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
# make the HTML template display above the plain template:
'fields': ('html_template', 'plain_template'),
'fields': ('html_template', 'plain_template', 'name'),
'description': '''
Enter template to be used by course staff when sending emails to enrolled students.
......@@ -49,11 +49,11 @@ unsupported tags will cause email sending to fail.
actions = None
def has_add_permission(self, request):
"""Disables the ability to add new templates, as we want to maintain a Singleton."""
return False
"""Enable the ability to add new templates, as we want to be able to define multiple templates."""
return True
def has_delete_permission(self, request, obj=None):
"""Disables the ability to remove existing templates, as we want to maintain a Singleton."""
"""Disables the ability to remove existing templates, as we'd like to make sure we don't have dangling references."""
return False
......
......@@ -6,5 +6,14 @@
"plain_template": "{course_title}\n\n{{message_body}}\r\n----\r\nCopyright 2013 edX, All rights reserved.\r\n----\r\nConnect with edX:\r\nFacebook (http://facebook.com/edxonline)\r\nTwitter (http://twitter.com/edxonline)\r\nGoogle+ (https://plus.google.com/108235383044095082735)\r\nMeetup (http://www.meetup.com/edX-Communities/)\r\n----\r\nThis email was automatically sent from {platform_name}.\r\nYou are receiving this email at address {email} because you are enrolled in {course_title}\r\n(URL: {course_url} ).\r\nTo stop receiving email like this, update your account settings at {account_settings_url}.\r\n",
"html_template": "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html xmlns:fb='http://www.facebook.com/2008/fbml' xmlns:og='http://opengraph.org/schema/'> <head><meta property='og:title' content='Update from {course_title}'/><meta property='fb:page_id' content='43929265776' /> <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'> <title>Update from {course_title}</title> </head> <body leftmargin='0' marginwidth='0' topmargin='0' marginheight='0' offset='0' style='margin: 0;padding: 0;background-color: #ffffff;'> <center> <table align='center' border='0' cellpadding='0' cellspacing='0' height='100%' width='100%' id='bodyTable' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;margin: 0;padding: 0;background-color: #ffffff;height: 100% !important;width: 100% !important;'> <tr> <td align='center' valign='top' id='bodyCell' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;margin: 0;padding: 0;border-top: 0;height: 100% !important;width: 100% !important;'> <!-- BEGIN TEMPLATE // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN PREHEADER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templatePreheader' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='preheaderContainer' style='padding-top: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='366' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-left: 18px;padding-bottom: 9px;padding-right: 0;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 11px;line-height: 125%;text-align: left;'> <br> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END PREHEADER --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN HEADER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateHeader' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='headerContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnImageBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnImageBlockOuter'> <tr> <td valign='top' style='padding: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;' class='mcnImageBlockInner'> <table align='left' width='100%' border='0' cellpadding='0' cellspacing='0' class='mcnImageContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td class='mcnImageContent' valign='top' style='padding-right: 9px;padding-left: 9px;padding-top: 0;padding-bottom: 0;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <a href='http://edx.org' title='' class='' target='_self' style='word-wrap: break-word !important;'> <img align='left' alt='edX' src='http://courses.edx.org/static/images/bulk_email/edXHeaderImage.jpg' width='564.0000152587891' style='max-width: 600px;padding-bottom: 0;display: inline !important;vertical-align: bottom;border: 0;line-height: 100%;outline: none;text-decoration: none;height: auto !important;' class='mcnImage'> </a> </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='599' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 15px;line-height: 150%;text-align: left;'> <div style='text-align: right;'><span style='font-size:11px;'><span style='color:#00a0e3;'>Connect with edX:</span></span> &nbsp;<a href='http://facebook.com/edxonline' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/FacebookIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://twitter.com/edxonline' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/TwitterIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='https://plus.google.com/108235383044095082735' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/GooglePlusIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://www.meetup.com/edX-Communities/' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/MeetupIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a></div> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END HEADER --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN BODY // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateBody' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='bodyContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnCaptionBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnCaptionBlockOuter'> <tr> <td class='mcnCaptionBlockInner' valign='top' style='padding: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' class='mcnCaptionLeftContentOuter' width='100%' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnCaptionLeftContentInner' style='padding: 0 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='right' border='0' cellpadding='0' cellspacing='0' class='mcnCaptionLeftImageContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td class='mcnCaptionLeftImageContent' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <img alt='' src='{course_image_url}' width='176' style='max-width: 180px;border: 0;line-height: 100%;outline: none;text-decoration: none;vertical-align: bottom;height: auto !important;' class='mcnImage'> </td> </tr> </tbody></table> <table class='mcnCaptionLeftTextContentContainer' align='left' border='0' cellpadding='0' cellspacing='0' width='352' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> <h3 class='null' style='display: block;font-family: Helvetica;font-size: 18px;font-style: normal;font-weight: bold;line-height: 125%;letter-spacing: -.5px;margin: 0;text-align: left;color: #606060 !important;'><strong style='font-size: 22px;'>{course_title}</strong><br></h3><br> </td> </tr> </tbody></table> </td> </tr></tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> {{message_body}} </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnDividerBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnDividerBlockOuter'> <tr> <td class='mcnDividerBlockInner' style='padding: 18px 18px 3px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table class='mcnDividerContent' border='0' cellpadding='0' cellspacing='0' width='100%' style='border-top-width: 1px;border-top-style: solid;border-top-color: #666666;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <span></span> </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> <div style='text-align: right;'><a href='http://facebook.com/edxonline' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/FacebookIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://twitter.com/edxonline' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/TwitterIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='https://plus.google.com/108235383044095082735' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/GooglePlusIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp; &nbsp;<a href='http://www.meetup.com/edX-Communities/' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/MeetupIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a></div> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END BODY --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN FOOTER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateFooter' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #9FCFE8;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='footerContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #f2f2f2;font-family: Helvetica;font-size: 11px;line-height: 125%;text-align: left;'> <em>Copyright © 2013 edX, All rights reserved.</em><br><br><br> <b>Our mailing address is:</b><br> edX<br> 11 Cambridge Center, Suite 101<br> Cambridge, MA, USA 02142<br><br><br>This email was automatically sent from {platform_name}. <br>You are receiving this email at address {email} because you are enrolled in <a href='{course_url}'>{course_title}</a>.<br>To stop receiving email like this, update your course email settings <a href='{account_settings_url}'>here</a>. <br> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END FOOTER --> </td> </tr> </table> <!-- // END TEMPLATE --> </td> </tr> </table> </center> </body> </body> </html>"
}
},
{
"pk": 2,
"model": "bulk_email.courseemailtemplate",
"fields": {
"plain_template": "THIS IS A BRANDED TEXT TEMPLATE. {course_title}\n\n{{message_body}}\r\n----\r\nCopyright 2013 edX, All rights reserved.\r\n----\r\nConnect with edX:\r\nFacebook (http://facebook.com/edxonline)\r\nTwitter (http://twitter.com/edxonline)\r\nGoogle+ (https://plus.google.com/108235383044095082735)\r\nMeetup (http://www.meetup.com/edX-Communities/)\r\n----\r\nThis email was automatically sent from {platform_name}.\r\nYou are receiving this email at address {email} because you are enrolled in {course_title}\r\n(URL: {course_url} ).\r\nTo stop receiving email like this, update your account settings at {account_settings_url}.\r\n",
"html_template": "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html xmlns:fb='http://www.facebook.com/2008/fbml' xmlns:og='http://opengraph.org/schema/'> <head><meta property='og:title' content='Update from {course_title}'/><meta property='fb:page_id' content='43929265776' /> <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'> THIS IS A BRANDED HTML TEMPLATE <title>Update from {course_title}</title> </head> <body leftmargin='0' marginwidth='0' topmargin='0' marginheight='0' offset='0' style='margin: 0;padding: 0;background-color: #ffffff;'> <center> <table align='center' border='0' cellpadding='0' cellspacing='0' height='100%' width='100%' id='bodyTable' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;margin: 0;padding: 0;background-color: #ffffff;height: 100% !important;width: 100% !important;'> <tr> <td align='center' valign='top' id='bodyCell' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;margin: 0;padding: 0;border-top: 0;height: 100% !important;width: 100% !important;'> <!-- BEGIN TEMPLATE // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN PREHEADER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templatePreheader' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='preheaderContainer' style='padding-top: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='366' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-left: 18px;padding-bottom: 9px;padding-right: 0;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 11px;line-height: 125%;text-align: left;'> <br> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END PREHEADER --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN HEADER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateHeader' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='headerContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnImageBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnImageBlockOuter'> <tr> <td valign='top' style='padding: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;' class='mcnImageBlockInner'> <table align='left' width='100%' border='0' cellpadding='0' cellspacing='0' class='mcnImageContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td class='mcnImageContent' valign='top' style='padding-right: 9px;padding-left: 9px;padding-top: 0;padding-bottom: 0;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <a href='http://edx.org' title='' class='' target='_self' style='word-wrap: break-word !important;'> <img align='left' alt='edX' src='http://courses.edx.org/static/images/bulk_email/edXHeaderImage.jpg' width='564.0000152587891' style='max-width: 600px;padding-bottom: 0;display: inline !important;vertical-align: bottom;border: 0;line-height: 100%;outline: none;text-decoration: none;height: auto !important;' class='mcnImage'> </a> </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='599' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 15px;line-height: 150%;text-align: left;'> <div style='text-align: right;'><span style='font-size:11px;'><span style='color:#00a0e3;'>Connect with edX:</span></span> &nbsp;<a href='http://facebook.com/edxonline' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/FacebookIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://twitter.com/edxonline' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/TwitterIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='https://plus.google.com/108235383044095082735' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/GooglePlusIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://www.meetup.com/edX-Communities/' target='_blank' style='color: #6DC6DD;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/MeetupIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a></div> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END HEADER --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN BODY // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateBody' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #fcfcfc;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='bodyContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnCaptionBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnCaptionBlockOuter'> <tr> <td class='mcnCaptionBlockInner' valign='top' style='padding: 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' class='mcnCaptionLeftContentOuter' width='100%' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnCaptionLeftContentInner' style='padding: 0 9px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='right' border='0' cellpadding='0' cellspacing='0' class='mcnCaptionLeftImageContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td class='mcnCaptionLeftImageContent' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <img alt='' src='{course_image_url}' width='176' style='max-width: 180px;border: 0;line-height: 100%;outline: none;text-decoration: none;vertical-align: bottom;height: auto !important;' class='mcnImage'> </td> </tr> </tbody></table> <table class='mcnCaptionLeftTextContentContainer' align='left' border='0' cellpadding='0' cellspacing='0' width='352' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> <h3 class='null' style='display: block;font-family: Helvetica;font-size: 18px;font-style: normal;font-weight: bold;line-height: 125%;letter-spacing: -.5px;margin: 0;text-align: left;color: #606060 !important;'><strong style='font-size: 22px;'>{course_title}</strong><br></h3><br> </td> </tr> </tbody></table> </td> </tr></tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> {{message_body}} </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnDividerBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnDividerBlockOuter'> <tr> <td class='mcnDividerBlockInner' style='padding: 18px 18px 3px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table class='mcnDividerContent' border='0' cellpadding='0' cellspacing='0' width='100%' style='border-top-width: 1px;border-top-style: solid;border-top-color: #666666;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <span></span> </td> </tr> </tbody></table> </td> </tr> </tbody></table><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #606060;font-family: Helvetica;font-size: 14px;line-height: 150%;text-align: left;'> <div style='text-align: right;'><a href='http://facebook.com/edxonline' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/FacebookIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='http://twitter.com/edxonline' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/TwitterIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp;&nbsp;<a href='https://plus.google.com/108235383044095082735' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/GooglePlusIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a>&nbsp; &nbsp;<a href='http://www.meetup.com/edX-Communities/' target='_blank' style='color: #2f73bc;font-weight: normal;text-decoration: underline;word-wrap: break-word !important;'><img align='none' height='16' src='http://courses.edx.org/static/images/bulk_email/MeetupIcon.png' style='width: 16px;height: 16px;border: 0;line-height: 100%;outline: none;text-decoration: none;' width='16'></a></div> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END BODY --> </td> </tr> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <!-- BEGIN FOOTER // --> <table border='0' cellpadding='0' cellspacing='0' width='100%' id='templateFooter' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;background-color: #9FCFE8;border-top: 0;border-bottom: 0;'> <tr> <td align='center' valign='top' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table border='0' cellpadding='0' cellspacing='0' width='600' class='templateContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tr> <td valign='top' class='footerContainer' style='padding-top: 10px;padding-right: 18px;padding-bottom: 10px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'><table border='0' cellpadding='0' cellspacing='0' width='100%' class='mcnTextBlock' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody class='mcnTextBlockOuter'> <tr> <td valign='top' class='mcnTextBlockInner' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <table align='left' border='0' cellpadding='0' cellspacing='0' width='600' class='mcnTextContentContainer' style='border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;'> <tbody><tr> <td valign='top' class='mcnTextContent' style='padding-top: 9px;padding-right: 18px;padding-bottom: 9px;padding-left: 18px;border-collapse: collapse;mso-table-lspace: 0pt;mso-table-rspace: 0pt;color: #f2f2f2;font-family: Helvetica;font-size: 11px;line-height: 125%;text-align: left;'> <em>Copyright © 2013 edX, All rights reserved.</em><br><br><br> <b>Our mailing address is:</b><br> edX<br> 11 Cambridge Center, Suite 101<br> Cambridge, MA, USA 02142<br><br><br>This email was automatically sent from {platform_name}. <br>You are receiving this email at address {email} because you are enrolled in <a href='{course_url}'>{course_title}</a>.<br>To stop receiving email like this, update your course email settings <a href='{account_settings_url}'>here</a>. <br> </td> </tr> </tbody></table> </td> </tr> </tbody></table></td> </tr> </table> </td> </tr> </table> <!-- // END FOOTER --> </td> </tr> </table> <!-- // END TEMPLATE --> </td> </tr> </table> </center> </body> </body> </html>",
"name": "branded.template"
}
}
]
......@@ -20,8 +20,10 @@ log = logging.getLogger(__name__)
class CourseEmailTemplateForm(forms.ModelForm): # pylint: disable=R0924
"""Form providing validation of CourseEmail templates."""
name = forms.CharField(required=False)
class Meta: # pylint: disable=C0111
model = CourseEmailTemplate
fields = ('html_template', 'plain_template', 'name')
def _validate_template(self, template):
"""Check the template for required tags."""
......@@ -50,6 +52,21 @@ class CourseEmailTemplateForm(forms.ModelForm): # pylint: disable=R0924
self._validate_template(template)
return template
def clean_name(self):
"""Validate the name field. Enforce uniqueness constraint on 'name' field"""
name = self.cleaned_data.get("name")
# if we are creating a new CourseEmailTemplate, then we need to
# enforce the uniquess constraint as part of the Form validation
if not self.instance.pk:
try:
CourseEmailTemplate.get_template(name)
# already exists, this is no good
raise ValidationError('Name of "{}" already exists, this must be unique.'.format(name))
except CourseEmailTemplate.DoesNotExist:
# this is actually the successful validation
pass
return name
class CourseAuthorizationAdminForm(forms.ModelForm): # pylint: disable=R0924
"""Input form for email enabling, allowing us to verify data."""
......
# -*- 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):
# Changing field 'Optout.course_id'
db.alter_column('bulk_email_optout', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255))
# Adding field 'CourseEmail.template_name'
db.add_column('bulk_email_courseemail', 'template_name',
self.gf('django.db.models.fields.CharField')(max_length=255, null=True),
keep_default=False)
# Adding field 'CourseEmail.from_addr'
db.add_column('bulk_email_courseemail', 'from_addr',
self.gf('django.db.models.fields.CharField')(max_length=255, null=True),
keep_default=False)
# Changing field 'CourseEmail.course_id'
db.alter_column('bulk_email_courseemail', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255))
# Adding field 'CourseEmailTemplate.name'
db.add_column('bulk_email_courseemailtemplate', 'name',
self.gf('django.db.models.fields.CharField')(max_length=255, unique=True, null=True),
keep_default=False)
# Changing field 'CourseAuthorization.course_id'
db.alter_column('bulk_email_courseauthorization', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(unique=True, max_length=255))
def backwards(self, orm):
# Changing field 'Optout.course_id'
db.alter_column('bulk_email_optout', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=255))
# Deleting field 'CourseEmail.template_name'
db.delete_column('bulk_email_courseemail', 'template_name')
# Deleting field 'CourseEmail.from_addr'
db.delete_column('bulk_email_courseemail', 'from_addr')
# Changing field 'CourseEmail.course_id'
db.alter_column('bulk_email_courseemail', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=255))
# Deleting field 'CourseEmailTemplate.name'
db.delete_column('bulk_email_courseemailtemplate', 'name')
# Changing field 'CourseAuthorization.course_id'
db.alter_column('bulk_email_courseauthorization', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=255, unique=True))
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'})
},
'bulk_email.courseauthorization': {
'Meta': {'object_name': 'CourseAuthorization'},
'course_id': ('xmodule_django.models.CourseKeyField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
'email_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'bulk_email.courseemail': {
'Meta': {'object_name': 'CourseEmail'},
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'from_addr': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'html_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'sender': ('django.db.models.fields.related.ForeignKey', [], {'default': '1', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'template_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
'text_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'to_option': ('django.db.models.fields.CharField', [], {'default': "'myself'", 'max_length': '64'})
},
'bulk_email.courseemailtemplate': {
'Meta': {'object_name': 'CourseEmailTemplate'},
'html_template': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
'plain_template': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
},
'bulk_email.optout': {
'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'Optout'},
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
},
'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'})
}
}
complete_apps = ['bulk_email']
\ No newline at end of file
......@@ -67,12 +67,14 @@ class CourseEmail(Email):
)
course_id = CourseKeyField(max_length=255, db_index=True)
to_option = models.CharField(max_length=64, choices=TO_OPTION_CHOICES, default=SEND_TO_MYSELF)
template_name = models.CharField(null=True, max_length=255)
from_addr = models.CharField(null=True, max_length=255)
def __unicode__(self):
return self.subject
@classmethod
def create(cls, course_id, sender, to_option, subject, html_message, text_message=None):
def create(cls, course_id, sender, to_option, subject, html_message, text_message=None, template_name=None, from_addr=None):
"""
Create an instance of CourseEmail.
......@@ -101,6 +103,8 @@ class CourseEmail(Email):
subject=subject,
html_message=html_message,
text_message=text_message,
template_name=template_name,
from_addr=from_addr,
)
course_email.save_now()
......@@ -120,6 +124,11 @@ class CourseEmail(Email):
"""
self.save()
def get_template(self):
"""
Returns the corresponding CourseEmailTemplate for this CourseEmail.
"""
return CourseEmailTemplate.get_template(name=self.template_name)
class Optout(models.Model):
"""
......@@ -151,16 +160,17 @@ class CourseEmailTemplate(models.Model):
"""
html_template = models.TextField(null=True, blank=True)
plain_template = models.TextField(null=True, blank=True)
name = models.CharField(null=True, max_length=255, unique=True, blank=True)
@staticmethod
def get_template():
def get_template(name=None):
"""
Fetch the current template
If one isn't stored, an exception is thrown.
"""
try:
return CourseEmailTemplate.objects.get()
return CourseEmailTemplate.objects.get(name=name)
except CourseEmailTemplate.DoesNotExist:
log.exception("Attempting to fetch a non-existent course email template")
raise
......
......@@ -438,9 +438,13 @@ def _send_course_email(entry_id, email_id, to_list, global_email_context, subtas
course_title = global_email_context['course_title']
subject = "[" + course_title + "] " + course_email.subject
from_addr = _get_source_address(course_email.course_id, course_title)
course_email_template = CourseEmailTemplate.get_template()
# use the email from address in the CourseEmail, if it is present, otherwise compute it
from_addr = course_email.from_addr if course_email.from_addr else \
_get_source_address(course_email.course_id, course_title)
# use the CourseEmailTemplate that was associated with the CourseEmail
course_email_template = course_email.get_template()
try:
connection = get_connection()
connection.open()
......
......@@ -29,6 +29,23 @@ class CourseEmailTest(TestCase):
self.assertEquals(email.html_message, html_message)
self.assertEquals(email.sender, sender)
def test_creation_with_optional_attributes(self):
course_id = SlashSeparatedCourseKey('abc', '123', 'doremi')
sender = UserFactory.create()
to_option = SEND_TO_STAFF
subject = "dummy subject"
html_message = "<html>dummy message</html>"
template_name = "branded_template"
from_addr = "branded@branding.com"
email = CourseEmail.create(course_id, sender, to_option, subject, html_message, template_name=template_name, from_addr=from_addr)
self.assertEquals(email.course_id, course_id)
self.assertEquals(email.to_option, SEND_TO_STAFF)
self.assertEquals(email.subject, subject)
self.assertEquals(email.html_message, html_message)
self.assertEquals(email.sender, sender)
self.assertEquals(email.template_name, template_name)
self.assertEquals(email.from_addr, from_addr)
def test_bad_to_option(self):
course_id = SlashSeparatedCourseKey('abc', '123', 'doremi')
sender = UserFactory.create()
......@@ -72,10 +89,19 @@ class CourseEmailTemplateTest(TestCase):
return context
def test_get_template(self):
# Get the default template, which has name=None
template = CourseEmailTemplate.get_template()
self.assertIsNotNone(template.html_template)
self.assertIsNotNone(template.plain_template)
def test_get_branded_template(self):
# Get a branded (non default) template and make sure we get what we expect
template = CourseEmailTemplate.get_template(name="branded.template")
self.assertIsNotNone(template.html_template)
self.assertIsNotNone(template.plain_template)
self.assertIn(u"THIS IS A BRANDED HTML TEMPLATE", template.html_template)
self.assertIn(u"THIS IS A BRANDED TEXT TEMPLATE", template.plain_template)
def test_render_html_without_context(self):
template = CourseEmailTemplate.get_template()
base_context = self._get_sample_html_context()
......
......@@ -1462,10 +1462,25 @@ def send_email(request, course_id):
subject = request.POST.get("subject")
message = request.POST.get("message")
# allow two branding points to come from Microsites: which CourseEmailTemplate should be used
# and what the 'from' field in the email should be
#
# If these are None (because we are not in a Microsite or they are undefined in Microsite config) than
# the system will use normal system defaults
template_name = microsite.get_value('course_email_template_name')
from_addr = microsite.get_value('course_email_from_addr')
# Create the CourseEmail object. This is saved immediately, so that
# any transaction that has been pending up to this point will also be
# committed.
email = CourseEmail.create(course_id, request.user, send_to, subject, message)
email = CourseEmail.create(
course_id,
request.user,
send_to,
subject,message,
template_name=template_name,
from_addr=from_addr
)
# Submit the task, so that the correct InstructorTask object gets created (for monitoring purposes)
instructor_task.api.submit_bulk_course_email(request, course_id, email.id) # pylint: disable=E1101
......
......@@ -209,6 +209,15 @@ class ReportStore(object):
elif storage_type.lower() == "localfs":
return LocalFSReportStore.from_config()
def _get_utf8_encoded_rows(self, rows):
"""
Given a list of `rows` containing unicode strings, return a
new list of rows with those strings encoded as utf-8 for CSV
compatibility.
"""
for row in rows:
yield [unicode(item).encode('utf-8') for item in row]
class S3ReportStore(ReportStore):
"""
......@@ -306,7 +315,8 @@ class S3ReportStore(ReportStore):
"""
output_buffer = StringIO()
gzip_file = GzipFile(fileobj=output_buffer, mode="wb")
csv.writer(gzip_file).writerows(rows)
csvwriter = csv.writer(gzip_file)
csvwriter.writerows(self._get_utf8_encoded_rows(rows))
gzip_file.close()
self.store(course_id, filename, output_buffer)
......@@ -384,7 +394,9 @@ class LocalFSReportStore(ReportStore):
write this data out.
"""
output_buffer = StringIO()
csv.writer(output_buffer).writerows(rows)
csvwriter = csv.writer(output_buffer)
csvwriter.writerows(self._get_utf8_encoded_rows(rows))
self.store(course_id, filename, output_buffer)
def links_for(self, course_id):
......
......@@ -575,7 +575,7 @@ def push_grades_to_s3(_xmodule_instance_args, _entry_id, course_id, _task_input,
# possible for a student to have a 0.0 show up in their row but
# still have 100% for the course.
row_percents = [percents.get(label, 0.0) for label in header]
rows.append([student.id, student.email.encode('utf-8'), student.username, gradeset['percent']] + row_percents)
rows.append([student.id, student.email, student.username, gradeset['percent']] + row_percents)
else:
# An empty gradeset means we failed to grade a student.
num_failed += 1
......
......@@ -33,16 +33,16 @@ class TestReport(ModuleStoreTestCase):
if os.path.exists(settings.GRADES_DOWNLOAD['ROOT_PATH']):
shutil.rmtree(settings.GRADES_DOWNLOAD['ROOT_PATH'])
def create_student(self, username, email):
student = UserFactory.create(username=username, email=email)
CourseEnrollmentFactory.create(user=student, course_id=self.course.id)
@ddt.ddt
class TestInstructorGradeReport(TestReport):
"""
Tests that CSV grade report generation works.
"""
def create_student(self, username, email):
student = UserFactory.create(username=username, email=email)
CourseEnrollmentFactory.create(user=student, course_id=self.course.id)
@ddt.data([u'student@example.com', u'ni\xf1o@example.com'])
def test_unicode_emails(self, emails):
"""
......@@ -60,6 +60,7 @@ class TestInstructorGradeReport(TestReport):
self.assertEquals(result['succeeded'], result['attempted'])
@ddt.ddt
class TestStudentReport(TestReport):
"""
Tests that CSV student profile report generation works.
......@@ -73,3 +74,27 @@ class TestStudentReport(TestReport):
self.assertEquals(len(links), 1)
self.assertEquals(result, UPDATE_STATUS_SUCCEEDED)
@ddt.data([u'student', u'student\xec'])
def test_unicode_usernames(self, students):
"""
Test that students with unicode characters in their usernames
are handled.
"""
for i, student in enumerate(students):
self.create_student(username=student, email='student{0}@example.com'.format(i))
self.current_task = Mock()
self.current_task.update_state = Mock()
task_input = {
'features': [
'id', 'username', 'name', 'email', 'language', 'location',
'year_of_birth', 'gender', 'level_of_education', 'mailing_address',
'goals'
]
}
with patch('instructor_task.tasks_helper._get_current_task') as mock_current_task:
mock_current_task.return_value = self.current_task
result = push_students_csv_to_s3(None, None, self.course.id, task_input, 'calculated')
#This assertion simply confirms that the generation completed with no errors
self.assertEquals(result, UPDATE_STATUS_SUCCEEDED)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment