]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Front.git/commitdiff
Admin minimal dashboard. v0.0.14
authorjloup <jloup@jloup.work>
Sun, 13 May 2018 21:14:26 +0000 (23:14 +0200)
committerjloup <jloup@jloup.work>
Sun, 13 May 2018 21:18:48 +0000 (23:18 +0200)
api/admin.go [new file with mode: 0644]
api/routes.go
api/user.go
cmd/app/main.go
cmd/web/js/admin.jsx [new file with mode: 0644]
cmd/web/js/api.js
cmd/web/js/balance.jsx
cmd/web/js/main.jsx
db/market_config.go

diff --git a/api/admin.go b/api/admin.go
new file mode 100644 (file)
index 0000000..0ac6050
--- /dev/null
@@ -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
+}
index 3adbfe95b1a9655a5fa7dc3d3a13b75019128b4b..a102419217561feab3871961b34e2097fe069fac 100644 (file)
@@ -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)
+}
index bc24bbb23111d478adb6bb82636cd7bc82dc4e81..ff539f0c388d395a157e579515addf1d28fae08b 100644 (file)
@@ -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 {
index 2cf29f96242a5e6ddbb8aba4d2fb33736029a58e..4405bf129dcf4ea7133a0aaadacc92fc0baa2b85 100644 (file)
@@ -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 (file)
index 0000000..81ce15d
--- /dev/null
@@ -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 <div></div>;
+    }
+    var portfolios = Object.keys(this.state.portfolios).map(function(email) {
+      return <div className="row" key={email}>
+               <div className="col-6"><span>{email}:</span></div>
+               <div className="col-6 text-center">
+                 <PFBalanceMinimal variationP={this.state.portfolios[email].performance.variationP} balance={this.state.portfolios[email].value} periodStart={this.state.portfolios[email].periodStart}/>
+               </div>
+             </div>;
+    }.bind(this));
+
+    return <Panel component={<div>{portfolios}</div>} title="Portfolios Overview"/>;
+  }
+
+}
+
+export default AdminDashboard;
index 63355f061142e5c8e7084bbc30c4e0d60e957733..b626c5f704e7a33a55f9dfa73997d9205f510d70 100644 (file)
@@ -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) {
index 515a7ede549b040c1a2bf1506bd598f2eb6e5c72..6217e96236435fdccd0e04a4fe89adcf52b6e0b5 100644 (file)
@@ -95,4 +95,16 @@ class PFBalance extends React.Component {
     }
 }
 
-export {PFBalance, Assets};
+class PFBalanceMinimal extends React.Component {
+    render = () => {
+        return <React.Fragment>
+            <div className="balance">
+              <div className="col-12">
+                <CurrencyLogo currency="BTC" /> <span><strong>{this.props.balance}</strong> <strong>{formatVariation(this.props.variationP)}</strong></span>
+              </div>
+            </div>
+        </React.Fragment>;
+    }
+}
+
+export {PFBalance, Assets, PFBalanceMinimal};
index 7fa2d2601c2331b896c47e520431ba6634a69104..8014377523aba32c31ef45f50c8ac7e39630c40a 100644 (file)
@@ -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) {
     </div>);
 });
 
+App.page('/admin', true, function(context) {
+  App.mount(<div>
+      <AdminDashboard/>
+    </div>);
+});
+
 App.page('/not_confirmed', true, function(context) {
   App.mount(<div>
       <div className="row">
index 30b453877464c08255f85413bb1b5015299a72b6..afb2842a529c94ef348922d2e4ae9e438f7160c4 100644 (file)
@@ -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
+}