mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into apollo_listTransactions
This commit is contained in:
commit
94e95240eb
@ -1,18 +0,0 @@
|
||||
import { createConnection, Connection } from 'mysql2/promise'
|
||||
import CONFIG from '../config'
|
||||
|
||||
const connection = async (): Promise<Connection> => {
|
||||
const con = await createConnection({
|
||||
host: CONFIG.DB_HOST,
|
||||
port: CONFIG.DB_PORT,
|
||||
user: CONFIG.DB_USER,
|
||||
password: CONFIG.DB_PASSWORD,
|
||||
database: CONFIG.DB_DATABASE,
|
||||
})
|
||||
|
||||
await con.connect()
|
||||
|
||||
return con
|
||||
}
|
||||
|
||||
export default connection
|
||||
19
backend/src/graphql/resolvers/index.ts
Normal file
19
backend/src/graphql/resolvers/index.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { UserResolver } from './UserResolver'
|
||||
import { BalanceResolver } from './BalanceResolver'
|
||||
import { GdtResolver } from './GdtResolver'
|
||||
import { TransactionResolver } from './TransactionResolver'
|
||||
import { KlicktippResolver } from './KlicktippResolver'
|
||||
import { NonEmptyArray } from 'type-graphql'
|
||||
|
||||
export { UserResolver, BalanceResolver, GdtResolver, TransactionResolver, KlicktippResolver }
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const resolvers = (): NonEmptyArray<Function> => [
|
||||
UserResolver,
|
||||
BalanceResolver,
|
||||
GdtResolver,
|
||||
TransactionResolver,
|
||||
KlicktippResolver,
|
||||
]
|
||||
|
||||
export default resolvers
|
||||
14
backend/src/graphql/schema.ts
Normal file
14
backend/src/graphql/schema.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { GraphQLSchema } from 'graphql'
|
||||
import { buildSchema } from 'type-graphql'
|
||||
|
||||
import resolvers from './resolvers'
|
||||
import { isAuthorized } from '../auth/auth'
|
||||
|
||||
const schema = async (): Promise<GraphQLSchema> => {
|
||||
return buildSchema({
|
||||
resolvers: resolvers(),
|
||||
authChecker: isAuthorized,
|
||||
})
|
||||
}
|
||||
|
||||
export default schema
|
||||
@ -2,98 +2,58 @@
|
||||
|
||||
import 'reflect-metadata'
|
||||
import express from 'express'
|
||||
import cors from 'cors'
|
||||
import { buildSchema } from 'type-graphql'
|
||||
import { ApolloServer } from 'apollo-server-express'
|
||||
import { RowDataPacket } from 'mysql2/promise'
|
||||
|
||||
import connection from './database/connection'
|
||||
import typeOrmConnection from './typeorm/connection'
|
||||
// config
|
||||
import CONFIG from './config'
|
||||
|
||||
// TODO move to extern
|
||||
import { UserResolver } from './graphql/resolvers/UserResolver'
|
||||
import { BalanceResolver } from './graphql/resolvers/BalanceResolver'
|
||||
import { GdtResolver } from './graphql/resolvers/GdtResolver'
|
||||
import { TransactionResolver } from './graphql/resolvers/TransactionResolver'
|
||||
import { KlicktippResolver } from './graphql/resolvers/KlicktippResolver'
|
||||
// database
|
||||
import connection from './typeorm/connection'
|
||||
import getDBVersion from './typeorm/getDBVersion'
|
||||
|
||||
import { isAuthorized } from './auth/auth'
|
||||
// server
|
||||
import cors from './server/cors'
|
||||
import context from './server/context'
|
||||
import plugins from './server/plugins'
|
||||
|
||||
// graphql
|
||||
import schema from './graphql/schema'
|
||||
|
||||
// TODO implement
|
||||
// import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity";
|
||||
|
||||
const DB_VERSION = '0001-init_db'
|
||||
|
||||
const context = (args: any) => {
|
||||
const authorization = args.req.headers.authorization
|
||||
let token = null
|
||||
if (authorization) {
|
||||
token = authorization.replace(/^Bearer /, '')
|
||||
}
|
||||
const context = {
|
||||
token,
|
||||
setHeaders: [],
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// check for correct database version
|
||||
// open mysql connection
|
||||
const con = await connection()
|
||||
const [rows] = await con.query(`SELECT * FROM migrations ORDER BY version DESC LIMIT 1;`)
|
||||
if (
|
||||
(<RowDataPacket>rows).length === 0 ||
|
||||
!(<RowDataPacket>rows)[0].fileName ||
|
||||
(<RowDataPacket>rows)[0].fileName.indexOf(DB_VERSION) === -1
|
||||
) {
|
||||
throw new Error(`Wrong database version - the backend requires '${DB_VERSION}'`)
|
||||
if (!con || !con.isConnected) {
|
||||
throw new Error(`Couldn't open connection to database`)
|
||||
}
|
||||
|
||||
const toCon = await typeOrmConnection()
|
||||
if (!toCon.isConnected) {
|
||||
throw new Error(`Couldn't open typeorm db connection`)
|
||||
}
|
||||
|
||||
const schema = await buildSchema({
|
||||
resolvers: [UserResolver, BalanceResolver, TransactionResolver, GdtResolver, KlicktippResolver],
|
||||
authChecker: isAuthorized,
|
||||
})
|
||||
|
||||
// Graphiql interface
|
||||
let playground = false
|
||||
if (CONFIG.GRAPHIQL) {
|
||||
playground = true
|
||||
// check for correct database version
|
||||
const dbVersion = await getDBVersion()
|
||||
if (!dbVersion || dbVersion.indexOf(DB_VERSION) === -1) {
|
||||
throw new Error(
|
||||
`Wrong database version - the backend requires '${DB_VERSION}' but found '${
|
||||
dbVersion || 'None'
|
||||
}'`,
|
||||
)
|
||||
}
|
||||
|
||||
// Express Server
|
||||
const server = express()
|
||||
|
||||
const corsOptions = {
|
||||
origin: '*',
|
||||
exposedHeaders: ['token'],
|
||||
}
|
||||
|
||||
server.use(cors(corsOptions))
|
||||
|
||||
const plugins = [
|
||||
{
|
||||
requestDidStart() {
|
||||
return {
|
||||
willSendResponse(requestContext: any) {
|
||||
const { setHeaders = [] } = requestContext.context
|
||||
setHeaders.forEach(({ key, value }: { [key: string]: string }) => {
|
||||
requestContext.response.http.headers.append(key, value)
|
||||
})
|
||||
return requestContext
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
// cors
|
||||
server.use(cors)
|
||||
|
||||
// Apollo Server
|
||||
const apollo = new ApolloServer({ schema, playground, context, plugins })
|
||||
const apollo = new ApolloServer({
|
||||
schema: await schema(),
|
||||
playground: CONFIG.GRAPHIQL,
|
||||
context,
|
||||
plugins,
|
||||
})
|
||||
apollo.applyMiddleware({ app: server })
|
||||
|
||||
// Start Server
|
||||
|
||||
14
backend/src/server/context.ts
Normal file
14
backend/src/server/context.ts
Normal file
@ -0,0 +1,14 @@
|
||||
const context = (args: any) => {
|
||||
const authorization = args.req.headers.authorization
|
||||
let token = null
|
||||
if (authorization) {
|
||||
token = authorization.replace(/^Bearer /, '')
|
||||
}
|
||||
const context = {
|
||||
token,
|
||||
setHeaders: [],
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
export default context
|
||||
8
backend/src/server/cors.ts
Normal file
8
backend/src/server/cors.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import cors from 'cors'
|
||||
|
||||
const corsOptions = {
|
||||
origin: '*',
|
||||
exposedHeaders: ['token'],
|
||||
}
|
||||
|
||||
export default cors(corsOptions)
|
||||
17
backend/src/server/plugins.ts
Normal file
17
backend/src/server/plugins.ts
Normal file
@ -0,0 +1,17 @@
|
||||
const plugins = [
|
||||
{
|
||||
requestDidStart() {
|
||||
return {
|
||||
willSendResponse(requestContext: any) {
|
||||
const { setHeaders = [] } = requestContext.context
|
||||
setHeaders.forEach(({ key, value }: { [key: string]: string }) => {
|
||||
requestContext.response.http.headers.append(key, value)
|
||||
})
|
||||
return requestContext
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export default plugins
|
||||
@ -2,18 +2,21 @@ import { createConnection, Connection } from 'typeorm'
|
||||
import CONFIG from '../config'
|
||||
import path from 'path'
|
||||
|
||||
const connection = async (): Promise<Connection> => {
|
||||
const con = await createConnection({
|
||||
name: 'default',
|
||||
type: 'mysql',
|
||||
host: CONFIG.DB_HOST,
|
||||
port: CONFIG.DB_PORT,
|
||||
username: CONFIG.DB_USER,
|
||||
password: CONFIG.DB_PASSWORD,
|
||||
database: CONFIG.DB_DATABASE,
|
||||
entities: [path.join(__dirname, 'entity', '*.ts')],
|
||||
synchronize: false,
|
||||
})
|
||||
const connection = async (): Promise<Connection | null> => {
|
||||
let con = null
|
||||
try {
|
||||
con = await createConnection({
|
||||
name: 'default',
|
||||
type: 'mysql',
|
||||
host: CONFIG.DB_HOST,
|
||||
port: CONFIG.DB_PORT,
|
||||
username: CONFIG.DB_USER,
|
||||
password: CONFIG.DB_PASSWORD,
|
||||
database: CONFIG.DB_DATABASE,
|
||||
entities: [path.join(__dirname, 'entity', '*.{ts,js}')],
|
||||
synchronize: false,
|
||||
})
|
||||
} catch (error) {}
|
||||
|
||||
return con
|
||||
}
|
||||
|
||||
13
backend/src/typeorm/entity/Migration.ts
Normal file
13
backend/src/typeorm/entity/Migration.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
|
||||
|
||||
@Entity('migrations')
|
||||
export class Migration extends BaseEntity {
|
||||
@PrimaryGeneratedColumn() // This is actually not a primary column
|
||||
version: number
|
||||
|
||||
@Column({ length: 256, nullable: true, default: null })
|
||||
fileName: string
|
||||
|
||||
@Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
|
||||
date: Date
|
||||
}
|
||||
15
backend/src/typeorm/getDBVersion.ts
Normal file
15
backend/src/typeorm/getDBVersion.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { getConnection } from 'typeorm'
|
||||
import { Migration } from './entity/Migration'
|
||||
|
||||
const getDBVersion = async (): Promise<string | null> => {
|
||||
const connection = getConnection()
|
||||
const migrations = connection.getRepository(Migration)
|
||||
try {
|
||||
const dbVersion = await migrations.findOne({ order: { version: 'DESC' } })
|
||||
return dbVersion ? dbVersion.fileName : null
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default getDBVersion
|
||||
103
docu/graphics/AnachBüberweisen.drawio
Normal file
103
docu/graphics/AnachBüberweisen.drawio
Normal file
@ -0,0 +1,103 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="ZvjvITeOyjQP4YKfGS0G" name="Page-1">
|
||||
<mxGraphModel dx="923" dy="562" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="29" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" vertex="1" parent="1">
|
||||
<mxGeometry x="660" y="135" width="120" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="28" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" vertex="1" parent="1">
|
||||
<mxGeometry x="540" y="135" width="120" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="27" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#e3c800;strokeColor=#B09500;fontColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="420" y="135" width="120" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="26" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="135" width="120" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="25" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fa6800;strokeColor=#C73500;fontColor=#000000;" vertex="1" parent="1">
|
||||
<mxGeometry x="180" y="135" width="120" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="24" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#e51400;strokeColor=#B20000;fontColor=#ffffff;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="135" width="110" height="215" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;fillColor=#008a00;strokeColor=#005700;jumpSize=6;endSize=6;startSize=6;strokeWidth=3;" edge="1" parent="1" source="2" target="3">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#008a00;strokeColor=#005700;strokeWidth=3;" edge="1" parent="1" source="2" target="4">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="2" value="1.5.0<br>Register" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="80" y="200" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="3" target="7">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#60a917;strokeColor=#2D7600;" edge="1" parent="1" source="3" target="10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="3" value="1.6.0<br>Kubernetes" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="150" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#60a917;strokeColor=#2D7600;" edge="1" parent="1" source="4" target="7">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#60a917;strokeColor=#2D7600;" edge="1" parent="1" source="4" target="10">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="1.6.0<br>Overview<br>Page" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="200" y="250" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#e3c800;strokeColor=#B09500;" edge="1" parent="1" source="7" target="15">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="7" value="1.7.0<br>Federation" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="150" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=3;fillColor=#e3c800;strokeColor=#B09500;" edge="1" parent="1" source="10" target="15">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="10" value="1.7.0<br>Statistics(?)" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="250" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;fillColor=#f0a30a;strokeColor=#BD7000;strokeWidth=3;" edge="1" parent="1" source="15" target="18">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="15" value="1.8.0<br>Activities" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="440" y="200" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;fillColor=#fa6800;strokeColor=#C73500;strokeWidth=3;" edge="1" parent="1" source="18" target="19">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="18" value="1.X.0<br>???" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="560" y="200" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="19" value="Von A nach B überweisen&nbsp;" style="whiteSpace=wrap;html=1;aspect=fixed;fillColor=#2A2A2A;strokeColor=#F0F0F0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="680" y="200" width="80" height="80" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="30" value="The background color symbolizes how far away we are from the goal. The arrow color symbolizes how sure we can be that this will be the course of action" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="640" width="330" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="31" value="Our current release" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="360" width="110" height="240" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="32" value="The Release 1.6.0 will make sure we can actually deploy multiple instances of our Software.<br>Additionally we will create the Overview Page in the Frontend" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="185" y="360" width="110" height="240" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="33" value="The Release 1.7.0 will focus on the Federation. Maybe we will be able to send Coins at this stage, but its likely this will be done in the next steps. Here we most likely get to know the other communties only.<br>In the Frontend we consider to show some statisticts with the amount of known Communities" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="305" y="361" width="110" height="239" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="35" value="The Release 1.8.0 will implement Activities in order to allow other communities to actually create GDD." style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="425" y="360" width="110" height="240" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="36" value="More Steps might be needed to have the usable full functionallity of sending from A to B." style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=top;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="545" y="360" width="110" height="240" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="37" value="Be aware that we might decide to split some Releases into two. Especially the Federation Release might need a followup Release in oder to actually send coins, since this will not be part of the Federation itself." style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#F0F0F0;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="710" width="330" height="50" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
BIN
docu/graphics/AnachBüberweisen.png
Normal file
BIN
docu/graphics/AnachBüberweisen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
@ -1,5 +1,3 @@
|
||||
LOGIN_API_URL=http://localhost/login_api/
|
||||
COMMUNITY_API_URL=http://localhost/api/
|
||||
ALLOW_REGISTER=true
|
||||
GRAPHQL_URI=http://localhost:4000/graphql
|
||||
//BUILD_COMMIT=0000000
|
||||
@ -1,120 +1,114 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="decayinformation">
|
||||
<span v-if="decaytyp === 'short'">
|
||||
<div v-if="decay.balance > 0">
|
||||
<span v-if="decay.balance > 0">
|
||||
{{ decay ? ' -' + decay.balance + ' ' + decayStartBlockTextShort : '' }}
|
||||
</div>
|
||||
<div v-else>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('decay.noDecay') }}
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div v-if="decaytyp === 'new'">
|
||||
<b-list-group style="border: 0px">
|
||||
<b-list-group-item style="border: 0px; background-color: #f1f1f1">
|
||||
<div class="d-flex" v-if="!decay.decayStartBlock">
|
||||
<div style="width: 100%" class="text-center pb-3">
|
||||
<b-icon icon="droplet-half" height="12" class="mb-2" />
|
||||
<b>{{ $t('decay.calculation_decay') }}</b>
|
||||
<div class="d-flex" v-if="!decay.decayStartBlock">
|
||||
<div style="width: 100%" class="text-center pb-3">
|
||||
<b-icon icon="droplet-half" height="12" class="mb-2" />
|
||||
<b>{{ $t('decay.calculation_decay') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div v-if="!decay.decayStartBlock">{{ $t('decay.last_transaction') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div v-if="decay.decayStartBlock > 0">
|
||||
<div class="display-4">{{ $t('decay.Starting_block_decay') }}</div>
|
||||
<div>
|
||||
{{ $t('decay.decay_introduced') }} :
|
||||
{{ $d($moment.unix(decay.decayStart), 'long') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div v-if="!decay.decayStartBlock">{{ $t('decay.last_transaction') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div v-if="decay.decayStartBlock > 0">
|
||||
<div class="display-4">{{ $t('decay.Starting_block_decay') }}</div>
|
||||
<div>
|
||||
{{ $t('decay.decay_introduced') }} :
|
||||
{{ $d($moment.unix(decay.decayStart), 'long') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="decay.decayStart">
|
||||
{{ $d($moment.unix(decay.decayStart), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div v-if="!decay.decayStartBlock">{{ $t('decay.past_time') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div v-if="decay.decayStartBlock > 0">{{ $t('decay.since_introduction') }}</div>
|
||||
<span v-if="duration">
|
||||
<span v-if="duration.years > 0">{{ duration.years }} {{ $t('decay.year') }},</span>
|
||||
<span v-if="duration.months > 0">
|
||||
{{ duration.months }} {{ $t('decay.months') }},
|
||||
</span>
|
||||
<span v-if="duration.days > 0">{{ duration.days }} {{ $t('decay.days') }},</span>
|
||||
<span v-if="duration.hours > 0">{{ duration.hours }} {{ $t('decay.hours') }},</span>
|
||||
<span v-if="duration.minutes > 0">
|
||||
{{ duration.minutes }} {{ $t('decay.minutes') }},
|
||||
</span>
|
||||
<span v-if="duration.seconds > 0">
|
||||
{{ duration.seconds }} {{ $t('decay.seconds') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<div v-if="decay.balance > 0">
|
||||
<!-- Decay-->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div>{{ $t('decay.decay') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div>- {{ decay.balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<hr class="mt-2 mb-2" />
|
||||
<b-row>
|
||||
<b-col class="text-center pt-3 pb-2">
|
||||
<b>{{ $t('decay.calculation_total') }}</b>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Type-->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div v-if="type === 'send'">{{ $t('decay.sent') }}</div>
|
||||
<div v-if="type === 'receive'">{{ $t('decay.received') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div v-if="type === 'send'">- {{ balance }}</div>
|
||||
<div v-if="type === 'receive'">+ {{ balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Decay-->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div>{{ $t('decay.decay') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div>- {{ decay.balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Total-->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<div>{{ $t('decay.total') }}</div>
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<div v-if="type === 'send'">
|
||||
<b>- {{ parseInt(balance) + decay.balance }}</b>
|
||||
</div>
|
||||
<div v-if="type === 'receive'">
|
||||
<b>{{ parseInt(balance) - decay.balance }}</b>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<div>
|
||||
<span v-if="decay.decayStart">
|
||||
{{ $d($moment.unix(decay.decayStart), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div v-if="!decay.decayStartBlock">{{ $t('decay.past_time') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div v-if="decay.decayStartBlock > 0">{{ $t('decay.since_introduction') }}</div>
|
||||
<span v-if="duration">
|
||||
<span v-if="duration.years > 0">{{ duration.years }} {{ $t('decay.year') }},</span>
|
||||
<span v-if="duration.months > 0">{{ duration.months }} {{ $t('decay.months') }},</span>
|
||||
<span v-if="duration.days > 0">{{ duration.days }} {{ $t('decay.days') }},</span>
|
||||
<span v-if="duration.hours > 0">{{ duration.hours }} {{ $t('decay.hours') }},</span>
|
||||
<span v-if="duration.minutes > 0">
|
||||
{{ duration.minutes }} {{ $t('decay.minutes') }},
|
||||
</span>
|
||||
<span v-if="duration.seconds > 0">
|
||||
{{ duration.seconds }} {{ $t('decay.seconds') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<div v-if="decay.balance > 0">
|
||||
<!-- Decay-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div>{{ $t('decay.decay') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div>- {{ decay.balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<hr class="mt-2 mb-2" />
|
||||
<b-row>
|
||||
<b-col class="text-center pt-3 pb-2">
|
||||
<b>{{ $t('decay.calculation_total') }}</b>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Type-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div v-if="type === 'send'">{{ $t('decay.sent') }}</div>
|
||||
<div v-if="type === 'receive'">{{ $t('decay.received') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div v-if="type === 'send'">- {{ balance }}</div>
|
||||
<div v-if="type === 'receive'">+ {{ balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Decay-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div>{{ $t('decay.decay') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div>- {{ decay.balance }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Total-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">
|
||||
<div>{{ $t('decay.total') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div v-if="type === 'send'">
|
||||
<b>- {{ parseInt(balance) + decay.balance }}</b>
|
||||
</div>
|
||||
<div v-if="type === 'receive'">
|
||||
<b>{{ parseInt(balance) - decay.balance }}</b>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
containsUppercaseCharacter: true,
|
||||
containsNumericCharacter: true,
|
||||
atLeastEightCharactera: true,
|
||||
atLeastOneSpecialCharater: true,
|
||||
noWhitespaceCharacters: true,
|
||||
}"
|
||||
:label="register ? $t('form.password') : $t('form.password_new')"
|
||||
:showAllErrors="true"
|
||||
|
||||
@ -14,7 +14,6 @@ export default {
|
||||
return {
|
||||
selected: null,
|
||||
options: [
|
||||
{ value: null, text: this.$t('select_language') },
|
||||
{ value: 'de', text: this.$t('languages.de') },
|
||||
{ value: 'en', text: this.$t('languages.en') },
|
||||
],
|
||||
|
||||
@ -19,40 +19,40 @@
|
||||
|
||||
<!-- type -->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<b-col cols="6" class="text-right">
|
||||
{{ getLinesByType(gdtEntryType).description }}
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<b-col cols="6">
|
||||
{{ getLinesByType(gdtEntryType).descriptiontext }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<!-- credit -->
|
||||
<b-row>
|
||||
<b-col col="6" class="text-right">
|
||||
<b-col cols="6" class="text-right">
|
||||
{{ $t('gdt.credit') }}
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<b-col cols="6">
|
||||
{{ getLinesByType(gdtEntryType).credittext }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<!-- Message-->
|
||||
<b-row v-if="comment && gdtEntryType !== 7">
|
||||
<b-col col="6" class="text-right">
|
||||
<b-col cols="6" class="text-right">
|
||||
{{ $t('form.memo') }}
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<b-col cols="6">
|
||||
{{ comment }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<!-- date-->
|
||||
<b-row class="gdt-list-row text-header">
|
||||
<b-col col="6" class="text-right">
|
||||
<b-col cols="6" class="text-right">
|
||||
{{ $t('form.date') }}
|
||||
</b-col>
|
||||
<b-col col="6">
|
||||
<b-col cols="6">
|
||||
{{ $d($moment(date), 'long') }} {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
@ -4,21 +4,21 @@
|
||||
style="border: 0px; background-color: #f1f1f1"
|
||||
>
|
||||
<b-row class="gdt-list-collapse-header-text text-center pb-3">
|
||||
<div id="collapse-headline" class="col">
|
||||
<b-col id="collapse-headline">
|
||||
<b>{{ getLinesByType(gdtEntryType).headline }}</b>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="gdt-list-collapse-box--all">
|
||||
<div class="col-6 text-right collapse-col-left">
|
||||
<b-col cols="6" class="text-right collapse-col-left">
|
||||
<div id="collapse-first">{{ getLinesByType(gdtEntryType).first }}</div>
|
||||
<div id="collapse-second">{{ getLinesByType(gdtEntryType).second }}</div>
|
||||
</div>
|
||||
<div class="col-6 collapse-col-right">
|
||||
</b-col>
|
||||
<b-col cols="6" class="collapse-col-right">
|
||||
<div id="collapse-firstMath">{{ getLinesByType(gdtEntryType).firstMath }}</div>
|
||||
<div id="collapse-secondMath">
|
||||
{{ getLinesByType(gdtEntryType).secondMath }}
|
||||
</div>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
@ -33,6 +33,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getLinesByType(givenType) {
|
||||
if (givenType === 2 || givenType === 3 || givenType === 5 || givenType === 6) givenType = 1
|
||||
|
||||
const linesByType = {
|
||||
1: {
|
||||
headline: this.$t('gdt.calculation'),
|
||||
|
||||
@ -18,8 +18,6 @@ const environment = {
|
||||
}
|
||||
|
||||
const server = {
|
||||
LOGIN_API_URL: process.env.LOGIN_API_URL || 'http://localhost/login_api/',
|
||||
COMMUNITY_API_URL: process.env.COMMUNITY_API_URL || 'http://localhost/api/',
|
||||
GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql',
|
||||
}
|
||||
|
||||
|
||||
@ -45,21 +45,14 @@
|
||||
"amount": "Betrag",
|
||||
"at": "am",
|
||||
"cancel": "Abbrechen",
|
||||
"change": "ändern",
|
||||
"change-name": "Name ändern",
|
||||
"change-password": "Passwort ändern",
|
||||
"changeLanguage": "Sprache ändern",
|
||||
"change_username_info": "Einmal gespeichert, kann der Username ncht mehr geändert werden!",
|
||||
"close": "schließen",
|
||||
"date": "Datum",
|
||||
"description": "Beschreibung",
|
||||
"edit": "bearbeiten",
|
||||
"email": "E-Mail",
|
||||
"email_repeat": "eMail wiederholen",
|
||||
"firstname": "Vorname",
|
||||
"from": "von",
|
||||
"lastname": "Nachname",
|
||||
"max_gdd_info": "Maximale anzahl GDD zum versenden erreicht!",
|
||||
"memo": "Nachricht",
|
||||
"message": "Nachricht",
|
||||
"password": "Passwort",
|
||||
@ -81,7 +74,6 @@
|
||||
"time": "Zeit",
|
||||
"to": "bis",
|
||||
"to1": "an",
|
||||
"username": "Username",
|
||||
"validation": {
|
||||
"gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein",
|
||||
"is-not": "Du kannst dir selbst keine Gradidos überweisen",
|
||||
@ -106,29 +98,40 @@
|
||||
},
|
||||
"imprint": "Impressum",
|
||||
"language": "Sprache",
|
||||
"languages": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"success": "Deine Sprache wurde erfolgreich geändert."
|
||||
},
|
||||
"login": "Anmeldung",
|
||||
"logout": "Abmelden",
|
||||
"members_area": "Mitgliederbereich",
|
||||
"message": "hallo gradido !!",
|
||||
"privacy_policy": "Datenschutzerklärung",
|
||||
"reset": "Passwort zurücksetzen",
|
||||
"reset-password": {
|
||||
"not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.",
|
||||
"text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst.",
|
||||
"title": "Passwort zurücksetzen"
|
||||
},
|
||||
"select_language": "Bitte wähle eine Sprache für die App und Newsletter",
|
||||
"send": "Senden",
|
||||
"setting": {
|
||||
"changeNewsletter": "Newsletter Status ändern",
|
||||
"newsletter": "Newsletter",
|
||||
"newsletterFalse": "Du bist aus Newslettersystem ausgetragen.",
|
||||
"newsletterTrue": "Du bist im Newslettersystem eingetraten."
|
||||
"settings": {
|
||||
"language": {
|
||||
"changeLanguage": "Sprache ändern",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"select_language": "Bitte wähle eine Sprache.",
|
||||
"success": "Deine Sprache wurde erfolgreich geändert."
|
||||
},
|
||||
"name": {
|
||||
"change-name": "Name ändern",
|
||||
"change-success": "Dein Name wurde erfolgreich geändert."
|
||||
},
|
||||
"newsletter": {
|
||||
"newsletter": "Newsletter",
|
||||
"newsletterFalse": "Du bist aus Newslettersystem ausgetragen.",
|
||||
"newsletterTrue": "Du bist im Newslettersystem eingetraten."
|
||||
},
|
||||
"password": {
|
||||
"change-password": "Passwort ändern",
|
||||
"forgot_pwd": "Passwort vergessen?",
|
||||
"reset": "Passwort zurücksetzen",
|
||||
"reset-password": {
|
||||
"not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.",
|
||||
"text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst."
|
||||
},
|
||||
"send_now": "Jetzt senden",
|
||||
"subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen."
|
||||
}
|
||||
},
|
||||
"signup": "Registrieren",
|
||||
"site": {
|
||||
@ -143,34 +146,21 @@
|
||||
},
|
||||
"login": {
|
||||
"community": "Tausend Dank, weil du bei uns bist!",
|
||||
"forgot_pwd": "Passwort vergessen?",
|
||||
"new_wallet": "Neues Konto erstellen",
|
||||
"remember": "Passwort merken",
|
||||
"signin": "Anmelden"
|
||||
},
|
||||
"navbar": {
|
||||
"activity": "Aktivität",
|
||||
"my-profil": "Mein Profil",
|
||||
"settings": "Einstellungen",
|
||||
"support": "Support"
|
||||
},
|
||||
"overview": {
|
||||
"account_overview": "Kontoübersicht",
|
||||
"add_work": "neuer Gemeinschaftsbeitrag",
|
||||
"send_gradido": "Gradido versenden",
|
||||
"since_last_month": "seid letzten Monat"
|
||||
},
|
||||
"password": {
|
||||
"send_now": "Jetzt senden",
|
||||
"subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen.",
|
||||
"title": "Passwort zurücksetzen"
|
||||
},
|
||||
"signup": {
|
||||
"agree": "Ich stimme der <a href='https://gradido.net/de/datenschutz/' target='_blank' >Datenschutzerklärung</a> zu.",
|
||||
"dont_match": "Die Passwörter stimmen nicht überein.",
|
||||
"lowercase": "Ein Kleinbuchstabe erforderlich.",
|
||||
"minimum": "Mindestens 8 Zeichen.",
|
||||
"no-whitespace": "Keine Leerzeichen und Tabulatoren",
|
||||
"one_number": "Eine Zahl erforderlich.",
|
||||
"special-char": "Ein Sonderzeichen erforderlich (z.B. _ oder ä)",
|
||||
"subtitle": "Werde Teil der Gemeinschaft!",
|
||||
"title": "Erstelle dein Gradido-Konto",
|
||||
"uppercase": "Ein Großbuchstabe erforderlich."
|
||||
@ -192,6 +182,5 @@
|
||||
"show_all": "Alle <strong>{count}</strong> Transaktionen ansehen"
|
||||
},
|
||||
"transactions": "Transaktionen",
|
||||
"welcome": "Willkommen!",
|
||||
"whitepaper": "Whitepaper"
|
||||
}
|
||||
|
||||
@ -45,21 +45,14 @@
|
||||
"amount": "Amount",
|
||||
"at": "at",
|
||||
"cancel": "Cancel",
|
||||
"change": "change",
|
||||
"change-name": "Change name",
|
||||
"change-password": "Change password",
|
||||
"changeLanguage": "Change language",
|
||||
"change_username_info": "Once saved, the username cannot be changed again!",
|
||||
"close": "Close",
|
||||
"date": "Date",
|
||||
"description": "Description",
|
||||
"edit": "Edit",
|
||||
"email": "Email",
|
||||
"email_repeat": "Repeat Email",
|
||||
"firstname": "Firstname",
|
||||
"from": "from",
|
||||
"lastname": "Lastname",
|
||||
"max_gdd_info": "Maximum number of GDDs to be sent has been reached!",
|
||||
"memo": "Message",
|
||||
"message": "Message",
|
||||
"password": "Password",
|
||||
@ -81,7 +74,6 @@
|
||||
"time": "Time",
|
||||
"to": "to",
|
||||
"to1": "to",
|
||||
"username": "Username",
|
||||
"validation": {
|
||||
"gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits",
|
||||
"is-not": "You cannot send Gradidos to yourself",
|
||||
@ -106,29 +98,40 @@
|
||||
},
|
||||
"imprint": "Legal notice",
|
||||
"language": "Language",
|
||||
"languages": {
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"success": "Your language has been successfully updated."
|
||||
},
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"members_area": "Member's area",
|
||||
"message": "hello gradido !!",
|
||||
"privacy_policy": "Privacy policy",
|
||||
"reset": "Reset password",
|
||||
"reset-password": {
|
||||
"not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.",
|
||||
"text": "Now you can save a new password to login to the Gradido-App in the future.",
|
||||
"title": "Reset Password"
|
||||
},
|
||||
"select_language": "Please choose a language for the app and newsletter",
|
||||
"send": "Send",
|
||||
"setting": {
|
||||
"changeNewsletter": "Newsletter status change",
|
||||
"newsletter": "Newsletter",
|
||||
"newsletterFalse": "You are unsubscribed from newsletter system.",
|
||||
"newsletterTrue": "You are subscribed to newsletter system."
|
||||
"settings": {
|
||||
"language": {
|
||||
"changeLanguage": "Change language",
|
||||
"de": "Deutsch",
|
||||
"en": "English",
|
||||
"select_language": "Please choose a language.",
|
||||
"success": "Your language has been successfully updated."
|
||||
},
|
||||
"name": {
|
||||
"change-name": "Change name",
|
||||
"change-success": "Your name has been successfully changed."
|
||||
},
|
||||
"newsletter": {
|
||||
"newsletter": "Newsletter",
|
||||
"newsletterFalse": "You are unsubscribed from newsletter system.",
|
||||
"newsletterTrue": "You are subscribed to newsletter system."
|
||||
},
|
||||
"password": {
|
||||
"change-password": "Change password",
|
||||
"forgot_pwd": "Forgot password?",
|
||||
"reset": "Reset password",
|
||||
"reset-password": {
|
||||
"not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.",
|
||||
"text": "Now you can save a new password to login to the Gradido-App in the future."
|
||||
},
|
||||
"send_now": "Send now",
|
||||
"subtitle": "If you have forgotten your password, you can reset it here."
|
||||
}
|
||||
},
|
||||
"signup": "Sign up",
|
||||
"site": {
|
||||
@ -143,34 +146,21 @@
|
||||
},
|
||||
"login": {
|
||||
"community": "A thousand thanks for being with us!",
|
||||
"forgot_pwd": "Forgot password?",
|
||||
"new_wallet": "Create new account",
|
||||
"remember": "Remember password",
|
||||
"signin": "Sign in"
|
||||
},
|
||||
"navbar": {
|
||||
"activity": "Activity",
|
||||
"my-profil": "My profile",
|
||||
"settings": "Settings",
|
||||
"support": "Support"
|
||||
},
|
||||
"overview": {
|
||||
"account_overview": "Account overview",
|
||||
"add_work": "New Community Contribution",
|
||||
"send_gradido": "Send Gradido",
|
||||
"since_last_month": "since last month"
|
||||
},
|
||||
"password": {
|
||||
"send_now": "Send now",
|
||||
"subtitle": "If you have forgotten your password, you can reset it here.",
|
||||
"title": "Reset password"
|
||||
},
|
||||
"signup": {
|
||||
"agree": "I agree to the <a href='https://gradido.net/en/datenschutz/' target='_blank' > privacy policy</a>.",
|
||||
"dont_match": "Passwords don't match.",
|
||||
"lowercase": "One lowercase letter required.",
|
||||
"minimum": "8 characters minimum.",
|
||||
"no-whitespace": "No white spaces and tabs",
|
||||
"one_number": "One number required.",
|
||||
"special-char": "One special character required (e.g. _ or ä)",
|
||||
"subtitle": "Become a part of the community!",
|
||||
"title": "Create your Gradido account",
|
||||
"uppercase": "One uppercase letter required."
|
||||
@ -192,6 +182,5 @@
|
||||
"show_all": "View all <strong>{count}</strong> transactions."
|
||||
},
|
||||
"transactions": "Transactions",
|
||||
"welcome": "Welcome!",
|
||||
"whitepaper": "Whitepaper"
|
||||
}
|
||||
|
||||
@ -112,6 +112,20 @@ export const loadAllRules = (i18nCallback) => {
|
||||
message: (_, values) => i18nCallback.t('site.signup.minimum', values),
|
||||
})
|
||||
|
||||
extend('atLeastOneSpecialCharater', {
|
||||
validate(value) {
|
||||
return !!value.match(/[^a-zA-Z0-9]/)
|
||||
},
|
||||
message: (_, values) => i18nCallback.t('site.signup.special-char', values),
|
||||
})
|
||||
|
||||
extend('noWhitespaceCharacters', {
|
||||
validate(value) {
|
||||
return !!value.match(/[^ \t\n\r]/)
|
||||
},
|
||||
message: (_, values) => i18nCallback.t('site.signup.no-whitespace', values),
|
||||
})
|
||||
|
||||
extend('samePassword', {
|
||||
validate(value, [pwd]) {
|
||||
return value === pwd
|
||||
|
||||
@ -54,7 +54,7 @@ describe('GddTransactionList', () => {
|
||||
await wrapper.setProps({
|
||||
transactions: [
|
||||
{
|
||||
balance: '19.93',
|
||||
balance: 19.93,
|
||||
date: '2021-05-25T17:38:13+00:00',
|
||||
memo: 'Alles Gute zum Geburtstag',
|
||||
name: 'Bob der Baumeister',
|
||||
@ -63,7 +63,7 @@ describe('GddTransactionList', () => {
|
||||
decay: { balance: '0.5' },
|
||||
},
|
||||
{
|
||||
balance: '1000',
|
||||
balance: 1000,
|
||||
date: '2021-04-29T15:34:49+00:00',
|
||||
memo: 'Gut das du da bist!',
|
||||
name: 'Gradido Akademie',
|
||||
@ -71,7 +71,7 @@ describe('GddTransactionList', () => {
|
||||
type: 'creation',
|
||||
},
|
||||
{
|
||||
balance: '314.98',
|
||||
balance: 314.98,
|
||||
date: '2021-04-29T17:26:40+00:00',
|
||||
memo: 'Für das Fahrrad!',
|
||||
name: 'Jan Ulrich',
|
||||
|
||||
@ -18,13 +18,13 @@
|
||||
</b-button>
|
||||
</div>
|
||||
|
||||
<b-row>
|
||||
<div>
|
||||
<!-- ICON -->
|
||||
<div class="col-1 gdd-transaction-list-item-icon">
|
||||
<b-icon :icon="getProperties(type).icon" :class="getProperties(type).class" />
|
||||
</div>
|
||||
|
||||
<div class="col col-11">
|
||||
<div>
|
||||
<!-- Betrag / Name Email -->
|
||||
<b-row>
|
||||
<div class="col-5 text-right">
|
||||
@ -70,7 +70,7 @@
|
||||
</div>
|
||||
</b-row>
|
||||
</div>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
<!-- Collaps Start -->
|
||||
|
||||
|
||||
@ -39,11 +39,11 @@ describe('ForgotPassword', () => {
|
||||
})
|
||||
|
||||
it('has a title', () => {
|
||||
expect(wrapper.find('h1').text()).toEqual('site.password.title')
|
||||
expect(wrapper.find('h1').text()).toEqual('settings.password.reset')
|
||||
})
|
||||
|
||||
it('has a subtitle', () => {
|
||||
expect(wrapper.find('p.text-lead').text()).toEqual('site.password.subtitle')
|
||||
expect(wrapper.find('p.text-lead').text()).toEqual('settings.password.subtitle')
|
||||
})
|
||||
|
||||
describe('back button', () => {
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
<div class="header-body text-center mb-7">
|
||||
<b-row class="justify-content-center">
|
||||
<b-col xl="5" lg="6" md="8" class="px-2">
|
||||
<h1>{{ $t('site.password.title') }}</h1>
|
||||
<p class="text-lead">{{ $t('site.password.subtitle') }}</p>
|
||||
<h1>{{ $t('settings.password.reset') }}</h1>
|
||||
<p class="text-lead">{{ $t('settings.password.subtitle') }}</p>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
@ -22,7 +22,7 @@
|
||||
<input-email v-model="form.email"></input-email>
|
||||
<div class="text-center">
|
||||
<b-button type="submit" variant="primary">
|
||||
{{ $t('site.password.send_now') }}
|
||||
{{ $t('settings.password.send_now') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form>
|
||||
|
||||
@ -71,7 +71,7 @@ describe('Login', () => {
|
||||
describe('links', () => {
|
||||
it('has a link "Forgot Password?"', () => {
|
||||
expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual(
|
||||
'site.login.forgot_pwd',
|
||||
'settings.password.forgot_pwd',
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
<b-row class="mt-3">
|
||||
<b-col cols="6">
|
||||
<router-link to="/password">
|
||||
{{ $t('site.login.forgot_pwd') }}
|
||||
{{ $t('settings.password.forgot_pwd') }}
|
||||
</router-link>
|
||||
</b-col>
|
||||
<b-col cols="6" class="text-right" v-show="allowRegister">
|
||||
|
||||
@ -25,7 +25,7 @@ describe('Register', () => {
|
||||
$store: {
|
||||
state: {
|
||||
email: 'peter@lustig.de',
|
||||
language: null,
|
||||
language: 'en',
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -55,11 +55,11 @@ describe('Register', () => {
|
||||
|
||||
describe('links', () => {
|
||||
it('has a link "Back"', () => {
|
||||
expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back')
|
||||
expect(wrapper.find('.test-button-back').text()).toEqual('back')
|
||||
})
|
||||
|
||||
it('links to /login when clicking "Back"', () => {
|
||||
expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/login')
|
||||
expect(wrapper.find('.test-button-back').props().to).toBe('/login')
|
||||
})
|
||||
})
|
||||
|
||||
@ -89,17 +89,17 @@ describe('Register', () => {
|
||||
it('has Language selected field', () => {
|
||||
expect(wrapper.find('.selectedLanguage').exists()).toBeTruthy()
|
||||
})
|
||||
it('selected Language value de', async () => {
|
||||
it('selects Language value en', async () => {
|
||||
wrapper.find('.selectedLanguage').findAll('option').at(1).setSelected()
|
||||
expect(wrapper.find('.selectedLanguage').element.value).toBe('de')
|
||||
expect(wrapper.find('.selectedLanguage').element.value).toBe('en')
|
||||
})
|
||||
|
||||
it('has 1 checkbox input fields', () => {
|
||||
expect(wrapper.find('#registerCheckbox').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has no submit button when not completely filled', () => {
|
||||
expect(wrapper.find('button[type="submit"]').exists()).toBe(false)
|
||||
it('has disabled submit button when not completely filled', () => {
|
||||
expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled')
|
||||
})
|
||||
|
||||
it('displays a message that Email is required', async () => {
|
||||
@ -127,70 +127,20 @@ describe('Register', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('resetForm', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('#registerFirstname').setValue('Max')
|
||||
wrapper.find('#registerLastname').setValue('Mustermann')
|
||||
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
||||
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
||||
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
||||
wrapper.find('.language-switch-select').findAll('option').at(1).setSelected()
|
||||
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('.language-switch-select').element.value).toBe(undefined)
|
||||
})
|
||||
|
||||
it('resets the firstName field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('#registerFirstname').element.value).toBe('')
|
||||
})
|
||||
|
||||
it('resets the lastName field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('#registerLastname').element.value).toBe('')
|
||||
})
|
||||
|
||||
it('resets the email field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('#Email-input-field').element.value).toBe('')
|
||||
})
|
||||
|
||||
it.skip('resets the password field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('input[name="form.password"]').element.value).toBe('')
|
||||
})
|
||||
|
||||
it.skip('resets the passwordRepeat field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('input[name="form.passwordRepeat"]').element.value).toBe('')
|
||||
})
|
||||
|
||||
it('resets the firstName field after clicking the reset button', async () => {
|
||||
await wrapper.find('button.ml-2').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.find('input[name="site.signup.agree"]').props.checked).not.toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('API calls', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('#registerFirstname').setValue('Max')
|
||||
wrapper.find('#registerLastname').setValue('Mustermann')
|
||||
wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net')
|
||||
wrapper.find('input[name="form.password"]').setValue('Aa123456')
|
||||
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456')
|
||||
wrapper.find('input[name="form.password"]').setValue('Aa123456_')
|
||||
wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456_')
|
||||
wrapper.find('.language-switch-select').findAll('option').at(1).setSelected()
|
||||
})
|
||||
|
||||
it('has enabled submit button when completely filled', () => {
|
||||
expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled')
|
||||
})
|
||||
|
||||
describe('server sends back error', () => {
|
||||
beforeEach(async () => {
|
||||
registerUserMutationMock.mockRejectedValue({ message: 'Ouch!' })
|
||||
@ -234,8 +184,8 @@ describe('Register', () => {
|
||||
email: 'max.mustermann@gradido.net',
|
||||
firstName: 'Max',
|
||||
lastName: 'Mustermann',
|
||||
password: 'Aa123456',
|
||||
language: 'de',
|
||||
password: 'Aa123456_',
|
||||
language: 'en',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
@ -116,13 +116,19 @@
|
||||
</span>
|
||||
</b-alert>
|
||||
|
||||
<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 type="submit" variant="primary">{{ $t('signup') }}</b-button>
|
||||
<b-button class="ml-2 test-button-back" to="/login">
|
||||
{{ $t('back') }}
|
||||
</b-button>
|
||||
|
||||
<b-button
|
||||
:disabled="!(namesFilled && emailFilled && form.agree && languageFilled)"
|
||||
type="submit"
|
||||
variant="primary"
|
||||
>
|
||||
{{ $t('signup') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</b-form>
|
||||
@ -131,9 +137,6 @@
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<div class="text-center py-lg-4">
|
||||
<router-link to="/login" class="mt-3">{{ $t('back') }}</router-link>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
@ -172,22 +175,6 @@ export default {
|
||||
getValidationState({ dirty, validated, valid = null }) {
|
||||
return dirty || validated ? valid : null
|
||||
},
|
||||
resetForm() {
|
||||
this.form = {
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
email: '',
|
||||
password: {
|
||||
password: '',
|
||||
passwordRepeat: '',
|
||||
},
|
||||
agree: false,
|
||||
}
|
||||
this.language = ''
|
||||
this.$nextTick(() => {
|
||||
this.$refs.observer.reset()
|
||||
})
|
||||
},
|
||||
async onSubmit() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
@ -238,7 +225,7 @@ export default {
|
||||
return this.form.email !== ''
|
||||
},
|
||||
languageFilled() {
|
||||
return this.language !== null && this.language !== ''
|
||||
return !!this.language
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -71,8 +71,10 @@ describe('ResetPassword', () => {
|
||||
})
|
||||
|
||||
it('has a message suggesting to contact the support', () => {
|
||||
expect(wrapper.find('div.header').text()).toContain('reset-password.title')
|
||||
expect(wrapper.find('div.header').text()).toContain('reset-password.not-authenticated')
|
||||
expect(wrapper.find('div.header').text()).toContain('settings.password.reset')
|
||||
expect(wrapper.find('div.header').text()).toContain(
|
||||
'settings.password.reset-password.not-authenticated',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -99,8 +101,10 @@ describe('ResetPassword', () => {
|
||||
|
||||
describe('Register header', () => {
|
||||
it('has a welcome message', async () => {
|
||||
expect(wrapper.find('div.header').text()).toContain('reset-password.title')
|
||||
expect(wrapper.find('div.header').text()).toContain('reset-password.text')
|
||||
expect(wrapper.find('div.header').text()).toContain('settings.password.reset')
|
||||
expect(wrapper.find('div.header').text()).toContain(
|
||||
'settings.password.reset-password.text',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -140,8 +144,8 @@ describe('ResetPassword', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setData({ authenticated: true, sessionId: 1 })
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.findAll('input').at(0).setValue('Aa123456')
|
||||
await wrapper.findAll('input').at(1).setValue('Aa123456')
|
||||
await wrapper.findAll('input').at(0).setValue('Aa123456_')
|
||||
await wrapper.findAll('input').at(1).setValue('Aa123456_')
|
||||
await flushPromises()
|
||||
await wrapper.find('form').trigger('submit')
|
||||
})
|
||||
@ -169,7 +173,7 @@ describe('ResetPassword', () => {
|
||||
variables: {
|
||||
sessionId: 1,
|
||||
email: 'user@example.org',
|
||||
password: 'Aa123456',
|
||||
password: 'Aa123456_',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
@ -5,13 +5,13 @@
|
||||
<div class="header-body text-center mb-7">
|
||||
<b-row class="justify-content-center">
|
||||
<b-col xl="5" lg="6" md="8" class="px-2">
|
||||
<h1>{{ $t('reset-password.title') }}</h1>
|
||||
<h1>{{ $t('settings.password.reset') }}</h1>
|
||||
<div class="pb-4" v-if="!pending">
|
||||
<span v-if="authenticated">
|
||||
{{ $t('reset-password.text') }}
|
||||
{{ $t('settings.password.reset-password.text') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('reset-password.not-authenticated') }}
|
||||
{{ $t('settings.password.reset-password.not-authenticated') }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
@ -29,7 +29,7 @@
|
||||
<input-password-confirmation v-model="form" :register="register" />
|
||||
<div class="text-center">
|
||||
<b-button type="submit" variant="primary" class="mt-4">
|
||||
{{ $t('reset') }}
|
||||
{{ $t('settings.password.reset') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form>
|
||||
|
||||
@ -139,7 +139,7 @@ describe('UserCard_FormUserData', () => {
|
||||
})
|
||||
|
||||
it('toasts a success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success')
|
||||
expect(toastSuccessMock).toBeCalledWith('settings.name.change-success')
|
||||
})
|
||||
|
||||
it('has an edit button again', () => {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<b-row class="mb-4 text-right">
|
||||
<b-col class="text-right">
|
||||
<a @click="showUserData ? (showUserData = !showUserData) : cancelEdit()">
|
||||
<span class="pointer mr-3">{{ $t('form.change-name') }}</span>
|
||||
<span class="pointer mr-3">{{ $t('settings.name.change-name') }}</span>
|
||||
<b-icon v-if="showUserData" class="pointer ml-3" icon="pencil"></b-icon>
|
||||
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
|
||||
</a>
|
||||
@ -122,7 +122,7 @@ export default {
|
||||
this.$store.commit('lastName', this.form.lastName)
|
||||
this.$store.commit('description', this.form.description)
|
||||
this.showUserData = true
|
||||
this.$toasted.success(this.$t('site.profil.user-data.change-success'))
|
||||
this.$toasted.success(this.$t('settings.name.change-success'))
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toasted.error(error.message)
|
||||
|
||||
@ -47,7 +47,7 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
})
|
||||
|
||||
it('has a change password button with text "form.change-password"', () => {
|
||||
expect(wrapper.find('a').text()).toEqual('form.change-password')
|
||||
expect(wrapper.find('a').text()).toEqual('settings.password.change-password')
|
||||
})
|
||||
|
||||
it('has a change password button with a pencil icon', () => {
|
||||
@ -105,12 +105,14 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
describe('validation', () => {
|
||||
it('displays all password requirements', () => {
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(5)
|
||||
expect(feedbackArray).toHaveLength(7)
|
||||
expect(feedbackArray.at(0).text()).toBe('validations.messages.required')
|
||||
expect(feedbackArray.at(1).text()).toBe('site.signup.lowercase')
|
||||
expect(feedbackArray.at(2).text()).toBe('site.signup.uppercase')
|
||||
expect(feedbackArray.at(3).text()).toBe('site.signup.one_number')
|
||||
expect(feedbackArray.at(4).text()).toBe('site.signup.minimum')
|
||||
expect(feedbackArray.at(5).text()).toBe('site.signup.special-char')
|
||||
expect(feedbackArray.at(6).text()).toBe('site.signup.no-whitespace')
|
||||
})
|
||||
|
||||
it('removes first message when a character is given', async () => {
|
||||
@ -125,7 +127,7 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
await wrapper.findAll('input').at(1).setValue('a')
|
||||
await flushPromises()
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(3)
|
||||
expect(feedbackArray).toHaveLength(4)
|
||||
expect(feedbackArray.at(0).text()).toBe('site.signup.uppercase')
|
||||
})
|
||||
|
||||
@ -133,7 +135,7 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
await wrapper.findAll('input').at(1).setValue('Aa')
|
||||
await flushPromises()
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(2)
|
||||
expect(feedbackArray).toHaveLength(3)
|
||||
expect(feedbackArray.at(0).text()).toBe('site.signup.one_number')
|
||||
})
|
||||
|
||||
@ -141,14 +143,22 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
await wrapper.findAll('input').at(1).setValue('Aa1')
|
||||
await flushPromises()
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(1)
|
||||
expect(feedbackArray).toHaveLength(2)
|
||||
expect(feedbackArray.at(0).text()).toBe('site.signup.minimum')
|
||||
})
|
||||
|
||||
it('removes all messages when all rules are fulfilled', async () => {
|
||||
it('removes the first five messages when a eight lowercase, uppercase and numeric characters are given', async () => {
|
||||
await wrapper.findAll('input').at(1).setValue('Aa123456')
|
||||
await flushPromises()
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(1)
|
||||
expect(feedbackArray.at(0).text()).toBe('site.signup.special-char')
|
||||
})
|
||||
|
||||
it('removes all messages when a eight lowercase, uppercase and numeric characters are given', async () => {
|
||||
await wrapper.findAll('input').at(1).setValue('Aa123456_')
|
||||
await flushPromises()
|
||||
const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span')
|
||||
expect(feedbackArray).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
@ -164,8 +174,8 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
},
|
||||
})
|
||||
await form.findAll('input').at(0).setValue('1234')
|
||||
await form.findAll('input').at(1).setValue('Aa123456')
|
||||
await form.findAll('input').at(2).setValue('Aa123456')
|
||||
await form.findAll('input').at(1).setValue('Aa123456_')
|
||||
await form.findAll('input').at(2).setValue('Aa123456_')
|
||||
await form.trigger('submit')
|
||||
await flushPromises()
|
||||
})
|
||||
@ -176,7 +186,7 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
variables: {
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
passwordNew: 'Aa123456',
|
||||
passwordNew: 'Aa123456_',
|
||||
},
|
||||
}),
|
||||
)
|
||||
@ -197,8 +207,8 @@ describe('UserCard_FormUserPasswort', () => {
|
||||
message: 'error',
|
||||
})
|
||||
await form.findAll('input').at(0).setValue('1234')
|
||||
await form.findAll('input').at(1).setValue('Aa123456')
|
||||
await form.findAll('input').at(2).setValue('Aa123456')
|
||||
await form.findAll('input').at(1).setValue('Aa123456_')
|
||||
await form.findAll('input').at(2).setValue('Aa123456_')
|
||||
await form.trigger('submit')
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<b-row class="mb-4 text-right">
|
||||
<b-col class="text-right">
|
||||
<a @click="showPassword ? (showPassword = !showPassword) : cancelEdit()">
|
||||
<span class="pointer mr-3">{{ $t('form.change-password') }}</span>
|
||||
<span class="pointer mr-3">{{ $t('settings.password.change-password') }}</span>
|
||||
<b-icon v-if="showPassword" class="pointer ml-3" icon="pencil"></b-icon>
|
||||
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
|
||||
</a>
|
||||
|
||||
@ -125,7 +125,7 @@ describe('UserCard_FormUsername', () => {
|
||||
})
|
||||
|
||||
it('toasts an success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success')
|
||||
expect(toastSuccessMock).toBeCalledWith('settings.name.change-success')
|
||||
})
|
||||
|
||||
it('has no edit button anymore', () => {
|
||||
|
||||
@ -98,7 +98,7 @@ export default {
|
||||
this.$store.commit('username', this.form.username)
|
||||
this.username = this.form.username
|
||||
this.showUsername = true
|
||||
this.$toasted.success(this.$t('site.profil.user-data.change-success'))
|
||||
this.$toasted.success(this.$t('settings.name.change-success'))
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toasted.error(error.message)
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<b-row class="mb-4 text-right">
|
||||
<b-col class="text-right">
|
||||
<a @click="showLanguage ? (showLanguage = !showLanguage) : cancelEdit()">
|
||||
<span class="pointer mr-3">{{ $t('form.changeLanguage') }}</span>
|
||||
<span class="pointer mr-3">{{ $t('settings.language.changeLanguage') }}</span>
|
||||
<b-icon v-if="showLanguage" class="pointer ml-3" icon="pencil"></b-icon>
|
||||
<b-icon v-else icon="x-circle" class="pointer ml-3" variant="danger"></b-icon>
|
||||
</a>
|
||||
@ -97,7 +97,7 @@ export default {
|
||||
this.$i18n.locale = this.language
|
||||
localeChanged(this.language)
|
||||
this.cancelEdit()
|
||||
this.$toasted.success(this.$t('languages.success'))
|
||||
this.$toasted.success(this.$t('settings.language.success'))
|
||||
})
|
||||
.catch((error) => {
|
||||
this.language = this.$store.state.language
|
||||
|
||||
@ -74,7 +74,7 @@ describe('UserCard_Newsletter', () => {
|
||||
})
|
||||
|
||||
it('toasts a success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('setting.newsletterFalse')
|
||||
expect(toastSuccessMock).toBeCalledWith('settings.newsletter.newsletterFalse')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<b-row class="mb-3">
|
||||
<b-col class="mb-2 col-12">
|
||||
<small>
|
||||
<b>{{ $t('setting.newsletter') }}</b>
|
||||
<b>{{ $t('settings.newsletter.newsletter') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col class="col-12">
|
||||
@ -15,7 +15,11 @@
|
||||
switch
|
||||
@change="onSubmit"
|
||||
>
|
||||
{{ newsletterState ? $t('setting.newsletterTrue') : $t('setting.newsletterFalse') }}
|
||||
{{
|
||||
newsletterState
|
||||
? $t('settings.newsletter.newsletterTrue')
|
||||
: $t('settings.newsletter.newsletterFalse')
|
||||
}}
|
||||
</b-form-checkbox>
|
||||
</b-col>
|
||||
</b-row>
|
||||
@ -46,8 +50,8 @@ export default {
|
||||
this.$store.commit('newsletterState', this.newsletterState)
|
||||
this.$toasted.success(
|
||||
this.newsletterState
|
||||
? this.$t('setting.newsletterTrue')
|
||||
: this.$t('setting.newsletterFalse'),
|
||||
? this.$t('settings.newsletter.newsletterTrue')
|
||||
: this.$t('settings.newsletter.newsletterFalse'),
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { createLocalVue } from '@vue/test-utils'
|
||||
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
||||
import Vuex from 'vuex'
|
||||
import Vue from 'vue'
|
||||
|
||||
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate'
|
||||
import * as rules from 'vee-validate/dist/rules'
|
||||
@ -47,3 +48,8 @@ global.localVue.component('validation-provider', ValidationProvider)
|
||||
global.localVue.component('validation-observer', ValidationObserver)
|
||||
global.localVue.directive('click-outside', clickOutside)
|
||||
global.localVue.directive('focus', focus)
|
||||
|
||||
// throw errors for vue warnings to force the programmers to take care about warnings
|
||||
Vue.config.warnHandler = (w) => {
|
||||
throw new Error(w)
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-06-21 13:37+0200\n"
|
||||
"PO-Revision-Date: 2021-06-21 13:38+0200\n"
|
||||
"POT-Creation-Date: 2021-09-23 17:56+0200\n"
|
||||
"PO-Revision-Date: 2021-09-27 13:31+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: de_DE\n"
|
||||
@ -455,11 +455,10 @@ msgstr "Gradido: Passwort zurücksetzen"
|
||||
#: src/cpp/SingletonManager/SessionManager.cpp:604
|
||||
msgid ""
|
||||
"Please enter a valid password with at least 8 characters, upper and lower "
|
||||
"case letters, at least one number and one special character (@$!%*?&+-_)!"
|
||||
"case letters, at least one number and one special character!"
|
||||
msgstr ""
|
||||
"Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und "
|
||||
"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen (@$!%*?&+-_) "
|
||||
"ein!"
|
||||
"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen!"
|
||||
|
||||
#: src/cpp/SingletonManager/SessionManager.cpp:610
|
||||
msgid "Your password is to short!"
|
||||
@ -478,8 +477,8 @@ msgid "Your password does not contain any number!"
|
||||
msgstr "Dein Passwort enthält keine Zahlen!"
|
||||
|
||||
#: src/cpp/SingletonManager/SessionManager.cpp:630
|
||||
msgid "Your password does not contain special characters (@$!%*?&+-)!"
|
||||
msgstr "Dein Passwort enthält keine Sonderzeichen (@$!%*?&+-)!"
|
||||
msgid "Your password does not contain special characters!"
|
||||
msgstr "Dein Passwort enthält keine Sonderzeichen!"
|
||||
|
||||
#~ msgid "Account"
|
||||
#~ msgstr "Konto"
|
||||
|
||||
@ -46,22 +46,22 @@ bool SessionManager::init()
|
||||
case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[^<>&;]{2,}$"); break;
|
||||
case VALIDATE_USERNAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z][a-zA-Z0-9_-]*$"); break;
|
||||
case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break;
|
||||
case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&+-_])[A-Za-z0-9@$!%*?&+-_]{8,}$"); break;
|
||||
case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9 \\t\\n\\r]).{8,}$"); break;
|
||||
case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break;
|
||||
case VALIDATE_GROUP_ALIAS: mValidations[i] = new Poco::RegularExpression("^[a-z0-9-]{3,120}"); break;
|
||||
case VALIDATE_HEDERA_ID: mValidations[i] = new Poco::RegularExpression("^[0-9]*\.[0-9]*\.[0-9]\.$"); break;
|
||||
case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break;
|
||||
case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression("[0-9]"); break;
|
||||
case VALIDATE_ONLY_INTEGER: mValidations[i] = new Poco::RegularExpression("^[0-9]*$"); break;
|
||||
case VALIDATE_ONLY_DECIMAL: mValidations[i] = new Poco::RegularExpression("^[0-9]*(\.|,)[0-9]*$"); break;
|
||||
case VALIDATE_ONLY_HEX: mValidations[i] = new Poco::RegularExpression("^(0x)?[a-fA-F0-9]*$"); break;
|
||||
//case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break;
|
||||
case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); break;
|
||||
case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break;
|
||||
case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression("[^a-zA-Z0-9 \\t\\n\\r]"); break;
|
||||
case VALIDATE_HAS_UPPERCASE_LETTER:
|
||||
mValidations[i] = new Poco::RegularExpression(".*[A-Z].*");
|
||||
mValidations[i] = new Poco::RegularExpression("[A-Z]");
|
||||
ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64());
|
||||
break;
|
||||
case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break;
|
||||
case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression("[a-z]"); break;
|
||||
default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
@ -601,7 +601,7 @@ bool SessionManager::checkPwdValidation(const std::string& pwd, NotificationList
|
||||
if (!isValid(pwd, VALIDATE_PASSWORD)) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character (@$!%*?&+-_)!")));
|
||||
lang->gettext("Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!")));
|
||||
|
||||
// @$!%*?&+-
|
||||
if (pwd.size() < 8) {
|
||||
@ -627,7 +627,7 @@ bool SessionManager::checkPwdValidation(const std::string& pwd, NotificationList
|
||||
else if (!isValid(pwd, VALIDATE_HAS_SPECIAL_CHARACTER)) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Your password does not contain special characters (@$!%*?&+-)!")));
|
||||
lang->gettext("Your password does not contain special characters!")));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@ -85,7 +85,7 @@ enum PageState {
|
||||
<form method="POST">
|
||||
<p>
|
||||
Bitte denke dir ein sicheres Passwort aus, das mindestens 8 Zeichen lang ist, einen Klein- und einen Großbuchstaben enthält,
|
||||
eine Zahl und eines der folgenden Sonderzeichen: @$!%*?&+-
|
||||
eine Zahl und ein Sonderzeichen.
|
||||
</p>
|
||||
<label class="form-label" for="register-password">Passwort</label>
|
||||
<input class="form-control" id="register-password" type="password" name="register-password"/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user