diff --git a/.travis.yml b/.travis.yml index 4d9a4c733..6ba9d7f12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ install: script: # Backend - docker-compose exec backend yarn run lint - - docker-compose exec backend yarn run test:jest --ci --verbose=false + - docker-compose exec backend yarn run test:jest --ci --verbose=false --coverage - docker-compose exec backend yarn run db:reset - docker-compose exec backend yarn run db:seed - docker-compose exec backend yarn run test:cucumber @@ -30,7 +30,7 @@ script: - docker-compose exec backend yarn run db:seed # Frontend - docker-compose exec webapp yarn run lint - - docker-compose exec webapp yarn run test --ci --verbose=false + - docker-compose exec webapp yarn run test --ci --verbose=false --coverage - docker-compose exec -d backend yarn run test:before:seeder # Fullstack - CYPRESS_RETRIES=1 yarn run cypress:run diff --git a/backend/package.json b/backend/package.json index 75258b36b..71c050461 100644 --- a/backend/package.json +++ b/backend/package.json @@ -26,7 +26,6 @@ "license": "MIT", "jest": { "verbose": true, - "collectCoverage": true, "collectCoverageFrom": [ "**/*.js", "!**/node_modules/**", @@ -106,7 +105,7 @@ "graphql-request": "~1.8.2", "jest": "~24.8.0", "nodemon": "~1.19.1", - "prettier": "~1.14.3", + "prettier": "~1.17.1", "supertest": "~4.0.2" } } diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js index 2e7a2cd1a..b1a08a14d 100644 --- a/backend/src/middleware/permissionsMiddleware.js +++ b/backend/src/middleware/permissionsMiddleware.js @@ -1,9 +1,9 @@ import { rule, shield, allow, or } from 'graphql-shield' /* -* TODO: implement -* See: https://github.com/Human-Connection/Nitro-Backend/pull/40#pullrequestreview-180898363 -*/ + * TODO: implement + * See: https://github.com/Human-Connection/Nitro-Backend/pull/40#pullrequestreview-180898363 + */ const isAuthenticated = rule()(async (parent, args, ctx, info) => { return ctx.user !== null }) diff --git a/backend/yarn.lock b/backend/yarn.lock index 176af3893..50415cf09 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -6233,10 +6233,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@~1.14.3: - version "1.14.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" - integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== +prettier@~1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.1.tgz#ed64b4e93e370cb8a25b9ef7fef3e4fd1c0995db" + integrity sha512-TzGRNvuUSmPgwivDqkZ9tM/qTGW9hqDKWOE9YHiyQdixlKbv7kvEqsmDPrcHJTKwthU774TQwZXVtaQ/mMsvjg== pretty-format@^24.8.0: version "24.8.0" diff --git a/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db b/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db index 233798527..6ffdf8e3f 100755 --- a/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db +++ b/deployment/legacy-migration/maintenance-worker/binaries/import_legacy_db @@ -8,5 +8,5 @@ do fi done -/migration/mongo/import.sh +/migration/mongo/export.sh /migration/neo4j/import.sh diff --git a/deployment/legacy-migration/maintenance-worker/migration/mongo/.env b/deployment/legacy-migration/maintenance-worker/migration/mongo/.env new file mode 100644 index 000000000..602f51fc4 --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/migration/mongo/.env @@ -0,0 +1,16 @@ +# SSH Access +# SSH_USERNAME='username' +# SSH_HOST='example.org' + +# Mongo DB on Remote Maschine +# MONGODB_USERNAME='mongouser' +# MONGODB_PASSWORD='mongopassword' +# MONGODB_DATABASE='mongodatabase' +# MONGODB_AUTH_DB='admin' + +# Export Settings +# On Windows this resolves to C:\Users\dornhoeschen\AppData\Local\Temp\mongo-export (MinGW) +EXPORT_PATH='/tmp/mongo-export/' +EXPORT_MONGOEXPORT_BIN='mongoexport' +# On Windows use something like this +# EXPORT_MONGOEXPORT_BIN='C:\Program Files\MongoDB\Server\3.6\bin\mongoexport.exe' \ No newline at end of file diff --git a/deployment/legacy-migration/maintenance-worker/migration/mongo/export.sh b/deployment/legacy-migration/maintenance-worker/migration/mongo/export.sh new file mode 100755 index 000000000..257bc4c61 --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/migration/mongo/export.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -e + +# import .env config +set -o allexport +source $(dirname "$0")/.env +set +o allexport + +# Export collection function defintion +function export_collection () { + "${EXPORT_MONGOEXPORT_BIN}" --db ${MONGODB_DATABASE} --host localhost -d ${MONGODB_DATABASE} --port 27018 --username ${MONGODB_USERNAME} --password ${MONGODB_PASSWORD} --authenticationDatabase ${MONGODB_AUTH_DB} --collection $1 --collection $1 --out "${EXPORT_PATH}$1.json" + mkdir -p ${EXPORT_PATH}splits/$1/ + split -l 1000 -a 3 ${EXPORT_PATH}$1.json ${EXPORT_PATH}splits/$1/ +} + +# Delete old export & ensure directory +rm -rf ${EXPORT_PATH}* +mkdir -p ${EXPORT_PATH} + +# Open SSH Tunnel +ssh -4 -M -S my-ctrl-socket -fnNT -L 27018:localhost:27017 -l ${SSH_USERNAME} ${SSH_HOST} + +# Export all Data from the Alpha to json and split them up +export_collection "badges" +export_collection "categories" +export_collection "comments" +export_collection "contributions" +export_collection "emotions" +export_collection "follows" +export_collection "invites" +export_collection "notifications" +export_collection "organizations" +export_collection "pages" +export_collection "projects" +export_collection "settings" +export_collection "shouts" +export_collection "status" +export_collection "systemnotifications" +export_collection "users" +export_collection "userscandos" +export_collection "usersettings" + +# Close SSH Tunnel +ssh -S my-ctrl-socket -O check -l ${SSH_USERNAME} ${SSH_HOST} +ssh -S my-ctrl-socket -O exit -l ${SSH_USERNAME} ${SSH_HOST} diff --git a/deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh b/deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh deleted file mode 100755 index d68a8c2a8..000000000 --- a/deployment/legacy-migration/maintenance-worker/migration/mongo/import.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -e - -echo "SSH_USERNAME ${SSH_USERNAME}" -echo "SSH_HOST ${SSH_HOST}" -echo "MONGODB_USERNAME ${MONGODB_USERNAME}" -echo "MONGODB_PASSWORD ${MONGODB_PASSWORD}" -echo "MONGODB_DATABASE ${MONGODB_DATABASE}" -echo "MONGODB_AUTH_DB ${MONGODB_AUTH_DB}" -echo "-------------------------------------------------" - - -rm -rf /tmp/mongo-export/* -mkdir -p /tmp/mongo-export/ - -ssh -4 -M -S my-ctrl-socket -fnNT -L 27018:localhost:27017 -l ${SSH_USERNAME} ${SSH_HOST} - -for collection in "categories" "badges" "users" "contributions" "comments" "follows" "shouts" -do - mongoexport --db ${MONGODB_DATABASE} --host localhost -d ${MONGODB_DATABASE} --port 27018 --username ${MONGODB_USERNAME} --password ${MONGODB_PASSWORD} --authenticationDatabase ${MONGODB_AUTH_DB} --collection $collection --collection $collection --out "/tmp/mongo-export/$collection.json" - mkdir -p /tmp/mongo-export/splits/$collection/ - split -l 1000 -a 3 /tmp/mongo-export/$collection.json /tmp/mongo-export/splits/$collection/ -done - -ssh -S my-ctrl-socket -O check -l ${SSH_USERNAME} ${SSH_HOST} -ssh -S my-ctrl-socket -O exit -l ${SSH_USERNAME} ${SSH_HOST} diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/.env b/deployment/legacy-migration/maintenance-worker/migration/neo4j/.env new file mode 100644 index 000000000..7691306ac --- /dev/null +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/.env @@ -0,0 +1,16 @@ +# Neo4J Settings +# NEO4J_USERNAME='neo4j' +# NEO4J_PASSWORD='letmein' + +# Import Settings +# On Windows this resolves to C:\Users\dornhoeschen\AppData\Local\Temp\mongo-export (MinGW) +IMPORT_PATH='/tmp/mongo-export/' +IMPORT_CHUNK_PATH='/tmp/mongo-export/splits/current-chunk.json' + +IMPORT_CHUNK_PATH_CQL='/tmp/mongo-export/splits/current-chunk.json' +# On Windows this path needs to be windows style since the cypher-shell runs native - note the forward slash +# IMPORT_CHUNK_PATH_CQL='C:/Users/dornhoeschen/AppData/Local/Temp/mongo-export/splits/current-chunk.json' + +IMPORT_CYPHERSHELL_BIN='cypher-shell' +# On Windows use something like this +# IMPORT_CYPHERSHELL_BIN='C:\Program Files\neo4j-community\bin\cypher-shell.bat' \ No newline at end of file diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql index 6b6a09592..62eddf124 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/badges.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as badge +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as badge MERGE(b:Badge {id: badge._id["$oid"]}) ON CREATE SET b.key = badge.key, diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql index 776811bec..81e73c1b9 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/categories.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as category +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as category MERGE(c:Category {id: category._id["$oid"]}) ON CREATE SET c.name = category.title, diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql index 234d29d26..1c8eb9397 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/comments.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as json +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as json MERGE (comment:Comment {id: json._id["$oid"]}) ON CREATE SET diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql index 01647f7fb..e4e148af3 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/contributions.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as post +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as post MERGE (p:Post {id: post._id["$oid"]}) ON CREATE SET p.title = post.title, @@ -20,6 +20,6 @@ MATCH (c:Category {id: categoryId}) MERGE (p)-[:CATEGORIZED]->(c) WITH p, post.tags AS tags UNWIND tags AS tag -MERGE (t:Tag {id: apoc.create.uuid(), name: tag}) +MERGE (t:Tag {id: tag, name: tag}) MERGE (p)-[:TAGGED]->(t) ; diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql index 0cd6d9cfc..bf3837b04 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/follows.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as follow +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as follow MATCH (u1:User {id: follow.userId}), (u2:User {id: follow.foreignId}) MERGE (u1)-[:FOLLOWS]->(u2) ; diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh b/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh index b7de74782..12cc7ce67 100755 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/import.sh @@ -1,17 +1,48 @@ #!/usr/bin/env bash set -e -SECONDS=0 -SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +# import .env config +set -o allexport +source $(dirname "$0")/.env +set +o allexport -echo "MATCH (n) DETACH DELETE n;" | cypher-shell - -for collection in "badges" "categories" "users" "follows" "contributions" "shouts" "comments" -do - for chunk in /tmp/mongo-export/splits/$collection/* +# Import collection function defintion +function import_collection () { + for chunk in ${IMPORT_PATH}splits/$1/* do - mv $chunk /tmp/mongo-export/splits/current-chunk.json - echo "Import ${chunk}" && cypher-shell < $SCRIPT_DIRECTORY/$collection.cql + mv $chunk ${IMPORT_CHUNK_PATH} + NEO4J_COMMAND="$(envsubst '${IMPORT_CHUNK_PATH_CQL}' < $(dirname "$0")/$1.cql)" + echo "Import ${chunk}" + echo "${NEO4J_COMMAND}" | "${IMPORT_CYPHERSHELL_BIN}" -u ${NEO4J_USERNAME} -p ${NEO4J_PASSWORD} done -done +} + +# Time variable +SECONDS=0 + +# Delete all Neo4J Database content +echo "Deleting Database Contents" +echo "MATCH (n) DETACH DELETE n;" | "${IMPORT_CYPHERSHELL_BIN}" -u ${NEO4J_USERNAME} -p ${NEO4J_PASSWORD} + +# Import Data +echo "Start Importing Data" +import_collection "badges" +import_collection "categories" +import_collection "users" +import_collection "follows" +import_collection "contributions" +import_collection "shouts" +import_collection "comments" +#import_collection "emotions" +#import_collection "invites" +#import_collection "notifications" +#import_collection "organizations" +#import_collection "pages" +#import_collection "projects" +#import_collection "settings" +#import_collection "status" +#import_collection "systemnotifications" +#import_collection "userscandos" +#import_collection "usersettings" + echo "Time elapsed: $SECONDS seconds" diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql index 5019cdc32..a82a7a33d 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/shouts.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as shout +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as shout MATCH (u:User {id: shout.userId}), (p:Post {id: shout.foreignId}) MERGE (u)-[:SHOUTED]->(p) ; diff --git a/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql b/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql index c877f8377..693fd75b6 100644 --- a/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql +++ b/deployment/legacy-migration/maintenance-worker/migration/neo4j/users.cql @@ -1,4 +1,4 @@ -CALL apoc.load.json('file:/tmp/mongo-export/splits/current-chunk.json') YIELD value as user +CALL apoc.load.json("file:${IMPORT_CHUNK_PATH_CQL}") YIELD value as user MERGE(u:User {id: user._id["$oid"]}) ON CREATE SET u.name = user.name, diff --git a/webapp/components/Avatar/Avatar.spec.js b/webapp/components/Avatar/Avatar.spec.js new file mode 100644 index 000000000..ae91fecfe --- /dev/null +++ b/webapp/components/Avatar/Avatar.spec.js @@ -0,0 +1,69 @@ +import { mount, createLocalVue } from '@vue/test-utils' +import Styleguide from '@human-connection/styleguide' +import Avatar from './Avatar.vue' + +const localVue = createLocalVue() +localVue.use(Styleguide) + +describe('Avatar.vue', () => { + let propsData = {} + + const Wrapper = () => { + return mount(Avatar, { propsData, localVue }) + } + + it('renders no image', () => { + expect( + Wrapper() + .find('img') + .exists(), + ).toBe(false) + }) + + it('renders an icon', () => { + expect( + Wrapper() + .find('.ds-icon') + .exists(), + ).toBe(true) + }) + + describe('given a user', () => { + describe('with a relative avatar url', () => { + beforeEach(() => { + propsData = { + user: { + avatar: '/avatar.jpg', + }, + } + }) + + it('adds a prefix to load the image from the uploads service', () => { + expect( + Wrapper() + .find('img') + .attributes('src'), + ).toBe('/api/avatar.jpg') + }) + }) + + describe('with an absolute avatar url', () => { + beforeEach(() => { + propsData = { + user: { + avatar: 'http://lorempixel.com/640/480/animals', + }, + } + }) + + it('keeps the avatar URL as is', () => { + // e.g. our seeds have absolute image URLs + expect( + Wrapper() + .find('img') + .attributes('src'), + ).toBe('http://lorempixel.com/640/480/animals') + }) + }) + }) +}) diff --git a/webapp/components/Avatar/Avatar.vue b/webapp/components/Avatar/Avatar.vue new file mode 100644 index 000000000..0d997c745 --- /dev/null +++ b/webapp/components/Avatar/Avatar.vue @@ -0,0 +1,28 @@ + + + diff --git a/webapp/components/Editor/index.vue b/webapp/components/Editor/index.vue index ebc812199..59aa73cb2 100644 --- a/webapp/components/Editor/index.vue +++ b/webapp/components/Editor/index.vue @@ -317,10 +317,18 @@ export default { }, }, }, + mounted() { + this.$root.$on('changeLanguage', () => { + this.changePlaceHolderText() + }) + }, beforeDestroy() { this.editor.destroy() }, methods: { + changePlaceHolderText() { + this.editor.extensions.options.placeholder.emptyNodeText = this.$t('editor.placeholder') + }, // navigate to the previous item // if it's the first item, navigate to the last one upHandler() { diff --git a/webapp/components/LocaleSwitch.vue b/webapp/components/LocaleSwitch.vue index f765c534f..f6f1a9727 100644 --- a/webapp/components/LocaleSwitch.vue +++ b/webapp/components/LocaleSwitch.vue @@ -68,6 +68,7 @@ export default { changeLanguage(locale, toggleMenu) { this.$i18n.set(locale) toggleMenu() + this.$root.$emit('changeLanguage') }, matcher(locale) { return locale === this.$i18n.locale() diff --git a/webapp/components/Upload/index.vue b/webapp/components/Upload/index.vue index 831edd2f8..f43ede7e6 100644 --- a/webapp/components/Upload/index.vue +++ b/webapp/components/Upload/index.vue @@ -48,13 +48,6 @@ export default {
-
-
-
-
-
-
- ` }, @@ -117,15 +110,16 @@ export default { } #customdropzone .dz-preview { + transition: all 0.2s ease-out; width: 160px; display: flex; } #customdropzone .dz-preview .dz-image { - position: relative; - width: 122px; - height: 122px; - margin: -35px; + width: 100%; + height: 100%; + object-fit: contain; + overflow: hidden; } #customdropzone .dz-preview .dz-image > div { diff --git a/webapp/components/User/index.vue b/webapp/components/User/index.vue index 756d4d032..7841fe596 100644 --- a/webapp/components/User/index.vue +++ b/webapp/components/User/index.vue @@ -3,7 +3,7 @@
- +
{{ $t('profile.userAnonym') }} @@ -16,12 +16,7 @@
- +
{{ userName | truncate(18) }} @@ -102,6 +97,7 @@ import { mapGetters } from 'vuex' import HcRelativeDateTime from '~/components/RelativeDateTime' import HcFollowButton from '~/components/FollowButton' import HcBadges from '~/components/Badges' +import HcAvatar from '~/components/Avatar/Avatar.vue' import Dropdown from '~/components/Dropdown' export default { @@ -109,6 +105,7 @@ export default { components: { HcRelativeDateTime, HcFollowButton, + HcAvatar, HcBadges, Dropdown, }, @@ -142,12 +139,6 @@ export default {