def global_stuff(request): try: header_image = Configuration.objects.get_or_create(name="Header Logo")[0].file.url except: header_image = None school_name = Configuration.get_or_default('School Name', default="Unnamed School") school_color = Configuration.get_or_default('School Color', default="").value google_analytics_code = Configuration.get_or_default('Google Analytics').value # Only show messages if user just logged in user_messages = None if not request.session.get('has_seen_message', False) and request.user.is_authenticated(): today = datetime.date.today() if request.user.groups.filter(name='students'): user_messages = MessageToStudent.objects.filter(start_date__lte=today, end_date__gte=today) if request.user.groups.filter(name='company') and 'work_study' in settings.INSTALLED_APPS: from work_study.models import MessageToSupervisor user_messages = MessageToSupervisor.objects.filter(start_date__lte=today, end_date__gte=today) request.session['has_seen_message'] = True return { "header_image": header_image, "school_name": school_name, "settings": settings, "school_color": school_color, 'user_messages':user_messages, 'google_analytics_code': google_analytics_code, }
def get_active_class_config(): if Configuration.get_or_default("Only Active Classes in Schedule", None).value == "True" \ or Configuration.get_or_default("Only Active Classes in Schedule", None).value == "true" \ or Configuration.get_or_default("Only Active Classes in Schedule", None).value == "T": return "True" else: return "False"
def get_appy_context(self): context = super(SisReport, self).get_appy_context() context['date'] = datetime.date.today() students = context['objects'] template = self.report_context.get('template') if template: self.date_end = self.report_context['date_end'] # backwards compatibility for templates context['date_of_report'] = self.date_end context['school_year'] = self.report_context['school_year'] context['school_name'] = Configuration.get_or_default(name="School Name") if template.transcript: self.pass_score = float(Configuration.get_or_default("Passing Grade", '70').value) self.pass_letters = Configuration.get_or_default("Letter Passing Grade", 'A,B,C,P').value for student in students: self.get_student_transcript_data(student) if template.benchmark_report_card and \ 'benchmark_grade' in settings.INSTALLED_APPS: from benchmark_grade.report import get_benchmark_report_card_data get_benchmark_report_card_data(self.report_context, context, students) elif template.report_card: self.blank_grade = struct() self.blank_grade.comment = "" school_year = SchoolYear.objects.filter(start_date__lte=self.report_context['date_end'] ).order_by('-start_date').first() context['year'] = school_year self.marking_periods = MarkingPeriod.objects.filter( school_year=school_year, show_reports=True) context['marking_periods'] = self.marking_periods.order_by('start_date') for student in students: self.get_student_report_card_data(student) if template.general_student: cal = Calendar() schedule_days = self.report_context.get('schedule_days', None) marking_periods = MarkingPeriod.objects.filter(start_date__gte=self.report_context['date_end'], end_date__lte=self.report_context['date_end']).order_by('start_date') if not marking_periods.count(): marking_periods = MarkingPeriod.objects.filter(start_date__gte=self.report_context['date_begin']).order_by('start_date') current_mp = marking_periods[0] for student in students: if current_mp: student.schedule_days, student.periods = cal.build_schedule(student, current_mp, schedule_days=schedule_days) #student.discipline_records = student.studentdiscipline_set.filter(date__gte=begin_end_dates[0], # date__lte=begin_end_dates[1]) #for d in student.discipline_records: # d.date = d.date.strftime('%b %d, %Y') context['students'] = students return context
def get_email(self): """ Returns email address using various configurable methods """ email_method = Configuration.get_or_default( "How to obtain student email", default="append", help_text="append, user, or student.").value if email_method == "append": email_end = Configuration.get_or_default("email", default="@change.me").value return '%s%s' % (self.student.username, email_end) elif email_method == "user": if User.objects.filter(username=self.student.username): return User.objects.filter(username=self.student.username)[0].email return None return self.alt_email
def get_report(self, report_view, context): marking_periods = report_view.report.report_context['marking_periods'] # anticipate str(student.year) students = Student.objects.select_related('year__name').filter( courseenrollment__course__marking_period__in=marking_periods ).distinct() titles = [''] departments = Department.objects.filter(course__courseenrollment__user__is_active=True).distinct() for department in departments: titles += [str(department)] titles += ['Total', '', 'Username', 'Year','GPA', '', 'Failed courses'] passing_grade = float(Configuration.get_or_default('Passing Grade','70').value) data = [] iy=2 for student in students: row = [str(student)] ix = 1 # letter A # query the database once per student, not once per student per department # anticipate calling str() on grade.course and grade.marking_period student.failed_grades = student.grade_set.select_related( 'course__department_id', 'course__fullname', 'marking_period__name', ).filter( override_final=False, grade__lt=passing_grade, marking_period__in=marking_periods ).distinct() department_counts = {} end_of_row = [] for grade in student.failed_grades: # every failing grade gets dumped out at the end of the row end_of_row += [ str(grade.course), str(grade.marking_period), str(grade.grade) ] # add one to the failed grade count for this department department_counts[grade.course.department_id] = department_counts.get( grade.course.department_id, 0) + 1 for department in departments: row += [department_counts.get(department.pk, 0)] ix += 1 row += [ '=sum(b{0}:{1}{0})'.format(str(iy),get_column_letter(ix)), '', student.username, str(student.year), student.gpa, '', ] row += end_of_row data += [row] iy += 1 return report_view.list_to_xlsx_response(data, 'fail_report', header=titles)
def build_schedule(self, student, marking_period, include_asp=False, schedule_days=None): """ Returns days ['Monday', 'Tuesday'...] and periods """ periods = Period.objects.filter(course__courseenrollment__user=student, course__marking_period=marking_period).order_by('start_time').distinct() course_meets = CourseMeet.objects.filter(course__courseenrollment__user=student, course__marking_period=marking_period).distinct() if schedule_days is None: day_list = CourseMeet.day_choice else: # super ugly day_choices = dict(CourseMeet.day_choice) day_list = [] for schedule_day in schedule_days: day_list.append((schedule_day, day_choices[schedule_day])) days = [] arr_days = [] for day in day_list: if course_meets.filter(day=day[0]).count(): days.append(day[1]) arr_days.append(day) only_active = Configuration.get_or_default("Only Active Classes in Schedule", "False").value in \ ['T', 'True', '1', 't', 'true'] hide_meetingless = Configuration.get_or_default('Hide Empty Periods in Schedule').value in \ ['T', 'True', '1', 't', 'true'] useful_periods = [] for period in periods: has_meeting = False period.days = [] for day in arr_days: if only_active: course = course_meets.filter(day=day[0], period=period, course__active=True) else: course = course_meets.filter(day=day[0], period=period) if course.count(): period.days.append(course[0]) has_meeting = True else: period.days.append(None) if has_meeting or not hide_meetingless: useful_periods.append(period) return days, useful_periods
def get_start_date_default(): """ Return default date for report. It should be X work days ago. """ work_days = (0,1,2,3,4) # python day of weeks mon-fri # Traverse back these many days days_back = int(Configuration.get_or_default('Discipline Merit Default Days', default=14).value) default_date = datetime.date.today() while days_back > 0: while not default_date.weekday() in work_days: default_date = default_date - datetime.timedelta(days=1) default_date = default_date - datetime.timedelta(days=1) days_back -= 1 return default_date
def global_stuff(request): try: header_image = Configuration.objects.get_or_create( name="Header Logo")[0].file.url except: header_image = None school_name = Configuration.get_or_default('School Name', default="Unnamed School") school_color = Configuration.get_or_default('School Color', default="").value google_analytics_code = Configuration.get_or_default( 'Google Analytics').value # Only show messages if user just logged in user_messages = None if not request.session.get('has_seen_message', False) and request.user.is_authenticated(): today = datetime.date.today() if request.user.groups.filter(name='students'): user_messages = MessageToStudent.objects.filter( start_date__lte=today, end_date__gte=today) if request.user.groups.filter( name='company') and 'work_study' in settings.INSTALLED_APPS: from work_study.models import MessageToSupervisor user_messages = MessageToSupervisor.objects.filter( start_date__lte=today, end_date__gte=today) request.session['has_seen_message'] = True return { "header_image": header_image, "school_name": school_name, "settings": settings, "school_color": school_color, 'user_messages': user_messages, 'google_analytics_code': google_analytics_code, }
def save(self, creating_worker=False, *args, **kwargs): # self.cache_cohorts() if self.is_active == False and (Configuration.get_or_default("Clear Placement for Inactive Students","False").value == "True" \ or Configuration.get_or_default("Clear Placement for Inactive Students","False").value == "true" \ or Configuration.get_or_default("Clear Placement for Inactive Students","False").value == "T"): try: self.studentworker.placement = None except: pass # Check year self.determine_year() super(Student, self).save(*args, **kwargs) # Create student worker if the app is installed. # https://code.djangoproject.com/ticket/7623 if 'work_study' in settings.INSTALLED_APPS: if not creating_worker and not hasattr(self, 'studentworker'): from work_study.models import StudentWorker worker = StudentWorker(user_ptr_id=self.user_ptr_id) worker.__dict__.update(self.__dict__) worker.save(creating_worker=True) group, gcreated = Group.objects.get_or_create(name="students") self.user_ptr.groups.add(group)
def save(self, *args, **kwargs): email = False emailStu = False if not self.supervisor_key or self.supervisor_key == "": # Use previous key if one exists if self.id: ts = TimeSheet.objects.get(id=self.id) self.supervisor_key = ts.supervisor_key else: self.genKey() email = True # set hours hours = self.time_lunch.hour - self.time_in.hour mins = self.time_lunch.minute - self.time_in.minute hours += self.time_out.hour - self.time_lunch_return.hour mins += self.time_out.minute - self.time_lunch_return.minute hours += mins/Decimal(60) self.hours = hours # set pay rates if self.for_pay and not self.school_pay_rate and not self.student_pay_rate: try: self.school_pay_rate = self.student.school_pay_rate self.student_pay_rate = self.student.student_pay_rate except: print >> sys.stderr, "warning: pay rate for company not set. " # set payment net sum if self.school_pay_rate: self.school_net = self.hours * self.school_pay_rate if self.student_pay_rate: self.student_net = self.hours * self.student_pay_rate super(TimeSheet, self).save(*args, **kwargs) self.student = StudentWorker.objects.get(id=self.student.id) # refresh data for p contact if email and self.student.primary_contact: try: sendTo = self.student.primary_contact.email subject = "Time Sheet for " + str(self.student) msg = "Hello " + unicode(self.student.primary_contact.fname) + ",\nPlease click on the link below to approve the time sheet.\n" + \ get_base_url() + "/work_study/approve?key=" + str(self.supervisor_key) from_addr = Configuration.get_or_default("From Email Address", "*****@*****.**").value send_mail(subject, msg, from_addr, [sendTo]) except: print >> sys.stderr, "Unable to send e-mail to supervisor! %s" % (self,)
def fte_by_day(request): cursor = connection.cursor() fte = int( Configuration.get_or_default(name="Students per FTE"[0], default=5).value) cursor.execute("select day, count(*)/" + str(fte) + \ " from work_study_studentworker left join work_study_workteam on work_study_workteam.id = "+\ "work_study_studentworker.placement_id where work_study_workteam.inactive = False group by day;") names = cursor.fetchall() titles = (["Day", "FTE"]) report = XlReport(file_name="report_fteByDay") report.add_sheet(names, header_row=titles, title="FTE by Day of Week", heading="FTE by Day of Week") return report.as_download()
def emailStudent(self, show_comment=True): try: sendTo = self.student.get_email subject = "Time sheet approved for " + unicode(self.student) if show_comment: msg = "Hello " + unicode(self.student) + ",\nYour time card for " + self.date.strftime("%x") + " was approved. Your rating was " + unicode(self.performance) + " \nYour supervisor's comment was \"" \ + unicode(self.supervisor_comment) + "\"" else: msg = "Hello " + unicode(self.student) + ",\nYour time card for " + self.date.strftime("%x") + " was approved." from_addr = Configuration.get_or_default("From Email Address", "*****@*****.**").value send_mail(subject, msg, from_addr, [str(sendTo)]) except: logging.warning('Could not e-mail student', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], })
def save(self, *args, **kwargs): super(ClientVisit, self).save(*args, **kwargs) if self.notify_mentors: try: users = User.objects.filter(groups__name='mentor') sendTo = [] for user in users: sendTo.append(user.email) subject = "CRA visit at " + unicode(self.company) msg = "A CRA report has been entered for " + unicode( self.company) + " on " + unicode( self.date) + ".\n" + unicode(self.notes) from_addr = Configuration.get_or_default( "From Email Address", "*****@*****.**").value send_mail(subject, msg, from_addr, sendTo) except: print >> sys.stderr, "warning: could not e-mail mentors"
def select_grade_method(request): """ Select a per user preferred grading method Forward to previously requested page after """ pref = UserPreference.objects.get_or_create(user=request.user)[0] if request.POST and 'choice' in request.POST: pref.gradebook_preference = request.POST['choice'] pref.save() options = [] if 'benchmark_grade' in settings.INSTALLED_APPS: options += ['O'] if 'engrade_sync' in settings.INSTALLED_APPS: options += ['E'] allow_spreadsheet = Configuration.get_or_default( 'grades_allow_spreadsheet_import').value if allow_spreadsheet == 'True': options += ['S'] else: allow_spreadsheet = False if request.user.has_perm('grades.change_own_grade' ) or request.user.has_pem('grades.change_grade'): options += ['M'] allow_manual = True if not pref.gradebook_preference and len(options) == 1: pref.gradebook_preference = options[0] pref.save() if pref.gradebook_preference and (not 'override' in request.GET or request.POST): if 'next' in request.GET: next_page = request.GET['next'] if next_page == "teacher_grade": return redirect('grades.views.teacher_grade') return render_to_response( 'grades/select_grade_method.html', { 'request': request, 'allow_spreadsheet': allow_spreadsheet, 'allow_manual': allow_manual }, RequestContext(request, {}), )
def change_view(self, request, object_id, extra_context=None): levels = [] applicant = get_object_or_404(Applicant, id=object_id) # Attempt to guess next school year future_years = SchoolYear.objects.filter( start_date__gt=datetime.date.today()).order_by('start_date') if future_years: override_date = Configuration.get_or_default( name="admissions_override_year_start", default='', help_text="Must be ISO date (ex 2012-10-25) or blank", ).value if override_date: try: override_date = parser.parse(override_date) future_years[0].start_date = override_date except: pass year = future_years[0] else: year = None for level in AdmissionLevel.objects.all(): level.checks = [] level.max = 0 for check in AdmissionCheck.objects.filter(level=level): level.checks.append(check) level.max += 1 if object_id: if check in applicant.checklist.all(): check.checked = True else: check.checked = False levels.append(level) my_context = { 'levels': levels, 'current_level': applicant.level, 'year': year, } return super(ApplicantAdmin, self).change_view(request, object_id, extra_context=my_context)
def save(self, *args, **kwargs): if not self.id: new = True else: new = False super(StudentInteraction, self).save(*args, **kwargs) #email if needed if self.student.count() >= 1 and new: try: stu = self.student.all()[0] subject = unicode(self) msg = "Hello CRA " + unicode(stu.placement.cra.name.first_name) + ",\n" for aStudent in self.student.all(): msg += unicode(aStudent.fname) + " " + unicode(aStudent.lname) + ", " msg = msg[:-2] + " had a mentor meeting on " + unicode(self.date) + "\n" + unicode(self.comments) + "\n" for com in self.preset_comment.all(): msg += unicode(com) + "\n" from_addr = Configuration.get_or_default("From Email Address", "*****@*****.**").value send_mail(subject, msg, from_addr, [unicode(stu.placement.cra.name.email)]) except: print >> sys.stderr, "warning: could not e-mail CRA"
def fte_by_ind(request): """ FTE by industry """ cursor = connection.cursor() fte = int( Configuration.get_or_default(name="Students per FTE"[0], default=5).value) cursor.execute("select industry_type, count(*)/" + str(fte) + \ " from work_study_studentworker left join work_study_workteam on work_study_workteam.id = "+\ "work_study_studentworker.placement_id where work_study_workteam.inactive = False group by industry_type;") names = cursor.fetchall() titles = (["Industry", "FTE"]) report = XlReport(file_name="report_fteByInd") report.add_sheet(data=names, header_row=titles, title="Analytics Report", heading="FTE by Industry Type") report.add_sheet(data=student_company_day_report(industry_type=True), heading="Detail") return report.as_download()
def fte_by_pay(request): report = XlReport(file_name="report_fteByPay") student_fte = int(Configuration.get_or_default(name="Students per FTE"[0], default=5).value) cursor = connection.cursor() cursor.execute("select paying, count(*)/" + str(student_fte) + \ " from work_study_studentworker left join work_study_workteam on work_study_workteam.id = "+\ "work_study_studentworker.placement_id where work_study_workteam.inactive = False group by paying;") totals = cursor.fetchall() cursor = connection.cursor() cursor.execute("select team_name, paying, count(*)/" + str(student_fte) + ", funded_by as fte from work_study_studentworker left join work_study_workteam on "+\ "work_study_workteam.id = work_study_studentworker.placement_id group by team_name order by paying, team_name;") company = cursor.fetchall() titles = (["Paying?","FTE"]) report.add_sheet(totals, header_row=titles, title="Totals") titles = (["WorkTeam", "Paying?","FTE", "Funded by"]) report.add_sheet(company, header_row=titles, title="Companies") report.add_sheet(student_company_day_report(paying=True), heading="Detail") return report.as_download()
def calculate_final_grade(self, student, date_report=None): """Calculates final grade. Does not take into account overrides. Note that this should math recalc_ytd_grade in gradesheet.js! """ from SMS.grades.models import Grade final = Decimal(0) number = 0 letter_grade = False grades = Grade.objects.filter(student=student, course=self) if date_report: grades = grades.filter(marking_period__end_date__lte=date_report) for grade in grades: try: final += grade.get_grade() number += 1 # otherwise it's a letter grade. except TypeError: # I (Incomplete) results in the final grade being I if grade.get_grade() == "I": return "I" elif grade.get_grade() in ["P", "HP", "LP"]: final += 100 number += 1 letter_grade = True elif grade.get_grade() == 'F': number += 1 letter_grade = True if number != 0: final = final / number final = Decimal(final).quantize(Decimal("0.01"), ROUND_HALF_UP) if letter_grade == True: if final > int( Configuration.get_or_default( 'letter_grade_required_for_pass', '60').value): return "P" else: return "F" else: final = None return final
def post_save_attendance_handler(sender, instance, **kwargs): """ Check for any triggers we should run """ if True: try: # Create work study attendance if student's workday is today if ('ecwsp.work_study' in settings.INSTALLED_APPS and Configuration.get_or_default("attendance_create_work_attendance", "False").value == "True" and instance.date == datetime.date.today() and instance.status.absent and hasattr(instance.student, 'studentworker') and instance.student.studentworker and datetime.date.today().isoweekday() == instance.student.studentworker.get_day_as_iso_date() ): from ecwsp.work_study.models import Attendance attn, created = Attendance.objects.get_or_create( student=instance.student.studentworker, absence_date = datetime.date.today(), ) if created: attn.sis_attendance = instance attn.save() except: logging.error('Attendance trigger error', exc_info=True)
def save(self, *args, **kwargs): try: previous = StudentWorker.objects.get(id=self.id) if previous.placement != self.placement: history = CompanyHistory(student = self, placement = previous.placement) history.save() # set primary contact to None if company has changed and p_contact isn't explicitly set if previous.primary_contact == self.primary_contact: self.primary_contact = None except: pass if self.primary_contact and self.placement: self.placement.contacts.add(self.primary_contact) # set pay rates if not self.school_pay_rate and not self.student_pay_rate: try: self.school_pay_rate = Decimal(Configuration.get_or_default("school pay rate per hour", default="13.00").value) self.student_pay_rate = Decimal(Configuration.objects.get("student pay rate per hour", default="9").value) except: pass super(StudentWorker, self).save(*args, **kwargs)
def post_save_attendance_handler(sender, instance, **kwargs): """ Check for any triggers we should run """ if True: try: # Create work study attendance if student's workday is today if ('ecwsp.work_study' in settings.INSTALLED_APPS and Configuration.get_or_default( "attendance_create_work_attendance", "False").value == "True" and instance.date == datetime.date.today() and instance.status.absent and hasattr(instance.student, 'studentworker') and instance.student.studentworker and datetime.date.today().isoweekday() == instance.student.studentworker.get_day_as_iso_date()): from ecwsp.work_study.models import Attendance attn, created = Attendance.objects.get_or_create( student=instance.student.studentworker, absence_date=datetime.date.today(), ) if created: attn.sis_attendance = instance attn.save() except: logging.error('Attendance trigger error', exc_info=True)
def calculate_grade_real(self, date_report=None, ignore_letter=False): """ Calculate the final grade for a course ignore_letter can be useful when computing averages when you don't care about letter grades """ cursor = connection.cursor() # postgres requires a over () to run # http://stackoverflow.com/questions/19271646/how-to-make-a-sum-without-group-by sql_string = ''' SELECT ( Sum(grade * weight) {over} / Sum(weight) {over} ) AS ave_grade, grades_grade.id, grades_grade.override_final FROM grades_grade LEFT JOIN schedule_markingperiod ON schedule_markingperiod.id = grades_grade.marking_period_id WHERE ( grades_grade.course_id = %s AND grades_grade.student_id = %s {extra_where} ) AND ( grade IS NOT NULL OR letter_grade IS NOT NULL ) ORDER BY grades_grade.override_final DESC limit 1''' if date_report: if settings.DATABASES['default'][ 'ENGINE'] == 'django.db.backends.postgresql_psycopg2': cursor.execute( sql_string.format( over='over ()', extra_where= 'AND (schedule_markingperiod.end_date <= %s OR override_final = 1)' ), (self.course_id, self.user_id, date_report)) else: cursor.execute( sql_string.format( over='', extra_where= 'AND (schedule_markingperiod.end_date <= %s OR grades_grade.override_final = 1)' ), (self.course_id, self.user_id, date_report)) else: if settings.DATABASES['default'][ 'ENGINE'] == 'django.db.backends.postgresql_psycopg2': cursor.execute( sql_string.format(over='over ()', extra_where=''), (self.course_id, self.user_id)) else: cursor.execute(sql_string.format(over='', extra_where=''), (self.course_id, self.user_id)) result = cursor.fetchone() if result: (ave_grade, grade_id, override_final) = result else: # No grades at all. The average of no grades is None return None if override_final: course_grades = grades.models.Grade.objects.get(id=grade_id) grade = course_grades.get_grade() if ignore_letter and not isinstance(grade, (int, Decimal, float)): return None return grade if ave_grade: # database math always comes out as a float :( return Decimal(ave_grade) # about 0.5 s # Letter Grade if ignore_letter == False: final = 0.0 grades = self.course.grade_set.filter(student=self.user) if date_report: grades = grades.filter( marking_period__end_date__lte=date_report) if grades: total_weight = Decimal(0) for grade in grades: get_grade = grade.get_grade() if get_grade in ["I", "IN", "YT"]: return get_grade elif get_grade in ["P", "HP", "LP"]: if grade.marking_period: final += float(100 * grade.marking_period.weight) total_weight += grade.marking_period.weight elif get_grade in ['F', 'M']: if grade.marking_period: total_weight += grade.marking_period.weight elif get_grade: final += get_grade if total_weight: final /= float(total_weight) final = Decimal(final).quantize(Decimal("0.01"), ROUND_HALF_UP) if final > int( Configuration.get_or_default( 'letter_grade_required_for_pass').value): return "P" else: return "F" return None
class Course(models.Model): active = models.BooleanField( default=True, help_text="Sometimes used in third party integrations such as Moodle.") fullname = models.CharField(max_length=255, unique=True) shortname = models.CharField(max_length=255) #marking_period = models.ManyToManyField(MarkingPeriod, blank=True) start_date = models.DateField(validators=settings.DATE_VALIDATORS) end_date = models.DateField(validators=settings.DATE_VALIDATORS) #periods = models.ManyToManyField(CourseMeet, blank=True)#, through=CourseMeet) teacher = models.ForeignKey('profiles.Faculty', blank=True, null=True, related_name="ateacher") secondary_teachers = models.ManyToManyField( 'profiles.Faculty', blank=True, null=True, related_name="secondary_teachers") homeroom = models.BooleanField( default=False, help_text="Homerooms can be used for attendance") graded = models.BooleanField( default=True, help_text="Teachers can submit grades for this course") enrollments = models.ManyToManyField('auth.User', through=CourseEnrollment, blank=True, null=True) description = models.TextField(blank=True) credits = models.DecimalField(max_digits=5, decimal_places=2, help_text="Credits affect GPA.", default=lambda: Configuration.get_or_default( name='Default course credits').value) award_credits = models.BooleanField( default=True, help_text='''When disabled, course will not be included in any student's credit totals. However, the number of credits will still be used as a weight in GPA calculations.''') department = models.ForeignKey(Department, blank=True, null=True) level = models.ForeignKey('profiles.GradeLevel', blank=True, null=True) last_grade_submission = models.DateTimeField( blank=True, null=True, editable=False, validators=settings.DATE_VALIDATORS) def __unicode__(self): return self.fullname def save(self, *args, **kwargs): super(Course, self).save(*args, **kwargs) # assign teacher in as enrolled user try: if self.teacher: enroll, created = CourseEnrollment.objects.get_or_create( course=self, user=self.teacher, role="teacher") except: pass @staticmethod def autocomplete_search_fields(): return ( "shortname__icontains", "fullname__icontains", ) def grades_link(self): link = '<a href="/grades/teacher_grade/upload/%s" class="historylink"> Grades </a>' % ( self.id, ) return link grades_link.allow_tags = True def calculate_final_grade(self, student): """ Shim code to calculate final grade WITHOUT cache """ enrollment = self.courseenrollment_set.get(user=student, role="student") return enrollment.calculate_grade_real() def get_enrolled_students(self): return Student.objects.filter(courseenrollment__course=self) def copy_instance(self, request): changes = (("fullname", self.fullname + " copy"), ) new = duplicate(self, changes) for enroll in self.courseenrollment_set.all(): new_enrollment = CourseEnrollment( course=new, user=enroll.user, role=enroll.role, attendance_note=enroll.attendance_note) new_enrollment.save() for day in enroll.exclude_days.all(): new_enrollment.exclude_days.add(day) for cm in self.coursemeet_set.all(): new.coursemeet_set.create(location=cm.location, day=cm.day, period=cm.period) new.save() messages.success(request, 'Copy successful!') def number_of_students(self): return self.courseenrollment_set.filter(role="student").count() number_of_students.short_description = "# of Students"
def get_city(): return Configuration.get_or_default("Default City", "").value
def grade_comment_length_validator(value): max_length = int( Configuration.get_or_default('Grade comment length limit').value) validator = MaxLengthValidator(max_length) return validator(value)
def get_default_benchmark_grade(): return str( Configuration.get_or_default("Benchmark-based grading", "False").value).lower() == "true"
def get_default_one(): return int( Configuration.get_or_default('Discipline Merit Level One', default=0).value)
def get_default_two(): return int( Configuration.get_or_default('Discipline Merit Level Two', default=1).value)
def get_default_three(): return int(Configuration.get_or_default('Discipline Merit Level Three', default=3).value)
def get_default_four(): return int( Configuration.get_or_default('Discipline Merit Level Four', default=5).value)
def get_default_four(): return int(Configuration.get_or_default('Discipline Merit Level Four', default=5).value)
from datetime import date import logging from django.conf import settings from celery.task.schedules import crontab from celery.decorators import periodic_task from celery import task import sys if 'work_study' in settings.INSTALLED_APPS: if settings.SYNC_SUGAR: from work_study.sugar_sync import SugarSync modify_date_minutes = int( Configuration.get_or_default("sync sugarcrm minutes", default="30").value) @periodic_task(run_every=crontab(minute='*/%s' % (modify_date_minutes, ))) def update_contacts_from_sugarcrm(): sugar_sync = SugarSync() sugar_sync.update_contacts_from_sugarcrm() @task() def update_contact_to_sugarcrm(contact): sugar_sync = SugarSync() sugar_sync.update_contact(contact) @periodic_task(run_every=crontab(hour=20, minute=27)) def email_cra_nightly(): """ Email CRA nightly time sheet and student interaction information
def grade_comment_length_validator(value): max_length = int(Configuration.get_or_default('Grade comment length limit').value) validator = MaxLengthValidator(max_length) return validator(value)
def teacher_grade_upload(request, id): """ This view is for inputing grades. It usually is done by uploading a spreadsheet. However it can also be done by manually overriding grades. This requires registrar level access. """ course = Course.objects.get(id=id) students = Student.objects.filter(courseenrollment__course=course) grades = course.grade_set.all() if request.method == 'POST' and 'upload' in request.POST: import_form = GradeUpload(request.POST, request.FILES) if import_form.is_valid(): from profiles.importer import Importer importer = Importer(request.FILES['file'], request.user) error = importer.import_grades( course, import_form.cleaned_data['marking_period']) if error: messages.warning(request, error) else: course.last_grade_submission = datetime.datetime.now() course.save() else: import_form = GradeUpload() import_form.fields['marking_period'].queryset = import_form.fields[ 'marking_period'].queryset.filter(course=course) if request.method == 'POST' and 'edit' in request.POST: handle_grade_save(request, course) marking_periods = course.marking_period.all().order_by('start_date') # Ensure grades exists for mp in marking_periods: for student in students: grade, created = Grade.objects.get_or_create(student=student, course=course, marking_period=mp) for student in students: student.grades = student.grade_set.filter(course=course, override_final=False) try: student.final = student.grade_set.get( course=course, override_final=True).get_grade() student.final_override = True except Grade.DoesNotExist: student.final = course.calculate_final_grade(student) if request.user.is_superuser or \ request.user.has_perm('grades.change_own_final_grade') or \ request.user.has_perm('grades.change_grade'): edit_final = True else: edit_final = False if request.user.is_superuser or \ request.user.has_perm('grades.change_own_grade') or \ request.user.has_perm('grades.change_grade'): edit = True else: edit = False letter_grade_required_for_pass = Configuration.get_or_default( 'letter_grade_required_for_pass', '60').value return render_to_response( 'grades/teacher_grade_upload.html', { 'request': request, 'course': course, 'marking_periods': marking_periods, 'students': students, 'import_form': import_form, 'edit': edit, 'edit_final': edit_final, 'letter_grade_required_for_pass': letter_grade_required_for_pass }, RequestContext(request, {}), )
def get_default_one(): return int(Configuration.get_or_default('Discipline Merit Level One', default=0).value)
def get_default_two(): return int(Configuration.get_or_default('Discipline Merit Level Two', default=1).value)
def inquiry_form(request): """ A place for applicants to inquire for more info Places them in the database as an applicant Public view can be used by anyone """ css = Configuration.get_or_default('admissions_inquiry_form_css').value exclude_years = Configuration.get_or_default('admissions_hide_inquiry_grade').value.split(',') valid_years = GradeLevel.objects.all() if exclude_years: try: valid_years = valid_years.exclude(id__in=exclude_years) except: valid_years = GradeLevel.objects.all() if request.POST: form = InquiryForm(request.POST) if form.is_valid(): data = form.cleaned_data applicant = form.save() applicant.from_online_inquiry = True if data['ethnicity_other']: applicant.ethnicity = EthnicityChoice.objects.get_or_create(name=data['ethnicity_other'])[0] if data['language_other']: applicant.family_preferred_language = LanguageChoice.objects.get_or_create(name=data['language_other'])[0] if data['religion_other']: applicant.religion = ReligionChoice.objects.get_or_create(name=data['religion_other'])[0] if data['p_lname'] and data['p_fname']: ec = EmergencyContact.objects.get_or_create( fname=data['p_fname'], lname=data['p_lname'], relationship_to_student=data['p_relationship_to_child'], street=data['p_address'], city=data['p_city'], state=data['p_state'], zip=data['p_zip'], email=data['p_email'], )[0] applicant.parent_guardians.add(ec) if data['p_home']: EmergencyContactNumber.objects.get_or_create( contact=ec, number=data['p_home'], type="H" ) if data['p_work']: ec_number = EmergencyContactNumber.objects.get_or_create( contact=ec, number=data['p_work'], ext=data['p_work_ext'], type="W" ) if data['p_mobile']: ec_number = EmergencyContactNumber.objects.get_or_create( contact=ec, number=data['p_mobile'], type="C" ) applicant.save() log = ContactLog( applicant=applicant, date=datetime.date.today(), note="Sent online inquiry form", ) log.save() return HttpResponse('Thank you for submitting an inquiry!') else: form = InquiryForm() form.fields['year'].queryset = valid_years return render_to_response('admissions/inquiry_form.html', { 'form': form, 'css': css, }, RequestContext(request, {}), )
def email_cra_nightly(): """ Email CRA nightly time sheet and student interaction information """ from_email = Configuration.objects.get_or_create( name="From Email Address")[0].value cras = CraContact.objects.filter(email=True) for cra in cras: msg = "Student(s): " subject = "SWORD student interactions" interactions = StudentInteraction.objects.filter( date__year=date.today().year, date__day=date.today().day, date__month=date.today().month).filter( student__placement__cras=cra) if interactions.count() > 0: for interaction in interactions: for student in interaction.student.all(): msg += unicode(student) + " " msg += "\n" msg += interaction.comments msg += "\n" for preset in interaction.preset_comment.all(): msg += unicode(preset) + "\n" try: send_mail(subject, msg, from_email, [unicode(cra.name.email)]) except: logging.warning('Could not email interactions', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], }) cras = CraContact.objects.filter(email=True).filter(email_all=False) for cra in cras: msg = "" subject = "SWORD comments" send = False timesheets = TimeSheet.objects.filter(company__cras=cra).filter( cra_email_sent=False, creation_date__month=date.today().month).order_by( 'company__team_name') if timesheets.count(): for timesheet in timesheets: if timesheet.supervisor_comment or timesheet.performance or timesheet.student_accomplishment: send = True if timesheet.show_student_comments: showtxt = "Student was able to view comments" else: showtxt = "Student was not allowed to view comments" msg += unicode(timesheet.student) + ": " + unicode(timesheet.performance) + "\nsupervisor: " + \ unicode(timesheet.company) + " - " + unicode(timesheet.student.primary_contact) + "\n" + \ unicode(timesheet.supervisor_comment) + "\nstudent: " + unicode(timesheet.student_accomplishment) + \ showtxt + "\n" if timesheet.approved: msg += "Timesheet approved by supervisor\n\n" else: msg += "Timesheet not yet approved by supervisor\n\n" # Now get students who are present but did not submit a time card students = StudentWorker.objects.filter( attendance__absence_date=date.today(), attendance__tardy="P", timesheet__company__cras=cra).exclude( timesheet__date=date.today()).distinct() if students: msg += "The following students were present but did not submit time sheets:\n" for student in students: msg += "{0}, ".format(student) msg = msg[:-2] try: send_mail(subject, msg, from_email, [unicode(cra.name.email)]) except: logging.warning('Could not email CRA', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], }) cras = CraContact.objects.filter(email_all=True) for cra in cras: msg = "" subject = "SWORD comments" send = False timesheets = TimeSheet.objects.filter( cra_email_sent=False, creation_date__month=date.today().month).order_by( 'company__cras', 'company__team_name') if timesheets.count() > 0: for timesheet in timesheets: if timesheet.supervisor_comment or timesheet.performance or timesheet.student_accomplishment: send = True msg += unicode(timesheet.student) + ": " + unicode(timesheet.performance) + "\nsupervisor: " + \ unicode(timesheet.company) + " - " + unicode(timesheet.student.primary_contact) + "\n" + \ unicode(timesheet.supervisor_comment) + "\nstudent: " + unicode(timesheet.student_accomplishment) + "\n" if timesheet.approved: msg += "Timesheet approved by supervisor\n\n" else: msg += "Timesheet not yet approved by supervisor\n\n" # Now get students who are present but did not submit a time card students = StudentWorker.objects.filter( attendance__absence_date=date.today(), attendance__tardy="P").exclude( timesheet__date=date.today()) if students: msg += "The following students were present but did not submit time sheets:\n" for student in students: msg += smart_unicode(student) + ", " msg = msg[:-2] try: send_mail(subject, msg, from_email, [unicode(cra.name.email)]) except: logging.warning('Could not email CRA all comments', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], }) # Check off time sheets that were processed today (so they aren't processed tomorrow) timesheets = TimeSheet.objects.filter( creation_date__month=date.today().month, cra_email_sent=False) for timesheet in timesheets: timesheet.cra_email_sent = True timesheet.save() # Remind students to submit time sheets students = StudentWorker.objects.filter( attendance__absence_date=date.today(), attendance__tardy="P").exclude(timesheet__date=date.today()) subject = "Timesheet not submitted" for student in students: msg = "Hello {0},\n" conf_msg = Configuration.get_or_default( "work_study message to student missing time sheet", default= "You did not submit a time card today. Please remember to do so. This is an automated message, please do not reply." ) msg += conf_msg.value email = student.get_email if email and email[-9:] != "change.me": try: send_mail(subject, msg, from_email, [unicode(email)]) except: logging.warning( 'Could not email student about missing time card', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], })
def calculate_grade_real(self, date_report=None, ignore_letter=False): """ Calculate the final grade for a course ignore_letter can be useful when computing averages when you don't care about letter grades """ cursor = connection.cursor() # postgres requires a over () to run # http://stackoverflow.com/questions/19271646/how-to-make-a-sum-without-group-by sql_string = ''' SELECT ( Sum(grade * weight) {over} / Sum(weight) {over} ) AS ave_grade, grades_grade.id, grades_grade.override_final FROM grades_grade LEFT JOIN schedule_markingperiod ON schedule_markingperiod.id = grades_grade.marking_period_id WHERE ( grades_grade.course_id = %s AND grades_grade.student_id = %s {extra_where} ) AND ( grade IS NOT NULL OR letter_grade IS NOT NULL ) ORDER BY grades_grade.override_final DESC limit 1''' if date_report: if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql_psycopg2': cursor.execute(sql_string.format( over='over ()', extra_where='AND (schedule_markingperiod.end_date <= %s OR override_final = 1)'), (self.course_id, self.user_id, date_report)) else: cursor.execute(sql_string.format( over='', extra_where='AND (schedule_markingperiod.end_date <= %s OR grades_grade.override_final = 1)'), (self.course_id, self.user_id, date_report)) else: if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql_psycopg2': cursor.execute(sql_string.format( over='over ()', extra_where=''), (self.course_id, self.user_id)) else: cursor.execute(sql_string.format( over='', extra_where=''), (self.course_id, self.user_id)) result = cursor.fetchone() if result: (ave_grade, grade_id, override_final) = result else: # No grades at all. The average of no grades is None return None if override_final: course_grades = grades.models.Grade.objects.get(id=grade_id) grade = course_grades.get_grade() if ignore_letter and not isinstance(grade, (int, Decimal, float)): return None return grade if ave_grade: # database math always comes out as a float :( return Decimal(ave_grade) # about 0.5 s # Letter Grade if ignore_letter == False: final = 0.0 grades = self.course.grade_set.filter(student=self.user) if date_report: grades = grades.filter(marking_period__end_date__lte=date_report) if grades: total_weight = Decimal(0) for grade in grades: get_grade = grade.get_grade() if get_grade in ["I", "IN", "YT"]: return get_grade elif get_grade in ["P","HP","LP"]: if grade.marking_period: final += float(100 * grade.marking_period.weight) total_weight += grade.marking_period.weight elif get_grade in ['F', 'M']: if grade.marking_period: total_weight += grade.marking_period.weight elif get_grade: final += get_grade if total_weight: final /= float(total_weight) final = Decimal(final).quantize(Decimal("0.01"), ROUND_HALF_UP) if final > int(Configuration.get_or_default('letter_grade_required_for_pass').value): return "P" else: return "F" return None
def get_default_three(): return int( Configuration.get_or_default('Discipline Merit Level Three', default=3).value)