From 2e4885d98ec49203180deb7e4e9148762e4720e7 Mon Sep 17 00:00:00 2001 From: jloup Date: Sun, 13 May 2018 23:14:26 +0200 Subject: [PATCH] Admin minimal dashboard. --- api/admin.go | 46 ++++++++++++++++++++++++++++++++++++++++++ api/routes.go | 12 ++++++++++- api/user.go | 7 ++++--- cmd/app/main.go | 1 + cmd/web/js/admin.jsx | 45 +++++++++++++++++++++++++++++++++++++++++ cmd/web/js/api.js | 9 +++++++++ cmd/web/js/balance.jsx | 14 ++++++++++++- cmd/web/js/main.jsx | 7 +++++++ db/market_config.go | 14 +++++++++++++ 9 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 api/admin.go create mode 100644 cmd/web/js/admin.jsx diff --git a/api/admin.go b/api/admin.go new file mode 100644 index 0000000..0ac6050 --- /dev/null +++ b/api/admin.go @@ -0,0 +1,46 @@ +package api + +import ( + "fmt" + + "immae.eu/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front/db" +) + +type GetAllPortfoliosQuery struct { + In struct { + Market string + } + Out map[string]Portfolio +} + +func (q GetAllPortfoliosQuery) ValidateParams() *Error { + if q.In.Market != "poloniex" { + return &Error{BadRequest, "invalid market name", fmt.Errorf("'%v' is not a valid market name", q.In.Market)} + } + + return nil +} + +func (q GetAllPortfoliosQuery) Run() (interface{}, *Error) { + u, err := db.GetActiveUsers() + if err != nil { + return nil, NewInternalError(err) + } + + q.Out = make(map[string]Portfolio) + + for _, marketConfig := range u { + report, err := GetWeekPortfolio(marketConfig) + if ErrorIs(err, NotFound) { + continue + } + + if err != nil { + return nil, NewInternalError(err) + } + + q.Out[marketConfig.User.Email] = report.Round() + } + + return q.Out, nil +} diff --git a/api/routes.go b/api/routes.go index 3adbfe9..a102419 100644 --- a/api/routes.go +++ b/api/routes.go @@ -58,7 +58,9 @@ var Groups = []Group{ { "/admin", []Middleware{JwtAuth, UserConfirmed, UserIsAdmin, OtpAuth}, - []Route{}, + []Route{ + {"GET", []gin.HandlerFunc{AdminGetAllPortfolios}, "/portfolios"}, + }, }, } @@ -189,3 +191,11 @@ func UserAccount(c *gin.Context) { RunQuery(query, c) } + +func AdminGetAllPortfolios(c *gin.Context) { + query := &GetAllPortfoliosQuery{} + + query.In.Market = "poloniex" + + RunQuery(query, c) +} diff --git a/api/user.go b/api/user.go index bc24bbb..ff539f0 100644 --- a/api/user.go +++ b/api/user.go @@ -62,7 +62,8 @@ type SignParams struct { } type SignResult struct { - Token string `json:"token"` + Token string `json:"token"` + IsAdmin bool `json:"isAdmin"` } func (s SignParams) Validate() *Error { @@ -142,7 +143,7 @@ func (q SignupQuery) Run() (interface{}, *Error) { } } - return SignResult{token}, nil + return SignResult{token, newUser.Role == db.RoleAdmin}, nil } type SigninQuery struct { @@ -173,7 +174,7 @@ func (q SigninQuery) Run() (interface{}, *Error) { return nil, NewInternalError(err) } - return SignResult{token}, nil + return SignResult{token, user.Role == db.RoleAdmin}, nil } type ConfirmEmailQuery struct { diff --git a/cmd/app/main.go b/cmd/app/main.go index 2cf29f9..4405bf1 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -146,6 +146,7 @@ func main() { "/change-password", "/signout", "/me", + "/admin", "/account", "/otp/enroll", "/otp/validate", diff --git a/cmd/web/js/admin.jsx b/cmd/web/js/admin.jsx new file mode 100644 index 0000000..81ce15d --- /dev/null +++ b/cmd/web/js/admin.jsx @@ -0,0 +1,45 @@ +import Api from './api.js'; +import React from 'react'; +import {PFBalanceMinimal} from './balance.js'; +import Panel from './panel.js'; + +class AdminDashboard extends React.Component { + constructor(state) { + super(state); + this.state = {'portfolios': null}; + } + + load = () => { + Api.Call('ADMIN_PORTFOLIOS', {}, function(err, status, data) { + if (err) { + console.error(err, data); + return; + } + + this.setState({'portfolios': data}); + }.bind(this)); + } + + componentDidMount = () => { + this.load(); + } + + render = () => { + if (this.state.portfolios === null) { + return
; + } + var portfolios = Object.keys(this.state.portfolios).map(function(email) { + return
+
{email}:
+
+ +
+
; + }.bind(this)); + + return {portfolios}} title="Portfolios Overview"/>; + } + +} + +export default AdminDashboard; diff --git a/cmd/web/js/api.js b/cmd/web/js/api.js index 63355f0..b626c5f 100644 --- a/cmd/web/js/api.js +++ b/cmd/web/js/api.js @@ -142,6 +142,15 @@ var ApiEndpoints = { return '/otp/validate'; } }, + 'ADMIN_PORTFOLIOS': { + 'type': 'GET', + 'auth': true, + 'parameters': [], + 'buildUrl': function() { + return '/admin/portfolios'; + } + }, + }; Api.BuildRequest = function(endpointId, params) { diff --git a/cmd/web/js/balance.jsx b/cmd/web/js/balance.jsx index 515a7ed..6217e96 100644 --- a/cmd/web/js/balance.jsx +++ b/cmd/web/js/balance.jsx @@ -95,4 +95,16 @@ class PFBalance extends React.Component { } } -export {PFBalance, Assets}; +class PFBalanceMinimal extends React.Component { + render = () => { + return +
+
+ {this.props.balance} {formatVariation(this.props.variationP)} +
+
+
; + } +} + +export {PFBalance, Assets, PFBalanceMinimal}; diff --git a/cmd/web/js/main.jsx b/cmd/web/js/main.jsx index 7fa2d26..8014377 100644 --- a/cmd/web/js/main.jsx +++ b/cmd/web/js/main.jsx @@ -5,6 +5,7 @@ import ChangePasswordForm from './change_password.js'; import OtpEnrollForm from './otp.js'; import PoloniexController from './poloniex.js'; import UserAccount from './account.js'; +import AdminDashboard from './admin.js'; import App from './app.js'; import Api from './api.js'; import cookies from './cookies.js'; @@ -101,6 +102,12 @@ App.page('/account', true, function(context) { ); }); +App.page('/admin', true, function(context) { + App.mount(
+ +
); +}); + App.page('/not_confirmed', true, function(context) { App.mount(
diff --git a/db/market_config.go b/db/market_config.go index 30b4538..afb2842 100644 --- a/db/market_config.go +++ b/db/market_config.go @@ -16,6 +16,9 @@ type MarketConfig struct { UserId int64 Status MarketConfigStatus Config map[string]string + + // Will be expanded by pg + User User } func InsertMarketConfig(config *MarketConfig) error { @@ -62,3 +65,14 @@ func SetMarketConfigStatus(marketConfig MarketConfig, status MarketConfigStatus) return &marketConfig, err } + +func GetActiveUsers() ([]MarketConfig, error) { + var configs []MarketConfig + + err := DB.Model(&configs).Column("User").Where("market_config.status=?", "enabled").Select() + if err != nil { + return nil, err + } + + return configs, nil +} -- 2.41.0