class WordCloudFields(object): """XFields for word cloud.""" num_inputs = Integer( display_name="Inputs", help= "Number of text boxes available for students to input words/sentences.", scope=Scope.settings, default=5, values={"min": 1}) num_top_words = Integer( display_name="Maximum Words", help="Maximum number of words to be displayed in generated word cloud.", scope=Scope.settings, default=250, values={"min": 1}) display_student_percents = Boolean( display_name="Show Percents", help="Statistics are shown for entered words near that word.", scope=Scope.settings, default=True) # Fields for descriptor. submitted = Boolean( help="Whether this student has posted words to the cloud.", scope=Scope.user_state, default=False) student_words = List(help="Student answer.", scope=Scope.user_state, default=[]) all_words = Dict(help="All possible words from all students.", scope=Scope.content) top_words = Dict(help="Top num_top_words words for word cloud.", scope=Scope.content)
class WordCloudFields(object): """XFields for word cloud.""" display_name = String(help="Display name for this module", scope=Scope.settings) num_inputs = Integer(help="Number of inputs.", scope=Scope.settings, default=5) num_top_words = Integer( help="Number of max words, which will be displayed.", scope=Scope.settings, default=250) display_student_percents = Boolean( help="Display usage percents for each word?", scope=Scope.settings, default=True) # Fields for descriptor. submitted = Boolean( help="Whether this student has posted words to the cloud.", scope=Scope.user_state, default=False) student_words = List(help="Student answer.", scope=Scope.user_state, default=[]) all_words = Object(help="All possible words from all students.", scope=Scope.content) top_words = Object(help="Top num_top_words words for word cloud.", scope=Scope.content)
class PeerGradingFields(object): use_for_single_location = Boolean( display_name="Show Single Problem", help='When True, only the single problem specified by "Link to Problem Location" is shown. ' 'When False, a panel is displayed with all problems available for peer grading.', default=USE_FOR_SINGLE_LOCATION, scope=Scope.settings ) link_to_location = String( display_name="Link to Problem Location", help='The location of the problem being graded. Only used when "Show Single Problem" is True.', default=LINK_TO_LOCATION, scope=Scope.settings ) is_graded = Boolean( display_name="Graded", help='Defines whether the student gets credit for grading this problem. Only used when "Show Single Problem" is True.', default=IS_GRADED, scope=Scope.settings ) due_date = Date(help="Due date that should be displayed.", default=None, scope=Scope.settings) grace_period_string = String(help="Amount of grace to give on the due date.", default=None, scope=Scope.settings) max_grade = Integer( help="The maximum grade that a student can receive for this problem.", default=MAX_SCORE, scope=Scope.settings, values={"min": 0} ) student_data_for_location = Dict( help="Student data for a given peer grading problem.", scope=Scope.user_state ) weight = Float( display_name="Problem Weight", help="Defines the number of points each problem is worth. If the value is not set, each problem is worth one point.", scope=Scope.settings, values={"min": 0, "step": ".1"} )
class CourseFields(object): textbooks = TextbookList(help="List of pairs of (title, url) for textbooks used in this course", scope=Scope.content) wiki_slug = String(help="Slug that points to the wiki for this course", scope=Scope.content) enrollment_start = Date(help="Date that enrollment for this class is opened", scope=Scope.settings) enrollment_end = Date(help="Date that enrollment for this class is closed", scope=Scope.settings) start = Date(help="Start time when this module is visible", scope=Scope.settings) end = Date(help="Date that this class ends", scope=Scope.settings) advertised_start = String(help="Date that this course is advertised to start", scope=Scope.settings) grading_policy = Dict(help="Grading policy definition for this class", scope=Scope.content) show_calculator = Boolean(help="Whether to show the calculator in this course", default=False, scope=Scope.settings) display_name = String(help="Display name for this module", scope=Scope.settings) tabs = List(help="List of tabs to enable in this course", scope=Scope.settings) end_of_course_survey_url = String(help="Url for the end-of-course survey", scope=Scope.settings) discussion_blackouts = List(help="List of pairs of start/end dates for discussion blackouts", scope=Scope.settings) discussion_topics = Dict( help="Map of topics names to ids", scope=Scope.settings ) testcenter_info = Dict(help="Dictionary of Test Center info", scope=Scope.settings) announcement = Date(help="Date this course is announced", scope=Scope.settings) cohort_config = Dict(help="Dictionary defining cohort configuration", scope=Scope.settings) is_new = Boolean(help="Whether this course should be flagged as new", scope=Scope.settings) no_grade = Boolean(help="True if this course isn't graded", default=False, scope=Scope.settings) disable_progress_graph = Boolean(help="True if this course shouldn't display the progress graph", default=False, scope=Scope.settings) pdf_textbooks = List(help="List of dictionaries containing pdf_textbook configuration", scope=Scope.settings) html_textbooks = List(help="List of dictionaries containing html_textbook configuration", scope=Scope.settings) remote_gradebook = Dict(scope=Scope.settings) allow_anonymous = Boolean(scope=Scope.settings, default=True) allow_anonymous_to_peers = Boolean(scope=Scope.settings, default=False) advanced_modules = List(help="Beta modules used in your course", scope=Scope.settings) has_children = True checklists = List(scope=Scope.settings) info_sidebar_name = String(scope=Scope.settings, default='Course Handouts') show_timezone = Boolean(help="True if timezones should be shown on dates in the courseware", scope=Scope.settings, default=True) enrollment_domain = String(help="External login method associated with user accounts allowed to register in course", scope=Scope.settings) # An extra property is used rather than the wiki_slug/number because # there are courses that change the number for different runs. This allows # courses to share the same css_class across runs even if they have # different numbers. # # TODO get rid of this as soon as possible or potentially build in a robust # way to add in course-specific styling. There needs to be a discussion # about the right way to do this, but arjun will address this ASAP. Also # note that the courseware template needs to change when this is removed. css_class = String(help="DO NOT USE THIS", scope=Scope.settings) # TODO: This is a quick kludge to allow CS50 (and other courses) to # specify their own discussion forums as external links by specifying a # "discussion_link" in their policy JSON file. This should later get # folded in with Syllabus, Course Info, and additional Custom tabs in a # more sensible framework later. discussion_link = String(help="DO NOT USE THIS", scope=Scope.settings) # TODO: same as above, intended to let internal CS50 hide the progress tab # until we get grade integration set up. # Explicit comparison to True because we always want to return a bool. hide_progress_tab = Boolean(help="DO NOT USE THIS", scope=Scope.settings)
class LmsNamespace(Namespace): """ Namespace that defines fields common to all blocks used in the LMS """ hide_from_toc = Boolean( help="Whether to display this module in the table of contents", default=False, scope=Scope.settings ) graded = Boolean( help="Whether this module contributes to the final course grade", default=False, scope=Scope.settings ) format = String( help="What format this module is in (used for deciding which " "grader to apply, and what to show in the TOC)", scope=Scope.settings, ) start = Date( help="Start time when this module is visible", default=datetime.fromtimestamp(0, UTC), scope=Scope.settings ) due = Date(help="Date that this problem is due by", scope=Scope.settings) source_file = String(help="source file name (eg for latex)", scope=Scope.settings) giturl = String(help="url root for course data git repository", scope=Scope.settings) xqa_key = String(help="DO NOT USE", scope=Scope.settings) ispublic = Boolean(help="Whether this course is open to the public, or only to admins", scope=Scope.settings) graceperiod = Timedelta( help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings ) showanswer = String( help="When to show the problem answer to the student", scope=Scope.settings, default="finished" ) rerandomize = String( help="When to rerandomize the problem", default="never", scope=Scope.settings ) days_early_for_beta = Float( help="Number of days early to show content to beta users", default=None, scope=Scope.settings )
class CrowdsourceHinterFields(object): """Defines fields for the crowdsource hinter module.""" has_children = True moderate = String(help='String "True"/"False" - activates moderation', scope=Scope.content, default='False') debug = String(help='String "True"/"False" - allows multiple voting', scope=Scope.content, default='False') # Usage: hints[answer] = {str(pk): [hint_text, #votes]} # hints is a dictionary that takes answer keys. # Each value is itself a dictionary, accepting hint_pk strings as keys, # and returning [hint text, #votes] pairs as values hints = Dict(help='A dictionary containing all the active hints.', scope=Scope.content, default={}) mod_queue = Dict(help='A dictionary containing hints still awaiting approval', scope=Scope.content, default={}) hint_pk = Integer(help='Used to index hints.', scope=Scope.content, default=0) # A list of previous hints that a student viewed. # Of the form [answer, [hint_pk_1, ...]] for each problem. # Sorry about the variable name - I know it's confusing. previous_answers = List(help='A list of hints viewed.', scope=Scope.user_state, default=[]) # user_submissions actually contains a list of previous answers submitted. # (Originally, preivous_answers did this job, hence the name confusion.) user_submissions = List(help='A list of previous submissions', scope=Scope.user_state, default=[]) user_voted = Boolean(help='Specifies if the user has voted on this problem or not.', scope=Scope.user_state, default=False)
class VideoFields(object): """Fields for `VideoModule` and `VideoDescriptor`.""" display_name = String( display_name="Display Name", help="This name appears in the horizontal navigation at the top of the page.", scope=Scope.settings, # it'd be nice to have a useful default but it screws up other things; so, # use display_name_with_default for those default="Video" ) data = String( help="XML data for the problem", default='', scope=Scope.content ) position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) show_captions = Boolean(help="This controls whether or not captions are shown by default.", display_name="Show Captions", scope=Scope.settings, default=True) youtube_id_1_0 = String(help="This is the Youtube ID reference for the normal speed video.", display_name="Default Speed", scope=Scope.settings, default="OEoXaMPEzfM") youtube_id_0_75 = String(help="The Youtube ID for the .75x speed video.", display_name="Speed: .75x", scope=Scope.settings, default="") youtube_id_1_25 = String(help="The Youtube ID for the 1.25x speed video.", display_name="Speed: 1.25x", scope=Scope.settings, default="") youtube_id_1_5 = String(help="The Youtube ID for the 1.5x speed video.", display_name="Speed: 1.5x", scope=Scope.settings, default="") start_time = Float(help="Time the video starts", display_name="Start Time", scope=Scope.settings, default=0.0) end_time = Float(help="Time the video ends", display_name="End Time", scope=Scope.settings, default=0.0) source = String(help="The external URL to download the video. This appears as a link beneath the video.", display_name="Download Video", scope=Scope.settings, default="") track = String(help="The external URL to download the subtitle track. This appears as a link beneath the video.", display_name="Download Track", scope=Scope.settings, default="")
class CrowdsourceHinterFields(object): """Defines fields for the crowdsource hinter module.""" has_children = True moderate = String(help='String "True"/"False" - activates moderation', scope=Scope.content, default='False') debug = String(help='String "True"/"False" - allows multiple voting', scope=Scope.content, default='False') # Usage: hints[answer] = {str(pk): [hint_text, #votes]} # hints is a dictionary that takes answer keys. # Each value is itself a dictionary, accepting hint_pk strings as keys, # and returning [hint text, #votes] pairs as values hints = Dict(help='A dictionary containing all the active hints.', scope=Scope.content, default={}) mod_queue = Dict( help='A dictionary containing hints still awaiting approval', scope=Scope.content, default={}) hint_pk = Integer(help='Used to index hints.', scope=Scope.content, default=0) # A list of previous answers this student made to this problem. # Of the form [answer, [hint_pk_1, hint_pk_2, hint_pk_3]] for each problem. hint_pk's are # None if the hint was not given. previous_answers = List(help='A list of previous submissions.', scope=Scope.user_state, default=[]) user_voted = Boolean( help='Specifies if the user has voted on this problem or not.', scope=Scope.user_state, default=False)
class TimeLimitFields(object): beginning_at = Float(help="The time this timer was started", scope=Scope.user_state) ending_at = Float(help="The time this timer will end", scope=Scope.user_state) accomodation_code = String(help="A code indicating accommodations to be given the student", scope=Scope.user_state) time_expired_redirect_url = String(help="Url to redirect users to after the timelimit has expired", scope=Scope.settings) duration = Float(help="The length of this timer", scope=Scope.settings) suppress_toplevel_navigation = Boolean(help="Whether the toplevel navigation should be suppressed when viewing this module", scope=Scope.settings)
class PeerGradingFields(object): use_for_single_location = Boolean( display_name="Show Single Problem", help= 'When True, only the single problem specified by "Link to Problem Location" is shown. ' 'When False, a panel is displayed with all problems available for peer grading.', default=False, scope=Scope.settings) link_to_location = String( display_name="Link to Problem Location", help= 'The location of the problem being graded. Only used when "Show Single Problem" is True.', default="", scope=Scope.settings) graded = Boolean( display_name="Graded", help= 'Defines whether the student gets credit for grading this problem. Only used when "Show Single Problem" is True.', default=False, scope=Scope.settings) due = Date(help="Due date that should be displayed.", default=None, scope=Scope.settings) grace_period_string = String( help="Amount of grace to give on the due date.", default=None, scope=Scope.settings) student_data_for_location = Dict( help="Student data for a given peer grading problem.", scope=Scope.user_state) weight = Float( display_name="Problem Weight", help= "Defines the number of points each problem is worth. If the value is not set, each problem is worth one point.", scope=Scope.settings, values={ "min": 0, "step": ".1" }, default=1) display_name = String(display_name="Display Name", help="Display name for this module", scope=Scope.settings, default="Peer Grading Interface") data = String(help="Html contents to display for this module", default='<peergrading></peergrading>', scope=Scope.content)
class CapaFields(object): attempts = StringyInteger(help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state) max_attempts = StringyInteger(help="Maximum number of attempts that a student is allowed", scope=Scope.settings) due = Date(help="Date that this problem is due by", scope=Scope.settings) graceperiod = Timedelta(help="Amount of time after the due date that submissions will be accepted", scope=Scope.settings) showanswer = String(help="When to show the problem answer to the student", scope=Scope.settings, default="closed", values=["answered", "always", "attempted", "closed", "never"]) force_save_button = Boolean(help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False) rerandomize = Randomization(help="When to rerandomize the problem", default="always", scope=Scope.settings) data = String(help="XML data for the problem", scope=Scope.content) correct_map = Object(help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={}) input_state = Object(help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state) student_answers = Object(help="Dictionary with the current student responses", scope=Scope.user_state) done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state) seed = StringyInteger(help="Random seed for this student", scope=Scope.user_state) weight = StringyFloat(help="How much to weight this problem by", scope=Scope.settings) markdown = String(help="Markdown source of this module", scope=Scope.settings) source_code = String(help="Source code for LaTeX and Word problems. This feature is not well-supported.", scope=Scope.settings)
class PollFields(object): # Name of poll to use in links to this poll display_name = String( help="Display name for this module", scope=Scope.settings) voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.user_state, default=False) poll_answer = String( help="Student answer", scope=Scope.user_state, default='') poll_answers = Object( help="All possible answers for the poll fro other students", scope=Scope.content) answers = List( help="Poll answers from xml", scope=Scope.content, default=[]) question = String(help="Poll question", scope=Scope.content, default='')
class VideoFields(object): """Fields for `VideoModule` and `VideoDescriptor`.""" position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) show_captions = Boolean( help="This controls whether or not captions are shown by default.", display_name="Show Captions", scope=Scope.settings, default=True) youtube_id_1_0 = String( help="This is the Youtube ID reference for the normal speed video.", display_name="Default Speed", scope=Scope.settings, default="OEoXaMPEzfM") youtube_id_0_75 = String(help="The Youtube ID for the .75x speed video.", display_name="Speed: .75x", scope=Scope.settings, default="") youtube_id_1_25 = String(help="The Youtube ID for the 1.25x speed video.", display_name="Speed: 1.25x", scope=Scope.settings, default="") youtube_id_1_5 = String(help="The Youtube ID for the 1.5x speed video.", display_name="Speed: 1.5x", scope=Scope.settings, default="") start_time = Float(help="Time the video starts", display_name="Start Time", scope=Scope.settings, default=0.0) end_time = Float(help="Time the video ends", display_name="End Time", scope=Scope.settings, default=0.0) source = String( help= "The external URL to download the video. This appears as a link beneath the video.", display_name="Download Video", scope=Scope.settings, default="") track = String( help= "The external URL to download the subtitle track. This appears as a link beneath the video.", display_name="Download Track", scope=Scope.settings, default="")
class TestFields(object): # Will be returned by editable_metadata_fields. max_attempts = Integer(scope=Scope.settings, default=1000, values={ 'min': 1, 'max': 10 }) # Will not be returned by editable_metadata_fields because filtered out by non_editable_metadata_fields. due = Date(scope=Scope.settings) # Will not be returned by editable_metadata_fields because is not Scope.settings. student_answers = Dict(scope=Scope.user_state) # Will be returned, and can override the inherited value from XModule. display_name = String(scope=Scope.settings, default='local default', display_name='Local Display Name', help='local help') # Used for testing select type, effect of to_json method string_select = CrazyJsonString(scope=Scope.settings, default='default value', values=[{ 'display_name': 'first', 'value': 'value a' }, { 'display_name': 'second', 'value': 'value b' }]) # Used for testing select type float_select = Float(scope=Scope.settings, default=.999, values=[1.23, 0.98]) # Used for testing float type float_non_select = Float(scope=Scope.settings, default=.999, values={ 'min': 0, 'step': .3 }) # Used for testing that Booleans get mapped to select type boolean_select = Boolean(scope=Scope.settings) # Used for testing Lists list_field = List(scope=Scope.settings, default=[])
class CourseFields(object): textbooks = TextbookList( help="List of pairs of (title, url) for textbooks used in this course", default=[], scope=Scope.content) wiki_slug = String(help="Slug that points to the wiki for this course", scope=Scope.content) enrollment_start = Date( help="Date that enrollment for this class is opened", scope=Scope.settings) enrollment_end = Date(help="Date that enrollment for this class is closed", scope=Scope.settings) start = Date( help="Start time when this module is visible", # using now(UTC()) resulted in fractional seconds which screwed up comparisons and anyway w/b the # time of first invocation of this stmt on the server default=datetime.fromtimestamp(0, UTC()), scope=Scope.settings) end = Date(help="Date that this class ends", scope=Scope.settings) advertised_start = String( help="Date that this course is advertised to start", scope=Scope.settings) grading_policy = Dict(help="Grading policy definition for this class", default={ "GRADER": [{ "type": "Homework", "min_count": 12, "drop_count": 2, "short_label": "HW", "weight": 0.15 }, { "type": "Lab", "min_count": 12, "drop_count": 2, "weight": 0.15 }, { "type": "Midterm Exam", "short_label": "Midterm", "min_count": 1, "drop_count": 0, "weight": 0.3 }, { "type": "Final Exam", "short_label": "Final", "min_count": 1, "drop_count": 0, "weight": 0.4 }], "GRADE_CUTOFFS": { "Pass": 0.5 } }, scope=Scope.content) show_calculator = Boolean( help="Whether to show the calculator in this course", default=False, scope=Scope.settings) display_name = String(help="Display name for this module", default="Empty", display_name="Display Name", scope=Scope.settings) show_chat = Boolean(help="Whether to show the chat widget in this course", default=False, scope=Scope.settings) tabs = List(help="List of tabs to enable in this course", scope=Scope.settings) end_of_course_survey_url = String(help="Url for the end-of-course survey", scope=Scope.settings) discussion_blackouts = List( help="List of pairs of start/end dates for discussion blackouts", scope=Scope.settings) discussion_topics = Dict(help="Map of topics names to ids", scope=Scope.settings) testcenter_info = Dict(help="Dictionary of Test Center info", scope=Scope.settings) announcement = Date(help="Date this course is announced", scope=Scope.settings) cohort_config = Dict(help="Dictionary defining cohort configuration", scope=Scope.settings) is_new = Boolean(help="Whether this course should be flagged as new", scope=Scope.settings) no_grade = Boolean(help="True if this course isn't graded", default=False, scope=Scope.settings) disable_progress_graph = Boolean( help="True if this course shouldn't display the progress graph", default=False, scope=Scope.settings) pdf_textbooks = List( help="List of dictionaries containing pdf_textbook configuration", scope=Scope.settings) html_textbooks = List( help="List of dictionaries containing html_textbook configuration", scope=Scope.settings) remote_gradebook = Dict(scope=Scope.settings) allow_anonymous = Boolean(scope=Scope.settings, default=True) allow_anonymous_to_peers = Boolean(scope=Scope.settings, default=False) advanced_modules = List(help="Beta modules used in your course", scope=Scope.settings) has_children = True checklists = List( scope=Scope.settings, default=[{ "short_description": "Getting Started With Sokratik", "items": [{ "short_description": "Add Course Team Members", "long_description": "Grant your collaborators permission to edit your course so you can work together.", "is_checked": False, "action_url": "ManageUsers", "action_text": "Edit Course Team", "action_external": False }, { "short_description": "Set Important Dates for Your Course", "long_description": "Establish your course's student enrollment and launch dates on the Schedule and Details page.", "is_checked": False, "action_url": "SettingsDetails", "action_text": "Edit Course Details & Schedule", "action_external": False }, { "short_description": "Draft Your Course's Grading Policy", "long_description": "Set up your assignment types and grading policy even if you haven't created all your assignments.", "is_checked": False, "action_url": "SettingsGrading", "action_text": "Edit Grading Settings", "action_external": False }, { "short_description": "Explore the Other Sokratik Checklists", "long_description": "Discover other available course authoring tools, and find help when you need it.", "is_checked": False, "action_url": "", "action_text": "", "action_external": False }] }, { "short_description": "Draft a Rough Course Outline", "items": [{ "short_description": "Create Your First Section and Subsection", "long_description": "Use your course outline to build your first Section and Subsection.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Set Section Release Dates", "long_description": "Specify the release dates for each Section in your course. Sections become visible to students on their release dates.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Designate a Subsection as Graded", "long_description": "Set a Subsection to be graded as a specific assignment type. Assignments within graded Subsections count toward a student's final grade.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Reordering Course Content", "long_description": "Use drag and drop to reorder the content in your course.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Renaming Sections", "long_description": "Rename Sections by clicking the Section name from the Course Outline.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Deleting Course Content", "long_description": "Delete Sections, Subsections, or Units you don't need anymore. Be careful, as there is no Undo function.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }, { "short_description": "Add an Instructor-Only Section to Your Outline", "long_description": "Some course authors find using a section for unsorted, in-progress work useful. To do this, create a section and set the release date to the distant future.", "is_checked": False, "action_url": "CourseOutline", "action_text": "Edit Course Outline", "action_external": False }] }, { "short_description": "Explore Sokratik's Support Tools", "items": [{ "short_description": "Explore the Help Forum", "long_description": "Access the Help forum from the menu that appears when you click your user name in the top right corner of Studio.", "is_checked": False, "action_url": "http://help.edge.edx.org/", "action_text": "Visit Help", "action_external": True }, { "short_description": "Enroll in edX 101", "long_description": "Register for edX 101, edX's primer for course creation.", "is_checked": False, "action_url": "https://edge.edx.org/courses/edX/edX101/How_to_Create_an_edX_Course/about", "action_text": "Register for edX 101", "action_external": True }, { "short_description": "Download the Documentation", "long_description": "Download the searchable reference documentation in PDF form.", "is_checked": False, "action_url": "http://files.edx.org/Getting_Started_with_Studio.pdf", "action_text": "Download Documentation", "action_external": True }] }, { "short_description": "Draft Your Course About Page", "items": [{ "short_description": "Draft a Course Description", "long_description": "Courses on Sokratik have an About page that includes a course video, description, and more. Draft the text students will read before deciding to enroll in your course.", "is_checked": False, "action_url": "SettingsDetails", "action_text": "Edit Course Schedule & Details", "action_external": False }, { "short_description": "Add Staff Bios", "long_description": "Showing prospective students who their instructor will be is helpful. Include staff bios on the course About page.", "is_checked": False, "action_url": "SettingsDetails", "action_text": "Edit Course Schedule & Details", "action_external": False }, { "short_description": "Add Course FAQs", "long_description": "Include a short list of frequently asked questions about your course.", "is_checked": False, "action_url": "SettingsDetails", "action_text": "Edit Course Schedule & Details", "action_external": False }, { "short_description": "Add Course Prerequisites", "long_description": "Let students know what knowledge and/or skills they should have before they enroll in your course.", "is_checked": False, "action_url": "SettingsDetails", "action_text": "Edit Course Schedule & Details", "action_external": False }] }]) info_sidebar_name = String(scope=Scope.settings, default='Course Handouts') show_timezone = Boolean( help="True if timezones should be shown on dates in the courseware", scope=Scope.settings, default=True) enrollment_domain = String( help= "External login method associated with user accounts allowed to register in course", scope=Scope.settings) course_image = String( help="Filename of the course image", scope=Scope.settings, # Ensure that courses imported from XML keep their image default="images_course_image.jpg") # An extra property is used rather than the wiki_slug/number because # there are courses that change the number for different runs. This allows # courses to share the same css_class across runs even if they have # different numbers. # # TODO get rid of this as soon as possible or potentially build in a robust # way to add in course-specific styling. There needs to be a discussion # about the right way to do this, but arjun will address this ASAP. Also # note that the courseware template needs to change when this is removed. css_class = String(help="DO NOT USE THIS", scope=Scope.settings) # TODO: This is a quick kludge to allow CS50 (and other courses) to # specify their own discussion forums as external links by specifying a # "discussion_link" in their policy JSON file. This should later get # folded in with Syllabus, Course Info, and additional Custom tabs in a # more sensible framework later. discussion_link = String(help="DO NOT USE THIS", scope=Scope.settings) # TODO: same as above, intended to let internal CS50 hide the progress tab # until we get grade integration set up. # Explicit comparison to True because we always want to return a bool. hide_progress_tab = Boolean(help="DO NOT USE THIS", scope=Scope.settings) display_organization = String( help= "An optional display string for the course organization that will get rendered in the LMS", scope=Scope.settings) display_coursenumber = String( help= "An optional display string for the course number that will get rendered in the LMS", scope=Scope.settings)
class CombinedOpenEndedFields(object): display_name = String( display_name="Display Name", help="This name appears in the horizontal navigation at the top of the page.", default="Open Response Assessment", scope=Scope.settings ) current_task_number = Integer( help="Current task that the student is on.", default=0, scope=Scope.user_state ) task_states = List( help="List of state dictionaries of each task within this module.", scope=Scope.user_state ) state = String( help="Which step within the current task that the student is on.", default="initial", scope=Scope.user_state ) graded = Boolean( display_name="Graded", help='Defines whether the student gets credit for grading this problem.', default=False, scope=Scope.settings ) student_attempts = Integer( help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state ) ready_to_reset = Boolean( help="If the problem is ready to be reset or not.", default=False, scope=Scope.user_state ) max_attempts = Integer( display_name="Maximum Attempts", help="The number of times the student can try to answer this problem.", default=1, scope=Scope.settings, values={"min" : 1 } ) accept_file_upload = Boolean( display_name="Allow File Uploads", help="Whether or not the student can submit files as a response.", default=False, scope=Scope.settings ) skip_spelling_checks = Boolean( display_name="Disable Quality Filter", help="If False, the Quality Filter is enabled and submissions with poor spelling, short length, or poor grammar will not be peer reviewed.", default=False, scope=Scope.settings ) due = Date( help="Date that this problem is due by", default=None, scope=Scope.settings ) graceperiod = Timedelta( help="Amount of time after the due date that submissions will be accepted", default=None, scope=Scope.settings ) version = VersionInteger(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings) data = String(help="XML data for the problem", scope=Scope.content, default=DEFAULT_DATA) weight = Float( display_name="Problem Weight", help="Defines the number of points each problem is worth. If the value is not set, each problem is worth one point.", scope=Scope.settings, values={"min" : 0 , "step": ".1"}, default=1 ) min_to_calibrate = Integer( display_name="Minimum Peer Grading Calibrations", help="The minimum number of calibration essays each student will need to complete for peer grading.", default=3, scope=Scope.settings, values={"min" : 1, "max" : 20, "step" : "1"} ) max_to_calibrate = Integer( display_name="Maximum Peer Grading Calibrations", help="The maximum number of calibration essays each student will need to complete for peer grading.", default=6, scope=Scope.settings, values={"min" : 1, "max" : 20, "step" : "1"} ) peer_grader_count = Integer( display_name="Peer Graders per Response", help="The number of peers who will grade each submission.", default=3, scope=Scope.settings, values={"min" : 1, "step" : "1", "max" : 5} ) required_peer_grading = Integer( display_name="Required Peer Grading", help="The number of other students each student making a submission will have to grade.", default=3, scope=Scope.settings, values={"min" : 1, "step" : "1", "max" : 5} ) markdown = String( help="Markdown source of this module", default=textwrap.dedent("""\ [prompt] <h3>Censorship in the Libraries</h3> <p>'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author </p> <p> Write a persuasive essay to a newspaper reflecting your vies on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading. </p> [prompt] [rubric] + Ideas - Difficult for the reader to discern the main idea. Too brief or too repetitive to establish or maintain a focus. - Attempts a main idea. Sometimes loses focus or ineffectively displays focus. - Presents a unifying theme or main idea, but may include minor tangents. Stays somewhat focused on topic and task. - Presents a unifying theme or main idea without going off on tangents. Stays completely focused on topic and task. + Content - Includes little information with few or no details or unrelated details. Unsuccessful in attempts to explore any facets of the topic. - Includes little information and few or no details. Explores only one or two facets of the topic. - Includes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.) Explores some facets of the topic. - Includes in-depth information and exceptional supporting details that are fully developed. Explores all facets of the topic. + Organization - Ideas organized illogically, transitions weak, and response difficult to follow. - Attempts to logically organize ideas. Attempts to progress in an order that enhances meaning, and demonstrates use of transitions. - Ideas organized logically. Progresses in an order that enhances meaning. Includes smooth transitions. + Style - Contains limited vocabulary, with many words used incorrectly. Demonstrates problems with sentence patterns. - Contains basic vocabulary, with words that are predictable and common. Contains mostly simple sentences (although there may be an attempt at more varied sentence patterns). - Includes vocabulary to make explanations detailed and precise. Includes varied sentence patterns, including complex sentences. + Voice - Demonstrates language and tone that may be inappropriate to task and reader. - Demonstrates an attempt to adjust language and tone to task and reader. - Demonstrates effective adjustment of language and tone to task and reader. [rubric] [tasks] (Self), ({4-12}AI), ({9-12}Peer) [tasks] """), scope=Scope.settings )
class ThumbsBlock(InputBlock): """ An XBlock with thumbs-up/thumbs-down voting. Vote totals are stored for all students to see. Each student is recorded as has-voted or not. This demonstrates multiple data scopes and ajax handlers. """ upvotes = Integer(help="Number of up votes", default=0, scope=Scope.content) downvotes = Integer(help="Number of down votes", default=0, scope=Scope.content) voted = Boolean(help="Has this student voted?", default=False, scope=Scope.user_state) def student_view(self, context): frag = Fragment(u""" <p> <span class='upvote'><span class='count'>{self.upvotes}</span>↑</span> <span class='downvote'><span class='count'>{self.downvotes}</span>↓</span> </p> """.format(self=self)) frag.add_css(""" .upvote, .downvote { cursor: pointer; border: 1px solid #888; padding: 0 .5em; } .upvote { color: green; } .downvote { color: red; } """) frag.add_javascript(""" function ThumbsBlock(runtime, element) { function update_votes(votes) { $('.upvote .count', element).text(votes.up); $('.downvote .count', element).text(votes.down); } var handler_url = runtime.handler_url('vote'); $('.upvote', element).bind('click.ThumbsBlock.up', function() { $.post(handler_url, JSON.stringify({vote_type: 'up'})).success(update_votes); }); $('.downvote', element).bind('click.ThumbsBlock.up', function() { $.post(handler_url, JSON.stringify({vote_type: 'down'})).success(update_votes); }); }; """) frag.initialize_js('ThumbsBlock') return frag problem_view = student_view @XBlock.json_handler def vote(self, data): # Here is where we would prevent a student from voting twice, but then # we couldn't click more than once in the demo! # # if self.student.voted: # log.error("cheater!") # return if data['vote_type'] not in ('up', 'down'): log.error('error!') return if data['vote_type'] == 'up': self.upvotes += 1 else: self.downvotes += 1 self.voted = True return {'up': self.upvotes, 'down': self.downvotes} @staticmethod def workbench_scenarios(): """A canned scenario for display in the workbench.""" return [("three thumbs at once", """\ <vertical> <thumbs/> <thumbs/> <thumbs/> </vertical> """)]
class ThumbsBlock(InputBlock): """ An XBlock with thumbs-up/thumbs-down voting. Vote totals are stored for all students to see. Each student is recorded as has-voted or not. This demonstrates multiple data scopes and ajax handlers. """ upvotes = Integer(help="Number of up votes", default=0, scope=Scope.content) downvotes = Integer(help="Number of down votes", default=0, scope=Scope.content) voted = Boolean(help="Has this student voted?", default=False, scope=Scope.user_state) def student_view(self, context): """ Create a fragment used to display the XBlock to a student. `context` is a dictionary used to configure the display (unused) Returns a `Fragment` object specifying the HTML, CSS, and JavaScript to display. """ # Load the HTML fragment from within the package and fill in the template html_str = pkg_resources.resource_string(__name__, "static/html/thumbs.html") frag = Fragment(unicode(html_str).format(self=self)) # Load the CSS and JavaScript fragments from within the package css_str = pkg_resources.resource_string(__name__, "static/css/thumbs.css") frag.add_css(unicode(css_str)) js_str = pkg_resources.resource_string(__name__, "static/js/src/thumbs.js") frag.add_javascript(unicode(js_str)) frag.initialize_js('ThumbsBlock') return frag problem_view = student_view @XBlock.json_handler def vote(self, data): """ Update the vote count in response to a user action. """ # Here is where we would prevent a student from voting twice, but then # we couldn't click more than once in the demo! # # if self.student.voted: # log.error("cheater!") # return if data['vote_type'] not in ('up', 'down'): log.error('error!') return if data['vote_type'] == 'up': self.upvotes += 1 else: self.downvotes += 1 self.voted = True return {'up': self.upvotes, 'down': self.downvotes} @staticmethod def workbench_scenarios(): """A canned scenario for display in the workbench.""" return [("three thumbs at once", """\ <vertical> <thumbs/> <thumbs/> <thumbs/> </vertical> """)]
class VideoFields(object): """Fields for `VideoModule` and `VideoDescriptor`.""" display_name = String(display_name="Display Name", help="Display name for this module.", default="Video", scope=Scope.settings) position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) show_captions = Boolean( help="This controls whether or not captions are shown by default.", display_name="Show Captions", scope=Scope.settings, default=True) # TODO: This should be moved to Scope.content, but this will # require data migration to support the old video module. youtube_id_1_0 = String( help="This is the Youtube ID reference for the normal speed video.", display_name="Youtube ID", scope=Scope.settings, default="OEoXaMPEzfM") youtube_id_0_75 = String(help="The Youtube ID for the .75x speed video.", display_name="Youtube ID for .75x speed", scope=Scope.settings, default="") youtube_id_1_25 = String(help="The Youtube ID for the 1.25x speed video.", display_name="Youtube ID for 1.25x speed", scope=Scope.settings, default="") youtube_id_1_5 = String(help="The Youtube ID for the 1.5x speed video.", display_name="Youtube ID for 1.5x speed", scope=Scope.settings, default="") start_time = Float(help="Start time for the video.", display_name="Start Time", scope=Scope.settings, default=0.0) end_time = Float(help="End time for the video.", display_name="End Time", scope=Scope.settings, default=0.0) source = String( help= "The external URL to download the video. This appears as a link beneath the video.", display_name="Download Video", scope=Scope.settings, default="") html5_sources = List( help= "A list of filenames to be used with HTML5 video. The first supported filetype will be displayed.", display_name="Video Sources", scope=Scope.settings, default=[]) track = String( help= "The external URL to download the subtitle track. This appears as a link beneath the video.", display_name="Download Track", scope=Scope.settings, default="") sub = String( help="The name of the subtitle track (for non-Youtube videos).", display_name="HTML5 Subtitles", scope=Scope.settings, default="")
class CapaFields(object): """ Define the possible fields for a Capa problem """ display_name = String( display_name="Display Name", help= "This name appears in the horizontal navigation at the top of the page.", scope=Scope.settings, # it'd be nice to have a useful default but it screws up other things; so, # use display_name_with_default for those default="Blank Advanced Problem") attempts = Integer( help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state) max_attempts = Integer( display_name="Maximum Attempts", help= ("Defines the number of times a student can try to answer this problem. " "If the value is not set, infinite attempts are allowed."), values={"min": 0}, scope=Scope.settings) due = Date(help="Date that this problem is due by", scope=Scope.settings) graceperiod = Timedelta( help= "Amount of time after the due date that submissions will be accepted", scope=Scope.settings) showanswer = String( display_name="Show Answer", help=("Defines when to show the answer to the problem. " "A default value can be set in Advanced Settings."), scope=Scope.settings, default="finished", values=[{ "display_name": "Always", "value": "always" }, { "display_name": "Answered", "value": "answered" }, { "display_name": "Attempted", "value": "attempted" }, { "display_name": "Closed", "value": "closed" }, { "display_name": "Finished", "value": "finished" }, { "display_name": "Past Due", "value": "past_due" }, { "display_name": "Never", "value": "never" }]) force_save_button = Boolean( help="Whether to force the save button to appear on the page", scope=Scope.settings, default=False) rerandomize = Randomization( display_name="Randomization", help= "Defines how often inputs are randomized when a student loads the problem. " "This setting only applies to problems that can have randomly generated numeric values. " "A default value can be set in Advanced Settings.", default="never", scope=Scope.settings, values=[{ "display_name": "Always", "value": "always" }, { "display_name": "On Reset", "value": "onreset" }, { "display_name": "Never", "value": "never" }, { "display_name": "Per Student", "value": "per_student" }]) data = String(help="XML data for the problem", scope=Scope.content, default="<problem></problem>") correct_map = Dict( help="Dictionary with the correctness of current student answers", scope=Scope.user_state, default={}) input_state = Dict( help="Dictionary for maintaining the state of inputtypes", scope=Scope.user_state) student_answers = Dict( help="Dictionary with the current student responses", scope=Scope.user_state) done = Boolean(help="Whether the student has answered the problem", scope=Scope.user_state) seed = Integer(help="Random seed for this student", scope=Scope.user_state) weight = Float( display_name="Problem Weight", help= ("Defines the number of points each problem is worth. " "If the value is not set, each response field in the problem is worth one point." ), values={ "min": 0, "step": .1 }, scope=Scope.settings) markdown = String(help="Markdown source of this module", default=None, scope=Scope.settings) source_code = String( help= "Source code for LaTeX and Word problems. This feature is not well-supported.", scope=Scope.settings)
class CombinedOpenEndedFields(object): display_name = String( display_name="Display Name", help= "This name appears in the horizontal navigation at the top of the page.", default="Open Ended Grading", scope=Scope.settings) current_task_number = Integer(help="Current task that the student is on.", default=0, scope=Scope.user_state) task_states = List( help="List of state dictionaries of each task within this module.", scope=Scope.user_state) state = String( help="Which step within the current task that the student is on.", default="initial", scope=Scope.user_state) student_attempts = Integer( help="Number of attempts taken by the student on this problem", default=0, scope=Scope.user_state) ready_to_reset = Boolean( help="If the problem is ready to be reset or not.", default=False, scope=Scope.user_state) attempts = Integer( display_name="Maximum Attempts", help="The number of times the student can try to answer this problem.", default=1, scope=Scope.settings, values={"min": 1}) is_graded = Boolean(display_name="Graded", help="Whether or not the problem is graded.", default=False, scope=Scope.settings) accept_file_upload = Boolean( display_name="Allow File Uploads", help="Whether or not the student can submit files as a response.", default=False, scope=Scope.settings) skip_spelling_checks = Boolean( display_name="Disable Quality Filter", help= "If False, the Quality Filter is enabled and submissions with poor spelling, short length, or poor grammar will not be peer reviewed.", default=False, scope=Scope.settings) due = Date(help="Date that this problem is due by", default=None, scope=Scope.settings) graceperiod = String( help= "Amount of time after the due date that submissions will be accepted", default=None, scope=Scope.settings) version = VersionInteger(help="Current version number", default=DEFAULT_VERSION, scope=Scope.settings) data = String(help="XML data for the problem", scope=Scope.content) weight = Float( display_name="Problem Weight", help= "Defines the number of points each problem is worth. If the value is not set, each problem is worth one point.", scope=Scope.settings, values={ "min": 0, "step": ".1" }) markdown = String(help="Markdown source of this module", scope=Scope.settings)