Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4b6a39d
Initial commit
DevPatel1106 Mar 23, 2026
65d70f2
Merge branch 'expertiza:main' into Reimp-Quiz
DevPatel1106 Mar 23, 2026
04f6686
Task ordering queue logic
MaybeNotArnav Mar 23, 2026
24e23cd
Added controller methods
DevPatel1106 Mar 23, 2026
79d405b
Refactor Task_gen_flow & student_task endpoints
DevPatel1106 Mar 25, 2026
375cbbc
Refactored TaskQueue and finished controller logic
MaybeNotArnav Mar 28, 2026
ec32bdd
Written some test cases but some of them fail.
akhilkumar2004 Mar 29, 2026
083259b
finished writing all the necessary test cases and running them. all o…
akhilkumar2004 Mar 29, 2026
1033a52
tested the student tasks controller and duties task controller
akhilkumar2004 Mar 29, 2026
490f789
finished testing all the required files!
akhilkumar2004 Mar 29, 2026
a564a62
added a test file for quiz_task and improved the line coverage for re…
akhilkumar2004 Mar 30, 2026
6a3bb7c
Added comments
DevPatel1106 Mar 30, 2026
af4664c
Merge branch 'Reimp-Quiz' into feature/test-cases
DevPatel1106 Mar 30, 2026
6d0871f
Merge pull request #5 from DevPatel1106/feature/test-cases
DevPatel1106 Mar 30, 2026
5bf44c9
Revert "Merge pull request #5 from DevPatel1106/feature/test-cases"
DevPatel1106 Mar 30, 2026
b201645
Clean Routes changes
DevPatel1106 Mar 30, 2026
360a3bf
redid all the test cases as all my test cases were under the test fil…
akhilkumar2004 Mar 30, 2026
177b930
Merge branch 'Reimp-Quiz' into feature/test-cases
DevPatel1106 Mar 31, 2026
e8cb549
updated the test cases
akhilkumar2004 Apr 26, 2026
ab08ded
Verify that the test cases have been passed.
akhilkumar2004 Apr 28, 2026
77f2e4e
Commit a new version of DangerFile to fix the CI errors.
akhilkumar2004 Apr 28, 2026
eba142d
Update Dangerfile
akhilkumar2004 Apr 28, 2026
02a1c56
Update Dangerfile
akhilkumar2004 Apr 28, 2026
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
Binary file added .DS_Store
Binary file not shown.
12 changes: 6 additions & 6 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ Style/FrozenStringLiteralComment:
Metrics/BlockLength:
Max: 120
Exclude:
- 'db/**/*.rb'
- "db/**/*.rb"

Metrics/MethodLength:
Max: 20
Exclude:
- 'db/**/*.rb'
Max: 20
Exclude:
- "db/**/*.rb"

Metrics/AbcSize:
Max: 20
Exclude:
- 'db/**/*.rb'
- "db/**/*.rb"
Style/StringLiterals:
Enabled: true
EnforcedStyle: single_quotes
Exclude:
- 'db/**/*.rb'
- "db/**/*.rb"
10 changes: 9 additions & 1 deletion Dangerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Helper to safely read files in UTF-8 and avoid "invalid byte sequence" errors
def safe_read(path)
File.read(path, encoding: "UTF-8", invalid: :replace, undef: :replace)
return "" unless File.exist?(path)

File.open(path, "rb") do |f|
f.read
.force_encoding("UTF-8")
.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
end
rescue
""
end

# --- PR Size Checks ---
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ application up and running.

Things you may want to cover:

* Ruby version - 3.4.5
- Ruby version - 3.4.5

## Development Environment

### Prerequisites

- Verify that [Docker Desktop](https://www.docker.com/products/docker-desktop/) is installed and running.
- [Download](https://www.jetbrains.com/ruby/download/) RubyMine
- Make sure that the Docker plugin [is enabled](https://www.jetbrains.com/help/ruby/docker.html#enable_docker).


### Instructions

Tutorial: [Docker Compose as a remote interpreter](https://www.jetbrains.com/help/ruby/using-docker-compose-as-a-remote-interpreter.html)

### Video Tutorial
Expand All @@ -25,5 +26,6 @@ Tutorial: [Docker Compose as a remote interpreter](https://www.jetbrains.com/hel
alt="IMAGE ALT TEXT HERE" width="560" height="315" border="10" /></a>

### Database Credentials

- username: root
- password: expertiza
Binary file added app/.DS_Store
Binary file not shown.
4 changes: 3 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
class ApplicationController < ActionController::API
include Authorization
include JwtToken

prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create] # changed from prepend_before_action
Comment on lines +12 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify set_response and find_and_authorize_map_for_create are only defined in ResponsesController
echo "=== Checking where set_response is defined ==="
rg -n "def set_response" app/controllers/

echo "=== Checking where find_and_authorize_map_for_create is defined ==="
rg -n "def find_and_authorize_map_for_create" app/controllers/

echo "=== List all controllers that would be affected ==="
fd -e rb . app/controllers/ | wc -l

Repository: expertiza/reimplementation-back-end

Length of output: 394


🏁 Script executed:

#!/bin/bash
# Check the actual content of application_controller.rb around lines 12-13
echo "=== Content of application_controller.rb ==="
cat -n app/controllers/application_controller.rb | head -20

echo -e "\n=== Verify these methods don't exist in any other controller ==="
echo "Checking all controller files for set_response or find_and_authorize_map_for_create:"
rg -l "def set_response|def find_and_authorize_map_for_create" app/controllers/

echo -e "\n=== Check if ResponsesController only_calls these callbacks or defines them ==="
rg -B 2 -A 5 "def set_response" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 1272


Critical: These callbacks are not defined in ApplicationController and will break other controllers.

set_response and find_and_authorize_map_for_create are defined only in ResponsesController (line 64 and 69 respectively). Adding these callbacks to ApplicationController will cause NoMethodError for every other controller's show, update, and create actions.

Move these callbacks to ResponsesController only:

Proposed fix

Remove from ApplicationController:

-  prepend_before_action :set_response, only: %i[show update]
-  before_action :find_and_authorize_map_for_create, only: %i[create]

Add to ResponsesController:

prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create] # changed from prepend_before_action
🧰 Tools
🪛 RuboCop (1.86.1)

[convention] 13-13: Unnecessary spacing detected.

(Layout/ExtraSpacing)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/application_controller.rb` around lines 12 - 13, The new
callbacks prepend_before_action :set_response and before_action
:find_and_authorize_map_for_create were added to ApplicationController but the
methods set_response and find_and_authorize_map_for_create are defined only in
ResponsesController and will raise NoMethodError in other controllers; remove
those two callback lines from ApplicationController and instead add them inside
ResponsesController (use prepend_before_action :set_response, only: %i[show
update] and before_action :find_and_authorize_map_for_create, only: %i[create])
so the callbacks live with the methods they call.


before_action :authorize

end
115 changes: 115 additions & 0 deletions app/controllers/responses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

class ResponsesController < ApplicationController
prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create]
Comment on lines +3 to +5

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify ApplicationController callback definitions
rg -n "before_action.*set_response|before_action.*find_and_authorize" app/controllers/application_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 253


Remove duplicate callback definitions inherited from ApplicationController.

ApplicationController already defines these callbacks (lines 12-13). Since ResponsesController extends it, redefining them here is redundant and may cause callbacks to execute in unexpected order or multiple times.

Delete lines 3-4 and rely on the inherited definitions from the parent class.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 3 - 5, Remove the
duplicate before_action callbacks in ResponsesController: delete the
prepend_before_action :set_response, only: %i[show update] and before_action
:find_and_authorize_map_for_create, only: %i[create] lines so the controller
relies on the inherited callbacks defined in ApplicationController; ensure no
other local callback definitions remain that would reintroduce duplication for
set_response or find_and_authorize_map_for_create.


def action_allowed?
case action_name
when "create"
true # auth already handled by prepend_before_action above
when "show", "update"
@response && @response.map.reviewer.user_id == current_user.id
else
true
end
end

def show
render json: {
response_id: @response.id,
map_id: @response.map_id,
task_type: @response.map.type,
submitted: @response.is_submitted,
additional_comment: @response.additional_comment
}
end

def create
return unless enforce_task_order!(@map)

round = (params[:round].presence || 1).to_i
response = Response.where(map_id: @map.id, round: round)
.order(:created_at)
.last || Response.new(map_id: @map.id, round: round)
Comment on lines +32 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential race condition in response selection/creation.

The pattern of where(...).last || new(...) followed by save isn't atomic. Under concurrent requests, two processes could both find no existing response, both create new ones, and save duplicates.

Consider using find_or_create_by with a unique constraint or locking:

♻️ Suggested fix
-    response = Response.where(map_id: `@map.id`, round: round)
-                       .order(:created_at)
-                       .last || Response.new(map_id: `@map.id`, round: round)
+    response = Response.find_or_initialize_by(map_id: `@map.id`, round: round)

Or with database-level uniqueness constraint on (map_id, round).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
response = Response.where(map_id: @map.id, round: round)
.order(:created_at)
.last || Response.new(map_id: @map.id, round: round)
response = Response.find_or_initialize_by(map_id: `@map.id`, round: round)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 32 - 34, Replace the
non-atomic selection/creation pattern around Response (the
`Response.where(map_id: `@map.id`, round: round).order(:created_at).last ||
Response.new(...)` block) with an atomic find-or-create operation (e.g., use
Response.find_or_create_by(map_id: `@map.id`, round: round) or a transaction with
locking) and add/ensure a database-level unique constraint on (map_id, round) to
prevent duplicates; update any save/error handling around the Response creation
to handle uniqueness validation failures or ActiveRecord::RecordNotUnique
exceptions accordingly.


if params[:content].present? || params[:additional_comment].present?
response.additional_comment = params[:content].presence || params[:additional_comment]
end

if response.save
render json: { response_id: response.id, map_id: @map.id, round: response.round }, status: :created
else
render json: { errors: response.errors.full_messages }, status: :unprocessable_entity
end
end

def update
return unless enforce_task_order!(@response.map)

if @response.update(response_update_params)
render json: {
response_id: @response.id,
map_id: @response.map_id,
submitted: @response.is_submitted,
additional_comment: @response.additional_comment
}, status: :ok
else
render json: { errors: @response.errors.full_messages }, status: :unprocessable_entity
end
end

private

def set_response
@response = Response.find(params[:id])
end

# Runs before action_allowed? — handles both existence and authorization for create
def find_and_authorize_map_for_create
@map = ResponseMap.find_by(id: params[:response_map_id])
unless @map
render json: { error: "ResponseMap not found" }, status: :not_found
return
end

unless @map.reviewer.user_id == current_user.id
render json: { error: "You are not authorized to create this responses" }, status: :forbidden
end
Comment on lines +76 to +78

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo in error message.

"this responses" should be "this response".

-      render json: { error: "You are not authorized to create this responses" }, status: :forbidden
+      render json: { error: "You are not authorized to create this response" }, status: :forbidden
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
unless @map.reviewer.user_id == current_user.id
render json: { error: "You are not authorized to create this responses" }, status: :forbidden
end
unless `@map.reviewer.user_id` == current_user.id
render json: { error: "You are not authorized to create this response" }, status: :forbidden
end
🧰 Tools
🪛 RuboCop (1.86.1)

[convention] 76-76: Use a guard clause (return if @map.reviewer.user_id == current_user.id) instead of wrapping the code inside a conditional expression.

(Style/GuardClause)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 76 - 78, Fix the typo
in the error message inside ResponsesController where the unauthorized branch
renders { error: "You are not authorized to create this responses" } — change
the string to "You are not authorized to create this response" so the grammar is
correct (look for the render json call in the unauthorized check using
`@map.reviewer.user_id` and current_user.id).

end


def response_update_params
p = params.permit(:is_submitted, :additional_comment, :content, :round)
p[:additional_comment] = p[:content] if p[:content].present?
p.delete(:content)
p
end

def enforce_task_order!(map)
participant = map.reviewer
unless participant.user_id == current_user.id
render json: { error: "Unauthorized" }, status: :forbidden
return false
end

team_participant = TeamsParticipant.find_by(participant_id: participant.id)
unless team_participant
render json: { error: "TeamsParticipant not found for reviewer" }, status: :forbidden
return false
end

queue = TaskOrdering::TaskQueue.new(participant.assignment, team_participant)
unless queue.map_in_queue?(map.id)
render json: { error: "Response map is not a respondable task for this participant" }, status: :forbidden
return false
end

unless queue.prior_tasks_complete_for?(map.id)
render json: { error: "You must complete prior tasks before responding to this one" }, status: :forbidden
return false
end

true
end
end
Loading
Loading