Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions app/controllers/account_requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ def processed_requests
def create
@account_request = AccountRequest.new(account_request_params)
if @account_request.save
# Check if username already exists in Users table
if User.exists?(username: @account_request.username)
render json: { error: 'Username already exists in the system' }, status: :unprocessable_entity
return
end
response = { account_request: @account_request }
if User.find_by(email: @account_request.email)
response[:warnings] = 'WARNING: User with this email already exists!'
Expand Down Expand Up @@ -81,11 +86,16 @@ def account_request_params

# Create a new user if account request is approved
def create_approved_user
# Check for BOTH email and username duplicates in the Users table
if User.exists?(email: @account_request.email)
render json: { error: 'A user with this email already exists. Cannot approve the account request.' }, status: :unprocessable_entity
render json: { error: 'A user with this email already exists.' }, status: :unprocessable_entity
return
end
if User.exists?(username: @account_request.username)
render json: { error: 'A user with this username already exists.' }, status: :unprocessable_entity
return
end
@new_user = User.new(name: @account_request.username, role_id: @account_request.role_id, institution_id: @account_request.institution_id, full_name: @account_request.full_name, email: @account_request.email, password: 'password')
@new_user = User.new(username: @account_request.username, role_id: @account_request.role_id, institution_id: @account_request.institution_id, full_name: @account_request.full_name, email: @account_request.email, password: 'password')
if @new_user.save
render json: { success: 'Account Request Approved and User successfully created.', user: @new_user}, status: :ok
else
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/authentication_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class AuthenticationController < ApplicationController

# POST /login
def login
user = User.find_by(name: params[:user_name]) || User.find_by(email: params[:user_name])
user = User.find_by(username: params[:user_name]) || User.find_by(email: params[:user_name])
if user&.authenticate(params[:password])
payload = { id: user.id, name: user.name, full_name: user.full_name, role: user.role.name,
institution_id: user.institution.id }
Expand Down
8 changes: 4 additions & 4 deletions app/controllers/bookmarks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def destroy
def get_bookmark_rating_score
begin
@bookmark = Bookmark.find(params[:id])
@bookmark_rating = BookmarkRating.where(bookmark_id: @bookmark.id, user_id: @current_user.id).first
@bookmark_rating = BookmarkRating.where(artifact_id: @bookmark.id, rater_id: @current_user.id).first
render json: @bookmark_rating, status: :ok and return
rescue ActiveRecord::RecordNotFound
render json: $ERROR_INFO.to_s, status: :not_found and return
Expand All @@ -79,11 +79,11 @@ def get_bookmark_rating_score
# POST on /bookmarks/:id/bookmarkratings
def save_bookmark_rating_score
@bookmark = Bookmark.find(params[:id])
@bookmark_rating = BookmarkRating.where(bookmark_id: @bookmark.id, user_id: @current_user.id).first
@bookmark_rating = BookmarkRating.where(artifact_id: @bookmark.id, rater_id: @current_user.id).first
if @bookmark_rating.blank?
@bookmark_rating = BookmarkRating.create(bookmark_id: @bookmark.id, user_id: @current_user.id, rating: params[:rating])
@bookmark_rating = BookmarkRating.create(artifact_id: @bookmark.id, rater_id: @current_user.id, ratings: params[:rating])
else
@bookmark_rating.update({'rating': params[:rating].to_i})
@bookmark_rating.update(ratings: params[:rating].to_i)
end
render json: {"bookmark": @bookmark, "rating": @bookmark_rating}, status: :ok
end
Expand Down
8 changes: 4 additions & 4 deletions app/controllers/grades_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def get_review_tableau_data

response_mapping_condition = "reviewed_object_id = " + params[:assignment_id] + " AND reviewer_id = " + params[:participant_id]
ReviewResponseMap.where(response_mapping_condition).find_each do |mapping|
Response.where("map_id = " + mapping[:id].to_s).find_each do |response|
Response.where("response_map_id = " + mapping[:id].to_s).find_each do |response|

# response = Response.find_by(map_id: mapping[:id])

Expand Down Expand Up @@ -203,11 +203,11 @@ def instructor_review
reviewee_id: @team.id
)

existing_response = Response.find_by(map_id: mapping.id)
existing_response = Response.find_by(response_map_id: mapping.id)
action = existing_response.present? ? 'edit' : 'new'

render json: {
map_id: mapping.id,
response_map_id: mapping.id,
response_id: existing_response&.id,
redirect_to: "/response/#{action}/#{mapping.id}"
}
Expand Down Expand Up @@ -323,7 +323,7 @@ def get_heatgrid_data_for(maps)
maps.each_with_index do |map, index|
# Find the most recent submitted response for the current round
submitted_round_response = map.responses.select do |r|
r.round == round && r.is_submitted && r.map_id == map.id
r.round == round && r.is_submitted && r.response_map_id == map.id
end.last

# Skip if no valid response was submitted
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/invitations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def inviter_team
end

def invitee_participant
invitee_user = User.find_by(name: params[:username])|| User.find_by(email: params[:username])
invitee_user = User.find_by(username: params[:username])|| User.find_by(email: params[:username])
unless invitee_user
render json: { error: "Participant with username #{params[:username]} not found" }, status: :not_found
return
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/participants_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ def destroy
def participant_params
params.require(:participant).permit(:user_id, :assignment_id, :authorization, :can_submit,
:can_review, :can_take_quiz, :can_mentor, :handle,
:team_id, :join_team_request_id, :permission_granted,
:topic, :current_stage, :stage_deadline)
:team_id, :join_team_request_id, :topic,
:current_stage, :stage_deadline)
end

private
Expand Down
9 changes: 4 additions & 5 deletions app/controllers/submitted_content_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def create
if record.save
render json: record, status: :created
else
render json: record.errors, status: :unprocessable_content
render json: record.errors, status: :unprocessable_entity
end
end

Expand Down Expand Up @@ -331,7 +331,7 @@ def ensure_participant_team
# Strong parameters for submission record creation
def submitted_content_params
# Permit only specified attributes for security
params.require(:submitted_content).permit(:id, :content, :operation, :team_id, :user, :assignment_id, :record_type)
params.require(:submitted_content).permit(:id, :content, :operation, :team_id, :submitted_by, :record_type)
end

# Returns the participant's team (local method, no instance variable caching)
Expand All @@ -342,7 +342,7 @@ def participant_team
end

# Renders an error response with the given message and HTTP status
def render_error(message, status = :unprocessable_content)
def render_error(message, status = :unprocessable_entity)
# Render JSON error response with specified status code
render json: { error: message }, status: status
end
Expand Down Expand Up @@ -371,9 +371,8 @@ def create_submission_record_for(record_type, content, operation)
SubmissionRecord.create!(
record_type: record_type, # 'file' or 'hyperlink'
content: content, # File path or URL
user: @participant.user_name, # Username from participant
submitted_by: @participant.user_name, # Username from participant
team_id: @participant.team_id, # Team ID from participant
assignment_id: @participant.assignment_id, # Assignment ID from participant
operation: operation # Operation description (e.g., 'Submit File')
)
end
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/teams_participants_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def list_participants
# Adds Participant to a team
def add_participant
# First Check if Participant exists
# Look up the User record based on the provided name parameter.
user = User.find_by(name: params[:name].strip) || (render(json: { error: "User not found" }, status: :not_found) and return)
# Look up the User record based on the provided username parameter.
user = User.find_by(username: params[:name].strip) || (render(json: { error: "User not found" }, status: :not_found) and return)
# Find the Participant associated with the user, or return not found error
participant = Participant.find_by(user_id: user.id) || (render(json: { error: "Couldn't find Participant" }, status: :not_found) and return)

Expand Down
2 changes: 1 addition & 1 deletion app/models/assignment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Assignment < ApplicationRecord
has_many :response_maps, foreign_key: 'reviewed_object_id', dependent: :destroy, inverse_of: :assignment
has_many :review_mappings, class_name: 'ReviewResponseMap', foreign_key: 'reviewed_object_id', dependent: :destroy, inverse_of: :assignment
has_many :project_topics , class_name: 'ProjectTopic', foreign_key: 'assignment_id', dependent: :destroy
has_many :due_dates,as: :parent, class_name: 'DueDate', dependent: :destroy
has_many :due_dates, class_name: 'DueDate', foreign_key: 'assignment_id', dependent: :destroy
has_many :assignments_duties, dependent: :destroy
has_many :duties, through: :assignments_duties
belongs_to :course, optional: true
Expand Down
4 changes: 2 additions & 2 deletions app/models/bookmark_rating.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class BookmarkRating < ApplicationRecord
belongs_to :bookmark
belongs_to :user
belongs_to :bookmark, foreign_key: 'artifact_id'
belongs_to :user, foreign_key: 'rater_id'
end
2 changes: 1 addition & 1 deletion app/models/dropdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class Dropdown < UnscoredItem
include QuestionHelper

self.inheritance_column = nil
attr_accessor :txt, :type, :count, :weight
def edit(count)
edit_common("Item #{count}:", txt , weight, type).to_json
Expand Down
19 changes: 12 additions & 7 deletions app/models/due_date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ class DueDate < ApplicationRecord
LATE_ALLOWED = 2
NOT_ALLOWED = 1

belongs_to :parent, polymorphic: true
belongs_to :parent, polymorphic: true, foreign_key: 'assignment_id'
belongs_to :assignment, foreign_key: 'assignment_id', optional: true
validate :due_at_is_valid_datetime
validates :due_at, presence: true

Expand All @@ -30,8 +31,8 @@ def self.sort_due_dates(due_dates)
end

# Fetches all due dates for the parent Assignment or Topic
def self.fetch_due_dates(parent_id)
due_dates = where('parent_id = ?', parent_id)
def self.fetch_due_dates(assignment_id)
due_dates = where(assignment_id: assignment_id)
sort_due_dates(due_dates)
end

Expand All @@ -42,21 +43,25 @@ def self.any_future_due_dates?(due_dates)

def set(deadline, assignment_id, max_round)
self.deadline_type_id = deadline
self.parent_id = assignment_id
self.assignment_id = assignment_id
self.round = max_round
save
end

# Fetches due dates from parent then selects the next upcoming due date
def self.next_due_date(parent_id)
due_dates = fetch_due_dates(parent_id)
def self.next_due_date(assignment_id)
due_dates = fetch_due_dates(assignment_id)
due_dates.find { |due_date| due_date.due_at > Time.zone.now }
end

# Creates duplicate due dates and assigns them to a new assignment
def copy(new_assignment_id)
new_due_date = dup
new_due_date.parent_id = new_assignment_id
new_due_date.assignment_id = new_assignment_id
new_due_date.save
end

def parent_id
assignment_id
end
end
1 change: 1 addition & 0 deletions app/models/question_advice.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

class QuestionAdvice < ApplicationRecord
self.table_name = 'question_advice'
belongs_to :item
def self.export_fields(_options)
QuestionAdvice.columns.map(&:name)
Expand Down
1 change: 1 addition & 0 deletions app/models/quiz_question_choice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

class QuizQuestionChoice < ApplicationRecord
belongs_to :item, dependent: :destroy
alias_attribute :iscorrect, :is_correct
end
4 changes: 2 additions & 2 deletions app/models/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Response < ApplicationRecord
include ScorableHelper
include MetricHelper

belongs_to :response_map, class_name: 'ResponseMap', foreign_key: 'map_id', inverse_of: false
belongs_to :response_map, class_name: 'ResponseMap', foreign_key: 'response_map_id', inverse_of: false
has_many :scores, class_name: 'Answer', foreign_key: 'response_id', dependent: :destroy, inverse_of: false

alias map response_map
Expand Down Expand Up @@ -43,7 +43,7 @@ def reportable_difference?
assignment_questionnaire = AssignmentQuestionnaire.find_by(assignment_id: assignment.id, questionnaire_id: questionnaire.id)

# notification_limit can be specified on 'Rubrics' tab on assignment edit page.
allowed_difference_percentage = assignment_questionnaire.notification_limit.to_f
allowed_difference_percentage = assignment_questionnaire.notification_threshold.to_f

# the range of average_score_on_same_artifact_from_others and score is [0,1]
# the range of allowed_difference_percentage is [0, 100]
Expand Down
6 changes: 3 additions & 3 deletions app/models/scale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
class Scale < ScoredItem
include QuestionHelper

attr_accessor :txt, :type, :weight, :min_label, :max_label, :answer, :min_question_score, :max_question_score
attr_accessor :txt, :question_type, :weight, :min_label, :max_label, :answer, :min_question_score, :max_question_score

def edit
edit_common('Item:', min_question_score, max_question_score , txt, weight, type).to_json
edit_common('Item:', min_question_score, max_question_score , txt, weight, question_type).to_json
end

def view_item_text
view_item_text_common(txt, type, weight, score_range).to_json
view_item_text_common(txt, question_type, weight, score_range).to_json
end

def complete
Expand Down
4 changes: 1 addition & 3 deletions app/models/student_task.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

class StudentTask
attr_accessor :assignment, :current_stage, :participant, :stage_deadline, :topic, :permission_granted
attr_accessor :assignment, :current_stage, :participant, :stage_deadline, :topic

# Initializes a new instance of the StudentTask class
def initialize(args)
Expand All @@ -10,7 +10,6 @@ def initialize(args)
@participant = args[:participant]
@stage_deadline = args[:stage_deadline]
@topic = args[:topic]
@permission_granted = args[:permission_granted]
end

# create a new StudentTask instance from a Participant object.cccccccc
Expand All @@ -20,7 +19,6 @@ def self.create_from_participant(participant)
topic: participant.topic, # Current stage of the assignment process
current_stage: participant.current_stage, # Participant object
stage_deadline: parse_stage_deadline(participant.stage_deadline), # Deadline for the current stage of the assignment
permission_granted: participant.permission_granted, # Topic of the assignment
participant: participant # Boolean indicating if Publishing Rights is enabled
)
end
Expand Down
3 changes: 1 addition & 2 deletions app/models/submission_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ 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
validates :submitted_by, presence: true

scope :files, -> { where(record_type: 'file') }
scope :hyperlinks, -> { where(record_type: 'hyperlink') }
Expand Down
20 changes: 13 additions & 7 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@
class User < ApplicationRecord
has_secure_password
after_initialize :set_defaults
alias_attribute :full_name, :name

# 2. Instead of alias_attribute for 'name', use explicit methods
# This prevents 'full_name' from accidentally following the 'name' alias
def name
self[:username]
end

def name=(value)
self[:username] = value
end
# name must be lowercase and unique
validates :name, presence: true, uniqueness: true, allow_blank: false
# format: { with: /\A[a-z]+\z/, message: 'must be in lowercase' }
Expand Down Expand Up @@ -126,26 +136,22 @@ def self.from_params(params)
# that only the id, name, and email attributes should be included when a User object is serialized.
def as_json(options = {})
super(options.merge({
only: %i[id name email full_name email_on_review email_on_submission
email_on_review_of_review],
only: %i[id username email full_name],
include:
{
role: { only: %i[id name] },
parent: { only: %i[id name] },
parent: { only: %i[id username] },
institution: { only: %i[id name] }
}
})).tap do |hash|
hash['parent'] ||= { id: nil, name: nil }
hash['parent'] ||= { id: nil, username: nil }
hash['institution'] ||= { id: nil, name: nil }
end
end

def set_defaults
self.is_new_user = true
self.copy_of_emails ||= false
self.email_on_review ||= false
self.email_on_submission ||= false
self.email_on_review_of_review ||= false
self.etc_icons_on_homepage ||= true
end

Expand Down
2 changes: 1 addition & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def self.preview_path=(_)
module Reimplementation
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
config.load_defaults 8.0
config.active_record.schema_format = :ruby

# Configuration for the application, engines, and railties goes here.
Expand Down
Loading
Loading