From eb02ff2b46636e75c4b4126d0b39b0b549d1f572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Mon, 14 Aug 2017 00:20:38 +0200 Subject: [PATCH] Add stats about the library --- src/internal/admins/stats.go | 57 ++++++++++++++++++++++++ src/public/js/actions/admins.js | 7 +++ src/public/js/components/admins/panel.js | 15 +++++-- src/public/js/components/admins/stats.js | 27 +++++++++++ src/public/js/reducers/admins.js | 2 + src/public/js/routes.js | 5 ++- src/routes.go | 1 + 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 src/internal/admins/stats.go create mode 100644 src/public/js/components/admins/stats.js diff --git a/src/internal/admins/stats.go b/src/internal/admins/stats.go new file mode 100644 index 0000000..0897d2c --- /dev/null +++ b/src/internal/admins/stats.go @@ -0,0 +1,57 @@ +package admin + +import ( + "net/http" + + "github.com/jmoiron/sqlx" + "github.com/sirupsen/logrus" + "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web" +) + +const ( + moviesCountQuery = `SELECT COUNT(*) FROM movies;` + showsCountQuery = `SELECT COUNT(*) FROM shows;` + episodesCountQuery = `SELECT COUNT(*) FROM episodes;` +) + +// GetCount gets the count from a query +func GetCount(db *sqlx.DB, query string) (int, error) { + var count int + err := db.QueryRow(query).Scan(&count) + if err != nil { + return 0, err + } + return count, nil +} + +// GetStatsHandler returns the stats of the app +func GetStatsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error { + log := env.Log.WithFields(logrus.Fields{ + "function": "admin.GetStatsHandler", + }) + + log.Debug("getting stats") + + stats := struct { + MoviesCount int `json:"movies_count"` + ShowsCount int `json:"shows_count"` + EpisodesCount int `json:"episodes_count"` + }{} + + for _, s := range []struct { + query string + ptr *int + }{ + {moviesCountQuery, &stats.MoviesCount}, + {showsCountQuery, &stats.ShowsCount}, + {episodesCountQuery, &stats.EpisodesCount}, + } { + var err error + *s.ptr, err = GetCount(env.Database, s.query) + if err != nil { + return err + } + } + + return env.RenderJSON(w, stats) +} diff --git a/src/public/js/actions/admins.js b/src/public/js/actions/admins.js index 15d2a65..050ca88 100644 --- a/src/public/js/actions/admins.js +++ b/src/public/js/actions/admins.js @@ -7,6 +7,13 @@ export function getUsers() { ) } +export function getStats() { + return request( + "ADMIN_GET_STATS", + configureAxios().get("/admins/stats") + ) +} + export function updateUser(data) { return request( "ADMIN_UPDATE_USER", diff --git a/src/public/js/components/admins/panel.js b/src/public/js/components/admins/panel.js index cd1847d..5f5e5f0 100644 --- a/src/public/js/components/admins/panel.js +++ b/src/public/js/components/admins/panel.js @@ -4,10 +4,12 @@ import { bindActionCreators } from "redux" import { updateUser } from "../../actions/admins" import UserList from "./users" +import Stats from "./stats" function mapStateToProps(state) { return { users : state.adminStore.get("users"), + stats : state.adminStore.get("stats"), }; } const mapDispatchToProps = (dipatch) => @@ -15,10 +17,15 @@ const mapDispatchToProps = (dipatch) => function AdminPanel(props) { return ( - +
+ + +
); } diff --git a/src/public/js/components/admins/stats.js b/src/public/js/components/admins/stats.js new file mode 100644 index 0000000..3993dbb --- /dev/null +++ b/src/public/js/components/admins/stats.js @@ -0,0 +1,27 @@ +import React from "react" + +export default function Stats(props) { + return ( +
+

Stats

+ + + +
+ ); +} + +function Stat(props) { + return ( +
+
+
+

{props.name}

+
+
+ {props.value} +
+
+
+ ); +} diff --git a/src/public/js/reducers/admins.js b/src/public/js/reducers/admins.js index caac3b6..a309c46 100644 --- a/src/public/js/reducers/admins.js +++ b/src/public/js/reducers/admins.js @@ -2,10 +2,12 @@ import { Map, List, fromJS } from "immutable" const defaultState = Map({ "users": List(), + "stats": Map({}), }); const handlers = { "ADMIN_LIST_USERS_FULFILLED": (state, action) => state.set("users", fromJS(action.payload.response.data)), + "ADMIN_GET_STATS_FULFILLED": (state, action) => state.set("stats", fromJS(action.payload.response.data)), } export default (state = defaultState, action) => diff --git a/src/public/js/routes.js b/src/public/js/routes.js index 1bcea9b..3f1fcd1 100644 --- a/src/public/js/routes.js +++ b/src/public/js/routes.js @@ -12,7 +12,7 @@ import { fetchTorrents } from "./actions/torrents" import { userLogout, getUserInfos } from "./actions/users" import { fetchMovies, getMovieExploreOptions } from "./actions/movies" import { fetchShows, fetchShowDetails, getShowExploreOptions } from "./actions/shows" -import { getUsers } from "./actions/admins" +import { getUsers, getStats } from "./actions/admins" import store from "./store" @@ -122,7 +122,7 @@ export default function getRoutes(App) { component: UserActivation, onEnter: function(nextState, replace, next) { if (!isLoggedIn()) { - replace('/users/login'); + replace("/users/login"); } if (isActivated()) { // User is already activated, redirect him to the default route @@ -254,6 +254,7 @@ export default function getRoutes(App) { onEnter: function(nextState, replace, next) { adminCheck(nextState, replace, next, function() { store.dispatch(getUsers()); + store.dispatch(getStats()); }); }, }, diff --git a/src/routes.go b/src/routes.go index f2d07df..0c56a58 100644 --- a/src/routes.go +++ b/src/routes.go @@ -61,4 +61,5 @@ func setupRoutes(env *web.Env) { // Admin routes env.Handle("/admins/users", admin.GetUsersHandler).WithRole(users.AdminRole).Methods("GET") env.Handle("/admins/users", admin.UpdateUserHandler).WithRole(users.AdminRole).Methods("POST") + env.Handle("/admins/stats", admin.GetStatsHandler).WithRole(users.AdminRole).Methods("GET") }