hswaw/site: add checkinator integration
Change-Id: I19a72da67410332d6d82d49e3a54f1dc0f81ff65
diff --git a/hswaw/site/BUILD.bazel b/hswaw/site/BUILD.bazel
index 21edded..a34f5b4 100644
--- a/hswaw/site/BUILD.bazel
+++ b/hswaw/site/BUILD.bazel
@@ -4,6 +4,7 @@
go_library(
name = "go_default_library",
srcs = [
+ "at.go",
"feeds.go",
"main.go",
"views.go",
diff --git a/hswaw/site/at.go b/hswaw/site/at.go
new file mode 100644
index 0000000..70df8c7
--- /dev/null
+++ b/hswaw/site/at.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+)
+
+const (
+ atURL = "https://at.hackerspace.pl/api"
+)
+
+// atStatus is the result of queruing checkinator/at (Hackerspace presence
+// service).
+type atStatus struct {
+ // Users is the list of present and publicly visible users.
+ Users []atUser `json:"users"`
+ // ESPs is the number of ESP{8266,32} devices.
+ ESPs int `json:"esps"`
+ // Kektops is the number of nettop “Kektop” devices.
+ Kektops int `json:"kektops"`
+ // Unknown is the number of unknown devices in the network.
+ Unknown int `json:"unknown"`
+}
+
+type atUser struct {
+ Login string `json:"login"`
+}
+
+func getAt(ctx context.Context) (*atStatus, error) {
+ r, err := http.NewRequestWithContext(ctx, "GET", atURL, nil)
+ if err != nil {
+ return nil, fmt.Errorf("NewRequest(%q): %w", atURL, err)
+ }
+ res, err := http.DefaultClient.Do(r)
+ if err != nil {
+ return nil, fmt.Errorf("GET: %w", err)
+ }
+ defer res.Body.Close()
+
+ var status atStatus
+ if err := json.NewDecoder(res.Body).Decode(&status); err != nil {
+ return nil, fmt.Errorf("when decoding JSON: %w", err)
+ }
+
+ return &status, nil
+}
diff --git a/hswaw/site/static/landing.css b/hswaw/site/static/landing.css
index 431d8ea..3ddae1a 100644
--- a/hswaw/site/static/landing.css
+++ b/hswaw/site/static/landing.css
@@ -141,9 +141,19 @@
opacity: 60%;
}
-#quicklinks {
- float: right;
- font-family: monospace;
- font-size: 14px;
- margin: 2rem;
+.atlist {
+ display: inline;
+ list-style: none;
+}
+
+.atlist li {
+ display: inline;
+}
+
+.atlist li:after {
+ content: ", ";
+}
+
+.atlist li:last-child:after {
+ content: ".";
}
diff --git a/hswaw/site/templates/index.html b/hswaw/site/templates/index.html
index 48f0acd..058c162 100644
--- a/hswaw/site/templates/index.html
+++ b/hswaw/site/templates/index.html
@@ -36,6 +36,28 @@
<p>
<b>Hackerspace nie zna barier.</b> Jeśli masz ciekawy pomysł i szukasz ludzi chętnych do współpracy lub po prostu potrzebujesz miejsca i sprzętu - <a href="">zapraszamy</a>!
</p>
+ <h3>Kto jest teraz w spejsie?</h3>
+ <p>
+ {{ if ne .AtError nil }}
+ <i>Ups, nie udało się załadować stanu checkinatora.</i>
+ {{ else }}
+ {{ $count := len .AtStatus.Users }}
+ {{ if gt $count 4 }}
+ Według <a href="https://at.hackerspace.pl">naszych instrumentów</a> w spejsie obecnie znajduje się {{ $count }} osób:
+ {{ else if gt $count 1 }}
+ Według <a href="https://at.hackerspace.pl">naszych instrumentów</a> w spejsie obecnie znajdują się {{ $count }} osoby:
+ {{ else if gt $count 0 }}
+ Według <a href="https://at.hackerspace.pl">naszych instrumentów</a> w spejsie obecnie znajduje się jedna osoba:
+ {{ else }}
+ Według <a href="https://at.hackerspace.pl">naszych instrumentów</a> w spejsie obecnie nie ma nikogo.
+ {{ end }}
+ <ul class="atlist">
+ {{ range .AtStatus.Users }}
+ <li>{{ .Login }}</li>
+ {{ end }}
+ </ul>
+ {{ end }}
+ </p>
</div>
<div class="blog">
<h2>Blog</h2>
diff --git a/hswaw/site/views.go b/hswaw/site/views.go
index 59f948e..ef1f1fa 100644
--- a/hswaw/site/views.go
+++ b/hswaw/site/views.go
@@ -53,7 +53,13 @@
// handleIndex handles rendering the main page at /.
func (s *service) handleIndex(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ atStatus, atError := getAt(ctx)
+
render(w, tmplIndex, map[string]interface{}{
- "Entries": s.getFeeds(),
+ "Entries": s.getFeeds(),
+ "AtStatus": atStatus,
+ "AtError": atError,
})
}