mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into 1319-email-optin
This commit is contained in:
commit
c83959fc58
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
.git
|
||||
.gitignore
|
||||
.gitignore
|
||||
!.eslintignore
|
||||
@ -1,4 +1,3 @@
|
||||
node_modules
|
||||
coverage
|
||||
**/*.min.js
|
||||
dist
|
||||
node_modules/
|
||||
dist/
|
||||
coverage/
|
||||
@ -8,9 +8,20 @@ module.exports = {
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
},
|
||||
extends: ['standard', 'plugin:vue/essential', 'plugin:prettier/recommended'],
|
||||
extends: [
|
||||
'standard',
|
||||
'plugin:vue/essential',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:@intlify/vue-i18n/recommended',
|
||||
],
|
||||
// required to lint *.vue files
|
||||
plugins: ['vue', 'prettier', 'jest'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.json'],
|
||||
extends: ['plugin:@intlify/vue-i18n/recommended'],
|
||||
},
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
'no-console': ['error'],
|
||||
@ -22,6 +33,17 @@ module.exports = {
|
||||
allowBinding: false,
|
||||
},
|
||||
],
|
||||
'@intlify/vue-i18n/no-dynamic-keys': 'error',
|
||||
'@intlify/vue-i18n/no-unused-keys': [
|
||||
'error',
|
||||
{
|
||||
src: './src',
|
||||
extensions: ['.js', '.vue'],
|
||||
ignores: [],
|
||||
enableFix: false,
|
||||
},
|
||||
],
|
||||
'@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
@ -29,4 +51,12 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
'vue-i18n': {
|
||||
localeDir: './src/locales/*.json',
|
||||
// Specify the version of `vue-i18n` you are using.
|
||||
// If not specified, the message will be parsed twice.
|
||||
messageSyntaxVersion: '^8.26.5',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -12,11 +12,10 @@
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "yarn run serve",
|
||||
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.vue .",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
||||
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
||||
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
|
||||
"test": "TZ=UTC jest --coverage",
|
||||
"locales": "scripts/missing-keys.sh && scripts/sort.sh"
|
||||
"locales": "scripts/sort.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.15.8",
|
||||
@ -52,6 +51,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.15.8",
|
||||
"@intlify/eslint-plugin-vue-i18n": "^1.4.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
|
||||
@ -4,24 +4,24 @@
|
||||
<b-row align-v="center" class="mt-4 justify-content-lg-between">
|
||||
<b-col>
|
||||
<div class="copyright text-center text-lg-center text-muted">
|
||||
© {{ year }}
|
||||
{{ $t('footer.copyright.year', { year }) }}
|
||||
<a
|
||||
:href="`https://gradido.net/${$i18n.locale}`"
|
||||
class="font-weight-bold ml-1"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('gradido_admin_footer') }}
|
||||
{{ $t('footer.copyright.link') }}
|
||||
</a>
|
||||
|
|
||||
{{ $t('math.pipe') }}
|
||||
<a href="https://github.com/gradido/gradido/releases/latest" target="_blank">
|
||||
App version {{ version }}
|
||||
{{ $t('footer.app_version', { version }) }}
|
||||
</a>
|
||||
<a
|
||||
v-if="hash"
|
||||
:href="'https://github.com/gradido/gradido/commit/' + hash"
|
||||
target="_blank"
|
||||
>
|
||||
({{ shortHash }})
|
||||
{{ $t('footer.short_hash', { shortHash }) }}
|
||||
</a>
|
||||
</div>
|
||||
</b-col>
|
||||
|
||||
@ -6,32 +6,30 @@ const localVue = global.localVue
|
||||
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
transactionList: {
|
||||
transactions: [
|
||||
{
|
||||
id: 1,
|
||||
amount: 100,
|
||||
balanceDate: 0,
|
||||
creationDate: new Date(),
|
||||
memo: 'Testing',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
creationTransactionList: [
|
||||
{
|
||||
id: 1,
|
||||
amount: 100,
|
||||
balanceDate: 0,
|
||||
creationDate: new Date(),
|
||||
memo: 'Testing',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
amount: 200,
|
||||
balanceDate: 0,
|
||||
creationDate: new Date(),
|
||||
memo: 'Testing 2',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
amount: 200,
|
||||
balanceDate: 0,
|
||||
creationDate: new Date(),
|
||||
memo: 'Testing 2',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@ -67,7 +65,6 @@ describe('CreationTransactionListFormular', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
order: 'DESC',
|
||||
onlyCreations: true,
|
||||
userId: 1,
|
||||
},
|
||||
}),
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { transactionList } from '../graphql/transactionList'
|
||||
import { creationTransactionList } from '../graphql/creationTransactionList'
|
||||
export default {
|
||||
name: 'CreationTransactionList',
|
||||
props: {
|
||||
@ -51,17 +51,16 @@ export default {
|
||||
getTransactions() {
|
||||
this.$apollo
|
||||
.query({
|
||||
query: transactionList,
|
||||
query: creationTransactionList,
|
||||
variables: {
|
||||
currentPage: 1,
|
||||
pageSize: 25,
|
||||
order: 'DESC',
|
||||
onlyCreations: true,
|
||||
userId: parseInt(this.userId),
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
this.items = result.data.transactionList.transactions
|
||||
this.items = result.data.creationTransactionList
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastError(error.message)
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<b-row class="mt-4">
|
||||
<b-col class="col-3">{{ $t('transactionlist.amount') }}</b-col>
|
||||
<b-col class="h3">
|
||||
<b>{{ item.amount }} GDD</b>
|
||||
<b>{{ item.amount }} {{ $t('GDD') }}</b>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
>
|
||||
<b-icon icon="plus" variant="success"></b-icon>
|
||||
</b-button>
|
||||
<div v-else>{{ $t('e_mail') }}!</div>
|
||||
<div v-else>{{ $t('e_mail') }}{{ $t('math.exclaim') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</b-table-lite>
|
||||
|
||||
22
admin/src/graphql/creationTransactionList.js
Normal file
22
admin/src/graphql/creationTransactionList.js
Normal file
@ -0,0 +1,22 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const creationTransactionList = gql`
|
||||
query ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC, $userId: Int!) {
|
||||
creationTransactionList(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
userId: $userId
|
||||
) {
|
||||
id
|
||||
amount
|
||||
balanceDate
|
||||
creationDate
|
||||
memo
|
||||
linkedUser {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -1,31 +0,0 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const transactionList = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$onlyCreations: Boolean = false
|
||||
$userId: Int = null
|
||||
) {
|
||||
transactionList(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
onlyCreations: $onlyCreations
|
||||
userId: $userId
|
||||
) {
|
||||
transactions {
|
||||
id
|
||||
amount
|
||||
balanceDate
|
||||
creationDate
|
||||
memo
|
||||
linkedUser {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -1,8 +1,6 @@
|
||||
{
|
||||
"all_emails": "Alle Nutzer",
|
||||
"back": "zurück",
|
||||
"bookmark": "bookmark",
|
||||
"confirmed": "bestätigt",
|
||||
"creation": "Schöpfung",
|
||||
"creation_form": {
|
||||
"creation_failed": "Ausstehende Schöpfung für {email} konnte nicht erzeugt werden.",
|
||||
@ -16,7 +14,6 @@
|
||||
"submit_creation": "Schöpfung einreichen",
|
||||
"toasted": "Offene Schöpfung ({value} GDD) für {email} wurde gespeichert und liegt zur Bestätigung bereit",
|
||||
"toasted_created": "Schöpfung wurde erfolgreich gespeichert",
|
||||
"toasted_default": "`Fall {event} wird nicht unterstützt`",
|
||||
"toasted_delete": "Offene Schöpfung wurde gelöscht",
|
||||
"toasted_update": "`Offene Schöpfung {value} GDD) für {email} wurde geändert und liegt zur Bestätigung bereit",
|
||||
"update_creation": "Schöpfung aktualisieren"
|
||||
@ -27,14 +24,26 @@
|
||||
"deleted": "gelöscht",
|
||||
"deleted_user": "Alle gelöschten Nutzer",
|
||||
"delete_user": "Nutzer löschen",
|
||||
"details": "Details",
|
||||
"edit": "Bearbeiten",
|
||||
"enabled": "aktiviert",
|
||||
"error": "Fehler",
|
||||
"e_mail": "E-Mail",
|
||||
"firstname": "Vorname",
|
||||
"gradido_admin_footer": "Gradido Akademie Adminkonsole",
|
||||
"footer": {
|
||||
"app_version": "App version {version}",
|
||||
"copyright": {
|
||||
"link": "Gradido Akademie Adminkonsole",
|
||||
"year": "© {year}"
|
||||
},
|
||||
"short_hash": "({shortHash})"
|
||||
},
|
||||
"GDD": "GDD",
|
||||
"hide_details": "Details verbergen",
|
||||
"lastname": "Nachname",
|
||||
"math": {
|
||||
"exclaim": "!",
|
||||
"pipe": "|"
|
||||
},
|
||||
"moderator": "Moderator",
|
||||
"multiple_creation_text": "Bitte wähle ein oder mehrere Mitglieder aus für die du Schöpfen möchtest.",
|
||||
"name": "Name",
|
||||
@ -47,7 +56,6 @@
|
||||
"user_search": "Nutzersuche"
|
||||
},
|
||||
"not_open_creations": "Keine offenen Schöpfungen",
|
||||
"open_creation": "Offene Schöpfung",
|
||||
"open_creations": "Offene Schöpfungen",
|
||||
"overlay": {
|
||||
"confirm": {
|
||||
@ -56,13 +64,6 @@
|
||||
"text": "Nach dem Speichern ist der Datensatz nicht mehr änderbar und kann auch nicht mehr gelöscht werden. Bitte überprüfe genau, dass alles stimmt.",
|
||||
"title": "Schöpfung bestätigen!",
|
||||
"yes": "Ja, Schöpfung bestätigen und speichern!"
|
||||
},
|
||||
"remove": {
|
||||
"no": "Nein, nicht löschen.",
|
||||
"question": "Willst du die vorgespeicherte Schöpfung wirklich löschen?",
|
||||
"text": "Nach dem Löschen gibt es keine Möglichkeit mehr diesen Datensatz wiederherzustellen. Es wird aber der gesamte Vorgang in der Logdatei als Übersicht gespeichert.",
|
||||
"title": "Achtung! Schöpfung löschen!",
|
||||
"yes": "Ja, Schöpfung löschen!"
|
||||
}
|
||||
},
|
||||
"remove": "Entfernen",
|
||||
@ -72,13 +73,11 @@
|
||||
"status": "Status",
|
||||
"success": "Erfolg",
|
||||
"text": "Text",
|
||||
"transaction": "Transaktion",
|
||||
"transactionlist": {
|
||||
"amount": "Betrag",
|
||||
"balanceDate": "Schöpfungsdatum",
|
||||
"community": "Gemeinschaft",
|
||||
"date": "Datum",
|
||||
"decay": "Vergänglichkeit",
|
||||
"memo": "Nachricht",
|
||||
"title": "Alle geschöpften Transaktionen für den Nutzer"
|
||||
},
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
{
|
||||
"all_emails": "All users",
|
||||
"back": "back",
|
||||
"bookmark": "Remember",
|
||||
"confirmed": "confirmed",
|
||||
"creation": "Creation",
|
||||
"creation_form": {
|
||||
"creation_failed": "Could not create pending creation for {email}",
|
||||
@ -16,7 +14,6 @@
|
||||
"submit_creation": "Submit creation",
|
||||
"toasted": "Open creation ({value} GDD) for {email} has been saved and is ready for confirmation.",
|
||||
"toasted_created": "Creation has been successfully saved",
|
||||
"toasted_default": "`Case {event} is not supported`",
|
||||
"toasted_delete": "Open creation has been deleted",
|
||||
"toasted_update": "Open creation {value} GDD) for {email} has been changed and is ready for confirmation.",
|
||||
"update_creation": "Creation update"
|
||||
@ -27,14 +24,26 @@
|
||||
"deleted": "deleted",
|
||||
"deleted_user": "All deleted user",
|
||||
"delete_user": "Delete user",
|
||||
"details": "Details",
|
||||
"edit": "Edit",
|
||||
"enabled": "enabled",
|
||||
"error": "Error",
|
||||
"e_mail": "E-mail",
|
||||
"firstname": "Firstname",
|
||||
"gradido_admin_footer": "Gradido Academy Admin Console",
|
||||
"footer": {
|
||||
"app_version": "App version {version}",
|
||||
"copyright": {
|
||||
"link": "Gradido Academy Admin Console",
|
||||
"year": "© {year}"
|
||||
},
|
||||
"short_hash": "({shortHash})"
|
||||
},
|
||||
"GDD": "GDD",
|
||||
"hide_details": "Hide details",
|
||||
"lastname": "Lastname",
|
||||
"math": {
|
||||
"exclaim": "!",
|
||||
"pipe": "|"
|
||||
},
|
||||
"moderator": "Moderator",
|
||||
"multiple_creation_text": "Please select one or more members for which you would like to perform creations.",
|
||||
"name": "Name",
|
||||
@ -47,7 +56,6 @@
|
||||
"user_search": "User search"
|
||||
},
|
||||
"not_open_creations": "No open creations",
|
||||
"open_creation": "Open creation",
|
||||
"open_creations": "Open creations",
|
||||
"overlay": {
|
||||
"confirm": {
|
||||
@ -56,13 +64,6 @@
|
||||
"text": "After saving, the record can no longer be changed or deleted. Please check carefully that everything is correct.",
|
||||
"title": "Confirm creation!",
|
||||
"yes": "Yes, confirm and save creation!"
|
||||
},
|
||||
"remove": {
|
||||
"no": "No, do not delete.",
|
||||
"question": "Do you really want to delete the pre-stored creation?",
|
||||
"text": "After deletion, there is no possibility to restore this data record. However, the entire process is saved in the log file as an overview.",
|
||||
"title": "Attention! Delete creation!",
|
||||
"yes": "Yes, delete creation!"
|
||||
}
|
||||
},
|
||||
"remove": "Remove",
|
||||
@ -72,13 +73,11 @@
|
||||
"status": "Status",
|
||||
"success": "Success",
|
||||
"text": "Text",
|
||||
"transaction": "Transaction",
|
||||
"transactionlist": {
|
||||
"amount": "Amount",
|
||||
"balanceDate": "Creation date",
|
||||
"community": "Community",
|
||||
"date": "Date",
|
||||
"decay": "Decay",
|
||||
"memo": "Message",
|
||||
"title": "All creation-transactions for the user"
|
||||
},
|
||||
|
||||
@ -15,7 +15,7 @@ export const toasters = {
|
||||
toast(message, options) {
|
||||
// for unit tests, check that replace is present
|
||||
if (message.replace) message = message.replace(/^GraphQL error: /, '')
|
||||
this.$bvToast.toast(message, {
|
||||
this.$root.$bvToast.toast(message, {
|
||||
autoHideDelay: 5000,
|
||||
appendToast: true,
|
||||
solid: true,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="creation">
|
||||
<b-row>
|
||||
<b-col cols="12" lg="6">
|
||||
<label>Usersuche</label>
|
||||
<label>{{ $t('user_search') }}</label>
|
||||
<b-input-group>
|
||||
<b-form-input
|
||||
type="text"
|
||||
|
||||
@ -2,7 +2,6 @@ import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import CONFIG from '../config'
|
||||
import store from '../store/store'
|
||||
import i18n from '../i18n'
|
||||
|
||||
const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI })
|
||||
|
||||
@ -15,7 +14,6 @@ const authLink = new ApolloLink((operation, forward) => {
|
||||
})
|
||||
return forward(operation).map((response) => {
|
||||
if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') {
|
||||
response.errors[0].message = i18n.t('error.session-expired')
|
||||
store.dispatch('logout', null)
|
||||
window.location.assign(CONFIG.WALLET_URL)
|
||||
return response
|
||||
|
||||
@ -14,6 +14,7 @@ module.exports = {
|
||||
fallbackLocale: 'de',
|
||||
localeDir: 'locales',
|
||||
enableInSFC: false,
|
||||
enableLegacy: false,
|
||||
},
|
||||
},
|
||||
lintOnSave: true,
|
||||
|
||||
205
admin/yarn.lock
205
admin/yarn.lock
@ -932,6 +932,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.14.0":
|
||||
version "7.17.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825"
|
||||
integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@7", "@babel/template@^7.0.0", "@babel/template@^7.15.4", "@babel/template@^7.3.3", "@babel/template@^7.4.0":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194"
|
||||
@ -1001,6 +1008,21 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/eslintrc@^1.2.0":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6"
|
||||
integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
espree "^9.3.1"
|
||||
globals "^13.9.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.2.1"
|
||||
js-yaml "^4.1.0"
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
@ -1042,6 +1064,83 @@
|
||||
cssnano-preset-default "^4.0.0"
|
||||
postcss "^7.0.0"
|
||||
|
||||
"@intlify/core-base@^9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.1.9.tgz#e4e8c951010728e4af3a0d13d74cf3f9e7add7f6"
|
||||
integrity sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==
|
||||
dependencies:
|
||||
"@intlify/devtools-if" "9.1.9"
|
||||
"@intlify/message-compiler" "9.1.9"
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/runtime" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
"@intlify/vue-devtools" "9.1.9"
|
||||
|
||||
"@intlify/devtools-if@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/devtools-if/-/devtools-if-9.1.9.tgz#a30e1dd1256ff2c5c98d8d75d075384fba898e5d"
|
||||
integrity sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==
|
||||
dependencies:
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@intlify/eslint-plugin-vue-i18n@^1.4.0":
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-1.4.0.tgz#f8fe791892c2dce7d189a364b6a908c87e1c3ac9"
|
||||
integrity sha512-anB1eBf6rpxpWyW883gi6O1hozQy4Q02VyzyodOUnohOqT07GATVSxnr2J9/qQSV47xWukV+9LiRErJcU7d/uA==
|
||||
dependencies:
|
||||
"@eslint/eslintrc" "^1.2.0"
|
||||
"@intlify/core-base" "^9.1.9"
|
||||
"@intlify/message-compiler" "^9.1.9"
|
||||
debug "^4.3.1"
|
||||
glob "^7.1.3"
|
||||
ignore "^5.0.5"
|
||||
is-language-code "^3.1.0"
|
||||
js-yaml "^4.0.0"
|
||||
json5 "^2.1.3"
|
||||
jsonc-eslint-parser "^2.0.0"
|
||||
lodash "^4.17.11"
|
||||
parse5 "^6.0.0"
|
||||
semver "^7.3.4"
|
||||
vue-eslint-parser "^8.0.0"
|
||||
yaml-eslint-parser "^0.5.0"
|
||||
|
||||
"@intlify/message-compiler@9.1.9", "@intlify/message-compiler@^9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.1.9.tgz#1193cbd224a71c2fb981455b8534a3c766d2948d"
|
||||
integrity sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==
|
||||
dependencies:
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
source-map "0.6.1"
|
||||
|
||||
"@intlify/message-resolver@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-resolver/-/message-resolver-9.1.9.tgz#3155ccd2f5e6d0dc16cad8b7f1d8e97fcda05bfc"
|
||||
integrity sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA==
|
||||
|
||||
"@intlify/runtime@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/runtime/-/runtime-9.1.9.tgz#2c12ce29518a075629efed0a8ed293ee740cb285"
|
||||
integrity sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==
|
||||
dependencies:
|
||||
"@intlify/message-compiler" "9.1.9"
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@intlify/shared@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.1.9.tgz#0baaf96128b85560666bec784ffb01f6623cc17a"
|
||||
integrity sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw==
|
||||
|
||||
"@intlify/vue-devtools@9.1.9":
|
||||
version "9.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz#2be8f4dbe7f7ed4115676eb32348141d411e426b"
|
||||
integrity sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==
|
||||
dependencies:
|
||||
"@intlify/message-resolver" "9.1.9"
|
||||
"@intlify/runtime" "9.1.9"
|
||||
"@intlify/shared" "9.1.9"
|
||||
|
||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
||||
@ -2399,6 +2498,11 @@ acorn@^8.2.4:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
|
||||
acorn@^8.5.0, acorn@^8.7.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
|
||||
|
||||
address@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
|
||||
@ -2645,6 +2749,11 @@ argparse@^1.0.7:
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
arr-diff@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
|
||||
@ -4892,7 +5001,7 @@ debug@^3.1.1, debug@^3.2.6, debug@^3.2.7:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.3.0, debug@^4.3.3:
|
||||
debug@^4.3.0, debug@^4.3.1, debug@^4.3.3:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
|
||||
@ -5615,6 +5724,14 @@ eslint-scope@^5.1.1:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.0.0:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
|
||||
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
|
||||
@ -5644,6 +5761,11 @@ eslint-visitor-keys@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186"
|
||||
integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==
|
||||
|
||||
eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
|
||||
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
|
||||
|
||||
eslint@7.25.0:
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.25.0.tgz#1309e4404d94e676e3e831b3a3ad2b050031eb67"
|
||||
@ -5710,6 +5832,15 @@ espree@^7.3.0, espree@^7.3.1:
|
||||
acorn-jsx "^5.3.1"
|
||||
eslint-visitor-keys "^1.3.0"
|
||||
|
||||
espree@^9.0.0, espree@^9.3.1:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd"
|
||||
integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==
|
||||
dependencies:
|
||||
acorn "^8.7.0"
|
||||
acorn-jsx "^5.3.1"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
esprima@^4.0.0, esprima@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
@ -7003,16 +7134,16 @@ ignore@^4.0.3, ignore@^4.0.6:
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
|
||||
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
|
||||
|
||||
ignore@^5.0.5, ignore@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
|
||||
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
|
||||
|
||||
ignore@^5.1.1, ignore@^5.1.4:
|
||||
version "5.1.8"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
|
||||
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
|
||||
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
|
||||
|
||||
import-cwd@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
||||
@ -7386,6 +7517,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-language-code@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-language-code/-/is-language-code-3.1.0.tgz#b2386b49227e7010636f16d0c2c681ca40136ab5"
|
||||
integrity sha512-zJdQ3QTeLye+iphMeK3wks+vXSRFKh68/Pnlw7aOfApFSEIOhYa8P9vwwa6QrImNNBMJTiL1PpYF0f4BxDuEgA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
|
||||
is-negative-zero@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
|
||||
@ -8571,6 +8709,13 @@ js-yaml@^3.13.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
js-yaml@^4.0.0, js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
@ -8723,7 +8868,7 @@ json3@^3.3.3:
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
|
||||
integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==
|
||||
|
||||
json5@2.x, json5@^2.1.2:
|
||||
json5@2.x, json5@^2.1.2, json5@^2.1.3:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
|
||||
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
|
||||
@ -8742,6 +8887,16 @@ json5@^1.0.1:
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
jsonc-eslint-parser@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.1.0.tgz#4c126b530aa583d85308d0b3041ff81ce402bbb2"
|
||||
integrity sha512-qCRJWlbP2v6HbmKW7R3lFbeiVWHo+oMJ0j+MizwvauqnCV/EvtAeEeuCgoc/ErtsuoKgYB8U4Ih8AxJbXoE6/g==
|
||||
dependencies:
|
||||
acorn "^8.5.0"
|
||||
eslint-visitor-keys "^3.0.0"
|
||||
espree "^9.0.0"
|
||||
semver "^7.3.5"
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||
@ -10014,7 +10169,7 @@ parse5@5.1.0:
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
|
||||
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==
|
||||
|
||||
parse5@6.0.1, parse5@^6.0.1:
|
||||
parse5@6.0.1, parse5@^6.0.0, parse5@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||
@ -11700,16 +11855,16 @@ source-map-url@^0.4.0:
|
||||
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
|
||||
integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
|
||||
|
||||
source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@^0.5.0, source-map@^0.5.6:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
|
||||
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@^0.7.3:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
@ -12970,6 +13125,19 @@ vue-eslint-parser@^7.10.0:
|
||||
lodash "^4.17.21"
|
||||
semver "^6.3.0"
|
||||
|
||||
vue-eslint-parser@^8.0.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
|
||||
integrity sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==
|
||||
dependencies:
|
||||
debug "^4.3.2"
|
||||
eslint-scope "^7.0.0"
|
||||
eslint-visitor-keys "^3.1.0"
|
||||
espree "^9.0.0"
|
||||
esquery "^1.4.0"
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.5"
|
||||
|
||||
vue-functional-data-merge@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz#08a7797583b7f35680587f8a1d51d729aa1dc657"
|
||||
@ -13515,7 +13683,16 @@ yallist@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
yaml@^1.10.0:
|
||||
yaml-eslint-parser@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/yaml-eslint-parser/-/yaml-eslint-parser-0.5.0.tgz#01d4e4d992a820769ea85ef5fd526dfc20ebc6f5"
|
||||
integrity sha512-nJeyLA3YHAzhBTZbRAbu3W6xrSCucyxExmA+ZDtEdUFpGllxAZpto2Zxo2IG0r0eiuEiBM4e+wiAdxTziTq94g==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.0.0"
|
||||
lodash "^4.17.21"
|
||||
yaml "^1.10.2"
|
||||
|
||||
yaml@^1.10.0, yaml@^1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
|
||||
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
|
||||
|
||||
@ -3,8 +3,9 @@ module.exports = {
|
||||
verbose: true,
|
||||
preset: 'ts-jest',
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**'],
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
||||
moduleNameMapper: {
|
||||
'@/(.*)': '<rootDir>/src/$1',
|
||||
'@model/(.*)': '<rootDir>/src/graphql/model/$1',
|
||||
|
||||
@ -10,10 +10,11 @@
|
||||
"scripts": {
|
||||
"build": "tsc --build",
|
||||
"clean": "tsc --build --clean",
|
||||
"start": "node build/src/index.js",
|
||||
"dev": "nodemon -w src --ext ts --exec ts-node src/index.ts",
|
||||
"start": "TZ=UTC TS_NODE_BASEURL=./build node -r tsconfig-paths/register build/src/index.js",
|
||||
"dev": "TZ=UTC nodemon -w src --ext ts --exec ts-node -r tsconfig-paths/register src/index.ts",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.ts .",
|
||||
"test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles"
|
||||
"test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles",
|
||||
"seed": "TZ=UTC ts-node -r tsconfig-paths/register src/seeds/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/jest": "^27.0.2",
|
||||
@ -31,7 +32,6 @@
|
||||
"jest": "^27.2.4",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"module-alias": "^2.2.2",
|
||||
"mysql2": "^2.3.0",
|
||||
"nodemailer": "^6.6.5",
|
||||
"random-bigint": "^0.0.1",
|
||||
@ -42,6 +42,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.12",
|
||||
"@types/faker": "^5.5.9",
|
||||
"@types/jsonwebtoken": "^8.5.2",
|
||||
"@types/node": "^16.10.3",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
@ -54,18 +55,11 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"faker": "^5.5.3",
|
||||
"nodemon": "^2.0.7",
|
||||
"prettier": "^2.3.1",
|
||||
"ts-node": "^10.0.0",
|
||||
"tsconfig-paths": "^3.14.0",
|
||||
"typescript": "^4.3.4"
|
||||
},
|
||||
"_moduleAliases": {
|
||||
"@": "./build/src",
|
||||
"@arg": "./build/src/graphql/arg",
|
||||
"@dbTools": "../database/build/src",
|
||||
"@entity": "../database/build/entity",
|
||||
"@enum": "./build/src/graphql/enum",
|
||||
"@model": "./build/src/graphql/model",
|
||||
"@repository": "./build/src/typeorm/repository"
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,4 +34,5 @@ export enum RIGHTS {
|
||||
SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
|
||||
DELETE_USER = 'DELETE_USER',
|
||||
UNDELETE_USER = 'UNDELETE_USER',
|
||||
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
|
||||
}
|
||||
|
||||
@ -11,10 +11,4 @@ export default class Paginated {
|
||||
|
||||
@Field(() => Order, { nullable: true })
|
||||
order?: Order
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
onlyCreations?: boolean
|
||||
|
||||
@Field(() => Int, { nullable: true })
|
||||
userId?: number
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ const isAuthorized: AuthChecker<any> = async ({ context }, rights) => {
|
||||
const userRepository = await getCustomRepository(UserRepository)
|
||||
try {
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
context.user = user
|
||||
const countServerUsers = await ServerUser.count({ email: user.email })
|
||||
context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER
|
||||
} catch {
|
||||
|
||||
@ -6,7 +6,7 @@ export enum TransactionTypeId {
|
||||
RECEIVE = 3,
|
||||
// This is a virtual property, never occurring on the database
|
||||
DECAY = 4,
|
||||
TRANSACTION_LINK = 5,
|
||||
LINK_SUMMARY = 5,
|
||||
}
|
||||
|
||||
registerEnumType(TransactionTypeId, {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx } from 'type-graphql'
|
||||
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type-graphql'
|
||||
import {
|
||||
getCustomRepository,
|
||||
IsNull,
|
||||
@ -19,16 +19,21 @@ import { UserRepository } from '@repository/User'
|
||||
import CreatePendingCreationArgs from '@arg/CreatePendingCreationArgs'
|
||||
import UpdatePendingCreationArgs from '@arg/UpdatePendingCreationArgs'
|
||||
import SearchUsersArgs from '@arg/SearchUsersArgs'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { Transaction as DbTransaction } from '@entity/Transaction'
|
||||
import { Transaction } from '@model/Transaction'
|
||||
import { TransactionRepository } from '@repository/Transaction'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
|
||||
import { hasElopageBuys } from '@/util/hasElopageBuys'
|
||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||
import { User } from '@entity/User'
|
||||
import { User as dbUser } from '@entity/User'
|
||||
import { User } from '@model/User'
|
||||
import { TransactionTypeId } from '@enum/TransactionTypeId'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { Decay } from '@model/Decay'
|
||||
import Paginated from '@arg/Paginated'
|
||||
import { Order } from '@enum/Order'
|
||||
import { communityUser } from '@/util/communityUser'
|
||||
|
||||
// const EMAIL_OPT_IN_REGISTER = 1
|
||||
// const EMAIL_OPT_UNKNOWN = 3 // elopage?
|
||||
@ -123,27 +128,26 @@ export class AdminResolver {
|
||||
@Authorized([RIGHTS.DELETE_USER])
|
||||
@Mutation(() => Date, { nullable: true })
|
||||
async deleteUser(@Arg('userId') userId: number, @Ctx() context: any): Promise<Date | null> {
|
||||
const user = await User.findOne({ id: userId })
|
||||
const user = await dbUser.findOne({ id: userId })
|
||||
// user exists ?
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with userId: ${userId}`)
|
||||
}
|
||||
// moderator user disabled own account?
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const moderatorUser = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const moderatorUser = context.user
|
||||
if (moderatorUser.id === userId) {
|
||||
throw new Error('Moderator can not delete his own account!')
|
||||
}
|
||||
// soft-delete user
|
||||
await user.softRemove()
|
||||
const newUser = await User.findOne({ id: userId }, { withDeleted: true })
|
||||
const newUser = await dbUser.findOne({ id: userId }, { withDeleted: true })
|
||||
return newUser ? newUser.deletedAt : null
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.UNDELETE_USER])
|
||||
@Mutation(() => Date, { nullable: true })
|
||||
async unDeleteUser(@Arg('userId') userId: number): Promise<Date | null> {
|
||||
const user = await User.findOne({ id: userId }, { withDeleted: true })
|
||||
const user = await dbUser.findOne({ id: userId }, { withDeleted: true })
|
||||
// user exists ?
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with userId: ${userId}`)
|
||||
@ -158,7 +162,7 @@ export class AdminResolver {
|
||||
async createPendingCreation(
|
||||
@Args() { email, amount, memo, creationDate, moderator }: CreatePendingCreationArgs,
|
||||
): Promise<number[]> {
|
||||
const user = await User.findOne({ email }, { withDeleted: true })
|
||||
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with email: ${email}`)
|
||||
}
|
||||
@ -215,7 +219,7 @@ export class AdminResolver {
|
||||
async updatePendingCreation(
|
||||
@Args() { id, email, amount, memo, creationDate, moderator }: UpdatePendingCreationArgs,
|
||||
): Promise<UpdatePendingCreation> {
|
||||
const user = await User.findOne({ email }, { withDeleted: true })
|
||||
const user = await dbUser.findOne({ email }, { withDeleted: true })
|
||||
if (!user) {
|
||||
throw new Error(`Could not find user with email: ${email}`)
|
||||
}
|
||||
@ -265,7 +269,7 @@ export class AdminResolver {
|
||||
|
||||
const userIds = pendingCreations.map((p) => p.userId)
|
||||
const userCreations = await getUserCreations(userIds)
|
||||
const users = await User.find({ where: { id: In(userIds) }, withDeleted: true })
|
||||
const users = await dbUser.find({ where: { id: In(userIds) }, withDeleted: true })
|
||||
|
||||
return pendingCreations.map((pendingCreation) => {
|
||||
const user = users.find((u) => u.id === pendingCreation.userId)
|
||||
@ -294,12 +298,11 @@ export class AdminResolver {
|
||||
@Mutation(() => Boolean)
|
||||
async confirmPendingCreation(@Arg('id') id: number, @Ctx() context: any): Promise<boolean> {
|
||||
const pendingCreation = await AdminPendingCreation.findOneOrFail(id)
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const moderatorUser = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const moderatorUser = context.user
|
||||
if (moderatorUser.id === pendingCreation.userId)
|
||||
throw new Error('Moderator can not confirm own pending creation')
|
||||
|
||||
const user = await User.findOneOrFail({ id: pendingCreation.userId }, { withDeleted: true })
|
||||
const user = await dbUser.findOneOrFail({ id: pendingCreation.userId }, { withDeleted: true })
|
||||
if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a creation.')
|
||||
|
||||
const creations = await getUserCreation(pendingCreation.userId, false)
|
||||
@ -321,7 +324,7 @@ export class AdminResolver {
|
||||
// TODO pending creations decimal
|
||||
newBalance = newBalance.add(new Decimal(Number(pendingCreation.amount)).toString())
|
||||
|
||||
const transaction = new Transaction()
|
||||
const transaction = new DbTransaction()
|
||||
transaction.typeId = TransactionTypeId.CREATION
|
||||
transaction.memo = pendingCreation.memo
|
||||
transaction.userId = pendingCreation.userId
|
||||
@ -339,6 +342,27 @@ export class AdminResolver {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.CREATION_TRANSACTION_LIST])
|
||||
@Query(() => [Transaction])
|
||||
async creationTransactionList(
|
||||
@Args()
|
||||
{ currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated,
|
||||
@Arg('userId', () => Int) userId: number,
|
||||
): Promise<Transaction[]> {
|
||||
const offset = (currentPage - 1) * pageSize
|
||||
const transactionRepository = getCustomRepository(TransactionRepository)
|
||||
const [userTransactions] = await transactionRepository.findByUserPaged(
|
||||
userId,
|
||||
pageSize,
|
||||
offset,
|
||||
order,
|
||||
true,
|
||||
)
|
||||
|
||||
const user = await dbUser.findOneOrFail({ id: userId })
|
||||
return userTransactions.map((t) => new Transaction(t, new User(user), communityUser))
|
||||
}
|
||||
}
|
||||
|
||||
interface CreationMap {
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Resolver, Query, Ctx, Authorized } from 'type-graphql'
|
||||
import { getCustomRepository } from '@dbTools/typeorm'
|
||||
import { Balance } from '@model/Balance'
|
||||
import { UserRepository } from '@repository/User'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
@ -16,9 +14,7 @@ export class BalanceResolver {
|
||||
@Query(() => Balance)
|
||||
async balance(@Ctx() context: any): Promise<Balance> {
|
||||
// load user and balance
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const { user } = context
|
||||
const now = new Date()
|
||||
|
||||
const lastTransaction = await Transaction.findOne(
|
||||
|
||||
@ -2,12 +2,10 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Resolver, Query, Args, Ctx, Authorized, Arg } from 'type-graphql'
|
||||
import { getCustomRepository } from '@dbTools/typeorm'
|
||||
import CONFIG from '@/config'
|
||||
import { GdtEntryList } from '@model/GdtEntryList'
|
||||
import Paginated from '@arg/Paginated'
|
||||
import { apiGet } from '@/apis/HttpRequest'
|
||||
import { UserRepository } from '@repository/User'
|
||||
import { Order } from '@enum/Order'
|
||||
import { RIGHTS } from '@/auth/RIGHTS'
|
||||
|
||||
@ -22,8 +20,7 @@ export class GdtResolver {
|
||||
@Ctx() context: any,
|
||||
): Promise<GdtEntryList> {
|
||||
// load user
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const userEntity = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const userEntity = context.user
|
||||
|
||||
try {
|
||||
const resultGDT = await apiGet(
|
||||
|
||||
@ -2,11 +2,9 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query } from 'type-graphql'
|
||||
import { getCustomRepository } from '@dbTools/typeorm'
|
||||
import { TransactionLink } from '@model/TransactionLink'
|
||||
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
|
||||
import { User as dbUser } from '@entity/User'
|
||||
import { UserRepository } from '@repository/User'
|
||||
import TransactionLinkArgs from '@arg/TransactionLinkArgs'
|
||||
import Paginated from '@arg/Paginated'
|
||||
import { calculateBalance } from '@/util/validate'
|
||||
@ -29,7 +27,7 @@ export const transactionLinkCode = (date: Date): string => {
|
||||
|
||||
const CODE_VALID_DAYS_DURATION = 14
|
||||
|
||||
const transactionLinkExpireDate = (date: Date): Date => {
|
||||
export const transactionLinkExpireDate = (date: Date): Date => {
|
||||
const validUntil = new Date(date)
|
||||
return new Date(validUntil.setDate(date.getDate() + CODE_VALID_DAYS_DURATION))
|
||||
}
|
||||
@ -42,8 +40,7 @@ export class TransactionLinkResolver {
|
||||
@Args() { amount, memo }: TransactionLinkArgs,
|
||||
@Ctx() context: any,
|
||||
): Promise<TransactionLink> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const { user } = context
|
||||
|
||||
const createdDate = new Date()
|
||||
const validUntil = transactionLinkExpireDate(createdDate)
|
||||
@ -74,8 +71,7 @@ export class TransactionLinkResolver {
|
||||
@Authorized([RIGHTS.DELETE_TRANSACTION_LINK])
|
||||
@Mutation(() => Boolean)
|
||||
async deleteTransactionLink(@Arg('id') id: number, @Ctx() context: any): Promise<boolean> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const { user } = context
|
||||
|
||||
const transactionLink = await dbTransactionLink.findOne({ id })
|
||||
if (!transactionLink) {
|
||||
@ -116,8 +112,7 @@ export class TransactionLinkResolver {
|
||||
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
|
||||
@Ctx() context: any,
|
||||
): Promise<TransactionLink[]> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const { user } = context
|
||||
// const now = new Date()
|
||||
const transactionLinks = await dbTransactionLink.find({
|
||||
where: {
|
||||
@ -137,8 +132,7 @@ export class TransactionLinkResolver {
|
||||
@Authorized([RIGHTS.REDEEM_TRANSACTION_LINK])
|
||||
@Mutation(() => Boolean)
|
||||
async redeemTransactionLink(@Arg('id') id: number, @Ctx() context: any): Promise<boolean> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const { user } = context
|
||||
const transactionLink = await dbTransactionLink.findOneOrFail({ id })
|
||||
const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId })
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@ import Paginated from '@arg/Paginated'
|
||||
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
import { UserRepository } from '@repository/User'
|
||||
import { TransactionRepository } from '@repository/Transaction'
|
||||
import { TransactionLinkRepository } from '@repository/TransactionLink'
|
||||
|
||||
@ -131,22 +130,11 @@ export class TransactionResolver {
|
||||
@Query(() => TransactionList)
|
||||
async transactionList(
|
||||
@Args()
|
||||
{
|
||||
currentPage = 1,
|
||||
pageSize = 25,
|
||||
order = Order.DESC,
|
||||
onlyCreations = false,
|
||||
userId,
|
||||
}: Paginated,
|
||||
{ currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated,
|
||||
@Ctx() context: any,
|
||||
): Promise<TransactionList> {
|
||||
const now = new Date()
|
||||
// find user
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
// TODO: separate those usecases - this is a security issue
|
||||
const user = userId
|
||||
? await userRepository.findOneOrFail({ id: userId }, { withDeleted: true })
|
||||
: await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const user = context.user
|
||||
|
||||
// find current balance
|
||||
const lastTransaction = await dbTransaction.findOne(
|
||||
@ -182,7 +170,6 @@ export class TransactionResolver {
|
||||
pageSize,
|
||||
offset,
|
||||
order,
|
||||
onlyCreations,
|
||||
)
|
||||
|
||||
// find involved users; I am involved
|
||||
@ -208,7 +195,7 @@ export class TransactionResolver {
|
||||
await transactionLinkRepository.summary(user.id, now)
|
||||
|
||||
// decay & link transactions
|
||||
if (!onlyCreations && currentPage === 1 && order === Order.DESC) {
|
||||
if (currentPage === 1 && order === Order.DESC) {
|
||||
transactions.push(
|
||||
virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self),
|
||||
)
|
||||
@ -256,8 +243,7 @@ export class TransactionResolver {
|
||||
@Ctx() context: any,
|
||||
): Promise<boolean> {
|
||||
// TODO this is subject to replay attacks
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const senderUser = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const senderUser = context.user
|
||||
if (senderUser.pubKey.length !== 32) {
|
||||
throw new Error('invalid sender public key')
|
||||
}
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers'
|
||||
import { createUserMutation, setPasswordMutation } from '@test/graphql'
|
||||
import gql from 'graphql-tag'
|
||||
import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers'
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||
import { createUser, setPassword } from '@/seeds/graphql/mutations'
|
||||
import { login, logout } from '@/seeds/graphql/queries'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||
import { User } from '@entity/User'
|
||||
import CONFIG from '@/config'
|
||||
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
||||
// import { klicktippSignIn } from '@/apis/KlicktippController'
|
||||
|
||||
jest.setTimeout(1000000)
|
||||
// import { klicktippSignIn } from '@/apis/KlicktippController'
|
||||
|
||||
jest.mock('@/mailer/sendAccountActivationEmail', () => {
|
||||
return {
|
||||
@ -30,27 +31,10 @@ jest.mock('@/apis/KlicktippController', () => {
|
||||
*/
|
||||
|
||||
let mutate: any, query: any, con: any
|
||||
|
||||
const loginQuery = gql`
|
||||
query ($email: String!, $password: String!, $publisherId: Int) {
|
||||
login(email: $email, password: $password, publisherId: $publisherId) {
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
language
|
||||
coinanimation
|
||||
klickTipp {
|
||||
newsletterState
|
||||
}
|
||||
hasElopage
|
||||
publisherId
|
||||
isAdmin
|
||||
}
|
||||
}
|
||||
`
|
||||
let testEnv: any
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await testEnvironment()
|
||||
testEnv = await testEnvironment()
|
||||
mutate = testEnv.mutate
|
||||
query = testEnv.query
|
||||
con = testEnv.con
|
||||
@ -77,7 +61,7 @@ describe('UserResolver', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.clearAllMocks()
|
||||
result = await mutate({ mutation: createUserMutation, variables })
|
||||
result = await mutate({ mutation: createUser, variables })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -85,7 +69,9 @@ describe('UserResolver', () => {
|
||||
})
|
||||
|
||||
it('returns success', () => {
|
||||
expect(result).toEqual(expect.objectContaining({ data: { createUser: 'success' } }))
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({ data: { createUser: { id: expect.any(Number) } } }),
|
||||
)
|
||||
})
|
||||
|
||||
describe('valid input data', () => {
|
||||
@ -149,7 +135,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('email already exists', () => {
|
||||
it('throws an error', async () => {
|
||||
await expect(mutate({ mutation: createUserMutation, variables })).resolves.toEqual(
|
||||
await expect(mutate({ mutation: createUser, variables })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('User already exists.')],
|
||||
}),
|
||||
@ -160,7 +146,7 @@ describe('UserResolver', () => {
|
||||
describe('unknown language', () => {
|
||||
it('sets "de" as default language', async () => {
|
||||
await mutate({
|
||||
mutation: createUserMutation,
|
||||
mutation: createUser,
|
||||
variables: { ...variables, email: 'bibi@bloxberg.de', language: 'es' },
|
||||
})
|
||||
await expect(User.find()).resolves.toEqual(
|
||||
@ -177,7 +163,7 @@ describe('UserResolver', () => {
|
||||
describe('no publisher id', () => {
|
||||
it('sets publisher id to null', async () => {
|
||||
await mutate({
|
||||
mutation: createUserMutation,
|
||||
mutation: createUser,
|
||||
variables: { ...variables, email: 'raeuber@hotzenplotz.de', publisherId: undefined },
|
||||
})
|
||||
await expect(User.find()).resolves.toEqual(
|
||||
@ -208,11 +194,11 @@ describe('UserResolver', () => {
|
||||
let newUser: any
|
||||
|
||||
beforeAll(async () => {
|
||||
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||
await mutate({ mutation: createUser, variables: createUserVariables })
|
||||
const loginEmailOptIn = await LoginEmailOptIn.find()
|
||||
emailOptIn = loginEmailOptIn[0].verificationCode.toString()
|
||||
result = await mutate({
|
||||
mutation: setPasswordMutation,
|
||||
mutation: setPassword,
|
||||
variables: { code: emailOptIn, password: 'Aa12345_' },
|
||||
})
|
||||
newUser = await User.find()
|
||||
@ -252,11 +238,11 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('no valid password', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||
await mutate({ mutation: createUser, variables: createUserVariables })
|
||||
const loginEmailOptIn = await LoginEmailOptIn.find()
|
||||
emailOptIn = loginEmailOptIn[0].verificationCode.toString()
|
||||
result = await mutate({
|
||||
mutation: setPasswordMutation,
|
||||
mutation: setPassword,
|
||||
variables: { code: emailOptIn, password: 'not-valid' },
|
||||
})
|
||||
})
|
||||
@ -280,9 +266,9 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('no valid optin code', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({ mutation: createUserMutation, variables: createUserVariables })
|
||||
await mutate({ mutation: createUser, variables: createUserVariables })
|
||||
result = await mutate({
|
||||
mutation: setPasswordMutation,
|
||||
mutation: setPassword,
|
||||
variables: { code: 'not valid', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
@ -303,7 +289,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('login', () => {
|
||||
const variables = {
|
||||
email: 'peter@lustig.de',
|
||||
email: 'bibi@bloxberg.de',
|
||||
password: 'Aa12345_',
|
||||
publisherId: 1234,
|
||||
}
|
||||
@ -316,7 +302,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('no users in database', () => {
|
||||
beforeAll(async () => {
|
||||
result = await query({ query: loginQuery, variables })
|
||||
result = await query({ query: login, variables })
|
||||
})
|
||||
|
||||
it('throws an error', () => {
|
||||
@ -330,14 +316,8 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('user is in database and correct login data', () => {
|
||||
beforeAll(async () => {
|
||||
await createUser(mutate, {
|
||||
email: 'peter@lustig.de',
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
language: 'de',
|
||||
publisherId: 1234,
|
||||
})
|
||||
result = await query({ query: loginQuery, variables })
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
result = await query({ query: login, variables })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -350,15 +330,16 @@ describe('UserResolver', () => {
|
||||
data: {
|
||||
login: {
|
||||
coinanimation: true,
|
||||
email: 'peter@lustig.de',
|
||||
firstName: 'Peter',
|
||||
email: 'bibi@bloxberg.de',
|
||||
firstName: 'Bibi',
|
||||
hasElopage: false,
|
||||
id: expect.any(Number),
|
||||
isAdmin: false,
|
||||
klickTipp: {
|
||||
newsletterState: false,
|
||||
},
|
||||
language: 'de',
|
||||
lastName: 'Lustig',
|
||||
lastName: 'Bloxberg',
|
||||
publisherId: 1234,
|
||||
},
|
||||
},
|
||||
@ -373,13 +354,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('user is in database and wrong password', () => {
|
||||
beforeAll(async () => {
|
||||
await createUser(mutate, {
|
||||
email: 'peter@lustig.de',
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
language: 'de',
|
||||
publisherId: 1234,
|
||||
})
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -388,7 +363,7 @@ describe('UserResolver', () => {
|
||||
|
||||
it('returns an error', () => {
|
||||
expect(
|
||||
query({ query: loginQuery, variables: { ...variables, password: 'wrong' } }),
|
||||
query({ query: login, variables: { ...variables, password: 'wrong' } }),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('No user with this credentials')],
|
||||
@ -399,16 +374,10 @@ describe('UserResolver', () => {
|
||||
})
|
||||
|
||||
describe('logout', () => {
|
||||
const logoutQuery = gql`
|
||||
query {
|
||||
logout
|
||||
}
|
||||
`
|
||||
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
resetToken()
|
||||
await expect(query({ query: logoutQuery })).resolves.toEqual(
|
||||
await expect(query({ query: logout })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('401 Unauthorized')],
|
||||
}),
|
||||
@ -418,19 +387,13 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('authenticated', () => {
|
||||
const variables = {
|
||||
email: 'peter@lustig.de',
|
||||
email: 'bibi@bloxberg.de',
|
||||
password: 'Aa12345_',
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await createUser(mutate, {
|
||||
email: 'peter@lustig.de',
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
language: 'de',
|
||||
publisherId: 1234,
|
||||
})
|
||||
await query({ query: loginQuery, variables })
|
||||
await userFactory(testEnv, bibiBloxberg)
|
||||
await query({ query: login, variables })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@ -438,7 +401,7 @@ describe('UserResolver', () => {
|
||||
})
|
||||
|
||||
it('returns true', async () => {
|
||||
await expect(query({ query: logoutQuery })).resolves.toEqual(
|
||||
await expect(query({ query: logout })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
data: { logout: 'true' },
|
||||
errors: undefined,
|
||||
|
||||
@ -14,7 +14,6 @@ import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs'
|
||||
import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddleware'
|
||||
import { UserSettingRepository } from '@repository/UserSettingRepository'
|
||||
import { Setting } from '@enum/Setting'
|
||||
import { UserRepository } from '@repository/User'
|
||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||
import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail'
|
||||
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
|
||||
@ -208,8 +207,7 @@ export class UserResolver {
|
||||
@UseMiddleware(klicktippNewsletterStateMiddleware)
|
||||
async verifyLogin(@Ctx() context: any): Promise<User> {
|
||||
// TODO refactor and do not have duplicate code with login(see below)
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const userEntity = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const userEntity = context.user
|
||||
const user = new User(userEntity)
|
||||
// user.pubkey = userEntity.pubKey.toString('hex')
|
||||
// Elopage Status & Stored PublisherId
|
||||
@ -307,10 +305,10 @@ export class UserResolver {
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.CREATE_USER])
|
||||
@Mutation(() => String)
|
||||
@Mutation(() => User)
|
||||
async createUser(
|
||||
@Args() { email, firstName, lastName, language, publisherId }: CreateUserArgs,
|
||||
): Promise<string> {
|
||||
): Promise<User> {
|
||||
// TODO: wrong default value (should be null), how does graphql work here? Is it an required field?
|
||||
// default int publisher_id = 0;
|
||||
|
||||
@ -390,7 +388,7 @@ export class UserResolver {
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
return 'success'
|
||||
return new User(dbUser)
|
||||
}
|
||||
|
||||
// THis is used by the admin only - should we move it to the admin resolver?
|
||||
@ -589,8 +587,7 @@ export class UserResolver {
|
||||
}: UpdateUserInfosArgs,
|
||||
@Ctx() context: any,
|
||||
): Promise<boolean> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const userEntity = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const userEntity = context.user
|
||||
|
||||
if (firstName) {
|
||||
userEntity.firstName = firstName
|
||||
@ -668,8 +665,7 @@ export class UserResolver {
|
||||
@Authorized([RIGHTS.HAS_ELOPAGE])
|
||||
@Query(() => Boolean)
|
||||
async hasElopage(@Ctx() context: any): Promise<boolean> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const userEntity = await userRepository.findByPubkeyHex(context.pubKey).catch()
|
||||
const userEntity = context.user
|
||||
if (!userEntity) {
|
||||
return false
|
||||
}
|
||||
|
||||
7
backend/src/seeds/creation/CreationInterface.ts
Normal file
7
backend/src/seeds/creation/CreationInterface.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface CreationInterface {
|
||||
email: string
|
||||
amount: number
|
||||
memo: string
|
||||
creationDate: string
|
||||
confirmed?: boolean
|
||||
}
|
||||
29
backend/src/seeds/creation/index.ts
Normal file
29
backend/src/seeds/creation/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { CreationInterface } from './CreationInterface'
|
||||
|
||||
const lastMonth = (date: Date): string => {
|
||||
return new Date(date.getFullYear(), date.getMonth() - 1, 1).toISOString()
|
||||
}
|
||||
|
||||
export const creations: CreationInterface[] = [
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 1000,
|
||||
memo: 'Herzlich Willkommen bei Gradido!',
|
||||
creationDate: lastMonth(new Date()),
|
||||
confirmed: true,
|
||||
},
|
||||
{
|
||||
email: 'bob@baumeister.de',
|
||||
amount: 1000,
|
||||
memo: 'Herzlich Willkommen bei Gradido!',
|
||||
creationDate: lastMonth(new Date()),
|
||||
confirmed: true,
|
||||
},
|
||||
{
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
amount: 1000,
|
||||
memo: 'Herzlich Willkommen bei Gradido!',
|
||||
creationDate: lastMonth(new Date()),
|
||||
confirmed: true,
|
||||
},
|
||||
]
|
||||
38
backend/src/seeds/factory/creation.ts
Normal file
38
backend/src/seeds/factory/creation.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { createPendingCreation, confirmPendingCreation } from '@/seeds/graphql/mutations'
|
||||
import { login } from '@/seeds/graphql/queries'
|
||||
import { CreationInterface } from '@/seeds/creation/CreationInterface'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { User } from '@entity/User'
|
||||
import { AdminPendingCreation } from '@entity/AdminPendingCreation'
|
||||
// import CONFIG from '@/config/index'
|
||||
|
||||
export const creationFactory = async (
|
||||
client: ApolloServerTestClient,
|
||||
creation: CreationInterface,
|
||||
): Promise<void> => {
|
||||
const { mutate, query } = client
|
||||
|
||||
// login as Peter Lustig (admin) and get his user ID
|
||||
const {
|
||||
data: {
|
||||
login: { id },
|
||||
},
|
||||
} = await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
|
||||
|
||||
await mutate({ mutation: createPendingCreation, variables: { ...creation, moderator: id } })
|
||||
|
||||
// get User
|
||||
const user = await User.findOneOrFail({ where: { email: creation.email } })
|
||||
|
||||
if (creation.confirmed) {
|
||||
const pendingCreation = await AdminPendingCreation.findOneOrFail({
|
||||
where: { userId: user.id },
|
||||
order: { created: 'DESC' },
|
||||
})
|
||||
|
||||
await mutate({ mutation: confirmPendingCreation, variables: { id: pendingCreation.id } })
|
||||
}
|
||||
}
|
||||
43
backend/src/seeds/factory/transactionLink.ts
Normal file
43
backend/src/seeds/factory/transactionLink.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { createTransactionLink } from '@/seeds/graphql/mutations'
|
||||
import { login } from '@/seeds/graphql/queries'
|
||||
import { TransactionLinkInterface } from '@/seeds/transactionLink/TransactionLinkInterface'
|
||||
import { transactionLinkExpireDate } from '@/graphql/resolver/TransactionLinkResolver'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
export const transactionLinkFactory = async (
|
||||
client: ApolloServerTestClient,
|
||||
transactionLink: TransactionLinkInterface,
|
||||
): Promise<void> => {
|
||||
const { mutate, query } = client
|
||||
|
||||
// login
|
||||
await query({ query: login, variables: { email: transactionLink.email, password: 'Aa12345_' } })
|
||||
|
||||
const variables = {
|
||||
amount: transactionLink.amount,
|
||||
memo: transactionLink.memo,
|
||||
}
|
||||
|
||||
// get the transaction links's id
|
||||
const {
|
||||
data: {
|
||||
createTransactionLink: { id },
|
||||
},
|
||||
} = await mutate({ mutation: createTransactionLink, variables })
|
||||
|
||||
if (transactionLink.createdAt || transactionLink.deletedAt) {
|
||||
const dbTransactionLink = await TransactionLink.findOneOrFail({ id })
|
||||
|
||||
if (transactionLink.createdAt) {
|
||||
dbTransactionLink.createdAt = transactionLink.createdAt
|
||||
dbTransactionLink.validUntil = transactionLinkExpireDate(transactionLink.createdAt)
|
||||
await dbTransactionLink.save()
|
||||
}
|
||||
|
||||
if (transactionLink.deletedAt) {
|
||||
dbTransactionLink.deletedAt = new Date()
|
||||
await dbTransactionLink.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
51
backend/src/seeds/factory/user.ts
Normal file
51
backend/src/seeds/factory/user.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { createUser, setPassword } from '@/seeds/graphql/mutations'
|
||||
import { User } from '@entity/User'
|
||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||
import { ServerUser } from '@entity/ServerUser'
|
||||
import { UserInterface } from '@/seeds/users/UserInterface'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
|
||||
export const userFactory = async (
|
||||
client: ApolloServerTestClient,
|
||||
user: UserInterface,
|
||||
): Promise<void> => {
|
||||
const { mutate } = client
|
||||
|
||||
const {
|
||||
data: {
|
||||
createUser: { id },
|
||||
},
|
||||
} = await mutate({ mutation: createUser, variables: user })
|
||||
|
||||
if (user.emailChecked) {
|
||||
const optin = await LoginEmailOptIn.findOneOrFail({ userId: id })
|
||||
await mutate({
|
||||
mutation: setPassword,
|
||||
variables: { password: 'Aa12345_', code: optin.verificationCode },
|
||||
})
|
||||
}
|
||||
|
||||
if (user.createdAt || user.deletedAt || user.isAdmin) {
|
||||
// get user from database
|
||||
const dbUser = await User.findOneOrFail({ id })
|
||||
|
||||
if (user.createdAt || user.deletedAt) {
|
||||
if (user.createdAt) dbUser.createdAt = user.createdAt
|
||||
if (user.deletedAt) dbUser.deletedAt = user.deletedAt
|
||||
await dbUser.save()
|
||||
}
|
||||
|
||||
if (user.isAdmin) {
|
||||
const admin = new ServerUser()
|
||||
admin.username = dbUser.firstName
|
||||
admin.password = 'please_refactor'
|
||||
admin.email = dbUser.email
|
||||
admin.role = 'admin'
|
||||
admin.activated = 1
|
||||
admin.lastLogin = new Date()
|
||||
admin.created = dbUser.createdAt
|
||||
admin.modified = dbUser.createdAt
|
||||
await admin.save()
|
||||
}
|
||||
}
|
||||
}
|
||||
9
backend/src/seeds/graphql/enums.ts
Normal file
9
backend/src/seeds/graphql/enums.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export const GdtEntryType = {
|
||||
FORM: 'FORM',
|
||||
CVS: 'CVS',
|
||||
ELOPAGE: 'ELOPAGE',
|
||||
ELOPAGE_PUBLISHER: 'ELOPAGE_PUBLISHER',
|
||||
DIGISTORE: 'DIGISTORE',
|
||||
CVS2: 'CVS2',
|
||||
GLOBAL_MODIFICATOR: 'GLOBAL_MODIFICATOR',
|
||||
}
|
||||
100
backend/src/seeds/graphql/mutations.ts
Normal file
100
backend/src/seeds/graphql/mutations.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const subscribeNewsletter = gql`
|
||||
mutation ($email: String!, $language: String!) {
|
||||
subscribeNewsletter(email: $email, language: $language)
|
||||
}
|
||||
`
|
||||
|
||||
export const unsubscribeNewsletter = gql`
|
||||
mutation ($email: String!) {
|
||||
unsubscribeNewsletter(email: $email)
|
||||
}
|
||||
`
|
||||
|
||||
export const setPassword = gql`
|
||||
mutation ($code: String!, $password: String!) {
|
||||
setPassword(code: $code, password: $password)
|
||||
}
|
||||
`
|
||||
|
||||
export const updateUserInfos = gql`
|
||||
mutation (
|
||||
$firstName: String
|
||||
$lastName: String
|
||||
$password: String
|
||||
$passwordNew: String
|
||||
$locale: String
|
||||
$coinanimation: Boolean
|
||||
) {
|
||||
updateUserInfos(
|
||||
firstName: $firstName
|
||||
lastName: $lastName
|
||||
password: $password
|
||||
passwordNew: $passwordNew
|
||||
language: $locale
|
||||
coinanimation: $coinanimation
|
||||
)
|
||||
}
|
||||
`
|
||||
|
||||
export const createUser = gql`
|
||||
mutation (
|
||||
$firstName: String!
|
||||
$lastName: String!
|
||||
$email: String!
|
||||
$language: String!
|
||||
$publisherId: Int
|
||||
) {
|
||||
createUser(
|
||||
email: $email
|
||||
firstName: $firstName
|
||||
lastName: $lastName
|
||||
language: $language
|
||||
publisherId: $publisherId
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const sendCoins = gql`
|
||||
mutation ($email: String!, $amount: Decimal!, $memo: String!) {
|
||||
sendCoins(email: $email, amount: $amount, memo: $memo)
|
||||
}
|
||||
`
|
||||
|
||||
export const createTransactionLink = gql`
|
||||
mutation ($amount: Decimal!, $memo: String!) {
|
||||
createTransactionLink(amount: $amount, memo: $memo) {
|
||||
id
|
||||
code
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// from admin interface
|
||||
|
||||
export const createPendingCreation = gql`
|
||||
mutation (
|
||||
$email: String!
|
||||
$amount: Float!
|
||||
$memo: String!
|
||||
$creationDate: String!
|
||||
$moderator: Int!
|
||||
) {
|
||||
createPendingCreation(
|
||||
email: $email
|
||||
amount: $amount
|
||||
memo: $memo
|
||||
creationDate: $creationDate
|
||||
moderator: $moderator
|
||||
)
|
||||
}
|
||||
`
|
||||
|
||||
export const confirmPendingCreation = gql`
|
||||
mutation ($id: Float!) {
|
||||
confirmPendingCreation(id: $id)
|
||||
}
|
||||
`
|
||||
145
backend/src/seeds/graphql/queries.ts
Normal file
145
backend/src/seeds/graphql/queries.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const login = gql`
|
||||
query ($email: String!, $password: String!, $publisherId: Int) {
|
||||
login(email: $email, password: $password, publisherId: $publisherId) {
|
||||
id
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
language
|
||||
coinanimation
|
||||
klickTipp {
|
||||
newsletterState
|
||||
}
|
||||
hasElopage
|
||||
publisherId
|
||||
isAdmin
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const verifyLogin = gql`
|
||||
query {
|
||||
verifyLogin {
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
language
|
||||
coinanimation
|
||||
klickTipp {
|
||||
newsletterState
|
||||
}
|
||||
hasElopage
|
||||
publisherId
|
||||
isAdmin
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const logout = gql`
|
||||
query {
|
||||
logout
|
||||
}
|
||||
`
|
||||
|
||||
export const transactionsQuery = gql`
|
||||
query (
|
||||
$currentPage: Int = 1
|
||||
$pageSize: Int = 25
|
||||
$order: Order = DESC
|
||||
$onlyCreations: Boolean = false
|
||||
) {
|
||||
transactionList(
|
||||
currentPage: $currentPage
|
||||
pageSize: $pageSize
|
||||
order: $order
|
||||
onlyCreations: $onlyCreations
|
||||
) {
|
||||
balanceGDT
|
||||
count
|
||||
balance
|
||||
decayStartBlock
|
||||
transactions {
|
||||
id
|
||||
typeId
|
||||
amount
|
||||
balance
|
||||
balanceDate
|
||||
memo
|
||||
linkedUser {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
decay {
|
||||
decay
|
||||
start
|
||||
end
|
||||
duration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const sendResetPasswordEmail = gql`
|
||||
query ($email: String!) {
|
||||
sendResetPasswordEmail(email: $email)
|
||||
}
|
||||
`
|
||||
|
||||
export const listGDTEntriesQuery = gql`
|
||||
query ($currentPage: Int!, $pageSize: Int!) {
|
||||
listGDTEntries(currentPage: $currentPage, pageSize: $pageSize) {
|
||||
count
|
||||
gdtEntries {
|
||||
id
|
||||
amount
|
||||
date
|
||||
comment
|
||||
gdtEntryType
|
||||
factor
|
||||
gdt
|
||||
}
|
||||
gdtSum
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const communityInfo = gql`
|
||||
query {
|
||||
getCommunityInfo {
|
||||
name
|
||||
description
|
||||
registerUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const communities = gql`
|
||||
query {
|
||||
communities {
|
||||
id
|
||||
name
|
||||
url
|
||||
description
|
||||
registerUrl
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const queryTransactionLink = gql`
|
||||
query ($code: String!) {
|
||||
queryTransactionLink(code: $code) {
|
||||
amount
|
||||
memo
|
||||
createdAt
|
||||
validUntil
|
||||
user {
|
||||
firstName
|
||||
publisherId
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
77
backend/src/seeds/index.ts
Normal file
77
backend/src/seeds/index.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import createServer from '../server/createServer'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
|
||||
import { name, internet, random } from 'faker'
|
||||
|
||||
import { users } from './users/index'
|
||||
import { creations } from './creation/index'
|
||||
import { transactionLinks } from './transactionLink/index'
|
||||
import { userFactory } from './factory/user'
|
||||
import { creationFactory } from './factory/creation'
|
||||
import { transactionLinkFactory } from './factory/transactionLink'
|
||||
import { entities } from '@entity/index'
|
||||
|
||||
const context = {
|
||||
token: '',
|
||||
setHeaders: {
|
||||
push: (value: { key: string; value: string }): void => {
|
||||
context.token = value.value
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
forEach: (): void => {},
|
||||
},
|
||||
}
|
||||
|
||||
export const cleanDB = async () => {
|
||||
// this only works as lond we do not have foreign key constraints
|
||||
for (let i = 0; i < entities.length; i++) {
|
||||
await resetEntity(entities[i])
|
||||
}
|
||||
}
|
||||
|
||||
const resetEntity = async (entity: any) => {
|
||||
const items = await entity.find({ withDeleted: true })
|
||||
if (items.length > 0) {
|
||||
const ids = items.map((i: any) => i.id)
|
||||
await entity.delete(ids)
|
||||
}
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
const server = await createServer(context)
|
||||
const seedClient = createTestClient(server.apollo)
|
||||
const { con } = server
|
||||
await cleanDB()
|
||||
|
||||
// seed the standard users
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
await userFactory(seedClient, users[i])
|
||||
}
|
||||
|
||||
// seed 100 random users
|
||||
for (let i = 0; i < 100; i++) {
|
||||
await userFactory(seedClient, {
|
||||
firstName: name.firstName(),
|
||||
lastName: name.lastName(),
|
||||
email: internet.email(),
|
||||
language: random.boolean() ? 'en' : 'de',
|
||||
})
|
||||
}
|
||||
|
||||
// create GDD
|
||||
for (let i = 0; i < creations.length; i++) {
|
||||
await creationFactory(seedClient, creations[i])
|
||||
}
|
||||
|
||||
// create Transaction Links
|
||||
for (let i = 0; i < transactionLinks.length; i++) {
|
||||
await transactionLinkFactory(seedClient, transactionLinks[i])
|
||||
}
|
||||
|
||||
await con.close()
|
||||
}
|
||||
|
||||
run()
|
||||
@ -0,0 +1,7 @@
|
||||
export interface TransactionLinkInterface {
|
||||
email: string
|
||||
amount: number
|
||||
memo: string
|
||||
createdAt?: Date
|
||||
deletedAt?: boolean
|
||||
}
|
||||
52
backend/src/seeds/transactionLink/index.ts
Normal file
52
backend/src/seeds/transactionLink/index.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { TransactionLinkInterface } from './TransactionLinkInterface'
|
||||
|
||||
export const transactionLinks: TransactionLinkInterface[] = [
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: 'Leider wollte niemand meine Gradidos zum Neujahr haben :(',
|
||||
createdAt: new Date(2022, 0, 1),
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: `Kein Trick, keine Zauberrei,
|
||||
bei Gradidio sei dabei!`,
|
||||
},
|
||||
{
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 19.99,
|
||||
memo: 'Da habe ich mich wohl etwas übernommen.',
|
||||
deletedAt: true,
|
||||
},
|
||||
]
|
||||
12
backend/src/seeds/users/UserInterface.ts
Normal file
12
backend/src/seeds/users/UserInterface.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export interface UserInterface {
|
||||
email?: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
// description?: string
|
||||
createdAt?: Date
|
||||
emailChecked?: boolean
|
||||
language?: string
|
||||
deletedAt?: Date
|
||||
publisherId?: number
|
||||
isAdmin?: boolean
|
||||
}
|
||||
11
backend/src/seeds/users/bibi-bloxberg.ts
Normal file
11
backend/src/seeds/users/bibi-bloxberg.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const bibiBloxberg: UserInterface = {
|
||||
email: 'bibi@bloxberg.de',
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
// description: 'Hex Hex',
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
publisherId: 1234,
|
||||
}
|
||||
10
backend/src/seeds/users/bob-baumeister.ts
Normal file
10
backend/src/seeds/users/bob-baumeister.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const bobBaumeister: UserInterface = {
|
||||
email: 'bob@baumeister.de',
|
||||
firstName: 'Bob',
|
||||
lastName: 'der Baumeister',
|
||||
// description: 'Können wir das schaffen? Ja, wir schaffen das!',
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
}
|
||||
12
backend/src/seeds/users/garrick-ollivander.ts
Normal file
12
backend/src/seeds/users/garrick-ollivander.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const garrickOllivander: UserInterface = {
|
||||
email: 'garrick@ollivander.com',
|
||||
firstName: 'Garrick',
|
||||
lastName: 'Ollivander',
|
||||
// description: `Curious ... curious ...
|
||||
// Renowned wandmaker Mr Ollivander owns the wand shop Ollivanders: Makers of Fine Wands Since 382 BC in Diagon Alley. His shop is widely considered the best place to purchase a wand.`,
|
||||
createdAt: new Date('2022-01-10T10:23:17'),
|
||||
emailChecked: false,
|
||||
language: 'en',
|
||||
}
|
||||
15
backend/src/seeds/users/index.ts
Normal file
15
backend/src/seeds/users/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { peterLustig } from './peter-lustig'
|
||||
import { bibiBloxberg } from './bibi-bloxberg'
|
||||
import { bobBaumeister } from './bob-baumeister'
|
||||
import { raeuberHotzenplotz } from './raeuber-hotzenplotz'
|
||||
import { stephenHawking } from './stephen-hawking'
|
||||
import { garrickOllivander } from './garrick-ollivander'
|
||||
|
||||
export const users = [
|
||||
peterLustig,
|
||||
bibiBloxberg,
|
||||
bobBaumeister,
|
||||
raeuberHotzenplotz,
|
||||
stephenHawking,
|
||||
garrickOllivander,
|
||||
]
|
||||
12
backend/src/seeds/users/peter-lustig.ts
Normal file
12
backend/src/seeds/users/peter-lustig.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const peterLustig: UserInterface = {
|
||||
email: 'peter@lustig.de',
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
// description: 'Latzhose und Nickelbrille',
|
||||
createdAt: new Date('2020-11-25T10:48:43'),
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
isAdmin: true,
|
||||
}
|
||||
10
backend/src/seeds/users/raeuber-hotzenplotz.ts
Normal file
10
backend/src/seeds/users/raeuber-hotzenplotz.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const raeuberHotzenplotz: UserInterface = {
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
firstName: 'Räuber',
|
||||
lastName: 'Hotzenplotz',
|
||||
// description: 'Pfefferpistole',
|
||||
emailChecked: true,
|
||||
language: 'de',
|
||||
}
|
||||
12
backend/src/seeds/users/stephen-hawking.ts
Normal file
12
backend/src/seeds/users/stephen-hawking.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { UserInterface } from './UserInterface'
|
||||
|
||||
export const stephenHawking: UserInterface = {
|
||||
email: 'stephen@hawking.uk',
|
||||
firstName: 'Stephen',
|
||||
lastName: 'Hawking',
|
||||
// description: 'A Brief History of Time',
|
||||
emailChecked: true,
|
||||
createdAt: new Date('1942-01-08T09:17:52'),
|
||||
deletedAt: new Date('2018-03-14T09:17:52'),
|
||||
language: 'en',
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import 'reflect-metadata'
|
||||
import 'module-alias/register'
|
||||
|
||||
import { ApolloServer } from 'apollo-server-express'
|
||||
import express, { Express } from 'express'
|
||||
|
||||
@ -41,7 +41,7 @@ const virtualLinkTransaction = (
|
||||
id: -2,
|
||||
userId: -1,
|
||||
previous: -1,
|
||||
typeId: TransactionTypeId.TRANSACTION_LINK,
|
||||
typeId: TransactionTypeId.LINK_SUMMARY,
|
||||
amount: amount,
|
||||
balance: balance,
|
||||
balanceDate: validUntil,
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const createUserMutation = gql`
|
||||
mutation (
|
||||
$email: String!
|
||||
$firstName: String!
|
||||
$lastName: String!
|
||||
$language: String!
|
||||
$publisherId: Int
|
||||
) {
|
||||
createUser(
|
||||
email: $email
|
||||
firstName: $firstName
|
||||
lastName: $lastName
|
||||
language: $language
|
||||
publisherId: $publisherId
|
||||
)
|
||||
}
|
||||
`
|
||||
|
||||
export const setPasswordMutation = gql`
|
||||
mutation ($code: String!, $password: String!) {
|
||||
setPassword(code: $code, password: $password)
|
||||
}
|
||||
`
|
||||
@ -4,9 +4,6 @@
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../src/server/createServer'
|
||||
import { initialize } from '@dbTools/helpers'
|
||||
import { createUserMutation, setPasswordMutation } from './graphql'
|
||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||
import { User } from '@entity/User'
|
||||
import { entities } from '@entity/index'
|
||||
|
||||
export const headerPushMock = jest.fn((t) => {
|
||||
@ -46,19 +43,6 @@ export const resetEntity = async (entity: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const createUser = async (mutate: any, user: any) => {
|
||||
// resetToken()
|
||||
await mutate({ mutation: createUserMutation, variables: user })
|
||||
const dbUser = await User.findOne({ where: { email: user.email } })
|
||||
if (!dbUser) throw new Error('Ups, no user found')
|
||||
const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } })
|
||||
if (!optin) throw new Error('Ups, no optin found')
|
||||
await mutate({
|
||||
mutation: setPasswordMutation,
|
||||
variables: { password: 'Aa12345_', code: optin.verificationCode },
|
||||
})
|
||||
}
|
||||
|
||||
export const resetToken = () => {
|
||||
context.token = ''
|
||||
}
|
||||
|
||||
@ -4,3 +4,4 @@
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
console.info = () => {}
|
||||
jest.setTimeout(1000000)
|
||||
|
||||
@ -45,16 +45,17 @@
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
|
||||
"paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
"@/*": ["./src/*"],
|
||||
"@arg/*": ["./src/graphql/arg/*"],
|
||||
"@dbTools/*": ["../database/src/*"],
|
||||
"@entity/*": ["../database/entity/*"],
|
||||
"@enum/*": ["./src/graphql/enum/*"],
|
||||
"@model/*": ["./src/graphql/model/*"],
|
||||
"@repository/*": ["./src/typeorm/repository/*"],
|
||||
"@test/*": ["./test/*"]
|
||||
"@/*": ["src/*"],
|
||||
"@arg/*": ["src/graphql/arg/*"],
|
||||
"@enum/*": ["src/graphql/enum/*"],
|
||||
"@model/*": ["src/graphql/model/*"],
|
||||
"@repository/*": ["src/typeorm/repository/*"],
|
||||
"@test/*": ["test/*"],
|
||||
/* external */
|
||||
"@dbTools/*": ["../database/src/*", "../../database/build/src/*"],
|
||||
"@entity/*": ["../database/entity/*", "../../database/build/entity/*"]
|
||||
},
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
@ -82,7 +83,7 @@
|
||||
{
|
||||
"path": "../database/tsconfig.json",
|
||||
// add 'prepend' if you want to include the referenced project in your output file
|
||||
// "prepend": true,
|
||||
// "prepend": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -811,6 +811,11 @@
|
||||
"@types/qs" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/faker@^5.5.9":
|
||||
version "5.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.5.9.tgz#588ede92186dc557bff8341d294335d50d255f0c"
|
||||
integrity sha512-uCx6mP3UY5SIO14XlspxsGjgaemrxpssJI0Ol+GfhxtcKpv9pgRZYsS4eeKeHVLje6Qtc8lGszuBI461+gVZBA==
|
||||
|
||||
"@types/fs-capacitor@*":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz#17113e25817f584f58100fb7a08eed288b81956e"
|
||||
@ -2510,6 +2515,11 @@ express@^4.17.1:
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
faker@^5.5.3:
|
||||
version "5.5.3"
|
||||
resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e"
|
||||
integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
@ -4092,11 +4102,6 @@ minimist@^1.2.0, minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
module-alias@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
|
||||
integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@ -5232,6 +5237,16 @@ tsconfig-paths@^3.11.0:
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tsconfig-paths@^3.14.0:
|
||||
version "3.14.0"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976"
|
||||
integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g==
|
||||
dependencies:
|
||||
"@types/json5" "^0.0.29"
|
||||
json5 "^1.0.1"
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
.git
|
||||
.gitignore
|
||||
.gitignore
|
||||
!.eslintignore
|
||||
@ -1,3 +1,3 @@
|
||||
node_modules
|
||||
**/*.min.js
|
||||
dist
|
||||
node_modules/
|
||||
dist/
|
||||
coverage/
|
||||
@ -8,9 +8,24 @@ module.exports = {
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
},
|
||||
extends: ['standard', 'plugin:vue/essential', 'plugin:prettier/recommended'],
|
||||
extends: [
|
||||
'standard',
|
||||
'plugin:vue/essential',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:@intlify/vue-i18n/recommended',
|
||||
],
|
||||
// required to lint *.vue files
|
||||
plugins: ['vue', 'prettier', 'jest'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.json'],
|
||||
extends: ['plugin:@intlify/vue-i18n/recommended'],
|
||||
rules: {
|
||||
// TODO: enable
|
||||
'@intlify/vue-i18n/no-html-messages': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
'no-console': ['error'],
|
||||
@ -22,6 +37,29 @@ module.exports = {
|
||||
allowBinding: false,
|
||||
},
|
||||
],
|
||||
'@intlify/vue-i18n/no-dynamic-keys': 'error',
|
||||
'@intlify/vue-i18n/no-unused-keys': [
|
||||
'error',
|
||||
{
|
||||
src: './src',
|
||||
extensions: ['.js', '.vue'],
|
||||
// TODO: remove ignores
|
||||
ignores: [
|
||||
'/site.thx./',
|
||||
'/form./',
|
||||
'/time./',
|
||||
'/decay.types./',
|
||||
'settings.password.resend_subtitle',
|
||||
'settings.password.reset-password.text',
|
||||
'settings.password.set',
|
||||
'settings.password.set-password.text',
|
||||
'settings.password.subtitle',
|
||||
'site.login.signin',
|
||||
],
|
||||
enableFix: false,
|
||||
},
|
||||
],
|
||||
'@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
@ -29,4 +67,12 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
'vue-i18n': {
|
||||
localeDir: './src/locales/*.json',
|
||||
// Specify the version of `vue-i18n` you are using.
|
||||
// If not specified, the message will be parsed twice.
|
||||
messageSyntaxVersion: '^8.22.4',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
1
frontend/.gitignore
vendored
1
frontend/.gitignore
vendored
@ -5,7 +5,6 @@ dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
test/unit/coverage
|
||||
|
||||
package-lock.json
|
||||
/.env
|
||||
|
||||
@ -8,11 +8,10 @@
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "yarn run serve",
|
||||
"analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.vue .",
|
||||
"lint": "eslint --max-warnings=0 --ext .js,.vue,.json .",
|
||||
"stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'",
|
||||
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
|
||||
"test": "TZ=UTC jest --coverage",
|
||||
"locales": "scripts/missing-keys.sh && scripts/sort.sh"
|
||||
"locales": "scripts/sort.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.13.13",
|
||||
@ -67,6 +66,7 @@
|
||||
"vuex-persistedstate": "^4.0.0-beta.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/eslint-plugin-vue-i18n": "^1.4.0",
|
||||
"@vue/cli-plugin-babel": "^3.7.0",
|
||||
"@vue/cli-plugin-eslint": "^3.7.0",
|
||||
"@vue/cli-service": "^3.7.0",
|
||||
|
||||
@ -52,10 +52,6 @@
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper" id="app">
|
||||
|
||||
</div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
{"state":"success", "statisticdata":
|
||||
[
|
||||
{
|
||||
"i_creation_sum": 29288278.4653,
|
||||
"i_creation_mon": 68278.4653,
|
||||
"i_creation_365d": 19288278.4653,
|
||||
"i_creation_30d": 288278.4653,
|
||||
"i_creation_14d": 88278.4653,
|
||||
"i_creation_7d": 3278.4653
|
||||
},
|
||||
{
|
||||
"i_transience_sum": 8278.4653,
|
||||
"i_transience_mon": 8278.4653,
|
||||
"i_transience_365d": 8278.4653,
|
||||
"i_transience_30d": 178.4653,
|
||||
"i_transience_14d": 78.4653,
|
||||
"i_transience_7d": 8.4653
|
||||
},
|
||||
{
|
||||
"i_exchange_sum": 23345.2324,
|
||||
"i_exchange_mon": 2,
|
||||
"i_exchange_365d": 2,
|
||||
"i_exchange_30d": 2,
|
||||
"i_exchange_14d": 2,
|
||||
"i_exchange_7d": 2
|
||||
},
|
||||
{
|
||||
"i_members_sum": 5398,
|
||||
"i_members_mon": 234,
|
||||
"i_members_365d": 2356,
|
||||
"i_members_30d": 123,
|
||||
"i_members_14d": 23,
|
||||
"i_members_7d": 24
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
{"state":"success", "statisticdata":
|
||||
[
|
||||
{
|
||||
"charts_creation_0_mon": 5635,
|
||||
"charts_creation_1_mon": 5635,
|
||||
"charts_creation_2_mon": 5635,
|
||||
"charts_creation_3_mon": 5635,
|
||||
"charts_creation_4_mon": 5635,
|
||||
"charts_creation_5_mon": 5635,
|
||||
"charts_creation_6_mon": 5635,
|
||||
"charts_creation_7_mon": 5635,
|
||||
"charts_creation_8_mon": 5635,
|
||||
"charts_creation_9_mon": 5635,
|
||||
"charts_creation_10_mon": 5635,
|
||||
"charts_creation_11_mon": 5635,
|
||||
"charts_creation_12_mon": 5635
|
||||
},
|
||||
{
|
||||
"charts_transience_0_mon": 5635,
|
||||
"charts_transience_1_mon": 5635,
|
||||
"charts_transience_2_mon": 5635,
|
||||
"charts_transience_3_mon": 5635,
|
||||
"charts_transience_4_mon": 5635,
|
||||
"charts_transience_5_mon": 5635,
|
||||
"charts_transience_6_mon": 5635,
|
||||
"charts_transience_7_mon": 5635,
|
||||
"charts_transience_8_mon": 5635,
|
||||
"charts_transience_9_mon": 5635,
|
||||
"charts_transience_10_mon": 5635,
|
||||
"charts_transience_11_mon": 5635,
|
||||
"charts_transience_12_mon": 5635
|
||||
},
|
||||
{
|
||||
"charts_exchange_0_mon": 5635,
|
||||
"charts_exchange_1_mon": 5635,
|
||||
"charts_exchange_2_mon": 5635,
|
||||
"charts_exchange_3_mon": 5635,
|
||||
"charts_exchange_4_mon": 5635,
|
||||
"charts_exchange_5_mon": 5635,
|
||||
"charts_exchange_6_mon": 5635,
|
||||
"charts_exchange_7_mon": 5635,
|
||||
"charts_exchange_8_mon": 5635,
|
||||
"charts_exchange_9_mon": 5635,
|
||||
"charts_exchange_10_mon": 5635,
|
||||
"charts_exchange_11_mon": 5635,
|
||||
"charts_exchange_12_mon": 5635
|
||||
},
|
||||
{
|
||||
"charts_members_0_mon": 5635,
|
||||
"charts_members_1_mon": 5635,
|
||||
"charts_members_2_mon": 5635,
|
||||
"charts_members_3_mon": 5635,
|
||||
"charts_members_4_mon": 5635,
|
||||
"charts_members_5_mon": 5635,
|
||||
"charts_members_6_mon": 5635,
|
||||
"charts_members_7_mon": 5635,
|
||||
"charts_members_8_mon": 5635,
|
||||
"charts_members_9_mon": 5635,
|
||||
"charts_members_10_mon": 5635,
|
||||
"charts_members_11_mon": 5635,
|
||||
"charts_members_12_mon": 5635
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{"state":"success", "statisticdata":
|
||||
[
|
||||
{
|
||||
"community_entries1_mon": 5635,
|
||||
"community_entries2_mon": 5635,
|
||||
"community_entries3_mon": 5635,
|
||||
"community_entries4_mon": 5635,
|
||||
"community_entries5_mon": 5635,
|
||||
"community_entries6_mon": 5635,
|
||||
"community_entries7_mon": 5635,
|
||||
"community_entries8_mon": 5635,
|
||||
"community_entries9_mon": 5635,
|
||||
"community_entries0_mon": 5635,
|
||||
"community_entries10_mon": 5635,
|
||||
"community_entries11_mon": 5635,
|
||||
"community_entries12_mon": 5635
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
{"state":"success", "transactions":
|
||||
[
|
||||
{
|
||||
"name": "Jon Tester",
|
||||
"email": "jon@example.de",
|
||||
"type": "send",
|
||||
"transaction_id": 12,
|
||||
"date": "29-11-2020",
|
||||
"balance": 7000,
|
||||
"memo": "Reperatur Waschbecken",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Gradido Community",
|
||||
"email": "gradido@example.de",
|
||||
"type": "creation",
|
||||
"transaction_id": 11,
|
||||
"date": "1-11-2020",
|
||||
"balance": 10000,
|
||||
"memo": "Müll gesammelt im Wald",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Maria Tester",
|
||||
"email": "maria@example.de",
|
||||
"type": "receive",
|
||||
"transaction_id": 7,
|
||||
"date": "23-10-2020",
|
||||
"balance": 5000,
|
||||
"memo": "Spende an Alice ",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Alice Tester",
|
||||
"email": "alice@example.de",
|
||||
"type": "receive",
|
||||
"transaction_id": 5,
|
||||
"date": "2-8-2020",
|
||||
"balance": 1000,
|
||||
"memo": "Bob hat meinen Müll getrennt",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Gradido Community",
|
||||
"email": "gradido@example.de",
|
||||
"type": "creation",
|
||||
"transaction_id": 1,
|
||||
"date": "11-7-2020",
|
||||
"balance": 10000,
|
||||
"memo": "Bob hat meinen Müll getrennt",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
}
|
||||
],
|
||||
"transactionExecutingCount": 8750,
|
||||
"count": 5
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
{"state":"success", "participation":
|
||||
[
|
||||
{
|
||||
"name": "",
|
||||
"type": "submitted",
|
||||
"participation_id": 412,
|
||||
"date_submitted": "9-12-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "8-12-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"type": "in progress",
|
||||
"participation_id": 312,
|
||||
"date_submitted": "2-11-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "2-11-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"type": "confirmed",
|
||||
"participation_id": 212,
|
||||
"date_submitted": "20-10-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "20-10-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"type": "rejected",
|
||||
"participation_id": 142,
|
||||
"date_submitted": "17-9-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "17-9-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
}
|
||||
],
|
||||
"count": 4
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
{"state":"success", "admin0userlist":
|
||||
[
|
||||
{
|
||||
"created": 1578688666,
|
||||
"disabled": false,
|
||||
"email": "dervommond@gmail.com",
|
||||
"email_checked": true,
|
||||
"first_name": "Max",
|
||||
"group_alias": "gdd1",
|
||||
"ident_hash": 2928827813,
|
||||
"last_name": "Miau",
|
||||
"public_hex": "2ed28a1cf5e116d83615406bc577152221c2f774a5656f66a0e7540f7576d71b",
|
||||
"role": "admin",
|
||||
"username": "",
|
||||
"balance_gdd": 174500,
|
||||
"balance_gdt": 4500,
|
||||
"errorCount": 0
|
||||
},
|
||||
{
|
||||
"created": 1578685678,
|
||||
"disabled": false,
|
||||
"email": "ttwer@gmail.com",
|
||||
"email_checked": true,
|
||||
"first_name": "John",
|
||||
"group_alias": "gdd1",
|
||||
"ident_hash": 2928827813,
|
||||
"last_name": "Doe",
|
||||
"public_hex": "2ed28a1cf5e116d83615406bc577152221c2f774a5656f66a0e7540f7576d71x",
|
||||
"role": "user",
|
||||
"username": "",
|
||||
"balance_gdd": 144500,
|
||||
"balance_gdt": 0,
|
||||
"errorCount": 0
|
||||
},
|
||||
{
|
||||
"created": 1578635671,
|
||||
"disabled": false,
|
||||
"email": "test@gmail.com",
|
||||
"email_checked": true,
|
||||
"first_name": "Alice",
|
||||
"group_alias": "gdd1",
|
||||
"ident_hash": 4928827813,
|
||||
"last_name": "Seer",
|
||||
"public_hex": "2ed28a1cf5e116d83615406bc577152221c2f774a5656f66a0e7540f7576d71a",
|
||||
"role": "user",
|
||||
"username": "",
|
||||
"balance_gdd": 444500,
|
||||
"balance_gdt": 4500,
|
||||
"errorCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{"state":"success", "userdata":
|
||||
[
|
||||
{
|
||||
"created": 1578688666,
|
||||
"disabled": false,
|
||||
"email": "dervommond@gmail.com",
|
||||
"email_checked": true,
|
||||
"first_name": "Max",
|
||||
"group_alias": "gdd1",
|
||||
"ident_hash": 2928827813,
|
||||
"last_name": "Miau",
|
||||
"public_hex": "2ed28a1cf5e116d83615406bc577152221c2f774a5656f66a0e7540f7576d71b",
|
||||
"role": "admin",
|
||||
"username": "",
|
||||
"balance": 174500,
|
||||
"errorCount": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
{"state":"success", "participation":
|
||||
[
|
||||
{
|
||||
"type": "submitted",
|
||||
"participation_id": 412,
|
||||
"date_submitted": "9-12-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "8-12-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"type": "in progress",
|
||||
"participation_id": 312,
|
||||
"date_submitted": "2-11-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "2-11-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"type": "confirmed",
|
||||
"participation_id": 212,
|
||||
"date_submitted": "20-10-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "20-10-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
},
|
||||
{
|
||||
"type": "rejected",
|
||||
"participation_id": 142,
|
||||
"date_submitted": "17-9-2020",
|
||||
"titel": "Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"text": "Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. Lorem Ipsum panta lore es Tastina sero was. ",
|
||||
"date_participation": "17-9-2020",
|
||||
"plz_participation": "01099",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
}
|
||||
],
|
||||
"count": 4
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
{"state":"success", "transactions":
|
||||
[
|
||||
{
|
||||
"name": "Jon Tester",
|
||||
"email": "jon@example.de",
|
||||
"type": "send",
|
||||
"transaction_id": 12,
|
||||
"date": "29-11-2020",
|
||||
"balance": 7000,
|
||||
"memo": "Reperatur Waschbecken",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Gradido Community",
|
||||
"email": "gradido@example.de",
|
||||
"type": "creation",
|
||||
"transaction_id": 11,
|
||||
"date": "1-11-2020",
|
||||
"balance": 10000,
|
||||
"memo": "Müll gesammelt im Wald",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Maria Tester",
|
||||
"email": "maria@example.de",
|
||||
"type": "receive",
|
||||
"transaction_id": 7,
|
||||
"date": "23-10-2020",
|
||||
"balance": 5000,
|
||||
"memo": "Spende an Alice ",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Alice Tester",
|
||||
"email": "alice@example.de",
|
||||
"type": "receive",
|
||||
"transaction_id": 5,
|
||||
"date": "2-8-2020",
|
||||
"balance": 1000,
|
||||
"memo": "Bob hat meinen Müll getrennt",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Gradido Community",
|
||||
"email": "gradido@example.de",
|
||||
"type": "creation",
|
||||
"transaction_id": 1,
|
||||
"date": "11-7-2020",
|
||||
"balance": 10000,
|
||||
"memo": "Bob hat meinen Müll getrennt",
|
||||
"pubkey": "abcdefghi123456789"
|
||||
|
||||
}
|
||||
],
|
||||
"transactionExecutingCount": 8750,
|
||||
"count": 5
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOT_DIR=$(dirname "$0")/..
|
||||
|
||||
sorting="jq -f $ROOT_DIR/scripts/sort_filter.jq"
|
||||
english="$sorting $ROOT_DIR/src/locales/en.json"
|
||||
german="$sorting $ROOT_DIR/src/locales/de.json"
|
||||
listPaths="jq -c 'path(..)|[.[]|tostring]|join(\".\")'"
|
||||
diffString="<( $english | $listPaths ) <( $german | $listPaths )"
|
||||
if eval "diff -q $diffString";
|
||||
then
|
||||
: # all good
|
||||
else
|
||||
eval "diff -y $diffString | grep '[|<>]'";
|
||||
printf "\nEnglish and German translation keys do not match, see diff above.\n"
|
||||
exit 1
|
||||
fi
|
||||
@ -11,7 +11,7 @@ describe('ContentFooter', () => {
|
||||
$i18n: {
|
||||
locale: 'en',
|
||||
},
|
||||
$t: jest.fn((t) => t),
|
||||
$t: jest.fn((t, options) => (options ? [t, options] : t)),
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
@ -33,11 +33,11 @@ describe('ContentFooter', () => {
|
||||
})
|
||||
|
||||
it('renders the copyright year', () => {
|
||||
expect(wrapper.find('div.copyright').text()).toMatch(/©\s*2[0-9]{3,3}\s+/)
|
||||
expect(mocks.$t).toBeCalledWith('footer.copyright.year', { year: 2022 })
|
||||
})
|
||||
|
||||
it('renders a link to Gradido-Akademie', () => {
|
||||
expect(wrapper.find('div.copyright').find('a').text()).toEqual('Gradido-Akademie')
|
||||
expect(wrapper.find('div.copyright').find('a').text()).toEqual('footer.copyright.link')
|
||||
})
|
||||
|
||||
it('links to the login page when clicked on copyright', () => {
|
||||
@ -51,7 +51,7 @@ describe('ContentFooter', () => {
|
||||
it('shows the current version', async () => {
|
||||
wrapper.setData({ version: 1.23 })
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('div.copyright').findAll('a').at(1).text()).toEqual('App version 1.23')
|
||||
expect(mocks.$t).toBeCalledWith('footer.app_version', { version: 1.23 })
|
||||
})
|
||||
|
||||
it('links to latest release on GitHub', () => {
|
||||
@ -64,7 +64,7 @@ describe('ContentFooter', () => {
|
||||
wrapper.setData({ shortHash: 'ACCEDED' })
|
||||
wrapper.setData({ hash: 'ACCEDEDC001D00DC001D00DC001D00DC001CAFA' })
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('div.copyright').findAll('a').at(2).text()).toEqual('(ACCEDED)')
|
||||
expect(mocks.$t).toBeCalledWith('footer.short_hash', { shortHash: 'ACCEDED' })
|
||||
})
|
||||
|
||||
it('links to last release commit', async () => {
|
||||
@ -78,7 +78,7 @@ describe('ContentFooter', () => {
|
||||
|
||||
describe('links to gradido.net', () => {
|
||||
it('has a link to the legal notice', () => {
|
||||
expect(wrapper.findAll('a.nav-link').at(0).text()).toEqual('imprint')
|
||||
expect(wrapper.findAll('a.nav-link').at(0).text()).toEqual('footer.imprint')
|
||||
})
|
||||
|
||||
it('links to the https://gradido.net/en/impressum when locale is en', () => {
|
||||
@ -88,7 +88,7 @@ describe('ContentFooter', () => {
|
||||
})
|
||||
|
||||
it('has a link to the privacy policy', () => {
|
||||
expect(wrapper.findAll('a.nav-link').at(1).text()).toEqual('privacy_policy')
|
||||
expect(wrapper.findAll('a.nav-link').at(1).text()).toEqual('footer.privacy_policy')
|
||||
})
|
||||
|
||||
it('links to the https://gradido.net/en/datenschutz when locale is en', () => {
|
||||
@ -98,7 +98,7 @@ describe('ContentFooter', () => {
|
||||
})
|
||||
|
||||
it('has a link to the members area', () => {
|
||||
expect(wrapper.findAll('a.nav-link').at(2).text()).toEqual('members_area')
|
||||
expect(wrapper.findAll('a.nav-link').at(2).text()).toEqual('navigation.members_area')
|
||||
})
|
||||
|
||||
it('links to the elopage', () => {
|
||||
@ -3,24 +3,24 @@
|
||||
<b-row align-v="center" class="mt-4 justify-content-lg-between">
|
||||
<b-col>
|
||||
<div class="copyright text-center text-lg-center text-muted">
|
||||
© {{ year }}
|
||||
{{ $t('footer.copyright.year', { year }) }}
|
||||
<a
|
||||
:href="`https://gradido.net/${$i18n.locale}`"
|
||||
class="font-weight-bold ml-1"
|
||||
target="_blank"
|
||||
>
|
||||
Gradido-Akademie
|
||||
{{ $t('footer.copyright.link') }}
|
||||
</a>
|
||||
|
|
||||
{{ $t('math.pipe') }}
|
||||
<a href="https://github.com/gradido/gradido/releases/latest" target="_blank">
|
||||
App version {{ version }}
|
||||
{{ $t('footer.app_version', { version }) }}
|
||||
</a>
|
||||
<a
|
||||
v-if="hash"
|
||||
:href="'https://github.com/gradido/gradido/commit/' + hash"
|
||||
target="_blank"
|
||||
>
|
||||
({{ shortHash }})
|
||||
{{ $t('footer.short_hash', { shortHash }) }}
|
||||
</a>
|
||||
</div>
|
||||
</b-col>
|
||||
@ -29,16 +29,16 @@
|
||||
<b-col>
|
||||
<b-nav class="nav-footer justify-content-center">
|
||||
<b-nav-item :href="`https://gradido.net/${$i18n.locale}/impressum/`" target="_blank">
|
||||
{{ $t('imprint') }}
|
||||
{{ $t('footer.imprint') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :href="`https://gradido.net/${$i18n.locale}/datenschutz/`" target="_blank">
|
||||
{{ $t('privacy_policy') }}
|
||||
{{ $t('footer.privacy_policy') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item
|
||||
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('members_area') }}
|
||||
{{ $t('navigation.members_area') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item
|
||||
:href="
|
||||
@ -48,10 +48,10 @@
|
||||
"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('whitepaper') }}
|
||||
{{ $t('footer.whitepaper') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :href="`https://gradido.net/${$i18n.locale}/contact/`" target="_blank">
|
||||
{{ $t('site.navbar.support') }}
|
||||
{{ $t('navigation.support') }}
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
</b-col>
|
||||
@ -0,0 +1,126 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import CollapseLinksList from './CollapseLinksList'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const mocks = {
|
||||
$i18n: {
|
||||
locale: 'en',
|
||||
},
|
||||
$tc: jest.fn((tc) => tc),
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
|
||||
const propsData = {
|
||||
transactionLinks: [
|
||||
{
|
||||
amount: '5',
|
||||
code: 'ce28664b5308c17f931c0367',
|
||||
createdAt: '2022-03-16T14:22:40.000Z',
|
||||
holdAvailableAmount: '5.13109484759482747111',
|
||||
id: 87,
|
||||
memo: 'Eene meene Siegerpreis, vor mir steht ein Schokoeis. Hex-hex!',
|
||||
redeemedAt: null,
|
||||
validUntil: '2022-03-30T14:22:40.000Z',
|
||||
},
|
||||
{
|
||||
amount: '6',
|
||||
code: 'ce28664b5308c17f931c0367',
|
||||
createdAt: '2022-03-16T14:22:40.000Z',
|
||||
holdAvailableAmount: '5.13109484759482747111',
|
||||
id: 86,
|
||||
memo: 'Eene meene buntes Laub, auf dem Schrank da liegt kein Staub.',
|
||||
redeemedAt: null,
|
||||
validUntil: '2022-03-30T14:22:40.000Z',
|
||||
},
|
||||
],
|
||||
transactionLinkCount: 3,
|
||||
value: 1,
|
||||
pending: false,
|
||||
pageSize: 5,
|
||||
}
|
||||
|
||||
describe('CollapseLinksList', () => {
|
||||
let wrapper
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(CollapseLinksList, { localVue, mocks, propsData })
|
||||
}
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component div.collapse-links-list', () => {
|
||||
expect(wrapper.find('div.collapse-links-list').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('load more links', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('button.test-button-load-more').trigger('click')
|
||||
})
|
||||
|
||||
it('emits input', () => {
|
||||
expect(wrapper.emitted('input')).toEqual([[2]])
|
||||
})
|
||||
})
|
||||
|
||||
describe('reset transaction link list', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper
|
||||
.findComponent({ name: 'TransactionLink' })
|
||||
.vm.$emit('reset-transaction-link-list')
|
||||
})
|
||||
|
||||
it('emits input ', () => {
|
||||
expect(wrapper.emitted('input')).toEqual([[0]])
|
||||
})
|
||||
})
|
||||
|
||||
describe('button text', () => {
|
||||
describe('one more link to load', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({
|
||||
value: 1,
|
||||
pending: false,
|
||||
pageSize: 5,
|
||||
})
|
||||
})
|
||||
|
||||
it('renders text in singular', () => {
|
||||
expect(mocks.$tc).toBeCalledWith('link-load', 0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('less than pageSize links to load', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({
|
||||
value: 1,
|
||||
pending: false,
|
||||
pageSize: 5,
|
||||
transactionLinkCount: 6,
|
||||
})
|
||||
})
|
||||
|
||||
it('renders text in plural and shows the correct count of links', () => {
|
||||
expect(mocks.$tc).toBeCalledWith('link-load', 1, { n: 4 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('more than pageSize links to load', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.setProps({
|
||||
value: 1,
|
||||
pending: false,
|
||||
pageSize: 5,
|
||||
transactionLinkCount: 16,
|
||||
})
|
||||
})
|
||||
|
||||
it('renders text in plural with page size links to load', () => {
|
||||
expect(mocks.$tc).toBeCalledWith('link-load', 2, { n: 5 })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,14 +1,66 @@
|
||||
<template>
|
||||
<div class="collapse-links-list">
|
||||
<div class="d-flex">
|
||||
<div class="text-center pb-3 gradido-max-width">
|
||||
<b>{{ $t('links-list.header') }}</b>
|
||||
<div class="gradido-max-width">
|
||||
<hr />
|
||||
<div>
|
||||
<transaction-link
|
||||
v-for="item in transactionLinks"
|
||||
:key="item.id"
|
||||
v-bind="item"
|
||||
@reset-transaction-link-list="resetTransactionLinkList"
|
||||
/>
|
||||
<div class="mb-3">
|
||||
<b-button
|
||||
class="test-button-load-more"
|
||||
v-if="!pending && transactionLinks.length < transactionLinkCount"
|
||||
block
|
||||
variant="outline-primary"
|
||||
@click="loadMoreLinks"
|
||||
>
|
||||
{{ buttonText }}
|
||||
</b-button>
|
||||
<div class="text-center">
|
||||
<b-icon v-if="pending" icon="three-dots" animation="cylon" font-scale="4"></b-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import TransactionLink from '@/components/TransactionLinks/TransactionLink.vue'
|
||||
export default {
|
||||
name: 'CollapseLinksList',
|
||||
components: {
|
||||
TransactionLink,
|
||||
},
|
||||
props: {
|
||||
transactionLinks: { type: Array, required: true },
|
||||
transactionLinkCount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
value: { type: Number, required: true },
|
||||
pageSize: { type: Number, default: 5 },
|
||||
pending: { type: Boolean, default: false },
|
||||
},
|
||||
methods: {
|
||||
resetTransactionLinkList() {
|
||||
this.$emit('input', 0)
|
||||
},
|
||||
loadMoreLinks() {
|
||||
this.$emit('input', this.value + 1)
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
buttonText() {
|
||||
const i = this.transactionLinkCount - this.transactionLinks.length
|
||||
if (i === 1) return this.$tc('link-load', 0)
|
||||
if (i <= this.pageSize) return this.$tc('link-load', 1, { n: i })
|
||||
return this.$tc('link-load', 2, { n: this.pageSize })
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
<div>
|
||||
{{ (Number(balance) - Number(decay.decay)) | GDD }}
|
||||
{{ decay.decay | GDD }} =
|
||||
{{ (Number(balance) - Number(decay)) | GDD }}
|
||||
{{ decay | GDD }} {{ $t('math.equal') }}
|
||||
<b>{{ balance | GDD }}</b>
|
||||
</div>
|
||||
</b-col>
|
||||
@ -27,9 +27,11 @@ export default {
|
||||
props: {
|
||||
balance: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
decay: {
|
||||
type: Object,
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -4,12 +4,11 @@
|
||||
<b-col cols="12" class="text-center">
|
||||
<div>
|
||||
<div class="display-4">{{ $t('decay.Starting_block_decay') }}</div>
|
||||
<div>{{ $t('decay.decay_introduced') }} :</div>
|
||||
<div>{{ $t('decay.decay_introduced') }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="decay.start">
|
||||
{{ $d(new Date(decay.start), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
@ -28,7 +27,8 @@
|
||||
</b-row>
|
||||
<!-- Type-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">{{ $t(`decay.${typeId.toLowerCase()}`) }}</b-col>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys-->
|
||||
<b-col cols="6" class="text-right">{{ $t(`decay.types.${typeId.toLowerCase()}`) }}</b-col>
|
||||
<b-col cols="6">{{ amount | GDD }}</b-col>
|
||||
</b-row>
|
||||
<!-- Decay-->
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
<div>
|
||||
<span>
|
||||
{{ $d(new Date(decay.start), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
@ -44,7 +43,8 @@
|
||||
</b-row>
|
||||
<!-- Type-->
|
||||
<b-row>
|
||||
<b-col cols="6" class="text-right">{{ $t(`decay.${typeId.toLowerCase()}`) }}</b-col>
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys-->
|
||||
<b-col cols="6" class="text-right">{{ $t(`decay.types.${typeId.toLowerCase()}`) }}</b-col>
|
||||
<b-col cols="6">{{ amount | GDD }}</b-col>
|
||||
</b-row>
|
||||
<!-- Decay-->
|
||||
@ -82,7 +82,8 @@ export default {
|
||||
const result = []
|
||||
order.forEach((timeSpan) => {
|
||||
if (this.duration[timeSpan] > 0) {
|
||||
const locale = this.$t(`decay.${timeSpan}`)
|
||||
// eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys
|
||||
const locale = this.$t(`time.${timeSpan}`)
|
||||
result.push(`${this.duration[timeSpan]} ${locale}`)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="decayinformation-short">
|
||||
<span v-if="decay.decay">{{ decay.decay | GDD }}</span>
|
||||
<span v-if="decay">{{ decay | GDD }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -8,7 +8,8 @@ export default {
|
||||
name: 'DecayInformation-Short',
|
||||
props: {
|
||||
decay: {
|
||||
type: Object,
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<b-alert show variant="secondary">
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-v-html -->
|
||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||
<b-col v-show="!scan" lg="12" class="text-right">
|
||||
<a @click="toggle" class="nav-link pointer">
|
||||
@ -18,6 +19,7 @@
|
||||
<b-row>
|
||||
<b-col lg="8">
|
||||
<b-alert show variant="secondary">
|
||||
<!-- eslint-disable-next-line @intlify/vue-i18n/no-v-html -->
|
||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||
</b-alert>
|
||||
</b-col>
|
||||
|
||||
@ -28,12 +28,14 @@
|
||||
<strong>{{ $t('gdd_per_link.decay-14-day') }}</strong>
|
||||
</b-col>
|
||||
<b-col class="text-right borderbottom">
|
||||
<strong>~ {{ (amount * 0.028 * -1) | GDD }}</strong>
|
||||
<strong>{{ $t('math.aprox') }} {{ (amount * 0.028 * -1) | GDD }}</strong>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="pr-3">
|
||||
<b-col class="text-right">{{ $t('form.new_balance') }}</b-col>
|
||||
<b-col class="text-right">~ {{ (balance - amount - amount * 0.028) | GDD }}</b-col>
|
||||
<b-col class="text-right">
|
||||
{{ $t('math.aprox') }} {{ (balance - amount - amount * 0.028) | GDD }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<label class="input-2" for="input-2">{{ $t('form.amount') }}</label>
|
||||
<b-input-group id="input-group-2" class="borderbottom" size="lg">
|
||||
<b-input-group-prepend class="p-2 d-none d-md-block gray-background">
|
||||
<div class="m-1 mt-2">GDD</div>
|
||||
<div class="m-1 mt-2">{{ $t('GDD') }}</div>
|
||||
</b-input-group-prepend>
|
||||
|
||||
<div class="p-3">{{ (amount * -1) | GDD }}</div>
|
||||
@ -27,7 +27,7 @@
|
||||
<b-input-group-prepend class="d-none d-md-block gray-background">
|
||||
<b-icon icon="chat-right-text" class="display-4 m-3 mt-4"></b-icon>
|
||||
</b-input-group-prepend>
|
||||
<div class="p-3">{{ memo ? memo : '-' }}</div>
|
||||
<div class="p-3">{{ memo ? memo : $t('em-dash') }}</div>
|
||||
</b-input-group>
|
||||
</b-list-group>
|
||||
</b-col>
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
<label class="input-2" for="input-2">{{ $t('form.amount') }}</label>
|
||||
<b-input-group id="input-group-2" class="border border-default" size="lg">
|
||||
<b-input-group-prepend class="p-2 d-none d-md-block">
|
||||
<div class="m-1 mt-2">GDD</div>
|
||||
<div class="m-1 mt-2">{{ $t('GDD') }}</div>
|
||||
</b-input-group-prepend>
|
||||
|
||||
<b-form-input
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
>
|
||||
{{ $t('transaction.receiverDeleted') }}
|
||||
</div>
|
||||
<div v-else>({{ errorResult }})</div>
|
||||
<div v-else>{{ errorResult }}</div>
|
||||
</div>
|
||||
<p class="text-center mt-3">
|
||||
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||
|
||||
@ -112,7 +112,8 @@ describe('GddTransactionList', () => {
|
||||
amount: '1',
|
||||
balance: '31.76099091058520945292',
|
||||
balanceDate: '2022-02-28T13:55:47',
|
||||
memo: 'adasd adada',
|
||||
memo:
|
||||
'Um den Kessel schlingt den Reihn, Werft die Eingeweid‘ hinein. Kröte du, die Nacht und Tag Unterm kalten Steine lag,',
|
||||
linkedUser: {
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
@ -124,31 +125,14 @@ describe('GddTransactionList', () => {
|
||||
duration: 282381,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
typeId: 'CREATION',
|
||||
amount: '1000',
|
||||
balance: '32.96482231613347376132',
|
||||
balanceDate: '2022-02-25T07:29:26',
|
||||
memo: 'asd adada dad',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
decay: {
|
||||
decay: '-0.03517768386652623868',
|
||||
start: '2022-02-23T10:55:30',
|
||||
end: '2022-02-25T07:29:26',
|
||||
duration: 160436,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
typeId: 'RECEIVE',
|
||||
amount: '10',
|
||||
balance: '10',
|
||||
balanceDate: '2022-02-23T10:55:30',
|
||||
memo: 'asd adaaad adad addad ',
|
||||
memo:
|
||||
'Monatlanges Gift sog ein, In den Topf zuerst hinein… (William Shakespeare, Die Hexen aus Macbeth)',
|
||||
linkedUser: {
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
@ -160,6 +144,24 @@ describe('GddTransactionList', () => {
|
||||
duration: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
typeId: 'CREATION',
|
||||
amount: '1000',
|
||||
balance: '32.96482231613347376132',
|
||||
balanceDate: '2022-02-25T07:29:26',
|
||||
memo: 'Jammern hilft nichts, sondern ich kann selber meinen Teil dazu beitragen.',
|
||||
linkedUser: {
|
||||
firstName: 'Gradido',
|
||||
lastName: 'Akademie',
|
||||
},
|
||||
decay: {
|
||||
decay: '-0.03517768386652623868',
|
||||
start: '2022-02-23T10:55:30',
|
||||
end: '2022-02-25T07:29:26',
|
||||
duration: 160436,
|
||||
},
|
||||
},
|
||||
],
|
||||
count: 12,
|
||||
decayStartBlock,
|
||||
@ -250,7 +252,7 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('shows the message of the transaction', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-message').at(0).text()).toContain(
|
||||
'adasd adada',
|
||||
'Um den Kessel schlingt den Reihn, Werft die Eingeweid‘ hinein. Kröte du, die Nacht und Tag Unterm kalten Steine lag,',
|
||||
)
|
||||
})
|
||||
|
||||
@ -285,7 +287,7 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('has a bi-gift icon', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-gift',
|
||||
'bi-arrow-right-circle',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
@ -296,7 +298,7 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('has gradido-global-color-accent color', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-gift',
|
||||
'bi-arrow-right-circle',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
@ -314,19 +316,19 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('shows the amount of transaction', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-item-amount').at(0).text()).toContain(
|
||||
'1000',
|
||||
'+ 10 GDD',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the name of the receiver', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-item-name').at(0).text()).toContain(
|
||||
'Gradido Akademie',
|
||||
'Bibi Bloxberg',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the date of the transaction', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-item-date').at(0).text()).toContain(
|
||||
'Fri Feb 25 2022 07:29:26 GMT+0000',
|
||||
'Wed Feb 23 2022 10:55:30 GMT+0000',
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -347,12 +349,19 @@ describe('GddTransactionList', () => {
|
||||
})
|
||||
|
||||
it('has a bi-arrow-right-circle icon', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toContain('bi-arrow-right-circle')
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-gift',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
'bi',
|
||||
'gradido-global-color-accent',
|
||||
])
|
||||
})
|
||||
|
||||
it('has gradido-global-color-accent color', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-arrow-right-circle',
|
||||
'bi-gift',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
@ -376,19 +385,19 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('shows the name of the recipient', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-item-name').at(0).text()).toContain(
|
||||
'Bibi Bloxberg',
|
||||
'Gradido Akademie',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the message of the transaction', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-message').at(0).text()).toContain(
|
||||
'asd adaaad adad addad',
|
||||
'Jammern hilft nichts, sondern ich kann selber meinen Teil dazu beitragen.',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the date of the transaction', () => {
|
||||
expect(transaction.findAll('.gdd-transaction-list-item-date').at(0).text()).toContain(
|
||||
'Wed Feb 23 2022 10:55:30 GMT+0000',
|
||||
'Fri Feb 25 2022 07:29:26 GMT+0000',
|
||||
)
|
||||
})
|
||||
|
||||
@ -440,7 +449,7 @@ describe('GddTransactionList', () => {
|
||||
})
|
||||
|
||||
it('shows the text "1 / 2"', () => {
|
||||
expect(paginationButtons.find('p.text-center').text()).toBe('1 / 2')
|
||||
expect(paginationButtons.find('p.text-center').text()).toBe('1 math.div 2')
|
||||
})
|
||||
|
||||
it('emits update-transactions when next button is clicked', async () => {
|
||||
@ -452,7 +461,7 @@ describe('GddTransactionList', () => {
|
||||
|
||||
it('shows text "2 / 2" when next button is clicked', async () => {
|
||||
await paginationButtons.find('button.next-page').trigger('click')
|
||||
expect(paginationButtons.find('p.text-center').text()).toBe('2 / 2')
|
||||
expect(paginationButtons.find('p.text-center').text()).toBe('2 math.div 2')
|
||||
})
|
||||
|
||||
it('has next-button disabled when next button is clicked', async () => {
|
||||
|
||||
@ -42,11 +42,12 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #TRANSACTION_LINK>
|
||||
<transaction-link
|
||||
<template #LINK_SUMMARY>
|
||||
<transaction-link-summary
|
||||
class="list-group-item"
|
||||
v-bind="transactions[index]"
|
||||
:transactionLinkCount="transactionLinkCount"
|
||||
@update-transactions="updateTransactions"
|
||||
/>
|
||||
</template>
|
||||
</transaction-list-item>
|
||||
@ -71,7 +72,7 @@ import TransactionDecay from '@/components/Transactions/TransactionDecay'
|
||||
import TransactionSend from '@/components/Transactions/TransactionSend'
|
||||
import TransactionReceive from '@/components/Transactions/TransactionReceive'
|
||||
import TransactionCreation from '@/components/Transactions/TransactionCreation'
|
||||
import TransactionLink from '@/components/Transactions/TransactionLink'
|
||||
import TransactionLinkSummary from '@/components/Transactions/TransactionLinkSummary'
|
||||
|
||||
export default {
|
||||
name: 'gdd-transaction-list',
|
||||
@ -82,7 +83,7 @@ export default {
|
||||
TransactionSend,
|
||||
TransactionReceive,
|
||||
TransactionCreation,
|
||||
TransactionLink,
|
||||
TransactionLinkSummary,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
<div>
|
||||
<b-list-group>
|
||||
<b-list-group-item v-if="count > 5">
|
||||
<!-- eslint-disable @intlify/vue-i18n/no-v-html -->
|
||||
<router-link
|
||||
to="/transactions"
|
||||
v-html="$t('transaction.show_all', { count: count })"
|
||||
v-html="$t('transaction.show_all', { count })"
|
||||
></router-link>
|
||||
<!-- eslint-enable @intlify/vue-i18n/no-v-html -->
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</div>
|
||||
|
||||
@ -54,31 +54,31 @@ describe('Navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(1).text()).toEqual('1234 GDD')
|
||||
})
|
||||
|
||||
it('has first nav-item "overview" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('overview')
|
||||
it('has first nav-item "navigation.overview" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.overview')
|
||||
})
|
||||
it('has first nav-item "send" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('send')
|
||||
it('has first nav-item "navigation.send" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.send')
|
||||
})
|
||||
it('has first nav-item "transactions" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('transactions')
|
||||
it('has first nav-item "navigation.transactions" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.transactions')
|
||||
})
|
||||
it('has first nav-item "my-profil" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('site.navbar.my-profil')
|
||||
it('has first nav-item "navigation.profile" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.profile')
|
||||
})
|
||||
|
||||
it('has a link to the members area', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(7).text()).toContain('members_area')
|
||||
expect(wrapper.findAll('.nav-item').at(7).text()).toContain('navigation.members_area')
|
||||
expect(wrapper.findAll('.nav-item').at(7).find('a').attributes('href')).toBe(
|
||||
'https://elopage.com',
|
||||
)
|
||||
})
|
||||
|
||||
it('has first nav-item "admin_area" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('admin_area')
|
||||
it('has first nav-item "navigation.admin_area" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('navigation.admin_area')
|
||||
})
|
||||
it('has first nav-item "logout" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('logout')
|
||||
it('has first nav-item "navigation.logout" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('navigation.logout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
</div>
|
||||
|
||||
<b-navbar-nav class="ml-auto" is-nav>
|
||||
<b-nav-item>{{ pending ? '—' : balance | amount }} GDD</b-nav-item>
|
||||
<b-nav-item>{{ pending ? $t('em-dash') : balance | amount }} {{ $t('GDD') }}</b-nav-item>
|
||||
<b-nav-item to="/profile" right class="d-none d-sm-none d-md-none d-lg-flex shadow-lg">
|
||||
<small>
|
||||
{{ $store.state.firstName }} {{ $store.state.lastName }},
|
||||
{{ $store.state.firstName }} {{ $store.state.lastName }}
|
||||
<b>{{ $store.state.email }}</b>
|
||||
<b-icon class="ml-3" icon="gear-fill" aria-hidden="true"></b-icon>
|
||||
</small>
|
||||
@ -32,40 +32,42 @@
|
||||
<b-link to="/profile">
|
||||
<small>
|
||||
{{ $store.state.firstName }}
|
||||
{{ $store.state.lastName }},
|
||||
{{ $store.state.lastName }}
|
||||
<b>{{ $store.state.email }}</b>
|
||||
</small>
|
||||
</b-link>
|
||||
</div>
|
||||
<b-nav-item to="/overview" class="mb-3">
|
||||
<b-icon icon="house" aria-hidden="true"></b-icon>
|
||||
{{ $t('overview') }}
|
||||
{{ $t('navigation.overview') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/send" class="mb-3">
|
||||
<b-icon icon="arrow-left-right" aria-hidden="true"></b-icon>
|
||||
{{ $t('send') }}
|
||||
{{ $t('navigation.send') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/transactions" class="mb-3">
|
||||
<b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
|
||||
{{ $t('transactions') }}
|
||||
{{ $t('navigation.transactions') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/profile" class="mb-3">
|
||||
<b-icon icon="gear" aria-hidden="true"></b-icon>
|
||||
{{ $t('site.navbar.my-profil') }}
|
||||
{{ $t('navigation.profile') }}
|
||||
</b-nav-item>
|
||||
<br />
|
||||
<b-nav-item :href="elopageUri" class="mb-3" target="_blank">
|
||||
<b-icon icon="link45deg" aria-hidden="true"></b-icon>
|
||||
{{ $t('members_area') }}
|
||||
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">!</b-badge>
|
||||
{{ $t('navigation.members_area') }}
|
||||
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">
|
||||
{{ $t('math.exclaim') }}
|
||||
</b-badge>
|
||||
</b-nav-item>
|
||||
<b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
|
||||
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
|
||||
{{ $t('admin_area') }}
|
||||
{{ $t('navigation.admin_area') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item class="mb-3" @click="$emit('logout')">
|
||||
<b-icon icon="power" aria-hidden="true"></b-icon>
|
||||
{{ $t('logout') }}
|
||||
{{ $t('navigation.logout') }}
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
</b-collapse>
|
||||
|
||||
@ -36,29 +36,29 @@ describe('Sidebar', () => {
|
||||
expect(wrapper.findAll('.nav-item')).toHaveLength(7)
|
||||
})
|
||||
|
||||
it('has first nav-item "overview" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(0).text()).toEqual('overview')
|
||||
it('has first nav-item "navigation.overview" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(0).text()).toEqual('navigation.overview')
|
||||
})
|
||||
|
||||
it('has first nav-item "send" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(1).text()).toEqual('send')
|
||||
it('has first nav-item "navigation.send" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(1).text()).toEqual('navigation.send')
|
||||
})
|
||||
|
||||
it('has first nav-item "transactions" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('transactions')
|
||||
it('has first nav-item "navigation.transactions" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions')
|
||||
})
|
||||
it('has first nav-item "my-profil" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('site.navbar.my-profil')
|
||||
it('has first nav-item "navigation.profile" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.profile')
|
||||
})
|
||||
it('has a link to the members area', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('members_area')
|
||||
expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.members_area')
|
||||
expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('#')
|
||||
})
|
||||
it('has first nav-item "admin_area" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('admin_area')
|
||||
it('has first nav-item "navigation.admin_area" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.admin_area')
|
||||
})
|
||||
it('has first nav-item "logout" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('logout')
|
||||
it('has first nav-item "navigation.logout" in navbar', () => {
|
||||
expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.logout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,35 +6,37 @@
|
||||
<b-nav vertical class="w-200">
|
||||
<b-nav-item to="/overview" class="mb-3">
|
||||
<b-icon icon="house" aria-hidden="true"></b-icon>
|
||||
{{ $t('overview') }}
|
||||
{{ $t('navigation.overview') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/send" class="mb-3">
|
||||
<b-icon icon="arrow-left-right" aria-hidden="true"></b-icon>
|
||||
{{ $t('send') }}
|
||||
{{ $t('navigation.send') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/transactions" class="mb-3">
|
||||
<b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
|
||||
{{ $t('transactions') }}
|
||||
{{ $t('navigation.transactions') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item to="/profile" class="mb-3">
|
||||
<b-icon icon="gear" aria-hidden="true"></b-icon>
|
||||
{{ $t('site.navbar.my-profil') }}
|
||||
{{ $t('navigation.profile') }}
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
<hr />
|
||||
<b-nav vertical class="w-100">
|
||||
<b-nav-item class="mb-3" :href="elopageUri" target="_blank">
|
||||
<b-icon icon="link45deg" aria-hidden="true"></b-icon>
|
||||
{{ $t('members_area') }}
|
||||
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">!</b-badge>
|
||||
{{ $t('navigation.members_area') }}
|
||||
<b-badge v-if="!$store.state.hasElopage" pill variant="danger">
|
||||
{{ $t('math.exclaim') }}
|
||||
</b-badge>
|
||||
</b-nav-item>
|
||||
<b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
|
||||
<b-icon icon="shield-check" aria-hidden="true"></b-icon>
|
||||
{{ $t('admin_area') }}
|
||||
{{ $t('navigation.admin_area') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item class="mb-3" @click="$emit('logout')">
|
||||
<b-icon icon="power" aria-hidden="true"></b-icon>
|
||||
{{ $t('logout') }}
|
||||
{{ $t('navigation.logout') }}
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
</div>
|
||||
|
||||
@ -12,8 +12,12 @@ const propsData = {
|
||||
describe('PaginationButtons', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(PaginationButtons, { localVue, propsData })
|
||||
return mount(PaginationButtons, { localVue, mocks, propsData })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
</b-button>
|
||||
</b-col>
|
||||
<b-col cols="3">
|
||||
<p class="text-center pt-2">{{ value }} / {{ totalPages }}</p>
|
||||
<p class="text-center pt-2">{{ value }} {{ $t('math.div') }} {{ totalPages }}</p>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-button class="next-page" :disabled="!hasNext" @click="currentValue++">
|
||||
|
||||
@ -7,6 +7,7 @@ describe('Status', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$n: jest.fn((n) => n),
|
||||
}
|
||||
|
||||
@ -26,7 +27,7 @@ describe('Status', () => {
|
||||
|
||||
describe('balance is pending', () => {
|
||||
it('it displays an en-dash', () => {
|
||||
expect(wrapper.find('div.gdd-status-div').text()).toEqual('— GDD')
|
||||
expect(wrapper.find('div.gdd-status-div').text()).toEqual('em-dash GDD')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="gdd-status">
|
||||
<div class="p-0 gdd-status-div">
|
||||
{{ pending || balance === null ? '—' : $n(balance, 'decimal') }} {{ statusText }}
|
||||
{{ pending || balance === null ? $t('em-dash') : $n(balance, 'decimal') }} {{ statusText }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
{{ $t('form.date') }}
|
||||
</b-col>
|
||||
<b-col cols="6">
|
||||
{{ $d(new Date(date), 'long') }} {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
{{ $d(new Date(date), 'long') }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user