package devices import ( "log" "net/http" "penguins.lan/api/types" "penguins.lan/database" "penguins.lan/utils" ) // DeviceView is one device row for the profile page. type DeviceView struct { Mac string // canonical colon form, used as the set-primary value Name string // .. FQDN IP string Online bool LastSeen string Primary bool } // ListDevicesContinuation loads the user's devices (with liveness + which is // primary) and the zone facts the profile page and wizard need. func ListDevicesContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { if context.User == nil { return failure(context, req, resp) } macs, err := database.ListUserMacs(context.DBConn, context.User.ID) if err != nil { log.Println("devices: list failed:", err) resp.WriteHeader(http.StatusInternalServerError) return failure(context, req, resp) } primary, err := database.GetUserPrimaryMAC(context.DBConn, context.User.ID) if err != nil { log.Println("devices: primary lookup failed:", err) resp.WriteHeader(http.StatusInternalServerError) return failure(context, req, resp) } zone := context.Args.DnsZone userDomain := context.User.Username + "." + zone views := make([]DeviceView, 0, len(macs)) for _, d := range macs { name := d.Mac if mac, err := utils.ParseMac(d.Mac); err == nil { name = mac.Compact() + "." + userDomain } views = append(views, DeviceView{ Mac: d.Mac, Name: name, IP: d.IP, Online: d.Online, LastSeen: utils.FormatSince(d.LastSeen), Primary: d.Mac == primary, }) } (*context.TemplateData)["Devices"] = views (*context.TemplateData)["PrimaryMAC"] = primary (*context.TemplateData)["DnsZone"] = zone (*context.TemplateData)["UserDomain"] = userDomain return success(context, req, resp) } } // SetPrimaryContinuation marks one of the caller's devices as primary. func SetPrimaryContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { mac := req.FormValue("mac") owned, err := database.MACBelongsToUser(context.DBConn, mac, context.User.ID) if err != nil { log.Println("devices: ownership check failed:", err) resp.WriteHeader(http.StatusInternalServerError) return failure(context, req, resp) } if !owned { resp.WriteHeader(http.StatusUnauthorized) return failure(context, req, resp) } if err := database.SetUserPrimaryMAC(context.DBConn, context.User.ID, mac); err != nil { log.Println("devices: set primary failed:", err) resp.WriteHeader(http.StatusInternalServerError) return failure(context, req, resp) } http.Redirect(resp, req, "/profile", http.StatusSeeOther) return success(context, req, resp) } }