diff options
Diffstat (limited to 'api/devices')
| -rw-r--r-- | api/devices/devices.go | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/api/devices/devices.go b/api/devices/devices.go new file mode 100644 index 0000000..227afcb --- /dev/null +++ b/api/devices/devices.go @@ -0,0 +1,92 @@ +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 // <compact-mac>.<username>.<zone> 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) + } +} |
