mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge master in the branch.
This commit is contained in:
commit
021952831f
21
backend/src/auth/auth.ts
Normal file
21
backend/src/auth/auth.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
import { AuthChecker } from 'type-graphql'
|
||||||
|
import decode from '../jwt/decode'
|
||||||
|
import { apiGet } from '../apis/loginAPI'
|
||||||
|
import CONFIG from '../config'
|
||||||
|
|
||||||
|
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
||||||
|
export const isAuthorized: AuthChecker<any> = async ({ root, args, context, info }, roles) => {
|
||||||
|
if (context.token) {
|
||||||
|
const decoded = decode(context.token)
|
||||||
|
if (decoded.sessionId && decoded.sessionId !== 0) {
|
||||||
|
const result = await apiGet(
|
||||||
|
`${CONFIG.LOGIN_API_URL}checkSessionState?session_id=${decoded.sessionId}`,
|
||||||
|
)
|
||||||
|
context.sessionId = decoded.sessionId
|
||||||
|
return result.success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@ -17,9 +17,6 @@ export class GdtTransactionInput {
|
|||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class GdtTransactionSessionIdInput {
|
export class GdtTransactionSessionIdInput {
|
||||||
@Field(() => Number)
|
|
||||||
sessionId: number
|
|
||||||
|
|
||||||
@Field(() => Int, { nullable: true })
|
@Field(() => Int, { nullable: true })
|
||||||
currentPage?: number
|
currentPage?: number
|
||||||
|
|
||||||
|
|||||||
@ -41,9 +41,6 @@ export class ChangePasswordArgs {
|
|||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class UpdateUserInfosArgs {
|
export class UpdateUserInfosArgs {
|
||||||
@Field(() => Number)
|
|
||||||
sessionId!: number
|
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
email!: string
|
email!: string
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,6 @@ import { ArgsType, Field, Int } from 'type-graphql'
|
|||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class TransactionListInput {
|
export class TransactionListInput {
|
||||||
@Field(() => Number)
|
|
||||||
sessionId: number
|
|
||||||
|
|
||||||
@Field(() => Int)
|
@Field(() => Int)
|
||||||
firstPage: number
|
firstPage: number
|
||||||
|
|
||||||
@ -17,9 +14,6 @@ export class TransactionListInput {
|
|||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class TransactionSendArgs {
|
export class TransactionSendArgs {
|
||||||
@Field(() => Number)
|
|
||||||
sessionId: number
|
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
email: string
|
email: string
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export enum GdtEntryType {
|
|||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class GdtEntry {
|
export class GdtEntry {
|
||||||
constructor(json: any) {
|
constructor(json: any) {
|
||||||
|
this.id = json.id
|
||||||
this.amount = json.amount
|
this.amount = json.amount
|
||||||
this.date = json.date
|
this.date = json.date
|
||||||
this.email = json.email
|
this.email = json.email
|
||||||
@ -27,6 +28,9 @@ export class GdtEntry {
|
|||||||
this.gdt = json.gdt
|
this.gdt = json.gdt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
id: number
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
amount: number
|
amount: number
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
||||||
import { ObjectType, Field } from 'type-graphql'
|
|
||||||
import { User } from './User'
|
|
||||||
|
|
||||||
// temporaray solution until we have JWT implemented
|
|
||||||
|
|
||||||
@ObjectType()
|
|
||||||
export class LoginResponse {
|
|
||||||
constructor(json: any) {
|
|
||||||
this.sessionId = json.session_id
|
|
||||||
this.user = new User(json.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Field(() => Number)
|
|
||||||
sessionId: number
|
|
||||||
|
|
||||||
@Field(() => User)
|
|
||||||
user: User
|
|
||||||
}
|
|
||||||
@ -1,13 +1,17 @@
|
|||||||
import { Resolver, Query, /* Mutation, */ Arg } from 'type-graphql'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
|
import { Resolver, Query, Ctx, Authorized } from 'type-graphql'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import { Balance } from '../models/Balance'
|
import { Balance } from '../models/Balance'
|
||||||
import { apiGet } from '../../apis/HttpRequest'
|
import { apiGet } from '../../apis/HttpRequest'
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class BalanceResolver {
|
export class BalanceResolver {
|
||||||
|
@Authorized()
|
||||||
@Query(() => Balance)
|
@Query(() => Balance)
|
||||||
async balance(@Arg('sessionId') sessionId: number): Promise<Balance> {
|
async balance(@Ctx() context: any): Promise<Balance> {
|
||||||
const result = await apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + sessionId)
|
const result = await apiGet(CONFIG.COMMUNITY_API_URL + 'getBalance/' + context.sessionId)
|
||||||
if (!result.success) throw new Error(result.data)
|
if (!result.success) throw new Error(result.data)
|
||||||
return new Balance(result.data)
|
return new Balance(result.data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
// import jwt from 'jsonwebtoken'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { Resolver, Query, /* Mutation, */ Args } from 'type-graphql'
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
|
import { Resolver, Query, Args, Ctx, Authorized } from 'type-graphql'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import { GdtEntryList } from '../models/GdtEntryList'
|
import { GdtEntryList } from '../models/GdtEntryList'
|
||||||
import { GdtTransactionSessionIdInput } from '../inputs/GdtInputs'
|
import { GdtTransactionSessionIdInput } from '../inputs/GdtInputs'
|
||||||
@ -7,14 +9,16 @@ import { apiGet } from '../../apis/HttpRequest'
|
|||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class GdtResolver {
|
export class GdtResolver {
|
||||||
|
@Authorized()
|
||||||
@Query(() => GdtEntryList)
|
@Query(() => GdtEntryList)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
async listGDTEntries(
|
async listGDTEntries(
|
||||||
@Args()
|
@Args()
|
||||||
{ currentPage = 1, pageSize = 5, order = 'DESC', sessionId }: GdtTransactionSessionIdInput,
|
{ currentPage = 1, pageSize = 5, order = 'DESC' }: GdtTransactionSessionIdInput,
|
||||||
|
@Ctx() context: any,
|
||||||
): Promise<GdtEntryList> {
|
): Promise<GdtEntryList> {
|
||||||
const result = await apiGet(
|
const result = await apiGet(
|
||||||
`${CONFIG.COMMUNITY_API_URL}listGDTTransactions/${currentPage}/${pageSize}/${order}/${sessionId}`,
|
`${CONFIG.COMMUNITY_API_URL}listGDTTransactions/${currentPage}/${pageSize}/${order}/${context.sessionId}`,
|
||||||
)
|
)
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.data)
|
throw new Error(result.data)
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
import { Resolver, Query, Args } from 'type-graphql'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
|
import { Resolver, Query, Args, Authorized, Ctx } from 'type-graphql'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import { TransactionList } from '../models/Transaction'
|
import { TransactionList } from '../models/Transaction'
|
||||||
import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput'
|
import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput'
|
||||||
@ -6,23 +9,27 @@ import { apiGet, apiPost } from '../../apis/HttpRequest'
|
|||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class TransactionResolver {
|
export class TransactionResolver {
|
||||||
|
@Authorized()
|
||||||
@Query(() => TransactionList)
|
@Query(() => TransactionList)
|
||||||
async transactionList(
|
async transactionList(
|
||||||
@Args() { sessionId, firstPage = 1, items = 25, order = 'DESC' }: TransactionListInput,
|
@Args() { firstPage = 1, items = 25, order = 'DESC' }: TransactionListInput,
|
||||||
|
@Ctx() context: any,
|
||||||
): Promise<TransactionList> {
|
): Promise<TransactionList> {
|
||||||
const result = await apiGet(
|
const result = await apiGet(
|
||||||
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${sessionId}`,
|
`${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${context.sessionId}`,
|
||||||
)
|
)
|
||||||
if (!result.success) throw new Error(result.data)
|
if (!result.success) throw new Error(result.data)
|
||||||
return new TransactionList(result.data)
|
return new TransactionList(result.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized()
|
||||||
@Query(() => String)
|
@Query(() => String)
|
||||||
async sendCoins(
|
async sendCoins(
|
||||||
@Args() { sessionId, email, amount, memo }: TransactionSendArgs,
|
@Args() { email, amount, memo }: TransactionSendArgs,
|
||||||
|
@Ctx() context: any,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const payload = {
|
const payload = {
|
||||||
session_id: sessionId,
|
session_id: context.sessionId,
|
||||||
target_email: email,
|
target_email: email,
|
||||||
amount: amount * 10000,
|
amount: amount * 10000,
|
||||||
memo,
|
memo,
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
// import jwt from 'jsonwebtoken'
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { Resolver, Query, Args, Arg, UseMiddleware } from 'type-graphql'
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware } from 'type-graphql'
|
||||||
import CONFIG from '../../config'
|
import CONFIG from '../../config'
|
||||||
import { CheckUsernameResponse } from '../models/CheckUsernameResponse'
|
import { CheckUsernameResponse } from '../models/CheckUsernameResponse'
|
||||||
import { LoginResponse } from '../models/LoginResponse'
|
import { User } from '../models/User'
|
||||||
import { LoginViaVerificationCode } from '../models/LoginViaVerificationCode'
|
import { LoginViaVerificationCode } from '../models/LoginViaVerificationCode'
|
||||||
import { SendPasswordResetEmailResponse } from '../models/SendPasswordResetEmailResponse'
|
import { SendPasswordResetEmailResponse } from '../models/SendPasswordResetEmailResponse'
|
||||||
import { UpdateUserInfosResponse } from '../models/UpdateUserInfosResponse'
|
import { UpdateUserInfosResponse } from '../models/UpdateUserInfosResponse'
|
||||||
@ -16,13 +17,14 @@ import {
|
|||||||
import { apiPost, apiGet } from '../../apis/HttpRequest'
|
import { apiPost, apiGet } from '../../apis/HttpRequest'
|
||||||
import { KlicktippController } from '../../apis/KlicktippController'
|
import { KlicktippController } from '../../apis/KlicktippController'
|
||||||
import { registerMiddleware } from '../../middleware/registerMiddleware'
|
import { registerMiddleware } from '../../middleware/registerMiddleware'
|
||||||
|
import encode from '../../jwt/encode'
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class UserResolver {
|
export class UserResolver {
|
||||||
private connector: KlicktippController = new KlicktippController(CONFIG.KLICKTTIPP_API_URL)
|
private connector: KlicktippController = new KlicktippController(CONFIG.KLICKTTIPP_API_URL)
|
||||||
|
|
||||||
@Query(() => LoginResponse)
|
@Query(() => String)
|
||||||
async login(@Args() { email, password }: UnsecureLoginArgs): Promise<LoginResponse> {
|
async login(@Args() { email, password }: UnsecureLoginArgs): Promise<string> {
|
||||||
email = email.trim().toLowerCase()
|
email = email.trim().toLowerCase()
|
||||||
const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
||||||
|
|
||||||
@ -31,21 +33,10 @@ export class UserResolver {
|
|||||||
throw new Error(result.data)
|
throw new Error(result.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporary solution until we have JWT implemented
|
const data = result.data
|
||||||
return new LoginResponse(result.data)
|
const sessionId = data.session_id
|
||||||
|
delete data.session_id
|
||||||
// create and return the json web token
|
return encode({ sessionId, user: new User(data.user) })
|
||||||
// The expire doesn't help us here. The client needs to track when the token expires on its own,
|
|
||||||
// since every action prolongs the time the session is valid.
|
|
||||||
/*
|
|
||||||
return jwt.sign(
|
|
||||||
{ result, role: 'todo' },
|
|
||||||
CONFIG.JWT_SECRET, // * , { expiresIn: CONFIG.JWT_EXPIRES_IN } ,
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
// return (await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', login)).result.data
|
|
||||||
// const loginResult: LoginResult = await loginAPI.login(data)
|
|
||||||
// return loginResult.user ? loginResult.user : new User()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Query(() => LoginViaVerificationCode)
|
@Query(() => LoginViaVerificationCode)
|
||||||
@ -63,9 +54,10 @@ export class UserResolver {
|
|||||||
return new LoginViaVerificationCode(result.data)
|
return new LoginViaVerificationCode(result.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized()
|
||||||
@Query(() => String)
|
@Query(() => String)
|
||||||
async logout(@Arg('sessionId') sessionId: number): Promise<string> {
|
async logout(@Ctx() context: any): Promise<string> {
|
||||||
const payload = { session_id: sessionId }
|
const payload = { session_id: context.sessionId }
|
||||||
const result = await apiPost(CONFIG.LOGIN_API_URL + 'logout', payload)
|
const result = await apiPost(CONFIG.LOGIN_API_URL + 'logout', payload)
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.data)
|
throw new Error(result.data)
|
||||||
@ -128,11 +120,11 @@ export class UserResolver {
|
|||||||
return 'sucess'
|
return 'sucess'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized()
|
||||||
@Query(() => UpdateUserInfosResponse)
|
@Query(() => UpdateUserInfosResponse)
|
||||||
async updateUserInfos(
|
async updateUserInfos(
|
||||||
@Args()
|
@Args()
|
||||||
{
|
{
|
||||||
sessionId,
|
|
||||||
email,
|
email,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
@ -142,9 +134,10 @@ export class UserResolver {
|
|||||||
password,
|
password,
|
||||||
passwordNew,
|
passwordNew,
|
||||||
}: UpdateUserInfosArgs,
|
}: UpdateUserInfosArgs,
|
||||||
|
@Ctx() context: any,
|
||||||
): Promise<UpdateUserInfosResponse> {
|
): Promise<UpdateUserInfosResponse> {
|
||||||
const payload = {
|
const payload = {
|
||||||
session_id: sessionId,
|
session_id: context.sessionId,
|
||||||
email,
|
email,
|
||||||
update: {
|
update: {
|
||||||
'User.first_name': firstName || undefined,
|
'User.first_name': firstName || undefined,
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { buildSchema } from 'type-graphql'
|
import { buildSchema } from 'type-graphql'
|
||||||
@ -8,17 +10,30 @@ import connection from './database/connection'
|
|||||||
import CONFIG from './config'
|
import CONFIG from './config'
|
||||||
|
|
||||||
// TODO move to extern
|
// TODO move to extern
|
||||||
// import { BookResolver } from './graphql/resolvers/BookResolver'
|
|
||||||
import { UserResolver } from './graphql/resolvers/UserResolver'
|
import { UserResolver } from './graphql/resolvers/UserResolver'
|
||||||
import { BalanceResolver } from './graphql/resolvers/BalanceResolver'
|
import { BalanceResolver } from './graphql/resolvers/BalanceResolver'
|
||||||
import { GdtResolver } from './graphql/resolvers/GdtResolver'
|
import { GdtResolver } from './graphql/resolvers/GdtResolver'
|
||||||
import { TransactionResolver } from './graphql/resolvers/TransactionResolver'
|
import { TransactionResolver } from './graphql/resolvers/TransactionResolver'
|
||||||
|
|
||||||
|
import { isAuthorized } from './auth/auth'
|
||||||
|
|
||||||
// TODO implement
|
// TODO implement
|
||||||
// import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity";
|
// import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity";
|
||||||
|
|
||||||
const DB_VERSION = '0001-init_db'
|
const DB_VERSION = '0001-init_db'
|
||||||
|
|
||||||
|
const context = (req: any) => {
|
||||||
|
const authorization = req.req.headers.authorization
|
||||||
|
let token = null
|
||||||
|
if (authorization) {
|
||||||
|
token = req.req.headers.authorization.replace(/^Bearer /, '')
|
||||||
|
}
|
||||||
|
const context = {
|
||||||
|
token,
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
// check for correct database version
|
// check for correct database version
|
||||||
const con = await connection()
|
const con = await connection()
|
||||||
@ -34,6 +49,7 @@ async function main() {
|
|||||||
// const connection = await createConnection()
|
// const connection = await createConnection()
|
||||||
const schema = await buildSchema({
|
const schema = await buildSchema({
|
||||||
resolvers: [UserResolver, BalanceResolver, TransactionResolver, GdtResolver],
|
resolvers: [UserResolver, BalanceResolver, TransactionResolver, GdtResolver],
|
||||||
|
authChecker: isAuthorized,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Graphiql interface
|
// Graphiql interface
|
||||||
@ -46,7 +62,7 @@ async function main() {
|
|||||||
const server = express()
|
const server = express()
|
||||||
|
|
||||||
// Apollo Server
|
// Apollo Server
|
||||||
const apollo = new ApolloServer({ schema, playground })
|
const apollo = new ApolloServer({ schema, playground, context })
|
||||||
apollo.applyMiddleware({ app: server })
|
apollo.applyMiddleware({ app: server })
|
||||||
|
|
||||||
// Start Server
|
// Start Server
|
||||||
|
|||||||
23
backend/src/jwt/decode.ts
Normal file
23
backend/src/jwt/decode.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
|
import jwt from 'jsonwebtoken'
|
||||||
|
import CONFIG from '../config/'
|
||||||
|
|
||||||
|
export default (token: string): any => {
|
||||||
|
if (!token) return null
|
||||||
|
let sessionId = null
|
||||||
|
const email = null
|
||||||
|
try {
|
||||||
|
const decoded = jwt.verify(token, CONFIG.JWT_SECRET)
|
||||||
|
sessionId = decoded.sub
|
||||||
|
// email = decoded.email
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
sessionId,
|
||||||
|
email,
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
18
backend/src/jwt/encode.ts
Normal file
18
backend/src/jwt/encode.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
|
||||||
|
import jwt from 'jsonwebtoken'
|
||||||
|
import CONFIG from '../config/'
|
||||||
|
|
||||||
|
// Generate an Access Token
|
||||||
|
export default function encode(data: any): string {
|
||||||
|
const { user, sessionId } = data
|
||||||
|
const { email, language, firstName, lastName } = user
|
||||||
|
const token = jwt.sign({ email, language, firstName, lastName, sessionId }, CONFIG.JWT_SECRET, {
|
||||||
|
expiresIn: CONFIG.JWT_EXPIRES_IN,
|
||||||
|
// issuer: CONFIG.GRAPHQL_URI,
|
||||||
|
// audience: CONFIG.CLIENT_URI,
|
||||||
|
subject: sessionId.toString(),
|
||||||
|
})
|
||||||
|
return token
|
||||||
|
}
|
||||||
@ -21,7 +21,7 @@ $this->assign('title', __('GDT Kontoübersicht'));
|
|||||||
$header = '<h3>' . __('Zur Verfügung: ') . '</h3>';
|
$header = '<h3>' . __('Zur Verfügung: ') . '</h3>';
|
||||||
|
|
||||||
if($gdtSum > 0){
|
if($gdtSum > 0){
|
||||||
$header .= '<h2>'.$this->element('printGDT', ['number' => $gdtSum]).'</h2>';
|
$header .= '<h2>'.$this->element('printGDT', ['number' => $gdtSum*100.0]).'</h2>';
|
||||||
}
|
}
|
||||||
if($moreEntrysAsShown) {
|
if($moreEntrysAsShown) {
|
||||||
$header .= '<span>'. __('Nur die letzten 100 Einträge werden angezeigt!') . '</span>';
|
$header .= '<span>'. __('Nur die letzten 100 Einträge werden angezeigt!') . '</span>';
|
||||||
@ -56,7 +56,7 @@ $this->assign('header', $header);
|
|||||||
<?= $this->Number->format($entry['factor2']) ?>
|
<?= $this->Number->format($entry['factor2']) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell c3"><?= $this->element('printGDT', ['number' => $entry['gdt']]) ?></div>
|
<div class="cell c3"><?= $this->element('printGDT', ['number' => $entry['gdt']*100.0]) ?></div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
@ -98,7 +98,7 @@ $this->assign('header', $header);
|
|||||||
<?= $this->Number->format($gdtEntry['factor2']) ?>
|
<?= $this->Number->format($gdtEntry['factor2']) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="cell c3"><?= $this->element('printGDT', ['number' => $gdtEntry['gdt']]) ?></div>
|
<div class="cell c3"><?= $this->element('printGDT', ['number' => $gdtEntry['gdt'] * 100.0]) ?></div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
53
docu/Concepts/Snippets/1-Blockchain/Roles.md
Normal file
53
docu/Concepts/Snippets/1-Blockchain/Roles.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Roles
|
||||||
|
User Roles also handled by blockchain and node servers
|
||||||
|
|
||||||
|
My Goal is to save not only the gradido transactions in blockchain but also
|
||||||
|
who is allowed to create new gradidos,
|
||||||
|
who allow joining new user to the group,
|
||||||
|
who allow connect to another group and
|
||||||
|
how the community decide which one is allowed to do this things.
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
If this would be handled only by community-server everyone could be easly
|
||||||
|
overwrite this rules by using a modified client to send his transactions direct over
|
||||||
|
hedera or iota bypassing the community-server rules.
|
||||||
|
With hedera it is possible to only allow sending messages to a topic with the correct admin key,
|
||||||
|
but then is the admin the single point of failure. Also must the key saved on server to allow everyone
|
||||||
|
sending gradidos or the transactions will only be proccessed, when admin is logging in.
|
||||||
|
If we don't use blockchain technologie at all, we have a big single point of failure.
|
||||||
|
The Community-Server and everyone who has direct access to server and the admins of course.
|
||||||
|
But it would be much much simpler of course :)
|
||||||
|
|
||||||
|
In summary it is to make sure that the community is in power and no one can take over.
|
||||||
|
|
||||||
|
## How?
|
||||||
|
There is a special type of transactions with which users determine who can determine what.
|
||||||
|
This transaction control which signatures are neccessary for things like creation and so one.
|
||||||
|
For this I think different types are needed.
|
||||||
|
- *one*: The founder of group (or someone other choosen) decide everything, this is default from start
|
||||||
|
- *some*: a number of user must sign, set absolute count or relative count
|
||||||
|
- *most*: more than 1/2 or 3/4 must sign
|
||||||
|
- *all*: all member must sign, default for choose which mode will be used
|
||||||
|
- *one-council*: one member of council
|
||||||
|
- *some-council*: absolute or relative number of council members must sign
|
||||||
|
- *most-council*: more than 1/2 or 3/4 from council members must sign
|
||||||
|
- *all-council*: all members of council must sign
|
||||||
|
|
||||||
|
this configuration can be done for different types of action,
|
||||||
|
so the voting-mode for creation may differ from voting mode for
|
||||||
|
add new members to community. Also the council members for different actions
|
||||||
|
may differ.
|
||||||
|
Also how to vote for council members is an extra type of action.
|
||||||
|
|
||||||
|
## Veto
|
||||||
|
Especially for *some* and *some-council* maybe also for other types.
|
||||||
|
The users there could vote but haven't yet and not all need to vote,
|
||||||
|
can make a Veto with Explanation which reset all existing signs of current vote,
|
||||||
|
and is needed to sign by all which again vote for the case.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
With that setup all community consense models should be possible except Democracy.
|
||||||
|
Democracy needs a secret ballot. The votes on blockchain are open (at least if someone knows which
|
||||||
|
public-key belongs to which user). A secret ballot on blockchain is really hard. By my last
|
||||||
|
recherche I haven't found on. But maybe this can do the trick: https://secure.vote/
|
||||||
|
|
||||||
42
docu/Concepts/Snippets/Iota/ColoredCoins.md
Normal file
42
docu/Concepts/Snippets/Iota/ColoredCoins.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Wie Colored Coins in Iota funktionieren
|
||||||
|
## Schöpfung
|
||||||
|
- Colored Coins werden bei Iota mit einer speziellen Transaktion erzeugt
|
||||||
|
- Die Farbe des neuen Coins wird durch den Transaktionshash beschrieben
|
||||||
|
- Die einmal erzeugte Menge von Colored Coins ist fest
|
||||||
|
- Um die Menge zu erhöhen müssten neue Colored Coin erzeugt werden und die alten damit ausgetauscht werden (z.B. mittels SmartContract)
|
||||||
|
|
||||||
|
## Geldmenge
|
||||||
|
- Colored Coins basierend auf den normalen Iota-Coins somit werden soviele Iota-Coins benötigt wie man Colored-Coins braucht
|
||||||
|
- 2.779.530.283.000.000 Iota maximale Coinmenge
|
||||||
|
- Weltbevölkerung 2021: 7.915.559.780
|
||||||
|
- Pro Kopf Geldmenge Gradido: 53.476
|
||||||
|
- Benötigte Iota Coins für Gradido mit 4 Nachkommastellen mit 25% Puffer:
|
||||||
|
- 7.915.559.780 * 534.760.000 * 1.25 = 5.291.155.935.000.000.000
|
||||||
|
- Vorhandene Iota coins: 2.779.530.283.000.000
|
||||||
|
- Es sind nicht genügend Iota Coins vorhanden im die ganze Welt mit Gradido auf Basis von Iota versorgen zu können
|
||||||
|
|
||||||
|
## Kosten
|
||||||
|
- Kurs am 30.08.2021: 1 Miota = 0,84
|
||||||
|
- Bei Verwendung von 4 Nachkommastellen braucht es 10 Miota für 1.000 Colored Coins (Gradido) also Miota im Wert von 8,40€
|
||||||
|
- Aktuell (30.08.2021) geschöpfte Gradido Cent: 17.001.990.500
|
||||||
|
- Notwendige Miota: 17.002.0, Wert: 14.286,73 €
|
||||||
|
- Solange die Benutzer Kontrolle über ihre Keys haben können sie mit einem regulärem Iota Wallet die Gradidos wieder in Iota umwandeln (um z.B. der Vergänglichkeit zu entgehen)
|
||||||
|
- Mit 2 Nachkommastellen wird die Vergänglichkeit schon bei 100 Gradido und 1 Stunde ungenau
|
||||||
|
- 1 Stunde, 100 Gradido, Vergänglichkeit: 0,00576, Gradidos nach einer Stunde: 99,99424 GDD
|
||||||
|
- 1 Minute, 100 Gradido, Vergänglichkeit: 0,000096, Gradidos nach einer Minute: 99,999904 GDD
|
||||||
|
|
||||||
|
## Dust-Protection
|
||||||
|
- Iota erlaubt bei leeren Adressen nur Transaktionen von mindestens 1 Miota
|
||||||
|
- Nachdem 1 Miota da ist sind bis zu 10 Transaktione < 1 Miota erlaubt, bevor ein weitere Transaktion mit mindestens 1 Miota eingehen muss
|
||||||
|
- Bei Verwendung von 4 Nachkommastellen entspricht das 100 GDD, bei 2 Nachkommastellen 10.000 GDD
|
||||||
|
|
||||||
|
## Lösung
|
||||||
|
Wir können nur 3 Nachkommastellen verwenden.
|
||||||
|
### Kosten
|
||||||
|
- 0,84 € für 1.000 GDD
|
||||||
|
- 1.428 Euro für alle bisherigen geschöpften Gradidos
|
||||||
|
### Dust-Protection
|
||||||
|
- 1.000 GDD entspricht 1 Miota, die erste Schöpfung muss also zwangsläufig 1k Gradido betragen
|
||||||
|
- Jeder kann nur maximal 10 Transaktionen < 1k GDD empfangen bevor er die GDD weitergesendet haben muss um neue erhalten zu können oder eine neue Schöpfung von 1k GDD bekommen hat
|
||||||
|
|
||||||
|
|
||||||
1
docu/Concepts/Snippets/images/classes.drawio
Normal file
1
docu/Concepts/Snippets/images/classes.drawio
Normal file
@ -0,0 +1 @@
|
|||||||
|
<mxfile host="7d619c52-f8a9-4b9d-82fe-1aa45d350dea" modified="2021-08-07T11:49:26.921Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.58.2 Chrome/89.0.4389.128 Electron/12.0.13 Safari/537.36" etag="5tat3B3yItVGc6mcvaQ1" version="12.2.4" pages="1"><diagram id="1SuIEZF2QCnWeueF3Zz_" name="Page-1">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</diagram></mxfile>
|
||||||
BIN
docu/Concepts/Snippets/images/classes.png
Normal file
BIN
docu/Concepts/Snippets/images/classes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
1
docu/Concepts/Snippets/images/example_blockchain.drawio
Normal file
1
docu/Concepts/Snippets/images/example_blockchain.drawio
Normal file
@ -0,0 +1 @@
|
|||||||
|
<mxfile host="11f51089-224b-4c51-8025-2a587ac1ee54" modified="2021-08-08T15:21:15.636Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.58.2 Chrome/89.0.4389.128 Electron/12.0.13 Safari/537.36" etag="Ph0quYraKNcgZ1LpaOqw" version="12.2.4" pages="1"><diagram id="svTVmLC50Oi8Ao2eC_wi" name="Page-1">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</diagram></mxfile>
|
||||||
BIN
docu/Concepts/Snippets/images/example_blockchain.png
Normal file
BIN
docu/Concepts/Snippets/images/example_blockchain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
1
docu/Concepts/Snippets/images/iota.drawio
Normal file
1
docu/Concepts/Snippets/images/iota.drawio
Normal file
@ -0,0 +1 @@
|
|||||||
|
<mxfile host="c8c9d8b1-9d45-405b-9350-947d02163aae" modified="2021-08-13T14:14:22.645Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.59.0 Chrome/91.0.4472.124 Electron/13.1.7 Safari/537.36" etag="M5WsFcVCZVYdDRxEgPr7" version="12.2.4" pages="1"><diagram id="4VYGDKFA-XGvTikjH5B0" name="Page-1">zVlLc+MoEP41Os6U9bRz9GMym9qaSmqTqp3sjUjYYoOEF6HYmV+/DQJLCHnieJRkLjK0oNV099cP7IXLYv+Vo23+jWWYesEk23vhyguCaRLAUxKeNWEaN4QNJ1lD8lvCLfmBNXGiqTXJcGUtFIxRQbY2MWVliVNh0RDnbGcvWzNqf3WLNtgh3KaIutS/SSbyhjoLpi39D0w2ufmyn1w0bwpkFuuTVDnK2K5DCr944ZIzJppRsV9iKnVn9NLsuzzy9iAYx6U4aYNW/BOitT7c1fXdXAsnns2JYRcoFyYLkHgriSllNTBZ7HIi8O0WpZK4A3MDLRcFhZkPQ1cgLeMT5gLvOyQt4FfMCiz4MyzRb8MLrSztLWa6a1XvG33mHbXPNA1pa28OnFuFwEDr5Ih+Ekc/4NIZydgdR2WFUkFY6WiLs7rMsGQxeRcNzWwF+ZMTNZSMoaGpoyHXe8psLmGn3AZVFUltFeA9Ed8743upuc+xnq32WpFq8mwmJQj6XS0EI+m53hibebtVzay9N5gTOC3mmnjUDhWreYptfxCIb7BZpjGEMytquNbqmCMesIahcUyRIE92rBkykf7CDSMg8TFnCKKekZvj6E3d0NDj44c9r7roMWp04DBSDnM49Wk+NHNR9td8dbW6/uwFCSokYihoaYEoga8b0kYczNZxNsCMsN2L44r8QA9qgbT0VoqsDhEvvHgl+daCVU2a8ZvPbEoYU7yWrCQQCUT/uSYLJr9eAaJJubmTk9WnaBwkB7OoB+WZC2V/wHmCEaBseHTMQEklcKnyKzxeYZREvXrgMFIUi5FeWj5U8qcgFFeClZDRg0tI2WvCCwiefbuaxLPlLMVV9XJgfUDp40aF4utaUFIa646RknrYCEI34gZDZhoj4poA+ysR97Rg91sHtrCf308NbFEQfp5Mkwswmnr6w6YcP8wFoWO4GzCUDCJtMVEddXwQAPMS0VvBuCpQPxAA8cv+7ydvVJMF0Xv5/0CyNzb8TTDhJOnpudm+Xza8IQzcnsPki9w3+eKfGlY8Um8ZevOIy8zRrADm7SJD3BrCn6woVJbJCIbnN8gTgJRKfkyW6ZMrJpDsHykmaQ6DEqmfDBfS9GoPYKAC78FSN7uaZ4odQEgeAJhzxYsfNh2SlxcsFZEfOD3Ai0Z+QTaSXY7kkzVrHo2ozWJUK0kKpBplpAQLLzun3raHfrHgqQRnj3jJKJPFbSmlCxdrQmmPpEsYIMROQRMca10YaGhNFbRykkn9QIVlNTxjxJfIdsckdPPrJHZh5ffd9qwA45ajxhCgo9LSfvJfLXv1RlOfqkZVc+lajCtjmgXGfGvpEouldIF/cSZNrxtKGFk95WSHaZpj5XfSl1tHcz1LOWrHWRoxj/jLGd2pY7gB8x4vluLYTtzRicnCH6OoDd2i9tXZwvSnbU9633kz3J8OpokXU445sZVyZh+ZYXqZPj67nZzYjKK3aydNRfczk787CCIbBLE/AILZgBnH6BjCETqGzn3L4Xrl3uvergzftZyJg5mLg/BDK60eDpJ+bDoXB3G/YhsRB0P9BmSlkqm8s8w5K0kqHeByxKLCXJ6kuFSXa871SQFVAz3WvgxVEr8EvCjqV8ixC7zJT/zmFcCDaXt13xis/f8j/PI/</diagram></mxfile>
|
||||||
BIN
docu/Concepts/Snippets/images/iota.png
Normal file
BIN
docu/Concepts/Snippets/images/iota.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@ -72,6 +72,7 @@
|
|||||||
"vue-good-table": "^2.21.3",
|
"vue-good-table": "^2.21.3",
|
||||||
"vue-i18n": "^8.22.4",
|
"vue-i18n": "^8.22.4",
|
||||||
"vue-jest": "^3.0.7",
|
"vue-jest": "^3.0.7",
|
||||||
|
"vue-jwt-decode": "^0.1.0",
|
||||||
"vue-loading-overlay": "^3.4.2",
|
"vue-loading-overlay": "^3.4.2",
|
||||||
"vue-moment": "^4.1.0",
|
"vue-moment": "^4.1.0",
|
||||||
"vue-qrcode": "^0.3.5",
|
"vue-qrcode": "^0.3.5",
|
||||||
|
|||||||
@ -15,7 +15,6 @@ describe('LanguageSwitch', () => {
|
|||||||
let wrapper
|
let wrapper
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
sessionId: 1234,
|
|
||||||
email: 'he@ho.he',
|
email: 'he@ho.he',
|
||||||
language: null,
|
language: null,
|
||||||
}
|
}
|
||||||
@ -123,7 +122,6 @@ describe('LanguageSwitch', () => {
|
|||||||
expect(updateUserInfosQueryMock).toBeCalledWith(
|
expect(updateUserInfosQueryMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1234,
|
|
||||||
email: 'he@ho.he',
|
email: 'he@ho.he',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
},
|
},
|
||||||
@ -136,7 +134,6 @@ describe('LanguageSwitch', () => {
|
|||||||
expect(updateUserInfosQueryMock).toBeCalledWith(
|
expect(updateUserInfosQueryMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1234,
|
|
||||||
email: 'he@ho.he',
|
email: 'he@ho.he',
|
||||||
locale: 'de',
|
locale: 'de',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -32,13 +32,13 @@ export default {
|
|||||||
localeChanged(locale)
|
localeChanged(locale)
|
||||||
},
|
},
|
||||||
async saveLocale(locale) {
|
async saveLocale(locale) {
|
||||||
|
// if (this.$i18n.locale === locale) return
|
||||||
this.setLocale(locale)
|
this.setLocale(locale)
|
||||||
if (this.$store.state.sessionId && this.$store.state.email) {
|
if (this.$store.state.email) {
|
||||||
this.$apollo
|
this.$apollo
|
||||||
.query({
|
.query({
|
||||||
query: updateUserInfos,
|
query: updateUserInfos,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
email: this.$store.state.email,
|
email: this.$store.state.email,
|
||||||
locale: locale,
|
locale: locale,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,23 +2,13 @@ import gql from 'graphql-tag'
|
|||||||
|
|
||||||
export const login = gql`
|
export const login = gql`
|
||||||
query($email: String!, $password: String!) {
|
query($email: String!, $password: String!) {
|
||||||
login(email: $email, password: $password) {
|
login(email: $email, password: $password)
|
||||||
sessionId
|
|
||||||
user {
|
|
||||||
email
|
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
language
|
|
||||||
username
|
|
||||||
description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const logout = gql`
|
export const logout = gql`
|
||||||
query($sessionId: Float!) {
|
query {
|
||||||
logout(sessionId: $sessionId)
|
logout
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -39,7 +29,6 @@ export const loginViaEmailVerificationCode = gql`
|
|||||||
|
|
||||||
export const updateUserInfos = gql`
|
export const updateUserInfos = gql`
|
||||||
query(
|
query(
|
||||||
$sessionId: Float!
|
|
||||||
$email: String!
|
$email: String!
|
||||||
$firstName: String
|
$firstName: String
|
||||||
$lastName: String
|
$lastName: String
|
||||||
@ -50,7 +39,6 @@ export const updateUserInfos = gql`
|
|||||||
$locale: String
|
$locale: String
|
||||||
) {
|
) {
|
||||||
updateUserInfos(
|
updateUserInfos(
|
||||||
sessionId: $sessionId
|
|
||||||
email: $email
|
email: $email
|
||||||
firstName: $firstName
|
firstName: $firstName
|
||||||
lastName: $lastName
|
lastName: $lastName
|
||||||
@ -66,8 +54,8 @@ export const updateUserInfos = gql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const transactionsQuery = gql`
|
export const transactionsQuery = gql`
|
||||||
query($sessionId: Float!, $firstPage: Int = 1, $items: Int = 25, $order: String = "DESC") {
|
query($firstPage: Int = 1, $items: Int = 25, $order: String = "DESC") {
|
||||||
transactionList(sessionId: $sessionId, firstPage: $firstPage, items: $items, order: $order) {
|
transactionList(firstPage: $firstPage, items: $items, order: $order) {
|
||||||
gdtSum
|
gdtSum
|
||||||
count
|
count
|
||||||
balance
|
balance
|
||||||
@ -115,8 +103,8 @@ export const resgisterUserQuery = gql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const sendCoins = gql`
|
export const sendCoins = gql`
|
||||||
query($sessionId: Float!, $email: String!, $amount: Float!, $memo: String!) {
|
query($email: String!, $amount: Float!, $memo: String!) {
|
||||||
sendCoins(sessionId: $sessionId, email: $email, amount: $amount, memo: $memo)
|
sendCoins(email: $email, amount: $amount, memo: $memo)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -137,10 +125,11 @@ export const checkUsername = gql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
export const listGDTEntriesQuery = gql`
|
export const listGDTEntriesQuery = gql`
|
||||||
query($currentPage: Int!, $pageSize: Int!, $sessionId: Float!) {
|
query($currentPage: Int!, $pageSize: Int!) {
|
||||||
listGDTEntries(currentPage: $currentPage, pageSize: $pageSize, sessionId: $sessionId) {
|
listGDTEntries(currentPage: $currentPage, pageSize: $pageSize) {
|
||||||
count
|
count
|
||||||
gdtEntries {
|
gdtEntries {
|
||||||
|
id
|
||||||
amount
|
amount
|
||||||
date
|
date
|
||||||
comment
|
comment
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en": "English"
|
"en": "English"
|
||||||
},
|
},
|
||||||
|
"select_language": "Bitte wähle eine Sprache für die App und Newsletter",
|
||||||
"decay": {
|
"decay": {
|
||||||
"decay": "Vergänglichkeit",
|
"decay": "Vergänglichkeit",
|
||||||
"decay_since_last_transaction":"Vergänglichkeit seit der letzten Transaktion",
|
"decay_since_last_transaction":"Vergänglichkeit seit der letzten Transaktion",
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
"de": "Deutsch",
|
"de": "Deutsch",
|
||||||
"en": "English"
|
"en": "English"
|
||||||
},
|
},
|
||||||
|
"select_language": "Please choose a language for the app and newsletter",
|
||||||
"decay": {
|
"decay": {
|
||||||
"decay": "Decay",
|
"decay": "Decay",
|
||||||
"decay_since_last_transaction":"Decay since the last transaction",
|
"decay_since_last_transaction":"Decay since the last transaction",
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import DashboardPlugin from './plugins/dashboard-plugin'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import i18n from './i18n.js'
|
import i18n from './i18n.js'
|
||||||
import { loadAllRules } from './validation-rules'
|
import { loadAllRules } from './validation-rules'
|
||||||
import ApolloClient from 'apollo-boost'
|
import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost'
|
||||||
import VueApollo from 'vue-apollo'
|
import VueApollo from 'vue-apollo'
|
||||||
import CONFIG from './config'
|
import CONFIG from './config'
|
||||||
|
|
||||||
@ -11,7 +11,21 @@ import { store } from './store/store'
|
|||||||
|
|
||||||
import router from './routes/router'
|
import router from './routes/router'
|
||||||
|
|
||||||
|
const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI })
|
||||||
|
|
||||||
|
const authLink = new ApolloLink((operation, forward) => {
|
||||||
|
const token = store.state.token
|
||||||
|
operation.setContext({
|
||||||
|
headers: {
|
||||||
|
Authorization: token && token.length > 0 ? `Bearer ${token}` : '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return forward(operation)
|
||||||
|
})
|
||||||
|
|
||||||
const apolloClient = new ApolloClient({
|
const apolloClient = new ApolloClient({
|
||||||
|
link: authLink.concat(httpLink),
|
||||||
|
cache: new InMemoryCache(),
|
||||||
uri: CONFIG.GRAPHQL_URI,
|
uri: CONFIG.GRAPHQL_URI,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -26,7 +40,7 @@ Vue.config.productionTip = false
|
|||||||
loadAllRules(i18n)
|
loadAllRules(i18n)
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
if (to.meta.requiresAuth && !store.state.sessionId) {
|
if (to.meta.requiresAuth && !store.state.token) {
|
||||||
next({ path: '/login' })
|
next({ path: '/login' })
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import createPersistedState from 'vuex-persistedstate'
|
import createPersistedState from 'vuex-persistedstate'
|
||||||
|
import VueJwtDecode from 'vue-jwt-decode'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
@ -10,9 +12,6 @@ export const mutations = {
|
|||||||
email: (state, email) => {
|
email: (state, email) => {
|
||||||
state.email = email
|
state.email = email
|
||||||
},
|
},
|
||||||
sessionId: (state, sessionId) => {
|
|
||||||
state.sessionId = sessionId
|
|
||||||
},
|
|
||||||
username: (state, username) => {
|
username: (state, username) => {
|
||||||
state.username = username
|
state.username = username
|
||||||
},
|
},
|
||||||
@ -25,43 +24,47 @@ export const mutations = {
|
|||||||
description: (state, description) => {
|
description: (state, description) => {
|
||||||
state.description = description
|
state.description = description
|
||||||
},
|
},
|
||||||
|
token: (state, token) => {
|
||||||
|
state.token = token
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
login: ({ dispatch, commit }, data) => {
|
login: ({ dispatch, commit }, token) => {
|
||||||
commit('sessionId', data.sessionId)
|
const decoded = VueJwtDecode.decode(token)
|
||||||
commit('email', data.user.email)
|
commit('token', token)
|
||||||
commit('language', data.user.language)
|
commit('email', decoded.email)
|
||||||
commit('username', data.user.username)
|
commit('language', decoded.language)
|
||||||
commit('firstName', data.user.firstName)
|
commit('username', decoded.username)
|
||||||
commit('lastName', data.user.lastName)
|
commit('firstName', decoded.firstName)
|
||||||
commit('description', data.user.description)
|
commit('lastName', decoded.lastName)
|
||||||
|
commit('description', decoded.description)
|
||||||
},
|
},
|
||||||
logout: ({ commit, state }) => {
|
logout: ({ commit, state }) => {
|
||||||
commit('sessionId', null)
|
commit('token', null)
|
||||||
commit('email', null)
|
commit('email', null)
|
||||||
commit('username', '')
|
commit('username', '')
|
||||||
commit('firstName', '')
|
commit('firstName', '')
|
||||||
commit('lastName', '')
|
commit('lastName', '')
|
||||||
commit('description', '')
|
commit('description', '')
|
||||||
sessionStorage.clear()
|
localStorage.clear()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const store = new Vuex.Store({
|
export const store = new Vuex.Store({
|
||||||
plugins: [
|
plugins: [
|
||||||
createPersistedState({
|
createPersistedState({
|
||||||
storage: window.sessionStorage,
|
storage: window.localStorage,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
state: {
|
state: {
|
||||||
sessionId: null,
|
|
||||||
email: '',
|
email: '',
|
||||||
language: null,
|
language: null,
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
username: '',
|
username: '',
|
||||||
description: '',
|
description: '',
|
||||||
|
token: null,
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
// Syncronous mutation of the state
|
// Syncronous mutation of the state
|
||||||
|
|||||||
@ -1,6 +1,17 @@
|
|||||||
import { mutations, actions } from './store'
|
import { mutations, actions } from './store'
|
||||||
|
import VueJwtDecode from 'vue-jwt-decode'
|
||||||
|
|
||||||
const { language, email, sessionId, username, firstName, lastName, description } = mutations
|
jest.mock('vue-jwt-decode')
|
||||||
|
VueJwtDecode.decode.mockReturnValue({
|
||||||
|
email: 'user@example.org',
|
||||||
|
language: 'de',
|
||||||
|
username: 'peter',
|
||||||
|
firstName: 'Peter',
|
||||||
|
lastName: 'Lustig',
|
||||||
|
description: 'Nickelbrille',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { language, email, token, username, firstName, lastName, description } = mutations
|
||||||
const { login, logout } = actions
|
const { login, logout } = actions
|
||||||
|
|
||||||
describe('Vuex store', () => {
|
describe('Vuex store', () => {
|
||||||
@ -21,11 +32,11 @@ describe('Vuex store', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('sessionId', () => {
|
describe('token', () => {
|
||||||
it('sets the state of sessionId', () => {
|
it('sets the state of token', () => {
|
||||||
const state = { sessionId: null }
|
const state = { token: null }
|
||||||
sessionId(state, '1234')
|
token(state, '1234')
|
||||||
expect(state.sessionId).toEqual('1234')
|
expect(state.token).toEqual('1234')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -66,41 +77,31 @@ describe('Vuex store', () => {
|
|||||||
describe('login', () => {
|
describe('login', () => {
|
||||||
const commit = jest.fn()
|
const commit = jest.fn()
|
||||||
const state = {}
|
const state = {}
|
||||||
const commitedData = {
|
const commitedData = 'token'
|
||||||
sessionId: 1234,
|
|
||||||
user: {
|
|
||||||
email: 'someone@there.is',
|
|
||||||
language: 'en',
|
|
||||||
username: 'user',
|
|
||||||
firstName: 'Peter',
|
|
||||||
lastName: 'Lustig',
|
|
||||||
description: 'Nickelbrille',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
it('calls seven commits', () => {
|
it('calls seven commits', () => {
|
||||||
login({ commit, state }, commitedData)
|
login({ commit, state }, commitedData)
|
||||||
expect(commit).toHaveBeenCalledTimes(7)
|
expect(commit).toHaveBeenCalledTimes(7)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits sessionId', () => {
|
it('commits token', () => {
|
||||||
login({ commit, state }, commitedData)
|
login({ commit, state }, commitedData)
|
||||||
expect(commit).toHaveBeenNthCalledWith(1, 'sessionId', 1234)
|
expect(commit).toHaveBeenNthCalledWith(1, 'token', 'token')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits email', () => {
|
it('commits email', () => {
|
||||||
login({ commit, state }, commitedData)
|
login({ commit, state }, commitedData)
|
||||||
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'someone@there.is')
|
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'user@example.org')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits language', () => {
|
it('commits language', () => {
|
||||||
login({ commit, state }, commitedData)
|
login({ commit, state }, commitedData)
|
||||||
expect(commit).toHaveBeenNthCalledWith(3, 'language', 'en')
|
expect(commit).toHaveBeenNthCalledWith(3, 'language', 'de')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits username', () => {
|
it('commits username', () => {
|
||||||
login({ commit, state }, commitedData)
|
login({ commit, state }, commitedData)
|
||||||
expect(commit).toHaveBeenNthCalledWith(4, 'username', 'user')
|
expect(commit).toHaveBeenNthCalledWith(4, 'username', 'peter')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits firstName', () => {
|
it('commits firstName', () => {
|
||||||
@ -128,9 +129,9 @@ describe('Vuex store', () => {
|
|||||||
expect(commit).toHaveBeenCalledTimes(6)
|
expect(commit).toHaveBeenCalledTimes(6)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits sessionId', () => {
|
it('commits token', () => {
|
||||||
logout({ commit, state })
|
logout({ commit, state })
|
||||||
expect(commit).toHaveBeenNthCalledWith(1, 'sessionId', null)
|
expect(commit).toHaveBeenNthCalledWith(1, 'token', null)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('commits email', () => {
|
it('commits email', () => {
|
||||||
@ -159,7 +160,7 @@ describe('Vuex store', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// how to get this working?
|
// how to get this working?
|
||||||
it.skip('calls sessionStorage.clear()', () => {
|
it.skip('calls localStorage.clear()', () => {
|
||||||
const clearStorageMock = jest.fn()
|
const clearStorageMock = jest.fn()
|
||||||
global.sessionStorage = jest.fn(() => {
|
global.sessionStorage = jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -41,7 +41,6 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
},
|
},
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
},
|
},
|
||||||
dispatch: storeDispatchMock,
|
dispatch: storeDispatchMock,
|
||||||
@ -128,16 +127,17 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
|
|
||||||
describe('logout', () => {
|
describe('logout', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
await apolloMock.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
logout: 'success',
|
||||||
|
},
|
||||||
|
})
|
||||||
await wrapper.findComponent({ name: 'sidebar' }).vm.$emit('logout')
|
await wrapper.findComponent({ name: 'sidebar' }).vm.$emit('logout')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calls the API', async () => {
|
it('calls the API', async () => {
|
||||||
expect(apolloMock).toBeCalledWith(
|
await expect(apolloMock).toBeCalled()
|
||||||
expect.objectContaining({
|
|
||||||
variables: { sessionId: 1 },
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('dispatches logout to store', () => {
|
it('dispatches logout to store', () => {
|
||||||
@ -196,7 +196,6 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
expect(apolloMock).toBeCalledWith(
|
expect(apolloMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
firstPage: 2,
|
firstPage: 2,
|
||||||
items: 5,
|
items: 5,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -92,7 +92,6 @@ export default {
|
|||||||
this.$apollo
|
this.$apollo
|
||||||
.query({
|
.query({
|
||||||
query: logout,
|
query: logout,
|
||||||
variables: { sessionId: this.$store.state.sessionId },
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$sidebar.displaySidebar(false)
|
this.$sidebar.displaySidebar(false)
|
||||||
@ -111,7 +110,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: transactionsQuery,
|
query: transactionsQuery,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
firstPage: pagination.firstPage,
|
firstPage: pagination.firstPage,
|
||||||
items: pagination.items,
|
items: pagination.items,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,12 +16,12 @@ describe('AccountOverview', () => {
|
|||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
|
$n: jest.fn((n) => String(n)),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
email: 'sender@example.org',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
$n: jest.fn((n) => String(n)),
|
|
||||||
$apollo: {
|
$apollo: {
|
||||||
query: sendMock,
|
query: sendMock,
|
||||||
},
|
},
|
||||||
@ -93,7 +93,6 @@ describe('AccountOverview', () => {
|
|||||||
expect(sendMock).toBeCalledWith(
|
expect(sendMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
amount: 23.45,
|
amount: 23.45,
|
||||||
memo: 'Make the best of it!',
|
memo: 'Make the best of it!',
|
||||||
|
|||||||
@ -107,10 +107,7 @@ export default {
|
|||||||
this.$apollo
|
this.$apollo
|
||||||
.query({
|
.query({
|
||||||
query: sendCoins,
|
query: sendCoins,
|
||||||
variables: {
|
variables: this.transactionData,
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
...this.transactionData,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.error = false
|
this.error = false
|
||||||
|
|||||||
@ -8,11 +8,6 @@ describe('GddSend', () => {
|
|||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$store: {
|
|
||||||
state: {
|
|
||||||
sessionId: 1234,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
$i18n: {
|
$i18n: {
|
||||||
locale: jest.fn(() => 'en'),
|
locale: jest.fn(() => 'en'),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -57,11 +57,6 @@ describe('GdtTransactionList', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$n: jest.fn((n) => n),
|
$n: jest.fn((n) => n),
|
||||||
$d: jest.fn((d) => d),
|
$d: jest.fn((d) => d),
|
||||||
$store: {
|
|
||||||
state: {
|
|
||||||
sessionId: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
$toasted: {
|
$toasted: {
|
||||||
error: toastErrorMock,
|
error: toastErrorMock,
|
||||||
},
|
},
|
||||||
@ -89,7 +84,6 @@ describe('GdtTransactionList', () => {
|
|||||||
expect(apolloMock).toBeCalledWith(
|
expect(apolloMock).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 25,
|
pageSize: 25,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -163,10 +163,19 @@
|
|||||||
import { listGDTEntriesQuery } from '../../../graphql/queries'
|
import { listGDTEntriesQuery } from '../../../graphql/queries'
|
||||||
import PaginationButtons from '../../../components/PaginationButtons'
|
import PaginationButtons from '../../../components/PaginationButtons'
|
||||||
|
|
||||||
const iconsByType = {
|
function iconByType(typeId) {
|
||||||
1: { icon: 'heart', classes: 'gradido-global-color-accent' },
|
switch (typeId) {
|
||||||
4: { icon: 'person-check', classes: 'gradido-global-color-accent' },
|
case 1:
|
||||||
7: { icon: 'gift', classes: 'gradido-global-color-accent' },
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
return { icon: 'heart', classes: 'gradido-global-color-accent' }
|
||||||
|
case 4:
|
||||||
|
return { icon: 'person-check', classes: 'gradido-global-color-accent' }
|
||||||
|
case 7:
|
||||||
|
return { icon: 'gift', classes: 'gradido-global-color-accent' }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -199,7 +208,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: listGDTEntriesQuery,
|
query: listGDTEntriesQuery,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
currentPage: this.currentPage,
|
currentPage: this.currentPage,
|
||||||
pageSize: this.pageSize,
|
pageSize: this.pageSize,
|
||||||
},
|
},
|
||||||
@ -216,7 +224,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
getIcon(givenType) {
|
getIcon(givenType) {
|
||||||
const type = iconsByType[givenType]
|
const type = iconByType(givenType)
|
||||||
if (type)
|
if (type)
|
||||||
return {
|
return {
|
||||||
icon: type.icon,
|
icon: type.icon,
|
||||||
|
|||||||
@ -6,12 +6,7 @@ const localVue = global.localVue
|
|||||||
|
|
||||||
const loginQueryMock = jest.fn().mockResolvedValue({
|
const loginQueryMock = jest.fn().mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
login: {
|
login: 'token',
|
||||||
sessionId: 1,
|
|
||||||
user: {
|
|
||||||
name: 'Peter Lustig',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -159,10 +154,7 @@ describe('Login', () => {
|
|||||||
|
|
||||||
describe('login success', () => {
|
describe('login success', () => {
|
||||||
it('dispatches server response to store', () => {
|
it('dispatches server response to store', () => {
|
||||||
expect(mockStoreDispach).toBeCalledWith('login', {
|
expect(mockStoreDispach).toBeCalledWith('login', 'token')
|
||||||
sessionId: 1,
|
|
||||||
user: { name: 'Peter Lustig' },
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('redirects to overview page', () => {
|
it('redirects to overview page', () => {
|
||||||
|
|||||||
@ -85,6 +85,13 @@ describe('Register', () => {
|
|||||||
it('has password repeat input fields', () => {
|
it('has password repeat input fields', () => {
|
||||||
expect(wrapper.find('input[name="form.passwordRepeat"]').exists()).toBeTruthy()
|
expect(wrapper.find('input[name="form.passwordRepeat"]').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
it('has Language selected field', () => {
|
||||||
|
expect(wrapper.find('#selectedLanguage').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
it('selected Language value de', async () => {
|
||||||
|
wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected()
|
||||||
|
expect(wrapper.find('#selectedLanguage').element.value).toBe('de')
|
||||||
|
})
|
||||||
|
|
||||||
it('has 1 checkbox input fields', () => {
|
it('has 1 checkbox input fields', () => {
|
||||||
expect(wrapper.find('#registerCheckbox').exists()).toBeTruthy()
|
expect(wrapper.find('#registerCheckbox').exists()).toBeTruthy()
|
||||||
@ -126,9 +133,16 @@ describe('Register', () => {
|
|||||||
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
||||||
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
||||||
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
||||||
|
wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected()
|
||||||
wrapper.find('input[name="site.signup.agree"]').setChecked(true)
|
wrapper.find('input[name="site.signup.agree"]').setChecked(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('reset selected value language', async () => {
|
||||||
|
await wrapper.find('button.ml-2').trigger('click')
|
||||||
|
await flushPromises()
|
||||||
|
expect(wrapper.find('#selectedLanguage').element.value).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
it('resets the firstName field after clicking the reset button', async () => {
|
it('resets the firstName field after clicking the reset button', async () => {
|
||||||
await wrapper.find('button.ml-2').trigger('click')
|
await wrapper.find('button.ml-2').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
@ -173,6 +187,7 @@ describe('Register', () => {
|
|||||||
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
||||||
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
||||||
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
||||||
|
wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('server sends back error', () => {
|
describe('server sends back error', () => {
|
||||||
|
|||||||
@ -84,6 +84,18 @@
|
|||||||
:register="register"
|
:register="register"
|
||||||
></input-password-confirmation>
|
></input-password-confirmation>
|
||||||
|
|
||||||
|
<b-row>
|
||||||
|
<b-col cols="12">
|
||||||
|
{{ $t('language') }}
|
||||||
|
<b-form-select
|
||||||
|
id="selectedLanguage"
|
||||||
|
v-model="selected"
|
||||||
|
:options="options"
|
||||||
|
class="mb-3"
|
||||||
|
></b-form-select>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
<b-row class="my-4">
|
<b-row class="my-4">
|
||||||
<b-col cols="12">
|
<b-col cols="12">
|
||||||
<b-form-checkbox
|
<b-form-checkbox
|
||||||
@ -109,7 +121,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</b-alert>
|
</b-alert>
|
||||||
|
|
||||||
<div class="text-center" v-if="namesFilled && emailFilled && form.agree">
|
<div
|
||||||
|
class="text-center"
|
||||||
|
v-if="namesFilled && emailFilled && form.agree && languageFilled"
|
||||||
|
>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<b-button class="ml-2" @click="resetForm()">{{ $t('form.reset') }}</b-button>
|
<b-button class="ml-2" @click="resetForm()">{{ $t('form.reset') }}</b-button>
|
||||||
<b-button type="submit" variant="primary">{{ $t('signup') }}</b-button>
|
<b-button type="submit" variant="primary">{{ $t('signup') }}</b-button>
|
||||||
@ -147,6 +162,12 @@ export default {
|
|||||||
passwordRepeat: '',
|
passwordRepeat: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
selected: null,
|
||||||
|
options: [
|
||||||
|
{ value: null, text: this.$t('select_language') },
|
||||||
|
{ value: 'de', text: this.$t('languages.de') },
|
||||||
|
{ value: 'en', text: this.$t('languages.en') },
|
||||||
|
],
|
||||||
submitted: false,
|
submitted: false,
|
||||||
showError: false,
|
showError: false,
|
||||||
messageError: '',
|
messageError: '',
|
||||||
@ -168,8 +189,7 @@ export default {
|
|||||||
},
|
},
|
||||||
agree: false,
|
agree: false,
|
||||||
}
|
}
|
||||||
this.form.password.password = ''
|
this.selected = null
|
||||||
this.form.password.passwordRepeat = ''
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.observer.reset()
|
this.$refs.observer.reset()
|
||||||
})
|
})
|
||||||
@ -183,7 +203,7 @@ export default {
|
|||||||
firstName: this.form.firstname,
|
firstName: this.form.firstname,
|
||||||
lastName: this.form.lastname,
|
lastName: this.form.lastname,
|
||||||
password: this.form.password.password,
|
password: this.form.password.password,
|
||||||
language: this.$store.state.language,
|
language: this.selected,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -192,6 +212,7 @@ export default {
|
|||||||
this.form.lastname = ''
|
this.form.lastname = ''
|
||||||
this.form.password.password = ''
|
this.form.password.password = ''
|
||||||
this.form.password.passwordRepeat = ''
|
this.form.password.passwordRepeat = ''
|
||||||
|
this.selected = null
|
||||||
this.$router.push('/thx/register')
|
this.$router.push('/thx/register')
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -207,6 +228,7 @@ export default {
|
|||||||
this.form.lastname = ''
|
this.form.lastname = ''
|
||||||
this.form.password.password = ''
|
this.form.password.password = ''
|
||||||
this.form.password.passwordRepeat = ''
|
this.form.password.passwordRepeat = ''
|
||||||
|
this.selected = null
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -221,6 +243,9 @@ export default {
|
|||||||
emailFilled() {
|
emailFilled() {
|
||||||
return this.form.email !== ''
|
return this.form.email !== ''
|
||||||
},
|
},
|
||||||
|
languageFilled() {
|
||||||
|
return this.selected !== null
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -17,7 +17,6 @@ describe('UserCard_FormUserData', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
firstName: 'Peter',
|
firstName: 'Peter',
|
||||||
lastName: 'Lustig',
|
lastName: 'Lustig',
|
||||||
@ -118,7 +117,6 @@ describe('UserCard_FormUserData', () => {
|
|||||||
expect(mockAPIcall).toBeCalledWith(
|
expect(mockAPIcall).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
firstName: 'Petra',
|
firstName: 'Petra',
|
||||||
lastName: 'Lustiger',
|
lastName: 'Lustiger',
|
||||||
@ -167,7 +165,6 @@ describe('UserCard_FormUserData', () => {
|
|||||||
expect(mockAPIcall).toBeCalledWith(
|
expect(mockAPIcall).toBeCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
firstName: 'Petra',
|
firstName: 'Petra',
|
||||||
lastName: 'Lustiger',
|
lastName: 'Lustiger',
|
||||||
|
|||||||
@ -85,7 +85,6 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showUserData: true,
|
showUserData: true,
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
form: {
|
form: {
|
||||||
firstName: this.$store.state.firstName,
|
firstName: this.$store.state.firstName,
|
||||||
lastName: this.$store.state.lastName,
|
lastName: this.$store.state.lastName,
|
||||||
@ -118,7 +117,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: updateUserInfos,
|
query: updateUserInfos,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
email: this.$store.state.email,
|
email: this.$store.state.email,
|
||||||
firstName: this.form.firstName,
|
firstName: this.form.firstName,
|
||||||
lastName: this.form.lastName,
|
lastName: this.form.lastName,
|
||||||
|
|||||||
@ -14,7 +14,6 @@ describe('UserCard_FormUserMail', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
firstName: 'Peter',
|
firstName: 'Peter',
|
||||||
lastName: 'Lustig',
|
lastName: 'Lustig',
|
||||||
@ -76,7 +75,6 @@ describe('UserCard_FormUserMail', () => {
|
|||||||
expect(mockAPIcall).toHaveBeenCalledWith(
|
expect(mockAPIcall).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
newEmail: 'test@example.org',
|
newEmail: 'test@example.org',
|
||||||
},
|
},
|
||||||
@ -106,7 +104,6 @@ describe('UserCard_FormUserMail', () => {
|
|||||||
expect(mockAPIcall).toHaveBeenCalledWith(
|
expect(mockAPIcall).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
newEmail: 'test@example.org',
|
newEmail: 'test@example.org',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -48,7 +48,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: updateUserInfos,
|
query: updateUserInfos,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
email: this.$store.state.email,
|
email: this.$store.state.email,
|
||||||
newEmail: this.newEmail,
|
newEmail: this.newEmail,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -17,7 +17,6 @@ describe('UserCard_FormUserPasswort', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -175,7 +174,6 @@ describe('UserCard_FormUserPasswort', () => {
|
|||||||
expect(changePasswordProfileMock).toHaveBeenCalledWith(
|
expect(changePasswordProfileMock).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
password: '1234',
|
password: '1234',
|
||||||
passwordNew: 'Aa123456',
|
passwordNew: 'Aa123456',
|
||||||
|
|||||||
@ -81,7 +81,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: updateUserInfos,
|
query: updateUserInfos,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
email: this.$store.state.email,
|
email: this.$store.state.email,
|
||||||
password: this.form.password,
|
password: this.form.password,
|
||||||
passwordNew: this.form.newPassword.password,
|
passwordNew: this.form.newPassword.password,
|
||||||
|
|||||||
@ -25,7 +25,6 @@ describe('UserCard_FormUsername', () => {
|
|||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
sessionId: 1,
|
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
username: '',
|
username: '',
|
||||||
},
|
},
|
||||||
@ -111,7 +110,6 @@ describe('UserCard_FormUsername', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
sessionId: 1,
|
|
||||||
username: 'username',
|
username: 'username',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -151,7 +149,6 @@ describe('UserCard_FormUsername', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variables: {
|
variables: {
|
||||||
email: 'user@example.org',
|
email: 'user@example.org',
|
||||||
sessionId: 1,
|
|
||||||
username: 'username',
|
username: 'username',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -90,7 +90,6 @@ export default {
|
|||||||
.query({
|
.query({
|
||||||
query: updateUserInfos,
|
query: updateUserInfos,
|
||||||
variables: {
|
variables: {
|
||||||
sessionId: this.$store.state.sessionId,
|
|
||||||
email: this.$store.state.email,
|
email: this.$store.state.email,
|
||||||
username: this.form.username,
|
username: this.form.username,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,11 +13,6 @@ describe('UserProfileTransactionList', () => {
|
|||||||
$i18n: {
|
$i18n: {
|
||||||
locale: jest.fn(() => 'en'),
|
locale: jest.fn(() => 'en'),
|
||||||
},
|
},
|
||||||
$store: {
|
|
||||||
state: {
|
|
||||||
sessionId: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const stubs = {
|
const stubs = {
|
||||||
|
|||||||
@ -13576,6 +13576,13 @@ vue-jest@^3.0.5, vue-jest@^3.0.7:
|
|||||||
tsconfig "^7.0.0"
|
tsconfig "^7.0.0"
|
||||||
vue-template-es2015-compiler "^1.6.0"
|
vue-template-es2015-compiler "^1.6.0"
|
||||||
|
|
||||||
|
vue-jwt-decode@^0.1.0:
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-jwt-decode/-/vue-jwt-decode-0.1.0.tgz#f9caf7b9030d5459cc567b1c3117d9d1f291458f"
|
||||||
|
integrity sha512-4iP0NzYHkAF7G13tYPc/nudk4oNpB8GCVZupc7lekxXok1XKEgefNaGTpDT14g7RKe5H9GaMphPduDj4UVfZwQ==
|
||||||
|
dependencies:
|
||||||
|
vue "^2.3.3"
|
||||||
|
|
||||||
vue-loader@^15.7.0:
|
vue-loader@^15.7.0:
|
||||||
version "15.9.6"
|
version "15.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.6.tgz#f4bb9ae20c3a8370af3ecf09b8126d38ffdb6b8b"
|
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.6.tgz#f4bb9ae20c3a8370af3ecf09b8126d38ffdb6b8b"
|
||||||
@ -13655,6 +13662,11 @@ vue@^2.2.6, vue@^2.5.17, vue@^2.6.11:
|
|||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
|
||||||
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
|
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
|
||||||
|
|
||||||
|
vue@^2.3.3:
|
||||||
|
version "2.6.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||||
|
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||||
|
|
||||||
vuex-persistedstate@^4.0.0-beta.3:
|
vuex-persistedstate@^4.0.0-beta.3:
|
||||||
version "4.0.0-beta.3"
|
version "4.0.0-beta.3"
|
||||||
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-4.0.0-beta.3.tgz#89dd712de72d28e85cc95467d066002c1405f277"
|
resolved "https://registry.yarnpkg.com/vuex-persistedstate/-/vuex-persistedstate-4.0.0-beta.3.tgz#89dd712de72d28e85cc95467d066002c1405f277"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user