diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..66374a65a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. +.scannerwork diff --git a/client/package-lock.json b/client/package-lock.json index 2f4b4a7ba..8a42f92c0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,6 +1,6 @@ { "name": "@superalgos/operations-client", - "version": "0.0.2", + "version": "0.0.14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client/package.json b/client/package.json index 43a89253f..40b5a1d21 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@superalgos/operations-client", - "version": "0.0.13", + "version": "0.0.14", "description": "Superalgos Operations client-side web app", "main": "src/index.js", "dependencies": { diff --git a/client/src/GraphQL/Calls/clones.js b/client/src/GraphQL/Calls/clones.js index cf6c8d7b8..7d4c1aff6 100644 --- a/client/src/GraphQL/Calls/clones.js +++ b/client/src/GraphQL/Calls/clones.js @@ -1,5 +1,5 @@ -import gql from 'graphql-tag'; -import { clone } from '../Fragments'; +import gql from 'graphql-tag' +import { clone } from '../Fragments' const OPERATIONS_ADD_CLONE = gql` mutation Operations_AddClone($clone: operations_CloneInput!) { @@ -8,7 +8,7 @@ const OPERATIONS_ADD_CLONE = gql` } } ${clone} -`; +` const OPERATIONS_LIST_CLONES = gql` query Operations_Clones{ @@ -17,7 +17,7 @@ const OPERATIONS_LIST_CLONES = gql` } } ${clone} -`; +` const OPERATIONS_HISTORY_CLONES = gql` query Operations_HistoryClones{ @@ -26,17 +26,17 @@ const OPERATIONS_HISTORY_CLONES = gql` } } ${clone} -`; +` const OPERATIONS_REMOVE_CLONE = gql` mutation Operations_RemoveClone($id: ID!){ operations_RemoveClone( id: $id) } -`; +` export default { OPERATIONS_LIST_CLONES, OPERATIONS_HISTORY_CLONES, OPERATIONS_ADD_CLONE, OPERATIONS_REMOVE_CLONE -}; +} diff --git a/client/src/GraphQL/Calls/index.js b/client/src/GraphQL/Calls/index.js index f410adf89..619c6f158 100644 --- a/client/src/GraphQL/Calls/index.js +++ b/client/src/GraphQL/Calls/index.js @@ -1,7 +1,9 @@ -import clones from './clones'; -import teams from './teams'; +import clones from './clones' +import teams from './teams' +import keys from './keys' export { clones, - teams -}; + teams, + keys +} diff --git a/client/src/GraphQL/Calls/keys.js b/client/src/GraphQL/Calls/keys.js new file mode 100644 index 000000000..0f6e8006a --- /dev/null +++ b/client/src/GraphQL/Calls/keys.js @@ -0,0 +1,15 @@ +import gql from 'graphql-tag' + +export const GET_ALL_KEYS = gql` + query { + keyVault_AvailableKeys { + id + key + description + } + } +` + +export default { + GET_ALL_KEYS +} diff --git a/client/src/GraphQL/Calls/teams.js b/client/src/GraphQL/Calls/teams.js index 0a27afd3c..2785ede48 100644 --- a/client/src/GraphQL/Calls/teams.js +++ b/client/src/GraphQL/Calls/teams.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from 'graphql-tag' export const GET_ALL_TEAMS_QUERY = gql` query { @@ -18,4 +18,4 @@ export const GET_ALL_TEAMS_QUERY = gql` export default { GET_ALL_TEAMS_QUERY -}; +} diff --git a/client/src/GraphQL/Fragments/clone.js b/client/src/GraphQL/Fragments/clone.js index 42022c0bd..75a5f9dbc 100644 --- a/client/src/GraphQL/Fragments/clone.js +++ b/client/src/GraphQL/Fragments/clone.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from 'graphql-tag' export const clone = gql` fragment clone on operations_Clone { @@ -30,5 +30,6 @@ export const clone = gql` botAvatar teamAvatar processName + keyId } -`; +` diff --git a/client/src/GraphQL/Fragments/index.js b/client/src/GraphQL/Fragments/index.js index 2ee040281..d916b776d 100644 --- a/client/src/GraphQL/Fragments/index.js +++ b/client/src/GraphQL/Fragments/index.js @@ -1,6 +1,5 @@ import { clone } from './clone' - export { clone -}; +} diff --git a/client/src/GraphQL/index.js b/client/src/GraphQL/index.js deleted file mode 100644 index 8b1378917..000000000 --- a/client/src/GraphQL/index.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/client/src/GraphQL/models.js b/client/src/GraphQL/models.js index c7a5df51b..47c7e6dfb 100644 --- a/client/src/GraphQL/models.js +++ b/client/src/GraphQL/models.js @@ -1,16 +1,15 @@ -const availableMonths = ["January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"] +const availableMonths = ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'] -const tradingStartModes ={ - live: "Live", - competition: "Competition", - backtest: "Backtest" +const tradingStartModes = { + live: 'Live', + backtest: 'Backtest' } const indicatorStartModes = { - allMonths: "All Months", - oneMonth: "One Month", - noTime: "No Time" + allMonths: 'All Months', + oneMonth: 'One Month', + noTime: 'No Time' } const exchanges = [ @@ -20,6 +19,4 @@ const exchanges = [ } ] - - export { tradingStartModes, exchanges, indicatorStartModes, availableMonths } diff --git a/client/src/index.js b/client/src/index.js index 970c534aa..dbc3944b5 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -1,9 +1,7 @@ -import React, { Component } from 'react' +import React from 'react' import { Route, Switch } from 'react-router-dom' - import { MuiPickersUtilsProvider } from 'material-ui-pickers' import LuxonUtils from 'material-ui-pickers/utils/luxon-utils' - import BrowseClones from './views/Clone/List' import HistoryClones from './views/Clone/History' import AddClone from './views/Clone/Add' @@ -12,10 +10,10 @@ import Home from './views/Home' const App = () => ( - - - - + + + + ) diff --git a/client/src/utils/index.js b/client/src/utils/index.js index e5e223f3c..a12aa4fa9 100644 --- a/client/src/utils/index.js +++ b/client/src/utils/index.js @@ -10,13 +10,13 @@ export function toLocalTime (epoch) { } export function toUTCTimestamp (localDate) { - if(isDefined(localDate)){ + if (isDefined(localDate)) { const date = new Date(localDate.valueOf()) const utcDate = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()) - return utcDate.valueOf() / 1000|0 + return utcDate.valueOf() / 1000 | 0 } } @@ -77,7 +77,7 @@ export function getIndicatorYears () { const localDate = new Date() let availableYears = [] for (var i = 2015; i <= localDate.getUTCFullYear(); i++) { - availableYears[i-2015] = i + availableYears[i - 2015] = i } return availableYears } diff --git a/client/src/views/Clone/Add/index.js b/client/src/views/Clone/Add/index.js index 3db9ccfdd..361f5ee43 100644 --- a/client/src/views/Clone/Add/index.js +++ b/client/src/views/Clone/Add/index.js @@ -1,30 +1,20 @@ import React, { Component } from 'react' import { graphql, compose, Query } from 'react-apollo' -import { clones, teams } from '../../../GraphQL/Calls' +import { clones, teams, keys } from '../../../GraphQL/Calls' import { DateTime } from 'luxon'; - import TopBar from '../../BannerTopBar' - import { withStyles } from '@material-ui/core/styles' import classNames from 'classnames' import styles from './styles' - -import { tradingStartModes, indicatorStartModes, availableMonths, processNames } from '../../../GraphQL/models' +import { tradingStartModes, indicatorStartModes, availableMonths } from '../../../GraphQL/models' import { isDefined, getIndicatorYears } from '../../../utils' - import { MenuItem, Button, TextField, FormControl, InputLabel, Input, Typography, Paper, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Select, FormControlLabel, Checkbox, FormHelperText } from '@material-ui/core' - -import NumberFormat from 'react-number-format' - import { DateTimePicker } from 'material-ui-pickers' -import { - ChevronLeft, - ChevronRight, -} from '@material-ui/icons' +import { ChevronLeft, ChevronRight } from '@material-ui/icons' class AddClone extends Component { @@ -45,6 +35,7 @@ class AddClone extends Component { runAsTeam: false, teams: [], teamId: '', + keyId: '', // Indicator Bot startYear: 2019, @@ -60,7 +51,8 @@ class AddClone extends Component { isNewCloneConfirmationOpen: false, serverResponse: '', serverError: false, - processNameError: false + processNameError: false, + keyIdError: false } } @@ -230,6 +222,60 @@ class AddClone extends Component { } + { this.state.mode == "live" && + + + Select one of your available Exchange API Keys to be used by this clone. + + + + {({ loading, error, data }) => { + if (loading) return ( + this.setState({keyId:e.target.value})} + onBlur={(e)=>this.setState({keyIdError:false})} + error={this.state.keyIdError} + fullWidth + > + + 'Loading keys...' + + + ); + if (error) return `Error! ${error.message}`; + const list = data.keyVault_AvailableKeys.map((key) => ( + + {key.key} + + )); + return ( + this.setState({keyId:e.target.value})} + onBlur={(e)=>this.setState({keyIdError:false})} + error={this.state.keyIdError} + fullWidth + > + { list } + + ); + }} + + + + + + } + If Run as Team is selected, the clone will be taken from the team respository instead of your own team member folder. @@ -399,7 +445,8 @@ class AddClone extends Component { - @@ -431,7 +478,7 @@ class AddClone extends Component { let serverResponse = await this.createCloneOnServer() error = serverResponse.errors || !isDefined(serverResponse.data.operations_AddClone) if(error){ - this.state.serverResponse = serverResponse.errors[0].message + this.state.serverResponse = serverResponse.errors[0].message || serverResponse.errors[0] this.state.serverError = true }else{ this.state.serverResponse = "The new clone was sucessfully created." @@ -453,15 +500,16 @@ class AddClone extends Component { } } - if(this.state.mode === "backtest"){ - variables.clone.beginDatetime = this.state.beginDatetime.valueOf() / 1000|0 - variables.clone.endDatetime = this.state.endDatetime.valueOf() / 1000|0 - variables.clone.waitTime = this.state.waitTime - } - if(this.state.selectedBot.kind === "TRADER"){ variables.clone.runAsTeam = this.state.runAsTeam variables.clone.processName = 'Trading-Process' + if(this.state.mode === "backtest"){ + variables.clone.beginDatetime = this.state.beginDatetime.valueOf() / 1000|0 + variables.clone.endDatetime = this.state.endDatetime.valueOf() / 1000|0 + variables.clone.waitTime = this.state.waitTime + } else { + variables.clone.keyId = this.state.keyId + } } else { variables.clone.processName = this.state.processName variables.clone.startYear = this.state.startYear @@ -508,6 +556,7 @@ class AddClone extends Component { processName: '', teams: [], teamId: '', + keyId: '', //Error handlers nameError: false, @@ -517,7 +566,8 @@ class AddClone extends Component { isNewCloneConfirmationOpen: false, serverResponse: '', serverError: false, - processNameError: false + processNameError: false, + keyIdError: false }) }; diff --git a/client/src/views/Clone/Add/styles.js b/client/src/views/Clone/Add/styles.js index c9339ec38..2d831d291 100644 --- a/client/src/views/Clone/Add/styles.js +++ b/client/src/views/Clone/Add/styles.js @@ -14,7 +14,7 @@ const styles = theme => ({ }, textField: { width: '80%', - marginLeft:'10%', + marginLeft: '10%', marginBottom: 10 }, actionButton: { @@ -30,8 +30,8 @@ const styles = theme => ({ marginTop: 20 }, selectEmpty: { - marginTop: theme.spacing.unit * 2, - }, -}); + marginTop: theme.spacing.unit * 2 + } +}) -export default styles; +export default styles diff --git a/client/src/views/Clone/History/index.js b/client/src/views/Clone/History/index.js index 7a1c103e3..4ccaed243 100644 --- a/client/src/views/Clone/History/index.js +++ b/client/src/views/Clone/History/index.js @@ -2,12 +2,8 @@ import React, { Component } from 'react' import { graphql } from 'react-apollo' import { clones } from '../../../GraphQL/Calls' import TopBar from '../../BannerTopBar' -//import CloneDialog from './CloneDialog' import ListClones from '../List/ListClones' -// Material-ui -import { Typography, Paper } from '@material-ui/core' - class HistoryClones extends Component { constructor (props) { @@ -44,7 +40,7 @@ class HistoryClones extends Component { { data.operations_HistoryClones.map((clone, i) => { return ( - + ) }) } diff --git a/client/src/views/Clone/List/CloneDialog.js b/client/src/views/Clone/List/CloneDialog.js index 46525d2c1..90998f09a 100644 --- a/client/src/views/Clone/List/CloneDialog.js +++ b/client/src/views/Clone/List/CloneDialog.js @@ -1,12 +1,9 @@ import React, { Component } from 'react' import AddClone from './AddClone' - -import AddIcon from '@material-ui/icons/Add' import { withStyles } from '@material-ui/core/styles' import styles from './styles' - import { - Button, Dialog, DialogContent, DialogContentText, DialogTitle, Paper, Typography + Button, Dialog, DialogContent, DialogContentText, DialogTitle } from '@material-ui/core' class CloneDialog extends Component { diff --git a/client/src/views/Clone/List/ListClones.js b/client/src/views/Clone/List/ListClones.js index 7eea28c18..b9c577826 100644 --- a/client/src/views/Clone/List/ListClones.js +++ b/client/src/views/Clone/List/ListClones.js @@ -1,19 +1,15 @@ import React, { Component } from 'react' import { graphql, compose } from 'react-apollo' import { clones } from '../../../GraphQL/Calls' -import Poloniex from '../../../img/poloniex.png' -import Binance from '../../../img/binance.png' - import { - Grid, Paper, Typography, Button, TextField, Dialog, DialogContent, + Typography, Button, TextField, Dialog, DialogContent, DialogContentText, DialogTitle, DialogActions, ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, - ExpansionPanelActions, Chip, Divider + ExpansionPanelActions, Divider } from '@material-ui/core' import Avatar from '@material-ui/core/Avatar'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; - import { tradingStartModes, indicatorStartModes } from '../../../GraphQL/models' import { isDefined, toLocalTime } from '../../../utils' import classNames from 'classnames' diff --git a/client/src/views/Clone/List/index.js b/client/src/views/Clone/List/index.js index 8b601e92e..6df628fa4 100644 --- a/client/src/views/Clone/List/index.js +++ b/client/src/views/Clone/List/index.js @@ -2,12 +2,8 @@ import React, { Component } from 'react' import { graphql } from 'react-apollo' import { clones } from '../../../GraphQL/Calls' import TopBar from '../../BannerTopBar' -//import CloneDialog from './CloneDialog' import ListClones from './ListClones' -// Material-ui -import { Typography, Paper } from '@material-ui/core' - class BrowseClones extends Component { constructor (props) { diff --git a/client/src/views/Clone/List/styles.js b/client/src/views/Clone/List/styles.js index f2c33d236..f7e1b1135 100644 --- a/client/src/views/Clone/List/styles.js +++ b/client/src/views/Clone/List/styles.js @@ -17,27 +17,26 @@ const styles = theme => ({ }, buttonList: { margin: theme.spacing.unit, - float: 'right', + float: 'right' }, buttonGrid: { - marginTop: -20, + marginTop: -20 }, button: { display: 'block', marginLeft: 'auto', - marginRight: 'auto', + marginRight: 'auto' }, textField: { marginLeft: theme.spacing.unit, - marginRight: theme.spacing.unit, + marginRight: theme.spacing.unit }, textArea: { - width:'1750px', margin: theme.spacing.unit, whiteSpace: 'pre', - width:'98%', - overflowY:'hidden', - overflowX:'hidden' + width: '98%', + overflowY: 'hidden', + overflowX: 'hidden' }, heading: { fontSize: theme.typography.pxToRem(18), @@ -50,15 +49,15 @@ const styles = theme => ({ }, helper: { borderLeft: `2px solid ${theme.palette.divider}`, - padding: `0px ${theme.spacing.unit * 2}px`, + padding: `0px ${theme.spacing.unit * 2}px` }, - logsWrapper:{ - width:'1750px', - overflowY:'auto', - overflowX:'hidden' + logsWrapper: { + width: '1750px', + overflowY: 'auto', + overflowX: 'hidden' }, - details:{ - display:'flex' + details: { + display: 'flex' }, column2: { flexBasis: '50%', @@ -68,23 +67,23 @@ const styles = theme => ({ flexBasis: '33.33%', maxWidth: '33.33%' }, - cloneInfoTitle:{ + cloneInfoTitle: { fontWeight: '600', flexBasis: '100%', maxWidth: '100%' }, - cloneInfoBold:{ + cloneInfoBold: { fontWeight: '600', paddingLeft: '10px', paddingTop: '10px' }, - cloneInfoNormal:{ + cloneInfoNormal: { paddingLeft: '10px', paddingTop: '10px' }, avatar: { - margin: 10, - }, + margin: 10 + } }) export default styles diff --git a/client/src/views/Home.js b/client/src/views/Home.js index 766c931a2..6b4d9aaec 100644 --- a/client/src/views/Home.js +++ b/client/src/views/Home.js @@ -1,6 +1,5 @@ import React, { Component } from 'react' import { Typography } from '@material-ui/core' -import { withStyles } from '@material-ui/core/styles' import TopBar from './BannerTopBar' class Home extends Component { @@ -29,9 +28,7 @@ class Home extends Component {
- - - +
diff --git a/server/README.md b/server/README.md index bb4cbecf6..6607a6cfd 100644 --- a/server/README.md +++ b/server/README.md @@ -2,3 +2,32 @@ ## AA Operations Server Server side functions support the business rules for the module. + +## Available Methods + +# Active clones List +- List active personal clones +- List active team clones (future release) + +# History clone List +- List history personal clones +- List history team clones (future release) + +# Get clone by id +- Get existing clones corresponding to the clone ids passed by parameter and returns: + - Clone id + - Team id + - Bot id + +# Add new clones: + Receive a list of clones, create each of them and return the newly created clone. + A clone can be created: + - As a personal clone (run from the personal user folder) + - As a team clone (on competitions, run from the team folder) + Who can create each type: + - Personal clones are managed by the user who creates it, not visible for any other user. + - Team clones are managed by any ADMIN type team member (on the team member role attribute), + and all team admins will see it listed. + + - Events Module: + At enroll time, the clone is created and the authId is sent diff --git a/server/src/enums/CloneMode.js b/server/src/enums/CloneMode.js index 0a463100f..fcf46ab0c 100644 --- a/server/src/enums/CloneMode.js +++ b/server/src/enums/CloneMode.js @@ -6,7 +6,6 @@ export const ONE_MONTH = 'oneMonth' export const NO_TIME = 'noTime' export const FIXED_INTERVAL = 'fixedInterval' - export const CloneModeEnum = [ LIVE, BACKTEST, diff --git a/server/src/errors/index.js b/server/src/errors/index.js index 63b27a61a..0a2f6ad14 100644 --- a/server/src/errors/index.js +++ b/server/src/errors/index.js @@ -1,5 +1,3 @@ -import logger from '../config/logger' - export class AuthentificationError extends Error { code = 401 message = 'Autentification not found, you have to be authentificated to perform this action.' @@ -53,6 +51,5 @@ export class KubernateError extends Error { message = 'OperationsModule Kubernate Error. ' + this.message constructor(message){ super(message) - logger.error(this.stack) } } diff --git a/server/src/graphQLCalls/authorizeClone.js b/server/src/graphQLCalls/authorizeClone.js new file mode 100644 index 000000000..da12c9879 --- /dev/null +++ b/server/src/graphQLCalls/authorizeClone.js @@ -0,0 +1,28 @@ +import logger from '../config/logger' +import axios from 'axios' + +const authorizeClon = (authorization, keyId, cloneId, releaseClon) => { + logger.debug('authorizeClon -> Entering function.') + + return axios({ + url: process.env.GATEWAY_ENDPOINT, + method: 'post', + data: { + query: ` + mutation keyVault_AuthorizeClone($keyId: String!, $cloneId: String!, $releaseClon: Boolean!){ + keyVault_AuthorizeClone(keyId: $keyId, cloneId: $cloneId, releaseClon:$releaseClon) + } + `, + variables: { + keyId: keyId, + cloneId: cloneId, + releaseClon: releaseClon + } + }, + headers: { + authorization: authorization + } + }) +} + +export default authorizeClon diff --git a/server/src/graphQLCalls/teamQuery.js b/server/src/graphQLCalls/teamQuery.js index c42c1722a..b38833ee5 100644 --- a/server/src/graphQLCalls/teamQuery.js +++ b/server/src/graphQLCalls/teamQuery.js @@ -1,8 +1,8 @@ import logger from '../config/logger' import axios from 'axios' -const teamQuery = async(authorization, teamId) => { - logger.debug('GraphQL retrieving team information. %s', teamId) +const teamQuery = (authorization, teamId) => { + logger.debug('teamQuery -> Entering function') return axios({ url: process.env.GATEWAY_ENDPOINT, @@ -34,13 +34,13 @@ const teamQuery = async(authorization, teamId) => { } `, variables: { - teamId: teamId - } + teamId: teamId + } }, headers: { authorization: authorization } }) -}; +} export default teamQuery diff --git a/server/src/index.js b/server/src/index.js index 02cdaa6fd..4d3e7c7a4 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -5,17 +5,17 @@ import schema from './schema' import mongoose from 'mongoose' import cors from 'cors' import logger from './config/logger' -import wrongPreshared from './errors/notAllowed.json'; +import wrongPreshared from './errors/notAllowed.json' const app = express() app.post('/graphql', (req, res, next) => { if (req.headers.preshared === process.env.OPERATIONS_API_PRESHARED) { - next(); + next() } else { - res.send(wrongPreshared); + res.send(wrongPreshared) } -}); +}) // Allow cross origing request app.use(cors()) diff --git a/server/src/kubernetes/createClone.js b/server/src/kubernetes/createClone.js index e4db79b8e..bad047b30 100644 --- a/server/src/kubernetes/createClone.js +++ b/server/src/kubernetes/createClone.js @@ -2,138 +2,140 @@ import logger from '../config/logger' import { toPlatformDatetime, isDefined } from '../config/utils' import { KubernateError } from '../errors' import { Client, config } from 'kubernetes-client' -// Get base Deployment config import deploymentManifest from '../config/clone-deployment.json' import { BACKTEST, NO_TIME } from '../enums/CloneMode' import { TRADER, INDICATOR, EXTRACTION } from '../enums/BotTypes' const createClone = async (clone) => { try { - logger.debug("createClone %s", clone.id) + logger.debug('createClone %s', clone.id) const client = new Client({config: config.fromKubeconfig(), version: '1.9'}) - - // Make changes to base deployment config deploymentManifest.metadata.name = clone.id - logger.debug("createClone Environment and Auth Configuration.") + logger.debug('createClone Environment and Auth Configuration.') let env = [] env.push({ - "name": "PLATFORM_ENVIRONMENT", - "value": process.env.PLATFORM_ENVIRONMENT + 'name': 'PLATFORM_ENVIRONMENT', + 'value': process.env.PLATFORM_ENVIRONMENT }) env.push({ - "name": "GATEWAY_ENDPOINT", - "value": process.env.GATEWAY_ENDPOINT + 'name': 'GATEWAY_ENDPOINT', + 'value': process.env.GATEWAY_ENDPOINT }) env.push({ - "name": "STORAGE_BASE_URL", - "value": process.env.STORAGE_BASE_URL + 'name': 'STORAGE_BASE_URL', + 'value': process.env.STORAGE_BASE_URL }) env.push({ - "name": "STORAGE_CONNECTION_STRING", - "value": process.env.STORAGE_CONNECTION_STRING + 'name': 'STORAGE_CONNECTION_STRING', + 'value': process.env.STORAGE_CONNECTION_STRING }) env.push({ - "name": "AUTH_URL", - "value": process.env.AUTH_URL + 'name': 'AUTH_URL', + 'value': process.env.AUTH_URL }) env.push({ - "name": "AUTH_CLIENT_ID", - "value": process.env.AUTH_CLIENT_ID + 'name': 'AUTH_CLIENT_ID', + 'value': process.env.AUTH_CLIENT_ID }) env.push({ - "name": "AUTH_CLIENT_SECRET", - "value": process.env.AUTH_CLIENT_SECRET + 'name': 'AUTH_CLIENT_SECRET', + 'value': process.env.AUTH_CLIENT_SECRET }) env.push({ - "name": "AUTH_AUDIENCE", - "value": process.env.AUTH_AUDIENCE + 'name': 'AUTH_AUDIENCE', + 'value': process.env.AUTH_AUDIENCE }) - logger.debug("createClone General Financial Being Configuration.") + logger.debug('createClone General Financial Being Configuration.') env.push({ - "name": "DEV_TEAM", - "value": clone.teamSlug + 'name': 'DEV_TEAM', + 'value': clone.teamSlug }) env.push({ - "name": "BOT", - "value": clone.botSlug + 'name': 'BOT', + 'value': clone.botSlug }) env.push({ - "name": "TYPE", - "value": clone.botType + 'name': 'TYPE', + 'value': clone.botType }) env.push({ - "name": "CLONE_ID", - "value": clone.id.toString() + 'name': 'CLONE_ID', + 'value': clone.id.toString() }) env.push({ - "name": "START_MODE", - "value": clone.mode + 'name': 'START_MODE', + 'value': clone.mode }) env.push({ - "name": "RUN_AS_TEAM", - "value": clone.runAsTeam.toString() + 'name': 'RUN_AS_TEAM', + 'value': clone.runAsTeam.toString() }) env.push({ - "name": "USER_LOGGED_IN", - "value": clone.userLoggedIn + 'name': 'USER_LOGGED_IN', + 'value': clone.userLoggedIn }) env.push({ - "name": "PROCESS", - "value": clone.processName + 'name': 'PROCESS', + 'value': clone.processName }) - logger.debug("createClone Trading Configuration.") - if(clone.botType === TRADER ){ + logger.debug('createClone Trading Configuration.') + if (clone.botType === TRADER) { env.push({ - "name": "RESUME_EXECUTION", - "value": clone.resumeExecution.toString() + 'name': 'RESUME_EXECUTION', + 'value': clone.resumeExecution.toString() }) - if(clone.mode === BACKTEST){ + if (clone.mode === BACKTEST) { env.push({ - "name": "BEGIN_DATE_TIME", - "value": toPlatformDatetime(clone.beginDatetime) + 'name': 'BEGIN_DATE_TIME', + 'value': toPlatformDatetime(clone.beginDatetime) }) env.push({ - "name": "END_DATE_TIME", - "value": toPlatformDatetime(clone.endDatetime) + 'name': 'END_DATE_TIME', + 'value': toPlatformDatetime(clone.endDatetime) }) env.push({ - "name": "WAIT_TIME", - "value": clone.waitTime.toString() + 'name': 'WAIT_TIME', + 'value': clone.waitTime.toString() + }) + } else { + env.push({ + 'name': 'KEY_ID', + 'value': clone.keyId + }) + } + } else if (clone.botType === INDICATOR || clone.botType === EXTRACTION) { + if (clone.mode !== NO_TIME) { + env.push({ + 'name': 'MIN_YEAR', + 'value': isDefined(clone.startYear) ? clone.startYear.toString() : '' + }) + env.push({ + 'name': 'MAX_YEAR', + 'value': isDefined(clone.endYear) ? clone.endYear.toString() : '' + }) + env.push({ + 'name': 'MONTH', + 'value': isDefined(clone.month) ? clone.month.toString() : '' + }) + env.push({ + 'name': 'INTERVAL', + 'value': isDefined(clone.interval) ? clone.interval.toString() : '' }) } - } else if(clone.botType === INDICATOR || clone.botType === EXTRACTION ){ - if(clone.mode !== NO_TIME){ - env.push({ - "name": "MIN_YEAR", - "value": isDefined(clone.startYear) ? clone.startYear.toString() : '' - }) - env.push({ - "name": "MAX_YEAR", - "value": isDefined(clone.endYear) ? clone.endYear.toString() : '' - }) - env.push({ - "name": "MONTH", - "value": isDefined(clone.month) ? clone.month.toString() : '' - }) - env.push({ - "name": "INTERVAL", - "value": isDefined(clone.interval) ? clone.interval.toString() : '' - }) - } } deploymentManifest.spec.template.spec.containers[0].env = env - const create = await client.apis.batch.v1.namespaces('default').jobs.post( + await client.apis.batch.v1.namespaces('default').jobs.post( { body: deploymentManifest }) - logger.debug("createClone %s on Kubernates success.", clone.id) + logger.debug('createClone %s on Kubernates success.', clone.id) } catch (err) { - throw new KubernateError(err) + throw new KubernateError(err) } } export default createClone diff --git a/server/src/kubernetes/getClonePodLogs.js b/server/src/kubernetes/getClonePodLogs.js index 9730f300c..5367bfdd8 100644 --- a/server/src/kubernetes/getClonePodLogs.js +++ b/server/src/kubernetes/getClonePodLogs.js @@ -4,31 +4,31 @@ import { Client, config } from 'kubernetes-client' const getClonePodLogs = async (cloneName) => { try { - logger.debug("getClonePodLogs on kubernates started.") + logger.debug('getClonePodLogs on kubernates started.') const client = new Client({config: config.fromKubeconfig(), version: '1.9'}) let query = { - "qs":{ - "labelSelector": "job-name="+cloneName + 'qs': { + 'labelSelector': 'job-name=' + cloneName } } const pod = await client.api.v1.namespaces('default').pods.get(query) let queryLogs = { - "qs":{ - "tailLines": "20" + 'qs': { + 'tailLines': '20' } } const logs = await client.api.v1.namespaces('default') .pods(pod.body.items[0].metadata.name).log.get(queryLogs) let logsArray = logs.body.split('\n') - logger.debug("getClonePodLogs on kubernates successful.") + logger.debug('getClonePodLogs on kubernates successful.') return JSON.stringify(logsArray, null, 2) } catch (err) { - throw new KubernateError(err) + throw new KubernateError(err) } } export default getClonePodLogs diff --git a/server/src/kubernetes/getClonePodStatus.js b/server/src/kubernetes/getClonePodStatus.js index e0abbea96..957cf49ed 100644 --- a/server/src/kubernetes/getClonePodStatus.js +++ b/server/src/kubernetes/getClonePodStatus.js @@ -4,12 +4,12 @@ import { Client, config } from 'kubernetes-client' const getClonePodStatus = async (cloneName) => { try { - logger.debug("getClonePodStatus on kubernates started. ") + logger.debug('getClonePodStatus on kubernates started. ') const client = new Client({config: config.fromKubeconfig(), version: '1.9'}) let query = { - "qs":{ - "labelSelector": "job-name="+cloneName + 'qs': { + 'labelSelector': 'job-name=' + cloneName } } @@ -21,10 +21,10 @@ const getClonePodStatus = async (cloneName) => { && clonePodStatus.terminated.hasOwnProperty('containerID')) { delete clonePodStatus.terminated.containerID } - logger.debug("getClonePodStatus %s on kubernates successful", cloneName) + logger.debug('getClonePodStatus %s on kubernates successful', cloneName) return JSON.stringify(clonePodStatus, null, 2) } catch (err) { - throw new KubernateError(err) + throw new KubernateError(err) } } export default getClonePodStatus diff --git a/server/src/kubernetes/removeClone.js b/server/src/kubernetes/removeClone.js index 5af470b47..8bac6a3fa 100644 --- a/server/src/kubernetes/removeClone.js +++ b/server/src/kubernetes/removeClone.js @@ -4,25 +4,23 @@ import { Client, config } from 'kubernetes-client' const removeClone = async (clone) => { try { - logger.debug("removeClone %s", clone.id) + logger.debug('removeClone %s', clone.id) const client = new Client({config: config.fromKubeconfig(), version: '1.9'}) let query = { - "qs":{ - "labelSelector": "job-name=" + clone.id + 'qs': { + 'labelSelector': 'job-name=' + clone.id } } - const removed = await client.apis.batch.v1.namespaces('default').jobs( - clone.id).delete() + await client.apis.batch.v1.namespaces('default').jobs(clone.id).delete() const pod = await client.api.v1.namespaces('default').pods.get(query) - const podRemoved = await client.api.v1.namespaces('default') - .pods(pod.body.items[0].metadata.name).delete() + await client.api.v1.namespaces('default').pods(pod.body.items[0].metadata.name).delete() - logger.debug("removeClone %s on kubernates succesful", clone.id) + logger.debug('removeClone %s on kubernates succesful', clone.id) } catch (err) { - throw new KubernateError(err) + throw new KubernateError(err) } } export default removeClone diff --git a/server/src/models/clone.js b/server/src/models/clone.js index e69df8262..d51d3a10a 100644 --- a/server/src/models/clone.js +++ b/server/src/models/clone.js @@ -2,31 +2,32 @@ import mongoose, { Schema } from 'mongoose' import { UNPUBLISHED, - CloneStateEnum, -} from '../enums/CloneState'; + CloneStateEnum +} from '../enums/CloneState' import { BACKTEST, - CloneModeEnum, -} from '../enums/CloneMode'; + CloneModeEnum +} from '../enums/CloneMode' const cloneSchema = new Schema({ authId: { type: String, - required: true, + required: true }, teamId: { - type: String, - required: true, + type: String, + required: true }, botId: { - type: String, - required: true, + type: String, + required: true }, + keyId: String, mode: { type: String, enum: CloneModeEnum, - default: BACKTEST, + default: BACKTEST }, resumeExecution: Boolean, beginDatetime: Number, @@ -35,7 +36,7 @@ const cloneSchema = new Schema({ state: { type: String, enum: CloneStateEnum, - default: UNPUBLISHED, + default: UNPUBLISHED }, stateDatetime: Number, createDatetime: Number, @@ -51,7 +52,7 @@ const cloneSchema = new Schema({ assetB: String, processName: { type: String, - required: true, + required: true } }) diff --git a/server/src/schema/cloneDetails.js b/server/src/schema/cloneDetails.js index 5ac7ba13b..b8cab3c23 100644 --- a/server/src/schema/cloneDetails.js +++ b/server/src/schema/cloneDetails.js @@ -2,11 +2,11 @@ import logger from '../config/logger' import { isDefined } from '../config/utils' import { AutorizationError } from '../errors' -const cloneDetails = async(authId, team, clone) => { - logger.debug('Retrieving clone details.') +const cloneDetails = (authId, team, clone) => { + logger.debug('cloneDetails -> Entering function.') - if(!(authId === (process.env.AUTH_CLIENT_ID + '@clients') || isAuthorized(team, authId))){ - logger.debug('User %s is not authorized to manage team %s.', authId, team.slug ) + if (!(authId === (process.env.AUTH_CLIENT_ID + '@clients') || isAuthorized(team, authId))) { + logger.debug('User %s is not authorized to manage team %s.', authId, team.slug) throw new AutorizationError() } @@ -20,29 +20,29 @@ const cloneDetails = async(authId, team, clone) => { clone.botName = selectedBot.name clone.botAvatar = selectedBot.avatar clone.teamAvatar = team.profile.avatar - clone.userLoggedIn = team.members[0].member.alias //TODO change by context info if possible + clone.userLoggedIn = team.members[0].member.alias // TODO change by context info if possible - logger.debug('Retrieving clone details complete.') + logger.debug('cloneDetails -> Retrieving clone details complete.') return clone -}; +} -function getSelectedBot(team, selectedBotId){ - logger.debug('Getting selected bot.') - if(isDefined(team)){ +function getSelectedBot (team, selectedBotId) { + logger.debug('cloneDetails -> Getting selected bot.') + if (isDefined(team)) { for (var i = 0; i < team.fb.length; i++) { - if(team.fb[i].id === selectedBotId){ + if (team.fb[i].id === selectedBotId) { return team.fb[i] } } } } -function isAuthorized(team, authId){ - logger.debug('Checking if the user is authorized by the teams module.') +function isAuthorized (team, authId) { + logger.debug('cloneDetails -> Checking if the user is authorized by the teams module.') let authorized = false - if(isDefined(team)){ + if (isDefined(team)) { for (var i = 0; i < team.members.length; i++) { - if(team.members[i].member.authId === authId){ + if (team.members[i].member.authId === authId) { authorized = true break } diff --git a/server/src/schema/index.js b/server/src/schema/index.js index 4155e4999..fe0cc23fd 100644 --- a/server/src/schema/index.js +++ b/server/src/schema/index.js @@ -1,7 +1,4 @@ -import { - GraphQLSchema -} from 'graphql' - +import { GraphQLSchema } from 'graphql' import Mutation from './mutations' import RootQuery from './queries' diff --git a/server/src/schema/mutations/AddCloneMutation.js b/server/src/schema/mutations/AddCloneMutation.js index a0f9db02e..76381ca74 100644 --- a/server/src/schema/mutations/AddCloneMutation.js +++ b/server/src/schema/mutations/AddCloneMutation.js @@ -1,23 +1,24 @@ -import { CloneInputType } from '../types/input'; -import { CloneType } from '../types'; -import { Clone } from '../../models'; -import { CloneModeEnum } from '../../enums/CloneMode'; -import { BotTypesEnum } from '../../enums/BotTypes'; +import { CloneInputType } from '../types/input' +import { CloneType } from '../types' +import { Clone } from '../../models' +import { CloneModeEnum } from '../../enums/CloneMode' +import { BotTypesEnum } from '../../enums/BotTypes' import teamQuery from '../../graphQLCalls/teamQuery' +import authorizeClone from '../../graphQLCalls/authorizeClone' import cloneDetails from '../cloneDetails' - import { AuthentificationError, WrongArgumentsError, - OperationsError + OperationsError, + AutorizationError } from '../../errors' - import logger from '../../config/logger' import createKubernetesClone from '../../kubernetes/createClone' import { isDefined } from '../../config/utils' +import { LIVE } from '../../enums/CloneMode' const args = { - clone: {type: CloneInputType } + clone: { type: CloneInputType } } const resolve = async(parent, { clone }, context) => { @@ -27,46 +28,50 @@ const resolve = async(parent, { clone }, context) => { throw new AuthentificationError() } - if(!Object.values(CloneModeEnum).includes(clone.mode)){ + if (!Object.values(CloneModeEnum).includes(clone.mode)) { throw new WrongArgumentsError('The mode selected is not valid.') } - if(!Object.values(BotTypesEnum).includes(clone.botType)){ + if (!Object.values(BotTypesEnum).includes(clone.botType)) { throw new WrongArgumentsError('The bot type selected is not valid.') } - try{ + if (clone.mode === LIVE && !isDefined(clone.keyId)) { + throw new WrongArgumentsError('The key was not provided to run the clone in Live mode.') + } + + try { let team = await teamQuery(context.authorization, clone.teamId) clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone) - clone.createDatetime = new Date().valueOf() / 1000|0 + clone.createDatetime = new Date().valueOf() / 1000 | 0 clone.active = true - logger.debug('addClone -> Creating a new clone.') let newClone = new Clone(clone) newClone.authId = context.userId clone.id = newClone._id - await createKubernetesClone(clone) - return new Promise((resolve, reject) => { - newClone.save((err) => { - if (err){ - logger.error('addClone -> Error: %s', err.stack) - reject('There has been an error storing the clone.') - } - else { - //TODO transaction on database - logger.debug('addClone -> Save clone sucessful.') - resolve(newClone) - } - }) - }) - } catch(err) { + logger.debug('addClone -> Creating the clone on the Database.') + let savedClone = await newClone.save() + + if (clone.mode === LIVE) { + logger.debug('addClone -> Authorizing clone to use the key.') + let response = await authorizeClone(context.authorization, clone.keyId, clone.id, false) + logger.debug('addClone -> Authorizing clone to use the key.') + if (response.data.data.keyVault_AuthorizeClone === clone.keyId) { + await createKubernetesClone(clone) + } else { + throw new AutorizationError() + } + } + logger.debug('addClone -> Clone created sucessfully.') + return savedClone + } catch (err) { logger.error('addClone -> Error: %s', err.stack) throw new OperationsError('There has been an error creating the clone.') } } -const mutation = { +const AddCloneMutation = { addClone: { type: CloneType, args, @@ -74,4 +79,4 @@ const mutation = { } } -export default mutation +export default AddCloneMutation diff --git a/server/src/schema/mutations/RemoveCloneMutation.js b/server/src/schema/mutations/RemoveCloneMutation.js index 2efa137c0..694f37c15 100644 --- a/server/src/schema/mutations/RemoveCloneMutation.js +++ b/server/src/schema/mutations/RemoveCloneMutation.js @@ -1,14 +1,5 @@ -import { - GraphQLNonNull, - GraphQLID, - GraphQLString -} from 'graphql' - -import { - AuthentificationError, - OperationsError -} from '../../errors' - +import { GraphQLNonNull, GraphQLID, GraphQLString } from 'graphql' +import { AuthentificationError, OperationsError } from '../../errors' import { Clone } from '../../models' import logger from '../../config/logger' import removeKuberneteClone from '../../kubernetes/removeClone' @@ -33,13 +24,16 @@ const resolve = async (parent, { id }, context) => { active: true }) - if(!isDefined(clone)){ + if (!isDefined(clone)) { throw new OperationsError('You are not authorized to remove this clone.') } let team = await teamQuery(context.authorization, clone.teamId) clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone) + logger.debug('removeClone -> Release the clone key.') + await authorizeClone(context.authorization, clone.keyId, clone.id, true) + logger.debug('removeClone -> Removing Clone from Kubernates.') await removeKuberneteClone(clone) @@ -51,17 +45,17 @@ const resolve = async (parent, { id }, context) => { const update = { active: false } Clone.findOneAndUpdate(query, update, options, (err, doc) => { - if (err){ + if (err) { logger.error('removeClone -> Error removing clone from the DB. %s', err.stack) throw new OperationsError(err) - }else{ + } else { logger.debug('removeClone -> Clone Removed from the DB.') - return('Clone Removed.') + return ('Clone Removed.') } }) } -const mutation = { +const RemoveCloneMutation = { removeClone: { type: GraphQLString, args, @@ -69,4 +63,4 @@ const mutation = { } } -export default mutation +export default RemoveCloneMutation diff --git a/server/src/schema/mutations/UpdateExecutionSummary.js b/server/src/schema/mutations/UpdateExecutionSummary.js index 1c889198d..63b2d6fb1 100644 --- a/server/src/schema/mutations/UpdateExecutionSummary.js +++ b/server/src/schema/mutations/UpdateExecutionSummary.js @@ -5,16 +5,11 @@ import { GraphQLInt, GraphQLFloat } from 'graphql' - -import { - OperationsError -} from '../../errors' - +import { OperationsError } from '../../errors' import { Clone } from '../../models' import logger from '../../config/logger' import teamQuery from '../../graphQLCalls/teamQuery' import cloneDetails from '../cloneDetails' -import removeKuberneteClone from '../../kubernetes/removeClone' import { isDefined } from '../../config/utils' const args = { @@ -33,31 +28,27 @@ const resolve = async (parent, { id, summaryDate, buyAverage, sellAverage, marketRate, combinedProfitsA, combinedProfitsB, assetA, assetB }, context) => { - logger.debug('UpdateExecutionSummary -> Entering Function.') if (!context.userId) { throw new AuthentificationError() } - try{ + try { let sucessful - let clone = await Clone.findOne( { + let clone = await Clone.findOne({ _id: id, active: true }) - if(!isDefined(clone)){ - return "Clone not found." + if (!isDefined(clone)) { + return 'Clone not found.' } let team = await teamQuery(context.authorization, clone.teamId) clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone) - logger.debug('UpdateExecutionSummary -> Removing Clone from Kubernates.') - await removeKuberneteClone(clone) - const query = { _id: id } const options = { new: true } const update = { @@ -74,7 +65,7 @@ const resolve = async (parent, logger.debug('UpdateExecutionSummary -> Updating clone on database.') await Clone.update(query, update, options, (err, clone) => { - if (err){ + if (err) { logger.error('Error updating execution summary on the database. %s', err.stack) throw err } else { @@ -83,16 +74,16 @@ const resolve = async (parent, } }) - if(sucessful) + if (sucessful) { return 'Execution summary updated.' - + } } catch (error) { logger.error('Error updating the execution summary. %s', error.stack) throw new OperationsError(error.message) } } -const mutation = { +const UpdateExecutionSummary = { updateExecutionSummary: { type: GraphQLString, args, @@ -100,4 +91,4 @@ const mutation = { } } -export default mutation +export default UpdateExecutionSummary diff --git a/server/src/schema/mutations/index.js b/server/src/schema/mutations/index.js index b5aa00205..74c316ea8 100644 --- a/server/src/schema/mutations/index.js +++ b/server/src/schema/mutations/index.js @@ -1,7 +1,4 @@ -import { - GraphQLObjectType -} from 'graphql' - +import { GraphQLObjectType } from 'graphql' import AddCloneMutation from './AddCloneMutation' import RemoveCloneMutation from './RemoveCloneMutation' import UpdateExecutionSummary from './UpdateExecutionSummary' diff --git a/server/src/schema/queries/GetClones.js b/server/src/schema/queries/GetClones.js index 7125edc7b..0c6616d90 100644 --- a/server/src/schema/queries/GetClones.js +++ b/server/src/schema/queries/GetClones.js @@ -1,12 +1,5 @@ -import { - GraphQLList, - GraphQLID -} from 'graphql' - -import { - OperationsError -} from '../../errors' - +import { GraphQLList, GraphQLID } from 'graphql' +import { OperationsError } from '../../errors' import { GetClonesType } from '../types' import { Clone } from '../../models' import logger from '../../config/logger' @@ -18,43 +11,41 @@ const args = { } const resolve = async(parent, { cloneIdList }, context) => { - logger.debug('Get Clones -> Entering Fuction. %j', cloneIdList) - try{ - let clones = [] - for (var i = 0; i < cloneIdList.length; i++) { + logger.debug('Get Clones -> Entering Fuction.') + try { + let clones = [] + for (var i = 0; i < cloneIdList.length; i++) { + if (mongoose.Types.ObjectId.isValid(cloneIdList[i])) { + let existingClone = await Clone.findOne({ + _id: cloneIdList[i] + }) - if(mongoose.Types.ObjectId.isValid(cloneIdList[i])){ - let existingClone = await Clone.findOne({ - _id: cloneIdList[i] - }) + if (isDefined(existingClone)) { + clones.push({ + id: cloneIdList[i], + teamId: existingClone.teamId, + botId: existingClone.botId + }) + } else { + clones.push({ + id: cloneIdList[i] + }) + } + } else { + clones.push({ + id: cloneIdList[i] + }) + } + } - if(isDefined(existingClone)){ - clones.push({ - id: cloneIdList[i], - teamId: existingClone.teamId, - botId: existingClone.botId - }) - }else{ - clones.push({ - id: cloneIdList[i] - }) - } - } else { - clones.push({ - id: cloneIdList[i] - }) - } - - } - - return clones - } catch (err){ + return clones + } catch (err) { logger.error('Get Clones error: %s', err.stack) throw new OperationsError('There has been an error getting the clones.') - } + } } -const query = { +const GetClones = { getClones: { type: new GraphQLList(GetClonesType), args, @@ -62,4 +53,4 @@ const query = { } } -export default query +export default GetClones diff --git a/server/src/schema/queries/HistoryClones.js b/server/src/schema/queries/HistoryClones.js index bdf853f3c..23bcd6d2f 100644 --- a/server/src/schema/queries/HistoryClones.js +++ b/server/src/schema/queries/HistoryClones.js @@ -1,17 +1,8 @@ -import { - GraphQLList -} from 'graphql' - -import { - AuthentificationError, - OperationsError -} from '../../errors' - +import { GraphQLList } from 'graphql' +import { AuthentificationError, OperationsError } from '../../errors' import { CloneType } from '../types' import { Clone } from '../../models' import logger from '../../config/logger' -import getKuberneteClonePodStatus from '../../kubernetes/getClonePodStatus' -import getKuberneteClonePodLogs from '../../kubernetes/getClonePodLogs' import cloneDetails from '../cloneDetails' import teamQuery from '../../graphQLCalls/teamQuery' @@ -19,30 +10,30 @@ const args = {} const resolve = async(parent, args, context) => { logger.debug('Retrieving History Clones.') - try{ - if (!context.userId) { - throw new AuthentificationError() - } + try { + if (!context.userId) { + throw new AuthentificationError() + } - let clones = await Clone.find({ - authId: context.userId, - active: false - }).sort({createDatetime: -1}) + let clones = await Clone.find({ + authId: context.userId, + active: false + }).sort({createDatetime: -1}) - for (var i = 0; i < clones.length; i++) { + for (var i = 0; i < clones.length; i++) { let team = await teamQuery(context.authorization, clones[i].teamId) clones[i] = await cloneDetails(context.userId, team.data.data.teams_TeamById, clones[i]) clones[i].botType = clones[i].kind // Only for listing we show the teams value - } + } - return clones - } catch (err){ - logger.error('Retrieving History Clones error: %s', err.stack) - throw new OperationsError('There has been an error retrieving history clones.') - } + return clones + } catch (err) { + logger.error('Retrieving History Clones error: %s', err.stack) + throw new OperationsError('There has been an error retrieving history clones.') + } } -const query = { +const HistoryClones = { historyClones: { type: new GraphQLList(CloneType), args, @@ -50,4 +41,4 @@ const query = { } } -export default query +export default HistoryClones diff --git a/server/src/schema/queries/ListClones.js b/server/src/schema/queries/ListClones.js index 9e80b9aec..b36a2b875 100644 --- a/server/src/schema/queries/ListClones.js +++ b/server/src/schema/queries/ListClones.js @@ -1,12 +1,5 @@ -import { - GraphQLList -} from 'graphql' - -import { - AuthentificationError, - OperationsError -} from '../../errors' - +import { GraphQLList } from 'graphql' +import { AuthentificationError, OperationsError } from '../../errors' import { CloneType } from '../types' import { Clone } from '../../models' import logger from '../../config/logger' @@ -19,33 +12,33 @@ const args = {} const resolve = async(parent, args, context) => { logger.debug('List Clones -> Entering Fuction.') - try{ - if (!context.userId) { - throw new AuthentificationError() - } + try { + if (!context.userId) { + throw new AuthentificationError() + } - let clones = await Clone.find({ - authId: context.userId, - active: true - }).sort({createDatetime: -1}) + let clones = await Clone.find({ + authId: context.userId, + active: true + }).sort({createDatetime: -1}) - for (var i = 0; i < clones.length; i++) { + for (var i = 0; i < clones.length; i++) { let team = await teamQuery(context.authorization, clones[i].teamId) clones[i] = await cloneDetails(context.userId, team.data.data.teams_TeamById, clones[i]) let state = await getCloneStatus(clones[i].id) - clones[i].state = state.substring(1, state.length-1) + clones[i].state = state.substring(1, state.length - 1) let lastLogs = await getCloneLogs(clones[i].id) - clones[i].lastLogs = lastLogs.substring(1, lastLogs.length-1) + clones[i].lastLogs = lastLogs.substring(1, lastLogs.length - 1) clones[i].botType = clones[i].kind // Only for listing we show the teams value - } - return clones - } catch (err){ + } + return clones + } catch (err) { logger.error('List Clones error: %s', err.stack) throw new OperationsError('There has been an error listing the clones.') - } + } } -const query = { +const ListClones = { clones: { type: new GraphQLList(CloneType), args, @@ -53,4 +46,4 @@ const query = { } } -export default query +export default ListClones diff --git a/server/src/schema/queries/index.js b/server/src/schema/queries/index.js index bdf6ff629..b7d1de155 100644 --- a/server/src/schema/queries/index.js +++ b/server/src/schema/queries/index.js @@ -1,7 +1,4 @@ -import { - GraphQLObjectType -} from 'graphql' - +import { GraphQLObjectType } from 'graphql' import ListClones from './ListClones' import HistoryClones from './HistoryClones' import GetClones from './GetClones' diff --git a/server/src/schema/types/CloneType.js b/server/src/schema/types/CloneType.js index dfcd10a68..e06819625 100644 --- a/server/src/schema/types/CloneType.js +++ b/server/src/schema/types/CloneType.js @@ -37,7 +37,8 @@ const CloneType = new GraphQLObjectType({ teamName: {type: GraphQLString}, botName: {type: GraphQLString}, botAvatar: {type: GraphQLString}, - teamAvatar: {type: GraphQLString} + teamAvatar: {type: GraphQLString}, + keyId: {type: GraphQLString} }) }) export default CloneType diff --git a/server/src/schema/types/GetClonesType.js b/server/src/schema/types/GetClonesType.js index f3bdebe35..df24d0502 100644 --- a/server/src/schema/types/GetClonesType.js +++ b/server/src/schema/types/GetClonesType.js @@ -1,7 +1,4 @@ -import { - GraphQLObjectType, - GraphQLID -} from 'graphql' +import { GraphQLObjectType, GraphQLID } from 'graphql' const GetClonesType = new GraphQLObjectType({ name: 'GetClones', diff --git a/server/src/schema/types/input/Clone.js b/server/src/schema/types/input/Clone.js index a4a6d95ec..509ea9af5 100644 --- a/server/src/schema/types/input/Clone.js +++ b/server/src/schema/types/input/Clone.js @@ -4,7 +4,7 @@ import { GraphQLInputObjectType, GraphQLBoolean, GraphQLNonNull -} from 'graphql'; +} from 'graphql' const Type = new GraphQLInputObjectType({ name: 'CloneInput', @@ -23,8 +23,9 @@ const Type = new GraphQLInputObjectType({ month: { type: GraphQLInt }, interval: { type: GraphQLInt }, processName: { type: new GraphQLNonNull(GraphQLString) }, - botType: { type: new GraphQLNonNull(GraphQLString) } - }) -}); + botType: { type: new GraphQLNonNull(GraphQLString) }, + keyId: { type: GraphQLString } + }) +}) -export default Type; +export default Type diff --git a/server/src/schema/types/input/index.js b/server/src/schema/types/input/index.js index e51b0ca74..5c39e7316 100644 --- a/server/src/schema/types/input/index.js +++ b/server/src/schema/types/input/index.js @@ -2,4 +2,4 @@ import CloneInputType from './Clone' export { CloneInputType -}; +}