diff --git a/client/package.json b/client/package.json
index 55e914360..c0a9f35e9 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@superalgos/operations-client",
- "version": "0.0.6",
+ "version": "0.0.7",
"description": "Superalgos Operations client-side web app",
"main": "src/index.js",
"dependencies": {
diff --git a/client/src/views/Clone/Add/index.js b/client/src/views/Clone/Add/index.js
index b24d35a0c..06781d9ad 100644
--- a/client/src/views/Clone/Add/index.js
+++ b/client/src/views/Clone/Add/index.js
@@ -157,7 +157,6 @@ class AddClone extends Component {
{this.state.selectedBot.kind}
- { /* TRADER BOT */ }
{ this.state.selectedBot.kind === "TRADER" &&
@@ -213,6 +212,10 @@ class AddClone extends Component {
fullWidth
/>
+
+ The Wait Time represent the number of miliseconds the bot will wait between executions.
+
+
}
- { /* INDICATOR AND EXTRACTOR BOTS */ }
{ (this.state.selectedBot.kind === "INDICATOR"
|| this.state.selectedBot.kind === "EXTRACTOR") &&
@@ -366,6 +368,11 @@ class AddClone extends Component {
}
+
+
+ You will your clone information under Active Clones until it finishes the execution, then it will moved to the History.
+
+
diff --git a/client/src/views/Home.js b/client/src/views/Home.js
index 2e2de92b5..766c931a2 100644
--- a/client/src/views/Home.js
+++ b/client/src/views/Home.js
@@ -24,13 +24,13 @@ class Home extends Component {
- The Operations module allows you to create copies of your bot
+ The Operations module allows you to create instances of your bots
that will be executed on a virtual machine.
-
+
diff --git a/server/src/config/clone-deployment.json b/server/src/config/clone-deployment.json
index 4b202ce6b..bc90901a1 100644
--- a/server/src/config/clone-deployment.json
+++ b/server/src/config/clone-deployment.json
@@ -14,7 +14,7 @@
"containers": [
{
"name": "aadev",
- "image": "benme/aadev:v3.5",
+ "image": "benme/aadev:v3.6",
"command": ["node", "Run.js"],
"env": [
]
diff --git a/server/src/config/utils.js b/server/src/config/utils.js
index 257881ebc..11f9909fa 100644
--- a/server/src/config/utils.js
+++ b/server/src/config/utils.js
@@ -7,17 +7,3 @@ export function toPlatformDatetime (epoch) {
export function isDefined (d) {
return d !== null && typeof d !== 'undefined'
}
-
-export function getJobNameFromClone (clone) {
- return clone.teamSlug + '-' + clone.botSlug + '-' + clone.mode.toLowerCase()
-}
-
-export function getSelectedBot(botsByUser, selectedBotId){
- if(isDefined(botsByUser)){
- for (var i = 0; i < botsByUser.fb.length; i++) {
- if(botsByUser.fb[i].id === selectedBotId){
- return botsByUser.fb[i]
- }
- }
- }
-}
diff --git a/server/src/errors/index.js b/server/src/errors/index.js
index b8fb06cf4..63b27a61a 100644
--- a/server/src/errors/index.js
+++ b/server/src/errors/index.js
@@ -2,7 +2,15 @@ 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'
+ message = 'Autentification not found, you have to be authentificated to perform this action.'
+ constructor(){
+ super()
+ }
+}
+
+export class AutorizationError extends Error {
+ code = 401
+ message = 'You are not authorized to perform this action.'
constructor(){
super()
}
diff --git a/server/src/graphQLCalls/teamAvatar.js b/server/src/graphQLCalls/teamAvatar.js
deleted file mode 100644
index c2ba09a3f..000000000
--- a/server/src/graphQLCalls/teamAvatar.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import logger from '../config/logger'
-import axios from 'axios'
-
-const teamAvatar = async(authorization, teamId) => {
- logger.debug('GraphQL call teamAvatar.')
-
- return axios({
- url: process.env.GATEWAY_ENDPOINT,
- method: 'post',
- data: {
- query: `
- query Teams_Team($teamId: String!){
- teams_TeamById(teamId:$teamId) {
- profile{
- avatar
- }
- }
- }
- `,
- variables: {
- teamId: teamId
- }
- },
- headers: {
- authorization: authorization
- }
- })
-};
-
-export default teamAvatar
diff --git a/server/src/graphQLCalls/teams_FbByTeamMember.js b/server/src/graphQLCalls/teamQuery.js
similarity index 59%
rename from server/src/graphQLCalls/teams_FbByTeamMember.js
rename to server/src/graphQLCalls/teamQuery.js
index 112e95790..c42c1722a 100644
--- a/server/src/graphQLCalls/teams_FbByTeamMember.js
+++ b/server/src/graphQLCalls/teamQuery.js
@@ -1,16 +1,16 @@
import logger from '../config/logger'
import axios from 'axios'
-const teams_FbByTeamMember = (authorization) => {
- logger.debug('GraphQL call teams_FbByTeamMember')
+const teamQuery = async(authorization, teamId) => {
+ logger.debug('GraphQL retrieving team information. %s', teamId)
return axios({
url: process.env.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
- query Teams_FbByTeamMember {
- teams_FbByTeamMember {
+ query Teams_Team($teamId: String!){
+ teams_TeamById(teamId:$teamId) {
id
name
slug
@@ -24,11 +24,18 @@ const teams_FbByTeamMember = (authorization) => {
members {
member {
alias
+ authId
}
}
+ profile{
+ avatar
+ }
}
}
`,
+ variables: {
+ teamId: teamId
+ }
},
headers: {
authorization: authorization
@@ -36,4 +43,4 @@ const teams_FbByTeamMember = (authorization) => {
})
};
-export default teams_FbByTeamMember
+export default teamQuery
diff --git a/server/src/schema/cloneDetails.js b/server/src/schema/cloneDetails.js
index 040ce1a7d..56d2d5f93 100644
--- a/server/src/schema/cloneDetails.js
+++ b/server/src/schema/cloneDetails.js
@@ -1,27 +1,55 @@
import logger from '../config/logger'
-import { getJobNameFromClone, getSelectedBot } from '../config/utils'
-import teamAvatar from '../graphQLCalls/teamAvatar'
+import { isDefined } from '../config/utils'
+import { AutorizationError } from '../errors'
-// TODO Refactor this code once financial beings api is ready
-const cloneDetails = async(authorization, botsByUser, clone) => {
+const cloneDetails = async(authId, team, clone) => {
logger.debug('Retrieving clone details.')
- let selectedBot = getSelectedBot(botsByUser.data.data.teams_FbByTeamMember, clone.botId)
- clone.teamId = botsByUser.data.data.teams_FbByTeamMember.id
+ if(!isAuthorized(team, authId)){
+ logger.debug('User %s is not authorized to manage team %s.', authId, team.slug )
+ throw new AutorizationError()
+ }
+
+ let selectedBot = getSelectedBot(team, clone.botId)
+ clone.teamId = team.id
clone.botId = selectedBot.id
clone.kind = selectedBot.kind
- clone.teamSlug = botsByUser.data.data.teams_FbByTeamMember.slug
+ clone.teamSlug = team.slug
clone.botSlug = selectedBot.slug
- clone.cloneName = getJobNameFromClone(clone)
- clone.teamName = botsByUser.data.data.teams_FbByTeamMember.name
+ clone.cloneName = clone.teamSlug + '-' + clone.botSlug + '-' + clone.mode.toLowerCase()
+ clone.teamName = team.name
clone.botName = selectedBot.name
clone.botAvatar = selectedBot.avatar
- let team = await teamAvatar(authorization, botsByUser.data.data.teams_FbByTeamMember.id)
- clone.teamAvatar = team.data.data.teams_TeamById.profile.avatar
- clone.userLoggedIn = botsByUser.data.data.teams_FbByTeamMember.members[0].member.alias //TODO change by context info if possible
+ clone.teamAvatar = team.profile.avatar
+ clone.userLoggedIn = team.members[0].member.alias //TODO change by context info if possible
logger.debug('Retrieving clone details complete.')
return clone
};
+function getSelectedBot(team, selectedBotId){
+ logger.debug('Getting selected bot.')
+ if(isDefined(team)){
+ for (var i = 0; i < team.fb.length; i++) {
+ 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.')
+ let authorized = false
+ if(isDefined(team)){
+ for (var i = 0; i < team.members.length; i++) {
+ if(team.members[i].member.authId === authId){
+ authorized = true
+ break
+ }
+ }
+ }
+ return authorized
+}
+
export default cloneDetails
diff --git a/server/src/schema/mutations/AddCloneMutation.js b/server/src/schema/mutations/AddCloneMutation.js
index d6f703ae5..dd14e931e 100644
--- a/server/src/schema/mutations/AddCloneMutation.js
+++ b/server/src/schema/mutations/AddCloneMutation.js
@@ -3,7 +3,7 @@ import { CloneType } from '../types';
import { Clone } from '../../models';
import { CloneModeEnum } from '../../enums/CloneMode';
import { BotTypesEnum } from '../../enums/BotTypes';
-import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember';
+import teamQuery from '../../graphQLCalls/teamQuery'
import cloneDetails from '../cloneDetails'
import {
@@ -14,7 +14,7 @@ import {
import logger from '../../config/logger'
import createKubernetesClone from '../../kubernetes/createClone'
-import { isDefined, getSelectedBot } from '../../config/utils'
+import { isDefined } from '../../config/utils'
const args = {
clone: {type: CloneInputType }
@@ -50,10 +50,8 @@ const resolve = async(parent, { clone }, context) => {
}
try{
- // Authorization is handled by the teams module
- let botsByUser = await teams_FbByTeamMember(context.authorization)
- clone = await cloneDetails(context.authorization, botsByUser, clone)
- let selectedBot = getSelectedBot(botsByUser.data.data.teams_FbByTeamMember, clone.botId)
+ let team = await teamQuery(context.authorization)
+ clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone)
clone.createDatetime = new Date().valueOf() / 1000|0
clone.active = true
diff --git a/server/src/schema/mutations/RemoveCloneMutation.js b/server/src/schema/mutations/RemoveCloneMutation.js
index 8d1afaf5e..9dc45173f 100644
--- a/server/src/schema/mutations/RemoveCloneMutation.js
+++ b/server/src/schema/mutations/RemoveCloneMutation.js
@@ -12,8 +12,8 @@ import {
import { Clone } from '../../models'
import logger from '../../config/logger'
import removeKuberneteClone from '../../kubernetes/removeClone'
-import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
-import { isDefined, getSelectedBot } from '../../config/utils'
+import teamQuery from '../../graphQLCalls/teamQuery'
+import { isDefined } from '../../config/utils'
import cloneDetails from '../cloneDetails'
const args = {
@@ -37,8 +37,8 @@ const resolve = async (parent, { id }, context) => {
throw new OperationsError('You are not authorized to remove this clone.')
}
- let botsByUser = await teams_FbByTeamMember(context.authorization)
- clone = await cloneDetails(context.authorization, botsByUser, clone)
+ let team = await teamQuery(context.authorization)
+ clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone)
logger.debug('removeClone -> Removing Clone from Kubernates.')
await removeKuberneteClone(clone)
diff --git a/server/src/schema/mutations/UpdateExecutionSummary.js b/server/src/schema/mutations/UpdateExecutionSummary.js
index b666b455c..235f84c41 100644
--- a/server/src/schema/mutations/UpdateExecutionSummary.js
+++ b/server/src/schema/mutations/UpdateExecutionSummary.js
@@ -7,12 +7,12 @@ import {
} from 'graphql'
import {
-
OperationsError
} from '../../errors'
import { Clone } from '../../models'
import logger from '../../config/logger'
+import teamQuery from '../../graphQLCalls/teamQuery'
const args = {
id: { type: new GraphQLNonNull(GraphQLID) },
@@ -29,34 +29,57 @@ const args = {
const resolve = async (parent,
{ id, summaryDate, buyAverage, sellAverage, marketRate, combinedProfitsA,
combinedProfitsB, assetA, assetB
- }) => {
+ }, context) => {
+
logger.debug('UpdateExecutionSummary -> Entering Function.')
- const query = { _id: id }
- const options = { new: true }
- const update = {
- summaryDate: summaryDate,
- buyAverage: buyAverage,
- sellAverage: sellAverage,
- marketRate: marketRate,
- combinedProfitsA: combinedProfitsA,
- combinedProfitsB: combinedProfitsB,
- assetA: assetA,
- assetB: assetB
+ if (!context.userId) {
+ throw new AuthentificationError()
}
- let sucessful
- await Clone.findOneAndUpdate(query, update, options, (err, doc) => {
- if (err){
- throw new OperationsError(err)
- } else {
- logger.debug('Execution summary updated')
- sucessful = true
- }
- })
+ try{
+ let sucessful
- if(sucessful){
- return 'Execution summary updated.'
+ let clone = await Clone.findOne( {
+ _id: id,
+ active: true
+ })
+
+ let team = await teamQuery(context.authorization)
+ clone = await cloneDetails(context.userId, team.data.data.teams_TeamById, clone)
+
+ logger.debug('removeClone -> Removing Clone from Kubernates.')
+ await removeKuberneteClone(clone)
+
+ const query = { _id: id }
+ const options = { new: true }
+ const update = {
+ summaryDate: summaryDate,
+ buyAverage: buyAverage,
+ sellAverage: sellAverage,
+ marketRate: marketRate,
+ combinedProfitsA: combinedProfitsA,
+ combinedProfitsB: combinedProfitsB,
+ assetA: assetA,
+ assetB: assetB
+ }
+
+ await Clone.update(query, update, (err) => {
+ if (err){
+ logger.error('Error updating execution summary on the database. %s', err.stack)
+ throw new OperationsError(err.message)
+ } else {
+ logger.debug('Execution summary updated.')
+ sucessful = true
+ }
+ })
+
+ if(sucessful){
+ return 'Execution summary updated.'
+ }
+ } catch (error) {
+ logger.error('Error updating the execution summary. %s', error.stack)
+ throw new OperationsError(error.message)
}
}
diff --git a/server/src/schema/queries/HistoryClones.js b/server/src/schema/queries/HistoryClones.js
index a37557ae7..bdf853f3c 100644
--- a/server/src/schema/queries/HistoryClones.js
+++ b/server/src/schema/queries/HistoryClones.js
@@ -3,7 +3,8 @@ import {
} from 'graphql'
import {
- AuthentificationError
+ AuthentificationError,
+ OperationsError
} from '../../errors'
import { CloneType } from '../types'
@@ -11,14 +12,14 @@ import { Clone } from '../../models'
import logger from '../../config/logger'
import getKuberneteClonePodStatus from '../../kubernetes/getClonePodStatus'
import getKuberneteClonePodLogs from '../../kubernetes/getClonePodLogs'
-import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
import cloneDetails from '../cloneDetails'
+import teamQuery from '../../graphQLCalls/teamQuery'
const args = {}
const resolve = async(parent, args, context) => {
- logger.debug('History Clones -> Entering Fuction.')
-
+ logger.debug('Retrieving History Clones.')
+ try{
if (!context.userId) {
throw new AuthentificationError()
}
@@ -26,18 +27,19 @@ const resolve = async(parent, args, context) => {
let clones = await Clone.find({
authId: context.userId,
active: false
- })
-
- // TODO Refactor this code once financial beings api is ready
- // Authorization is handled by the teams module
- let botsByUser = await teams_FbByTeamMember(context.authorization)
+ }).sort({createDatetime: -1})
for (var i = 0; i < clones.length; i++) {
- clones[i] = await cloneDetails(context.authorization, botsByUser, clones[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.')
+ }
}
const query = {
diff --git a/server/src/schema/queries/ListClones.js b/server/src/schema/queries/ListClones.js
index 74e0868b4..66d283e80 100644
--- a/server/src/schema/queries/ListClones.js
+++ b/server/src/schema/queries/ListClones.js
@@ -12,7 +12,6 @@ import { Clone } from '../../models'
import logger from '../../config/logger'
import getCloneStatus from '../../kubernetes/getClonePodStatus'
import getCloneLogs from '../../kubernetes/getClonePodLogs'
-import teams_FbByTeamMember from '../../graphQLCalls/teams_FbByTeamMember'
import cloneDetails from '../cloneDetails'
const args = {}
@@ -27,14 +26,11 @@ const resolve = async(parent, args, context) => {
let clones = await Clone.find({
authId: context.userId,
active: true
- })
-
- // TODO Refactor this code once financial beings api is ready
- // Authorization is handled by the teams module
- let botsByUser = await teams_FbByTeamMember(context.authorization)
+ }).sort({createDatetime: -1})
for (var i = 0; i < clones.length; i++) {
- clones[i] = await cloneDetails(context.authorization, botsByUser, clones[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].cloneName)
clones[i].state = state.substring(1, state.length-1)
let lastLogs = await getCloneLogs(clones[i].cloneName)