mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #1334 from Human-Connection/C-1187-terms-and-conditions-confirmed-function
Check if user has agreed to the current terms and conditions
This commit is contained in:
commit
4ca84ee04a
@ -89,8 +89,10 @@ describe('slugify', () => {
|
||||
})
|
||||
|
||||
describe('SignupVerification', () => {
|
||||
const mutation = `mutation($password: String!, $email: String!, $name: String!, $slug: String, $nonce: String!) {
|
||||
SignupVerification(email: $email, password: $password, name: $name, slug: $slug, nonce: $nonce) { slug }
|
||||
const mutation = `mutation($password: String!, $email: String!, $name: String!, $slug: String, $nonce: String!, $termsAndConditionsAgreedVersion: String!) {
|
||||
SignupVerification(email: $email, password: $password, name: $name, slug: $slug, nonce: $nonce, termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion) {
|
||||
slug
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -98,7 +100,12 @@ describe('slugify', () => {
|
||||
// required for SignupVerification
|
||||
await instance.create('EmailAddress', { email: '123@example.org', nonce: '123456' })
|
||||
|
||||
const defaultVariables = { nonce: '123456', password: 'yo', email: '123@example.org' }
|
||||
const defaultVariables = {
|
||||
nonce: '123456',
|
||||
password: 'yo',
|
||||
email: '123@example.org',
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
}
|
||||
return authenticatedClient.request(mutation, { ...defaultVariables, ...variables })
|
||||
}
|
||||
|
||||
|
||||
@ -80,9 +80,19 @@ module.exports = {
|
||||
notifications: {
|
||||
type: 'relationship',
|
||||
relationship: 'NOTIFIED',
|
||||
target: 'Notification',
|
||||
target: 'User',
|
||||
direction: 'in',
|
||||
},
|
||||
termsAndConditionsAgreedVersion: {
|
||||
type: 'string',
|
||||
allow: [null],
|
||||
},
|
||||
/* termsAndConditionsAgreedAt: {
|
||||
type: 'string',
|
||||
isoDate: true,
|
||||
allow: [null],
|
||||
// required: true, TODO
|
||||
}, */
|
||||
shouted: {
|
||||
type: 'relationship',
|
||||
relationship: 'SHOUTED',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { UserInputError } from 'apollo-server'
|
||||
import { ForbiddenError, UserInputError } from 'apollo-server'
|
||||
import uuid from 'uuid/v4'
|
||||
import { neode } from '../../bootstrap/neo4j'
|
||||
import fileUpload from './fileUpload'
|
||||
@ -77,6 +77,12 @@ export default {
|
||||
}
|
||||
},
|
||||
SignupVerification: async (object, args, context, resolveInfo) => {
|
||||
const { termsAndConditionsAgreedVersion } = args
|
||||
const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g)
|
||||
if (!regEx.test(termsAndConditionsAgreedVersion)) {
|
||||
throw new ForbiddenError('Invalid version format!')
|
||||
}
|
||||
|
||||
let { nonce, email } = args
|
||||
email = email.toLowerCase()
|
||||
const result = await instance.cypher(
|
||||
|
||||
@ -34,6 +34,7 @@ describe('CreateInvitationCode', () => {
|
||||
name: 'Inviter',
|
||||
email: 'inviter@example.org',
|
||||
password: '1234',
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
}
|
||||
action = async () => {
|
||||
const factory = Factory()
|
||||
@ -293,19 +294,25 @@ describe('Signup', () => {
|
||||
|
||||
describe('SignupVerification', () => {
|
||||
const mutation = `
|
||||
mutation($name: String!, $password: String!, $email: String!, $nonce: String!) {
|
||||
SignupVerification(name: $name, password: $password, email: $email, nonce: $nonce) {
|
||||
mutation($name: String!, $password: String!, $email: String!, $nonce: String!, $termsAndConditionsAgreedVersion: String!) {
|
||||
SignupVerification(name: $name, password: $password, email: $email, nonce: $nonce, termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion) {
|
||||
id
|
||||
termsAndConditionsAgreedVersion
|
||||
}
|
||||
}
|
||||
`
|
||||
describe('given valid password and email', () => {
|
||||
const variables = {
|
||||
nonce: '123456',
|
||||
name: 'John Doe',
|
||||
password: '123',
|
||||
email: 'john@example.org',
|
||||
}
|
||||
let variables
|
||||
|
||||
beforeEach(async () => {
|
||||
variables = {
|
||||
nonce: '123456',
|
||||
name: 'John Doe',
|
||||
password: '123',
|
||||
email: 'john@example.org',
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
}
|
||||
})
|
||||
|
||||
describe('unauthenticated', () => {
|
||||
beforeEach(async () => {
|
||||
@ -349,9 +356,9 @@ describe('SignupVerification', () => {
|
||||
describe('sending a valid nonce', () => {
|
||||
it('creates a user account', async () => {
|
||||
const expected = {
|
||||
SignupVerification: {
|
||||
SignupVerification: expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
},
|
||||
}),
|
||||
}
|
||||
await expect(client.request(mutation, variables)).resolves.toEqual(expected)
|
||||
})
|
||||
@ -385,6 +392,24 @@ describe('SignupVerification', () => {
|
||||
const { records: emails } = await instance.cypher(cypher, { name: 'John Doe' })
|
||||
expect(emails).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('is version of terms and conditions saved correctly', async () => {
|
||||
const expected = {
|
||||
SignupVerification: expect.objectContaining({
|
||||
termsAndConditionsAgreedVersion: '0.0.1',
|
||||
}),
|
||||
}
|
||||
await expect(client.request(mutation, variables)).resolves.toEqual(expected)
|
||||
})
|
||||
|
||||
it('rejects if version of terms and conditions has wrong format', async () => {
|
||||
await expect(
|
||||
client.request(mutation, {
|
||||
...variables,
|
||||
termsAndConditionsAgreedVersion: 'invalid version format',
|
||||
}),
|
||||
).rejects.toThrow('Invalid version format!')
|
||||
})
|
||||
})
|
||||
|
||||
describe('sending invalid nonce', () => {
|
||||
|
||||
@ -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,7 @@
|
||||
import { neo4jgraphql } from 'neo4j-graphql-js'
|
||||
import fileUpload from './fileUpload'
|
||||
import { neode } from '../../bootstrap/neo4j'
|
||||
import { UserInputError } from 'apollo-server'
|
||||
import { UserInputError, ForbiddenError } from 'apollo-server'
|
||||
import Resolver from './helpers/Resolver'
|
||||
|
||||
const instance = neode()
|
||||
@ -88,6 +88,13 @@ export default {
|
||||
return blockedUser.toJson()
|
||||
},
|
||||
UpdateUser: async (object, args, context, resolveInfo) => {
|
||||
const { termsAndConditionsAgreedVersion } = args
|
||||
if (termsAndConditionsAgreedVersion) {
|
||||
const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g)
|
||||
if (!regEx.test(termsAndConditionsAgreedVersion)) {
|
||||
throw new ForbiddenError('Invalid version format!')
|
||||
}
|
||||
}
|
||||
args = await fileUpload(args, { file: 'avatarUpload', url: 'avatar' })
|
||||
try {
|
||||
const user = await instance.find('User', args.id)
|
||||
|
||||
@ -75,22 +75,33 @@ describe('User', () => {
|
||||
})
|
||||
|
||||
describe('UpdateUser', () => {
|
||||
const userParams = {
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
id: 'u47',
|
||||
name: 'John Doe',
|
||||
}
|
||||
const variables = {
|
||||
id: 'u47',
|
||||
name: 'John Doughnut',
|
||||
}
|
||||
let userParams
|
||||
let variables
|
||||
|
||||
beforeEach(async () => {
|
||||
userParams = {
|
||||
email: 'user@example.org',
|
||||
password: '1234',
|
||||
id: 'u47',
|
||||
name: 'John Doe',
|
||||
}
|
||||
|
||||
variables = {
|
||||
id: 'u47',
|
||||
name: 'John Doughnut',
|
||||
}
|
||||
})
|
||||
|
||||
const updateUserMutation = gql`
|
||||
mutation($id: ID!, $name: String) {
|
||||
UpdateUser(id: $id, name: $name) {
|
||||
mutation($id: ID!, $name: String, $termsAndConditionsAgreedVersion: String) {
|
||||
UpdateUser(
|
||||
id: $id
|
||||
name: $name
|
||||
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
|
||||
) {
|
||||
id
|
||||
name
|
||||
termsAndConditionsAgreedVersion
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -159,6 +170,30 @@ describe('UpdateUser', () => {
|
||||
'child "name" fails because ["name" length must be at least 3 characters long]',
|
||||
)
|
||||
})
|
||||
|
||||
it('given a new agreed version of terms and conditions', async () => {
|
||||
variables = { ...variables, termsAndConditionsAgreedVersion: '0.0.2' }
|
||||
const expected = {
|
||||
data: {
|
||||
UpdateUser: expect.objectContaining({
|
||||
termsAndConditionsAgreedVersion: '0.0.2',
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
await expect(mutate({ mutation: updateUserMutation, variables })).resolves.toMatchObject(
|
||||
expected,
|
||||
)
|
||||
})
|
||||
|
||||
it('rejects if version of terms and conditions has wrong format', async () => {
|
||||
variables = {
|
||||
...variables,
|
||||
termsAndConditionsAgreedVersion: 'invalid version format',
|
||||
}
|
||||
const { errors } = await mutate({ mutation: updateUserMutation, variables })
|
||||
expect(errors[0]).toHaveProperty('message', 'Invalid version format!')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
type EmailAddress {
|
||||
id: ID!
|
||||
email: String!
|
||||
email: ID!
|
||||
verifiedAt: String
|
||||
createdAt: String
|
||||
}
|
||||
@ -19,5 +18,6 @@ type Mutation {
|
||||
avatarUpload: Upload
|
||||
locationName: String
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String
|
||||
): User
|
||||
}
|
||||
|
||||
@ -1,173 +1,177 @@
|
||||
type User {
|
||||
id: ID!
|
||||
actorId: String
|
||||
name: String
|
||||
email: String! @cypher(statement: "MATCH (this)-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e.email")
|
||||
slug: String!
|
||||
avatar: String
|
||||
coverImg: String
|
||||
deleted: Boolean
|
||||
disabled: Boolean
|
||||
disabledBy: User @relation(name: "DISABLED", direction: "IN")
|
||||
role: UserGroup!
|
||||
publicKey: String
|
||||
invitedBy: User @relation(name: "INVITED", direction: "IN")
|
||||
invited: [User] @relation(name: "INVITED", direction: "OUT")
|
||||
id: ID!
|
||||
actorId: String
|
||||
name: String
|
||||
email: String! @cypher(statement: "MATCH (this)-[: PRIMARY_EMAIL]->(e: EmailAddress) RETURN e.email")
|
||||
slug: String!
|
||||
avatar: String
|
||||
coverImg: String
|
||||
deleted: Boolean
|
||||
disabled: Boolean
|
||||
disabledBy: User @relation(name: "DISABLED", direction: "IN")
|
||||
role: UserGroup!
|
||||
publicKey: String
|
||||
invitedBy: User @relation(name: "INVITED", direction: "IN")
|
||||
invited: [User] @relation(name: "INVITED", direction: "OUT")
|
||||
|
||||
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||
locationName: String
|
||||
about: String
|
||||
socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
|
||||
location: Location @cypher(statement: "MATCH (this)-[: IS_IN]->(l: Location) RETURN l")
|
||||
locationName: String
|
||||
about: String
|
||||
socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
|
||||
|
||||
#createdAt: DateTime
|
||||
#updatedAt: DateTime
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
# createdAt: DateTime
|
||||
# updatedAt: DateTime
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
|
||||
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
|
||||
friendsCount: Int! @cypher(statement: "MATCH (this)<-[:FRIENDS]->(r:User) RETURN COUNT(DISTINCT r)")
|
||||
termsAndConditionsAgreedVersion: String
|
||||
|
||||
following: [User]! @relation(name: "FOLLOWS", direction: "OUT")
|
||||
followingCount: Int! @cypher(statement: "MATCH (this)-[:FOLLOWS]->(r:User) RETURN COUNT(DISTINCT r)")
|
||||
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
|
||||
friendsCount: Int! @cypher(statement: "MATCH (this)<-[: FRIENDS]->(r: User) RETURN COUNT(DISTINCT r)")
|
||||
|
||||
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
|
||||
followedByCount: Int! @cypher(statement: "MATCH (this)<-[:FOLLOWS]-(r:User) RETURN COUNT(DISTINCT r)")
|
||||
following: [User]! @relation(name: "FOLLOWS", direction: "OUT")
|
||||
followingCount: Int! @cypher(statement: "MATCH (this)-[: FOLLOWS]->(r: User) RETURN COUNT(DISTINCT r)")
|
||||
|
||||
# Is the currently logged in user following that user?
|
||||
followedByCurrentUser: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)<-[:FOLLOWS]-(u:User {id: $cypherParams.currentUserId})
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
isBlocked: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)<-[:BLOCKED]-(u:User {id: $cypherParams.currentUserId})
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
|
||||
followedByCount: Int! @cypher(statement: "MATCH (this)<-[: FOLLOWS]-(r: User) RETURN COUNT(DISTINCT r)")
|
||||
|
||||
#contributions: [WrittenPost]!
|
||||
#contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
|
||||
# @cypher(
|
||||
# statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp"
|
||||
# )
|
||||
contributions: [Post]! @relation(name: "WROTE", direction: "OUT")
|
||||
contributionsCount: Int! @cypher(
|
||||
statement: """
|
||||
MATCH (this)-[:WROTE]->(r:Post)
|
||||
WHERE NOT r.deleted = true AND NOT r.disabled = true
|
||||
RETURN COUNT(r)
|
||||
"""
|
||||
)
|
||||
# Is the currently logged in user following that user?
|
||||
followedByCurrentUser: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId})
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
isBlocked: Boolean! @cypher(
|
||||
statement: """
|
||||
MATCH (this)<-[: BLOCKED]-(u: User { id: $cypherParams.currentUserId})
|
||||
RETURN COUNT(u) >= 1
|
||||
"""
|
||||
)
|
||||
|
||||
comments: [Comment]! @relation(name: "WROTE", direction: "OUT")
|
||||
commentedCount: Int! @cypher(statement: "MATCH (this)-[:WROTE]->(:Comment)-[:COMMENTS]->(p:Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))")
|
||||
# contributions: [WrittenPost]!
|
||||
# contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
|
||||
# @cypher(
|
||||
# statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp"
|
||||
# )
|
||||
contributions: [Post]! @relation(name: "WROTE", direction: "OUT")
|
||||
contributionsCount: Int! @cypher(
|
||||
statement: """
|
||||
MATCH (this)-[: WROTE]->(r: Post)
|
||||
WHERE NOT r.deleted = true AND NOT r.disabled = true
|
||||
RETURN COUNT(r)
|
||||
"""
|
||||
)
|
||||
|
||||
shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT")
|
||||
shoutedCount: Int! @cypher(statement: "MATCH (this)-[:SHOUTED]->(r:Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)")
|
||||
comments: [Comment]! @relation(name: "WROTE", direction: "OUT")
|
||||
commentedCount: Int! @cypher(statement: "MATCH (this)-[: WROTE]->(: Comment)-[: COMMENTS]->(p: Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))")
|
||||
|
||||
organizationsCreated: [Organization] @relation(name: "CREATED_ORGA", direction: "OUT")
|
||||
organizationsOwned: [Organization] @relation(name: "OWNING_ORGA", direction: "OUT")
|
||||
shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT")
|
||||
shoutedCount: Int! @cypher(statement: "MATCH (this)-[: SHOUTED]->(r: Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)")
|
||||
|
||||
categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT")
|
||||
organizationsCreated: [Organization] @relation(name: "CREATED_ORGA", direction: "OUT")
|
||||
organizationsOwned: [Organization] @relation(name: "OWNING_ORGA", direction: "OUT")
|
||||
|
||||
badges: [Badge]! @relation(name: "REWARDED", direction: "IN")
|
||||
badgesCount: Int! @cypher(statement: "MATCH (this)<-[:REWARDED]-(r:Badge) RETURN COUNT(r)")
|
||||
categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT")
|
||||
|
||||
emotions: [EMOTED]
|
||||
badges: [Badge]! @relation(name: "REWARDED", direction: "IN")
|
||||
badgesCount: Int! @cypher(statement: "MATCH (this)<-[: REWARDED]-(r: Badge) RETURN COUNT(r)")
|
||||
|
||||
emotions: [EMOTED]
|
||||
}
|
||||
|
||||
|
||||
input _UserFilter {
|
||||
AND: [_UserFilter!]
|
||||
OR: [_UserFilter!]
|
||||
name_contains: String
|
||||
about_contains: String
|
||||
slug_contains: String
|
||||
id: ID
|
||||
id_not: ID
|
||||
id_in: [ID!]
|
||||
id_not_in: [ID!]
|
||||
id_contains: ID
|
||||
id_not_contains: ID
|
||||
id_starts_with: ID
|
||||
id_not_starts_with: ID
|
||||
id_ends_with: ID
|
||||
id_not_ends_with: ID
|
||||
friends: _UserFilter
|
||||
friends_not: _UserFilter
|
||||
friends_in: [_UserFilter!]
|
||||
friends_not_in: [_UserFilter!]
|
||||
friends_some: _UserFilter
|
||||
friends_none: _UserFilter
|
||||
friends_single: _UserFilter
|
||||
friends_every: _UserFilter
|
||||
following: _UserFilter
|
||||
following_not: _UserFilter
|
||||
following_in: [_UserFilter!]
|
||||
following_not_in: [_UserFilter!]
|
||||
following_some: _UserFilter
|
||||
following_none: _UserFilter
|
||||
following_single: _UserFilter
|
||||
following_every: _UserFilter
|
||||
followedBy: _UserFilter
|
||||
followedBy_not: _UserFilter
|
||||
followedBy_in: [_UserFilter!]
|
||||
followedBy_not_in: [_UserFilter!]
|
||||
followedBy_some: _UserFilter
|
||||
followedBy_none: _UserFilter
|
||||
followedBy_single: _UserFilter
|
||||
followedBy_every: _UserFilter
|
||||
AND: [_UserFilter!]
|
||||
OR: [_UserFilter!]
|
||||
name_contains: String
|
||||
about_contains: String
|
||||
slug_contains: String
|
||||
id: ID
|
||||
id_not: ID
|
||||
id_in: [ID!]
|
||||
id_not_in: [ID!]
|
||||
id_contains: ID
|
||||
id_not_contains: ID
|
||||
id_starts_with: ID
|
||||
id_not_starts_with: ID
|
||||
id_ends_with: ID
|
||||
id_not_ends_with: ID
|
||||
friends: _UserFilter
|
||||
friends_not: _UserFilter
|
||||
friends_in: [_UserFilter!]
|
||||
friends_not_in: [_UserFilter!]
|
||||
friends_some: _UserFilter
|
||||
friends_none: _UserFilter
|
||||
friends_single: _UserFilter
|
||||
friends_every: _UserFilter
|
||||
following: _UserFilter
|
||||
following_not: _UserFilter
|
||||
following_in: [_UserFilter!]
|
||||
following_not_in: [_UserFilter!]
|
||||
following_some: _UserFilter
|
||||
following_none: _UserFilter
|
||||
following_single: _UserFilter
|
||||
following_every: _UserFilter
|
||||
followedBy: _UserFilter
|
||||
followedBy_not: _UserFilter
|
||||
followedBy_in: [_UserFilter!]
|
||||
followedBy_not_in: [_UserFilter!]
|
||||
followedBy_some: _UserFilter
|
||||
followedBy_none: _UserFilter
|
||||
followedBy_single: _UserFilter
|
||||
followedBy_every: _UserFilter
|
||||
}
|
||||
|
||||
type Query {
|
||||
User(
|
||||
id: ID
|
||||
email: String
|
||||
actorId: String
|
||||
name: String
|
||||
slug: String
|
||||
avatar: String
|
||||
coverImg: String
|
||||
role: UserGroup
|
||||
locationName: String
|
||||
about: String
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
friendsCount: Int
|
||||
followingCount: Int
|
||||
followedByCount: Int
|
||||
followedByCurrentUser: Boolean
|
||||
contributionsCount: Int
|
||||
commentedCount: Int
|
||||
shoutedCount: Int
|
||||
badgesCount: Int
|
||||
first: Int
|
||||
offset: Int
|
||||
orderBy: [_UserOrdering]
|
||||
filter: _UserFilter
|
||||
): [User]
|
||||
User(
|
||||
id: ID
|
||||
email: String
|
||||
actorId: String
|
||||
name: String
|
||||
slug: String
|
||||
avatar: String
|
||||
coverImg: String
|
||||
role: UserGroup
|
||||
locationName: String
|
||||
about: String
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
friendsCount: Int
|
||||
followingCount: Int
|
||||
followedByCount: Int
|
||||
followedByCurrentUser: Boolean
|
||||
contributionsCount: Int
|
||||
commentedCount: Int
|
||||
shoutedCount: Int
|
||||
badgesCount: Int
|
||||
first: Int
|
||||
offset: Int
|
||||
orderBy: [_UserOrdering]
|
||||
filter: _UserFilter
|
||||
): [User]
|
||||
|
||||
blockedUsers: [User]
|
||||
blockedUsers: [User]
|
||||
currentUser: User
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
UpdateUser (
|
||||
id: ID!
|
||||
name: String
|
||||
email: String
|
||||
slug: String
|
||||
avatar: String
|
||||
coverImg: String
|
||||
avatarUpload: Upload
|
||||
locationName: String
|
||||
about: String
|
||||
): User
|
||||
UpdateUser (
|
||||
id: ID!
|
||||
name: String
|
||||
email: String
|
||||
slug: String
|
||||
avatar: String
|
||||
coverImg: String
|
||||
avatarUpload: Upload
|
||||
locationName: String
|
||||
about: String
|
||||
termsAndConditionsAgreedVersion: String
|
||||
): User
|
||||
|
||||
DeleteUser(id: ID!, resource: [Deletable]): User
|
||||
DeleteUser(id: ID!, resource: [Deletable]): User
|
||||
|
||||
|
||||
block(id: ID!): User
|
||||
unblock(id: ID!): User
|
||||
}
|
||||
block(id: ID!): User
|
||||
unblock(id: ID!): 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 = {
|
||||
|
||||
@ -3,4 +3,4 @@
|
||||
"NEO4J_URI": "bolt://localhost:7687",
|
||||
"NEO4J_USERNAME": "neo4j",
|
||||
"NEO4J_PASSWORD": "letmein"
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,7 @@ Given('I am logged in with a {string} role', role => {
|
||||
cy.factory().create('User', {
|
||||
email: `${role}@example.org`,
|
||||
password: '1234',
|
||||
termsAndConditionsAgreedVersion: "0.0.2",
|
||||
role
|
||||
})
|
||||
cy.login({
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { Given, When, Then } from "cypress-cucumber-preprocessor/steps";
|
||||
import {
|
||||
Given,
|
||||
When,
|
||||
Then
|
||||
} from "cypress-cucumber-preprocessor/steps";
|
||||
import helpers from "../../support/helpers";
|
||||
|
||||
/* global cy */
|
||||
@ -9,12 +13,16 @@ let loginCredentials = {
|
||||
email: "peterpan@example.org",
|
||||
password: "1234"
|
||||
};
|
||||
const termsAndConditionsAgreedVersion = {
|
||||
termsAndConditionsAgreedVersion: "0.0.2"
|
||||
};
|
||||
const narratorParams = {
|
||||
id: 'id-of-peter-pan',
|
||||
name: "Peter Pan",
|
||||
slug: "peter-pan",
|
||||
avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg",
|
||||
...loginCredentials
|
||||
...loginCredentials,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
};
|
||||
|
||||
Given("I am logged in", () => {
|
||||
@ -28,25 +36,54 @@ Given("we have a selection of categories", () => {
|
||||
Given("we have a selection of tags and categories as well as posts", () => {
|
||||
cy.createCategories("cat12")
|
||||
.factory()
|
||||
.create("Tag", { id: "Ecology" })
|
||||
.create("Tag", { id: "Nature" })
|
||||
.create("Tag", { id: "Democracy" });
|
||||
.create("Tag", {
|
||||
id: "Ecology"
|
||||
})
|
||||
.create("Tag", {
|
||||
id: "Nature"
|
||||
})
|
||||
.create("Tag", {
|
||||
id: "Democracy"
|
||||
});
|
||||
|
||||
cy.factory()
|
||||
.create("User", { id: 'a1' })
|
||||
.create("Post", {authorId: 'a1', tagIds: [ "Ecology", "Nature", "Democracy" ], categoryIds: ["cat12"] })
|
||||
.create("Post", {authorId: 'a1', tagIds: [ "Nature", "Democracy" ], categoryIds: ["cat121"] });
|
||||
.create("User", {
|
||||
id: 'a1'
|
||||
})
|
||||
.create("Post", {
|
||||
authorId: 'a1',
|
||||
tagIds: ["Ecology", "Nature", "Democracy"],
|
||||
categoryIds: ["cat12"]
|
||||
})
|
||||
.create("Post", {
|
||||
authorId: 'a1',
|
||||
tagIds: ["Nature", "Democracy"],
|
||||
categoryIds: ["cat121"]
|
||||
});
|
||||
|
||||
cy.factory()
|
||||
.create("User", { id: 'a2'})
|
||||
.create("Post", { authorId: 'a2', tagIds: ['Nature', 'Democracy'], categoryIds: ["cat12"] });
|
||||
.create("User", {
|
||||
id: 'a2'
|
||||
})
|
||||
.create("Post", {
|
||||
authorId: 'a2',
|
||||
tagIds: ['Nature', 'Democracy'],
|
||||
categoryIds: ["cat12"]
|
||||
});
|
||||
cy.factory()
|
||||
.create("Post", { authorId: narratorParams.id, tagIds: ['Democracy'], categoryIds: ["cat122"] })
|
||||
.create("Post", {
|
||||
authorId: narratorParams.id,
|
||||
tagIds: ['Democracy'],
|
||||
categoryIds: ["cat122"]
|
||||
})
|
||||
});
|
||||
|
||||
Given("we have the following user accounts:", table => {
|
||||
table.hashes().forEach(params => {
|
||||
cy.factory().create("User", params);
|
||||
cy.factory().create("User", {
|
||||
...params,
|
||||
...termsAndConditionsAgreedVersion
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -57,7 +94,8 @@ Given("I have a user account", () => {
|
||||
Given("my user account has the role {string}", role => {
|
||||
cy.factory().create("User", {
|
||||
role,
|
||||
...loginCredentials
|
||||
...loginCredentials,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
});
|
||||
});
|
||||
|
||||
@ -117,7 +155,9 @@ Given("I previously switched the language to {string}", name => {
|
||||
});
|
||||
|
||||
Then("the whole user interface appears in {string}", name => {
|
||||
const { code } = helpers.getLangByName(name);
|
||||
const {
|
||||
code
|
||||
} = helpers.getLangByName(name);
|
||||
cy.get(`html[lang=${code}]`);
|
||||
cy.getCookie("locale").should("have.property", "value", code);
|
||||
});
|
||||
@ -151,7 +191,9 @@ Given("we have the following posts in our database:", table => {
|
||||
icon: "smile"
|
||||
})
|
||||
|
||||
table.hashes().forEach(({ ...postAttributes }, i) => {
|
||||
table.hashes().forEach(({
|
||||
...postAttributes
|
||||
}, i) => {
|
||||
postAttributes = {
|
||||
...postAttributes,
|
||||
deleted: Boolean(postAttributes.deleted),
|
||||
@ -229,10 +271,15 @@ Then("the first post on the landing page has the title:", title => {
|
||||
Then(
|
||||
"the page {string} returns a 404 error with a message:",
|
||||
(route, message) => {
|
||||
cy.request({ url: route, failOnStatusCode: false })
|
||||
cy.request({
|
||||
url: route,
|
||||
failOnStatusCode: false
|
||||
})
|
||||
.its("status")
|
||||
.should("eq", 404);
|
||||
cy.visit(route, { failOnStatusCode: false });
|
||||
cy.visit(route, {
|
||||
failOnStatusCode: false
|
||||
});
|
||||
cy.get(".error").should("contain", message);
|
||||
}
|
||||
);
|
||||
@ -240,7 +287,10 @@ Then(
|
||||
Given("my user account has the following login credentials:", table => {
|
||||
loginCredentials = table.hashes()[0];
|
||||
cy.debug();
|
||||
cy.factory().create("User", loginCredentials);
|
||||
cy.factory().create("User", {
|
||||
...termsAndConditionsAgreedVersion,
|
||||
...loginCredentials
|
||||
});
|
||||
});
|
||||
|
||||
When("I fill the password form with:", table => {
|
||||
@ -259,7 +309,9 @@ When("submit the form", () => {
|
||||
|
||||
Then("I cannot login anymore with password {string}", password => {
|
||||
cy.reload();
|
||||
const { email } = loginCredentials;
|
||||
const {
|
||||
email
|
||||
} = loginCredentials;
|
||||
cy.visit(`/login`);
|
||||
cy.get("input[name=email]")
|
||||
.trigger("focus")
|
||||
@ -280,14 +332,22 @@ Then("I can login successfully with password {string}", password => {
|
||||
cy.reload();
|
||||
cy.login({
|
||||
...loginCredentials,
|
||||
...{ password }
|
||||
...{
|
||||
password
|
||||
}
|
||||
});
|
||||
cy.get(".iziToast-wrapper").should("contain", "You are logged in!");
|
||||
});
|
||||
|
||||
When("I log in with the following credentials:", table => {
|
||||
const { email, password } = table.hashes()[0];
|
||||
cy.login({ email, password });
|
||||
const {
|
||||
email,
|
||||
password
|
||||
} = table.hashes()[0];
|
||||
cy.login({
|
||||
email,
|
||||
password
|
||||
});
|
||||
});
|
||||
|
||||
When("open the notification menu and click on the first item", () => {
|
||||
@ -337,12 +397,14 @@ Then("there are no notifications in the top menu", () => {
|
||||
Given("there is an annoying user called {string}", name => {
|
||||
const annoyingParams = {
|
||||
email: "spammy-spammer@example.org",
|
||||
password: "1234"
|
||||
password: "1234",
|
||||
...termsAndConditionsAgreedVersion
|
||||
};
|
||||
cy.factory().create("User", {
|
||||
...annoyingParams,
|
||||
id: "annoying-user",
|
||||
name
|
||||
name,
|
||||
...termsAndConditionsAgreedVersion,
|
||||
});
|
||||
});
|
||||
|
||||
@ -364,7 +426,9 @@ When(
|
||||
cy.get(".user-content-menu .content-menu-trigger").click();
|
||||
cy.get(".popover .ds-menu-item-link")
|
||||
.contains(button)
|
||||
.click({ force: true });
|
||||
.click({
|
||||
force: true
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@ -379,10 +443,14 @@ When("I navigate to my {string} settings page", settingsPage => {
|
||||
|
||||
Given("I follow the user {string}", name => {
|
||||
cy.neode()
|
||||
.first("User", { name })
|
||||
.first("User", {
|
||||
name
|
||||
})
|
||||
.then(followed => {
|
||||
cy.neode()
|
||||
.first("User", { name: narratorParams.name })
|
||||
.first("User", {
|
||||
name: narratorParams.name
|
||||
})
|
||||
.relateTo(followed, "following");
|
||||
});
|
||||
});
|
||||
@ -390,7 +458,11 @@ Given("I follow the user {string}", name => {
|
||||
Given('"Spammy Spammer" wrote a post {string}', title => {
|
||||
cy.createCategories("cat21")
|
||||
.factory()
|
||||
.create("Post", { authorId: 'annoying-user', title, categoryIds: ["cat21"] });
|
||||
.create("Post", {
|
||||
authorId: 'annoying-user',
|
||||
title,
|
||||
categoryIds: ["cat21"]
|
||||
});
|
||||
});
|
||||
|
||||
Then("the list of posts of this user is empty", () => {
|
||||
@ -409,23 +481,37 @@ Then("nobody is following the user profile anymore", () => {
|
||||
Given("I wrote a post {string}", title => {
|
||||
cy.createCategories(`cat213`, title)
|
||||
.factory()
|
||||
.create("Post", { authorId: narratorParams.id, title, categoryIds: ["cat213"] });
|
||||
.create("Post", {
|
||||
authorId: narratorParams.id,
|
||||
title,
|
||||
categoryIds: ["cat213"]
|
||||
});
|
||||
});
|
||||
|
||||
When("I block the user {string}", name => {
|
||||
cy.neode()
|
||||
.first("User", { name })
|
||||
.first("User", {
|
||||
name
|
||||
})
|
||||
.then(blocked => {
|
||||
cy.neode()
|
||||
.first("User", { name: narratorParams.name })
|
||||
.first("User", {
|
||||
name: narratorParams.name
|
||||
})
|
||||
.relateTo(blocked, "blocked");
|
||||
});
|
||||
});
|
||||
|
||||
When("I log in with:", table => {
|
||||
const [firstRow] = table.hashes();
|
||||
const { Email, Password } = firstRow;
|
||||
cy.login({ email: Email, password: Password });
|
||||
const {
|
||||
Email,
|
||||
Password
|
||||
} = firstRow;
|
||||
cy.login({
|
||||
email: Email,
|
||||
password: Password
|
||||
});
|
||||
});
|
||||
|
||||
Then("I see only one post with the title {string}", title => {
|
||||
@ -433,4 +519,4 @@ Then("I see only one post with the title {string}", title => {
|
||||
.find(".post-link")
|
||||
.should("have.length", 1);
|
||||
cy.get(".main-container").contains(".post-link", title);
|
||||
});
|
||||
});
|
||||
@ -77,6 +77,7 @@ describe('CreateUserAccount', () => {
|
||||
email: 'sixseven@example.org',
|
||||
nonce: '666777',
|
||||
password: 'hellopassword',
|
||||
termsAndConditionsAgreedVersion: '0.0.2',
|
||||
},
|
||||
})
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
|
||||
|
||||
@ -55,7 +55,10 @@
|
||||
v-model="termsAndConditionsConfirmed"
|
||||
:checked="termsAndConditionsConfirmed"
|
||||
/>
|
||||
<label for="checkbox" v-html="$t('site.termsAndConditionsConfirmed')"></label>
|
||||
<label
|
||||
for="checkbox"
|
||||
v-html="$t('termsAndConditions.termsAndConditionsConfirmed')"
|
||||
></label>
|
||||
</ds-text>
|
||||
|
||||
<template slot="footer">
|
||||
@ -84,9 +87,24 @@ import gql from 'graphql-tag'
|
||||
import PasswordStrength from '../Password/Strength'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||
import { VERSION } from '~/constants/terms-and-conditions-version.js'
|
||||
|
||||
/* TODO: hier muss die version rein */
|
||||
export const SignupVerificationMutation = gql`
|
||||
mutation($nonce: String!, $name: String!, $email: String!, $password: String!) {
|
||||
SignupVerification(nonce: $nonce, email: $email, name: $name, password: $password) {
|
||||
mutation(
|
||||
$nonce: String!
|
||||
$name: String!
|
||||
$email: String!
|
||||
$password: String!
|
||||
$termsAndConditionsAgreedVersion: String!
|
||||
) {
|
||||
SignupVerification(
|
||||
nonce: $nonce
|
||||
email: $email
|
||||
name: $name
|
||||
password: $password
|
||||
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
@ -135,10 +153,11 @@ export default {
|
||||
async submit() {
|
||||
const { name, password, about } = this.formData
|
||||
const { email, nonce } = this
|
||||
const termsAndConditionsAgreedVersion = VERSION
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: SignupVerificationMutation,
|
||||
variables: { name, password, about, email, nonce },
|
||||
variables: { name, password, about, email, nonce, termsAndConditionsAgreedVersion },
|
||||
})
|
||||
this.success = true
|
||||
setTimeout(() => {
|
||||
|
||||
1
webapp/constants/terms-and-conditions-version.js
Normal file
1
webapp/constants/terms-and-conditions-version.js
Normal file
@ -0,0 +1 @@
|
||||
export const VERSION = '0.0.2'
|
||||
@ -224,7 +224,7 @@ export default {
|
||||
},
|
||||
showFilterPostsDropdown() {
|
||||
const [firstRoute] = this.$route.matched
|
||||
return firstRoute.name === 'index'
|
||||
return firstRoute && firstRoute.name === 'index'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
}
|
||||
},
|
||||
"site": {
|
||||
"thanks": "Danke!",
|
||||
"made": "Mit ❤ gemacht",
|
||||
"imprint": "Impressum",
|
||||
"data-privacy": "Datenschutz",
|
||||
@ -34,8 +35,7 @@
|
||||
"responsible": "Verantwortlicher gemäß § 55 Abs. 2 RStV ",
|
||||
"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."
|
||||
"code-of-conduct": "Verhaltenscodex"
|
||||
},
|
||||
"sorting": {
|
||||
"newest": "Neuste",
|
||||
@ -575,6 +575,11 @@
|
||||
"get-help": "Wenn du einem inakzeptablen Verhalten ausgesetzt bist, es miterlebst oder andere Bedenken hast, benachrichtige bitte so schnell wie möglich einen Organisator der Gemeinschaft und verlinke oder verweise auf den entsprechenden Inhalt:"
|
||||
},
|
||||
"termsAndConditions": {
|
||||
"termsAndConditionsConfirmed": "Ich habe die <a href=\"/terms-and-conditions\" target=\"_blank\">Nutzungsbedingungen</a> durchgelesen und stimme ihnen zu.",
|
||||
"newTermsAndConditions": "Neue Nutzungsbedingungen",
|
||||
"termsAndConditionsNewConfirmText": "Bitte lies dir die neue Nutzungsbedingungen jetzt durch!",
|
||||
"termsAndConditionsNewConfirm": "Ich habe die neuen Nutzungsbedingungen durchgelesen und stimme zu.",
|
||||
"agree": "Ich stimme zu!",
|
||||
"risk": {
|
||||
"title": "Unfallgefahr",
|
||||
"description": "Das ist eine Testversion! Alle Daten, Dein Profil und die Server können jederzeit komplett vernichtet, verloren, verbrannt und vielleicht auch in der Nähe von Alpha Centauri synchronisiert werden. Die Benutzung läuft auf eigene Gefahr. Mit kommerziellen Nebenwirkungen ist jedoch nicht zu rechnen."
|
||||
@ -610,4 +615,4 @@
|
||||
"have-fun": "Jetzt aber viel Spaß mit der Alpha von Human Connection! Für den ersten Weltfrieden. ♥︎",
|
||||
"closing": "Herzlichst <br><br> Euer Human Connection Team"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@
|
||||
}
|
||||
},
|
||||
"site": {
|
||||
"thanks": "Thanks!",
|
||||
"made": "Made with ❤",
|
||||
"imprint": "Imprint",
|
||||
"termsAndConditions": "Terms and conditions",
|
||||
@ -34,8 +35,7 @@
|
||||
"responsible": "responsible for contents of this page (§ 55 Abs. 2 RStV)",
|
||||
"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>."
|
||||
"code-of-conduct": "Code of Conduct"
|
||||
},
|
||||
"sorting": {
|
||||
"newest": "Newest",
|
||||
@ -575,6 +575,11 @@
|
||||
"get-help": "If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible and link or refer to the corresponding content:"
|
||||
},
|
||||
"termsAndConditions": {
|
||||
"newTermsAndConditions": "New Terms and Conditions",
|
||||
"termsAndConditionsConfirmed": "I have read and confirmed the <a href=\"/terms-and-conditions\" target=\"_blank\">Terms and Conditions</a>.",
|
||||
"termsAndConditionsNewConfirmText": "Please read the new terms of use now!",
|
||||
"termsAndConditionsNewConfirm": "I have read and agree to the new terms of conditions.",
|
||||
"agree": "I agree!",
|
||||
"risk": {
|
||||
"title": "Risk of accident",
|
||||
"description": "This is a test version! All data, your profile and the server can be completely destroyed, wiped out, lost, burnt and eventually synchronised near Alpha Centauri at any time. Use on your own risk. Commercial effects are not likely though."
|
||||
@ -610,4 +615,4 @@
|
||||
"have-fun": "Now have fun with the alpha version of Human Connection! For the first universal peace. ♥︎",
|
||||
"closing": "Thank you very much <br> <br> your Human Connection Team"
|
||||
}
|
||||
}
|
||||
}
|
||||
19
webapp/middleware/termsAndConditions.js
Normal file
19
webapp/middleware/termsAndConditions.js
Normal file
@ -0,0 +1,19 @@
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
|
||||
export default async ({ store, env, route, redirect }) => {
|
||||
let publicPages = env.publicPages
|
||||
// only affect non public pages
|
||||
if (publicPages.indexOf(route.name) >= 0) {
|
||||
return true
|
||||
}
|
||||
if (route.name === 'terms-and-conditions-confirm') return true // avoid endless loop
|
||||
|
||||
if (store.getters['auth/termsAndConditionsAgreed']) return true
|
||||
|
||||
let params = {}
|
||||
if (!isEmpty(route.path) && route.path !== '/') {
|
||||
params.path = route.path
|
||||
}
|
||||
|
||||
return redirect('/terms-and-conditions-confirm', params)
|
||||
}
|
||||
@ -122,7 +122,7 @@ module.exports = {
|
||||
],
|
||||
|
||||
router: {
|
||||
middleware: ['authenticated'],
|
||||
middleware: ['authenticated', 'termsAndConditions'],
|
||||
linkActiveClass: 'router-link-active',
|
||||
linkExactActiveClass: 'router-link-exact-active',
|
||||
scrollBehavior: (to, _from, savedPosition) => {
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
|
||||
<script>
|
||||
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||||
import { VERSION } from '~/constants/terms-and-conditions-version.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -96,7 +97,7 @@ export default {
|
||||
},
|
||||
},
|
||||
asyncData({ store, redirect }) {
|
||||
if (store.getters['auth/isLoggedIn']) {
|
||||
if (store.getters['auth/user'].termsAndConditionsAgreedVersion === VERSION) {
|
||||
redirect('/')
|
||||
}
|
||||
},
|
||||
|
||||
98
webapp/pages/terms-and-conditions-confirm.vue
Normal file
98
webapp/pages/terms-and-conditions-confirm.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<ds-container width="medium">
|
||||
<ds-card icon="balance-scale" :header="$t(`termsAndConditions.newTermsAndConditions`)" centered>
|
||||
<p>
|
||||
<ds-button>
|
||||
<nuxt-link class="post-link" :to="{ name: 'terms-and-conditions' }" target="_blank">
|
||||
{{ $t(`termsAndConditions.termsAndConditionsNewConfirmText`) }}
|
||||
</nuxt-link>
|
||||
</ds-button>
|
||||
</p>
|
||||
<ds-text>
|
||||
<input id="checkbox" type="checkbox" v-model="checked" :checked="checked" />
|
||||
<label
|
||||
for="checkbox"
|
||||
v-html="$t('termsAndConditions.termsAndConditionsNewConfirm')"
|
||||
></label>
|
||||
</ds-text>
|
||||
|
||||
<template slot="footer">
|
||||
<ds-button primary @click="submit" :disabled="!checked">{{ $t(`actions.save`) }}</ds-button>
|
||||
</template>
|
||||
</ds-card>
|
||||
</ds-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { VERSION } from '~/constants/terms-and-conditions-version.js'
|
||||
const mutation = gql`
|
||||
mutation($id: ID!, $termsAndConditionsAgreedVersion: String) {
|
||||
UpdateUser(id: $id, termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion) {
|
||||
id
|
||||
termsAndConditionsAgreedVersion
|
||||
}
|
||||
}
|
||||
`
|
||||
export default {
|
||||
layout: 'default',
|
||||
head() {
|
||||
return {
|
||||
title: this.$t('termsAndConditions.newTermsAndConditions'),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checked: false,
|
||||
sections: [
|
||||
'risk',
|
||||
'data-privacy',
|
||||
'work-in-progress',
|
||||
'code-of-conduct',
|
||||
'moderation',
|
||||
'fairness',
|
||||
'questions',
|
||||
'human-connection',
|
||||
],
|
||||
}
|
||||
},
|
||||
asyncData({ store, redirect }) {
|
||||
if (store.getters['auth/termsAndConditionsAgreed']) {
|
||||
redirect('/')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setCurrentUser: 'auth/SET_USER',
|
||||
}),
|
||||
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('site.thanks'))
|
||||
this.$router.replace(this.$route.query.path || '/')
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -1,4 +1,5 @@
|
||||
import gql from 'graphql-tag'
|
||||
import { VERSION } from '~/constants/terms-and-conditions-version.js'
|
||||
|
||||
export const state = () => {
|
||||
return {
|
||||
@ -42,6 +43,9 @@ export const getters = {
|
||||
token(state) {
|
||||
return state.token
|
||||
},
|
||||
termsAndConditionsAgreed(state) {
|
||||
return state.user && state.user.termsAndConditionsAgreedVersion === VERSION
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
@ -82,6 +86,7 @@ export const actions = {
|
||||
locationName
|
||||
contributionsCount
|
||||
commentedCount
|
||||
termsAndConditionsAgreedVersion
|
||||
socialMedia {
|
||||
id
|
||||
url
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user