Class: Course

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
PeopleInACollection
Defined in:
app/models/course.rb

Overview

Course represents a course taught at CMU-SV.

At present, there is no distinction between sections of a course. Each team can belong to a “section” which is only a labeled text field.

Adding a Course Offering

Sometime before a new semester starts, Gerry will create all the courses for the next semester. The HUB has a deadline for updating their system with courses, once that deadline has passed, Gerry typically will update the rails system. A course can be added/removed/modified after this deadline, and the information in the rails system should be updated. When Gerry creates a course, its will the minimal necessary information. When the course is created, certain information is copied from the previous offering of the same course, where as other information must not be copied.

The CMU-SV community typically does not refer to courses by their number, where as on the Pittsburgh campus, most undergraduate courses are referred to by their number.

The system asks for the tuple (course_number, semester, and year) to create the course and then puts the user in an edit mode prompting reasonable defaults from the last time the course was offered. If nothing has changed, it's easy for Gerry to create the next course. If the instructor has changed then it's easy to edit that information

Notifying instructors

Whenever an instructor is added to a course, they are notified about the change, asking them to review the course options. We ask that one of the instructors confirm the settings, when this happens we consider that the faculty has “configured” the course. (Or verified it's settings.) If this doesn't happen, the system should periodically remind faculty about the change.)

Course has grading rules. These include grading cut_offs for grade's like A,A-,B+ etc.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PeopleInACollection

#added_people, #detect_if_list_changed, #map_member_strings_to_users, #remove_empty_fields, #removed_people, #update_collection_members, #validate_members

Instance Attribute Details

#faculty_assignments_overrideObject

When assigning faculty to a page, the user types in a series of strings that then need to be processed :faculty_assignments_override is a temporary variable that is used to do validation of the strings (to verify that they are people in the system) and then to save the people in the faculty association.


66
67
68
# File 'app/models/course.rb', line 66

def faculty_assignments_override
  @faculty_assignments_override
end

Class Method Details

.copy_courses_from_a_semester_to_next_year(semester, year) ⇒ Object


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'app/models/course.rb', line 260

def self.copy_courses_from_a_semester_to_next_year(semester, year)
  next_year = year + 1
  if Course.for_semester(semester, next_year).empty?
    Course.for_semester(semester, year).each do |last_year_course|
      puts last_year_course.id
      next_year_course = last_year_course.copy_as_new_course
      next_year_course.peer_evaluation_first_email += 1.year if next_year_course.peer_evaluation_first_email
      next_year_course.peer_evaluation_second_email += 1.year if next_year_course.peer_evaluation_second_email
      next_year_course.year = next_year
      next_year_course.save
    end
  else
    raise "There are already courses in semester #{semester} #{next_year}"
  end
end

.current_semester_coursesObject


143
144
145
146
# File 'app/models/course.rb', line 143

def self.current_semester_courses()
  return self.for_semester(AcademicCalendar.current_semester(),
                           Date.today.year)
end

.first_email_on_peer_evaluation_is_todayObject


153
154
155
# File 'app/models/course.rb', line 153

def self.first_email_on_peer_evaluation_is_today
  Course.where(:peer_evaluation_first_email => Date.today).all
end

.first_offering_for_course_name(course_name) ⇒ Object


135
136
137
# File 'app/models/course.rb', line 135

def self.first_offering_for_course_name(course_name)
  Course.with_course_name(course_name).first
end

.for_semester(semester, year) ⇒ Object


139
140
141
# File 'app/models/course.rb', line 139

def self.for_semester(semester, year)
  return Course.where(:semester => semester, :year => year).order("name ASC").all
end

.last_offering(course_number) ⇒ Object

Find the last time this course was offered


253
254
255
256
257
258
# File 'app/models/course.rb', line 253

def self.last_offering(course_number)
  #TODO: move this sorting into the database
  offerings = Course.where(:number => course_number).all
  offerings = offerings.sort_by { |c| -c.sortable_value } # note the '-' is for desc sorting
  return offerings.first
end

.next_semester_coursesObject


148
149
150
151
# File 'app/models/course.rb', line 148

def self.next_semester_courses()
  return self.for_semester(AcademicCalendar.next_semester(),
                           AcademicCalendar.next_semester_year())
end

.remind_about_effort_course_listObject


206
207
208
209
210
# File 'app/models/course.rb', line 206

def self.remind_about_effort_course_list
  courses = Course.where(:remind_about_effort => true, :year => Date.today.cwyear, :semester => AcademicCalendar.current_semester(), :mini => "Both").all
  courses = courses + Course.where(:remind_about_effort => true, :year => Date.today.cwyear, :semester => AcademicCalendar.current_semester(), :mini => AcademicCalendar.current_mini).all
  return courses
end

.second_email_on_peer_evaluation_is_todayObject


157
158
159
# File 'app/models/course.rb', line 157

def self.second_email_on_peer_evaluation_is_today
  Course.where(:peer_evaluation_second_email => Date.today).all
end

Instance Method Details

#auto_generated_peer_evaluation_date_endObject


220
221
222
# File 'app/models/course.rb', line 220

def auto_generated_peer_evaluation_date_end
  return Date.commercial(self.year, self.course_start + 7)
end

#auto_generated_peer_evaluation_date_startObject


216
217
218
# File 'app/models/course.rb', line 216

def auto_generated_peer_evaluation_date_start
  return Date.commercial(self.year, self.course_start + 6)
end

#auto_generated_twiki_urlObject


212
213
214
# File 'app/models/course.rb', line 212

def auto_generated_twiki_url
  return "http://info.sv.cmu.edu/do/view/#{self.semester}#{self.year}/#{self.short_or_full_name}/WebHome".delete(' ')
end

#copy_as_new_courseObject


238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'app/models/course.rb', line 238

def copy_as_new_course
  new_course = self.dup
  new_course.is_configured = false
  new_course.configured_by = nil
  new_course.updated_by = nil
  new_course.created_at = Time.now
  new_course.updated_at = Time.now
  new_course.curriculum_url = nil if self.curriculum_url.nil? || self.curriculum_url.include?("twiki")
  new_course.faculty = self.faculty
  new_course.grading_rule = self.grading_rule.dup if self.grading_rule.present?
  self.assignments.each { |assignment| new_course.assignments << assignment.dup } if self.assignments.present?
  return new_course
end

#copy_teams_to_another_course(destination_course_id) ⇒ Object


276
277
278
279
280
281
# File 'app/models/course.rb', line 276

def copy_teams_to_another_course(destination_course_id)
  #Todo: at some point, refactor teams to be an ordered list, so that we wouldn't need to reverse it here to preserve ordering.
  self.teams.reverse.each do |team|
    team.clone_to_another_course(destination_course_id)
  end
end

#course_endObject

Return the week number of the year for the end of a course


197
198
199
# File 'app/models/course.rb', line 197

def course_end
  self.course_start + self.course_length - 1
end

#course_lengthObject


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'app/models/course.rb', line 162

def course_length
  if self.mini == "Both" then
    if semester == "Summer" then
      return 12
    elsif semester == "Fall" then
      return 15
    else
      return 16
    end
  else
    if semester == "Summer" then
      return 6
    else
      return 7
    end
  end
end

#course_startObject

Return the week number of the year for the start of a course


181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'app/models/course.rb', line 181

def course_start
  start = AcademicCalendar.semester_start(semester, year)

  if semester == "Spring" then
    return self.mini == "B" ? start + 9 : start
  end
  if semester == "Summer" then
    return self.mini == "B" ? start + 6 : start
  end
  if semester == "Fall" then
    return self.mini == "B" ? start + 8 : start
  end
  return 0 #If the semester field isn't set
end

#current_mini?Boolean

Returns:

  • (Boolean)

283
284
285
286
287
288
289
290
# File 'app/models/course.rb', line 283

def current_mini?
  case self.mini
    when "Both"
      self.year == Date.today.year && self.semester == AcademicCalendar.current_semester()
    else
      self.year == Date.today.year && self.mini == AcademicCalendar.current_mini()
  end
end

#display_course_nameObject

def to_param

  display_course_name
end

84
85
86
87
88
# File 'app/models/course.rb', line 84

def display_course_name
  mini_text = self.mini == "Both" ? "" : self.mini
  result = self.short_or_full_name + self.semester + mini_text + self.year.to_s
  result.gsub(" ", "")
end

#display_for_course_pageObject


90
91
92
93
94
# File 'app/models/course.rb', line 90

def display_for_course_page
# Consider this
#    "#{self.number} #{self.name} (#{self.short_name}) #{self.display_semester}"
  "#{self.number} #{self.name} (#{self.short_name})"
end

#display_nameObject


96
97
98
99
# File 'app/models/course.rb', line 96

def display_name
  return self.name if self.short_name.blank?
  return self.name + " (" + self.short_name + ")"
end

#display_semesterObject


117
118
119
120
# File 'app/models/course.rb', line 117

def display_semester
  mini_text = self.mini == "Both" ? "" : self.mini + " "
  return self.semester + " " + mini_text + self.year.to_s
end

#email_faculty_to_configure_course_unless_already_configuredObject


300
301
302
# File 'app/models/course.rb', line 300

def email_faculty_to_configure_course_unless_already_configured
  CourseMailer.configure_course_faculty_email(self).deliver unless self.is_configured?
end

#grade_type_points_or_weightsObject


313
314
315
316
317
318
319
# File 'app/models/course.rb', line 313

def grade_type_points_or_weights
  if self.grading_rule.nil? || self.grading_rule.grade_type=="points"
    "points"
  else
    "weights"
  end
end

#invalidate_distribution_listObject


292
293
294
# File 'app/models/course.rb', line 292

def invalidate_distribution_list
  self.updating_email = true
end

#nomenclature_assignment_or_deliverableObject


305
306
307
308
309
310
311
# File 'app/models/course.rb', line 305

def nomenclature_assignment_or_deliverable
  if self.grading_rule.nil? || self.grading_rule.is_nomenclature_deliverable?
    "deliverable"
  else
    "assignment"
  end
end

#registered_students_and_students_on_teams_hashObject


366
367
368
369
370
371
372
373
374
375
376
377
# File 'app/models/course.rb', line 366

def registered_students_and_students_on_teams_hash
  students = Hash.new
  self.registered_students.each do |student|
    students[student.human_name] = {:hub => true}
  end
  self.teams.each do |team|
    team.members.each do |user|
      students[user.human_name] = (students[user.human_name] || Hash.new).merge({:team => true, :team_name => team.name})
    end
  end
  return students
end

#registered_students_or_on_teamsObject


321
322
323
# File 'app/models/course.rb', line 321

def registered_students_or_on_teams
  self.registered_students | self.teams.collect { |team| team.members }.flatten
end

#short_or_course_numberObject


109
110
111
112
113
114
115
# File 'app/models/course.rb', line 109

def short_or_course_number
  unless self.short_name.blank?
    self.short_name
  else
    self.number
  end
end

#short_or_full_nameObject


101
102
103
104
105
106
107
# File 'app/models/course.rb', line 101

def short_or_full_name
  unless self.short_name.blank?
    self.short_name
  else
    self.name
  end
end

#sortable_valueObject


201
202
203
# File 'app/models/course.rb', line 201

def sortable_value
  self.year.to_i * 100 + self.course_end
end

#update_email_addressObject


296
297
298
# File 'app/models/course.rb', line 296

def update_email_address
  self.email = build_email
end

#update_facultyObject

When modifying validate_faculty or update_faculty, modify the same code in team.rb Todo - move to a higher class or try as a mixin


226
227
228
229
230
231
232
233
234
235
236
# File 'app/models/course.rb', line 226

def update_faculty
  return "" if faculty_assignments_override.nil?
  self.faculty = []

  self.faculty_assignments_override = faculty_assignments_override.select { |name| name != nil && name.strip != "" }
  list = map_member_strings_to_users(self.faculty_assignments_override)
  raise "Error converting faculty_assignments_override to IDs!" if list.include?(nil)
  self.faculty = list
  faculty_assignments_override = nil
  self.updating_email = true
end

#validate_faculty_assignmentsObject


76
77
78
# File 'app/models/course.rb', line 76

def validate_faculty_assignments
  validate_members :faculty_assignments_override
end