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 'ecwsp.work_study' in settings.INSTALLED_APPS: from ecwsp.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. # No other way to do it see: # https://code.djangoproject.com/ticket/7623 if 'ecwsp.work_study' in settings.INSTALLED_APPS: if not creating_worker and not hasattr(self, 'studentworker'): from ecwsp.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 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 build_schedule(self, student, marking_period, include_asp=False): """ 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() days = [] arr_days = [] for day in CourseMeet.day_choice: if course_meets.filter(day=day[0]).count(): days.append(day[1]) arr_days.append(day) for period in periods: period.days = [] for day in arr_days: if Configuration.get_or_default("Only Active Classes in Schedule", "False").value == "True" \ or Configuration.get_or_default("Only Active Classes in Schedule", "False").value == "true" \ or Configuration.get_or_default("Only Active Classes in Schedule", "False").value == "T": 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]) else: period.days.append(None) CourseMeet.objects.filter(course__courseenrollment__user=student, course__marking_period=marking_period, ).distinct() return days, periods
def ajax_get_student_info(request, course_id, student_id): student = get_object_or_404(Student, pk=student_id) course = get_object_or_404(Course, pk=course_id) # TODO: remove TC hard-coding try: Category.objects.get(name='Standards') # are we in TC land? standards_missing = Item.objects.filter(course=course, category__name='Standards', mark__student=student).annotate(best_mark=Max('mark__mark')).filter(best_mark__lt=3) if not standards_missing: standards_missing = ('None',) lists = ({'heading':'Standards Missing for {}'.format(student), 'items':standards_missing},) except Category.DoesNotExist: pass_letters = Configuration.get_or_default("Letter Passing Grade").value.split(',') pass_number = float(Configuration.get_or_default("Passing Grade").value) / 100 # yay, assumptions items_missing = Item.objects.filter(course=course, mark__student=student).annotate(best_mark=Max('mark__normalized_mark')).filter( best_mark__lt=pass_number) text_missing = [] for item in items_missing: if item.mark_set.get(student=student).letter_grade in pass_letters: continue text_missing.append(u'{} / {} ({:.0f}%) {}'.format( item.best_mark * float(item.points_possible), item.points_possible, item.best_mark * 100, unicode(item))) lists = ({'heading':'Items Missing for {}'.format(student), 'items':text_missing},) afterword = '<a onclick="open_grade_detail({}, {})">Create report from current view of gradebook (in new tab)</a>' afterword = afterword.format(course_id, student_id) return render_to_response('sis/generic_list_fragment.html', { 'lists': lists, 'afterword': afterword, }, RequestContext(request, {}),)
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 is_passing(self, student, date_report=None): """ Is student passing course? """ pass_score = float(Configuration.get_or_default("Passing Grade", "70").value) grade = self.get_final_grade(student, date_report=date_report) try: if grade >= int(pass_score): return True except: pass_letters = Configuration.get_or_default("Letter Passing Grade", "A,B,C,P").value if grade in pass_letters.split(","): return True return False
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_user_excludes(self): # get user-configured exclusions at runtime allowed_exclude = set(['marking_period', 'assignment_type', 'benchmark', 'date', 'description']) from ecwsp.administration.models import Configuration exclude = [x.strip() for x in Configuration.get_or_default('Gradebook hide fields').value.lower().split(',')] exclude = set(exclude).intersection(allowed_exclude) return list(exclude)
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 save(self, saved_by_volunteer=False, *args, **kwargs): if not self.secret_key or self.secret_key == "": self.genKey() if saved_by_volunteer: if not self.volunteer.email_queue: self.volunteer.email_queue = "" self.volunteer.email_queue += "Added site %s. " % (unicode(self.site)) self.volunteer.save() if self.id: old_volunteer = VolunteerSite.objects.get(id=self.id) if old_volunteer.site_approval == "Submitted" and self.site_approval == "Accepted": try: from django.core.mail import send_mail from_email = Configuration.get_or_default("From Email Address",default="*****@*****.**").value msg = "Hello %s,\nYour site %s has been approved!" % (self.volunteer, self.site) subject = "Site approval" send_to = self.volunteer.student.get_email send_mail(subject, msg, from_email, [send_to]) except: exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning( 'Unable to send email to volunteer about site approval! %s' % (self,), exc_info=True, extra={'request': request,'exception':exc_type,'traceback':'%s %s' % (fname,exc_tb.tb_lineno)} ) super(VolunteerSite, self).save(*args, **kwargs)
def add_view(self, request, form_url='', extra_context=None): levels = [] # 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 levels.append(level) my_context = { 'levels': levels, 'current_level': None, 'year': year, } return super(ApplicantAdmin, self).add_view(request, form_url, extra_context=my_context)
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 email student", exc_info=True, extra={"exception": sys.exc_info()[0], "exception2": sys.exc_info()[1]}, )
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'] context['date_of_report'] = self.date_end # backwards compatibility for templates 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 \ 'ecwsp.benchmark_grade' in settings.INSTALLED_APPS: from ecwsp.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_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=3 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__lte=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 save(self, *args, **kwargs): if not self.id: new = True else: new = False super(ReferralForm, self).save(*args, **kwargs) if new: try: subject = 'New counseling referral for %s.' % (self.student,) msg = '%s has submitted a counseling referral form for %s. Click this link to view \n%s%s' % \ (self.referred_by,self.student,settings.BASE_URL,reverse('admin:counseling_referralform_change',args=(self.id,)),) from_addr = Configuration.get_or_default("From Email Address", "*****@*****.**").value to_addr = Configuration.get_or_default("counseling_referral_notice_email_to", "").value.split(',') if to_addr and to_addr != ['']: send_mail(subject, msg, from_addr, to_addr) except: logging.error('Couldn\'t email counseling referral form', exc_info=True)
def update_contacts_from_sugarcrm(self): """ Query recently changed contacts in SugarCRM and sync them to django-sis """ modify_date_minutes = int(Configuration.get_or_default("sync sugarcrm minutes",default="30").value) modify_date = datetime.datetime.now() - datetime.timedelta(minutes=modify_date_minutes + 1) contacts = self.get_recent_sugar_contacts(modify_date) for contact in contacts: self.set_django_sis_contact(contact)
def is_passing(self, student, date_report=None, cache_grade=None, cache_passing=None, cache_letter_passing=None): """ Is student passing course? """ if cache_passing == None: pass_score = float(Configuration.get_or_default("Passing Grade", '70').value) else: pass_score = cache_passing if cache_grade: grade = cache_grade else: grade = self.get_final_grade(student, date_report=date_report) try: if grade >= int(pass_score): return True except: pass_letters = Configuration.get_or_default("Letter Passing Grade", 'A,B,C,P').value if grade in pass_letters.split(','): return True return False
def build_schedule(self, student, marking_period, include_asp=False, schedule_days=None): """ Returns days ['Monday', 'Tuesday'...] and periods """ periods = Period.objects.filter(coursesection__courseenrollment__user=student, coursesection__marking_period=marking_period).order_by('start_time').distinct() course_meets = CourseMeet.objects.filter(course_section__courseenrollment__user=student, course_section__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_section = course_meets.filter(day=day[0], period=period, course_section__is_active=True) else: course_section = course_meets.filter(day=day[0], period=period) if course_section.exists(): period.days.append(course_section[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 save(self, *args, **kwargs): if Faculty.objects.filter(id=self.id).count(): raise ValidationError('Cannot have someone be a student AND faculty!') self.cache_cohorts() if self.inactive == True 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) user, created = User.objects.get_or_create(username=self.username) if created: user.password = "******" user.save() group, gcreated = Group.objects.get_or_create(name="students") user.groups.add(group)
def applicants_to_students(request, year_id): """ Copies all applicants marked as ready for export to sis students Does not create copies. Once student is in sis he/she cannot be updated from applicant data.""" imp = Importer() school_year = SchoolYear.objects.get(id=year_id) msg = "" if request.POST: imp = Importer() applicants = Applicant.objects.filter(ready_for_export=True, sis_student=None, school_year=school_year) for appl in applicants: student = Student( first_name=appl.fname, mname=appl.mname, last_name=appl.lname, sex=appl.sex, ssn=appl.ssn, bday=appl.bday, unique_id=appl.unique_id, email=appl.email, year=appl.year, pic=appl.pic, family_preferred_language=appl.family_preferred_language, ) if not student.username: student.username = imp.gen_username(student.first_name, student.last_name) student.save() add_worker = Configuration.get_or_default("Admissions to student also makes student worker", "False") if add_worker.value == "True": student.promote_to_worker() appl.sis_student = student appl.save() for sib in appl.siblings.all(): student.siblings.add() for par in appl.parent_guardians.all(): student.emergency_contacts.add(par) student.save() for contact in student.emergency_contacts.filter(primary_contact=True): contact.cache_student_addresses() msg += "Imported <a href='/admin/sis/student/%s'>%s</a>, %s<br/>" % ( student.id, unicode(student), student.username, ) msg += "<br/>Maybe you want to save this list to add students to Active Directory or Google Apps?<br/><br/>" num = Applicant.objects.filter(ready_for_export=True, sis_student=None, school_year=school_year).count() msg += ( "There are currently %s applicants marked as ready for export. This is not a reversable process! Note usernames will be generated, you may change them later.<br/>" % str(num) ) return render_to_response("admissions/applicants_to_students.html", {"msg": msg}, RequestContext(request, {}))
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" + settings.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 email 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 email_admissions_new_inquiries(): """ Email Admissions team about new online inquiries """ from_email = Configuration.get_or_default("From Email Address").value to_email = Configuration.get_or_default('admissions_notify_email').value subject = "New online inquiries" today = datetime.date.today() new_inquiries = Applicant.objects.filter(date_added=today, from_online_inquiry=True) if new_inquiries: msg = "The following inquiries were submitted today\n" for inquiry in new_inquiries: msg += '\n<a href="{0}{1}">{2} {3}</a>\n'.format( settings.BASE_URL, reverse('admin:admissions_applicant_change', args=(inquiry.id,)), inquiry.fname, inquiry.lname) if Applicant.objects.filter(fname=inquiry.fname, lname=inquiry.lname).count() > 1: msg += "(May be duplicate)\n" send_mail(subject, msg, from_email, to_email.split(','))
def fte_by_day(request): fileName = "report_fteByDay.xls" 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 = xlsReport(names, titles, fileName, heading="FTE by Day of Week") report.addSheet(student_company_day_report(), heading="Detail") return report.finish()
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 email_admissions_new_inquiries(): """ Email Admissions team about new online inquiries """ from_email = Configuration.get_or_default("From Email Address").value to_email = Configuration.get_or_default('admissions_notify_email').value if not len(to_email): # don't complain if no one wants this report, just quit return # validate the from address try: validate_email(from_email) except ValidationError: logging.warning('email_admissions_new_inquiries failed because of invalid From Email Address "{}"'.format(from_email), exc_info=True) return # validate the to addresses to_email_list = [] for addr in to_email.split(','): try: print addr validate_email(addr) to_email_list.append(addr) except ValidationError: logging.warning('email_admissions_new_inquiries omitting invalid address "{}" in admissions_notify_email'.format(addr), exc_info=True) subject = "New online inquiries" today = datetime.date.today() new_inquiries = Applicant.objects.filter(date_added=today, from_online_inquiry=True) if new_inquiries: msg = "The following inquiries were submitted today\n" for inquiry in new_inquiries: msg += '\n<a href="{0}{1}">{2} {3}</a>\n'.format( settings.BASE_URL, reverse('admin:admissions_applicant_change', args=(inquiry.id,)), inquiry.fname, inquiry.lname) if Applicant.objects.filter(fname=inquiry.fname, lname=inquiry.lname).count() > 1: msg += "(May be duplicate)\n" send_mail(subject, msg, from_email, to_email_list)
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() if date_report: cursor.execute("SELECT (SUM(grade * weight) / sum(weight)) 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 AND schedule_markingperiod.end_date <= %s) and (grade is not null or letter_grade is not null ) ORDER BY `grades_grade`.`override_final` DESC limit 1", (self.course_id, self.user_id, date_report) ) else: cursor.execute("SELECT (SUM(grade * weight) / sum(weight)) AS `ave_grade`, `grades_grade`.`id`, `grades_grade`.`override_final` FROM `grades_grade` left join schedule_markingperiod on schedule_markingperiod.id=marking_period_id WHERE (`grades_grade`.`course_id` = %s AND `grades_grade`.`student_id` = %s ) and (grade is not null or letter_grade is not null ) ORDER BY `grades_grade`.`override_final` DESC limit 1", (self.course_id, self.user_id) ) (ave_grade, grade_id, override_final) = cursor.fetchone() if override_final: course_grades = ecwsp.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: return ave_grade.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) # 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"]: 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 calculate_final_grade(self, student, date_report=None): """ Calculates final grade. Note that this should match recalc_ytd_grade in gradesheet.js! """ if 'ecwsp.grades' in settings.INSTALLED_APPS: from ecwsp.grades.models import Grade final = Grade.objects.filter(course=self, override_final=True, student=student) if final: if not date_report or final[0].course.marking_period.filter(end_date__lte=date_report).count(): return final[0].get_grade() final = Decimal(0) number = 0 letter_grade = False grades = Grade.objects.filter(student=student, course=self, marking_period__course=self) if date_report: grades = grades.filter(marking_period__end_date__lte=date_report) total_weight = Decimal(0) for grade in grades: try: final += Decimal(grade.get_grade()) * grade.marking_period.weight number += 1 total_weight += grade.marking_period.weight # otherwise it's a letter grade. except: # 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 * grade.marking_period.weight number += 1 letter_grade = True total_weight += grade.marking_period.weight elif grade.get_grade() in ['F', 'M']: number += 1 letter_grade = True total_weight += grade.marking_period.weight if final is not None and total_weight: final /= total_weight if number != 0: 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 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 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 'ecwsp.benchmark_grade' in settings.INSTALLED_APPS: options += ['O'] if 'ecwsp.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_import = 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('ecwsp.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 send_email_approval(self): """ Send email to supervisor for approval """ if not self.site_supervisor or not self.site_supervisor.email: return None try: sendTo = self.site_supervisor.email subject = "Volunteer hours approval for " + unicode(self.student) msg = "Hello " + unicode(self.site_supervisor.name) + ",\nPlease click on the link below to approve the time sheet\n" + \ settings.BASE_URL + "/volunteer_tracker/approve?key=" + str(self.secret_key) from_addr = Configuration.get_or_default( "From Email Address", "*****@*****.**").value send_mail(subject, msg, from_addr, [sendTo]) except: logging.warning( "Unable to send email to volunteer's supervisor! %s" % (self, ), exc_info=True)
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 email 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 calculate_final_grade(self, student, date_report=None): """ Calculates final grade. Does not take into account overrides. Note that this should match recalc_ytd_grade in gradesheet.js! """ if 'ecwsp.grades' in settings.INSTALLED_APPS: from ecwsp.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 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 build_schedule(self, student, marking_period, include_asp=False): """ 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() days = [] arr_days = [] for day in CourseMeet.day_choice: 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 for period in periods: period.days = [] for day in arr_days: if only_active in ['T', 'True', '1', 't', 'true']: 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]) else: period.days.append(None) CourseMeet.objects.filter( course__courseenrollment__user=student, course__marking_period=marking_period, ).distinct() return days, periods
class SchoolYear(models.Model): name = models.CharField(max_length=255, unique=True) start_date = models.DateField(validators=settings.DATE_VALIDATORS) end_date = models.DateField(validators=settings.DATE_VALIDATORS) grad_date = models.DateField(blank=True, null=True, validators=settings.DATE_VALIDATORS) active_year = models.BooleanField( help_text="DANGER!! This is the current school year. There can only be one and setting this will remove it from other years. " \ "If you want to change the active year you almost certainly want to click Admin, Change School Year.") benchmark_grade = models.BooleanField( default=lambda: str( Configuration.get_or_default("Benchmark-based grading", "False"). value).lower() == "true", help_text= "Causes additional information to appear on transcripts. The configuration option \"Benchmark-based grading\" sets the default for this field." ) class Meta: ordering = ('-start_date', ) def __unicode__(self): return self.name def get_number_days(self, date=date.today()): """ Returns number of active school days in this year, based on each marking period of the year. date: Defaults to today, date to count towards. Used to get days up to a certain date""" mps = self.markingperiod_set.filter( show_reports=True).order_by('start_date') day = 0 for mp in mps: day += mp.get_number_days(date) return day def save(self, *args, **kwargs): super(SchoolYear, self).save(*args, **kwargs) if self.active_year: all = SchoolYear.objects.exclude(id=self.id).update( active_year=False)
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 email student', exc_info=True, extra={ 'exception': sys.exc_info()[0], 'exception2': sys.exc_info()[1], })
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 handle(): """ Emails subscribed volunteer managers daily site submissions """ volunteers = Volunteer.objects.filter(email_queue__isnull=False).exclude(email_queue="") if volunteers: from_email = Configuration.objects.get_or_create(name="From Email Address")[0].value to_emails = Configuration.get_or_default("Volunteer Track Manager Emails", default="").value msg = "Student(s): \n" subject = "SWORD daily volunteer changes" for volunteer in volunteers: msg += "%s - %s\n\n" % (volunteer, volunteer.email_queue) to_emails = to_emails.split(',') sane_to_emails = [] for email in to_emails: if email and email != " ": sane_to_emails.append(email.strip()) send_mail(subject, msg, from_email, sane_to_emails) for volunteer in volunteers: volunteer.email_queue = "" volunteer.save()
def save(self, saved_by_volunteer=False, *args, **kwargs): if not self.secret_key or self.secret_key == "": self.genKey() if saved_by_volunteer: if not self.volunteer.email_queue: self.volunteer.email_queue = "" self.volunteer.email_queue += "Added Site %s. " % (unicode( self.site)) self.volunteer.save() if self.id: old_volunteer = VolunteerSite.objects.get(id=self.id) if old_volunteer.site_approval == "Submitted" and self.site_approval == "Accepted": try: from django.core.mail import send_mail from_email = Configuration.get_or_default( "From Email Address", default="*****@*****.**").value msg = "Hello %s,\nYour site %s has been approved!" % ( self.volunteer, self.site) subject = "Site approval" send_to = self.volunteer.student.get_email send_mail(subject, msg, from_email, [send_to]) except: exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split( exc_tb.tb_frame.f_code.co_filename)[1] logging.warning( 'Unable to send email to volunteer about site approval! %s' % (self, ), exc_info=True, extra={ 'request': request, 'exception': exc_type, 'traceback': '%s %s' % (fname, exc_tb.tb_lineno) }) super(VolunteerSite, 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 get_context_data(self, **kwargs): context = super(CourseSectionGrades, self).get_context_data(**kwargs) form_class = self.get_form_class() form = self.get_form(form_class) form.fields['marking_period'].queryset = form.fields[ 'marking_period'].queryset.filter( coursesection=context['coursesection']) context['form'] = form if self.request.user.is_superuser or \ self.request.user.has_perm('grades.change_own_final_grade') or \ self.request.user.has_perm('grades.change_grade'): context['edit_final'] = True else: context['edit_final'] = False if self.request.user.is_superuser or \ self.request.user.has_perm('grades.change_own_grade') or \ self.request.user.has_perm('grades.change_grade'): context['edit'] = True else: context['edit'] = False context[ 'letter_grade_required_for_pass'] = Configuration.get_or_default( 'letter_grade_required_for_pass', '60').value return context
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 = 3 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__lte=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 get_hours_default(): return Configuration.get_or_default('Volunteer Track Required Hours', default=20).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) + \ "\n" + 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").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', 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 = u"Hello {0},\n".format(student.first_name) 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 get_default_three(): return int( Configuration.get_or_default('Discipline Merit Level Three', default=3).value)
def get_default_two(): return int( Configuration.get_or_default('Discipline Merit Level Two', default=1).value)
def get_default_one(): return int( Configuration.get_or_default('Discipline Merit Level One', default=0).value)
def get_default_four(): return int( Configuration.get_or_default('Discipline Merit Level Four', default=5).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 ecwsp.sis.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_city(): return Configuration.get_or_default("Default City", "").value
def get_credits_default(): return Configuration.get_or_default(name='Default course credits').value
def calculate_grade_real(self, date_report=None, ignore_letter=False): """ Calculate the final grade for a course section 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 case when Sum(override_final{postgres_type_cast}) {over} = 1 then -9001 else (Sum(grade * weight) {over} / Sum(weight) {over}) end AS ave_grade FROM grades_grade LEFT JOIN schedule_markingperiod ON schedule_markingperiod.id = grades_grade.marking_period_id WHERE (grades_grade.course_section_id = %s AND grades_grade.student_id = %s {extra_where} ) AND ( grade IS NOT NULL OR letter_grade IS NOT NULL )''' if date_report: if settings.DATABASES['default']['ENGINE'] in [ 'django.db.backends.postgresql_psycopg2', 'tenant_schemas.postgresql_backend' ]: cursor.execute( sql_string.format( postgres_type_cast='::int', over='over ()', extra_where= 'AND (schedule_markingperiod.end_date <= %s OR override_final = true)' ), (self.course_section_id, self.user_id, date_report)) else: cursor.execute( sql_string.format( postgres_type_cast='', over='', extra_where= 'AND (schedule_markingperiod.end_date <= %s OR grades_grade.override_final = true)' ), (self.course_section_id, self.user_id, date_report)) else: if settings.DATABASES['default']['ENGINE'] in [ 'django.db.backends.postgresql_psycopg2', 'tenant_schemas.postgresql_backend' ]: cursor.execute( sql_string.format(postgres_type_cast='::int', over='over ()', extra_where=''), (self.course_section_id, self.user_id)) else: cursor.execute( sql_string.format(postgres_type_cast='', over='', extra_where=''), (self.course_section_id, self.user_id)) result = cursor.fetchone() if result: ave_grade = result[0] else: # No grades at all. The average of no grades is None return None # -9001 = override. We can't mix text and int in picky postgress. if str(ave_grade) == "-9001": course_section_grade = Grade.objects.get( override_final=True, student=self.user, course_section=self.course_section) grade = course_section_grade.get_grade() if ignore_letter and not isinstance(grade, (int, Decimal, float)): return None return grade elif ave_grade: return Decimal(ave_grade) # about 0.5 s # Letter Grade if ignore_letter == False: final = 0.0 grades = self.course_section.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: try: final += get_grade except TypeError: return 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 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_readonly_fields(self, request, obj=None): edit_all = Configuration.get_or_default("Edit all Student Worker Fields", "False") if edit_all.value == "True": return ['parent_guardian', 'street', 'city', 'state', 'zip', 'parent_email', 'alt_email'] return super(StudentAdmin, self).get_readonly_fields(request, obj=obj)
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 'ecwsp.work_study' in settings.INSTALLED_APPS: if settings.SYNC_SUGAR: from ecwsp.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