Skip to content

Commit

Permalink
E2424 project (expertiza#122)
Browse files Browse the repository at this point in the history
* Added instructions for creating test objects in SQL server and starting up backend services

* bookmark scaffold files created

* add student_task model and its tests

* improve student_task test

* Re-scaffolded student task controller, generated db migrations, implemented basic list function and got basic JSON response functionality working

* Reverted creation of student task table

* Un-commented seed file to properly seed database

* Added view function in student_tasks_controller.rb and cleaned up the file

* Updated view function

* add course seed

* Added permission granted flag to participants

* Removed comments and simplified code for student task controller and model.

* Added permission granted to student task model rspec test, reformatted file a bit

* Got initial authenticated/unauthenticated rspec tests working for student task controller.

* add course to seeds.rb

* Removed set student method throwing errors

* Added view function route for student_task_controller

* add Student_task list in SwaggerUI

* Create bookmarks_controller

* crud ops

* add score related functions for bookmark

* Create bookmarks_controller_spec.rb

* Adding setup.sh to automate the setup inside containers (expertiza#84)

* Adding files to setup

* Updating setup script with working seed file

* Adding a setup script to try to automate setup

* Adding setup.sh as entrypoint

* add db creation initilization script

---------

Co-authored-by: Muhammad Ali Qureshi <[email protected]>
Co-authored-by: ameyagv <[email protected]>

* deleted unnecessary files

* modified sign_up_topic

* removed gemfile.lock and schema.rb

* added gemfile.lock and schema.rb

* changes bookmarks controller

* Bolstered test suite for controller list function and improved readability

* added bookmark rating functions

* added bookmark controller tests

* add swaggerUI

* update student_task model

* schema update

* swagger config update

* add view function

* delete view in SwaggerUI as it is out of scope

* add commits to student_task.rb

* Added comments for student task controller

* add SwaggerUI view

* resovle sign_up_topic migration

* update schema.rb

---------

Co-authored-by: hmckinn <[email protected]>
Co-authored-by: Akshat Nitin Savla <[email protected]>
Co-authored-by: Yunfei Chen <[email protected]>
Co-authored-by: david12white <[email protected]>
Co-authored-by: David White <[email protected]>
Co-authored-by: ychen-207523 <[email protected]>
Co-authored-by: Mitanshu Reshamwala <[email protected]>
Co-authored-by: Mitanshu Reshamwala <[email protected]>
Co-authored-by: vyshnavi-adusumelli <[email protected]>
Co-authored-by: Ali Qureshi <[email protected]>
Co-authored-by: Muhammad Ali Qureshi <[email protected]>
Co-authored-by: Yunfei Chen <[email protected]>
  • Loading branch information
13 people authored Oct 16, 2024
1 parent 11faa07 commit 13a0fdc
Show file tree
Hide file tree
Showing 14 changed files with 387 additions and 3 deletions.
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ GEM
nio4r (2.5.9)
nokogiri (1.15.2-aarch64-linux)
racc (~> 1.4)
nokogiri (1.15.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.15.2-x64-mingw-ucrt)
racc (~> 1.4)
nokogiri (1.15.2-x86_64-linux)
Expand Down Expand Up @@ -243,6 +245,7 @@ GEM

PLATFORMS
aarch64-linux
arm64-darwin-22
x64-mingw-ucrt
x86_64-linux

Expand Down
25 changes: 25 additions & 0 deletions app/controllers/api/v1/student_tasks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Api::V1::StudentTasksController < ApplicationController

# List retrieves all student tasks associated with the current logged-in user.
def list
# Retrieves all tasks that belong to the current user.
@student_tasks = StudentTask.from_user(current_user)
# Render the list of student tasks as JSON.
render json: @student_tasks, status: :ok
end

def show
render json: @student_task, status: :ok
end

# The view function retrieves a student task based on a participant's ID.
# It is meant to provide an endpoint where tasks can be queried based on participant ID.
def view
# Retrieves the student task where the participant's ID matches the provided parameter.
# This function will be used for clicking on a specific student task to "view" its details.
@student_task = StudentTask.from_participant_id(params[:id])
# Render the found student task as JSON.
render json: @student_task, status: :ok
end

end
48 changes: 48 additions & 0 deletions app/models/student_task.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class StudentTask
attr_accessor :assignment, :current_stage, :participant, :stage_deadline, :topic, :permission_granted

# Initializes a new instance of the StudentTask class
def initialize(args)
@assignment = args[:assignment]
@current_stage = args[:current_stage]
@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
def self.create_from_participant(participant)
new(
assignment: participant.assignment.name, # Name of the assignment associated with the student task
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


# create an array of StudentTask instances for all participants linked to a user, sorted by deadline.
def self.from_user(user)
Participant.where(user_id: user.id)
.map { |participant| StudentTask.create_from_participant(participant) }
.sort_by(&:stage_deadline)
end

# create a StudentTask instance from a participant of the provided id
def self.from_participant_id(id)
create_from_participant(Participant.find_by(id: id))
end

private

# Parses a date string to a Time object, if parsing fails, set the time to be one year after current
def self.parse_stage_deadline(date_string)
Time.parse(date_string)
rescue StandardError
Time.now + 1.year
end

end
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
post 'bookmarkratings', to: 'bookmarks#save_bookmark_rating_score'
end
end
resources :student_tasks do
collection do
get :list, action: :list
get :view
end
end

resources :courses do
collection do
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class AddPermissionGrantedToParticipants < ActiveRecord::Migration[7.0]
def change
add_column :participants, :permission_granted, :boolean
add_column :participants, :permission_granted, :boolean, default: false
end
end
13 changes: 13 additions & 0 deletions db/migrate/20240415155554_create_student_tasks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateStudentTasks < ActiveRecord::Migration[7.0]
def change
create_table :student_tasks do |t|
t.references :assignment, null: false, foreign_key: true
t.string :current_stage
t.references :participant, null: false, foreign_key: true
t.datetime :stage_deadline
t.string :topic

t.timestamps
end
end
end
7 changes: 7 additions & 0 deletions db/migrate/20240415163413_add_columns_to_participants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class AddColumnsToParticipants < ActiveRecord::Migration[7.0]
def change
add_column :participants, :topic, :string
add_column :participants, :current_stage, :string
add_column :participants, :stage_deadline, :datetime
end
end
5 changes: 5 additions & 0 deletions db/migrate/20240415192048_drop_student_task_tabkle.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class DropStudentTaskTabkle < ActiveRecord::Migration[7.0]
def change
drop_table :student_tasks
end
end
7 changes: 5 additions & 2 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions spec/factories.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
FactoryBot.define do
factory :student_task do
assignment { nil }
current_stage { "MyString" }
participant { nil }
stage_deadline { "2024-04-15 15:55:54" }
topic { "MyString" }
end


factory :join_team_request do
end
Expand Down
83 changes: 83 additions & 0 deletions spec/models/student_task_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'rails_helper'


RSpec.describe StudentTask, type: :model do
before(:each) do
@assignment = double(name: "Final Project")
@participant = double(
assignment: @assignment,
topic: "E2442",
current_stage: "finished",
stage_deadline: "2024-04-23",
permission_granted: true
)

end

describe ".initialize" do
it "correctly assigns all attributes" do
args = {
assignment: @assignment,
current_stage: "finished",
participant: @participant,
stage_deadline: "2024-04-23",
topic: "E2442",
permission_granted: false
}

student_task = StudentTask.new(args)

expect(student_task.assignment.name).to eq("Final Project")
expect(student_task.current_stage).to eq("finished")
expect(student_task.participant).to eq(@participant)
expect(student_task.stage_deadline).to eq("2024-04-23")
expect(student_task.topic).to eq("E2442")
expect(student_task.permission_granted).to be false
end
end

describe ".from_participant" do
it "creates an instance from a participant instance" do

student_task = StudentTask.create_from_participant(@participant)

expect(student_task.assignment).to eq(@participant.assignment.name)
expect(student_task.topic).to eq(@participant.topic)
expect(student_task.current_stage).to eq(@participant.current_stage)
expect(student_task.stage_deadline).to eq(Time.parse(@participant.stage_deadline))
expect(student_task.permission_granted).to be @participant.permission_granted
expect(student_task.participant).to be @participant
end
end

describe ".parse_stage_deadline" do
context "valid date string" do
it "parses the date string into a Time object" do
valid_date = "2024-04-25"
expect(StudentTask.send(:parse_stage_deadline, valid_date)).to eq(Time.parse("2024-04-25"))
end
end

context "invalid date string" do
it "returns current time plus one year" do
invalid_date = "invalid input"
# Set the now to be 2024-05-01 for testing purpose
allow(Time).to receive(:now).and_return(Time.new(2024, 5, 1))
expected_time = Time.new(2025, 5, 1)
expect(StudentTask.send(:parse_stage_deadline, invalid_date)).to eq(expected_time)
end
end
end

describe ".from_participant_id" do
it "fetches a participant by id and creates a student task from it" do
allow(Participant).to receive(:find_by).with(id: 1).and_return(@participant)

expect(Participant).to receive(:find_by).with(id: 1).and_return(@participant)
expect(StudentTask).to receive(:create_from_participant).with(@participant)

StudentTask.from_participant_id(1)
end
end

end
125 changes: 125 additions & 0 deletions spec/requests/api/v1/student_tasks_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
require 'swagger_helper'

def login_user()
# Give the login details of a DB-seeded user. (see seeds.rb)
login_details = {
user_name: "john",
password: "password123"
}

# Make the request to the login function.
post '/login', params: login_details

# return the token from the response
json_response = JSON.parse(response.body)
json_response['token']
end

describe 'StudentTasks API', type: :request do

# Re-login and get the token after each request.
before(:each) do
@token = login_user
end

path '/api/v1/student_tasks/list' do
get 'student tasks list' do
# Tag for testing purposes.
tags 'StudentTasks'
produces 'application/json'

# Define parameter to send with request.
parameter name: 'Authorization', :in => :header, :type => :string

# Ensure an authorized request gets a 200 response.
response '200', 'authorized request has success response' do
# Attach parameter to request.
let(:'Authorization') {"Bearer #{@token}"}

run_test!
end

# Ensure an authorized test gets the right data for the logged-in user.
response '200', 'authorized request has proper JSON schema' do
# Attach parameter to request.
let(:'Authorization') {"Bearer #{@token}"}

# Run test and give expectations about result.
run_test! do |response|
data = JSON.parse(response.body)
expect(data).to be_instance_of(Array)
expect(data.length()).to be 5

# Ensure the objects have the correct type.
data.each do |task|
expect(task['assignment']).to be_instance_of(String)
expect(task['current_stage']).to be_instance_of(String)
expect(task['stage_deadline']).to be_instance_of(String)
expect(task['topic']).to be_instance_of(String)
expect(task['permission_granted']).to be_in([true, false])

# Not true in general case- this is only for the seeded data.
expect(task['assignment']).to eql(task['topic'])
end
end
end

# Ensure a request with an invalid bearer token gets a 401 response.
response '401', 'unauthorized request has error response' do
let(:'Authorization') {"Bearer "}
run_test!
end

# Ensure a request with an invalid bearer token gets the proper error response.
response '401', 'unauthorized request has error response' do
let(:'Authorization') {"Bearer "}
run_test! do |response|
data = JSON.parse(response.body)
expect(data["error"]).to eql("Not Authorized")
end
end
end
end

path '/api/v1/student_tasks/view' do
get 'Retrieve a specific student task by ID' do
tags 'StudentTasks'
produces 'application/json'
parameter name: 'id', in: :query, type: :Integer, required: true
parameter name: 'Authorization', in: :header, type: :string

response '200', 'successful retrieval of a student task' do
let(:'Authorization') { "Bearer #{@token}" }
let(:id) { 1 }

run_test! do |response|
data = JSON.parse(response.body)
expect(data['assignment']).to be_instance_of(String)
expect(data['current_stage']).to be_instance_of(String)
expect(data['stage_deadline']).to be_instance_of(String)
expect(data['topic']).to be_instance_of(String)
expect(data['permission_granted']).to be_in([true, false])
end
end

response '500', 'participant not found' do
let(:'Authorization') { "Bearer #{@token}" }
let(:id) { -1 }

run_test! do |response|
expect(response.status).to eq(500)
end
end

response '401', 'unauthorized request has error response' do
let(:'Authorization') { "Bearer " }
let(:id) { 'any_id' }
run_test! do |response|
data = JSON.parse(response.body)
expect(data["error"]).to eql("Not Authorized")
end
end
end

end
end
Loading

0 comments on commit 13a0fdc

Please sign in to comment.