CSC/ECE 517 Spring 2024 - E2417. Reimplement submitted content controller.rb
E2417. Reimplement Submitted Content Controller
This page provides a description of the Expertiza based OSS Project E2417. Reimplement the SubmittedContentController
About Expertiza
Expertiza is an open-source web application facilitating peer feedback and assessment in educational courses. It enables students to submit work, review peers' submissions, and receive feedback. The platform supports anonymous peer reviews, grading rubrics, and discussion forums. Its goal is to enhance collaborative learning and improve the quality of student work through constructive criticism.
Objective
A submitted content controller should have the functionalities to manage the submitted content, for eg, the CRUD operations for submissions, different types of submissions, etc. The goal here is to implement this controller via API's and use principles of Object-Oriented Programming such as SOLID.
Problem Description
The reimplementation of SubmittedContentController in Expertiza needs to be done to enhance its functionality and maintainability. It should handle various tasks like file submissions and uploads, hyperlink submissions, and downloads, but the controller suffers from code redundancy and mixed responsibilities within methods. The reimplementation aims to ensure participants receive appropriate messages and HTTP status codes for actions like uploading files and deleting them, while also using SOLID principles, refactoring DRY code and minimizing excessive use of instance variables. The goal is to optimize the controller's design, adhering to best practices in readability and modularity.
Improvements in New Code
Index, show and create operations have been performed for the submission content controller.
- Index method for Submitted Content
- Show method for Submitted Content
- Create method to Submit Content
- SignedUpTopic Model
- SignedUpTeam Model
- SubmissionRecord Model
- Duty Model
- Late Policy Model
- Submitted Content Helper
Index method for Submitted Content
def index @submission_record = SubmissionRecord.all render json: @submission_record, status: :ok end
The index function is responsible for retrieving the data for the users. This function serves to fetch all submission records from the database using the `SubmissionRecord` model and assigns them to an instance variable `@submission_record`. The status: :ok parameter ensures that the HTTP response status is set to 200, indicating a successful request. This function operates on the HTTP GET method, allowing clients to request information from the server. The rendered JSON response includes the submission records, providing comprehensive data to clients.
Show method for Submitted Content
def show @submission_record = SubmissionRecord.find(params[:id]) render json: @submission_record, status: :ok rescue ActiveRecord::RecordNotFound => e render json: { error: e.message }, status: :not_found end
The show function enables clients to retrieve detailed information about specific submission records stored in the backend database and operates on HTTP GET method. The function retrieves the submission record associated with the provided ID using the SubmissionRecord.find(params[:id]) query. If the record is found, it is serialized into JSON format using the render method. If the record is not found, it renders a JSON response containing an error message conveying the exception's details, alongside an appropriate HTTP status code of :not_found (404).
Create method to Submit Content
def create @submission_record = SubmissionRecord.create(submitted_content_params) if @submission_record.save render json: @submission_record, status: :created else render json: @submission_record.errors, status: :unprocessable_entity end end
The create function facilitates the creation of new submission records using HTTP POST method. The function initializes a new SubmissionRecord instance by passing the submitted content parameters obtained from the client to the SubmissionRecord.create method. If the record is successfully saved, indicating that the submission was processed without errors, the function renders a JSON response containing the newly created submission record along with an HTTP status code of :created (201), signifying successful record creation. If not, it renders a JSON response containing the errors encountered during the submission attempt, along with an appropriate HTTP status code of :unprocessable_entity (422), indicating that it cannot process it due to validation errors.
SignedUpTeam Model
The SignedUpTeam model represents the association between a topic and a team in the Expertiza project. Each instance of SignedUpTeam signifies that a particular team has signed up for a specific topic. This model facilitates the management and validation of these associations. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class SignedUpTeam < ApplicationRecord validates :topic_id, :team_id, presence: true scope :by_team_id, ->(team_id) { where('team_id = ?', team_id) } end
SignedUpTopic Model
The SignUpTopic model in the Expertiza project manages topics that users can sign up for within specific assignments. It provides functionalities for topic creation, modification, and retrieval. Additionally, it handles the association between topics and various other entities such as teams, due dates, bids, and assignment questionnaires. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class SignUpTopic < ApplicationRecord validates :topic_name, :assignment_id, :max_choosers, presence: true validates :topic_identifier, length: { maximum: 10 } end
SubmissionRecord Model
The SubmissionRecord model in the Expertiza project manages records of submissions made by users for specific assignments. It ensures that essential attributes related to the submission, such as content, operation, team ID, user, and assignment ID, are present through validations. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class SubmissionRecord < ApplicationRecord validates :content, presence: true validates :operation, presence: true validates :team_id, presence: true validates :user, presence: true validates :assignment_id, presence: true end
Participant Model
Participant model is implemented in association with user submitting an assignment. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class Participant < ApplicationRecord validates :grade, numericality: { allow_nil: true } end
Assignment Model
Assignment model handles the assignment submission. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class Assignment < ApplicationRecord end
Assignment Participant Model
The AssignmentParticipant model extends the functionality of the Participant model, providing additional features and associations specific to assignments. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class AssignmentParticipant < Participant validates :handle, presence: true end
SignUpSheet Model
The SignUpSheet model handles the signing up of users for topics within assignments. It provides methods for managing teams, confirming topics, adding signup topics, and importing signup data. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class SignUpSheet < ApplicationRecord end
Team Model
The Team model facilitates the management of teams. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class Team < ApplicationRecord end
Team User Model
The TeamUserNode model represents nodes in a tree structure associated with team users. This model is used by the Submitted Content Control so a skeleton for the same was implemented in this phase of the project.
class TeamsUser < ApplicationRecord end
Duty Model
The Duty model in the Expertiza project manages duties assigned to individuals within teams. It validates the attributes of duties, including their names and maximum member counts, and provides a method for determining whether a duty can be assigned to a particular team. The Submitted Content Controller has an indirect dependency on this model. This model will be implemented in the next phase of the project.
Late Policy Model
The LatePolicy model in the Expertiza project manages late submission policies. It associates late policies with assignments. The model provides validations for policy attributes and methods for checking policy names and updating penalty objects when policies are modified. The Submitted Content Controller has an indirect dependency on this model. This model will be implemented in the next phase of the project.
Submitted Content Helper
The SubmittedContentHelper module facilitates the unzipping of files, aiding in the management of uploaded content within web applications. Its unzip_file method efficiently extracts the contents of a zip file to a specified directory, ensuring reliability. By leveraging the RubyZip gem, this module helps in the process of handling zip files, enhancing the backend's functionality.
Original Code
module SubmittedContentHelper # Installing RubyZip # run the command, gem install rubyzip # restart the server def self.unzip_file(file_name, unzip_dir, should_delete) # Checking if file exists. raise "File #{file_name} does not exist" unless File.exist?(file_name) # begin Zip::File.open(file_name) do |zf| zf.each do |e| safename = FileHelper.sanitize_filename(e.name) fpath = File.join(unzip_dir, safename) FileUtils.mkdir_p(File.dirname(fpath)) zf.extract(e, fpath) end end if should_delete # The zip file is no longer needed, so delete it File.delete(file_name) end end end
Refactored Code
module SubmittedContentHelper # Installing RubyZip # run the command, gem install rubyzip # restart the server def self.unzip_file(file_name, unzip_dir, should_delete) # Checking if file exists. raise "File #{file_name} does not exist" unless File.exist?(file_name) # begin Zip::File.open(file_name) do |zf| zf.each do |e| extract_entry(e, unzip_dir) end end if should_delete # The zip file is no longer needed, so delete it File.delete(file_name) end end private def extract_entry(e, unzip_dir) safename = FileHelper.sanitize_filename(e.name) fpath = File.join(unzip_dir, safename) FileUtils.mkdir_p(File.dirname(fpath)) zf.extract(e, fpath) end end
In the previous code, to extract files, it was tightly coupled with the unzip_files method, making it less reusable and harder to maintain. After refactoring the code, a separate private method is formed to unzip the file. By separating the extract_entry function into its own module or file, each component now has a single responsibility: the extract_entry function is responsible solely for extracting a single entry from a zip file. Single Responsibility Principle is followed.
Deployment Link
http://152.7.177.13:3000/api-docs
- Credentials:
Username: admin Password: admin
Note: The authorization has been skipped to ensure smooth testing.
Github Repo
https://github.com/Neel317/reimplementation-back-end
PR Link
https://github.com/expertiza/reimplementation-back-end/pull/78/files