diff --git a/.gitmodules b/.gitmodules index 22790ccc7..70fda6a17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,6 +31,3 @@ [submodule "login_server/src/proto"] path = login_server/src/proto url = https://github.com/gradido/gradido_protocol.git -[submodule "login_server/dependencies/protobuf"] - path = login_server/dependencies/protobuf - url = https://github.com/protocolbuffers/protobuf.git diff --git a/backend/.env.dist b/backend/.env.dist index fe9d5e566..f5308a4fa 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,4 +1,4 @@ PORT=4000 GRAPHIQL=false // LOGIN_API_URL=http://login-server:1201/ -// COMMUNITY_API_URL=http://localhost/api/ \ No newline at end of file +// COMMUNITY_API_URL=http://nginx/api/ \ No newline at end of file diff --git a/backend/src/apis/loginAPI.ts b/backend/src/apis/loginAPI.ts index b81316b3f..1aa6cace1 100644 --- a/backend/src/apis/loginAPI.ts +++ b/backend/src/apis/loginAPI.ts @@ -2,35 +2,38 @@ import axios from 'axios' // eslint-disable-next-line @typescript-eslint/no-explicit-any export const apiPost = async (url: string, payload: unknown): Promise => { - try { - const result = await axios.post(url, payload) - if (result.status !== 200) { - throw new Error('HTTP Status Error ' + result.status) - } - if (result.data.state === 'warning') { - return { success: true, result: result.data.errors } - } - if (result.data.state !== 'success') { - throw new Error(result.data.msg) - } - return { success: true, result } - } catch (error) { - return { success: false, result: error } - } + return axios + .post(url, payload) + .then((result) => { + if (result.status !== 200) { + throw new Error('HTTP Status Error ' + result.status) + } + if (result.data.state !== 'success') { + throw new Error(result.data.msg) + } + return { success: true, result } + }) + .catch((error) => { + return { success: false, result: error } + }) } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const apiGet = async (url: string): Promise => { - try { - const result = await axios.get(url) - if (result.status !== 200) { - throw new Error('HTTP Status Error ' + result.status) - } - if (!['success', 'warning'].includes(result.data.state)) { - throw new Error(result.data.msg) - } - return { success: true, result } - } catch (error) { - return { success: false, result: error } - } + return axios + .get(url) + .then((result) => { + if (result.status !== 200) { + throw new Error('HTTP Status Error ' + result.status) + } + if (!['success', 'warning'].includes(result.data.state)) { + throw new Error(result.data.msg) + } + return { success: true, result: result } + }) + .catch((error) => { + // eslint-disable-next-line no-console + console.log('IN apiGet.ERROR: ' + JSON.stringify({ success: false, result: error })) + return { success: false, result: error } + }) } diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 14e824d19..685ff698e 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -8,8 +8,8 @@ const server = { JWT_SECRET: process.env.JWT_SECRET || 'secret123', JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', GRAPHIQL: process.env.GRAPHIQL === 'true' || false, - LOGIN_API_URL: process.env.LOGIN_API_URL || 'http://localhost/login_api/', - // COMMUNITY_API_URL: process.env.COMMUNITY_API_URL || 'http://localhost/api/', + LOGIN_API_URL: process.env.LOGIN_API_URL || 'http://login-server:1201/', + COMMUNITY_API_URL: process.env.COMMUNITY_API_URL || 'http://ngninx/api/', } // This is needed by graphql-directive-auth diff --git a/backend/src/graphql/inputs/LoginUserInput.ts b/backend/src/graphql/inputs/LoginUserInput.ts index c93b934b6..68ddad628 100644 --- a/backend/src/graphql/inputs/LoginUserInput.ts +++ b/backend/src/graphql/inputs/LoginUserInput.ts @@ -26,6 +26,42 @@ export class UnsecureLoginArgs { password: string } +@ArgsType() +export class CreateUserArgs { + @Field(() => String) + email: string + + @Field(() => String) + firstName: string + + @Field(() => String) + lastName: string + + @Field(() => String) + password: string +} + +@ArgsType() +export class SendEmailArgs { + @Field(() => String) + email: string + + @Field(() => Number) + emailText: number + + @Field(() => String) + emailVerificationCodeType: string +} + +@ArgsType() +export class GetUserInfoArgs { + @Field(() => Number) + sessionId: number + + @Field(() => String) + email: string +} + @ArgsType() export class ChangePasswordArgs { @Field(() => Number) @@ -37,3 +73,39 @@ export class ChangePasswordArgs { @Field(() => String) password: string } + +@ArgsType() +export class UpdateUserInfosArgs { + @Field(() => Number) + sessionId!: number + + @Field(() => String) + email!: string + + @Field(() => String) + firstName?: string + + @Field(() => String) + lastName?: string + + @Field(() => String) + username?: string + + @Field(() => String) + language?: string + + @Field(() => String) + password?: string + + @Field(() => String) + passwordNew?: string +} + +@ArgsType() +export class CheckUsernameArgs { + @Field(() => String) + username: string + + @Field(() => Number) + groupId?: number +} diff --git a/backend/src/graphql/inputs/TransactionInput.ts b/backend/src/graphql/inputs/TransactionInput.ts new file mode 100644 index 000000000..279e09dd6 --- /dev/null +++ b/backend/src/graphql/inputs/TransactionInput.ts @@ -0,0 +1,50 @@ +import { ObjectType, ArgsType, Field, Int, Float } from 'type-graphql' +import { Entity, BaseEntity, Column, Double } from 'typeorm' + +@ArgsType() +export class TransactionInput { + @Field(() => Number) + sessionId: number + + @Field(() => Number) + firstPage: number + + @Field(() => Number) + items: number + + @Field(() => String) + order: string +} + +@ArgsType() +export class TransactionSendArgs { + @Field(() => Number) + sessionId: number + + @Field(() => String) + email: string + + @Field(() => Number) + amount: number + + @Field(() => String) + memo: string +} + +@ArgsType() +export class TransactionCreateArgs { + @Field(() => Number) + sessionId: number + + @Field(() => String) + email: string + + @Field(() => Number) + amount: number + + @Field(() => String) + memo: string + + @Field(() => Date) + targetDate: Date +} diff --git a/backend/src/graphql/models/Balance.ts b/backend/src/graphql/models/Balance.ts new file mode 100644 index 000000000..2ba34ec75 --- /dev/null +++ b/backend/src/graphql/models/Balance.ts @@ -0,0 +1,26 @@ +import { Entity, BaseEntity, Column } from 'typeorm' +import { ObjectType, Field } from 'type-graphql' + +@Entity() +@ObjectType() +export class Balance extends BaseEntity { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + constructor(json: any) { + super() + this.balance = json.balance + this.decay = json.decay + this.decayDate = json.decay_date + } + + @Field(() => Number) + @Column() + balance: number + + @Field(() => Number) + @Column() + decay: number + + @Field(() => String) + @Column() + decayDate: string +} diff --git a/backend/src/graphql/models/Group.ts.old b/backend/src/graphql/models/Group.ts.old deleted file mode 100644 index 45582225e..000000000 --- a/backend/src/graphql/models/Group.ts.old +++ /dev/null @@ -1,26 +0,0 @@ -import { Entity, BaseEntity, PrimaryGeneratedColumn, Column } from 'typeorm' -import { ObjectType, Field, ID } from 'type-graphql' - -@Entity() -@ObjectType() -export class Group extends BaseEntity { - @Field(() => ID) - @PrimaryGeneratedColumn() - id: number - - @Field(() => String) - @Column({ length: 190 }) - alias: string - - @Field(() => String) - @Column() - name: string - - @Field(() => String) - @Column('text') - description: string - - @Field(() => String) - @Column() - url: string -} diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts new file mode 100644 index 000000000..b638e797e --- /dev/null +++ b/backend/src/graphql/models/Transaction.ts @@ -0,0 +1,10 @@ +import { Entity, BaseEntity, Column } from 'typeorm' +import { ObjectType, Field } from 'type-graphql' + +@Entity() +@ObjectType() +export class Transaction extends BaseEntity { + @Field(() => String) + @Column({ length: 191 }) + email: string +} diff --git a/backend/src/graphql/models/User.ts b/backend/src/graphql/models/User.ts index 938d0a9f9..b935871d1 100644 --- a/backend/src/graphql/models/User.ts +++ b/backend/src/graphql/models/User.ts @@ -95,3 +95,90 @@ export class LoginViaVerificationCode extends BaseEntity { @Column() email: string } + +@Entity() +@ObjectType() +export class LogoutResponse extends BaseEntity { + @Field(() => String) + state: string +} + +@Entity() +@ObjectType() +export class CreateResponse extends BaseEntity { + @Field(() => String) + state: string +} + +@Entity() +@ObjectType() +export class SendEmailResponse extends BaseEntity { + @Field(() => String) + state: string + + @Field(() => String) + msg?: string +} + +@Entity() +@ObjectType() +export class Server extends BaseEntity { + @Field(() => String) + loginServerPath: string +} + +@Entity() +@ObjectType() +export class ErrorData extends BaseEntity { + @Field(() => String) + messages: string +} + +@Entity() +@ObjectType() +export class GetUserInfoResponse extends BaseEntity { + @Field(() => String) + state: string + + @Field(() => User) + userData: User + + @Field(() => Server) + server: Server + + @Field(() => [ErrorData]) + errors: [ErrorData] +} + +@Entity() +@ObjectType() +export class ChangePasswordResponse extends BaseEntity { + @Field(() => String) + state: string +} + +@Entity() +@ObjectType() +export class UpdateUserInfosResponse extends BaseEntity { + @Field(() => String) + state: string + + @Field(() => Number) + validValues: number + + @Field(() => [ErrorData]) + errors: [ErrorData] +} + +@Entity() +@ObjectType() +export class CheckUsernameResponse extends BaseEntity { + @Field(() => String) + state: string + + @Field(() => String) + msg?: string + + @Field(() => Number) + groupId?: number +} diff --git a/backend/src/graphql/resolvers/CommunityTransactionResolver.ts b/backend/src/graphql/resolvers/CommunityTransactionResolver.ts new file mode 100644 index 000000000..7eb7a9921 --- /dev/null +++ b/backend/src/graphql/resolvers/CommunityTransactionResolver.ts @@ -0,0 +1,57 @@ +import { Resolver, Query, /* Mutation, */ Args, Arg } from 'type-graphql' +import CONFIG from '../../config' +import {} from '../models/Transaction' +import { Balance } from '../models/Balance' +import { + TransactionCreateArgs, + TransactionInput, + TransactionSendArgs, +} from '../inputs/TransactionInput' +import { apiPost, apiGet } from '../../apis/loginAPI' + +@Resolver() +export class CommunityTransactionResolver { + @Query(() => Balance) + async balance(@Arg('sessionId') sessionId: number): Promise { + // eslint-disable-next-line no-console + console.log('IN BALANCE: URL: ' + CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId) + const result = await apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId) + return new Balance(result.result.data) + } + + @Query(() => String) + async transactions( + @Args() { sessionId, firstPage = 1, items = 5, order = 'DESC' }: TransactionInput, + ): Promise { + return apiGet( + `${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`, + ) + } + + @Query(() => String) + async send(@Args() { sessionId, email, amount, memo }: TransactionSendArgs): Promise { + const payload = { + session_id: sessionId, + auto_sign: true, + email: email, + amount: amount, + memo: memo, + } + return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload) + } + + @Query(() => String) + async create( + @Args() { sessionId, email, amount, memo, targetDate = new Date() }: TransactionCreateArgs, + ): Promise { + const payload = { + sessionId, + email, + amount, + targetDate, + memo, + auto_sign: true, + } + return apiPost(CONFIG.COMMUNITY_API_URL + 'createCoins/', payload) + } +} diff --git a/backend/src/graphql/resolvers/GroupResolver.ts.old b/backend/src/graphql/resolvers/GroupResolver.ts.old deleted file mode 100644 index 8294c09ab..000000000 --- a/backend/src/graphql/resolvers/GroupResolver.ts.old +++ /dev/null @@ -1,23 +0,0 @@ -import { Resolver, Query, Mutation, Arg } from 'type-graphql' -import { Group } from '../models/Group' -import { loginAPI, NetworkInfosResult } from '../../apis/loginAPI' -@Resolver() -export class GroupResolver { - @Query(() => [Group]) - async groups(): Promise { - const result: NetworkInfosResult = await loginAPI.getNetworkInfos(['groups']) - const groups: Group[] = [] - - result.data.groups?.forEach((alias: string) => { - const group = new Group() - group.alias = alias - groups.push(group) - }) - return groups - } - - @Query(() => Group) - group(@Arg('id') id: string): Promise { - return Group.findOne({ where: { id } }) - } -} diff --git a/backend/src/graphql/resolvers/UserResolver.ts b/backend/src/graphql/resolvers/UserResolver.ts index f22d9c9b9..723f7539e 100644 --- a/backend/src/graphql/resolvers/UserResolver.ts +++ b/backend/src/graphql/resolvers/UserResolver.ts @@ -1,22 +1,30 @@ // import jwt from 'jsonwebtoken' import { Resolver, Query, /* Mutation, */ Args, Arg } from 'type-graphql' import CONFIG from '../../config' -import { LoginResponse, LoginViaVerificationCode } from '../models/User' -import { UnsecureLoginArgs, ChangePasswordArgs } from '../inputs/LoginUserInput' +import { + ChangePasswordResponse, + CheckUsernameResponse, + CreateResponse, + GetUserInfoResponse, + LoginResponse, + LoginViaVerificationCode, + LogoutResponse, + SendEmailResponse, + UpdateUserInfosResponse, +} from '../models/User' +import { + ChangePasswordArgs, + CheckUsernameArgs, + CreateUserArgs, + GetUserInfoArgs, + SendEmailArgs, + UnsecureLoginArgs, + UpdateUserInfosArgs, +} from '../inputs/LoginUserInput' import { apiPost, apiGet } from '../../apis/loginAPI' @Resolver() export class UserResolver { - /* @Query(() => [User]) - users(): Promise { - return User.find() - } */ - - /* @Query(() => User) - user(@Arg('id') id: string): Promise { - return User.findOne({ where: { id } }) - } */ - @Query(() => LoginResponse) // eslint-disable-next-line @typescript-eslint/no-explicit-any async login(@Args() { email, password }: UnsecureLoginArgs): Promise { @@ -55,20 +63,6 @@ export class UserResolver { // return loginResult.user ? loginResult.user : new User() } - // forgot password request - @Query(() => String) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async sendEmail(@Arg('email') email: string): Promise { - const payload = { - email, - email_text: 7, - email_verification_code_type: 'resetPassword', - } - const result = await apiPost(CONFIG.LOGIN_API_URL + 'sendEmail', payload) - if (result.success) return result.result.data.state - return result.result - } - @Query(() => LoginViaVerificationCode) // eslint-disable-next-line @typescript-eslint/no-explicit-any async loginViaEmailVerificationCode(@Arg('optin') optin: string): Promise { @@ -85,8 +79,50 @@ export class UserResolver { return result.result } - @Query(() => String) - // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Query(() => LogoutResponse) + async logout(@Arg('sessionId') sessionId: number): Promise { + const payload = { session_id: sessionId } + const result = apiPost(CONFIG.LOGIN_API_URL + 'logout', payload); + return result + } + + @Query(() => CreateResponse) + async create(@Args() { email, firstName, lastName, password }: CreateUserArgs): Promise { + const payload = { + email, + first_name: firstName, + last_name: lastName, + password, + emailType: 2, + login_after_register: true, + } + return apiPost(CONFIG.LOGIN_API_URL + 'createUser', payload) + } + + @Query(() => SendEmailResponse) + async sendEmail( + @Args() + { email, emailText = 7, emailVerificationCodeType = 'resetPassword' }: SendEmailArgs, + ): Promise { + const payload = { + email, + email_text: emailText, + email_verification_code_type: emailVerificationCodeType, + } + return apiPost(CONFIG.LOGIN_API_URL + 'sendEmail', payload) + } + + @Query(() => GetUserInfoResponse) + async getUserInfos(@Args() { sessionId, email }: GetUserInfoArgs): Promise { + const payload = { + session_id: sessionId, + email: email, + ask: ['user.first_name', 'user.last_name'], + } + return apiPost(CONFIG.LOGIN_API_URL + 'getUserInfos', payload) + } + + @Query(() => ChangePasswordResponse) async changePassword(@Args() { sessionId, email, password }: ChangePasswordArgs): Promise { const payload = { session_id: sessionId, @@ -94,8 +130,42 @@ export class UserResolver { password, } const result = await apiPost(CONFIG.LOGIN_API_URL + 'resetPassword', payload) - console.log(result) if (result.success) return result.result.data.state return result.result } + + @Query(() => UpdateUserInfosResponse) + async updateUserInfos( + @Args() + { + sessionId, + email, + firstName, + lastName, + username, + language, + password, + passwordNew, + }: UpdateUserInfosArgs, + ): Promise { + const payload = { + session_id: sessionId, + email, + update: { + 'User.first_name': firstName, + 'User.last_name': lastName, + // 'User.description': data.description, + 'User.username': username, + 'User.language': language, + 'User.password_old': password, + 'User.password': passwordNew, + }, + } + return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload) + } + + @Query(() => CheckUsernameResponse) + async checkUsername(@Args() { username, groupId = 1 }: CheckUsernameArgs): Promise { + return apiGet(CONFIG.LOGIN_API_URL + `checkUsername?username=${username}&group_id=${groupId}`) + } } diff --git a/backend/src/index.ts b/backend/src/index.ts index 0d4bfd3db..b6e19f56d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -8,6 +8,7 @@ import CONFIG from './config' // TODO move to extern // import { BookResolver } from './graphql/resolvers/BookResolver' import { UserResolver } from './graphql/resolvers/UserResolver' +import { CommunityTransactionResolver } from './graphql/resolvers/CommunityTransactionResolver' // import { GroupResolver } from './graphql/resolvers/GroupResolver' // TODO implement // import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity"; @@ -15,7 +16,7 @@ import { UserResolver } from './graphql/resolvers/UserResolver' async function main() { // const connection = await createConnection() const schema = await buildSchema({ - resolvers: [/* BookResolver , GroupResolver, */ UserResolver], + resolvers: [/* BookResolver , GroupResolver, */ UserResolver, CommunityTransactionResolver], }) // Graphiql interface diff --git a/community_server/src/Controller/AppRequestsController.php b/community_server/src/Controller/AppRequestsController.php index 271265257..12dd8aa6e 100644 --- a/community_server/src/Controller/AppRequestsController.php +++ b/community_server/src/Controller/AppRequestsController.php @@ -271,6 +271,8 @@ class AppRequestsController extends AppController public function getBalance($session_id = 0) { $this->viewBuilder()->setLayout('ajax'); + $this->response = $this->response->withType('application/json'); + $login_result = $this->requestLogin($session_id, false); if($login_result !== true) { $this->set('body', $login_result); @@ -301,12 +303,16 @@ class AppRequestsController extends AppController } $body['decay_date'] = $now; + $this->addAdminError("AppRequests", "getBalance", $body, $user['id']); $this->set('body', $body); } public function listTransactions($page = 1, $count = 25, $orderDirection = 'ASC', $session_id = 0) { + $this->viewBuilder()->setLayout('ajax'); + $this->response = $this->response->withType('application/json'); + $startTime = microtime(true); $login_result = $this->requestLogin($session_id, false); diff --git a/community_server/src/Template/AppRequests/get_balance.ctp b/community_server/src/Template/AppRequests/get_balance.ctp index 618ec4c2e..7dd4d6025 100644 --- a/community_server/src/Template/AppRequests/get_balance.ctp +++ b/community_server/src/Template/AppRequests/get_balance.ctp @@ -6,6 +6,10 @@ * and open the template in the editor. */ -$body['balance'] = $this->element('centToFloat', ['cent' => $body['balance'], 'precision' => 4]); -$body['decay'] = $this->element('centToFloat', ['cent' => $body['decay'], 'precision' => 4]); +if(isset($body['balance'])) { + $body['balance'] = $this->element('centToFloat', ['cent' => $body['balance'], 'precision' => 4]); +} +if(isset($body['decay'])) { + $body['decay'] = $this->element('centToFloat', ['cent' => $body['decay'], 'precision' => 4]); +} ?> \ No newline at end of file diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 092cd9db1..8a0295d61 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -30,6 +30,7 @@ services: target: development networks: - external-net + - internal-net environment: - NODE_ENV="development" volumes: diff --git a/login_server/dependencies/protobuf b/login_server/dependencies/protobuf deleted file mode 160000 index 0b8d13a1d..000000000 --- a/login_server/dependencies/protobuf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0b8d13a1d4cd9be16ed8a2230577aa9c296aa1ca