Skip to content

Commit 2414f0a

Browse files
committed
Implement blacklist on the frontend
1 parent daf9443 commit 2414f0a

File tree

23 files changed

+1369
-946
lines changed

23 files changed

+1369
-946
lines changed

.babelrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"env": {
3+
"test": {
4+
"plugins": ["transform-object-rest-spread"],
5+
"presets": [
6+
["env", { "targets": { "node": "current" }}]
7+
]
8+
}
9+
}
10+
}
11+

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module.exports = {
66
sourceType: 'module'
77
},
88
env: {
9+
jest: true,
910
browser: true,
1011
node: true
1112
},
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<template>
2+
<div class="columns is-mobile field has-text-centered">
3+
<div class="column control has-text-centered">
4+
<hc-button color="button"
5+
:disabled="isPending"
6+
:isLoading="isPending"
7+
@click="click">
8+
<template v-if="isBlacklisted()">
9+
<hc-icon icon="ban" :class="['icon-left', 'is-danger']" /> {{ $t('component.blacklist.buttonLabelUnblock') }}
10+
</template>
11+
<template v-else>
12+
<hc-icon icon="ban" class="icon-left" /> {{ $t('component.blacklist.buttonLabelBlock') }}
13+
</template>
14+
</hc-button>
15+
</div>
16+
</div>
17+
</template>
18+
<script>
19+
import Icon from '~/components/Global/Elements/Icon/Icon.vue'
20+
import Button from '~/components/Global/Elements/Button/Button.vue'
21+
import { mapGetters } from 'vuex'
22+
23+
export default {
24+
name: 'hc-block-button',
25+
components: {
26+
'hc-button': Button,
27+
'hc-icon': Icon
28+
},
29+
props: {
30+
foreignEntity: {
31+
type: Object,
32+
required: true
33+
},
34+
confirmation: {
35+
type: Function
36+
}
37+
},
38+
computed: {
39+
...mapGetters({
40+
isPending: 'feathers-vuex-usersettings/isPending',
41+
currentUserSettings: 'feathers-vuex-usersettings/current'
42+
})
43+
},
44+
methods: {
45+
isBlacklisted () {
46+
let { blacklist } = this.currentUserSettings || {}
47+
return blacklist && blacklist.includes(this.foreignEntity._id)
48+
},
49+
async click(){
50+
if (this.confirmation && !this.isBlacklisted()) {
51+
return await this.confirmation(this.toggleBlacklist)
52+
} else return await this.toggleBlacklist()
53+
},
54+
async toggleBlacklist() {
55+
let message
56+
try {
57+
await this.$store.dispatch('feathers-vuex-usersettings/toggleBlacklist', this.foreignEntity)
58+
const translationKey = `component.blacklist.${this.isBlacklisted() ? 'blockSuccess' : 'unblockSuccess'}`
59+
message = this.$t(translationKey, {
60+
name: this.foreignEntity.name || this.$t('component.contribution.creatorUnknown')
61+
})
62+
} catch (error) {
63+
message = this.$t('component.error.general')
64+
throw (error)
65+
} finally {
66+
this.$snackbar.open({ message })
67+
}
68+
}
69+
}
70+
71+
}
72+
</script>
73+
74+
<style lang="scss" scoped>
75+
@import "assets/styles/utilities";
76+
</style>

components/Global/Elements/Follow/FollowButtons.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<div v-if="showButtons" class="columns is-mobile field has-text-centered">
1818
<div class="column control has-text-centered">
1919
<hc-button color="button is-fullwidth"
20-
:class="{'is-primary': !follow.isLoading && !follow.isPending && !follow.isFollowing}"
20+
:class="{'is-primary': !follow.isPending && !follow.isFollowing}"
2121
@click="toggleFollow"
2222
:disabled="follow.isPending"
2323
:isLoading="follow.isPending">

locales/de.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@
6060
"messageFollowSuccess": "Du folgst {name} nun",
6161
"messageUnFollowSuccess": "Du folgst {name} nicht mehr"
6262
},
63+
"blacklist": {
64+
"buttonLabelBlock": "Blockieren",
65+
"buttonLabelUnblock": "Blockiert",
66+
"confirmUnfollowTitle": "Nicht mehr Folgen",
67+
"confirmUnfollowMessage": "Möchtest Du {name} nicht mehr folgen und dessen Inhalte nie mehr sehen?",
68+
"blockSuccess": "Du wirst keine Inhalte von {name} mehr sehen",
69+
"unblockSuccess": "Du wirst wieder Inhalte von {name} sehen"
70+
},
6371
"admin": {
6472
"activate": "Aktivieren",
6573
"addCategory": "Kategorie hinzufügen",
@@ -165,6 +173,8 @@
165173
"actionReport": "Beitrag melden",
166174
"actionDisable": "Beitrag deaktivieren",
167175
"actionEnable": "Beitrag aktivieren",
176+
"actionBlockAuthor": "Autor blockieren",
177+
"actionUnblockAuthor": "Autor freigeben",
168178
"bestList": "Bestenliste",
169179
"canDos": "Can Do",
170180
"canDoAdd": "Can Do starten",
@@ -621,7 +631,9 @@
621631
"organizationStreet": "Straße",
622632
"organizationZipCode": "PLZ",
623633
"organizationCity": "Stadt",
624-
"organizationCountry": "Land"
634+
"organizationCountry": "Land",
635+
"blacklist": "Sperrliste",
636+
"blacklistSubtitle": "Nutzerprofile deren Inhalte Du nicht mehr siehst"
625637
}
626638
},
627639
"ressource": {

locales/en.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"copy403": "Sorry, access to this resource on the server is denied. <br />Either check the URL, <a href=\"/auth/login\">login</a> or <a href=\"/\">go home</a>.",
1717
"copy404": "Sorry, the page you're looking for cannot be found. <br />Either check the URL, <a href=\"/\">go home</a>, or feel free to <a href=\"mailto:[email protected]\">report this issue.</a>",
1818
"copy500": "An error ocurred and your request couldn’t be completed. <br />Either check the URL, <a href=\"/\">go home</a>, or feel free to <a href=\"mailto:[email protected]\">report this issue.</a>",
19-
"copy503": "We are currently working on it, <br />so take a coffee brake and come back a bit later."
19+
"copy503": "We are currently working on it, <br />so take a coffee brake and come back a bit later.",
20+
"general": "Oops, something went terribly wrong"
2021
},
2122
"badges": {
2223
"user_role_moderator": "Moderator",
@@ -60,6 +61,14 @@
6061
"messageFollowSuccess": "You now follow {name}",
6162
"messageUnFollowSuccess": "You not longer follow {name}"
6263
},
64+
"blacklist": {
65+
"buttonLabelBlock": "Block",
66+
"buttonLabelUnblock": "Blocked",
67+
"confirmUnfollowTitle": "Unfollow",
68+
"confirmUnfollowMessage": "Do you want to unfollow and block any content by {name}?",
69+
"blockSuccess": "You will no longer see any content by {name}",
70+
"unblockSuccess": "You will see content by {name} again"
71+
},
6372
"admin": {
6473
"activate": "Activate",
6574
"addCategory": "add category",
@@ -166,6 +175,8 @@
166175
"actionReport": "report post",
167176
"actionDisable": "disable post",
168177
"actionEnable": "enable post",
178+
"actionBlockAuthor": "block author",
179+
"actionUnblockAuthor": "unblock author",
169180
"bestList": "Bestlist",
170181
"canDos": "Can Do’s",
171182
"canDoAdd": "Start Can Do",
@@ -623,7 +634,9 @@
623634
"organizationStreet": "Street",
624635
"organizationZipCode": "Zip Code",
625636
"organizationCity": "City",
626-
"organizationCountry": "Country"
637+
"organizationCountry": "Country",
638+
"blacklist": "Blacklist",
639+
"blacklistSubtitle": "Users whose content you no longer see"
627640
}
628641
},
629642
"ressource": {

package.json

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"eslint": "eslint --ext .js,.vue .",
3838
"styleguide": "vue-styleguidist server",
3939
"styleguide:build": "vue-styleguidist build",
40-
"test": "ava",
40+
"test": "jest",
4141
"cypress:open": "cypress open",
4242
"cypress:run": "cypress run",
4343
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov"
@@ -117,10 +117,10 @@
117117
},
118118
"devDependencies": {
119119
"@nuxtjs/webpackmonitor": "~0.1.0",
120-
"@vue/test-utils": "^1.0.0-beta.20",
121-
"ava": "~0.25.0",
120+
"@vue/server-test-utils": "^1.0.0-beta.25",
121+
"@vue/test-utils": "^1.0.0-beta.25",
122+
"babel-jest": "^23.6.0",
122123
"backpack-core": "~0.7.0",
123-
"browser-env": "~3.2.4",
124124
"codecov": "~3.0.4",
125125
"eslint": "~4.19.1",
126126
"eslint-config-standard": "~11.0.0-beta.0",
@@ -132,21 +132,34 @@
132132
"eslint-plugin-standard": "~3.1.0",
133133
"eslint-plugin-vue": "^4.5.0",
134134
"istanbul": "~0.4.5",
135-
"jsdom": "~11.10.0",
135+
"jest": "^23.6.0",
136+
"jsdom": "^12.0.0",
137+
"jsdom-global": "^3.0.2",
136138
"less": "~2.7.3",
137139
"less-loader": "^4.1.0",
138140
"node-sass": "~4.9.0",
139141
"require-extension-hooks": "~0.3.2",
140142
"require-extension-hooks-babel": "~0.1.1",
141143
"require-extension-hooks-vue": "~1.0.0",
142144
"sass-loader": "~6.0.7",
145+
"sinon": "^6.3.4",
143146
"source-map-support": "~0.5.6",
144147
"vue-docgen-api": "^2.3.11",
148+
"vue-jest": "^2.6.0",
145149
"vue-style-loader": "~4.1.0"
146150
},
147-
"ava": {
148-
"require": [
149-
"./test/helpers/setup.js"
150-
]
151+
"jest": {
152+
"moduleFileExtensions": [
153+
"js",
154+
"json",
155+
"vue"
156+
],
157+
"moduleNameMapper": {
158+
"^~/(.*)$": "<rootDir>/$1"
159+
},
160+
"transform": {
161+
".*\\.(vue)$": "vue-jest",
162+
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
163+
}
151164
}
152165
}

pages/auth/settings.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<li>
2525
<nuxt-link :to="{ name: 'auth-settings-security' }">{{ $t('auth.settings.security', 'Security') }}</nuxt-link>
2626
</li>
27+
<li>
28+
<nuxt-link :to="{ name: 'auth-settings-blacklist' }">{{ $t('auth.settings.blacklist', 'Blacklist') }}</nuxt-link>
29+
</li>
2730
<li v-if="showInvites">
2831
<nuxt-link :to="{ name: 'auth-settings-invites' }">{{ $t('auth.settings.invites', 'Invites') }}</nuxt-link>
2932
</li>

pages/auth/settings/blacklist.vue

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div class="info-text">
3+
<h2 class="title is-3">
4+
{{ $t('auth.settings.blacklist') }}
5+
</h2>
6+
<p class="subtitle is-6">{{ $t('auth.settings.blacklistSubtitle') }}</p>
7+
<author
8+
v-for="(user, index) in blacklistedUsers"
9+
:key="user._id"
10+
:user="user"
11+
/>
12+
</div>
13+
</template>
14+
15+
<script>
16+
import Author from '~/components/Author/Author.vue'
17+
export default {
18+
components: {
19+
Author
20+
},
21+
data() {
22+
return {
23+
blacklistedUsers: [],
24+
}
25+
},
26+
async asyncData ({store}) {
27+
const { blacklist } = store.getters['feathers-vuex-usersettings/current'];
28+
if (!blacklist) return {}
29+
const res = await store.dispatch('feathers-vuex-users/find', { query: {_id: { $in: blacklist } } } );
30+
return {
31+
blacklistedUsers: res.data
32+
}
33+
}
34+
};
35+
</script>
36+
37+
<style lang="scss" scoped>
38+
</style>

pages/profile/_slug.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
<hc-follow-buttons v-if="user"
4242
:showButtons="!isOwner"
4343
:entity="user" />
44+
45+
<hc-block-button v-if="user && !isOwner" :foreignEntity="user" :confirmation="confirmUnfollow"/>
4446
<div v-if="false" class="hc-shortcuts level under-construction">
4547
<!-- TODO: replace the cdn images with local hc icons -->
4648
<div class="level-item has-text-centered">
@@ -140,6 +142,7 @@
140142
import {mapGetters} from 'vuex'
141143
import FollowerItem from '~/components/Profile/FollowerItem/FollowerItem.vue'
142144
import FollowButtons from '~/components/Global/Elements/Follow/FollowButtons.vue'
145+
import BlockButton from '~/components/Global/Elements/BlockButton/BlockButton'
143146
import Map from '~/components/Map/Map.vue'
144147
import Timeline from '~/components/layout/Timeline'
145148
import Badges from '~/components/Profile/Badges/Badges'
@@ -150,6 +153,7 @@
150153
components: {
151154
'hc-follower-item': FollowerItem,
152155
'hc-follow-buttons': FollowButtons,
156+
'hc-block-button': BlockButton,
153157
'hc-profile-badges': Badges,
154158
'hc-map': Map,
155159
'hc-timeline': Timeline
@@ -261,6 +265,20 @@
261265
}
262266
},
263267
methods: {
268+
confirmUnfollow(next){
269+
const message = this.$t('component.blacklist.confirmUnfollowMessage', {
270+
name: this.user.name || this.$t('component.contribution.creatorUnknown')
271+
})
272+
this.$dialog.confirm({
273+
title: this.$t('component.blacklist.confirmUnfollowTitle'),
274+
message,
275+
confirmText: this.$t('button.yes'),
276+
cancelText: this.$t('button.cancel'),
277+
type: 'is-danger',
278+
hasIcon: true,
279+
onConfirm: () => { next() }
280+
})
281+
},
264282
async onCoverUploadCompleted (value) {
265283
this.form.coverImg = value
266284
const user = await this.$store.dispatch('auth/patch', {

0 commit comments

Comments
 (0)