CSC/ECE 517 Fall 2020 - E2058. Two issues related to assignment management: Difference between revisions
(27 intermediate revisions by 2 users not shown) | |||
Line 12: | Line 12: | ||
=== Project Goal === | === Project Goal === | ||
The goals of this project were to solve tow issues related to assignment management. | The goals of this project were to solve tow issues related to assignment management. | ||
*'''Issue 1384''': On the homepage, under the “Actions” column in the assignment list when a user (instructor orTA or admin) logs in and navigates to Manage -> Assignments(as shown below). | *'''Issue 1384''': On the homepage, under the “Actions” column in the assignment list when a user (instructor orTA or admin) logs in and navigates to Manage -> Assignments (as shown below). | ||
[[File:Goal_issue_1384.png]] | [[File:Goal_issue_1384.png]] | ||
Line 49: | Line 49: | ||
_general.html.erb | _general.html.erb | ||
assignment_creation_page_spec.rb | |||
instructor_interface_spec.rb | |||
== Modifications made w.r.t issue 1384 == | == Modifications made w.r.t issue 1384 == | ||
'''app/assets/javascripts/tree_display.jsx''' | ===='''app/assets/javascripts/tree_display.jsx'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
let app_variables = { | let app_variables = { | ||
Line 62: | Line 61: | ||
}; | }; | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
let app_variables = { | let app_variables = { | ||
Line 70: | Line 69: | ||
</pre> | </pre> | ||
... | ... | ||
Before: | |||
<pre> | <pre> | ||
jQuery(document).ready(function() { | jQuery(document).ready(function() { | ||
Line 80: | Line 80: | ||
}; | }; | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
jQuery(document).ready(function() { | jQuery(document).ready(function() { | ||
Line 91: | Line 91: | ||
</pre> | </pre> | ||
... | ... | ||
Before: | |||
<pre> | <pre> | ||
else if (newNodeType === 'assignments') { | else if (newNodeType === 'assignments') { | ||
Line 98: | Line 99: | ||
moreContent.push( | moreContent.push( | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
else if (newNodeType === 'assignments' && app_variables.homeActionShowFlag=='true') { | else if (newNodeType === 'assignments' && app_variables.homeActionShowFlag=='true') { | ||
Line 106: | Line 107: | ||
</pre> | </pre> | ||
'''app/controllers/profile_controller.rb''' | ===='''app/controllers/profile_controller.rb'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
end | end | ||
Line 116: | Line 117: | ||
ExpertizaLogger.error LoggerMessage.new(controller_name, @user.name, "An error occurred and your profile could not updated.", request) | ExpertizaLogger.error LoggerMessage.new(controller_name, @user.name, "An error occurred and your profile could not updated.", request) | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
end | end | ||
if @user.update_attributes(params[:user]) | if @user.update_attributes(params[:user]) | ||
ExpertizaLogger.info LoggerMessage.new(controller_name, @user.name, "Your profile was successfully updated.", request) | ExpertizaLogger.info LoggerMessage.new(controller_name, @user.name, "Your profile was successfully updated.", request) | ||
if params[:no_show_action] == 'not_show_actions' | if params[:no_show_action] == 'not_show_actions' | ||
@user.preference_home_flag = false | @user.preference_home_flag = false | ||
Line 133: | Line 133: | ||
</pre> | </pre> | ||
... | ... | ||
Before: | |||
<pre> | <pre> | ||
def user_params | def user_params | ||
Line 158: | Line 160: | ||
:institution_id) | :institution_id) | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
def user_params | def user_params | ||
Line 186: | Line 188: | ||
</pre> | </pre> | ||
'''app/controllers/user_controller.rb''' | ===='''app/controllers/user_controller.rb'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
def user_params | def user_params | ||
Line 213: | Line 215: | ||
end | end | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
def user_params | def user_params | ||
Line 241: | Line 243: | ||
</pre> | </pre> | ||
'''app/models/user.rb''' | ===='''app/models/user.rb'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
def initialize(attributes = nil) | def initialize(attributes = nil) | ||
Line 253: | Line 255: | ||
end | end | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
def initialize(attributes = nil) | def initialize(attributes = nil) | ||
Line 266: | Line 268: | ||
</pre> | </pre> | ||
... | ... | ||
Before: | |||
<pre> | <pre> | ||
def self.export(csv, _parent_id, options) | def self.export(csv, _parent_id, options) | ||
Line 281: | Line 284: | ||
end | end | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
def self.export(csv, _parent_id, options) | def self.export(csv, _parent_id, options) | ||
Line 298: | Line 301: | ||
</pre> | </pre> | ||
'''app/views/profile/edit.html.erb''' | ===='''app/views/profile/edit.html.erb'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
<%= render :partial => 'users/email' %> | <%= render :partial => 'users/email' %> | ||
Line 306: | Line 309: | ||
<%= render :partial => 'handle' %> | <%= render :partial => 'handle' %> | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
<%= render :partial => 'users/email' %> | <%= render :partial => 'users/email' %> | ||
Line 319: | Line 322: | ||
</pre> | </pre> | ||
'''app/views/tree_display/list.html.erb''' | ===='''app/views/tree_display/list.html.erb'''==== | ||
====Before | Before: | ||
<pre> | <pre> | ||
<h1>Manage content</h1> | <h1>Manage content</h1> | ||
Line 330: | Line 333: | ||
<div id="tree_display" params="#{@reactjsParams}" data-menu-item= '<%= "#{@currCtlr}" %>'></div> | <div id="tree_display" params="#{@reactjsParams}" data-menu-item= '<%= "#{@currCtlr}" %>'></div> | ||
</pre> | </pre> | ||
After: | |||
<pre> | <pre> | ||
<h1>Manage content</h1> | <h1>Manage content</h1> | ||
Line 340: | Line 343: | ||
<div id="tree_display" params="#{@reactjsParams}" data-user-id="<%= current_user.id %>" data-user-show="<%= current_user.preference_home_flag %>" data-menu-item= '<%= "#{@currCtlr}" %>'></div> | <div id="tree_display" params="#{@reactjsParams}" data-user-id="<%= current_user.id %>" data-user-show="<%= current_user.preference_home_flag %>" data-menu-item= '<%= "#{@currCtlr}" %>'></div> | ||
</pre> | </pre> | ||
.. | |||
==== | == Modifications made w.r.t issue 1430 == | ||
===='''app/helpers/assignment_helper.rb'''==== | |||
before: | |||
<pre> | <pre> | ||
module AssignmentHelper | |||
def course_options(instructor) | |||
if session[:user].role.name == 'Teaching Assistant' | |||
courses = [] | |||
ta = Ta.find(session[:user].id) | |||
ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } | |||
# If a TA created some courses before, s/he can still add new assignments to these courses. | |||
courses << Course.where(instructor_id: instructor.id) | |||
courses.flatten! | |||
# Administrator and Super-Administrator can see all courses | |||
elsif session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' | |||
courses = Course.all | |||
elsif session[:user].role.name == 'Instructor' | |||
courses = Course.where(instructor_id: instructor.id) | |||
# instructor can see courses his/her TAs created | |||
ta_ids = [] | |||
ta_ids << Instructor.get_my_tas(session[:user].id) | |||
ta_ids.flatten! | |||
ta_ids.each do |ta_id| | |||
ta = Ta.find(ta_id) | |||
ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } | |||
end | |||
end | |||
options = [] | |||
options << ['-----------', nil] | |||
courses.each do |course| | |||
options << [course.name, course.id] | |||
end | |||
options.uniq.sort | |||
end | |||
</pre> | </pre> | ||
after: | |||
<pre> | <pre> | ||
module AssignmentHelper | |||
def course_options(instructor) | |||
if session[:user].role.name == 'Teaching Assistant' | |||
courses = [] | |||
ta = Ta.find(session[:user].id) | |||
ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } | |||
# If a TA created some courses before, s/he can still add new assignments to these courses. | |||
courses << Course.where(instructor_id: ta.id) | |||
courses.flatten! | |||
# Administrator and Super-Administrator can see all courses | |||
elsif session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' | |||
courses = Course.all | |||
elsif session[:user].role.name == 'Instructor' | |||
courses = Course.where(instructor_id: instructor.id) | |||
# instructor can see courses his/her TAs created | |||
ta_ids = [] | |||
ta_ids << Instructor.get_my_tas(session[:user].id) | |||
ta_ids.flatten! | |||
ta_ids.each do |ta_id| | |||
ta = Ta.find(ta_id) | |||
ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } | |||
end | |||
end | |||
options = [] | |||
if session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' or session[:user].role.name == 'Instructor' | |||
options << ['-----------', nil] | |||
end | |||
courses.each do |course| | |||
options << [course.name, course.id] | |||
end | |||
options.uniq.sort | |||
end | |||
</pre> | |||
== Test == | |||
===='''spec/features/assignment_creation_page_spec.rb'''==== | |||
Added: | |||
<pre> | <pre> | ||
it "is able show tab Etc." do | |||
assignment_creation_setup(0,'public assignment for test') | |||
find_link('Etc.').click | |||
expect(page).to have_content("Create teams") | |||
end | |||
</pre> | </pre> | ||
==== | |||
===='''spec/features/instructor_interface_spec.rb'''==== | |||
Added: | |||
<pre> | <pre> | ||
describe "View Profile" do | |||
it 'should see profile add one new radio button for user preference' do | |||
login_as("instructor6") | |||
visit '/profile/edit' | |||
expect(page).to have_content("Action Preference") | |||
end | |||
end | |||
describe "View User Preference" do | |||
it 'should see user preference default button (home can show actions) is checked' do | |||
login_as("instructor6") | |||
visit '/profile/edit' | |||
expect(page).to have_content("Action Preference") | |||
choose "no_show_action_not_show_actions" | |||
click_button "Save" | |||
expect(User.where(name: 'instructor6').first.preference_home_flag).to eq(false) | |||
end | |||
end | |||
describe "View Assignment List" do | |||
it 'should not see user action buttons if user preference (home cannot show actions) is checked' do | |||
login_as("instructor6") | |||
visit '/profile/edit' | |||
expect(page).to have_content("Action Preference") | |||
choose "no_show_action_not_show_actions" | |||
click_button "Save" | |||
visit 'tree_display/list?currCtlr=Assignments' | |||
expect(page).to have_no_content("View submission") | |||
end | |||
end | |||
</pre> | </pre> | ||
== Results == | |||
==== | |||
==== Issue 1384 ==== | |||
Now in the user's (instructor or TA) profile page, we have two radio buttons to select from. If we choose not to show actions on the home page, and click 'save' at the bottom of the page: | |||
[[File:Action_pref.png]] | |||
Actions will not show up on the homepage as expected: | |||
[[File:No_show_on_homepage.png]] | |||
=== | ==== Issue 1430 ==== | ||
Now if we want to assign this final project to another course, we can open up the dropdown list can choose CSC 216 (for example), and click save. | |||
[[File:Change_assigned_course.png]] | |||
The action is successful. | |||
[[File:Change_assigned_course_result.png]] | |||
== Deployment == | |||
http://152.7.99.26:8080/ | |||
Instructor username: instructor6 | |||
Instructor password: password | |||
TA username: test_TA | |||
TA password: password | |||
== Other Known Issues == | |||
*On the assignment homepage, if you click on the blank area of an assignment, the 'edit' icon will dispear. This issue is not in the scope of this project. Reload to get it back. | |||
*Other user email preferences can not be properly updated when rendering to another form, also it's a pre-exsiting issue. |
Latest revision as of 21:53, 5 November 2020
Project Introduction
Expertiza has Assignment objects, which represent an assignment that is done by some number of users. This project enabled instructors or TAs to customize viewing preference and fixed two bugs in their assigment management process.
Team
Hao Zhang (hzhang62)
Zhuolin Li (zli82)
Lige Han (lhan6)
Project Goal
The goals of this project were to solve tow issues related to assignment management.
- Issue 1384: On the homepage, under the “Actions” column in the assignment list when a user (instructor orTA or admin) logs in and navigates to Manage -> Assignments (as shown below).
- It looks crowded and is easy to be misclicked by some users. The goal of this issue is to add a preference option in user's profile where they can choose wether to show or hide detailed actions on the assignment management homepage.
- Issue 1430:
- What is wrong:
- 1. A TA or an instructor can assign an assignment to any course even when they don't have access to the course.
- 2. TAs can unassign an assignment from the course, and if they do so, they lose access to the assignment.
- What needs to be done:
- 1. Only those courses should be shown in the dropdown list of courses, the assignment is part of and the instructor or TA has access to.
- 2. Instructors, but not TAs, would then be allowed to change an assignment to be part of no course.
Files Involved
tree_display.jsx
profile_controller.rb
users_controller.rb
user.rb
edit.html.erb
list.html.erb
assignment_helper.rb
_general.html.erb
assignment_creation_page_spec.rb
instructor_interface_spec.rb
Modifications made w.r.t issue 1384
app/assets/javascripts/tree_display.jsx
Before:
let app_variables = { currentUserId: null };
After:
let app_variables = { currentUserId: null, homeActionShowFlag: null };
...
Before:
jQuery(document).ready(function() { // This preloadedImages function is refered from http://jsfiddle.net/slashingweapon/8jAeu/ // Actually I am not using the values in preloadedImages, but image loading speed is indeed getting faster var preloadedImages = [] function preloadImages() { for (var idx = 0; idx < arguments.length; idx++) { };
After:
jQuery(document).ready(function() { // This preloadedImages function is refered from http://jsfiddle.net/slashingweapon/8jAeu/ // Actually I am not using the values in preloadedImages, but image loading speed is indeed getting faster var preloadedImages = [] function preloadImages() { for (var idx = 0; idx < arguments.length; idx++) { };
...
Before:
else if (newNodeType === 'assignments') { // Assignment tab starts here // Now is_intelligent and Add Manager related buttons have not been added into the new UI moreContent.push(
After:
else if (newNodeType === 'assignments' && app_variables.homeActionShowFlag=='true') { // Assignment tab starts here // Now is_intelligent and Add Manager related buttons have not been added into the new UI moreContent.push(
app/controllers/profile_controller.rb
Before:
end if @user.update_attributes(params[:user]) ExpertizaLogger.info LoggerMessage.new(controller_name, @user.name, "Your profile was successfully updated.", request) flash[:success] = 'Your profile was successfully updated.' else ExpertizaLogger.error LoggerMessage.new(controller_name, @user.name, "An error occurred and your profile could not updated.", request)
After:
end if @user.update_attributes(params[:user]) ExpertizaLogger.info LoggerMessage.new(controller_name, @user.name, "Your profile was successfully updated.", request) if params[:no_show_action] == 'not_show_actions' @user.preference_home_flag = false else @user.preference_home_flag = true end @user.save! flash[:success] = 'Your profile was successfully updated.' else ExpertizaLogger.error LoggerMessage.new(controller_name, @user.name, "An error occurred and your profile could not updated.", request)
...
Before:
def user_params params.require(:user).permit(:name, :crypted_password, :role_id, :password_salt, :fullname, :email, :parent_id, :private_by_default, :mru_directory_path, :email_on_review, :email_on_submission, :email_on_review_of_review, :is_new_user, :master_permission_granted, :handle, :digital_certificate, :persistence_token, :timezonepref, :public_key, :copy_of_emails, :institution_id)
After:
def user_params params.require(:user).permit(:name, :crypted_password, :role_id, :password_salt, :fullname, :email, :parent_id, :private_by_default, :mru_directory_path, :email_on_review, :email_on_submission, :email_on_review_of_review, :is_new_user, :master_permission_granted, :handle, :digital_certificate, :persistence_token, :timezonepref, :public_key, :copy_of_emails, :institution_id, :preference_home_flag) end
app/controllers/user_controller.rb
Before:
def user_params params.require(:user).permit(:name, :crypted_password, :role_id, :password_salt, :fullname, :email, :parent_id, :private_by_default, :mru_directory_path, :email_on_review, :email_on_submission, :email_on_review_of_review, :is_new_user, :master_permission_granted, :handle, :digital_certificate, :persistence_token, :timezonepref, :public_key, :copy_of_emails, :institution_id) end
After:
def user_params params.require(:user).permit(:name, :crypted_password, :role_id, :password_salt, :fullname, :email, :parent_id, :private_by_default, :mru_directory_path, :email_on_review, :email_on_submission, :email_on_review_of_review, :is_new_user, :master_permission_granted, :handle, :digital_certificate, :persistence_token, :timezonepref, :public_key, :copy_of_emails, :institution_id, :preference_home_flag) end
app/models/user.rb
Before:
def initialize(attributes = nil) super(attributes) Authlogic::CryptoProviders::Sha1.stretches = 1 @email_on_review = true @email_on_submission = true @email_on_review_of_review = true @copy_of_emails = false end
After:
def initialize(attributes = nil) super(attributes) Authlogic::CryptoProviders::Sha1.stretches = 1 @email_on_review = true @email_on_submission = true @email_on_review_of_review = true @copy_of_emails = false @preference_home_flag = true end
...
Before:
def self.export(csv, _parent_id, options) users = User.all users.each do |user| tcsv = [] tcsv.push(user.name, user.fullname, user.email) if options["personal_details"] == "true" tcsv.push(user.role.name) if options["role"] == "true" tcsv.push(user.parent.name) if options["parent"] == "true" tcsv.push(user.email_on_submission, user.email_on_review, user.email_on_review_of_review, user.copy_of_emails) if options["email_options"] == "true" tcsv.push(user.handle) if options["handle"] == "true" csv << tcsv end end
After:
def self.export(csv, _parent_id, options) users = User.all users.each do |user| tcsv = [] tcsv.push(user.name, user.fullname, user.email) if options["personal_details"] == "true" tcsv.push(user.role.name) if options["role"] == "true" tcsv.push(user.parent.name) if options["parent"] == "true" tcsv.push(user.email_on_submission, user.email_on_review, user.email_on_review_of_review, user.copy_of_emails) if options["email_options"] == "true" tcsv.push(user.handle) if options["handle"] == "true" tcsv.push(user.preference_home_flag) if options["preference_home_flag"] == "true" csv << tcsv end end
app/views/profile/edit.html.erb
Before:
<%= render :partial => 'users/email' %> <%= render :partial => 'users/institutions' %> <%= render :partial => 'users/prefs' %> <%= render :partial => 'handle' %>
After:
<%= render :partial => 'users/email' %> <%= render :partial => 'users/institutions' %> <%= render :partial => 'users/prefs' %> <p><strong>Action Preference<strong><p> <%= radio_button_tag(:no_show_action, 'not_show_actions',checked = @user.preference_home_flag ? false : true) %> <%= label_tag(:no_show_action, "homepage cannot show actions") %> <%= radio_button_tag(:no_show_action, 'show_actions', checked = @user.preference_home_flag) %> <%= label_tag(:no_show_action, "homepage can show actions") %> <%= render :partial => 'handle' %>
app/views/tree_display/list.html.erb
Before:
<h1>Manage content</h1> <%= link_to 'Manage Notifications', notifications_url %> <%# add data-user-id %> <%# associated with current logged in user %> <%# done to make it available in the frontend %> <div id="tree_display" params="#{@reactjsParams}" data-menu-item= '<%= "#{@currCtlr}" %>'></div>
After:
<h1>Manage content</h1> <%= link_to 'Manage Notifications', notifications_url %> <%# add data-user-id %> <%# associated with current logged in user %> <%# done to make it available in the frontend %> <div id="tree_display" params="#{@reactjsParams}" data-user-id="<%= current_user.id %>" data-user-show="<%= current_user.preference_home_flag %>" data-menu-item= '<%= "#{@currCtlr}" %>'></div>
Modifications made w.r.t issue 1430
app/helpers/assignment_helper.rb
before:
module AssignmentHelper def course_options(instructor) if session[:user].role.name == 'Teaching Assistant' courses = [] ta = Ta.find(session[:user].id) ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } # If a TA created some courses before, s/he can still add new assignments to these courses. courses << Course.where(instructor_id: instructor.id) courses.flatten! # Administrator and Super-Administrator can see all courses elsif session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' courses = Course.all elsif session[:user].role.name == 'Instructor' courses = Course.where(instructor_id: instructor.id) # instructor can see courses his/her TAs created ta_ids = [] ta_ids << Instructor.get_my_tas(session[:user].id) ta_ids.flatten! ta_ids.each do |ta_id| ta = Ta.find(ta_id) ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } end end options = [] options << ['-----------', nil] courses.each do |course| options << [course.name, course.id] end options.uniq.sort end
after:
module AssignmentHelper def course_options(instructor) if session[:user].role.name == 'Teaching Assistant' courses = [] ta = Ta.find(session[:user].id) ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } # If a TA created some courses before, s/he can still add new assignments to these courses. courses << Course.where(instructor_id: ta.id) courses.flatten! # Administrator and Super-Administrator can see all courses elsif session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' courses = Course.all elsif session[:user].role.name == 'Instructor' courses = Course.where(instructor_id: instructor.id) # instructor can see courses his/her TAs created ta_ids = [] ta_ids << Instructor.get_my_tas(session[:user].id) ta_ids.flatten! ta_ids.each do |ta_id| ta = Ta.find(ta_id) ta.ta_mappings.each {|mapping| courses << Course.find(mapping.course_id) } end end options = [] if session[:user].role.name == 'Administrator' or session[:user].role.name == 'Super-Administrator' or session[:user].role.name == 'Instructor' options << ['-----------', nil] end courses.each do |course| options << [course.name, course.id] end options.uniq.sort end
Test
spec/features/assignment_creation_page_spec.rb
Added:
it "is able show tab Etc." do assignment_creation_setup(0,'public assignment for test') find_link('Etc.').click expect(page).to have_content("Create teams") end
spec/features/instructor_interface_spec.rb
Added:
describe "View Profile" do it 'should see profile add one new radio button for user preference' do login_as("instructor6") visit '/profile/edit' expect(page).to have_content("Action Preference") end end describe "View User Preference" do it 'should see user preference default button (home can show actions) is checked' do login_as("instructor6") visit '/profile/edit' expect(page).to have_content("Action Preference") choose "no_show_action_not_show_actions" click_button "Save" expect(User.where(name: 'instructor6').first.preference_home_flag).to eq(false) end end describe "View Assignment List" do it 'should not see user action buttons if user preference (home cannot show actions) is checked' do login_as("instructor6") visit '/profile/edit' expect(page).to have_content("Action Preference") choose "no_show_action_not_show_actions" click_button "Save" visit 'tree_display/list?currCtlr=Assignments' expect(page).to have_no_content("View submission") end end
Results
Issue 1384
Now in the user's (instructor or TA) profile page, we have two radio buttons to select from. If we choose not to show actions on the home page, and click 'save' at the bottom of the page:
Actions will not show up on the homepage as expected:
Issue 1430
Now if we want to assign this final project to another course, we can open up the dropdown list can choose CSC 216 (for example), and click save.
The action is successful.
Deployment
Instructor username: instructor6
Instructor password: password
TA username: test_TA
TA password: password
Other Known Issues
- On the assignment homepage, if you click on the blank area of an assignment, the 'edit' icon will dispear. This issue is not in the scope of this project. Reload to get it back.
- Other user email preferences can not be properly updated when rendering to another form, also it's a pre-exsiting issue.