mirror of
https://git.boykissers.com/pawkey/pawkey-sk.git
synced 2025-12-20 04:04:16 +00:00
feat: require a special registration word in registration reason (#2)
A crude way to prune out people who don't read the rules. The hint is in the bottom of the rules generally.
This commit is contained in:
@@ -1982,6 +1982,7 @@ _signup:
|
||||
almostThere: "Almost there"
|
||||
emailAddressInfo: "Please enter your email address. It will not be made public."
|
||||
emailSent: "A confirmation email has been sent to your email address ({email}). Please click the included link to complete account creation."
|
||||
registrationWordRequired: "Please include the required registration word in your reason"
|
||||
_accountDelete:
|
||||
accountDelete: "Delete account"
|
||||
mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded."
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddRegWordFieldsToMeta1743894419864 implements MigrationInterface {
|
||||
name = 'AddRegWordFieldsToMeta1743894419864'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "regWordRequired" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "registrationWord" character varying(1024)`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "registrationWord"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "regWordRequired"`);
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,8 @@ export class MetaEntityService {
|
||||
disableRegistration: instance.disableRegistration,
|
||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||
approvalRequiredForSignup: instance.approvalRequiredForSignup,
|
||||
regWordRequired: instance.regWordRequired,
|
||||
registrationWord: instance.registrationWord,
|
||||
enableHcaptcha: instance.enableHcaptcha,
|
||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||
enableMcaptcha: instance.enableMcaptcha,
|
||||
|
||||
@@ -139,9 +139,8 @@ export class MiMeta {
|
||||
})
|
||||
public logoImageUrl: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public iconUrl: string | null;
|
||||
|
||||
@@ -204,6 +203,18 @@ export class MiMeta {
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public regWordRequired: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public registrationWord: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public enableHcaptcha: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
|
||||
@@ -313,6 +313,14 @@ export const packedMetaLiteSchema = {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
regWordRequired: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
registrationWord: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
privacyPolicyUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
|
||||
@@ -39,6 +39,14 @@ export const meta = {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
registrationWord: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
regWordRequired: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableHcaptcha: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
@@ -657,6 +665,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
disableRegistration: instance.disableRegistration,
|
||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||
approvalRequiredForSignup: instance.approvalRequiredForSignup,
|
||||
registrationWord: instance.registrationWord,
|
||||
regWordRequired: instance.regWordRequired,
|
||||
enableHcaptcha: instance.enableHcaptcha,
|
||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||
enableMcaptcha: instance.enableMcaptcha,
|
||||
|
||||
@@ -74,6 +74,8 @@ export const paramDef = {
|
||||
cacheRemoteSensitiveFiles: { type: 'boolean' },
|
||||
emailRequiredForSignup: { type: 'boolean' },
|
||||
approvalRequiredForSignup: { type: 'boolean' },
|
||||
regWordRequired: { type: 'boolean', nullable: false },
|
||||
registrationWord: { type: 'string', nullable: true },
|
||||
enableHcaptcha: { type: 'boolean' },
|
||||
hcaptchaSiteKey: { type: 'string', nullable: true },
|
||||
hcaptchaSecretKey: { type: 'string', nullable: true },
|
||||
@@ -357,6 +359,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
set.approvalRequiredForSignup = ps.approvalRequiredForSignup;
|
||||
}
|
||||
|
||||
if (ps.registrationWord !== undefined) {
|
||||
set.registrationWord = ps.registrationWord;
|
||||
}
|
||||
|
||||
if (ps.regWordRequired !== undefined) {
|
||||
set.regWordRequired = ps.regWordRequired;
|
||||
}
|
||||
|
||||
if (ps.enableHcaptcha !== undefined) {
|
||||
set.enableHcaptcha = ps.enableHcaptcha;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkInput v-if="instance.approvalRequiredForSignup" v-model="reason" type="text" :spellcheck="false" required data-cy-signup-reason>
|
||||
<template #label>Reason <div v-tooltip:dialog="i18n.ts._signup.reasonInfo" class="_button _help"><i class="ph-question ph-bold ph-lg"></i></div></template>
|
||||
<template #prefix><i class="ph-chalkboard-teacher ph-bold ph-lg"></i></template>
|
||||
<template #caption>
|
||||
<span v-if="instance.regWordRequired && !reason.includes(instance.registrationWord)" style="color: var(--MI_THEME-error)">
|
||||
<i class="ti ti-alert-triangle ti-fw"></i> Registration word is required
|
||||
</span>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="instance.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="instance.mcaptchaSiteKey" :instanceUrl="instance.mcaptchaInstanceUrl"/>
|
||||
@@ -149,7 +154,8 @@ const shouldDisableSubmitting = computed((): boolean => {
|
||||
instance.enableTestcaptcha && !testcaptchaResponse.value ||
|
||||
instance.emailRequiredForSignup && emailState.value !== 'ok' ||
|
||||
usernameState.value !== 'ok' ||
|
||||
passwordRetypeState.value !== 'match';
|
||||
passwordRetypeState.value !== 'match' ||
|
||||
(instance.regWordRequired && !reason.value.includes(instance.registrationWord));
|
||||
});
|
||||
|
||||
function getPasswordStrength(source: string): number {
|
||||
|
||||
@@ -4,91 +4,117 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||
<div class="_spacer" style="--MI_SPACER-w: 700px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
|
||||
<div class="_gaps_m">
|
||||
<MkFolder v-if="meta.federation !== 'none'">
|
||||
<template #label>{{ i18n.ts.authorizedFetchSection }}</template>
|
||||
<template #suffix>{{ meta.allowUnsignedFetch !== 'always' ? i18n.ts.enabled : i18n.ts.disabled }}</template>
|
||||
<template v-if="authFetchForm.modified.value" #footer>
|
||||
<MkFormFooter :form="authFetchForm"/>
|
||||
</template>
|
||||
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||
<div class="_spacer" style="--MI_SPACER-w: 700px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;">
|
||||
<div class="_gaps_m">
|
||||
<MkFolder v-if="meta.federation !== 'none'">
|
||||
<template #label>{{ i18n.ts.authorizedFetchSection }}</template>
|
||||
<template #suffix>{{ meta.allowUnsignedFetch !== 'always' ? i18n.ts.enabled : i18n.ts.disabled
|
||||
}}</template>
|
||||
<template v-if="authFetchForm.modified.value" #footer>
|
||||
<MkFormFooter :form="authFetchForm" />
|
||||
</template>
|
||||
|
||||
<MkRadios v-model="authFetchForm.state.allowUnsignedFetch">
|
||||
<template #label>{{ i18n.ts.authorizedFetchLabel }}</template>
|
||||
<template #caption>{{ i18n.ts.authorizedFetchDescription }}</template>
|
||||
<option value="never">{{ i18n.ts._authorizedFetchValue.never }} - {{ i18n.ts._authorizedFetchValueDescription.never }}</option>
|
||||
<option value="always">{{ i18n.ts._authorizedFetchValue.always }} - {{ i18n.ts._authorizedFetchValueDescription.always }}</option>
|
||||
<option value="essential">{{ i18n.ts._authorizedFetchValue.essential }} - {{ i18n.ts._authorizedFetchValueDescription.essential }}</option>
|
||||
</MkRadios>
|
||||
</MkFolder>
|
||||
<MkRadios v-model="authFetchForm.state.allowUnsignedFetch">
|
||||
<template #label>{{ i18n.ts.authorizedFetchLabel }}</template>
|
||||
<template #caption>{{ i18n.ts.authorizedFetchDescription }}</template>
|
||||
<option value="never">{{ i18n.ts._authorizedFetchValue.never }} - {{
|
||||
i18n.ts._authorizedFetchValueDescription.never
|
||||
}}</option>
|
||||
<option value="always">{{ i18n.ts._authorizedFetchValue.always }} - {{
|
||||
i18n.ts._authorizedFetchValueDescription.always }}</option>
|
||||
<option value="essential">{{ i18n.ts._authorizedFetchValue.essential }} - {{
|
||||
i18n.ts._authorizedFetchValueDescription.essential }}</option>
|
||||
</MkRadios>
|
||||
</MkFolder>
|
||||
|
||||
<XBotProtection/>
|
||||
<XBotProtection />
|
||||
|
||||
<MkFolder>
|
||||
<template #label>Active Email Validation</template>
|
||||
<template v-if="emailValidationForm.savedState.enableActiveEmailValidation" #suffix>Enabled</template>
|
||||
<template v-else #suffix>Disabled</template>
|
||||
<template v-if="emailValidationForm.modified.value" #footer>
|
||||
<MkFormFooter :form="emailValidationForm"/>
|
||||
</template>
|
||||
<MkFolder>
|
||||
<template #label>Active Email Validation</template>
|
||||
<template v-if="emailValidationForm.savedState.enableActiveEmailValidation"
|
||||
#suffix>Enabled</template>
|
||||
<template v-else #suffix>Disabled</template>
|
||||
<template v-if="emailValidationForm.modified.value" #footer>
|
||||
<MkFormFooter :form="emailValidationForm" />
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<span>{{ i18n.ts.activeEmailValidationDescription }}</span>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableActiveEmailValidation">
|
||||
<template #label>Enable</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableVerifymailApi">
|
||||
<template #label>Use Verifymail.io API</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="emailValidationForm.state.verifymailAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Verifymail.io API Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableTruemailApi">
|
||||
<template #label>Use TrueMail API</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="emailValidationForm.state.truemailInstance">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>TrueMail API Instance</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="emailValidationForm.state.truemailAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>TrueMail API Auth Key</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<div class="_gaps_m">
|
||||
<span>{{ i18n.ts.activeEmailValidationDescription }}</span>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableActiveEmailValidation">
|
||||
<template #label>Enable</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableVerifymailApi">
|
||||
<template #label>Use Verifymail.io API</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="emailValidationForm.state.verifymailAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Verifymail.io API Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableTruemailApi">
|
||||
<template #label>Use TrueMail API</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="emailValidationForm.state.truemailInstance">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>TrueMail API Instance</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="emailValidationForm.state.truemailAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>TrueMail API Auth Key</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #label>Banned Email Domains</template>
|
||||
<template v-if="bannedEmailDomainsForm.modified.value" #footer>
|
||||
<MkFormFooter :form="bannedEmailDomainsForm"/>
|
||||
</template>
|
||||
<MkFolder>
|
||||
<template #label>Banned Email Domains</template>
|
||||
<template v-if="bannedEmailDomainsForm.modified.value" #footer>
|
||||
<MkFormFooter :form="bannedEmailDomainsForm" />
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkTextarea v-model="bannedEmailDomainsForm.state.bannedEmailDomains">
|
||||
<template #label>Banned Email Domains List</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<div class="_gaps_m">
|
||||
<MkTextarea v-model="bannedEmailDomainsForm.state.bannedEmailDomains">
|
||||
<template #label>Banned Email Domains List</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #label>Log IP address</template>
|
||||
<template v-if="ipLoggingForm.savedState.enableIpLogging" #suffix>Enabled</template>
|
||||
<template v-else #suffix>Disabled</template>
|
||||
<template v-if="ipLoggingForm.modified.value" #footer>
|
||||
<MkFormFooter :form="ipLoggingForm"/>
|
||||
</template>
|
||||
<MkFolder>
|
||||
<template #label>Log IP address</template>
|
||||
<template v-if="ipLoggingForm.savedState.enableIpLogging" #suffix>Enabled</template>
|
||||
<template v-else #suffix>Disabled</template>
|
||||
<template v-if="ipLoggingForm.modified.value" #footer>
|
||||
<MkFormFooter :form="ipLoggingForm" />
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkSwitch v-model="ipLoggingForm.state.enableIpLogging">
|
||||
<template #label>Enable</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<div class="_gaps_m">
|
||||
<MkSwitch v-model="ipLoggingForm.state.enableIpLogging">
|
||||
<template #label>Enable</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #label>Registration Word</template>
|
||||
<template v-if="regWordForm.savedState.regWordRequired" #suffix>Enabled</template>
|
||||
<template v-else #suffix>Disabled</template>
|
||||
<template v-if="regWordForm.modified.value" #footer>
|
||||
<MkFormFooter :form="regWordForm" />
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkSwitch v-model="regWordForm.state.regWordRequired">
|
||||
<template #label>Enable</template>
|
||||
<template #caption>Require user to input a special registration word</template>
|
||||
</MkSwitch>
|
||||
<MkInput v-model="regWordForm.state.registrationWord">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Registration Word</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageWithHeader>
|
||||
</PageWithHeader>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -128,6 +154,17 @@ const ipLoggingForm = useForm({
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
||||
const regWordForm = useForm({
|
||||
regWordRequired: meta.regWordRequired,
|
||||
registrationWord: meta.registrationWord,
|
||||
}, async (state) => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
regWordRequired: state.regWordRequired,
|
||||
registrationWord: state.registrationWord,
|
||||
});
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
||||
const emailValidationForm = useForm({
|
||||
enableActiveEmailValidation: meta.enableActiveEmailValidation,
|
||||
enableVerifymailApi: meta.enableVerifymailApi,
|
||||
|
||||
Reference in New Issue
Block a user