mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-04-27 00:08:45 +00:00
Merge branch 'master' of https://github.com/Ocelot-Social-Community/Ocelot-Social into 4092-redesign-registration-process
This commit is contained in:
commit
e3d3f988ce
9
.github/ISSUE_TEMPLATE/bug_report.md
vendored
9
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -8,7 +8,6 @@ title: 🐛 [Bug]
|
|||||||
## :bug: Bugreport
|
## :bug: Bugreport
|
||||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the bug is.-->
|
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the bug is.-->
|
||||||
|
|
||||||
|
|
||||||
### Steps to reproduce the behavior
|
### Steps to reproduce the behavior
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
@ -16,17 +15,11 @@ title: 🐛 [Bug]
|
|||||||
4. ...
|
4. ...
|
||||||
5. Profit
|
5. Profit
|
||||||
|
|
||||||
|
|
||||||
### Expected behavior
|
### Expected behavior
|
||||||
<!-- A clear and concise description of what you expected to happen. -->
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
|
||||||
### Version & Environment
|
### Version & Environment
|
||||||
Type: [] <!-- [Desktop|Smartphone] -->
|
<!-- Add context about your environment and used version here. -->
|
||||||
- OS: [] <!-- [e.g. iOS8.1 or Windows] -->
|
|
||||||
- Browser: [] <!-- [e.g. stock browser, safari, chrome] -->
|
|
||||||
- Version [] <!-- [e.g. 22] -->
|
|
||||||
- Device: [] <!-- [e.g. iPhone6] -->
|
|
||||||
|
|
||||||
### Additional context
|
### Additional context
|
||||||
<!-- Add any other context about the problem here. -->
|
<!-- Add any other context about the problem here. -->
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
2
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
@ -5,7 +5,7 @@ labels: devops
|
|||||||
title: 💥 [DevOps]
|
title: 💥 [DevOps]
|
||||||
---
|
---
|
||||||
|
|
||||||
## :fire: DevOps ticket
|
## 💥 DevOps ticket
|
||||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the problem is.-->
|
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the problem is.-->
|
||||||
|
|
||||||
### Motive
|
### Motive
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/refactor_tickets.md
vendored
1
.github/ISSUE_TEMPLATE/refactor_tickets.md
vendored
@ -10,6 +10,7 @@ title: 🔧 [Refactor]
|
|||||||
|
|
||||||
### Motive
|
### Motive
|
||||||
<!-- What is the purpose of this refactoring? If it's removing depcrecated code, please link to the deprecation notice. -->
|
<!-- What is the purpose of this refactoring? If it's removing depcrecated code, please link to the deprecation notice. -->
|
||||||
|
|
||||||
### Related issues
|
### Related issues
|
||||||
<!-- Are there any related issues to link to? Please paste them below for reference. -->
|
<!-- Are there any related issues to link to? Please paste them below for reference. -->
|
||||||
|
|
||||||
|
|||||||
2
.github/semantic.yml
vendored
2
.github/semantic.yml
vendored
@ -1,2 +0,0 @@
|
|||||||
# Always validate the PR title, and ignore the commits
|
|
||||||
titleOnly: true
|
|
||||||
18
.github/stale-disabled.yml
vendored
18
.github/stale-disabled.yml
vendored
@ -1,18 +0,0 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
|
||||||
daysUntilStale: 60
|
|
||||||
# Number of days of inactivity before a stale issue is closed
|
|
||||||
daysUntilClose: 30
|
|
||||||
# Issues with these labels will never be considered stale
|
|
||||||
exemptLabels:
|
|
||||||
- pinned
|
|
||||||
- security
|
|
||||||
- bounty
|
|
||||||
# Label to use when marking an issue as stale
|
|
||||||
staleLabel: stale
|
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
||||||
markComment: >
|
|
||||||
This issue has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
|
||||||
for your contributions.
|
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
||||||
closeComment: false
|
|
||||||
92
.github/workflows/ci.yml
vendored
92
.github/workflows/ci.yml
vendored
@ -1,92 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on: [push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Continuous Integration
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Check translation files
|
|
||||||
run: |
|
|
||||||
scripts/translations/sort.sh
|
|
||||||
scripts/translations/missing-keys.sh
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# NEO4J ##################################################################
|
|
||||||
##########################################################################
|
|
||||||
- name: Neo4J | Build `community` image
|
|
||||||
uses: docker/build-push-action@v1.1.0
|
|
||||||
with:
|
|
||||||
repository: ocelotsocialnetwork/neo4j
|
|
||||||
tags: latest
|
|
||||||
path: neo4j/
|
|
||||||
push: false
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# BACKEND ################################################################
|
|
||||||
##########################################################################
|
|
||||||
# TODO: We want to push this to dockerhub
|
|
||||||
#- name: Build backend production image
|
|
||||||
# uses: docker/build-push-action@v1.1.0
|
|
||||||
# with:
|
|
||||||
# repository: ocelotsocialnetwork/backend
|
|
||||||
# tags: production
|
|
||||||
# target: production
|
|
||||||
# path: backend/
|
|
||||||
# push: false
|
|
||||||
|
|
||||||
# Build Docker Image (build)
|
|
||||||
- name: backend | Build `build` image
|
|
||||||
uses: docker/build-push-action@v1.1.0
|
|
||||||
with:
|
|
||||||
repository: ocelotsocialnetwork/backend
|
|
||||||
tags: build
|
|
||||||
target: build
|
|
||||||
path: backend/
|
|
||||||
push: false
|
|
||||||
|
|
||||||
# Lint
|
|
||||||
- name: backend | Lint
|
|
||||||
run: docker run --rm ocelotsocialnetwork/backend:build yarn run lint
|
|
||||||
|
|
||||||
# Unit Tests
|
|
||||||
#- name: backend | Unit tests
|
|
||||||
# run: |
|
|
||||||
# docker-compose up
|
|
||||||
# docker-compose exec backend yarn test
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
# WEBAPP #################################################################
|
|
||||||
##########################################################################
|
|
||||||
# TODO: We want to push this to dockerhub
|
|
||||||
#- name: Build webapp production image
|
|
||||||
# uses: docker/build-push-action@v1.1.0
|
|
||||||
# with:
|
|
||||||
# repository: ocelotsocialnetwork/webapp
|
|
||||||
# tags: production
|
|
||||||
# target: production
|
|
||||||
# path: webapp/
|
|
||||||
# push: false
|
|
||||||
|
|
||||||
# Build Docker Image (build)
|
|
||||||
- name: webapp | Build `build` image
|
|
||||||
uses: docker/build-push-action@v1.1.0
|
|
||||||
with:
|
|
||||||
repository: ocelotsocialnetwork/webapp
|
|
||||||
tags: build
|
|
||||||
target: build
|
|
||||||
path: webapp/
|
|
||||||
push: false
|
|
||||||
|
|
||||||
# Lint
|
|
||||||
- name: webapp | Lint
|
|
||||||
run: docker run --rm ocelotsocialnetwork/webapp:build yarn run lint
|
|
||||||
|
|
||||||
# Unit Tests
|
|
||||||
- name: webapp | Unit tests
|
|
||||||
run: docker run --rm ocelotsocialnetwork/webapp:build yarn run test
|
|
||||||
|
|
||||||
244
.github/workflows/test.yml
vendored
Normal file
244
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
name: ocelot.social test CI
|
||||||
|
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
##############################################################################
|
||||||
|
# JOB: PREPARE #####################################################
|
||||||
|
##############################################################################
|
||||||
|
prepare:
|
||||||
|
name: Prepare
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# needs: [nothing]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# TODO: DO STUFF ??? #####################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Check translation files
|
||||||
|
run: |
|
||||||
|
scripts/translations/sort.sh
|
||||||
|
scripts/translations/missing-keys.sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: DOCKER BUILD TEST NEO4J ###############################################
|
||||||
|
##############################################################################
|
||||||
|
build_test_neo4j:
|
||||||
|
name: Docker Build Test - Neo4J
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [prepare]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# NEO4J ##################################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Neo4J | Build `community` image
|
||||||
|
run: |
|
||||||
|
docker build --target community -t "ocelotsocialnetwork/neo4j:community" neo4j/
|
||||||
|
docker save "ocelotsocialnetwork/neo4j:community" > /tmp/neo4j.tar
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-neo4j-image
|
||||||
|
path: /tmp/neo4j.tar
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: DOCKER BUILD TEST BACKEND #############################################
|
||||||
|
##############################################################################
|
||||||
|
build_test_backend:
|
||||||
|
name: Docker Build Test - Backend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [prepare]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# BUILD BACKEND DOCKER IMAGE (build) #####################################
|
||||||
|
##########################################################################
|
||||||
|
- name: backend | Build `test` image
|
||||||
|
run: |
|
||||||
|
docker build --target test -t "ocelotsocialnetwork/backend:test" backend/
|
||||||
|
docker save "ocelotsocialnetwork/backend:test" > /tmp/backend.tar
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-backend-test
|
||||||
|
path: /tmp/backend.tar
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: DOCKER BUILD TEST WEBAPP ##############################################
|
||||||
|
##############################################################################
|
||||||
|
build_test_webapp:
|
||||||
|
name: Docker Build Test - WebApp
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [prepare]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# BUILD WEBAPP DOCKER IMAGE (build) ######################################
|
||||||
|
##########################################################################
|
||||||
|
- name: webapp | Build `test` image
|
||||||
|
run: |
|
||||||
|
docker build --target test -t "ocelotsocialnetwork/webapp:test" webapp/
|
||||||
|
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-webapp-test
|
||||||
|
path: /tmp/webapp.tar
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: LINT BACKEND ##########################################################
|
||||||
|
##############################################################################
|
||||||
|
lint_backend:
|
||||||
|
name: Lint backend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build_test_backend]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Download Docker Image (Backend)
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-backend-test
|
||||||
|
path: /tmp
|
||||||
|
- name: Load Docker Image
|
||||||
|
run: docker load < /tmp/backend.tar
|
||||||
|
##########################################################################
|
||||||
|
# LINT BACKEND ###########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: backend | Lint
|
||||||
|
run: docker run --rm ocelotsocialnetwork/backend:test yarn run lint
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: LINT WEBAPP ###########################################################
|
||||||
|
##############################################################################
|
||||||
|
lint_webapp:
|
||||||
|
name: Lint webapp
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build_test_webapp]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# DOWNLOAD DOCKER IMAGE ##################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Download Docker Image (Webapp)
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-webapp-test
|
||||||
|
path: /tmp
|
||||||
|
- name: Load Docker Image
|
||||||
|
run: docker load < /tmp/webapp.tar
|
||||||
|
##########################################################################
|
||||||
|
# LINT WEBAPP ############################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: webapp | Lint
|
||||||
|
run: docker run --rm ocelotsocialnetwork/webapp:test yarn run lint
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: UNIT TEST BACKEND #####################################################
|
||||||
|
##############################################################################
|
||||||
|
unit_test_backend:
|
||||||
|
name: Unit tests - backend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build_test_neo4j,build_test_backend]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# DOWNLOAD DOCKER IMAGES #################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Download Docker Image (Neo4J)
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-neo4j-image
|
||||||
|
path: /tmp
|
||||||
|
- name: Load Docker Image
|
||||||
|
run: docker load < /tmp/neo4j.tar
|
||||||
|
- name: Download Docker Image (Backend)
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-backend-test
|
||||||
|
path: /tmp
|
||||||
|
- name: Load Docker Image
|
||||||
|
run: docker load < /tmp/backend.tar
|
||||||
|
##########################################################################
|
||||||
|
# UNIT TESTS BACKEND #####################################################
|
||||||
|
##########################################################################
|
||||||
|
# TODO: Why do we need those .envs?
|
||||||
|
- name: backend | copy env files webapp
|
||||||
|
run: cp webapp/.env.template webapp/.env
|
||||||
|
- name: backend | copy env files backend
|
||||||
|
run: cp backend/.env.template backend/.env
|
||||||
|
- name: backend | docker-compose
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps neo4j backend
|
||||||
|
- name: backend | Initialize Database
|
||||||
|
run: docker-compose exec -T backend yarn db:migrate init
|
||||||
|
- name: backend | Unit test
|
||||||
|
run: docker-compose exec -T backend yarn test
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# JOB: UNIT TEST WEBAPP ######################################################
|
||||||
|
##############################################################################
|
||||||
|
unit_test_webapp:
|
||||||
|
name: Unit tests - webapp
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [build_test_webapp]
|
||||||
|
steps:
|
||||||
|
##########################################################################
|
||||||
|
# CHECKOUT CODE ##########################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
##########################################################################
|
||||||
|
# DOWNLOAD DOCKER IMAGES #################################################
|
||||||
|
##########################################################################
|
||||||
|
- name: Download Docker Image (Webapp)
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: docker-webapp-test
|
||||||
|
path: /tmp
|
||||||
|
- name: Load Docker Image
|
||||||
|
run: docker load < /tmp/webapp.tar
|
||||||
|
##########################################################################
|
||||||
|
# UNIT TESTS WEBAPP #####################################################
|
||||||
|
##########################################################################
|
||||||
|
# TODO: Why do we need those .envs?
|
||||||
|
- name: backend | copy env files webapp
|
||||||
|
run: cp webapp/.env.template webapp/.env
|
||||||
|
- name: backend | copy env files backend
|
||||||
|
run: cp backend/.env.template backend/.env
|
||||||
|
- name: backend | docker-compose
|
||||||
|
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp
|
||||||
|
- name: webapp | Unit tests
|
||||||
|
#run: docker run --rm ocelotsocialnetwork/webapp:build yarn run test
|
||||||
|
run: docker-compose exec -T webapp yarn test
|
||||||
@ -68,6 +68,14 @@ RUN yarn install --production=false --frozen-lockfile --non-interactive
|
|||||||
# yarn build
|
# yarn build
|
||||||
RUN yarn run build
|
RUN yarn run build
|
||||||
|
|
||||||
|
##################################################################################
|
||||||
|
# TEST ###########################################################################
|
||||||
|
##################################################################################
|
||||||
|
FROM build as test
|
||||||
|
|
||||||
|
# Run command
|
||||||
|
CMD /bin/sh -c "yarn run dev"
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) #
|
# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) #
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|||||||
@ -121,6 +121,7 @@ export default shield(
|
|||||||
userData: isAuthenticated,
|
userData: isAuthenticated,
|
||||||
MyInviteCodes: isAuthenticated,
|
MyInviteCodes: isAuthenticated,
|
||||||
isValidInviteCode: allow,
|
isValidInviteCode: allow,
|
||||||
|
queryLocations: isAuthenticated,
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
'*': deny,
|
'*': deny,
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
import { UserInputError } from 'apollo-server'
|
||||||
import Resolver from './helpers/Resolver'
|
import Resolver from './helpers/Resolver'
|
||||||
|
import { queryLocations } from './users/location'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Location: {
|
Location: {
|
||||||
@ -16,4 +18,13 @@ export default {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
Query: {
|
||||||
|
queryLocations: async (object, args, context, resolveInfo) => {
|
||||||
|
try {
|
||||||
|
return queryLocations(args)
|
||||||
|
} catch (e) {
|
||||||
|
throw new UserInputError(e.message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,4 +137,15 @@ const createOrUpdateLocations = async (userId, locationName, session) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const queryLocations = async ({ place, lang }) => {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${CONFIG.MAPBOX_TOKEN}&types=region,place,country&language=${lang}`,
|
||||||
|
)
|
||||||
|
// Return empty array if no location found or error occurred
|
||||||
|
if (!res || !res.features) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return res.features
|
||||||
|
}
|
||||||
|
|
||||||
export default createOrUpdateLocations
|
export default createOrUpdateLocations
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import createServer from '../../../server'
|
|||||||
|
|
||||||
const neode = getNeode()
|
const neode = getNeode()
|
||||||
const driver = getDriver()
|
const driver = getDriver()
|
||||||
let authenticatedUser, mutate, variables
|
let authenticatedUser, mutate, query, variables
|
||||||
|
|
||||||
const updateUserMutation = gql`
|
const updateUserMutation = gql`
|
||||||
mutation($id: ID!, $name: String!, $locationName: String) {
|
mutation($id: ID!, $name: String!, $locationName: String) {
|
||||||
@ -16,6 +16,15 @@ const updateUserMutation = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const queryLocations = gql`
|
||||||
|
query($place: String!, $lang: String!) {
|
||||||
|
queryLocations(place: $place, lang: $lang) {
|
||||||
|
place_name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const newlyCreatedNodesWithLocales = [
|
const newlyCreatedNodesWithLocales = [
|
||||||
{
|
{
|
||||||
city: {
|
city: {
|
||||||
@ -76,6 +85,7 @@ beforeAll(() => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
mutate = createTestClient(server).mutate
|
mutate = createTestClient(server).mutate
|
||||||
|
query = createTestClient(server).query
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -85,6 +95,66 @@ beforeEach(() => {
|
|||||||
|
|
||||||
afterEach(cleanDatabase)
|
afterEach(cleanDatabase)
|
||||||
|
|
||||||
|
describe('Location Service', () => {
|
||||||
|
// Authentication
|
||||||
|
// TODO: unify, externalize, simplify, wtf?
|
||||||
|
let user
|
||||||
|
beforeEach(async () => {
|
||||||
|
user = await Factory.build('user', {
|
||||||
|
id: 'location-user',
|
||||||
|
})
|
||||||
|
authenticatedUser = await user.toJson()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('query Location existing', async () => {
|
||||||
|
variables = {
|
||||||
|
place: 'Berlin',
|
||||||
|
lang: 'en',
|
||||||
|
}
|
||||||
|
const result = await query({ query: queryLocations, variables })
|
||||||
|
expect(result.data.queryLocations).toEqual([
|
||||||
|
{ id: 'place.14094307404564380', place_name: 'Berlin, Germany' },
|
||||||
|
{ id: 'place.15095411613564380', place_name: 'Berlin, Maryland, United States' },
|
||||||
|
{ id: 'place.5225018734564380', place_name: 'Berlin, Connecticut, United States' },
|
||||||
|
{ id: 'place.16922023226564380', place_name: 'Berlin, New Jersey, United States' },
|
||||||
|
{ id: 'place.4035845612564380', place_name: 'Berlin Township, New Jersey, United States' },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('query Location existing in different language', async () => {
|
||||||
|
variables = {
|
||||||
|
place: 'Berlin',
|
||||||
|
lang: 'de',
|
||||||
|
}
|
||||||
|
const result = await query({ query: queryLocations, variables })
|
||||||
|
expect(result.data.queryLocations).toEqual([
|
||||||
|
{ id: 'place.14094307404564380', place_name: 'Berlin, Deutschland' },
|
||||||
|
{ id: 'place.15095411613564380', place_name: 'Berlin, Maryland, Vereinigte Staaten' },
|
||||||
|
{ id: 'place.16922023226564380', place_name: 'Berlin, New Jersey, Vereinigte Staaten' },
|
||||||
|
{ id: 'place.10735893248465990', place_name: 'Berlin Heights, Ohio, Vereinigte Staaten' },
|
||||||
|
{ id: 'place.1165756679564380', place_name: 'Berlin, Massachusetts, Vereinigte Staaten' },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('query Location not existing', async () => {
|
||||||
|
variables = {
|
||||||
|
place: 'GbHtsd4sdHa',
|
||||||
|
lang: 'en',
|
||||||
|
}
|
||||||
|
const result = await query({ query: queryLocations, variables })
|
||||||
|
expect(result.data.queryLocations).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('query Location without a place name given', async () => {
|
||||||
|
variables = {
|
||||||
|
place: '',
|
||||||
|
lang: 'en',
|
||||||
|
}
|
||||||
|
const result = await query({ query: queryLocations, variables })
|
||||||
|
expect(result.data.queryLocations).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('userMiddleware', () => {
|
describe('userMiddleware', () => {
|
||||||
describe('UpdateUser', () => {
|
describe('UpdateUser', () => {
|
||||||
let user
|
let user
|
||||||
@ -95,7 +165,7 @@ describe('userMiddleware', () => {
|
|||||||
authenticatedUser = await user.toJson()
|
authenticatedUser = await user.toJson()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('creates a Location node with localised city/state/country names', async () => {
|
it('creates a Location node with localized city/state/country names', async () => {
|
||||||
variables = {
|
variables = {
|
||||||
...variables,
|
...variables,
|
||||||
id: 'updating-user',
|
id: 'updating-user',
|
||||||
|
|||||||
@ -16,3 +16,13 @@ type Location {
|
|||||||
parent: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
parent: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This is not smart - we need one location for everything - use the same type everywhere!
|
||||||
|
type LocationMapBox {
|
||||||
|
id: ID!
|
||||||
|
place_name: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query {
|
||||||
|
queryLocations(place: String!, lang: String!): [LocationMapBox]!
|
||||||
|
}
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- NODE_ENV="development"
|
- NODE_ENV="development"
|
||||||
# - DEBUG=true
|
# - DEBUG=true
|
||||||
# - NUXT_BUILD=/tmp/nuxt # avoid file permission issues when `rm -rf .nuxt/`
|
- NUXT_BUILD=/tmp/nuxt # avoid file permission issues when `rm -rf .nuxt/`
|
||||||
volumes:
|
volumes:
|
||||||
# This makes sure the docker container has its own node modules.
|
# This makes sure the docker container has its own node modules.
|
||||||
# Therefore it is possible to have a different node version on the host machine
|
# Therefore it is possible to have a different node version on the host machine
|
||||||
|
|||||||
47
docker-compose.test.yml
Normal file
47
docker-compose.test.yml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
version: "3.4"
|
||||||
|
|
||||||
|
services:
|
||||||
|
########################################################
|
||||||
|
# WEBAPP ###############################################
|
||||||
|
########################################################
|
||||||
|
webapp:
|
||||||
|
image: ocelotsocialnetwork/webapp:test
|
||||||
|
build:
|
||||||
|
target: test
|
||||||
|
environment:
|
||||||
|
- NODE_ENV="test"
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# BACKEND ##############################################
|
||||||
|
########################################################
|
||||||
|
backend:
|
||||||
|
image: ocelotsocialnetwork/backend:test
|
||||||
|
build:
|
||||||
|
target: test
|
||||||
|
environment:
|
||||||
|
- NODE_ENV="test"
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# NEO4J ################################################
|
||||||
|
########################################################
|
||||||
|
neo4j:
|
||||||
|
image: ocelotsocialnetwork/neo4j:community
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# MAINTENANCE ##########################################
|
||||||
|
########################################################
|
||||||
|
maintenance:
|
||||||
|
image: ocelotsocialnetwork/maintenance:test
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# MAILSERVER TO FAKE SMTP ##############################
|
||||||
|
########################################################
|
||||||
|
mailserver:
|
||||||
|
image: djfarrelly/maildev
|
||||||
|
ports:
|
||||||
|
- 1080:80
|
||||||
|
networks:
|
||||||
|
- external-net
|
||||||
|
volumes:
|
||||||
|
webapp_node_modules:
|
||||||
|
backend_node_modules:
|
||||||
@ -1,4 +1,3 @@
|
|||||||
MAPBOX_TOKEN="pk.eyJ1IjoiYnVzZmFrdG9yIiwiYSI6ImNraDNiM3JxcDBhaWQydG1uczhpZWtpOW4ifQ.7TNRTO-o9aK1Y6MyW_Nd4g"
|
|
||||||
SENTRY_DSN_WEBAPP=
|
SENTRY_DSN_WEBAPP=
|
||||||
COMMIT=
|
COMMIT=
|
||||||
PUBLIC_REGISTRATION=false
|
PUBLIC_REGISTRATION=false
|
||||||
|
|||||||
@ -68,6 +68,14 @@ RUN yarn install --production=false --frozen-lockfile --non-interactive
|
|||||||
# yarn build
|
# yarn build
|
||||||
RUN yarn run build
|
RUN yarn run build
|
||||||
|
|
||||||
|
##################################################################################
|
||||||
|
# TEST ###########################################################################
|
||||||
|
##################################################################################
|
||||||
|
FROM build as test
|
||||||
|
|
||||||
|
# Run command
|
||||||
|
CMD /bin/sh -c "yarn run dev"
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) #
|
# PRODUCTION (Does contain only "binary"- and static-files to reduce image size) #
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|||||||
@ -14,9 +14,6 @@
|
|||||||
<div class="filter-menu-options">
|
<div class="filter-menu-options">
|
||||||
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||||
<following-filter />
|
<following-filter />
|
||||||
<categories-filter />
|
|
||||||
<emotions-filter />
|
|
||||||
<languages-filter />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
@ -26,17 +23,11 @@
|
|||||||
import Dropdown from '~/components/Dropdown'
|
import Dropdown from '~/components/Dropdown'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import FollowingFilter from './FollowingFilter'
|
import FollowingFilter from './FollowingFilter'
|
||||||
import CategoriesFilter from './CategoriesFilter'
|
|
||||||
import EmotionsFilter from './EmotionsFilter'
|
|
||||||
import LanguagesFilter from './LanguagesFilter'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
FollowingFilter,
|
FollowingFilter,
|
||||||
CategoriesFilter,
|
|
||||||
EmotionsFilter,
|
|
||||||
LanguagesFilter,
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
placement: { type: String },
|
placement: { type: String },
|
||||||
|
|||||||
@ -27,11 +27,18 @@ describe('ImageUploader.vue', () => {
|
|||||||
beforeEach(() => jest.useFakeTimers())
|
beforeEach(() => jest.useFakeTimers())
|
||||||
const message = 'File upload failed'
|
const message = 'File upload failed'
|
||||||
const fileError = { status: 'error' }
|
const fileError = { status: 'error' }
|
||||||
|
const unSupportedFileMessage =
|
||||||
|
'Please upload an image of file format : JPG , JPEG , PNG or GIF'
|
||||||
|
|
||||||
it('shows an error toaster when verror is called', () => {
|
it('shows an error toaster when verror is called', () => {
|
||||||
wrapper.vm.onDropzoneError(fileError, message)
|
wrapper.vm.onDropzoneError(fileError, message)
|
||||||
expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, message)
|
expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, message)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows an error toaster when unSupported file is uploaded', () => {
|
||||||
|
wrapper.vm.onUnSupportedFormat(fileError.status, unSupportedFileMessage)
|
||||||
|
expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, unSupportedFileMessage)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -65,6 +65,7 @@ export default {
|
|||||||
url: () => '',
|
url: () => '',
|
||||||
maxFilesize: 5.0,
|
maxFilesize: 5.0,
|
||||||
previewTemplate: '<span class="no-preview" />',
|
previewTemplate: '<span class="no-preview" />',
|
||||||
|
acceptedFiles: '.png,.jpg,.jpeg,.gif',
|
||||||
},
|
},
|
||||||
cropper: null,
|
cropper: null,
|
||||||
file: null,
|
file: null,
|
||||||
@ -76,7 +77,20 @@ export default {
|
|||||||
onDropzoneError(file, message) {
|
onDropzoneError(file, message) {
|
||||||
this.$toast.error(file.status, message)
|
this.$toast.error(file.status, message)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onUnSupportedFormat(status, message) {
|
||||||
|
this.$toast.error(status, message)
|
||||||
|
},
|
||||||
initCropper(file) {
|
initCropper(file) {
|
||||||
|
const supportedFormats = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
|
||||||
|
|
||||||
|
if (supportedFormats.indexOf(file.type) < 0) {
|
||||||
|
this.onUnSupportedFormat(
|
||||||
|
'error',
|
||||||
|
this.$t('contribution.teaserImage.errors.unSupported-file-format'),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.showCropper = true
|
this.showCropper = true
|
||||||
this.file = file
|
this.file = file
|
||||||
|
|
||||||
|
|||||||
@ -23,18 +23,7 @@
|
|||||||
<div class="content hyphenate-text" v-html="excerpt" />
|
<div class="content hyphenate-text" v-html="excerpt" />
|
||||||
<!-- eslint-enable vue/no-v-html -->
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="categories">
|
<div class="categories-placeholder"></div>
|
||||||
<hc-category
|
|
||||||
v-for="category in post.categories"
|
|
||||||
:key="category.id"
|
|
||||||
v-tooltip="{
|
|
||||||
content: $t(`contribution.category.name.${category.slug}`),
|
|
||||||
placement: 'bottom-start',
|
|
||||||
delay: { show: 500 },
|
|
||||||
}"
|
|
||||||
:icon="category.icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<counter-icon
|
<counter-icon
|
||||||
icon="bullhorn"
|
icon="bullhorn"
|
||||||
:count="post.shoutedCount"
|
:count="post.shoutedCount"
|
||||||
@ -67,7 +56,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
||||||
import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
||||||
import HcCategory from '~/components/Category'
|
|
||||||
import HcRibbon from '~/components/Ribbon'
|
import HcRibbon from '~/components/Ribbon'
|
||||||
import CounterIcon from '~/components/_new/generic/CounterIcon/CounterIcon'
|
import CounterIcon from '~/components/_new/generic/CounterIcon/CounterIcon'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
@ -77,7 +65,6 @@ export default {
|
|||||||
name: 'PostTeaser',
|
name: 'PostTeaser',
|
||||||
components: {
|
components: {
|
||||||
UserTeaser,
|
UserTeaser,
|
||||||
HcCategory,
|
|
||||||
HcRibbon,
|
HcRibbon,
|
||||||
ContentMenu,
|
ContentMenu,
|
||||||
CounterIcon,
|
CounterIcon,
|
||||||
@ -181,7 +168,7 @@ export default {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
> .categories {
|
> .categories-placeholder {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,9 @@ const sentry = {
|
|||||||
const options = {
|
const options = {
|
||||||
VERSION: process.env.VERSION || pkg.version,
|
VERSION: process.env.VERSION || pkg.version,
|
||||||
DESCRIPTION: process.env.DESCRIPTION || pkg.description,
|
DESCRIPTION: process.env.DESCRIPTION || pkg.description,
|
||||||
|
// Cookies
|
||||||
|
COOKIE_EXPIRE_TIME: process.env.COOKIE_EXPIRE_TIME || 730, // Two years by default
|
||||||
|
COOKIE_HTTPS_ONLY: process.env.COOKIE_HTTPS_ONLY || process.env.NODE_ENV === 'production', // ensure true in production if not set explicitly
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
|
|||||||
10
webapp/graphql/location.js
Normal file
10
webapp/graphql/location.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
export const queryLocations = () => gql`
|
||||||
|
query($place: String!, $lang: String!) {
|
||||||
|
queryLocations(place: $place, lang: $lang) {
|
||||||
|
place_name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -224,6 +224,9 @@
|
|||||||
"success": "Gespeichert!",
|
"success": "Gespeichert!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Bestätigen",
|
"cropperConfirm": "Bestätigen",
|
||||||
|
"errors": {
|
||||||
|
"unSupported-file-format": "Bitte lade ein Bild in den folgenden Formaten hoch: JPG, JPEG, PNG or GIF!"
|
||||||
|
},
|
||||||
"supportedFormats": "Füge ein Bild im Dateiformat JPG, PNG oder GIF ein"
|
"supportedFormats": "Füge ein Bild im Dateiformat JPG, PNG oder GIF ein"
|
||||||
},
|
},
|
||||||
"title": "Titel"
|
"title": "Titel"
|
||||||
|
|||||||
@ -224,7 +224,10 @@
|
|||||||
"success": "Saved!",
|
"success": "Saved!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Confirm",
|
"cropperConfirm": "Confirm",
|
||||||
"supportedFormats": "Insert a picture of file format JPG , PNG or GIF"
|
"errors": {
|
||||||
|
"unSupported-file-format": "Please upload an image of file format: JPG, JPEG, PNG or GIF!"
|
||||||
|
},
|
||||||
|
"supportedFormats": "Insert a picture of file format JPG, PNG or GIF"
|
||||||
},
|
},
|
||||||
"title": "Title"
|
"title": "Title"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -209,7 +209,7 @@
|
|||||||
"success": "¡Guardado!",
|
"success": "¡Guardado!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Confirmar",
|
"cropperConfirm": "Confirmar",
|
||||||
"supportedFormats": "Insertar una imagen de formato de archivo JPG, PNG o GIF"
|
"supportedFormats": "Insertar una imagen de formato de archivo JPG, PNG o GIF!"
|
||||||
},
|
},
|
||||||
"title": "Título"
|
"title": "Título"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -209,7 +209,7 @@
|
|||||||
"success": "Enregistré!",
|
"success": "Enregistré!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Confirmer",
|
"cropperConfirm": "Confirmer",
|
||||||
"supportedFormats": "Insérer une image au format de fichier JPG, PNG ou GIF"
|
"supportedFormats": "Insérer une image au format de fichier JPG, PNG ou GIF!"
|
||||||
},
|
},
|
||||||
"title": "Titre"
|
"title": "Titre"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -215,7 +215,7 @@
|
|||||||
"success": null,
|
"success": null,
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Confermare",
|
"cropperConfirm": "Confermare",
|
||||||
"supportedFormats": "Inserisci un'immagine in formato file JPG, PNG o GIF"
|
"supportedFormats": "Inserisci un'immagine in formato file JPG, PNG o GIF!"
|
||||||
},
|
},
|
||||||
"title": null
|
"title": null
|
||||||
},
|
},
|
||||||
|
|||||||
@ -69,7 +69,7 @@
|
|||||||
"edit": "Bijdrage bewerken",
|
"edit": "Bijdrage bewerken",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Bevestigen",
|
"cropperConfirm": "Bevestigen",
|
||||||
"supportedFormats": "Voeg een afbeelding in met het bestandsformaat JPG, PNG of GIF"
|
"supportedFormats": "Voeg een afbeelding in met het bestandsformaat JPG, PNG of GIF!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"disable": {
|
"disable": {
|
||||||
|
|||||||
@ -120,7 +120,7 @@
|
|||||||
"success": "Zapisano!",
|
"success": "Zapisano!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Potwierdzać",
|
"cropperConfirm": "Potwierdzać",
|
||||||
"supportedFormats": "Wstaw zdjęcie w formacie pliku JPG, PNG lub GIF"
|
"supportedFormats": "Wstaw zdjęcie w formacie pliku JPG, PNG lub GIF!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
|||||||
@ -253,7 +253,7 @@
|
|||||||
"success": "Salvo!",
|
"success": "Salvo!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Confirmar",
|
"cropperConfirm": "Confirmar",
|
||||||
"supportedFormats": "Insira uma imagem do formato JPG, PNG ou GIF"
|
"supportedFormats": "Insira uma imagem do formato JPG, PNG ou GIF!"
|
||||||
},
|
},
|
||||||
"title": "Título"
|
"title": "Título"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -209,7 +209,7 @@
|
|||||||
"success": "Сохранено!",
|
"success": "Сохранено!",
|
||||||
"teaserImage": {
|
"teaserImage": {
|
||||||
"cropperConfirm": "Подтвердить",
|
"cropperConfirm": "Подтвердить",
|
||||||
"supportedFormats": "Вставьте изображение файла формата JPG, PNG или GIF"
|
"supportedFormats": "Вставьте изображение файла формата JPG, PNG или GIF!"
|
||||||
},
|
},
|
||||||
"title": "Заголовок"
|
"title": "Заголовок"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -191,7 +191,13 @@ export default {
|
|||||||
apollo: {
|
apollo: {
|
||||||
tokenName: metadata.COOKIE_NAME, // optional, default: apollo-token
|
tokenName: metadata.COOKIE_NAME, // optional, default: apollo-token
|
||||||
cookieAttributes: {
|
cookieAttributes: {
|
||||||
expires: 1, // optional, default: 7 (days)
|
expires: CONFIG.COOKIE_EXPIRE_TIME, // optional, default: 7 (days)
|
||||||
|
/** * Define the path where the cookie is available. Defaults to '/' */
|
||||||
|
// For some reason this can vary - lets see if setting this helps.
|
||||||
|
path: '/', // optional
|
||||||
|
/** * A Boolean indicating if the cookie transmission requires a
|
||||||
|
* secure protocol (https). Defaults to false. */
|
||||||
|
secure: CONFIG.COOKIE_HTTPS_ONLY,
|
||||||
},
|
},
|
||||||
// includeNodeModules: true, // optional, default: false (this includes graphql-tag for node_modules folder)
|
// includeNodeModules: true, // optional, default: false (this includes graphql-tag for node_modules folder)
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ describe('index.vue', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocks = {
|
mocks = {
|
||||||
|
$i18n: { locale: () => 'en' },
|
||||||
$t: jest.fn(),
|
$t: jest.fn(),
|
||||||
$apollo: {
|
$apollo: {
|
||||||
mutate: jest
|
mutate: jest
|
||||||
@ -27,6 +28,40 @@ describe('index.vue', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
query: jest
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValue({ message: 'Ouch!' })
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
data: {
|
||||||
|
queryLocations: [
|
||||||
|
{
|
||||||
|
place_name: 'Brazil',
|
||||||
|
id: 'country.9531777110682710',
|
||||||
|
__typename: 'LocationMapBox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
place_name: 'United Kingdom',
|
||||||
|
id: 'country.12405201072814600',
|
||||||
|
__typename: 'LocationMapBox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
place_name: 'Buenos Aires, Argentina',
|
||||||
|
id: 'place.7159025980072860',
|
||||||
|
__typename: 'LocationMapBox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
place_name: 'Bandung, West Java, Indonesia',
|
||||||
|
id: 'place.8224726664248590',
|
||||||
|
__typename: 'LocationMapBox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
place_name: 'Banten, Indonesia',
|
||||||
|
id: 'region.11849645724544000',
|
||||||
|
__typename: 'LocaLocationMapBoxtion2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
$toast: {
|
$toast: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
@ -93,9 +128,182 @@ describe('index.vue', () => {
|
|||||||
wrapper.find('#name').setValue('Peter')
|
wrapper.find('#name').setValue('Peter')
|
||||||
wrapper.find('.ds-form').trigger('submit')
|
wrapper.find('.ds-form').trigger('submit')
|
||||||
|
|
||||||
expect(mocks.$apollo.mutate).toHaveBeenCalled()
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
name: 'Peter',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('given a new slug and hitting submit', () => {
|
||||||
|
it('calls updateUser mutation', () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.find('#slug').setValue('peter-der-lustige')
|
||||||
|
wrapper.find('.ds-form').trigger('submit')
|
||||||
|
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
slug: 'peter-der-lustige',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a new location and hitting submit', () => {
|
||||||
|
it('calls updateUser mutation', async () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
wrapper.setData({
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
label: 'Berlin, Germany',
|
||||||
|
value: 'Berlin, Germany',
|
||||||
|
id: '1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
wrapper.find('.ds-select-option').trigger('click')
|
||||||
|
wrapper.find('.ds-form').trigger('submit')
|
||||||
|
|
||||||
|
await expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
locationName: 'Berlin, Germany',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a new about and hitting submit', () => {
|
||||||
|
it('calls updateUser mutation', () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.find('#about').setValue('I am Peter!111elf')
|
||||||
|
wrapper.find('.ds-form').trigger('submit')
|
||||||
|
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
about: 'I am Peter!111elf',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given new username, slug, location and about then hitting submit', () => {
|
||||||
|
it('calls updateUser mutation', async () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.setData({
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
label: 'Berlin, Germany',
|
||||||
|
value: 'Berlin, Germany',
|
||||||
|
id: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hamburg, Germany',
|
||||||
|
value: 'Hamburg, Germany',
|
||||||
|
id: '2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
wrapper.find('#name').setValue('Peter')
|
||||||
|
wrapper.find('#slug').setValue('peter-der-lustige')
|
||||||
|
wrapper.findAll('.ds-select-option').at(1).trigger('click')
|
||||||
|
wrapper.find('#about').setValue('I am Peter!111elf')
|
||||||
|
wrapper.find('.ds-form').trigger('submit')
|
||||||
|
|
||||||
|
await expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
name: 'Peter',
|
||||||
|
slug: 'peter-der-lustige',
|
||||||
|
locationName: 'Hamburg, Germany',
|
||||||
|
about: 'I am Peter!111elf',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given user input on location field', () => {
|
||||||
|
it('calls queryLocations query', async () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
wrapper.find('#city').trigger('input')
|
||||||
|
wrapper.find('#city').setValue('B')
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
|
||||||
|
expect(mocks.$apollo.query).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
variables: expect.objectContaining({
|
||||||
|
place: 'B',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('opens the dropdown', () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.find('#city').trigger('input')
|
||||||
|
wrapper.find('#city').setValue('B')
|
||||||
|
|
||||||
|
expect(wrapper.find('.ds-select-dropdown').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given no user input on location field', () => {
|
||||||
|
it('cannot call queryLocations query', async () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
jest.useFakeTimers()
|
||||||
|
|
||||||
|
wrapper.find('#city').setValue('')
|
||||||
|
wrapper.find('#city').trigger('input')
|
||||||
|
|
||||||
|
jest.runAllTimers()
|
||||||
|
|
||||||
|
expect(mocks.$apollo.query).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not show the dropdown', () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.find('#city').setValue('')
|
||||||
|
wrapper.find('#city').trigger('input')
|
||||||
|
|
||||||
|
expect(wrapper.find('.ds-select-is-open').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given user presses escape on location field', () => {
|
||||||
|
it('closes the dropdown', () => {
|
||||||
|
const wrapper = Wrapper()
|
||||||
|
|
||||||
|
wrapper.find('#city').setValue('B')
|
||||||
|
wrapper.find('#city').trigger('input')
|
||||||
|
|
||||||
|
expect(wrapper.find('.ds-select-dropdown').isVisible()).toBe(true)
|
||||||
|
|
||||||
|
wrapper.find('#city').trigger('keyup.esc')
|
||||||
|
|
||||||
|
expect(wrapper.find('.ds-select-is-open').exists()).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
/>
|
/>
|
||||||
<!-- eslint-enable vue/use-v-on-exact -->
|
<!-- eslint-enable vue/use-v-on-exact -->
|
||||||
<ds-input
|
<ds-input
|
||||||
id="bio"
|
id="about"
|
||||||
model="about"
|
model="about"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
rows="3"
|
rows="3"
|
||||||
@ -41,17 +41,15 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
import { CancelToken } from 'axios'
|
|
||||||
import UniqueSlugForm from '~/components/utils/UniqueSlugForm'
|
import UniqueSlugForm from '~/components/utils/UniqueSlugForm'
|
||||||
import { updateUserMutation } from '~/graphql/User'
|
import { updateUserMutation } from '~/graphql/User'
|
||||||
|
import { queryLocations } from '~/graphql/location'
|
||||||
|
|
||||||
let timeout
|
let timeout
|
||||||
const mapboxToken = process.env.MAPBOX_TOKEN
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
axiosSource: null,
|
|
||||||
cities: [],
|
cities: [],
|
||||||
loadingData: false,
|
loadingData: false,
|
||||||
loadingGeo: false,
|
loadingGeo: false,
|
||||||
@ -123,51 +121,38 @@ export default {
|
|||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
timeout = setTimeout(() => this.requestGeoData(value), 500)
|
timeout = setTimeout(() => this.requestGeoData(value), 500)
|
||||||
},
|
},
|
||||||
processCityResults(res) {
|
processLocationsResult(places) {
|
||||||
if (!res || !res.data || !res.data.features || !res.data.features.length) {
|
if (!places.length) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const output = []
|
const result = []
|
||||||
res.data.features.forEach((item) => {
|
places.forEach((place) => {
|
||||||
output.push({
|
result.push({
|
||||||
label: item.place_name,
|
label: place.place_name,
|
||||||
value: item.place_name,
|
value: place.place_name,
|
||||||
id: item.id,
|
id: place.id,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return output
|
return result
|
||||||
},
|
},
|
||||||
requestGeoData(e) {
|
async requestGeoData(e) {
|
||||||
if (this.axiosSource) {
|
|
||||||
// cancel last request
|
|
||||||
this.axiosSource.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = e.target ? e.target.value.trim() : ''
|
const value = e.target ? e.target.value.trim() : ''
|
||||||
if (value === '' || value.length < 3) {
|
if (value === '') {
|
||||||
this.cities = []
|
this.cities = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.loadingGeo = true
|
this.loadingGeo = true
|
||||||
this.axiosSource = CancelToken.source()
|
|
||||||
|
|
||||||
const place = encodeURIComponent(value)
|
const place = encodeURIComponent(value)
|
||||||
const lang = this.$i18n.locale()
|
const lang = this.$i18n.locale()
|
||||||
|
|
||||||
this.$axios
|
const {
|
||||||
.get(
|
data: { queryLocations: res },
|
||||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${mapboxToken}&types=region,place,country&language=${lang}`,
|
} = await this.$apollo.query({ query: queryLocations(), variables: { place, lang } })
|
||||||
{
|
|
||||||
cancelToken: this.axiosSource.token,
|
this.cities = this.processLocationsResult(res)
|
||||||
},
|
this.loadingGeo = false
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
this.cities = this.processCityResults(res)
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loadingGeo = false
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user