diff --git a/README.md b/README.md index fe6f2e7f3..ead54701c 100644 --- a/README.md +++ b/README.md @@ -8,33 +8,73 @@ The Gradido model can create global prosperity and peace The Corona crisis has fundamentally changed our world within a very short time. The dominant financial system threatens to fail around the globe, followed by mass insolvencies, record unemployment and abject poverty. Only with a sustainable new monetary system can humanity master these challenges of the 21st century. The Gradido Academy for Bionic Economy has developed such a system. +Find out more about the Project on its [Website](https://gradido.net/). It is offering vast resources about the idea. The remaining document will discuss the gradido software only. ## Software requirements -Currently we only support `docker` as environment to run all services, since many different programming languages and frameworks are used. +Currently we only support `docker` install instructions to run all services, since many different programming languages and frameworks are used. -- [docker](https://www.docker.com/) +- [docker](https://www.docker.com/) +- [docker-compose] + +### For Arch Linux +Install the required packages: +```bash +sudo pacman -S docker +sudo pacman -S docker-compose +``` + +Add group `docker` and then your user to it in order to allow you to run docker without sudo +```bash +sudo groupadd docker # may already exist `groupadd: group 'docker' already exists` +sudo usermod -aG docker $USER +groups # verify you have the group (requires relog) +``` + +Start the docker service: +```bash +sudo systemctrl start docker +``` ## How to run? -1. Clone the repo and pull all submodules - +### 1. Clone Sources +Clone the repo and pull all submodules ```bash git clone git@github.com:gradido/gradido.git git submodule update --recursive --init ``` -2. Run docker compose - 1. Run docker compose for the debug build +### 2. Run docker-compose +Run docker-compose to bring up the development environment +```bash +docker-compose up +``` +### Additional Build options +If you want to build for production you can do this aswell: +```bash +docker-compose -f docker-compose.yml up +``` - ```bash - docker-compose up - ``` +## Services defined in this package - 2. Or run docker compose in production build +- [frontend](./frontend) Wallet frontend +- [backend](./backend) GraphQL & Business logic backend +- [mariadb](./mariadb) Database backend +- [login_server](./login_server) User credential storage & business logic backend +- [community_server](./community_server/) Business logic backend - ```bash - docker-compose -f docker-compose.yml up - ``` +We are currently restructuring the service to reduce dependencies and unify business logic into one place. Furthermore the databases defined for each service will be unified into one. + +### Open the wallet + +Once you have `docker-compose` up and running, you can open [http://localhost/vue](http://localhost/vue) and create yourself a new wallet account. + +## Troubleshooting + +| Problem | Issue | Solution | Description | +| ------- | ----- | -------- | ----------- | +| docker-compose raises database connection errors | [#1062](https://github.com/gradido/gradido/issues/1062) | End `ctrl+c` and restart the `docker-compose up` after a successful build | Several Database connection related errors occur in the docker-compose log. | +| Wallet page is empty | [#1063](https://github.com/gradido/gradido/issues/1063) | Accept Cookies and Local Storage in your Browser | The page stays empty when navigating to [http://localhost/vue](http://localhost/vue) | ## Useful Links diff --git a/backend/src/graphql/arg/CheckUsernameArgs.ts b/backend/src/graphql/arg/CheckUsernameArgs.ts index 6aaed6d0b..64265b64e 100644 --- a/backend/src/graphql/arg/CheckUsernameArgs.ts +++ b/backend/src/graphql/arg/CheckUsernameArgs.ts @@ -4,7 +4,4 @@ import { ArgsType, Field } from 'type-graphql' export default class CheckUsernameArgs { @Field(() => String) username: string - - @Field(() => Number, { nullable: true }) - groupId?: number } diff --git a/backend/src/graphql/model/CheckUsernameResponse.ts b/backend/src/graphql/model/CheckUsernameResponse.ts deleted file mode 100644 index b3186ffcf..000000000 --- a/backend/src/graphql/model/CheckUsernameResponse.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { ObjectType, Field } from 'type-graphql' - -@ObjectType() -export class CheckUsernameResponse { - constructor(json: any) { - this.state = json.state - this.msg = json.msg - this.groupId = json.group_id - } - - @Field(() => String) - state: string - - @Field(() => String) - msg?: string - - @Field(() => Number) - groupId?: number -} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 33949197c..f6eccd7e8 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -3,8 +3,8 @@ import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware, Mutation } from 'type-graphql' import { from_hex as fromHex } from 'libsodium-wrappers' +import { getCustomRepository } from 'typeorm' import CONFIG from '../../config' -import { CheckUsernameResponse } from '../model/CheckUsernameResponse' import { LoginViaVerificationCode } from '../model/LoginViaVerificationCode' import { SendPasswordResetEmailResponse } from '../model/SendPasswordResetEmailResponse' import { UpdateUserInfosResponse } from '../model/UpdateUserInfosResponse' @@ -22,10 +22,10 @@ import { klicktippNewsletterStateMiddleware, } from '../../middleware/klicktippMiddleware' import { CheckEmailResponse } from '../model/CheckEmailResponse' -import { getCustomRepository } from 'typeorm' import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository' import { Setting } from '../enum/Setting' import { UserRepository } from '../../typeorm/repository/User' +import { LoginUser } from '@entity/LoginUser' @Resolver() export class UserResolver { @@ -275,15 +275,27 @@ export class UserResolver { return response } - @Query(() => CheckUsernameResponse) - async checkUsername( - @Args() { username, groupId = 1 }: CheckUsernameArgs, - ): Promise { - const response = await apiGet( - CONFIG.LOGIN_API_URL + `checkUsername?username=${username}&group_id=${groupId}`, - ) - if (!response.success) throw new Error(response.data) - return new CheckUsernameResponse(response.data) + @Query(() => Boolean) + async checkUsername(@Args() { username }: CheckUsernameArgs): Promise { + // Username empty? + if (username === '') { + throw new Error('Username must be set.') + } + + // Do we fullfil the minimum character length? + const MIN_CHARACTERS_USERNAME = 2 + if (username.length < MIN_CHARACTERS_USERNAME) { + throw new Error(`Username must be at minimum ${MIN_CHARACTERS_USERNAME} characters long.`) + } + + const usersFound = await LoginUser.count({ username }) + + // Username already present? + if (usersFound !== 0) { + throw new Error(`Username "${username}" already taken.`) + } + + return true } @Query(() => CheckEmailResponse) diff --git a/database/entity/0003-login_server_tables/LoginUser.ts b/database/entity/0003-login_server_tables/LoginUser.ts new file mode 100644 index 000000000..26614b4db --- /dev/null +++ b/database/entity/0003-login_server_tables/LoginUser.ts @@ -0,0 +1,56 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' + +// Moriz: I do not like the idea of having two user tables +@Entity('login_users') +export class LoginUser extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ length: 191, unique: true }) + email: string + + @Column({ name: 'first_name', length: 150 }) + firstName: string + + @Column({ name: 'last_name', length: 255, default: '' }) + lastName: string + + @Column({ length: 255, default: '' }) + username: string + + @Column({ default: '' }) + description: string + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: string + + @Column({ name: 'pubkey', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP' }) + createdAt: Date + + @Column({ name: 'email_checked', default: 0 }) + emailChecked: boolean + + @Column({ name: 'passphrase_shown', default: 0 }) + passphraseShown: boolean + + @Column({ length: 4, default: 'de' }) + language: string + + @Column({ default: 0 }) + disabled: boolean + + @Column({ name: 'group_id', default: 0, unsigned: true }) + groupId: number + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number +} diff --git a/database/entity/LoginUser.ts b/database/entity/LoginUser.ts new file mode 100644 index 000000000..034f791cb --- /dev/null +++ b/database/entity/LoginUser.ts @@ -0,0 +1 @@ +export { LoginUser } from './0003-login_server_tables/LoginUser' diff --git a/database/entity/index.ts b/database/entity/index.ts index e18757ab8..1881b2932 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -1,4 +1,5 @@ import { Balance } from './Balance' +import { LoginUser } from './LoginUser' import { Migration } from './Migration' import { Transaction } from './Transaction' import { TransactionCreation } from './TransactionCreation' @@ -9,6 +10,7 @@ import { UserTransaction } from './UserTransaction' export const entities = [ Balance, + LoginUser, Migration, Transaction, TransactionCreation, diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 2ee381dd8..01021f601 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -75,9 +75,7 @@ export const sendResetPasswordEmail = gql` export const checkUsername = gql` query($username: String!) { - checkUsername(username: $username) { - state - } + checkUsername(username: $username) } ` diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index 5552794d1..54f4c3090 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -59,7 +59,7 @@ export const loadAllRules = (i18nCallback) => { }, }) .then((result) => { - return result.data.checkUsername.state === 'success' + return result.data.checkUsername }) .catch(() => { return false