Remove ReviewDB

abuse / harassment has gotten pretty bad.
i proposed the ability to allow users to delete comments from their own
profile, but there seems to be no interest among the reviewdb owners.

i don't want vencord to harbour harassment, so i'm removing the plugin
for now
This commit is contained in:
V 2023-10-09 03:09:56 +02:00
parent 377cf60055
commit 390987e4a9
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
12 changed files with 0 additions and 1238 deletions

View file

@ -1,61 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { DeleteIcon } from "@components/Icons";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { Tooltip } from "@webpack/common";
const iconClasses = findByPropsLazy("button", "wrapper", "disabled", "separator");
export function DeleteButton({ onClick }: { onClick(): void; }) {
return (
<Tooltip text="Delete Review">
{props => (
<div
{...props}
className={classes(iconClasses.button, iconClasses.dangerous)}
onClick={onClick}
>
<DeleteIcon width="20" height="20" />
</div>
)}
</Tooltip>
);
}
export function ReportButton({ onClick }: { onClick(): void; }) {
return (
<Tooltip text="Report Review">
{props => (
<div
{...props}
className={iconClasses.button}
onClick={onClick}
>
<svg width="20" height="20" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M20,6.002H14V3.002C14,2.45 13.553,2.002 13,2.002H4C3.447,2.002 3,2.45 3,3.002V22.002H5V14.002H10.586L8.293,16.295C8.007,16.581 7.922,17.011 8.076,17.385C8.23,17.759 8.596,18.002 9,18.002H20C20.553,18.002 21,17.554 21,17.002V7.002C21,6.45 20.553,6.002 20,6.002Z"
/>
</svg>
</div>
)}
</Tooltip>
);
}

View file

@ -1,46 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { MaskedLinkStore, Tooltip } from "@webpack/common";
import { Badge } from "../entities";
import { cl } from "../utils";
export default function ReviewBadge(badge: Badge) {
return (
<Tooltip
text={badge.name}>
{({ onMouseEnter, onMouseLeave }) => (
<img
className={cl("badge")}
width="22px"
height="22px"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
src={badge.icon}
alt={badge.description}
onClick={() =>
MaskedLinkStore.openUntrustedLink({
href: badge.redirectURL,
})
}
/>
)}
</Tooltip>
);
}

View file

@ -1,147 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { openUserProfile } from "@utils/discord";
import { classes } from "@utils/misc";
import { LazyComponent } from "@utils/react";
import { filters, findBulk } from "@webpack";
import { Alerts, moment, Parser, showToast, Timestamp } from "@webpack/common";
import { Review, ReviewType } from "../entities";
import { deleteReview, reportReview } from "../reviewDbApi";
import { settings } from "../settings";
import { canDeleteReview, cl } from "../utils";
import { DeleteButton, ReportButton } from "./MessageButton";
import ReviewBadge from "./ReviewBadge";
export default LazyComponent(() => {
// this is terrible, blame mantika
const p = filters.byProps;
const [
{ cozyMessage, buttons, message, buttonsInner, groupStart },
{ container, isHeader },
{ avatar, clickable, username, wrapper, cozy },
buttonClasses,
botTag
] = findBulk(
p("cozyMessage"),
p("container", "isHeader"),
p("avatar", "zalgo"),
p("button", "wrapper", "selected"),
p("botTag", "botTagRegular")
);
const dateFormat = new Intl.DateTimeFormat();
return function ReviewComponent({ review, refetch, profileId }: { review: Review; refetch(): void; profileId: string; }) {
function openModal() {
openUserProfile(review.sender.discordID);
}
function delReview() {
Alerts.show({
title: "Are you sure?",
body: "Do you really want to delete this review?",
confirmText: "Delete",
cancelText: "Nevermind",
onConfirm: () => {
deleteReview(review.id).then(res => {
if (res.success) {
refetch();
}
showToast(res.message);
});
}
});
}
function reportRev() {
Alerts.show({
title: "Are you sure?",
body: "Do you really you want to report this review?",
confirmText: "Report",
cancelText: "Nevermind",
// confirmColor: "red", this just adds a class name and breaks the submit button guh
onConfirm: () => reportReview(review.id)
});
}
return (
<div className={classes(cozyMessage, wrapper, message, groupStart, cozy, cl("review"))} style={
{
marginLeft: "0px",
paddingLeft: "52px", // wth is this
paddingRight: "16px"
}
}>
<img
className={classes(avatar, clickable)}
onClick={openModal}
src={review.sender.profilePhoto || "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"}
style={{ left: "0px", zIndex: 0 }}
/>
<div style={{ display: "inline-flex", justifyContent: "center", alignItems: "center" }}>
<span
className={classes(clickable, username)}
style={{ color: "var(--channels-default)", fontSize: "14px" }}
onClick={() => openModal()}
>
{review.sender.username}
</span>
{review.type === ReviewType.System && (
<span
className={classes(botTag.botTagVerified, botTag.botTagRegular, botTag.botTag, botTag.px, botTag.rem)}
style={{ marginLeft: "4px" }}>
<span className={botTag.botText}>
System
</span>
</span>
)}
</div>
{review.sender.badges.map(badge => <ReviewBadge {...badge} />)}
{
!settings.store.hideTimestamps && review.type !== ReviewType.System && (
<Timestamp timestamp={moment(review.timestamp * 1000)} >
{dateFormat.format(review.timestamp * 1000)}
</Timestamp>)
}
<div className={cl("review-comment")}>
{Parser.parseGuildEventDescription(review.comment)}
</div>
{review.id !== 0 && (
<div className={classes(container, isHeader, buttons)} style={{
padding: "0px",
}}>
<div className={classes(buttonClasses.wrapper, buttonsInner)} >
<ReportButton onClick={reportRev} />
{canDeleteReview(profileId, review) && (
<DeleteButton onClick={delReview} />
)}
</div>
</div>
)}
</div>
);
};
});

View file

@ -1,105 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import ErrorBoundary from "@components/ErrorBoundary";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { useForceUpdater } from "@utils/react";
import { Paginator, Text, useRef, useState } from "@webpack/common";
import { Auth } from "../auth";
import { Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
import { cl } from "../utils";
import ReviewComponent from "./ReviewComponent";
import ReviewsView, { ReviewsInputComponent } from "./ReviewsView";
function Modal({ modalProps, discordId, name }: { modalProps: any; discordId: string; name: string; }) {
const [data, setData] = useState<Response>();
const [signal, refetch] = useForceUpdater(true);
const [page, setPage] = useState(1);
const ref = useRef<HTMLDivElement>(null);
const reviewCount = data?.reviewCount;
const ownReview = data?.reviews.find(r => r.sender.discordID === Auth.user?.discordID);
return (
<ErrorBoundary>
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
<ModalHeader>
<Text variant="heading-lg/semibold" className={cl("modal-header")}>
{name}'s Reviews
{!!reviewCount && <span> ({reviewCount} Reviews)</span>}
</Text>
<ModalCloseButton onClick={modalProps.onClose} />
</ModalHeader>
<ModalContent scrollerRef={ref}>
<div className={cl("modal-reviews")}>
<ReviewsView
discordId={discordId}
name={name}
page={page}
refetchSignal={signal}
onFetchReviews={setData}
scrollToTop={() => ref.current?.scrollTo({ top: 0, behavior: "smooth" })}
hideOwnReview
/>
</div>
</ModalContent>
<ModalFooter className={cl("modal-footer")}>
<div>
{ownReview && (
<ReviewComponent
refetch={refetch}
review={ownReview}
profileId={discordId}
/>
)}
<ReviewsInputComponent
isAuthor={ownReview != null}
discordId={discordId}
name={name}
refetch={refetch}
/>
{!!reviewCount && (
<Paginator
currentPage={page}
maxVisiblePages={5}
pageSize={REVIEWS_PER_PAGE}
totalCount={reviewCount}
onPageChange={setPage}
/>
)}
</div>
</ModalFooter>
</ModalRoot>
</ErrorBoundary>
);
}
export function openReviewsModal(discordId: string, name: string) {
openModal(props => (
<Modal
modalProps={props}
discordId={discordId}
name={name}
/>
));
}

View file

@ -1,200 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { LazyComponent, useAwaiter, useForceUpdater } from "@utils/react";
import { find, findByPropsLazy } from "@webpack";
import { Forms, React, RelationshipStore, showToast, useRef, UserStore } from "@webpack/common";
import { Auth, authorize } from "../auth";
import { Review } from "../entities";
import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
import { settings } from "../settings";
import { cl } from "../utils";
import ReviewComponent from "./ReviewComponent";
const Editor = findByPropsLazy("start", "end", "addMark");
const Transform = findByPropsLazy("unwrapNodes");
const InputTypes = findByPropsLazy("VOICE_CHANNEL_STATUS", "SIDEBAR");
const InputComponent = LazyComponent(() => find(m => m?.type?.render?.toString().includes("CHANNEL_TEXT_AREA).AnalyticsLocationProvider")));
interface UserProps {
discordId: string;
name: string;
}
interface Props extends UserProps {
onFetchReviews(data: Response): void;
refetchSignal?: unknown;
showInput?: boolean;
page?: number;
scrollToTop?(): void;
hideOwnReview?: boolean;
}
export default function ReviewsView({
discordId,
name,
onFetchReviews,
refetchSignal,
scrollToTop,
page = 1,
showInput = false,
hideOwnReview = false,
}: Props) {
const [signal, refetch] = useForceUpdater(true);
const [reviewData] = useAwaiter(() => getReviews(discordId, (page - 1) * REVIEWS_PER_PAGE), {
fallbackValue: null,
deps: [refetchSignal, signal, page],
onSuccess: data => {
if (settings.store.hideBlockedUsers)
data!.reviews = data!.reviews?.filter(r => !RelationshipStore.isBlocked(r.sender.discordID));
scrollToTop?.();
onFetchReviews(data!);
}
});
if (!reviewData) return null;
return (
<>
<ReviewList
refetch={refetch}
reviews={reviewData!.reviews}
hideOwnReview={hideOwnReview}
profileId={discordId}
/>
{showInput && (
<ReviewsInputComponent
name={name}
discordId={discordId}
refetch={refetch}
isAuthor={reviewData!.reviews?.some(r => r.sender.discordID === UserStore.getCurrentUser().id)}
/>
)}
</>
);
}
function ReviewList({ refetch, reviews, hideOwnReview, profileId }: { refetch(): void; reviews: Review[]; hideOwnReview: boolean; profileId: string; }) {
const myId = UserStore.getCurrentUser().id;
return (
<div className={cl("view")}>
{reviews?.map(review =>
(review.sender.discordID !== myId || !hideOwnReview) &&
<ReviewComponent
key={review.id}
review={review}
refetch={refetch}
profileId={profileId}
/>
)}
{reviews?.length === 0 && (
<Forms.FormText className={cl("placeholder")}>
Looks like nobody reviewed this user yet. You could be the first!
</Forms.FormText>
)}
</div>
);
}
export function ReviewsInputComponent({ discordId, isAuthor, refetch, name }: { discordId: string, name: string; isAuthor: boolean; refetch(): void; }) {
const { token } = Auth;
const editorRef = useRef<any>(null);
const inputType = InputTypes.FORM;
inputType.disableAutoFocus = true;
const channel = {
flags_: 256,
guild_id_: null,
id: "0",
getGuildId: () => null,
isPrivate: () => true,
isActiveThread: () => false,
isArchivedLockedThread: () => false,
isDM: () => true,
roles: { "0": { permissions: 0n } },
getRecipientId: () => "0",
hasFlag: () => false,
};
return (
<>
<div onClick={() => {
if (!token) {
showToast("Opening authorization window...");
authorize();
}
}}>
<InputComponent
className={cl("input")}
channel={channel}
placeholder={
!token
? "You need to authorize to review users!"
: isAuthor
? `Update review for @${name}`
: `Review @${name}`
}
type={inputType}
disableThemedBackground={true}
setEditorRef={ref => editorRef.current = ref}
textValue=""
onSubmit={
async res => {
const response = await addReview({
userid: discordId,
comment: res.value,
});
if (response?.success) {
refetch();
const slateEditor = editorRef.current.ref.current.getSlateEditor();
// clear editor
Transform.delete(slateEditor, {
at: {
anchor: Editor.start(slateEditor, []),
focus: Editor.end(slateEditor, []),
}
});
} else if (response?.message) {
showToast(response.message);
}
// even tho we need to return this, it doesnt do anything
return {
shouldClear: false,
shouldRefocus: true,
};
}
}
/>
</div>
</>
);
}