diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000000..2f1d69f05e1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,27 @@
+# Use an official Ruby runtime as a parent image
+FROM ruby:2.7
+
+# Install dependencies
+RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
+
+# Set up the working directory
+WORKDIR /app
+
+# Copy the Gemfile and Gemfile.lock into the container
+COPY Gemfile /app/Gemfile
+COPY Gemfile.lock /app/Gemfile.lock
+
+# Install gems
+RUN bundle install
+
+# Copy the rest of the application files into the container
+COPY . /app
+
+# Precompile assets (if your app has assets)
+RUN bundle exec rake assets:precompile || true
+
+# Expose the port that the app runs on
+EXPOSE 3000
+
+# Start the server by default
+CMD ["rails", "server", "-b", "0.0.0.0"]
diff --git a/E2460-MentorMeetingManagement b/E2460-MentorMeetingManagement
new file mode 160000
index 00000000000..c1e6c750acc
--- /dev/null
+++ b/E2460-MentorMeetingManagement
@@ -0,0 +1 @@
+Subproject commit c1e6c750acc39255283558f7b97c869f644f09a3
diff --git a/README.md b/README.md
index 57d9118cade..6488ca3535d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,13 @@
Expertiza
=========
+MMM Last Semester's Pull Requests
+Pull Request: (https://github.com/expertiza/expertiza/pull/2769)
+Pull Request: (https://github.com/expertiza/expertiza/pull/2772)
+
+Their Wiki (https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2024_-_E2403_Mentor-Meeting_Management)
+
+
[](https://travis-ci.org/expertiza/expertiza)
[](https://coveralls.io/github/expertiza/expertiza?branch=main)
[](https://codeclimate.com/github/expertiza/expertiza/maintainability)
diff --git a/app/controllers/mentor_meeting_controller.rb b/app/controllers/mentor_meeting_controller.rb
new file mode 100644
index 00000000000..c4ec017870f
--- /dev/null
+++ b/app/controllers/mentor_meeting_controller.rb
@@ -0,0 +1,74 @@
+class MentorMeetingController < ApplicationController
+ include MentorMeetingsHelper
+
+ before_action :set_team_and_meeting, only: [:edit_date, :delete_date]
+
+ # Method to get meeting dates for a particular assignment
+ def get_dates
+ @mentor_meetings = MentorMeeting.all
+ render json: @mentor_meetings, status::ok
+ end
+
+ # Method to add meetings dates to the mentor_meetings table.
+def add_date
+ team_id = params[:team_id]
+ meeting_date = params[:meeting_date]
+ @mentor_meeting = MentorMeeting.create(team_id: team_id, meeting_date: meeting_date)
+
+ if @mentor_meeting.save
+ MentorMeetingNotifications.send_notification(team_id, meeting_date)
+ render json: { status: 'success', message: "Meeting date added" }
+ else
+ render json: { status: 'error', message: "Unable to add meeting date" }
+ end
+end
+
+
+ def edit_date
+ team_id = params[:team_id]
+ old_meeting_date = params[:old_date]
+ new_meeting_date = params[:new_date]
+
+ @meeting = MentorMeeting.where(team_id: team_id.to_i, meeting_date: old_meeting_date).first
+ if @meeting
+ @meeting.meeting_date = new_meeting_date
+ if @meeting.save
+ # Trigger notification after editing
+ ActiveSupport::Notifications.instrument('mentor_meeting.updated', team_id: team_id, old_meeting_date: old_meeting_date, new_meeting_date: new_meeting_date)
+ render json: { status: 'success', message: 'Meeting updated successfully' }
+ else
+ render json: { status: 'error', message: 'Failed to update meeting' }
+ end
+ else
+ render json: { status: 'error', message: 'Meeting not found' }
+ end
+ end
+
+
+ def delete_date
+ team_id = params[:team_id]
+ meeting_date = params[:meeting_date]
+ @meeting = MentorMeeting.where(team_id: team_id.to_i, meeting_date: meeting_date).first
+
+ if @meeting
+ @meeting.destroy
+ # Trigger notification after deletion
+ ActiveSupport::Notifications.instrument('mentor_meeting.deleted', team_id: team_id, meeting_date: meeting_date)
+ render json: { status: 'success', message: 'Meeting deleted successfully' }
+ else
+ render json: { status: 'error', message: 'Meeting not found' }
+ end
+ end
+
+ private
+
+ def meeting_dates_params #permitting parameters through the model
+ params.require(:meeting_dates).permit(:team_id, :date)
+ end
+
+ def set_team_and_meeting #means by which a specific team meeting can be found based on its parameters
+ @meeting = MentorMeeting.find_by(team_id: params[:team_id].to_i, meeting_date: params[:meeting_date])
+ render json: { status: 'error', message: 'Meeting not found' }, status: :not_found unless @meeting
+ end
+end
+
diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb
index 1d2fd966a3d..055a7cc29ed 100644
--- a/app/controllers/teams_controller.rb
+++ b/app/controllers/teams_controller.rb
@@ -1,6 +1,7 @@
class TeamsController < ApplicationController
include AuthorizationHelper
-
+ include MentorMeetingsHelper
+
autocomplete :user, :name
# Check if the current user has TA privileges
@@ -53,6 +54,8 @@ def list
unless @assignment.nil?
if @assignment.auto_assign_mentor
@model = MentoredTeam
+ # MentorMeeting.delete_all
+ @mentor_meetings = MentorMeeting.all
else
@model = AssignmentTeam
end
@@ -61,6 +64,8 @@ def list
begin
@root_node = Object.const_get(session[:team_type] + 'Node').find_by(node_object_id: params[:id])
@child_nodes = @root_node.get_teams
+
+ @meetings_map = get_dates_for_team(@child_nodes)
rescue StandardError
flash[:error] = $ERROR_INFO
end
@@ -171,6 +176,20 @@ def copy_teams(operation)
redirect_to controller: 'teams', action: 'list', id: assignment.id
end
+ # Method to get meeting dates for a particular assignment
+ def get_mentor_meeting_dates
+ mentor_meetings = MentorMeeting.all # Or your query to fetch data
+ render json: mentor_meetings
+ end
+
+ # Method to add meetings dates to the mentor_meetings table.
+ def add_mentor_meeting_date
+ team_id = params[:team_id]
+ meeting_date = params[:meeting_date]
+ MentorMeeting.create(team_id: team_id, meeting_date: meeting_date)
+ render :json => { :status => 'success', :message => "Ok"}
+ end
+
# Abstraction over different methods
def choose_copy_type(assignment, operation)
course = Course.find(assignment.course_id)
diff --git a/app/helpers/mailer_helper.rb b/app/helpers/mailer_helper.rb
index 568f35788c1..bc052d0aa81 100644
--- a/app/helpers/mailer_helper.rb
+++ b/app/helpers/mailer_helper.rb
@@ -14,6 +14,22 @@ def self.send_mail_to_user(user, subject, partial_name, password)
)
end
+ def self.send_team_confirmation_mail_to_user(user, subject, partial_name, team_name, assignment_name)
+ # This function serves as a helper to send emails to users letting them know they have added to a team
+ # note that the below hash is sent to a view html that has the partial_name
+ Mailer.generic_message(
+ to: user.email,
+ subject: subject,
+ body: {
+ user: user,
+ first_name: ApplicationHelper.get_user_first_name(user),
+ partial_name: partial_name,
+ team: team_name,
+ assignment: assignment_name
+ }
+ )
+ end
+
def self.send_mail_to_all_super_users(super_user, user, subject)
Mailer.request_user_message(
to: super_user.email,
diff --git a/app/helpers/mentor_meetings_helper.rb b/app/helpers/mentor_meetings_helper.rb
new file mode 100644
index 00000000000..4618be97634
--- /dev/null
+++ b/app/helpers/mentor_meetings_helper.rb
@@ -0,0 +1,14 @@
+module MentorMeetingsHelper
+
+ def get_dates_for_team(children)
+ @meeting_map = {}
+
+ children.each do |child|
+ team_id = child.node_object_id.to_i
+ @meeting_map[team_id] = MentorMeeting.where(team_id: team_id).pluck(:meeting_date)
+ end
+
+ @meeting_map
+ end
+
+end
diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb
index b96924fbf6c..4d4ccf1e3ef 100644
--- a/app/mailers/mailer.rb
+++ b/app/mailers/mailer.rb
@@ -24,7 +24,8 @@ def generic_message(defn)
@avg_pct = defn[:body][:avg_pct]
@assignment = defn[:body][:assignment]
@conference_variable = defn[:body][:conference_variable]
-
+ @team = defn[:body][:team] # team name
+
if Rails.env.development? || Rails.env.test?
defn[:to] = 'expertiza.mailer@gmail.com'
end
diff --git a/app/models/mentor_meeting.rb b/app/models/mentor_meeting.rb
new file mode 100644
index 00000000000..1281200e41b
--- /dev/null
+++ b/app/models/mentor_meeting.rb
@@ -0,0 +1,5 @@
+class MentorMeeting < ApplicationRecord
+ def self.table
+ 'mentor_meetings'
+ end
+end
diff --git a/app/models/mentor_meeting_notifications.rb b/app/models/mentor_meeting_notifications.rb
new file mode 100644
index 00000000000..4ee02f08588
--- /dev/null
+++ b/app/models/mentor_meeting_notifications.rb
@@ -0,0 +1,9 @@
+class MentorMeetingNotifications
+ def self.send_notification(team_id, meeting_date)
+ ActiveSupport::Notifications.instrument('mentor_meeting.created', team_id: team_id, meeting_date: meeting_date)
+ end
+end
+
+ActiveSupport::Notifications.subscribe('mentor_meeting.created') do |name, start, finish, id, payload|
+ puts "New meeting created for team #{payload[:team_id]} on #{payload[:meeting_date]}"
+end
diff --git a/app/models/mentored_team.rb b/app/models/mentored_team.rb
index daccd65d37d..a43feca21e7 100644
--- a/app/models/mentored_team.rb
+++ b/app/models/mentored_team.rb
@@ -12,7 +12,20 @@ def add_member(user, _assignment_id = nil)
TeamUserNode.create(parent_id: parent.id, node_object_id: t_user.id)
add_participant(parent_id, user)
ExpertizaLogger.info LoggerMessage.new('Model:Team', user.name, "Added member to the team #{id}")
+
+ assignment_name = _assignment_id ? Assignment.find(_assignment_id).name.to_s : ""
+ # mentor only
+ if MentorManagement.user_a_mentor?(user) && !user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "mentor_added_to_team", "#{name}", assignment_name).deliver
+ # participant only
+ elsif !MentorManagement.user_a_mentor?(user) && user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "user_added_to_team", "#{name}", assignment_name).deliver
+ # dual case
+ elsif MentorManagement.user_a_mentor?(user) && user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "dual_role_added_to_team", "#{name}", assignment_name).deliver
+ end
end
+
if can_add_member
MentorManagement.assign_mentor(_assignment_id, id)
end
diff --git a/app/models/team.rb b/app/models/team.rb
index 9786c55431b..f2d4a06e210 100644
--- a/app/models/team.rb
+++ b/app/models/team.rb
@@ -88,6 +88,25 @@ def add_member(user, _assignment_id = nil)
TeamUserNode.create(parent_id: parent.id, node_object_id: t_user.id)
add_participant(parent_id, user)
ExpertizaLogger.info LoggerMessage.new('Model:Team', user.name, "Added member to the team #{id}")
+
+ # if assignment_id is nil, then don't send an assignment name
+ assignment_name = _assignment_id ? Assignment.find(_assignment_id).name.to_s : ""
+
+ # addressing efg's comment in previous PR
+ # if just mentor
+ if MentorManagement.user_a_mentor?(user) && !user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "mentor_added_to_team", "#{name}", assignment_name).deliver
+
+ # only a participant
+ elsif !MentorManagement.user_a_mentor?(user) && user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "user_added_to_team", "#{name}", assignment_name).deliver
+
+ # both mentor and participant
+ elsif MentorManagement.user_a_mentor?(user) && user.is_a?(Participant)
+ MailerHelper.send_team_confirmation_mail_to_user(user, "[Expertiza] Added to a Team", "dual_role_added_to_team", "#{name}", assignment_name).deliver
+
+ end
+
end
can_add_member
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 38e80f15b36..2e0d8582f9d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -324,3 +324,10 @@ def self.search_users(role, user_id, letter, search_by)
users
end
end
+
+
+def get_user_details(name)
+ user = User.where('name = ?', name).first
+end
+
+public :get_user_details
diff --git a/app/views/mailer/partials/_dual_role_added_to_team_html.html.erb b/app/views/mailer/partials/_dual_role_added_to_team_html.html.erb
new file mode 100644
index 00000000000..e28a835e1c1
--- /dev/null
+++ b/app/views/mailer/partials/_dual_role_added_to_team_html.html.erb
@@ -0,0 +1,11 @@
+Hi <%= @first_name %>,
+
+
+ You have been added to Team '<%= @team %>' for the Assignment '<%= @assignment %>' on Expertiza. +
++ Please note that you are assigned both as a mentor and a participant for this team. +
++ Expertiza Team +
diff --git a/app/views/mailer/partials/_mentor_added_to_team_html.html.erb b/app/views/mailer/partials/_mentor_added_to_team_html.html.erb new file mode 100644 index 00000000000..1fc320c8ec1 --- /dev/null +++ b/app/views/mailer/partials/_mentor_added_to_team_html.html.erb @@ -0,0 +1,8 @@ +Hi <%= @first_name %>, ++ You are now mentoring Team '<%= @team %>' for the Assignment '<%= @assignment %>' on Expertiza. +
++ Expertiza Team +
diff --git a/app/views/mailer/partials/_mentor_added_to_team_plain.html.erb b/app/views/mailer/partials/_mentor_added_to_team_plain.html.erb new file mode 100644 index 00000000000..c943a3a8f3f --- /dev/null +++ b/app/views/mailer/partials/_mentor_added_to_team_plain.html.erb @@ -0,0 +1,5 @@ +Hi <%= @first_name %>, + +You are now mentoring Team '<%= @team %>' for the Assignment '<%= @assignment %>' on Expertiza. + +Expertiza Team diff --git a/app/views/mailer/partials/_user_added_to_team_html.html.erb b/app/views/mailer/partials/_user_added_to_team_html.html.erb new file mode 100644 index 00000000000..eb8e15d7df5 --- /dev/null +++ b/app/views/mailer/partials/_user_added_to_team_html.html.erb @@ -0,0 +1,8 @@ +Hi <%= @first_name %>, ++ You have been added to Team '<%= @team %>' for the Assignment '<%= @assignment %>' on Expertiza. +
++ Expertiza Team +
diff --git a/app/views/mailer/partials/_user_added_to_team_plain.html.erb b/app/views/mailer/partials/_user_added_to_team_plain.html.erb new file mode 100644 index 00000000000..4ca128adf37 --- /dev/null +++ b/app/views/mailer/partials/_user_added_to_team_plain.html.erb @@ -0,0 +1,5 @@ +Hi <%= @first_name %>, + +You have been added to Team '<%= @team %>' for the Assignment '<%= @assignment %>' on Expertiza. + +Expertiza Team diff --git a/app/views/teams/_team.html.erb b/app/views/teams/_team.html.erb index a45b599012b..c2936e9ceb9 100644 --- a/app/views/teams/_team.html.erb +++ b/app/views/teams/_team.html.erb @@ -1,14 +1,21 @@ +<% if @model == MentoredTeam %> + <%= render :partial => '/tree_display/page_footer_assignments', :locals => { :assignment_id => @root_node.node_object_id, :@meeting_map => @meeting_map } %>Mentor: <%= team.mentor.name %>
+Members: <%= team.members.map(&:name).join(', ') %>
+ +| Team name | +Members' name | +Members' User IDs | +Emails | +Mentor | +Actions | +1st mtg. | +2nd mtg. | +3rd mtg. | + <% + (3..max_dates_length - 1).each do |index| + %> +<%= index + 1 %>th mtg. | + <% + end + %> +Add mtg. | +||
|---|---|---|---|---|---|---|---|---|---|---|---|---|