Beispiel #1
0
func (s *Server) HandleDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := NewContext(r, w)

	user := ctx.User()
	if user == nil {
		s.redirectToSignIn(w, r)
		return
	}

	logs, err := s.db.RecentUserLogs(user, dashboardRecentLogsCount)
	if err != nil {
		panic(err)
	}

	data := new(dashboardData)
	for _, log := range logs {
		data.Logs = append(data.Logs, dashboardLog{
			ID:       log.ID,
			Name:     log.Name,
			Date:     log.Start.Format(logTimeFormat),
			Duration: utils.Duration(log.Duration).String(),
			Distance: utils.Distance(log.Distance).String(),
			Tags:     log.Tags,
		})
	}

	ctx.SetTitle("Dashboard")
	ctx.Breadcrumb().Add("Dashboard", "", true)
	ctx.SetActiveTab("dashboard")
	ctx.SetData(data)

	s.render(w, r, "dashboard")
}
Beispiel #2
0
func (s *Server) HandleGetLogs(w http.ResponseWriter, r *http.Request) {
	ctx := NewContext(r, w)

	user := ctx.User()
	if user == nil {
		s.redirectToSignIn(w, r)
		return
	}

	years, err := s.db.UserLogYears(user)
	if err != nil {
		panic(err)
	}

	year := 0
	explicitYear := false
	if s := r.FormValue("year"); s != "" {
		if y, err := strconv.Atoi(s); err == nil {
			year = y
			explicitYear = true
		}
	}
	if year == 0 && len(years) > 0 {
		year = years[len(years)-1]
	}

	logs, err := s.db.UserLogsByYear(user, year)
	if err != nil {
		panic(err)
	}

	var (
		data     logsData
		group    *logDataGroup
		duration uint
		distance uint
		month    time.Month
	)

	for _, log := range logs {
		if month != log.Start.Month() {
			if group != nil {
				group.Duration = utils.Duration(duration).String()
				group.Distance = utils.Distance(distance).String()
			}

			duration = 0
			distance = 0
			month = log.Start.Month()

			group = &logDataGroup{
				Title: fmt.Sprintf("%s %d", month, year),
			}
			data.Groups = append(data.Groups, group)
		}

		group.Logs = append(group.Logs, logsDataLog{
			ID:       log.ID,
			Name:     log.Name,
			Start:    log.Start.Format(logTimeFormat),
			Duration: utils.Duration(log.Duration).String(),
			Distance: utils.Distance(log.Distance).String(),
			Tags:     log.Tags,
		})
		distance += log.Distance
		duration += log.Duration
	}
	if group != nil {
		group.Duration = utils.Duration(duration).String()
		group.Distance = utils.Distance(distance).String()
	}

	for _, y := range years {
		data.Years = append(data.Years, logsDataYear{
			Year:   y,
			Active: y == year,
		})
	}

	if explicitYear {
		ctx.SetTitle(fmt.Sprintf("Logs %d", year))
		ctx.Breadcrumb().Add("Logs", "/logs", false)
		ctx.Breadcrumb().Add(strconv.Itoa(year), "", true)
	} else {
		ctx.SetTitle("Logs")
		ctx.Breadcrumb().Add("Logs", "", true)
	}

	ctx.SetActiveTab("logs")
	ctx.SetData(data)

	s.render(w, r, "logs")
}
Beispiel #3
0
func (s *Server) HandleGetLog(w http.ResponseWriter, r *http.Request) {
	ctx := NewContext(r, w)

	user := ctx.User()
	if user == nil {
		s.redirectToSignIn(w, r)
		return
	}

	id, err := strconv.Atoi(ctx.Params().ByName("id"))
	if err != nil {
		http.NotFound(w, r)
		return
	}

	log, err := s.db.UserLogByID(user, id)
	if err != nil {
		panic(err)
	}
	if log == nil {
		http.NotFound(w, r)
		return
	}

	data := logData{
		Log: logDataLog{
			ID:       log.ID,
			Name:     log.Name,
			Start:    log.Start.Format(logTimeFormat),
			End:      log.End.Format(logTimeFormat),
			Duration: utils.Duration(log.Duration).String(),
			Distance: utils.Distance(log.Distance).String(),
			Speed:    utils.Speed(log.Speed()).String(),
			Pace:     utils.Speed(log.Speed()).Pace().String(),
			Tracks:   make([][]logDataPoint, 0, len(log.Tracks)),
			Tags:     log.Tags,
		},
	}
	if data.Log.Tags == nil {
		data.Log.Tags = make([]string, 0, 0)
	}

	var cumDistance, ascent, descent float64
	performReduce := r.FormValue("reduce") != "no"

	for _, track := range log.Tracks {
		points := track.Points

		if performReduce {
			rdpPoints := make([]rdp.Point, 0, len(track.Points))
			for _, point := range track.Points {
				λ, φ := geo.ToRad(point.Longitude), geo.ToRad(point.Latitude)
				x, y := geo.EquirectangularProjection(λ, φ, 0)
				rdpPoints = append(rdpPoints, rdp.Point{
					X:    x,
					Y:    y,
					Data: point,
				})
			}
			const epsilon = 0.0000001 // ≈ 1m
			reducedPoints := rdp.Reduce(rdpPoints, epsilon)
			points = make([]*models.Point, 0, len(reducedPoints))
			for _, rp := range reducedPoints {
				points = append(points, rp.Data.(*models.Point))
			}
		}

		var ps []logDataPoint
		for i, point := range points {
			p := logDataPoint{
				Lat: point.Latitude,
				Lon: point.Longitude,
				Ele: point.Elevation,
				HR:  point.Heartrate,
			}
			if i > 0 {
				lastPoint := points[i-1]
				cumDistance += point.DistanceTo(lastPoint)
				p.CumulatedDistance = cumDistance
				p.Speed = point.SpeedTo(lastPoint)

				dEle := point.Elevation - lastPoint.Elevation
				if dEle >= 0 {
					ascent += dEle
				} else {
					descent += -dEle
				}
			} else if len(points) > 1 {
				nextPoint := points[i+1]
				p.CumulatedDistance = cumDistance
				p.Speed = nextPoint.SpeedTo(point)
			}
			ps = append(ps, p)
		}
		data.Log.Tracks = append(data.Log.Tracks, ps)
	}

	if ascent != 0 || descent != 0 {
		data.Log.Ascent = fmt.Sprintf("%d m", int(ascent))
		data.Log.Descent = fmt.Sprintf("%d m", int(descent))
	}

	hrSummary := heartrate.SummaryForLog(log)
	if len(hrSummary.Rates) > 0 {
		data.Log.HR = strconv.Itoa(hrSummary.Average)

		perc := func(zone heartrate.Zone) float64 {
			return float64(hrSummary.Zones[zone]) / float64(len(hrSummary.Rates)) * 100.0
		}

		data.Log.HRZones.Red = perc(heartrate.ZoneRed)
		data.Log.HRZones.Anaerobic = perc(heartrate.ZoneAnaerobic)
		data.Log.HRZones.Aerobic = perc(heartrate.ZoneAerobic)
		data.Log.HRZones.FatBurning = perc(heartrate.ZoneFatBurning)
		data.Log.HRZones.Easy = perc(heartrate.ZoneEasy)
		data.Log.HRZones.None = perc(heartrate.ZoneNone)
	}

	ctx.SetTitle(log.Name)
	ctx.Breadcrumb().Add("Logs", "/logs", false)
	ctx.Breadcrumb().Add(log.Name, "", true)
	ctx.SetActiveTab("logs")
	ctx.SetData(data)

	s.render(w, r, "log")
}