CSC/ECE 517 Fall 2020 - E2054. Auto generate submission directory names based on assignment names
This wiki page describes the changes made under E2054, in order to auto-generate submission directory names based on assignment names for Fall 2020, CSC/ECE 517.
About Expertiza
Expertiza is an open source project based on Ruby on Rails framework, created and maintained by the joint efforts of students and faculty at North Carolina State University.
It allows the instructors to create new assignments and customize new or existing assignments. Expertiza also allows an instructor to create a list of topics the students can sign up for. Students can form teams on the web application to work on various projects and assignments together. Additionally, students can peer review each other's submissions allowing them to improve upon their work. Expertiza supports submission across various document types, including the URLs and wiki pages.
Need for the current project
Goal
Each assignment should have its own unique auto-generated submission directory, which is named based on the assignment name entered by the teacher.
Issues to be fixed
In the current implementation of Expertiza, there are following issues need to be addressed:
Issue #1: The directory name should be auto-generated from the assignment name.
Issue #2: It should be done by changing spaces in the names to underscores. E.g., the directory for Program 1 is by default "Program_1".
Issue #3: A check should be added to prevent two assignments in the same course from having the same name.
Issue #4: Verify or add if not present - a check to stop two assignments from sharing the same directory.
Issue #5: On changing name of an assignment while creating it, the code shouldn't throw a NoMethodError.
Issues that have been fixed
Fix #1: Submission directory is successfully being generated after the assignment name is typed in. If needed, the submission directory can be changed, however any modifications to the assignment name will just auto-generate it to match.
Fix #2: A check was added to ensure that assignments in the same course do not share the same name. When creating a course, if the assignment name is a duplicate, it will reset the entire form.
Fix #3: A check was added to ensure that assignments in the same course do not share the same submission directory. When creating a course, if the submission directory is a duplicate, it will reset the entire form.
Fix #4: These checks were also put in place when modifying an existent assignment.
Project implementation
Submitted work and demonstration of project
Files involved
The controller, helper and spec were modified for this project:
1. Assignments Controller - assignments_controller.rb
2. Assignments View - _general.html.erb
3. Assignemnts Controller Spec - assignments_controller_spec.rb
4. Assignments Model - assignment.rb
Assignments Controller
This is a controller that helps instructors create, modify, copy new assignments. Each assignment can be associated with specific Rubrics, Review Strategy and Due dates.
Assignments View
This the view for creating the new assignments and editing the existing assignments. This view also handles specifications of Rubrics, Review Strategy and Dates.
Assignemnts Controller Spec
Tests and bug fixes pertaining to assignments controller.
Assignments Model
The ruby code which defines how the assignment model functions.
Description of current project
The project primarily deals with the AssignmentsController and AssignmentsView, and changes made are as follows:
The directory name is auto-generated from the assignment name typed in by the instructor.
This is achieved by replacing all spaces in the names with underscores, and removing all special characters like '/','\','$', etc from the auto-generated submission directory name.
If any two assignments of the same name under the same course are attempted to be created, it is prevented and an error message is displayed to the user stating the the submission directory name already exists.
The odd case of a teacher editing the name of an already existing assignment to one that already exists is also handled. Expertiza will display a similar error message stating that the assignment couldn't be saved.
Changes made to code
Most changes were made in the assignments_controller.rb file. Checks were added to ensure that an existing assignment name or submission directory did not exist when creating a new assignment. If the assignment was not created due to an error, the code would render new which would cause the assignment to be created even though it did not pass all of the checks. Instead of using render new, redirect_to "/assignments/new?private=1" was used to ensure the form would be reset upon any errors.
The following function was added to app/views/assignments/edit/_general.html.erb, to generate submission directory names with underscores replacing spaces:
// E2054 Javascript function to generate the submission directory $(function() { $("#assignment_form_assignment_name").change(function() { filename = $( "#assignment_form_assignment_name" ).val().replace(/ /g,"_").replace(/[/\\?%*:|"<>/$&!#%^@]/g, '');; $('#assignment_form_assignment_directory_path').val(filename); }); });
Changes were made to the create function in assignments_controller.rb, such that it only creates the assignment directory if the one with the same name doesn't already exist:
Before
def create @assignment_form = AssignmentForm.new(assignment_form_params) if params[:button] if @assignment_form.save @assignment_form.create_assignment_node exist_assignment = Assignment.find_by(id: @assignment_form.assignment.id) assignment_form_params[:assignment][:id] = exist_assignment.id.to_s if assignment_form_params[:assignment][:directory_path].blank? assignment_form_params[:assignment][:directory_path] = "assignment_#{assignment_form_params[:assignment][:id]}" end ques_array = assignment_form_params[:assignment_questionnaire] due_array = assignment_form_params[:due_date] ques_array.each do |cur_questionnaire| cur_questionnaire[:assignment_id] = exist_assignment.id.to_s end due_array.each do |cur_due| cur_due[:parent_id] = exist_assignment.id.to_s end assignment_form_params[:assignment_questionnaire] = ques_array assignment_form_params[:due_date] = due_array @assignment_form.update(assignment_form_params, current_user) aid = Assignment.find_by(id: @assignment_form.assignment.id).id ExpertizaLogger.info "Assignment created: #{@assignment_form.as_json}" redirect_to edit_assignment_path aid undo_link("Assignment \"#{@assignment_form.assignment.name}\" has been created successfully. ") return else flash.now[:error] = "Failed to create assignment" render 'new' end else render 'new' undo_link("Assignment \"#{@assignment_form.assignment.name}\" has been created successfully. ") end end
After
def create @assignment_form = AssignmentForm.new(assignment_form_params) if params[:button] # E2054 Query for existing directory name and assignment name find_existing_assignment = Assignment.find_by(name: @assignment_form.assignment.name, course_id: @assignment_form.assignment.course_id) dir_path = assignment_form_params[:assignment][:directory_path] find_existing_directory = Assignment.find_by(directory_path: dir_path, course_id: @assignment_form.assignment.course_id) if !find_existing_assignment and !find_existing_directory and @assignment_form.save #No existing names/directories @assignment_form.create_assignment_node current_assignment = Assignment.find_by(name: @assignment_form.assignment.name, course_id: @assignment_form.assignment.course_id) assignment_form_params[:assignment][:id] = current_assignment.id.to_s ques_array = assignment_form_params[:assignment_questionnaire] due_array = assignment_form_params[:due_date] ques_array.each do |cur_questionnaire| cur_questionnaire[:assignment_id] = current_assignment.id.to_s end due_array.each do |cur_due| cur_due[:parent_id] = current_assignment.id.to_s end assignment_form_params[:assignment_questionnaire] = ques_array assignment_form_params[:due_date] = due_array @assignment_form.update(assignment_form_params, current_user) aid = Assignment.find_by(name: @assignment_form.assignment.name, course_id: @assignment_form.assignment.course_id).id ExpertizaLogger.info "Assignment created: #{@assignment_form.as_json}" redirect_to edit_assignment_path aid undo_link("Assignment \"#{@assignment_form.assignment.name}\" has been created successfully. ") return else # E2054 Existing Directory or Assignment Name was Found if find_existing_assignment flash[:error] = @assignment_form.assignment.name + " already exists as an assignment name" end if find_existing_directory flash[:error] = dir_path + " already exists as a submission directory name" end redirect_to "/assignments/new?private=1" # E2054 Rendering to this page instead of render new, this prevents it from creating a new assignment upon error end else render 'new' undo_link("Assignment \"#{@assignment_form.assignment.name}\" has been created successfully. ") end end
Changes were made to the update_feedback_assignment_form_attributes function in the same file to flash an error if an edited file has the same name:
Before
def update_feedback_assignment_form_attributes if params[:set_pressed][:bool] == 'false' flash[:error] = "There has been some submissions for the rounds of reviews that you're trying to reduce. You can only increase the round of review." else if @assignment_form.update_attributes(assignment_form_params, current_user) flash[:note] = 'The assignment was successfully saved....' else flash[:error] = "Failed to save the assignment: #{@assignment_form.errors.get(:message)}" end end ExpertizaLogger.info LoggerMessage.new("", session[:user].name, "The assignment was saved: #{@assignment_form.as_json}", request) end
After
def update_feedback_assignment_form_attributes if params[:set_pressed][:bool] == 'false' flash[:error] = "There has been some submissions for the rounds of reviews that you're trying to reduce. You can only increase the round of review." else if @assignment_form.update_attributes(assignment_form_params, current_user) flash[:note] = 'The assignment was successfully saved....' else flash[:error] = "Failed to save the assignment: #{@assignment_form.assignment.name}" end end ExpertizaLogger.info LoggerMessage.new("", session[:user].name, "The assignment was saved: #{@assignment_form.as_json}", request) end
The following validations were added to app/models/assignment.rb, without these validations the user was allowed to change the assignment name or submission directory to one that already exists.
validates :directory_path, presence: true # E2054 Needs Validation for unique submission directory validates :directory_path, uniqueness: {scope: :course_id} # E2054 Needs Validation for unique submission directory
Test Plan
Manual UI Testing
The following steps must be performed to test the project UI:
Step 1: Log in as an Instructor, with Username - instructor6, Password - password
Step 2: Create a new assignment. In this case our assignment is called "E2054 Test Assignment", under course CSC 216 Fall 2009
Step 3: To save the assignment, the Review and Author Feedback rubrics need to be filled in
Step 4: On completion, the assignment will be saved
Step 5: If another assignment of the same name under the same course is created, the following error is displayed
Step 6: On editing an already made assignment to match the same details as "E2054 Test Assignment"
We get the following error:
RSpec Testing
The following RSpec tests were added to the assignments_contoller_spec.rb file
# E2054 Ensure Assignment Names Cannot Match context 'when assignment_form is not saved successfully due to same assignment name already existing' do it 'raises validation error' do assignment1 = create(:assignment, name: 'Assignment 1', course_id: 1, directory_path: 'Assignment1') expect {create(:assignment, name: 'Assignment 1', course_id: 1, directory_path: 'Assignment2')}.to raise_error(ActiveRecord::RecordInvalid) end end # E2054 Ensure Submission Directory Cannot Match context 'when assignment_form is not saved successfully due to same submission directory already existing' do it 'raises validation error' do assignment1 = create(:assignment, name: 'Assignment 1', course_id: 1, directory_path: 'Assignment1') expect {create(:assignment, name: 'Assignment 2', course_id: 1, directory_path: 'Assignment1')}.to raise_error(ActiveRecord::RecordInvalid) end end
Manual Rspec Testing Video Link
Team Information
1) Nicholas Viado (ndviado)
2) Akshay Podila (apodila)
Mentor: Sanket Pai (sgpai2)