func (ed *HTTPd) survey(w http.ResponseWriter, r *http.Request) { //Cache ? kind := r.URL.Query().Get("kind") s := schema.Survey{} if _, err := toml.DecodeFile("assets/surveys/"+kind+".toml", &s); err != nil { logger.Log("event", "survey", "Unable to read the questions for '"+kind+"'", err) http.Error(w, "", http.StatusInternalServerError) return } tpl, err := template.New("survey.html").Funcs( template.FuncMap{ "html": func(value interface{}) template.HTML { return template.HTML(fmt.Sprint(value)) }, }).ParseFiles("assets/surveys/survey.html") if err != nil { logger.Log("event", "survey", "Unable to read the template for '"+kind+"'", err) http.Error(w, "", http.StatusInternalServerError) return } w.Header().Set("Content-type", "text/html; charset=utf-8") if err := tpl.Execute(w, s); err != nil { logger.Log("event", "survey", "Unable to run the template for '"+kind+"'", err) http.Error(w, "", http.StatusInternalServerError) return } }
//TutorNewsLetter send to a tutor a mail about the missing reports or reviews func (n *Notifier) TutorNewsLetter(tut schema.User, lates []schema.StudentReports) { now := time.Now() var statuses []studentStatus reports := 0 reviews := 0 for _, stu := range lates { s := studentStatus{Student: stu.Student.User, Status: make([]string, 0)} for _, r := range stu.Reports { //missing deadlines if r.Delivery == nil { s.Status = append(s.Status, r.Kind+" deadline passed; was "+r.Deadline.Format(config.DateLayout)) reports++ } //missing reviews if r.Deadline.Before(now) && r.Reviewed == nil { deadline := r.Deadline.Add(n.reviewDuration[r.Kind]) s.Status = append(s.Status, r.Kind+" waiting for review (deadline: "+deadline.Format(config.DateLayout)+")") reviews++ } } statuses = append(statuses, s) } //Safety belt if reviews == 0 && reports == 0 { return } buf := fmt.Sprintf("send the weekly report to '%s' with %d warning(s): %d late reports, %d pending reviews", tut.Fullname(), len(statuses), reports, reviews) err := n.mailer.Send(tut.Person, "tutor_newsletter.txt", statuses) logger.Log("event", "cron", buf, err) }
//PasswordChanged logs the event and notify the target func (n *Notifier) PasswordChanged(em string, err error) error { logger.Log("event", em, "password changed", err) if err != nil { return err } return n.mailer.Send(schema.Person{Email: em}, "password-changed.txt", nil) }
func status(not *notifier.Notifier, w http.ResponseWriter, r *http.Request, e error) { switch e { case os.ErrNotExist, schema.ErrUnknownConvention, schema.ErrUnknownStudent, schema.ErrUnknownSurvey, schema.ErrUnknownUser, schema.ErrUnknownReport, schema.ErrUnknownInternship, schema.ErrNoPendingRequests, schema.ErrUnknownDefense: http.Error(w, e.Error(), http.StatusNotFound) return case schema.ErrDefenseConflict, schema.ErrReportExists, schema.ErrUserExists, schema.ErrInternshipExists, schema.ErrUserTutoring, schema.ErrConventionExists, schema.ErrDefenseJuryConflict, schema.ErrDefenseExists: http.Error(w, e.Error(), http.StatusConflict) return case schema.ErrCredentials, schema.ErrInvalidToken, schema.ErrSessionExpired, ErrNotActivatedAccount: http.Error(w, e.Error(), http.StatusUnauthorized) return case feeder.ErrAuthorization: http.Error(w, "Unable to fetch the conventions from the server: "+e.Error(), http.StatusUnauthorized) return case ErrMalformedJSON, schema.ErrInvalidSurvey, schema.ErrInvalidAlumniEmail, schema.ErrInvalidEmail, schema.ErrDeadlinePassed, schema.ErrInvalidGrade, schema.ErrInvalidMajor, schema.ErrInvalidPromotion, schema.ErrInvalidPeriod, schema.ErrGradedReport, schema.ErrPasswordTooShort: http.Error(w, e.Error(), http.StatusBadRequest) return case session.ErrPermission: http.Error(w, e.Error(), http.StatusForbidden) return case feeder.ErrTimeout: http.Error(w, e.Error(), http.StatusRequestTimeout) return case nil: return default: http.Error(w, "Internal server error. A possible bug to report", http.StatusInternalServerError) logger.Log("event", "httpd", "unsupported error ", e) } }
//Send just print the mailing on stdout func (fake *Fake) Send(to schema.Person, tpl string, data interface{}, cc ...schema.Person) error { path := fmt.Sprintf("%s%c%s", fake.Config.Path, os.PathSeparator, tpl) dta := metaData{ WWW: fake.WWW, To: to, Fullname: fake.Config.Fullname, Data: data, } body, err := fill(path, dta) if err != nil { logger.Log("mailer", tpl, "filling template", err) return err } buf := fmt.Sprintf("-----\nFrom: %s\nTo: %s\nCC: %s\n%s\n-----\n", fake.Config.Sender, to.Email, emails(cc...), body) logger.Log("mailer", tpl, buf, nil) return nil }
func fatal(msg string, err error) { logger.Log("event", "daemon", msg, err) st := "" if err != nil { st = ": " + err.Error() log.Fatalln(msg + st) } else { log.Println(msg + st) } }
func (ex *Exchange) outFile(mime, filename string, cnt []byte, e error) error { if e != nil { return e } ex.w.Header().Set("Content-type", mime) ex.w.Header().Set("Content-disposition", "attachment; filename="+filename) _, err := ex.w.Write(cnt) if err != nil { logger.Log("event", ex.s.Me().Person.Email, "Unable to send '"+filename+"'", err) http.Error(ex.w, "", http.StatusInternalServerError) } return err }
//NeverLogged scan students that never logged in since //one week before the beginning of the internship func NeverLogged(provider schema.Internshipser, not *notifier.Notifier) { ints, err := provider.Internships() logger.Log("event", "cron", "Scanning the internships for student that never connected", err) if err != nil { return } for _, i := range ints { last := i.Convention.Student.User.LastVisit if last == nil && i.Convention.Begin.Before(time.Now()) { //The internship began not.ReportIdleAccount(i.Convention.Student.User) } } }
//AccountReseted logs an account reset and send the mail to the targeted user func (n *Notifier) AccountReseted(em string, token []byte, err error) error { //mail with token //log logger.Log("event", "daemon", "start password reset for "+em, err) if err != nil { return err } data := struct { Email string Token string }{Email: em, Token: string(token)} return n.mailer.Send(schema.Person{Email: em}, "reset.txt", data) }
//Mon monitores the requests func Mon(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { myRw := NewMonResponseWriter(w) start := time.Now() defer func() { ms := int(time.Since(start).Nanoseconds() / 1000000) msg := fmt.Sprintf("\"%s\" %d %d", r.URL.String(), myRw.Status(), ms) logger.Log("access", r.Method, msg, nil) codeFamily := myRw.Status() / 100 logApi(r.Method, codeFamily, ms) }() h(myRw, r) } }
//SurveyRequest sends the survey request to the supervisor func (n *Notifier) SurveyRequest(sup schema.Person, tutor schema.User, student schema.Student, survey schema.SurveyHeader, err error) error { frMonths := []string{"", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Decembre"} dta := struct { Student schema.User Survey schema.SurveyHeader FrDate string EnDate string }{Student: student.User, Survey: survey, FrDate: fmt.Sprintf("%d %s %d", survey.Deadline.Day(), frMonths[survey.Deadline.Month()], survey.Deadline.Year()), EnDate: survey.Deadline.Format("Mon, 02 Jan 2006"), } if err == nil { err = n.mailer.Send(sup, "survey_request.txt", dta) } logger.Log("event", "cron", "send invitation for survey '"+student.User.Person.Email+"/"+survey.Kind+"' to '"+sup.Email+"'", err) return err }
func (ed *HTTPd) home(w http.ResponseWriter, r *http.Request) { c, err := r.Cookie("token") if err != nil { http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) return } s, err := ed.store.Session([]byte(c.Value)) if err != nil || s.Expire.Before(time.Now()) { msg := "session expired" if err != nil { msg = "invalid session token" } logger.Log("event", s.Email, msg, err) wipeCookies(w) http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) return } http.Redirect(w, r, "/home", http.StatusTemporaryRedirect) }
//Send the mail to the smtp server func (m *SMTP) Send(to schema.Person, tpl string, data interface{}, cc ...schema.Person) error { path := fmt.Sprintf("%s%c%s", m.path, os.PathSeparator, tpl) dta := metaData{ To: to, WWW: m.www, Fullname: m.fullname, Data: data, } body, err := fill(path, dta) if err != nil { return err } if err == nil { err = m.sendMail(to.Email, emails(cc...), body) } buf := fmt.Sprintf("sending '%s' to %s (cc %s)", tpl, to.Email, emails(cc...)) logger.Log("event", "mailer", buf, err) return err }
//MissingSurveys scans the missing surveys //One week before the deadine, it send a first mail, then a reminder every week until the survey is uploaded func MissingSurveys(provider schema.Internshipser, not *notifier.Notifier) { ints, err := provider.Internships() logger.Log("event", "cron", "Scanning the internships for surveys to request", err) if err != nil { return } now := time.Now() for _, i := range ints { if i.Convention.Skip { continue } for _, s := range i.Surveys { if s.Delivery == nil && s.Invitation.Before(now) { //Its time to notify the supervisor not.SurveyRequest(i.Convention.Supervisor, i.Convention.Tutor, i.Convention.Student, s, nil) } } } }
//Import imports all the conventions by requesting in parallel the conventions for each registered promotions func (f *CsvConventions) Import() ([]schema.Convention, *ImportError) { lock := &sync.Mutex{} var all []schema.Convention var wg sync.WaitGroup ierr := NewImportError() for i, prom := range f.promotions { wg.Add(1) go func(i int, p string) { convs, err := f.scan(p) if err != nil { ierr.NewWarning(err.Warnings...) } lock.Lock() defer lock.Unlock() all = append(all, convs...) wg.Done() }(i, prom) } wg.Wait() logger.Log("event", "feeder", "Scanning conventions", ierr) return all, ierr }
func (ed *EndPoints) openSession(w http.ResponseWriter, r *http.Request) (session.Session, error) { token, err := r.Cookie("token") if err != nil { token = &http.Cookie{} } s, err := ed.store.Session([]byte(token.Value)) if err != nil { wipeCookies(w) return session.Session{}, err } if s.Expire.Before(time.Now()) { logger.Log("event", s.Email, "session expired at "+s.Expire.Format(config.DateTimeLayout), nil) wipeCookies(w) return session.Session{}, schema.ErrSessionExpired } user, err := ed.store.User(s.Email) if err != nil { wipeCookies(w) return session.Session{}, err } ed.store.Visit(user.Person.Email) return session.NewSession(user, ed.store, ed.conventions), err }
//MissingReports scan the internships for reports or reviews that are missing func MissingReports(provider schema.Internshipser, not notifier.NewsLetter) { ints, err := provider.Internships() logger.Log("event", "cron", "Scanning the internships for the tutor newsletters", err) if err != nil { return } byTutor := make(map[string][]schema.StudentReports) tutors := make(map[string]schema.User) for _, i := range ints { if i.Convention.Skip { continue } student := i.Convention.Student em := i.Convention.Tutor.Person.Email reports, ok := byTutor[em] if !ok { reports = make([]schema.StudentReports, 0) tutors[em] = i.Convention.Tutor } lates := lateReports(i.Reports) if len(lates) > 0 { x := schema.StudentReports{ Student: student, Reports: lates, } reports = append(reports, x) } byTutor[em] = reports } for em, lates := range byTutor { if len(lates) > 0 { not.TutorNewsLetter(tutors[em], lates) } } }
func redirectToSecure(w http.ResponseWriter, req *http.Request) { logger.Log("event", "insecure", "redirection to "+cfg.HTTPd.WWW+req.RequestURI, nil) http.Redirect(w, req, cfg.HTTPd.WWW+req.RequestURI, http.StatusMovedPermanently) }
func userLog(u schema.User, msg string, err error) { logger.Log("event", u.Person.Email, msg, err) }
//ReportIdleAccount send a mail to the user to remind him to connect func (n *Notifier) ReportIdleAccount(u schema.User) { err := n.mailer.Send(u.Person, "idle_account.txt", u) logger.Log("event", "cron", "send an idle account reminder for "+u.Fullname(), err) }
//Login logs the login func (n *Notifier) Login(s schema.Session, err error) { logger.Log("event", s.Email, "login", err) }