From 964e74a9f4511b2dbf24c920ed704a84b017dc3b Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Wed, 16 Nov 2022 16:44:24 +0100 Subject: [PATCH] dis: Display initial statistics --- cmd/info.go | 12 +++ .../component/control/info/html/instance.html | 97 ++++++++++++++++++- .../control/static/templates/_base.html | 1 + internal/phpx/serialize.go | 49 ++++++++++ .../barrel/barrel/scripts/user_shell.sh | 15 +-- .../barrel/{ => wisskiutils}/ssh/keys.sh | 0 .../barrel/{ => wisskiutils}/ssh/sshd_config | 0 .../barrel/{ => wisskiutils}/ssh/start.sh | 0 internal/wisski/ingredient/fetcher.go | 39 ++++++++ .../wisski/ingredient/php/extras/stats.go | 37 +++++++ .../wisski/ingredient/php/extras/stats.php | 8 ++ internal/wisski/wisski.go | 1 + 12 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 internal/phpx/serialize.go rename internal/wisski/ingredient/barrel/barrel/{ => wisskiutils}/ssh/keys.sh (100%) rename internal/wisski/ingredient/barrel/barrel/{ => wisskiutils}/ssh/sshd_config (100%) rename internal/wisski/ingredient/barrel/barrel/{ => wisskiutils}/ssh/start.sh (100%) create mode 100644 internal/wisski/ingredient/php/extras/stats.go create mode 100644 internal/wisski/ingredient/php/extras/stats.php diff --git a/cmd/info.go b/cmd/info.go index 139a0eb..8e7f9b8 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -63,6 +63,18 @@ func (i info) Run(context wisski_distillery.Context) error { context.Printf("Last Update: %v\n", info.LastUpdate.String()) context.Printf("Last Cron: %v\n", info.LastCron.String()) + context.Printf("Bundles: (count %d)\n", info.Statistics.Bundles.TotalBundles) + for _, bundle := range info.Statistics.Bundles.Bundles { + if bundle.Count == 0 { + continue + } + context.Printf("- %s %d %v\n", bundle.Label, bundle.Count, bundle.MainBundle) + } + context.Printf("Graphs: (count %d)\n", len(info.Statistics.Triplestore.Graphs)) + for _, graph := range info.Statistics.Triplestore.Graphs { + context.Printf("- %s %d\n", graph.URI, graph.Count) + } + context.Printf("SSH Keys: (count %d)\n", len(info.SSHKeys)) for _, key := range info.SSHKeys { context.Printf("- %s\n", key) diff --git a/internal/dis/component/control/info/html/instance.html b/internal/dis/component/control/info/html/instance.html index 71598fd..6578dd0 100644 --- a/internal/dis/component/control/info/html/instance.html +++ b/internal/dis/component/control/info/html/instance.html @@ -265,11 +265,106 @@ +
+

Statistics

+
+ +
+
+
+ + + + + + + + + + + + + + + {{ range .Info.Statistics.Bundles.Bundles }} + + + + + + + + {{ end }} + +
+ Bundles +
+ Label + + Machine Name + + Count + + LastEdit + + MainBundle +
+ {{ .Label }} + + {{ .MachineName }} + + {{ .Count }} + + {{ .LastEdit }} + + {{ .MainBundle }} +
+
+
+
+ + +
+
+
+ + + + + + + + + + + + {{ range .Info.Statistics.Triplestore.Graphs }} + + + + + {{ end }} + +
+ Triplestore +
+ URI + + Count +
+ {{ .URI }} + + {{ .Count }} +
+
+
+
+

SSH Keys

- {{ range .Info.Keys }} + {{ range .Info.SSHKeys }}
{{ . }} diff --git a/internal/dis/component/control/static/templates/_base.html b/internal/dis/component/control/static/templates/_base.html index 4faa834..b1c40c1 100644 --- a/internal/dis/component/control/static/templates/_base.html +++ b/internal/dis/component/control/static/templates/_base.html @@ -2,6 +2,7 @@ + {{ block "block" . }}Distillery Control Page{{ end }} {{ block "styles" . }}styles{{ end }} diff --git a/internal/phpx/serialize.go b/internal/phpx/serialize.go new file mode 100644 index 0000000..958fc7f --- /dev/null +++ b/internal/phpx/serialize.go @@ -0,0 +1,49 @@ +package phpx + +import "encoding/json" + +// BooleanIsh represents a boolean php value. +// +// The value can be serialized to and from php and will behave accordingly. +// +// The value will always be Marshaled as "true" or "false". +// +// When Unmarshaled, it behaves as described on https://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting. +type BooleanIsh bool + +func (bi BooleanIsh) MarshalJSON() ([]byte, error) { + if bi { + return []byte("true"), nil + } + return []byte("false"), nil +} +func (bi *BooleanIsh) UnmarshalJSON(data []byte) (err error) { + // unmarshal into a generic value + var value any + err = json.Unmarshal(data, &value) + if err != nil { + return err + } + + // check if it is false ish + var isFalseIsh bool + switch d := value.(type) { + case bool: + isFalseIsh = !d + case int: + isFalseIsh = d == 0 + case float64: + isFalseIsh = d == 0 + case string: + isFalseIsh = d == "" || d == "0" + case []any: + isFalseIsh = len(d) == 0 + case map[string]any: + isFalseIsh = len(d) == 0 + case nil: + isFalseIsh = true + } + *bi = BooleanIsh(!isFalseIsh) + + return nil +} diff --git a/internal/wisski/ingredient/barrel/barrel/scripts/user_shell.sh b/internal/wisski/ingredient/barrel/barrel/scripts/user_shell.sh index 10a738c..9156c8f 100755 --- a/internal/wisski/ingredient/barrel/barrel/scripts/user_shell.sh +++ b/internal/wisski/ingredient/barrel/barrel/scripts/user_shell.sh @@ -1,12 +1,15 @@ #!/bin/bash set -e -# This script is used to start a user shell inside the docker container. +# if the user is not www-data, re-invoke self as www-data +if [ "$USER" != "www-data" ]; then + sudo -u www-data /bin/bash /user_shell.sh "$@" + exit $? +fi + +# Now start a shell in the proper path cd "/var/www/data/project" export "PATH=/var/www/data/project/vendor/bin:$PATH" -if [ "$USER" = "www-data" ]; then - /bin/bash "$@" -else - sudo -u www-data /bin/bash "$@" -fi; \ No newline at end of file +# Re-invoke the actual command +/bin/bash "$@" \ No newline at end of file diff --git a/internal/wisski/ingredient/barrel/barrel/ssh/keys.sh b/internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/keys.sh similarity index 100% rename from internal/wisski/ingredient/barrel/barrel/ssh/keys.sh rename to internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/keys.sh diff --git a/internal/wisski/ingredient/barrel/barrel/ssh/sshd_config b/internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/sshd_config similarity index 100% rename from internal/wisski/ingredient/barrel/barrel/ssh/sshd_config rename to internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/sshd_config diff --git a/internal/wisski/ingredient/barrel/barrel/ssh/start.sh b/internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/start.sh similarity index 100% rename from internal/wisski/ingredient/barrel/barrel/ssh/start.sh rename to internal/wisski/ingredient/barrel/barrel/wisskiutils/ssh/start.sh diff --git a/internal/wisski/ingredient/fetcher.go b/internal/wisski/ingredient/fetcher.go index 18d0440..d371fa1 100644 --- a/internal/wisski/ingredient/fetcher.go +++ b/internal/wisski/ingredient/fetcher.go @@ -38,6 +38,9 @@ type Information struct { LastUpdate time.Time LastCron time.Time + // Statistics of the wisski (TODO: fix me) + Statistics Statistics + // List of backups made Snapshots []models.Export @@ -49,3 +52,39 @@ type Information struct { Prefixes []string // list of prefixes Pathbuilders map[string]string // all the pathbuilders } + +type Statistics struct { + Activity struct { + MostVisited string `json:"mostVisited"` + PageVisits []struct { + URL string `json:"url"` + Visits int `json:"visits"` + } `json:"pageVisits"` + TotalEditsLastWeek int `json:"totalEditsLastWeek"` + } `json:"activity"` + Bundles struct { + Bundles []struct { + Label string `json:"label"` + MachineName string `json:"machineName"` + + Count int `json:"entities"` + + LastEdit int `json:"lastEdit"` + + MainBundle phpx.BooleanIsh `json:"mainBundle"` + } `json:"bundleStatistics"` + TotalBundles int `json:"totalBundles"` + TotalMainBundles int `json:"totalMainBundles"` + } `json:"bundles"` + Triplestore struct { + Graphs []struct { + URI string `json:"uri"` + Count int `json:"triples"` + } `json:"graphStatistics"` + Total int `json:"totalTriples"` + } `json:"triplestore"` + Users struct { + LastLogin string `json:"lastLogin"` + TotalUsers int `json:"totalUsers"` + } `json:"users"` +} diff --git a/internal/wisski/ingredient/php/extras/stats.go b/internal/wisski/ingredient/php/extras/stats.go new file mode 100644 index 0000000..047ac4e --- /dev/null +++ b/internal/wisski/ingredient/php/extras/stats.go @@ -0,0 +1,37 @@ +package extras + +import ( + _ "embed" + "log" + + "github.com/FAU-CDI/wisski-distillery/internal/phpx" + "github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient" + "github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/php" +) + +type Stats struct { + ingredient.Base + + PHP *php.PHP +} + +//go:embed stats.php +var statsPHP string + +// Get fetches all statistics from the server +func (stats *Stats) Get(server *phpx.Server) (data ingredient.Statistics, err error) { + err = stats.PHP.ExecScript(server, &data, statsPHP, "export_statistics") + if err != nil { + log.Println(err) + } + return +} + +func (stats *Stats) Fetch(flags ingredient.FetchFlags, info *ingredient.Information) (err error) { + if flags.Quick { + return + } + + info.Statistics, _ = stats.Get(flags.Server) + return +} diff --git a/internal/wisski/ingredient/php/extras/stats.php b/internal/wisski/ingredient/php/extras/stats.php new file mode 100644 index 0000000..69d7b3d --- /dev/null +++ b/internal/wisski/ingredient/php/extras/stats.php @@ -0,0 +1,8 @@ +update(); +} diff --git a/internal/wisski/wisski.go b/internal/wisski/wisski.go index af39a37..65a06e4 100644 --- a/internal/wisski/wisski.go +++ b/internal/wisski/wisski.go @@ -99,6 +99,7 @@ func (wisski *WissKI) allIngredients() []initFunc { auto[*extras.Prefixes], auto[*extras.Settings], auto[*extras.Pathbuilder], + auto[*extras.Stats], // info manual(func(info *info.Info) {