Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define panel initial state #761

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions src/components/Pages/ManageWiki/Cards/QuestyCaptcha.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<template>
<v-card>
<v-card-title>Additional Spam Protection</v-card-title>
<v-card-text class="pb-2">
QuestyCaptcha offers an extra layer of protection against spam accounts. During account creation, users will have to answer a question, which can be defined in settings. For more information on QuestyCaptcha, please visit the documentation page
</v-card-text>
<v-col class="checkbox">
<v-checkbox label="Activate spam protection" v-model="captchaActivate"></v-checkbox>
</v-col>
<!-- Setting Panel-->
<v-expansion-panels v-model="panel">
<v-expansion-panel>
<v-expansion-panel-header>
<strong>SETTINGS</strong>
</v-expansion-panel-header>
<v-expansion-panel-content>
<strong>Guidelines for creating questions and answers:</strong><br/>
<ul>
<li>Keep in mind that users have a wide variety of knowledge and abilities. We therefore recommend three questions at minimum, each requiring different abilities or knowledge.</li>
<li>Consider cultural bias. Use questions that rely on universal knowledge or knowledge related to your wiki.</li>
<li>Keep the answers short and simple. Ideally, try to use questions with only one possible answer.</li>
</ul>
<!-- Question/Answer Bundle-->
<v-form ref="questyForm">
<div class="pt-10" v-for="(entry, index) in questionsFromStore" :key="index">
Question
<v-text-field
class="trash-icon pb-2"
v-model="entry.question"
outlined
hide-details="auto"
:append-outer-icon="showIcon ? 'mdi-delete-outline' : undefined"
:rules="[() => !!entry.question || 'Field cannot be empty. Please provide a question']"
@click:append-outer="removeQuestion(index)"
dense
></v-text-field>
Answer
<v-combobox
:class="{'answer-box': true, 'answer-input-field': applyStyling}"
v-model="entry.answers"
:items="entry.answers"
multiple
outlined
:rules="[required]"
hide-selected
hide-details="auto"
dense
>
<template v-slot:selection="{ item }" >
<v-chip class="chips">
<span class="pr-1">
{{ item }}
</span>
<v-icon
small
@click="removeAnswer(entry, item)"
>
mdi-close-circle
</v-icon>
</v-chip>
</template>
</v-combobox>
</div>
<!-- Buttons-->
<div class="d-flex pb-12 pt-10">
<v-btn @click="addQuestion" elevation=0 plain class="ml-auto">+ ADD QUESTION</v-btn>
</div>
<div>
<v-btn @click="saveForm" color="primary" width="100%">SAVE QUESTIONS</v-btn>
</div>
<div class="pt-4">
<v-btn @click="recoverDefaultQuestions" elevation=0 width="100%">RECOVER DEFAULT QUESTIONS</v-btn>
</div>
</v-form>
<!-- Success/Error Message Snackbar-->
<v-snackbar color="success" elevation="24" v-model="successMessage">
Your questions have been saved
<template v-slot:action>
<v-btn
text
variant="text"
@click="closeAlert"
>
Close
</v-btn>
</template>
</v-snackbar>
<v-snackbar color="error" elevation="24" v-model="errorMessage">
Something is wrong with saving your questions. Please try again
<template v-slot:action>
<v-btn
text
variant="text"
@click="closeAlert"
>
Close
</v-btn>
</template>
</v-snackbar>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-card>
</template>

<script>

export default {
name: 'QuestyCaptcha',
props: [
'wikiId'
],
data () {
return {
successMessage: false,
errorMessage: false,
captchaActivate: false,
questionsFromStore: [],
showIcon: true,
applyStyling: true,
panel: false
}
},
created () {
this.questionsFromStore = this.$store.state.wikis.currentWikiSettings.captchaQuestions
this.captchaActivate = this.$store.state.wikis.currentWikiSettings.wwUseQuestyCaptcha
},
methods: {
removeAnswer (question, answer) {
const index = question.answers.indexOf(answer)
if (index !== -1) {
question.answers.splice(index, 1)
}
},
removeQuestion (index) {
this.questionsFromStore.splice(index, 1)
// hide trash icon when there is just one QA bundle
if (this.questionsFromStore.length === 1) {
this.showIcon = false
this.applyStyling = false
}
},
addQuestion () {
this.questionsFromStore.push({
question: '',
answers: []
})
// show the trash icon again when there are more than one QA bundle
this.showIcon = true
this.applyStyling = true
},
saveForm () {
for (let i = 0; i < this.questionsFromStore.length; i++) {
const entry = this.questionsFromStore[i]
const noQuestion = entry.question.trim() === ''
const noAnswer = entry.answers && entry.answers.length === 0
if (noQuestion && noAnswer && this.questionsFromStore.length > 1) {
this.questionsFromStore.splice(i, 1)
}
}
this.$nextTick(() => {
if (!this.$refs.questyForm.validate()) {
return
}
const wiki = this.wikiId
const promises = []
const captchaEnabledSetting = 'wwUseQuestyCaptcha'
const captchaQuestionsSetting = 'wwCaptchaQuestions'
const enableValue = this.captchaActivate
const questions = {}
this.questionsFromStore.forEach(item => {
questions[item.question] = item.answers
})
const JSONQuestions = JSON.stringify(questions)
promises.push(
this.$store.dispatch('updateSetting', { wiki, setting: captchaEnabledSetting, value: enableValue }),
this.$store.dispatch('updateSetting', { wiki, setting: captchaQuestionsSetting, value: JSONQuestions })
)
Promise.all(promises)
.then(() => {
this.$store.dispatch('setEnabledQuestyCaptcha', enableValue)
this.$store.dispatch('setQuestyCaptchaQuestions', this.questionsFromStore)
this.successMessage = true
})
.catch(err => {
console.log(err.response)
this.errorMessage = true
})
this.panel = false
})
},
recoverDefaultQuestions () {
const recoveredDefaultQuestions = this.$store.state.wikis.currentWikiSettings.defaultQuestions
this.questionsFromStore = JSON.parse(JSON.stringify(recoveredDefaultQuestions))
},
required (value) {
if (value.length === 0) {
return 'Field cannot be empty. Please provide an answer'
}
return !!value || 'Field cannot be empty. Please provide an answer'
},
closeAlert () {
this.successMessage = false
this.errorMessage = false
}
}
}
</script>

<style lang="css" scoped>
.checkbox {
padding-left: 20px;
padding-bottom: 0;
padding-top: 0;
}
.answer-input-field {
margin-right: 33px !important;
}
>>> .answer-box .v-input__append-inner {
display: none !important;
}
.chips {
margin: 0 8px 0 0 !important;
}
>>> .trash-icon .v-input__append-outer {
margin-top: 0 !important;
}
</style>
7 changes: 7 additions & 0 deletions src/components/Pages/ManageWiki/Tabs/ManageWiki.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
<Logo :wikiId="this.wikiId"/>
</v-col>
</v-row>
<v-row>
<v-col>
<QuestyCaptcha :wikiId="this.wikiId"/>
</v-col>
</v-row>
</v-col>
<!--Col 2-->
<v-col>
Expand Down Expand Up @@ -62,10 +67,12 @@ import Skin from '~/components/Pages/ManageWiki/Cards/Skin'
import Registration from '~/components/Pages/ManageWiki/Cards/Registration'
import Wikibase from '~/components/Pages/ManageWiki/Cards/Wikibase'
import Delete from '~/components/Pages/ManageWiki/Cards/Delete'
import QuestyCaptcha from '../Cards/QuestyCaptcha'

export default {
name: 'ManageWiki',
components: {
QuestyCaptcha,
Details,
Logo,
Skin,
Expand Down
37 changes: 36 additions & 1 deletion src/store/wikis.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ const mutations = {
const defaultMapping = { properties: { P31: MAPPING_SUGGESTION_PLACEHOLDER, P279: MAPPING_SUGGESTION_PLACEHOLDER }, items: {} }
const wikibaseManifestEquivEntities = entityMappingSetting ? JSON.parse(entityMappingSetting.value) : defaultMapping

const wwUseQuestyCaptchaSetting = details.public_settings.find(setting => setting.name === 'wwUseQuestyCaptcha')
const wwUseQuestyCaptcha = wwUseQuestyCaptchaSetting ? parseInt(wwUseQuestyCaptchaSetting.value) === 1 : false

const captchaQuestionsSetting = details.public_settings.find(setting => setting.name === 'wwCaptchaQuestions')
const defaultQuestions = [
{ question: 'How many vowels are in this question?', answers: ['12', 'twelve'] },
{ question: 'What is the chemical formula of water?', answers: ['H2O'] },
{ question: '2 + 4 = ?', answers: ['6', 'six'] }
]
let captchaQuestions
let questionFromStoreAsArrayOfObjects
if (captchaQuestionsSetting) {
questionFromStoreAsArrayOfObjects = Object.keys(captchaQuestionsSetting).map(
(key) => { return { question: key, answers: captchaQuestionsSetting[key] } }
)
captchaQuestions = questionFromStoreAsArrayOfObjects
} else {
captchaQuestions = JSON.parse(JSON.stringify(defaultQuestions))
}

const federatedPropertiesSetting = details.public_settings.find(setting => setting.name === 'wikibaseFedPropsEnable')
const wikibaseFedPropsEnable = federatedPropertiesSetting ? parseInt(federatedPropertiesSetting.value) === 1 : false

Expand Down Expand Up @@ -90,7 +110,10 @@ const mutations = {
wwWikibaseStringLengthString,
wwWikibaseStringLengthMonolingualText,
wwWikibaseStringLengthMultilang,
wwExtEnableConfirmAccount
wwExtEnableConfirmAccount,
wwUseQuestyCaptcha,
captchaQuestions,
defaultQuestions
}
},
clear_current_wiki_settings (state) {
Expand Down Expand Up @@ -119,6 +142,12 @@ const mutations = {
},
set_enable_confirm_account (state, { value }) {
state.currentWikiSettings.wwExtEnableConfirmAccount = value
},
set_enable_questy_captcha (state, { value }) {
state.currentWikiSettings.wwUseQuestyCaptcha = value
},
set_questy_captcha_questions (state, value) {
state.currentWikiSettings.captchaQuestions = value
}
}

Expand Down Expand Up @@ -186,6 +215,12 @@ const actions = {
items: filterOutPlaceholderMapping(mapping.items)
})
})
},
setEnabledQuestyCaptcha ({ commit }, enabled) {
commit('set_enable_questy_captcha', enabled)
},
setQuestyCaptchaQuestions ({ commit }, value) {
commit('set_questy_captcha_questions', value)
}
}

Expand Down
Loading