feat(spam): Introduce checking new accounts, events & comments for spam with the help of Akismet
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -16,23 +16,6 @@ body {
|
||||
.btn-rounded {
|
||||
@apply rounded-full;
|
||||
}
|
||||
.btn-outlined-,
|
||||
.btn-outlined-primary {
|
||||
@apply bg-transparent text-black dark:text-white font-semibold py-2 px-4 border border-mbz-bluegreen dark:border-violet-3;
|
||||
}
|
||||
.btn-outlined-success {
|
||||
@apply border-mbz-success;
|
||||
}
|
||||
.btn-outlined-danger {
|
||||
@apply border-mbz-danger;
|
||||
}
|
||||
.btn-outlined-warning {
|
||||
@apply border-mbz-warning;
|
||||
}
|
||||
.btn-outlined-:hover,
|
||||
.btn-outlined-primary:hover {
|
||||
@apply font-bold py-2 px-4 bg-mbz-bluegreen dark:bg-violet-3 text-white rounded;
|
||||
}
|
||||
.btn-size-large {
|
||||
@apply text-2xl py-6;
|
||||
}
|
||||
@@ -54,6 +37,26 @@ body {
|
||||
.btn-text {
|
||||
@apply bg-transparent border-transparent text-black dark:text-white font-normal underline hover:bg-zinc-200 hover:text-black;
|
||||
}
|
||||
.btn-outlined-,
|
||||
.btn-outlined-primary {
|
||||
@apply bg-transparent text-black dark:text-white font-semibold py-2 px-4 border border-mbz-bluegreen dark:border-violet-3;
|
||||
}
|
||||
.btn-outlined-success {
|
||||
@apply border-mbz-success;
|
||||
}
|
||||
.btn-outlined-warning {
|
||||
@apply bg-transparent border dark:text-white hover:dark:text-slate-900 hover:bg-mbz-warning border-mbz-warning;
|
||||
}
|
||||
.btn-outlined-danger {
|
||||
@apply border-mbz-danger;
|
||||
}
|
||||
.btn-outlined-text {
|
||||
@apply bg-transparent hover:text-slate-900;
|
||||
}
|
||||
.btn-outlined-:hover,
|
||||
.btn-outlined-primary:hover {
|
||||
@apply font-bold py-2 px-4 bg-mbz-bluegreen dark:bg-violet-3 text-white rounded;
|
||||
}
|
||||
|
||||
/* Field */
|
||||
.field {
|
||||
|
||||
@@ -120,7 +120,6 @@ const confirm = () => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
emit("confirm", prompt.value);
|
||||
props.onConfirm(prompt.value);
|
||||
close();
|
||||
};
|
||||
|
||||
@@ -366,6 +366,7 @@ export const FEATURES = gql`
|
||||
features {
|
||||
groups
|
||||
eventCreation
|
||||
antispam
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +116,16 @@ export const CREATE_REPORT = gql`
|
||||
`;
|
||||
|
||||
export const UPDATE_REPORT = gql`
|
||||
mutation UpdateReport($reportId: ID!, $status: ReportStatus!) {
|
||||
updateReportStatus(reportId: $reportId, status: $status) {
|
||||
mutation UpdateReport(
|
||||
$reportId: ID!
|
||||
$status: ReportStatus!
|
||||
$antispamFeedback: AntiSpamFeedback
|
||||
) {
|
||||
updateReportStatus(
|
||||
reportId: $reportId
|
||||
status: $status
|
||||
antispamFeedback: $antispamFeedback
|
||||
) {
|
||||
...ReportFragment
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1448,5 +1448,10 @@
|
||||
"Select this resource": "Select this resource",
|
||||
"You can add resources by using the button above.": "You can add resources by using the button above.",
|
||||
"{user}'s follow request was accepted": "{user}'s follow request was accepted",
|
||||
"{user}'s follow request was rejected": "{user}'s follow request was rejected"
|
||||
"{user}'s follow request was rejected": "{user}'s follow request was rejected",
|
||||
"Report as spam": "Report as spam",
|
||||
"Report as ham": "Report as ham",
|
||||
"Report as undetected spam": "Report as undetected spam",
|
||||
"The report contents (eventual comments and event) and the reported profile details will be transmitted to Akismet.": "The report contents (eventual comments and event) and the reported profile details will be transmitted to Akismet.",
|
||||
"Submit to Akismet": "Submit to Akismet"
|
||||
}
|
||||
@@ -1445,5 +1445,10 @@
|
||||
"Select this resource": "Sélectionner cette ressource",
|
||||
"You can add resources by using the button above.": "Vous pouvez ajouter des ressources en utilisant le bouton au dessus.",
|
||||
"{user}'s follow request was accepted": "La demande de suivi de {user} a été acceptée",
|
||||
"{user}'s follow request was rejected": "La demande de suivi de {user} a été rejetée"
|
||||
"{user}'s follow request was rejected": "La demande de suivi de {user} a été rejetée",
|
||||
"Report as spam": "Signaler comme spam",
|
||||
"Report as ham": "Signaler comme faux positif",
|
||||
"Report as undetected spam": "Signaler comme spam non détecté",
|
||||
"The report contents (eventual comments and event) and the reported profile details will be transmitted to Akismet.": "Les contenus du signalement (les éventuels commentaires et événement) et les détails du profil signalé seront transmis à Akismet.",
|
||||
"Submit to Akismet": "Envoyer à Akismet"
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ export interface IConfig {
|
||||
features: {
|
||||
eventCreation: boolean;
|
||||
groups: boolean;
|
||||
antispam: boolean;
|
||||
};
|
||||
restrictions: {
|
||||
onlyAdminCanCreateGroups: boolean;
|
||||
|
||||
@@ -291,3 +291,8 @@ export enum SearchTargets {
|
||||
INTERNAL = "INTERNAL",
|
||||
GLOBAL = "GLOBAL",
|
||||
}
|
||||
|
||||
export enum AntiSpamFeedback {
|
||||
HAM = "HAM",
|
||||
SPAM = "SPAM",
|
||||
}
|
||||
|
||||
@@ -45,6 +45,20 @@
|
||||
variant="danger"
|
||||
>{{ t("Close") }}</o-button
|
||||
>
|
||||
<o-button
|
||||
outlined
|
||||
@click="reportToAntispam(true)"
|
||||
variant="text"
|
||||
class="!text-mbz-danger"
|
||||
>{{ t("Report as spam") }}</o-button
|
||||
>
|
||||
<o-button
|
||||
outlined
|
||||
@click="reportToAntispam(false)"
|
||||
variant="text"
|
||||
class="!text-mbz-success"
|
||||
>{{ t("Report as ham") }}</o-button
|
||||
>
|
||||
</div>
|
||||
<section class="w-full">
|
||||
<table class="table w-full">
|
||||
@@ -305,7 +319,7 @@ import uniq from "lodash/uniq";
|
||||
import { nl2br } from "@/utils/html";
|
||||
import { DELETE_COMMENT } from "@/graphql/comment";
|
||||
import { IComment } from "@/types/comment.model";
|
||||
import { ActorType, ReportStatusEnum } from "@/types/enums";
|
||||
import { ActorType, AntiSpamFeedback, ReportStatusEnum } from "@/types/enums";
|
||||
import RouteName from "@/router/name";
|
||||
import { GraphQLError } from "graphql";
|
||||
import { ApolloCache, FetchResult } from "@apollo/client/core";
|
||||
@@ -320,6 +334,7 @@ import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import { Dialog } from "@/plugins/dialog";
|
||||
import { Notifier } from "@/plugins/notifier";
|
||||
import EventCard from "@/components/Event/EventCard.vue";
|
||||
import { useFeatures } from "@/composition/apollo/config";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -327,6 +342,10 @@ const props = defineProps<{ reportId: string }>();
|
||||
|
||||
const { currentActor } = useCurrentActorClient();
|
||||
|
||||
const { features } = useFeatures();
|
||||
|
||||
const antispamEnabled = computed(() => features.value?.antispam);
|
||||
|
||||
const { result: reportResult, onError: onReportQueryError } = useQuery<{
|
||||
report: IReport;
|
||||
}>(REPORT, () => ({
|
||||
@@ -467,7 +486,14 @@ const {
|
||||
mutate: updateReportMutation,
|
||||
onDone: onUpdateReportMutation,
|
||||
onError: onUpdateReportError,
|
||||
} = useMutation(UPDATE_REPORT, () => ({
|
||||
} = useMutation<
|
||||
Record<string, any>,
|
||||
{
|
||||
reportId: string;
|
||||
status: ReportStatusEnum;
|
||||
antispamFeedback?: AntiSpamFeedback;
|
||||
}
|
||||
>(UPDATE_REPORT, () => ({
|
||||
update: (
|
||||
store: ApolloCache<{ updateReportStatus: IReport }>,
|
||||
{ data }: FetchResult
|
||||
@@ -505,9 +531,32 @@ onUpdateReportError((error) => {
|
||||
});
|
||||
|
||||
const updateReport = async (status: ReportStatusEnum): Promise<void> => {
|
||||
updateReportMutation({
|
||||
reportId: report.value?.id,
|
||||
status,
|
||||
if (report.value) {
|
||||
updateReportMutation({
|
||||
reportId: report.value?.id,
|
||||
status,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const reportToAntispam = (spam: boolean) => {
|
||||
dialog?.confirm({
|
||||
title: spam ? t("Report as undetected spam") : t("Report as ham"),
|
||||
message: t(
|
||||
"The report contents (eventual comments and event) and the reported profile details will be transmitted to Akismet."
|
||||
),
|
||||
confirmText: t("Submit to Akismet"),
|
||||
variant: "warning",
|
||||
hasIcon: true,
|
||||
onConfirm: () => {
|
||||
if (report.value) {
|
||||
updateReportMutation({
|
||||
reportId: report.value.id,
|
||||
status: report.value.status,
|
||||
antispamFeedback: spam ? AntiSpamFeedback.SPAM : AntiSpamFeedback.HAM,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
>
|
||||
{{ error }}
|
||||
</o-notification>
|
||||
<form @submit="loginAction" v-if="config?.auth.databaseLogin">
|
||||
<form @submit="loginAction" v-if="config?.auth?.databaseLogin">
|
||||
<o-field
|
||||
:label="t('Email')"
|
||||
label-for="email"
|
||||
@@ -116,7 +116,7 @@
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
<div v-if="config && config?.auth.oauthProviders.length > 0">
|
||||
<div v-if="config && config?.auth?.oauthProviders?.length > 0">
|
||||
<auth-providers :oauthProviders="config.auth.oauthProviders" />
|
||||
</div>
|
||||
</section>
|
||||
@@ -169,7 +169,7 @@ const config = computed(() => configResult.value?.config);
|
||||
const canRegister = computed(() => {
|
||||
return (
|
||||
(config.value?.registrationsOpen || config.value?.registrationsAllowlist) &&
|
||||
config.value?.auth.databaseLogin
|
||||
config.value?.auth?.databaseLogin
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user