mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Alle Daten übernommen die für serverseitig rendern nötig sind
This commit is contained in:
parent
fb8468dc8b
commit
36ce6361ec
@ -8,7 +8,33 @@ export default {
|
||||
return result
|
||||
},
|
||||
UpdateUser: async (resolve, root, args, context, info) => {
|
||||
const { currentUser } = context
|
||||
if (
|
||||
!!currentUser &&
|
||||
!!args.termsAndConditionsAgreedVersion &&
|
||||
args.termsAndConditionsAgreedVersion
|
||||
) {
|
||||
const session = context.driver.session()
|
||||
const cypher = `
|
||||
MATCH (user: User { id: $userId})
|
||||
SET user.termsAndConditionsAgreedAt = $createdAt
|
||||
SET user.termsAndConditionsAgreedVersion = $version
|
||||
RETURN user { .termsAndConditionsAgreedAt, .termsAndConditionsAgreedVersion }
|
||||
`
|
||||
const variable = {
|
||||
userId: currentUser.id,
|
||||
createdAt: new Date().toISOString(),
|
||||
version: args.termsAndConditionsAgreedVersion,
|
||||
}
|
||||
await session.run(cypher, variable)
|
||||
// console.log('Nach dem speichern')
|
||||
// console.log(transactionResult)
|
||||
// console.log('-------------------------------------')
|
||||
session.close()
|
||||
}
|
||||
|
||||
const result = await resolve(root, args, context, info)
|
||||
|
||||
await createOrUpdateLocations(args.id, args.locationName, context.driver)
|
||||
return result
|
||||
},
|
||||
|
||||
@ -83,4 +83,14 @@ module.exports = {
|
||||
target: 'Notification',
|
||||
direction: 'in',
|
||||
},
|
||||
termsAndConditionsAgreedVersion: {
|
||||
type: 'string',
|
||||
allow: [null],
|
||||
},
|
||||
termsAndConditionsAgreedAt: {
|
||||
type: 'string',
|
||||
isoDate: true,
|
||||
allow: [null],
|
||||
/* required: true, TODO */
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import encode from '../../jwt/encode'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { AuthenticationError } from 'apollo-server'
|
||||
import { neo4jgraphql } from 'neo4j-graphql-js'
|
||||
import { neode } from '../../bootstrap/neo4j'
|
||||
|
||||
const instance = neode()
|
||||
@ -12,9 +11,9 @@ export default {
|
||||
return Boolean(user && user.id)
|
||||
},
|
||||
currentUser: async (object, params, ctx, resolveInfo) => {
|
||||
const { user } = ctx
|
||||
if (!user) return null
|
||||
return neo4jgraphql(object, { id: user.id }, ctx, resolveInfo, false)
|
||||
if (!ctx.user) return null
|
||||
const user = await instance.find('User', ctx.user.id)
|
||||
return user.toJson()
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import encode from '../../jwt/encode'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { neo4jgraphql } from 'neo4j-graphql-js'
|
||||
import fileUpload from './fileUpload'
|
||||
import { neode } from '../../bootstrap/neo4j'
|
||||
import { UserInputError } from 'apollo-server'
|
||||
import { AuthenticationError, UserInputError } from 'apollo-server'
|
||||
import Resolver from './helpers/Resolver'
|
||||
|
||||
const instance = neode()
|
||||
@ -55,8 +57,66 @@ export default {
|
||||
}
|
||||
return neo4jgraphql(object, args, context, resolveInfo, false)
|
||||
},
|
||||
isLoggedIn: (_, args, { driver, user }) => {
|
||||
return Boolean(user && user.id)
|
||||
},
|
||||
currentUser: async (object, params, ctx, resolveInfo) => {
|
||||
const { user } = ctx
|
||||
if (!user) return null
|
||||
return neo4jgraphql(object, { id: user.id }, ctx, resolveInfo, false)
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
login: async (_, { email, password }, { driver, req, user }) => {
|
||||
// if (user && user.id) {
|
||||
// throw new Error('Already logged in.')
|
||||
// }
|
||||
const session = driver.session()
|
||||
const result = await session.run(
|
||||
'MATCH (user:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: $userEmail})' +
|
||||
'RETURN user {.id, .slug, .name, .avatar, .encryptedPassword, .role, .disabled, email:e.email} as user LIMIT 1',
|
||||
{
|
||||
userEmail: email,
|
||||
},
|
||||
)
|
||||
session.close()
|
||||
const [currentUser] = await result.records.map(record => {
|
||||
return record.get('user')
|
||||
})
|
||||
|
||||
if (
|
||||
currentUser &&
|
||||
(await bcrypt.compareSync(password, currentUser.encryptedPassword)) &&
|
||||
!currentUser.disabled
|
||||
) {
|
||||
delete currentUser.encryptedPassword
|
||||
return encode(currentUser)
|
||||
} else if (currentUser && currentUser.disabled) {
|
||||
throw new AuthenticationError('Your account has been disabled.')
|
||||
} else {
|
||||
throw new AuthenticationError('Incorrect email address or password.')
|
||||
}
|
||||
},
|
||||
changePassword: async (_, { oldPassword, newPassword }, { driver, user }) => {
|
||||
const currentUser = await instance.find('User', user.id)
|
||||
|
||||
const encryptedPassword = currentUser.get('encryptedPassword')
|
||||
if (!(await bcrypt.compareSync(oldPassword, encryptedPassword))) {
|
||||
throw new AuthenticationError('Old password is not correct')
|
||||
}
|
||||
|
||||
if (await bcrypt.compareSync(newPassword, encryptedPassword)) {
|
||||
throw new AuthenticationError('Old password and new password should be different')
|
||||
}
|
||||
|
||||
const newEncryptedPassword = await bcrypt.hashSync(newPassword, 10)
|
||||
await currentUser.update({
|
||||
encryptedPassword: newEncryptedPassword,
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
|
||||
return encode(await currentUser.toJson())
|
||||
},
|
||||
block: async (object, args, context, resolveInfo) => {
|
||||
const { user: currentUser } = context
|
||||
if (currentUser.id === args.id) return null
|
||||
@ -122,14 +182,6 @@ export default {
|
||||
},
|
||||
},
|
||||
User: {
|
||||
email: async (parent, params, context, resolveInfo) => {
|
||||
if (typeof parent.email !== 'undefined') return parent.email
|
||||
const { id } = parent
|
||||
const statement = `MATCH(u:User {id: {id}})-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e`
|
||||
const result = await instance.cypher(statement, { id })
|
||||
const [{ email }] = result.records.map(r => r.get('e').properties)
|
||||
return email
|
||||
},
|
||||
...Resolver('User', {
|
||||
undefinedToNull: [
|
||||
'actorId',
|
||||
@ -173,5 +225,13 @@ export default {
|
||||
badges: '<-[:REWARDED]-(related:Badge)',
|
||||
},
|
||||
}),
|
||||
email: async (parent, params, context, resolveInfo) => {
|
||||
if (typeof parent.email !== 'undefined') return parent.email
|
||||
const { id } = parent
|
||||
const statement = `MATCH(u:User {id: {id}})-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e`
|
||||
const result = await instance.cypher(statement, { id })
|
||||
const [{ email }] = result.records.map(r => r.get('e').properties)
|
||||
return email
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
describe('SignupVerification', () => {
|
||||
describe('given a valid version', () => {
|
||||
// const version = '1.2.3'
|
||||
|
||||
it.todo('saves the version with the new created user account')
|
||||
it.todo('saves the current datetime in `termsAndConditionsAgreedAt`')
|
||||
})
|
||||
|
||||
describe('given an invalid version string', () => {
|
||||
// const version = 'this string does not follow semantic versioning'
|
||||
|
||||
it.todo('rejects')
|
||||
})
|
||||
})
|
||||
|
||||
describe('UpdateUser', () => {
|
||||
describe('given a new agreed version of terms and conditions', () => {
|
||||
it.todo('updates `termsAndConditionsAgreedAt`')
|
||||
it.todo('updates `termsAndConditionsAgreedVersion`')
|
||||
})
|
||||
})
|
||||
@ -19,5 +19,6 @@ type Mutation {
|
||||
avatarUpload: Upload
|
||||
locationName: String
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String!
|
||||
): User
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@ type User {
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
|
||||
termsAndConditionsAgreedVersion: String!
|
||||
|
||||
notifications(read: Boolean): [Notification]! @relation(name: "NOTIFIED", direction: "IN")
|
||||
|
||||
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
|
||||
@ -152,6 +154,7 @@ type Query {
|
||||
): [User]
|
||||
|
||||
blockedUsers: [User]
|
||||
currentUser: User
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
@ -165,6 +168,7 @@ type Mutation {
|
||||
avatarUpload: Upload
|
||||
locationName: String
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String
|
||||
): User
|
||||
|
||||
DeleteUser(id: ID!, resource: [Deletable]): User
|
||||
|
||||
@ -14,6 +14,8 @@ export default function create() {
|
||||
role: 'user',
|
||||
avatar: faker.internet.avatar(),
|
||||
about: faker.lorem.paragraph(),
|
||||
termsAndConditionsAgreedAt: new Date().toISOString(),
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
}
|
||||
defaults.slug = slugify(defaults.name, { lower: true })
|
||||
args = {
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
"imprint": "Impressum",
|
||||
"data-privacy": "Datenschutz",
|
||||
"termsAndConditions": "Nutzungsbedingungen",
|
||||
"newTermsAndConditions": "Neue Nutzungsbedingungen",
|
||||
"changelog": "Änderungen & Verlauf",
|
||||
"contact": "Kontakt",
|
||||
"tribunal": "Registergericht",
|
||||
@ -35,7 +36,8 @@
|
||||
"bank": "Bankverbindung",
|
||||
"germany": "Deutschland",
|
||||
"code-of-conduct": "Verhaltenscodex",
|
||||
"termsAndConditionsConfirmed": "Ich habe die <a href=\"/terms-and-conditions\" target=\"_blank\">Nutzungsbedingungen</a> durchgelesen und stimme ihnen zu."
|
||||
"termsAndConditionsConfirmed": "Ich habe die <a href=\"/terms-and-conditions\" target=\"_blank\">Nutzungsbedingungen</a> durchgelesen und stimme ihnen zu.",
|
||||
"termsAndConditionsNewConfirm": "Bestätige bitte die neuen Nutzungsbedingungen"
|
||||
},
|
||||
"sorting": {
|
||||
"newest": "Neuste",
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
"made": "Made with ❤",
|
||||
"imprint": "Imprint",
|
||||
"termsAndConditions": "Terms and conditions",
|
||||
"newTermsAndConditions": "New Terms and conditions",
|
||||
"data-privacy": "Data privacy",
|
||||
"changelog": "Changes & History",
|
||||
"contact": "Contact",
|
||||
@ -35,7 +36,8 @@
|
||||
"bank": "bank account",
|
||||
"germany": "Germany",
|
||||
"code-of-conduct": "Code of Conduct",
|
||||
"termsAndConditionsConfirmed": "I have read and confirmed the <a href=\"/terms-and-conditions\" target=\"_blank\">terms and conditions</a>."
|
||||
"termsAndConditionsConfirmed": "I have read and confirmed the <a href=\"/terms-and-conditions\" target=\"_blank\">terms and conditions</a>.",
|
||||
"termsAndConditionsNewConfirm": "Please confirm the new Terms and Conditions"
|
||||
},
|
||||
"sorting": {
|
||||
"newest": "Newest",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import { VERSION } from '~/pages/terms-and-conditions'
|
||||
|
||||
export default async ({ store, env, route, redirect }) => {
|
||||
let publicPages = env.publicPages
|
||||
@ -9,7 +10,14 @@ export default async ({ store, env, route, redirect }) => {
|
||||
|
||||
// await store.dispatch('auth/refreshJWT', 'authenticated middleware')
|
||||
const isAuthenticated = await store.dispatch('auth/check')
|
||||
if (isAuthenticated === true) {
|
||||
|
||||
// TODO: find a better solution to **reliably** get the user
|
||||
// having the encrypted JWT does not mean we have access to the user object
|
||||
const user = await store.getters['auth/user']
|
||||
|
||||
const upToDate = user.termsAndConditionsAgreedVersion === VERSION
|
||||
|
||||
if (isAuthenticated === true && upToDate) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -22,5 +30,9 @@ export default async ({ store, env, route, redirect }) => {
|
||||
params.path = route.path
|
||||
}
|
||||
|
||||
return redirect('/login', params)
|
||||
if (!upToDate) {
|
||||
return redirect('/terms-and-conditions-confirm', params)
|
||||
} else {
|
||||
return redirect('/login', params)
|
||||
}
|
||||
}
|
||||
|
||||
101
webapp/pages/terms-and-conditions-confirm.vue
Normal file
101
webapp/pages/terms-and-conditions-confirm.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-space>
|
||||
<ds-heading tag="h2">{{ $t(`site.newTermsAndConditions`) }}</ds-heading>
|
||||
</ds-space>
|
||||
<ds-container>
|
||||
<div>
|
||||
<ds-button secondary class="display:none" @click="submit">
|
||||
{{ $t(`site.termsAndConditionsNewConfirm`) }}
|
||||
</ds-button>
|
||||
</div>
|
||||
<div>
|
||||
<ol>
|
||||
<li v-for="section in sections" :key="section">
|
||||
<strong>{{ $t(`termsAndConditions.${section}.title`) }}:</strong>
|
||||
<p v-html="$t(`termsAndConditions.${section}.description`)" />
|
||||
</li>
|
||||
</ol>
|
||||
<p>{{ $t(`termsAndConditions.have-fun`) }}</p>
|
||||
<br />
|
||||
<p>
|
||||
<strong v-html="$t(`termsAndConditions.closing`)" />
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<ds-button secondary class="display:none" @click="submit">
|
||||
{{ $t(`site.termsAndConditionsNewConfirm`) }}
|
||||
</ds-button>
|
||||
</div>
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { VERSION } from '~/pages/terms-and-conditions'
|
||||
const mutation = gql`
|
||||
mutation($id: ID!, $termsAndConditionsAgreedVersion: String) {
|
||||
UpdateUser(id: $id, termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion) {
|
||||
id
|
||||
termsAndConditionsAgreedVersion
|
||||
}
|
||||
}
|
||||
`
|
||||
export default {
|
||||
layout: 'default',
|
||||
head() {
|
||||
return {
|
||||
title: this.$t('site.newTermsAndConditions'),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
...mapMutations({
|
||||
setCurrentUser: 'auth/SET_USER',
|
||||
}),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
sections: [
|
||||
'risk',
|
||||
'data-privacy',
|
||||
'work-in-progress',
|
||||
'code-of-conduct',
|
||||
'moderation',
|
||||
'fairness',
|
||||
'questions',
|
||||
'human-connection',
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation,
|
||||
variables: {
|
||||
id: this.currentUser.id,
|
||||
termsAndConditionsAgreedVersion: VERSION,
|
||||
},
|
||||
update: (store, { data: { UpdateUser } }) => {
|
||||
const { termsAndConditionsAgreedVersion } = UpdateUser
|
||||
this.setCurrentUser({
|
||||
...this.currentUser,
|
||||
termsAndConditionsAgreedVersion,
|
||||
})
|
||||
},
|
||||
})
|
||||
this.$toast.success(this.$t('DANKE'))
|
||||
this.$router.push('/')
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -22,6 +22,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export const VERSION = '0.0.2'
|
||||
|
||||
export default {
|
||||
layout: 'default',
|
||||
head() {
|
||||
|
||||
@ -82,6 +82,7 @@ export const actions = {
|
||||
locationName
|
||||
contributionsCount
|
||||
commentedCount
|
||||
termsAndConditionsAgreedVersion
|
||||
socialMedia {
|
||||
id
|
||||
url
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user