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:
Thomas Citharel
2023-01-31 19:35:29 +01:00
parent 1db5c4ae2d
commit 317a3434b2
83 changed files with 7186 additions and 2394 deletions

View File

@@ -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 {

View File

@@ -120,7 +120,6 @@ const confirm = () => {
return;
}
}
emit("confirm", prompt.value);
props.onConfirm(prompt.value);
close();
};

View File

@@ -366,6 +366,7 @@ export const FEATURES = gql`
features {
groups
eventCreation
antispam
}
}
}

View File

@@ -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
}
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -97,6 +97,7 @@ export interface IConfig {
features: {
eventCreation: boolean;
groups: boolean;
antispam: boolean;
};
restrictions: {
onlyAdminCanCreateGroups: boolean;

View File

@@ -291,3 +291,8 @@ export enum SearchTargets {
INTERNAL = "INTERNAL",
GLOBAL = "GLOBAL",
}
export enum AntiSpamFeedback {
HAM = "HAM",
SPAM = "SPAM",
}

View File

@@ -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>

View File

@@ -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
);
});