Commit 2302c324 by Vik Paruchuri

Merge branch 'feature/vik/disable-spell-check' into feature/vik/check-if-submission-allowed

parents 72d06982 c48998b3
......@@ -2,7 +2,7 @@
[run]
data_file = reports/cms/.coverage
source = cms,common/djangoapps
omit = cms/envs/*, cms/manage.py, common/djangoapps/*/migrations/*
omit = cms/envs/*, cms/manage.py, common/djangoapps/terrain/*, common/djangoapps/*/migrations/*
[report]
ignore_errors = True
......
......@@ -146,6 +146,7 @@ def add_section(name='My Section'):
span_css = 'span.section-name-span'
assert_true(world.browser.is_element_present_by_css(span_css, 5))
def add_subsection(name='Subsection One'):
css = 'a.new-subsection-item'
css_click(css)
......
......@@ -59,4 +59,4 @@ def i_am_on_tab(step, tab_name):
@step('I see a link for adding a new section$')
def i_see_new_section_link(step):
link_css = 'a.new-courseware-section-button'
assert_css_with_text(link_css, 'New Section')
assert_css_with_text(link_css, '+ New Section')
......@@ -342,7 +342,7 @@ class ContentStoreTest(ModuleStoreTestCase):
# Create a course so there is something to view
resp = self.client.get(reverse('index'))
self.assertContains(resp,
'<h1>My Courses</h1>',
'<h1 class="title-1">My Courses</h1>',
status_code=200,
html=True)
......
......@@ -131,7 +131,8 @@ def index(request):
reverse('course_index', args=[
course.location.org,
course.location.course,
course.location.name]))
course.location.name]),
get_lms_link_for_item(course.location))
for course in courses],
'user': request.user,
'disable_course_creation': settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False) and not request.user.is_staff
......@@ -172,6 +173,8 @@ def course_index(request, org, course, name):
if not has_access(request.user, location):
raise PermissionDenied()
lms_link = get_lms_link_for_item(location)
upload_asset_callback_url = reverse('upload_asset', kwargs={
'org': org,
'course': course,
......@@ -184,6 +187,7 @@ def course_index(request, org, course, name):
return render_to_response('overview.html', {
'active_tab': 'courseware',
'context_course': course,
'lms_link': lms_link,
'sections': sections,
'course_graders': json.dumps(CourseGradingModel.fetch(course.location).graders),
'parent_location': course.location,
......
class CMS.Views.TabsEdit extends Backbone.View
events:
'click .new-tab': 'addNewTab'
initialize: =>
@$('.component').each((idx, element) =>
......@@ -13,6 +11,7 @@ class CMS.Views.TabsEdit extends Backbone.View
)
)
@options.mast.find('.new-tab').on('click', @addNewTab)
@$('.components').sortable(
handle: '.drag-handle'
update: @tabMoved
......
......@@ -43,6 +43,12 @@ $(document).ready(function () {
$('body').addClass('js');
// lean/simple modal
$('a[rel*=modal]').leanModal({overlay : 0.80, closeButton: '.action-modal-close' });
$('a.action-modal-close').click(function(e){
(e).preventDefault();
});
// nav - dropdown related
$body.click(function (e) {
$('.nav-dropdown .nav-item .wrapper-nav-sub').removeClass('is-shown');
......@@ -638,7 +644,7 @@ function addNewCourse(e) {
$(e.target).hide();
var $newCourse = $($('#new-course-template').html());
var $cancelButton = $newCourse.find('.new-course-cancel');
$('.new-course-button').after($newCourse);
$('.inner-wrapper').prepend($newCourse);
$newCourse.find('.new-course-name').focus().select();
$newCourse.find('form').bind('submit', saveNewCourse);
$cancelButton.bind('click', cancelNewCourse);
......@@ -822,4 +828,4 @@ function saveSetSectionScheduleDate(e) {
hideModal();
});
}
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ CMS.Views.CourseInfoEdit = Backbone.View.extend({
render: function() {
// instantiate the ClassInfoUpdateView and delegate the proper dom to it
new CMS.Views.ClassInfoUpdateView({
el: this.$('#course-update-view'),
el: $('body.updates'),
collection: this.model.get('updates')
});
......@@ -27,10 +27,10 @@ CMS.Views.ClassInfoUpdateView = Backbone.View.extend({
// collection is CourseUpdateCollection
events: {
"click .new-update-button" : "onNew",
"click .save-button" : "onSave",
"click .cancel-button" : "onCancel",
"click .edit-button" : "onEdit",
"click .delete-button" : "onDelete"
"click #course-update-view .save-button" : "onSave",
"click #course-update-view .cancel-button" : "onCancel",
"click .post-actions > .edit-button" : "onEdit",
"click .post-actions > .delete-button" : "onDelete"
},
initialize: function() {
......
......@@ -50,7 +50,142 @@ h1 {
// ====================
// layout - basic
// layout - basic page header
.wrapper-mast {
margin: 0;
padding: 0 $baseline;
position: relative;
.mast, .metadata {
@include clearfix();
@include font-size(16);
position: relative;
max-width: $fg-max-width;
min-width: $fg-min-width;
width: flex-grid(12);
margin: 0 auto $baseline auto;
color: $gray-d2;
}
.mast {
border-bottom: 1px solid $gray-l4;
padding-bottom: ($baseline/2);
.title-sub {
@include font-size(14);
position: relative;
top: ($baseline/4);
display: block;
margin: 0;
color: $gray-l2;
font-weight: 400;
}
.title, .title-1 {
@include font-size(32);
margin: 0;
padding: 0;
font-weight: 600;
color: $gray-d3;
}
.nav-hierarchy {
@include font-size(14);
display: block;
margin: 0;
color: $gray-l2;
font-weight: 400;
.nav-item {
display: inline;
vertical-align: middle;
margin-right: ($baseline/4);
&:after {
content: ">>";
margin-left: ($baseline/4);
}
&:last-child {
margin-right: 0;
&:after {
content: none;
}
}
}
}
// layout with actions
.title {
width: flex-grid(12);
}
// layout with actions
&.has-actions {
@include clearfix();
.title {
float: left;
width: flex-grid(6,12);
margin-right: flex-gutter();
}
.nav-actions {
position: relative;
bottom: -($baseline*0.75);
float: right;
width: flex-grid(6,12);
text-align: right;
.nav-item {
display: inline-block;
vertical-align: top;
margin-right: ($baseline/2);
&:last-child {
margin-right: 0;
}
}
// buttons
.button {
padding: ($baseline/4) ($baseline/2) ($baseline/3) ($baseline/2) !important;
font-weight: 400 !important;
}
.new-button {
font-weight: 700 !important;
}
.view-button {
font-weight: 700 !important;
}
.upload-button .icon-create {
@include font-size(18);
margin-top: ($baseline/4);
}
}
}
// layout with actions
&.has-subtitle {
.nav-actions {
bottom: -($baseline*1.5);
}
}
}
// page metadata/action bar
.metadata {
}
}
// layout - basic page content
.wrapper-content {
margin: 0;
padding: 0 $baseline;
......@@ -89,8 +224,39 @@ h1 {
}
.introduction {
@include box-sizing(border-box);
@include font-size(14);
width: flex-grid(12);
margin: 0 0 $baseline 0;
.copy strong {
font-weight: 600;
}
&.has-links {
@include clearfix();
.copy {
float: left;
width: flex-grid(8,12);
margin-right: flex-gutter();
}
.nav-introduction-supplementary {
@include font-size(13);
float: right;
width: flex-grid(4,12);
display: block;
text-align: right;
.icon {
@include font-size(14);
display: inline-block;
vertical-align: middle;
margin-right: ($baseline/4);
}
}
}
}
}
......@@ -98,6 +264,7 @@ h1 {
@include box-sizing(border-box);
}
// layout - primary content
.content-primary {
.title-1, .title-2, .title-3, .title-4, .title-5, .title-5 {
......@@ -129,6 +296,7 @@ h1 {
}
}
// layout - supplemental content
.content-supplementary {
.bit {
......@@ -494,22 +662,49 @@ hr.divide {
.new-button {
@include green-button;
font-size: 13px;
@include font-size(13);
padding: 8px 20px 10px;
text-align: center;
&.big {
display: block;
}
.icon-create {
display: inline-block;
vertical-align: middle;
margin-right: ($baseline/4);
margin-top: ($baseline/10);
line-height: 0;
}
}
.view-button {
@include blue-button;
@include font-size(13);
text-align: center;
&.big {
display: block;
}
.icon-view {
@include font-size(15);
display: inline-block;
vertical-align: middle;
margin-right: ($baseline/2);
margin-top: ($baseline/5);
line-height: 0;
}
}
.edit-button.standard,
.delete-button.standard {
float: left;
@include font-size(12);
@include white-button;
float: left;
padding: 3px 10px 4px;
margin-left: 7px;
font-size: 12px;
font-weight: 400;
.edit-icon,
......@@ -579,6 +774,72 @@ hr.divide {
// ====================
// js dependant
body.js {
// lean/simple modal window
.content-modal {
@include border-bottom-radius(2px);
@include box-sizing(border-box);
@include box-shadow(0 2px 4px $shadow-d1);
position: relative;
display: none;
width: 700px;
overflow: hidden;
border: 1px solid $gray-d1;
padding: ($baseline);
background: $white;
.action-modal-close {
@include transition(top .25s ease-in-out);
@include border-bottom-radius(3px);
position: absolute;
top: -3px;
right: $baseline;
padding: ($baseline/4) ($baseline/2) 0 ($baseline/2);
background: $gray-l3;
text-align: center;
.label {
@include text-sr();
}
.ss-icon {
@include font-size(18);
color: $white;
}
&:hover {
background: $blue;
top: 0;
}
}
img {
@include box-sizing(border-box);
width: 100%;
overflow-y: scroll;
padding: ($baseline/10);
border: 1px solid $gray-l4;
}
.title {
@include font-size(18);
margin: 0 0 ($baseline/2) 0;
font-weight: 600;
color: $gray-d3;
}
.description {
@include font-size(13);
margin-top: ($baseline/2);
color: $gray-l1;
}
}
}
// ====================
// works in progress
body.hide-wip {
......
......@@ -37,6 +37,11 @@
padding: 34px 0 42px;
border-top: 1px solid #cbd1db;
&:first-child {
padding-top: 0;
border: none;
}
&.editing {
position: relative;
z-index: 1001;
......
......@@ -6,19 +6,27 @@
@include box-shadow(0 1px 2px rgba(0, 0, 0, .1));
li {
position: relative;
border-bottom: 1px solid $mediumGrey;
&:last-child {
border-bottom: none;
}
}
a {
padding: 20px 25px;
line-height: 1.3;
&:hover {
background: $paleYellow;
.class-link {
z-index: 100;
display: block;
padding: 20px 25px;
line-height: 1.3;
&:hover {
background: $paleYellow;
+ .view-live-button {
opacity: 1.0;
pointer-events: auto;
}
}
}
}
......@@ -34,6 +42,22 @@
margin-right: 20px;
color: #3c3c3c;
}
// view live button
.view-live-button {
z-index: 10000;
position: absolute;
top: 15px;
right: $baseline;
padding: ($baseline/4) ($baseline/2);
opacity: 0;
pointer-events: none;
&:hover {
opacity: 1.0;
pointer-events: auto;
}
}
}
.new-course {
......
......@@ -350,67 +350,4 @@
}
}
}
// js dependant
&.js {
.content-modal {
@include border-bottom-radius(2px);
@include box-sizing(border-box);
@include box-shadow(0 2px 4px $shadow-d1);
position: relative;
display: none;
width: 700px;
overflow: hidden;
border: 1px solid $gray-d1;
padding: ($baseline);
background: $white;
.action-modal-close {
@include transition(top .25s ease-in-out);
@include border-bottom-radius(3px);
position: absolute;
top: -3px;
right: $baseline;
padding: ($baseline/4) ($baseline/2) 0 ($baseline/2);
background: $gray-l3;
text-align: center;
.label {
@include text-sr();
}
.ss-icon {
@include font-size(18);
color: $white;
}
&:hover {
background: $blue;
top: 0;
}
}
img {
@include box-sizing(border-box);
width: 100%;
overflow-y: scroll;
padding: ($baseline/10);
border: 1px solid $gray-l4;
}
.title {
@include font-size(18);
margin: 0 0 ($baseline/2) 0;
font-weight: 600;
color: $gray-d3;
}
.description {
@include font-size(13);
margin-top: ($baseline/2);
color: $gray-l1;
}
}
}
}
}
\ No newline at end of file
......@@ -28,8 +28,9 @@
border-radius: 0;
&.new-component-item {
margin-top: 20px;
background: transparent;
border: none;
@include box-shadow(none);
}
}
......
......@@ -33,12 +33,27 @@
</tr>
</script>
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<div class="title">
<span class="title-sub">Course Content</span>
<h1 class="title-1">Files &amp; Uploads</h1>
</div>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
<a href="#" class="button upload-button new-button"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#xEB40;</i> Upload New File</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<div class="page-actions">
<a href="#" class="upload-button new-button">
<span class="upload-icon"></span>Upload New Asset
</a>
<input type="text" class="asset-search-input search wip-box" placeholder="search assets" style="display:none"/>
</div>
<article class="asset-library">
......
......@@ -42,16 +42,38 @@
</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<div class="title">
<span class="title-sub">Course Content</span>
<h1 class="title-1">Course Updates</h1>
</div>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
<a href="#" class=" button new-button new-update-button"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#x002B;</i> New Update</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<div class="introduction">
<p clas="copy">Course updates are announcements or notifications you want to share with your class. Other course authors have used them for important exam/date reminders, change in schedules, and to call out any important steps students need to be aware of.</p>
</div>
</section>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<h1>Course Info</h1>
<div class="course-info-wrapper">
<div class="main-column window">
<article class="course-updates" id="course-update-view">
<h2>Course Updates & News</h2>
<a href="#" class="new-update-button">New Update</a>
<ol class="update-list" id="course-update-list"></ol>
<!-- probably replace w/ a vertical where each element of the vertical is a separate update w/ a date and html field -->
</article>
</div>
<div class="sidebar window course-handouts" id="course-handouts-view"></div>
......
......@@ -9,25 +9,49 @@
el: $('.main-wrapper'),
model: new CMS.Models.Module({
id: '${context_course.location}'
})
}),
mast: $('.wrapper-mast')
});
</script>
</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<div class="title">
<span class="title-sub">Course Content</span>
<h1 class="title-1">Static Pages</h1>
</div>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
<a href="#" class="button new-button new-tab"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#x002B;</i> New Page</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<div class="introduction has-links">
<p class="copy">Static Pages are additional pages that supplement your Courseware. Other course authors have used them to share a syllabus, calendar, handouts, and more.</p>
<nav class="nav-introduction-supplementary">
<ul>
<li class="nav-item">
<a rel="modal" href="#preview-lms-staticpages"><i class="ss-icon ss-symbolicons-block icon icon-information">&#x2753;</i>How do Static Pages look to students in my course?</a>
</li>
</ul>
</nav>
</div>
</section>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<article class="unit-body">
<div class="details">
<h2>Here you can add and manage additional pages for your course</h2>
<p>These pages will be added to the primary navigation menu alongside Courseware, Course Info, Discussion, etc.</p>
</div>
<div class="page-actions">
<a href="#" class="new-button new-tab">
<span class="plus-icon white"></span>New Page
</a>
</div>
<div class="tab-list">
<ol class='components'>
......@@ -43,4 +67,17 @@
</article>
</div>
</div>
<div class="content-modal" id="preview-lms-staticpages">
<h3 class="title">How Static Pages are Used in Your Course</h3>
<figure>
<img src="/static/img/preview-lms-staticpages.png" alt="Preview of how Static Pages are used in your course" />
<figcaption class="description">These pages will be presented in your course's main navigation alongside Courseware, Course Info, Discussion, etc.</figcaption>
</figure>
<a href="#" rel="view" class="action action-modal-close">
<i class="ss-icon ss-symbolicons-block icon-close icon">&#x2421;</i>
<span class="label">close modal</span>
</a>
</div>
</%block>
\ No newline at end of file
......@@ -6,6 +6,15 @@
<%block name="bodyclass">is-signedin course tools export</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-subtitle">
<div class="title">
<span class="title-sub">Tools</span>
<h1 class="title-1">Course Export</h1>
</div>
</header>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<article class="export-overview">
......
......@@ -28,7 +28,7 @@
<img src="/static/img/thumb-hiw-feature1.png" alt="Studio Helps You Keep Your Courses Organized" />
<figcaption class="sr">Studio Helps You Keep Your Courses Organized</figcaption>
<span class="action-zoom">
<i class="ss-icon ss-symbolicons-block">&#xE002;</i>
<i class="ss-icon ss-symbolicons-block icon icon-zoom">&#xE002;</i>
</span>
</a>
</figure>
......@@ -62,7 +62,7 @@
<img src="/static/img/thumb-hiw-feature2.png" alt="Learning is More than Just Lectures" />
<figcaption class="sr">Learning is More than Just Lectures</figcaption>
<span class="action-zoom">
<i class="ss-icon ss-symbolicons-block">&#xE002;</i>
<i class="ss-icon ss-symbolicons-block icon icon-zoom">&#xE002;</i>
</span>
</a>
</figure>
......@@ -96,7 +96,7 @@
<img src="/static/img/thumb-hiw-feature3.png" alt="Studio Gives You Simple, Fast, and Incremental Publishing. With Friends." />
<figcaption class="sr">Studio Gives You Simple, Fast, and Incremental Publishing. With Friends.</figcaption>
<span class="action-zoom">
<i class="ss-icon ss-symbolicons-block">&#xE002;</i>
<i class="ss-icon ss-symbolicons-block icon icon-zoom">&#xE002;</i>
</span>
</a>
</figure>
......@@ -152,7 +152,7 @@
</figure>
<a href="#" rel="view" class="action action-modal-close">
<i class="ss-icon ss-symbolicons-block">&#x2421;</i>
<i class="ss-icon ss-symbolicons-block icon icon-close">&#x2421;</i>
<span class="label">close modal</span>
</a>
</div>
......@@ -165,7 +165,7 @@
</figure>
<a href="#" rel="view" class="action action-modal-close">
<i class="ss-icon ss-symbolicons-block">&#x2421;</i>
<i class="ss-icon ss-symbolicons-block icon icon-close">&#x2421;</i>
<span class="label">close modal</span>
</a>
</div>
......@@ -178,22 +178,8 @@
</figure>
<a href="#" rel="view" class="action action-modal-close">
<i class="ss-icon ss-symbolicons-block">&#x2421;</i>
<i class="ss-icon ss-symbolicons-block icon icon-close">&#x2421;</i>
<span class="label">close modal</span>
</a>
</div>
</%block>
<%block name="jsextra">
<script type="text/javascript">
(function() {
// lean modal window
$('a[rel*=modal]').leanModal({overlay : 0.50, closeButton: '.action-modal-close' });
$('a.action-modal-close').click(function(e){
(e).preventDefault();
});
})(this)
</script>
</%block>
\ No newline at end of file
......@@ -6,6 +6,15 @@
<%block name="bodyclass">is-signedin course tools import</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-subtitle">
<div class="title">
<span class="title-sub">Tools</span>
<h1 class="title-1">Course Import</h1>
</div>
</header>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<article class="import-overview">
......
......@@ -33,35 +33,57 @@
</%block>
<%block name="content">
<div class="main-wrapper">
<div class="inner-wrapper">
<h1>My Courses</h1>
<article class="my-classes">
% if user.is_active:
% if not disable_course_creation:
<a href="#" class="new-button new-course-button"><span class="plus-icon white"></span> New Course</a>
%endif
<ul class="class-list">
%for course, url in courses:
<li>
<a href="${url}" class="class-name">
<span class="class-name">${course}</span>
<!--
<span class="detail">Started: 9/21/2012</span>
<span class="detail">Ends: 10/21/2012</span>
-->
</a>
</li>
%endfor
</ul>
% else:
<div class='warn-msg'>
<p>
In order to start authoring courses using edX studio, please click on the activation link in your email.
</p>
</div>
% endif
</article>
</div>
</div>
</%block>
<div class="wrapper-mast wrapper">
<header class="mast has-actions">
<div class="title">
<h1 class="title-1">My Courses</h1>
</div>
% if user.is_active:
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
% if not disable_course_creation:
<a href="#" class="button new-button new-course-button"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#x002B;</i> New Course</a>
% endif
</li>
</ul>
</nav>
% endif
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<div class="introduction">
<p class="copy"><strong>Welcome, ${ user.username }</strong>. Here are all of the courses you are currently authoring in Studio:</p>
</div>
</section>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<article class="my-classes">
% if user.is_active:
<ul class="class-list">
%for course, url, lms_link in courses:
<li>
<a class="class-link" href="${url}" class="class-name">
<span class="class-name">${course}</span>
</a>
<a href="${lms_link}" rel="external" class="button view-button view-live-button"><i class="ss-icon ss-symbolicons-block icon icon-view">&#xE010;</i>View Live</a>
</li>
%endfor
</ul>
% else:
<div class='warn-msg'>
<p>
In order to start authoring courses using edX Studio, please click on the activation link in your email.
</p>
</div>
% endif
</article>
</div>
</div>
</%block>
\ No newline at end of file
......@@ -4,15 +4,28 @@
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<div class="title">
<span class="title-sub">Course Settings</span>
<h1 class="title-1">Course Team</h1>
</div>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
%if allow_actions:
<li class="nav-item">
<a href="#" class="button new-button new-user-button"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#x002B;</i> New User</a>
</li>
%endif
</ul>
</nav>
</header>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<div class="page-actions">
%if allow_actions:
<a href="#" class="new-button new-user-button">
<span class="plus-icon white"></span>New User
</a>
%endif
</div>
<div class="details">
<p>The following list of users have been designated as course staff. This means that these users will have permissions to modify course content. You may add additional course staff below, if you are the course instructor. Please note that they must have already registered and verified their account.</p>
......
......@@ -120,12 +120,32 @@
</div>
</div>
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<div class="title">
<span class="title-sub">Course Content</span>
<h1 class="title-1">Course Outline</h1>
</div>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
<a href="#" class="toggle-button toggle-button-sections"><i class="ss-icon ss-symbolicons-block icon">up</i> <span class="label">Collapse All Sections</span></a>
</li>
<li class="nav-item">
<a href="#" class="button new-button new-courseware-section-button"><i class="ss-icon ss-symbolicons-standard icon icon-create">&#x002B;</i> New Section</a>
</li>
<li class="nav-item">
<a href="${lms_link}" rel="external" class="button view-button view-live-button"><i class="ss-icon ss-symbolicons-block icon icon-view">&#xE010;</i>View Live</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="main-wrapper">
<div class="inner-wrapper">
<div class="page-actions">
<a href="#" class="new-button new-courseware-section-button"><span class="plus-icon white"></span> New Section</a>
<a href="#" class="toggle-button toggle-button-sections"><i class="ss-icon ss-symbolicons-block">up</i> <span class="label">Collapse All Sections</span></a>
</div>
<article class="courseware-overview" data-course-id="${context_course.location.url()}">
% for section in sections:
<section class="courseware-section branch" data-id="${section.location}">
......
......@@ -42,17 +42,17 @@ from contentstore import utils
</%block>
<%block name="content">
<div class="wrapper-content wrapper">
<section class="content">
<header class="page">
<div class="wrapper-mast wrapper">
<header class="mast has-subtitle">
<div class="title">
<span class="title-sub">Settings</span>
<h1 class="title-1">Schedule &amp; Details</h1>
</header>
<!-- <div class="introduction">
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.</p>
</div> -->
</div>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
<form id="settings_details" class="settings-details" method="post" action="">
<section class="group-settings basic">
......
......@@ -39,17 +39,17 @@ from contentstore import utils
</%block>
<%block name="content">
<div class="wrapper-content wrapper">
<section class="content">
<header class="page">
<div class="wrapper-mast wrapper">
<header class="mast has-subtitle">
<div class="title">
<span class="title-sub">Settings</span>
<h1 class="title-1">Grading</h1>
</header>
<!-- <div class="introduction">
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.</p>
</div> -->
</div>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
<form id="settings_details" class="settings-grading" method="post" action="">
<section class="group-settings grade-range">
......
......@@ -17,7 +17,7 @@
</div>
<nav class="nav-course primary nav-dropdown" role="navigation">
<h2 class="sr">PH207x's Navigation:</h2>
<h2 class="sr">${context_course.display_name}'s Navigation:</h2>
<ol>
<li class="nav-item nav-course-courseware">
......
......@@ -12,6 +12,8 @@ import capa.xqueue_interface as xqueue_interface
from datetime import datetime
from . import test_system
import test_util_open_ended
"""
Tests for the various pieces of the CombinedOpenEndedGrading system
......@@ -43,7 +45,10 @@ class OpenEndedChildTest(unittest.TestCase):
'max_score': max_score,
'display_name': 'Name',
'accept_file_upload': False,
'close_date': None
'close_date': None,
's3_interface' : "",
'open_ended_grading_interface' : {},
'skip_basic_checks' : False,
}
definition = Mock()
descriptor = Mock()
......@@ -161,6 +166,9 @@ class OpenEndedModuleTest(unittest.TestCase):
'accept_file_upload': False,
'rewrite_content_links' : "",
'close_date': None,
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
'skip_basic_checks' : False,
}
oeparam = etree.XML('''
......@@ -293,6 +301,9 @@ class CombinedOpenEndedModuleTest(unittest.TestCase):
'accept_file_upload' : False,
'rewrite_content_links' : "",
'close_date' : "",
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
'skip_basic_checks' : False,
}
oeparam = etree.XML('''
......
......@@ -9,6 +9,7 @@ from nose.plugins.skip import SkipTest
from . import test_system
import test_util_open_ended
class SelfAssessmentTest(unittest.TestCase):
......@@ -47,7 +48,10 @@ class SelfAssessmentTest(unittest.TestCase):
'max_score': 1,
'display_name': "Name",
'accept_file_upload': False,
'close_date': None
'close_date': None,
's3_interface' : test_util_open_ended.S3_INTERFACE,
'open_ended_grading_interface' : test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE,
'skip_basic_checks' : False,
}
self.module = SelfAssessmentModule(test_system, self.location,
......
OPEN_ENDED_GRADING_INTERFACE = {
'url' : 'http://127.0.0.1:3033/',
'username' : 'incorrect',
'password' : 'incorrect',
'staff_grading' : 'staff_grading',
'peer_grading' : 'peer_grading',
'grading_controller' : 'grading_controller'
}
S3_INTERFACE = {
'aws_access_key' : "",
'aws_secret_key' : "",
"aws_bucket_name" : "",
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
[run]
data_file = reports/lms/.coverage
source = lms,common/djangoapps
omit = lms/envs/*, lms/djangoapps/portal/*, lms/djangoapps/terrain/*, common/djangoapps/*/migrations/*
omit = lms/envs/*, common/djangoapps/terrain/*, common/djangoapps/*/migrations/*
[report]
ignore_errors = True
......
from lettuce import world, step # , before, after
from factories import *
from lettuce import world, step
from django.core.management import call_command
from nose.tools import assert_equals, assert_in
from lettuce.django import django_url
......
......@@ -9,7 +9,6 @@ logger = getLogger(__name__)
## support functions
def get_courses():
'''
Returns dict of lists of courses available, keyed by course.org (ie university).
......@@ -20,29 +19,6 @@ def get_courses():
courses = sorted(courses, key=lambda course: course.number)
return courses
# def get_courseware(course_id):
# """
# Given a course_id (string), return a courseware array of dictionaries for the
# top two levels of navigation. Example:
# [
# {'chapter_name': 'Overview',
# 'sections': ['Welcome', 'System Usage Sequence', 'Lab0: Using the tools', 'Circuit Sandbox']
# },
# {'chapter_name': 'Week 1',
# 'sections': ['Administrivia and Circuit Elements', 'Basic Circuit Analysis', 'Resistor Divider', 'Week 1 Tutorials']
# },
# {'chapter_name': 'Midterm Exam',
# 'sections': ['Midterm Exam']
# }
# ]
# """
# course = get_course_by_id(course_id)
# chapters = course.get_children()
# courseware = [ {'chapter_name':c.display_name, 'sections':[s.display_name for s in c.get_children()]} for c in chapters]
# return courseware
def get_courseware_with_tabs(course_id):
"""
......@@ -106,8 +82,8 @@ def get_courseware_with_tabs(course_id):
course = get_course_by_id(course_id)
chapters = [chapter for chapter in course.get_children() if chapter.metadata.get('hide_from_toc', 'false').lower() != 'true']
courseware = [{'chapter_name': c.display_name,
'sections': [{'section_name': s.display_name,
'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
'sections': [{'section_name': s.display_name,
'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
'tabs': [{'children_count': len(t.get_children()) if (type(t) == vertical_module.VerticalDescriptor) else 0,
'class': t.__class__.__name__}
for t in s.get_children()]}
......
......@@ -9,10 +9,3 @@ Feature: View the Courseware Tab
And I click on View Courseware
When I click on the "Courseware" tab
Then the "Courseware" tab is active
# TODO: fix this one? Not sure whether you should get a 404.
# Scenario: I cannot get to the courseware tab when not logged in
# Given I am not logged in
# And I visit the homepage
# When I visit the courseware URL
# Then the login dialog is visible
......@@ -34,7 +34,6 @@ def click_the_dropdown(step):
#### helper functions
def user_is_an_unactivated_user(uname):
u = User.objects.get(username=uname)
u.is_active = False
......
......@@ -3,31 +3,35 @@ Feature: Open ended grading
In order to complete the courseware questions
I want the machine learning grading to be functional
Scenario: An answer that is too short is rejected
Given I navigate to an openended question
And I enter the answer "z"
When I press the "Check" button
And I wait for "8" seconds
And I see the grader status "Submitted for grading"
And I press the "Recheck for Feedback" button
Then I see the red X
And I see the grader score "0"
# Commenting these all out right now until we can
# make a reference implementation for a course with
# an open ended grading problem that is always available
#
# Scenario: An answer that is too short is rejected
# Given I navigate to an openended question
# And I enter the answer "z"
# When I press the "Check" button
# And I wait for "8" seconds
# And I see the grader status "Submitted for grading"
# And I press the "Recheck for Feedback" button
# Then I see the red X
# And I see the grader score "0"
Scenario: An answer with too many spelling errors is rejected
Given I navigate to an openended question
And I enter the answer "az"
When I press the "Check" button
And I wait for "8" seconds
And I see the grader status "Submitted for grading"
And I press the "Recheck for Feedback" button
Then I see the red X
And I see the grader score "0"
When I click the link for full output
Then I see the spelling grading message "More spelling errors than average."
# Scenario: An answer with too many spelling errors is rejected
# Given I navigate to an openended question
# And I enter the answer "az"
# When I press the "Check" button
# And I wait for "8" seconds
# And I see the grader status "Submitted for grading"
# And I press the "Recheck for Feedback" button
# Then I see the red X
# And I see the grader score "0"
# When I click the link for full output
# Then I see the spelling grading message "More spelling errors than average."
Scenario: An answer makes its way to the instructor dashboard
Given I navigate to an openended question as staff
When I submit the answer "I love Chemistry."
And I wait for "8" seconds
And I visit the staff grading page
Then my answer is queued for instructor grading
\ No newline at end of file
# Scenario: An answer makes its way to the instructor dashboard
# Given I navigate to an openended question as staff
# When I submit the answer "I love Chemistry."
# And I wait for "8" seconds
# And I visit the staff grading page
# Then my answer is queued for instructor grading
......@@ -14,4 +14,4 @@ Feature: Register for a course
And I visit the dashboard
When I click the link with the text "Unregister"
And I press the "Unregister" button in the Unenroll dialog
Then I should see "Looks like you haven't registered for any courses yet." somewhere in the page
\ No newline at end of file
Then I should see "Looks like you haven't registered for any courses yet." somewhere in the page
......@@ -4,7 +4,7 @@ from lettuce import world, step
@step('I register for the course numbered "([^"]*)"$')
def i_register_for_the_course(step, course):
courses_section = world.browser.find_by_css('section.courses')
course_link_css = 'article[id*="%s"] a' % course
course_link_css = 'article[id*="%s"] > div' % course
course_link = courses_section.find_by_css(course_link_css).first
course_link.click()
......@@ -25,3 +25,4 @@ def i_should_see_that_course_in_my_dashboard(step, course):
def i_press_the_button_in_the_unenroll_dialog(step, value):
button_css = 'section#unenroll-modal input[value="%s"]' % value
world.browser.find_by_css(button_css).click()
assert world.browser.is_element_present_by_css('section.container.dashboard')
......@@ -23,37 +23,41 @@ Feature: There are courses on the homepage
As an acceptance test
I want to count all the chapters, sections, and tabs for each course
Scenario: Navigate through course MITx/3.091x/2012_Fall
Given I am registered for course "MITx/3.091x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course MITx/6.002x/2012_Fall
Given I am registered for course "MITx/6.002x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course MITx/6.00x/2012_Fall
Given I am registered for course "MITx/6.00x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course HarvardX/PH207x/2012_Fall
Given I am registered for course "HarvardX/PH207x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course BerkeleyX/CS169.1x/2012_Fall
Given I am registered for course "BerkeleyX/CS169.1x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course BerkeleyX/CS169.2x/2012_Fall
Given I am registered for course "BerkeleyX/CS169.2x/2012_Fall"
And I log in
Then I verify all the content of each course
Scenario: Navigate through course BerkeleyX/CS184.1x/2012_Fall
Given I am registered for course "BerkeleyX/CS184.1x/2012_Fall"
And I log in
Then I verify all the content of each course
\ No newline at end of file
# Commenting these all out for now because they don't always run,
# they have too many prerequesites, e.g. the course exists, and
# is within the start and end dates, etc.
# Scenario: Navigate through course MITx/3.091x/2012_Fall
# Given I am registered for course "MITx/3.091x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course MITx/6.002x/2012_Fall
# Given I am registered for course "MITx/6.002x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course MITx/6.00x/2012_Fall
# Given I am registered for course "MITx/6.00x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course HarvardX/PH207x/2012_Fall
# Given I am registered for course "HarvardX/PH207x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course BerkeleyX/CS169.1x/2012_Fall
# Given I am registered for course "BerkeleyX/CS169.1x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course BerkeleyX/CS169.2x/2012_Fall
# Given I am registered for course "BerkeleyX/CS169.2x/2012_Fall"
# And I log in
# Then I verify all the content of each course
# Scenario: Navigate through course BerkeleyX/CS184.1x/2012_Fall
# Given I am registered for course "BerkeleyX/CS184.1x/2012_Fall"
# And I log in
# Then I verify all the content of each course
\ No newline at end of file
......@@ -26,6 +26,8 @@ log = logging.getLogger(__name__)
from django.test.utils import override_settings
from django.http import QueryDict
from xmodule.tests import test_util_open_ended
@override_settings(MODULESTORE=ct.TEST_DATA_XML_MODULESTORE)
class TestStaffGradingService(ct.PageLoader):
......@@ -145,9 +147,11 @@ class TestPeerGradingService(ct.PageLoader):
location = "i4x://edX/toy/peergrading/init"
self.mock_service = peer_grading_service.MockPeerGradingService()
self.system = ModuleSystem(location, None, None, render_to_string, None)
self.system = ModuleSystem(location, None, None, render_to_string, None,
s3_interface = test_util_open_ended.S3_INTERFACE,
open_ended_grading_interface=test_util_open_ended.OPEN_ENDED_GRADING_INTERFACE
)
self.descriptor = peer_grading_module.PeerGradingDescriptor(self.system)
self.peer_module = peer_grading_module.PeerGradingModule(self.system, location, "<peergrading/>", self.descriptor)
self.peer_module.peer_gs = self.mock_service
self.logout()
......
## acceptance_testing
This fake django app is here to support acceptance testing using <a href="http://lettuce.it/">lettuce</a> +
<a href="http://splinter.cobrateam.info/">splinter</a> (which wraps <a href="http://selenium.googlecode.com/svn/trunk/docs/api/py/index.html">selenium</a>).
First you need to make sure that you've installed the requirements.
This includes lettuce, selenium, splinter, etc.
Do this with:
```pip install -r test-requirements.txt```
The settings.py environment file used is named acceptance.py.
It uses a test SQLite database defined as ../db/test-mitx.db.
You need to first start up the server separately, then run the lettuce scenarios.
Full documentation can be found on the wiki at <a href="https://edx-wiki.atlassian.net/wiki/display/ENG/Lettuce+Acceptance+Testing">this link</a>.
import factory
from student.models import User, UserProfile, Registration
from datetime import datetime
import uuid
class UserProfileFactory(factory.Factory):
FACTORY_FOR = UserProfile
user = None
name = 'Jack Foo'
level_of_education = None
gender = 'm'
mailing_address = None
goals = 'World domination'
class RegistrationFactory(factory.Factory):
FACTORY_FOR = Registration
user = None
activation_key = uuid.uuid4().hex
class UserFactory(factory.Factory):
FACTORY_FOR = User
username = 'robot'
email = 'robot+test@edx.org'
password = 'test'
first_name = 'Robot'
last_name = 'Test'
is_staff = False
is_active = True
is_superuser = False
last_login = datetime(2012, 1, 1)
date_joined = datetime(2011, 1, 1)
......@@ -38,4 +38,4 @@ MITX_FEATURES['STUB_VIDEO_FOR_TESTING'] = True
# Include the lettuce app for acceptance testing, including the 'harvest' django-admin command
INSTALLED_APPS += ('lettuce.django',)
LETTUCE_APPS = ('portal',) # dummy app covers the home page, login, registration, and course enrollment
LETTUCE_APPS = ('courseware',)
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