1
0
Fork 0

feat: edit report notes; unify card links

fix-1
Paul Makles 2023-07-28 14:29:46 +01:00
parent 9f5de75d26
commit 3a246a7052
No known key found for this signature in database
GPG Key ID: 5059F398521BB0F6
15 changed files with 216 additions and 125 deletions

View File

@ -22,7 +22,7 @@ export default async function Message({
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<NavigationToolbar>Inspecting Message</NavigationToolbar> <NavigationToolbar>Inspecting Message</NavigationToolbar>
<Card className="shadow-none"> <Card>
<CardHeader> <CardHeader>
<p>{message.content}</p> <p>{message.content}</p>
</CardHeader> </CardHeader>

View File

@ -3,25 +3,10 @@ import { MessageContextCard } from "@/components/cards/MessageContextCard";
import { ReportCard } from "@/components/cards/ReportCard"; import { ReportCard } from "@/components/cards/ReportCard";
import { ServerCard } from "@/components/cards/ServerCard"; import { ServerCard } from "@/components/cards/ServerCard";
import { UserCard } from "@/components/cards/UserCard"; import { UserCard } from "@/components/cards/UserCard";
import { CardLink } from "@/components/common/CardLink";
import { NavigationToolbar } from "@/components/common/NavigationToolbar"; import { NavigationToolbar } from "@/components/common/NavigationToolbar";
import { Badge } from "@/components/ui/badge"; import { ReportActions } from "@/components/inspector/ReportActions";
import { Button, buttonVariants } from "@/components/ui/button";
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { Textarea } from "@/components/ui/textarea";
import { import {
fetchReportById, fetchReportById,
fetchReports, fetchReports,
@ -56,51 +41,8 @@ export default async function Reports({ params }: { params: { id: string } }) {
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<NavigationToolbar>Viewing Report</NavigationToolbar> <NavigationToolbar>Viewing Report</NavigationToolbar>
<ReportCard report={report} />
<Card className="shadow-none"> <ReportActions report={report} />
<CardHeader>
<CardTitle className="overflow-ellipsis whitespace-nowrap overflow-x-clip flex gap-2 items-center">
{report.content.report_reason.includes("Illegal") && (
<Badge variant="destructive">Urgent</Badge>
)}{" "}
{report.additional_context || "No reason specified"}
</CardTitle>
<CardDescription>
{report._id.toString().substring(20, 26)} &middot;{" "}
{report.content.report_reason} &middot; {report.content.type}
</CardDescription>
</CardHeader>
</Card>
<Textarea
placeholder="Enter notes here..."
className="!min-h-0 !h-[76px]"
/>
<div className="flex gap-2">
<Button className="flex-1 bg-green-400 hover:bg-green-300">
Resolve
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="flex-1 bg-red-400 hover:bg-red-300">
Reject
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Custom Reason</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Presets</DropdownMenuLabel>
<DropdownMenuItem>Invalid</DropdownMenuItem>
<DropdownMenuItem>False or Spam</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuItem>Not Enough Evidence</DropdownMenuItem>
<DropdownMenuItem>Request Clarification</DropdownMenuItem>
<DropdownMenuItem>Acknowledge Only</DropdownMenuItem>
<DropdownMenuItem>Ignore</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<Link href={`/panel/inspect/user/${author!._id}`}> <Link href={`/panel/inspect/user/${author!._id}`}>
<UserCard user={author!} subtitle="Report Author" /> <UserCard user={author!} subtitle="Report Author" />
@ -132,7 +74,12 @@ export default async function Reports({ params }: { params: { id: string } }) {
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h2 className="text-md text-center pb-2">Other Reports</h2> <h2 className="text-md text-center pb-2">Other Reports</h2>
{relatedReports[index].map((relatedReport) => ( {relatedReports[index].map((relatedReport) => (
<ReportCard key={relatedReport._id} report={relatedReport} /> <CardLink
key={relatedReport._id}
href={`/panel/reports/${relatedReport._id}`}
>
<ReportCard report={relatedReport} />
</CardLink>
))} ))}
</div> </div>
) : undefined} ) : undefined}

View File

@ -1,4 +1,5 @@
import { ReportCard } from "@/components/cards/ReportCard"; import { ReportCard } from "@/components/cards/ReportCard";
import { CardLink } from "@/components/common/CardLink";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { fetchReports } from "@/lib/db"; import { fetchReports } from "@/lib/db";
@ -11,7 +12,9 @@ export default async function Reports() {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Input placeholder="Search for reports..." disabled /> <Input placeholder="Search for reports..." disabled />
{reports.map((report) => ( {reports.map((report) => (
<ReportCard key={report._id} report={report} /> <CardLink key={report._id} href={`/panel/reports/${report._id}`}>
<ReportCard report={report} />
</CardLink>
))} ))}
</div> </div>
); );

View File

@ -1,7 +1,6 @@
import { Channel } from "revolt-api"; import { Channel } from "revolt-api";
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
import Link from "next/link";
import { AUTUMN_URL } from "@/lib/constants"; import { AUTUMN_URL } from "@/lib/constants";
export function ChannelCard({ export function ChannelCard({
@ -18,14 +17,12 @@ export function ChannelCard({
channel.channel_type === "DirectMessage" ? "Direct Message" : channel.name; channel.channel_type === "DirectMessage" ? "Direct Message" : channel.name;
return ( return (
<Card className="shadow-none"> <Card>
<CardHeader> <CardHeader>
<CardTitle> <CardTitle>
<Avatar> <Avatar>
{channel.channel_type !== "DirectMessage" && ( {channel.channel_type !== "DirectMessage" && (
<AvatarImage <AvatarImage src={`${AUTUMN_URL}/icons/${channel.icon?._id}`} />
src={`${AUTUMN_URL}/icons/${channel.icon?._id}`}
/>
)} )}
<AvatarFallback> <AvatarFallback>
{name {name

View File

@ -14,7 +14,7 @@ export function JsonCard({ obj }: { obj: any }) {
const [shown, setShown] = useState(false); const [shown, setShown] = useState(false);
return ( return (
<Card className="shadow-none"> <Card>
<CardHeader> <CardHeader>
<CardTitle>Document</CardTitle> <CardTitle>Document</CardTitle>
<CardDescription>Raw JSON representation</CardDescription> <CardDescription>Raw JSON representation</CardDescription>

View File

@ -1,4 +1,3 @@
import Link from "next/link";
import { Report } from "revolt-api"; import { Report } from "revolt-api";
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
import { Badge } from "../ui/badge"; import { Badge } from "../ui/badge";
@ -10,28 +9,26 @@ dayjs.extend(relativeTime);
export function ReportCard({ report }: { report: Report }) { export function ReportCard({ report }: { report: Report }) {
return ( return (
<Link href={`/panel/reports/${report._id}`}> <Card>
<Card className="transition-all hover:-translate-y-1 hover:shadow-md"> <CardHeader>
<CardHeader> <CardTitle
<CardTitle className={`overflow-ellipsis whitespace-nowrap overflow-x-clip ${
className={`overflow-ellipsis whitespace-nowrap overflow-x-clip ${ report.status !== "Created" ? "text-gray-500" : ""
report.status !== "Created" ? "text-gray-500" : "" }`}
}`} >
> {report.content.report_reason.includes("Illegal") && (
{report.content.report_reason.includes("Illegal") && ( <Badge className="align-middle" variant="destructive">
<Badge className="align-middle" variant="destructive"> Urgent
Urgent </Badge>
</Badge> )}{" "}
)}{" "} {report.additional_context || "No reason specified"}
{report.additional_context || "No reason specified"} </CardTitle>
</CardTitle> <CardDescription>
<CardDescription> {report._id.toString().substring(20, 26)} &middot;{" "}
{report._id.toString().substring(20, 26)} &middot;{" "} {report.content.report_reason} &middot; {report.content.type} &middot;{" "}
{report.content.report_reason} &middot; {report.content.type}{" "} {dayjs(decodeTime(report._id)).fromNow()}
&middot; {dayjs(decodeTime(report._id)).fromNow()} </CardDescription>
</CardDescription> </CardHeader>
</CardHeader> </Card>
</Card>
</Link>
); );
} }

View File

@ -1,7 +1,6 @@
import { Server } from "revolt-api"; import { Server } from "revolt-api";
import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { Card, CardDescription, CardHeader, CardTitle } from "../ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
import Link from "next/link";
import { AUTUMN_URL } from "@/lib/constants"; import { AUTUMN_URL } from "@/lib/constants";
export function ServerCard({ export function ServerCard({
@ -12,13 +11,11 @@ export function ServerCard({
subtitle: string; subtitle: string;
}) { }) {
return ( return (
<Card className="shadow-none"> <Card>
<CardHeader> <CardHeader>
<CardTitle> <CardTitle>
<Avatar> <Avatar>
<AvatarImage <AvatarImage src={`${AUTUMN_URL}/icons/${server.icon?._id}`} />
src={`${AUTUMN_URL}/icons/${server.icon?._id}`}
/>
<AvatarFallback> <AvatarFallback>
{server.name {server.name
.split(" ") .split(" ")

View File

@ -7,7 +7,7 @@ import { AUTUMN_URL } from "@/lib/constants";
export function UserCard({ user, subtitle }: { user: User; subtitle: string }) { export function UserCard({ user, subtitle }: { user: User; subtitle: string }) {
return ( return (
<Card <Card
className="shadow-none bg-no-repeat bg-right text-left" className="bg-no-repeat bg-right text-left"
style={{ style={{
backgroundImage: user.profile?.background backgroundImage: user.profile?.background
? `linear-gradient(to right, white, rgba(255,0,0,0)), url('${AUTUMN_URL}/backgrounds/${user.profile.background._id}')` ? `linear-gradient(to right, white, rgba(255,0,0,0)), url('${AUTUMN_URL}/backgrounds/${user.profile.background._id}')`
@ -18,9 +18,7 @@ export function UserCard({ user, subtitle }: { user: User; subtitle: string }) {
<CardHeader> <CardHeader>
<CardTitle className="overflow-hidden overflow-ellipsis whitespace-nowrap"> <CardTitle className="overflow-hidden overflow-ellipsis whitespace-nowrap">
<Avatar> <Avatar>
<AvatarImage <AvatarImage src={`${AUTUMN_URL}/avatars/${user.avatar?._id}`} />
src={`${AUTUMN_URL}/avatars/${user.avatar?._id}`}
/>
<AvatarFallback className="overflow-hidden overflow-ellipsis whitespace-nowrap"> <AvatarFallback className="overflow-hidden overflow-ellipsis whitespace-nowrap">
{(user.display_name ?? user.username) {(user.display_name ?? user.username)
.split(" ") .split(" ")

View File

@ -0,0 +1,19 @@
import Link from "next/link";
import { ReactNode } from "react";
export function CardLink({
href,
children,
}: {
href: string;
children: ReactNode;
}) {
return (
<Link
href={href}
className="transition-all hover:-translate-y-1 hover:shadow-md rounded-xl"
>
{children}
</Link>
);
}

View File

@ -3,6 +3,7 @@
import { Report } from "revolt-api"; import { Report } from "revolt-api";
import { ListCompactor } from "../common/ListCompactor"; import { ListCompactor } from "../common/ListCompactor";
import { ReportCard } from "../cards/ReportCard"; import { ReportCard } from "../cards/ReportCard";
import { CardLink } from "../common/CardLink";
export function RelevantReports({ export function RelevantReports({
byUser, byUser,
@ -17,14 +18,22 @@ export function RelevantReports({
<h2 className="text-md text-center pb-2">Created Reports</h2> <h2 className="text-md text-center pb-2">Created Reports</h2>
<ListCompactor <ListCompactor
data={byUser} data={byUser}
Component={({ item }) => <ReportCard report={item} />} Component={({ item }) => (
<CardLink href={`/panel/reports/${item._id}`}>
<ReportCard report={item} />
</CardLink>
)}
/> />
</div> </div>
<div className="flex-1 min-w-0 flex flex-col gap-2"> <div className="flex-1 min-w-0 flex flex-col gap-2">
<h2 className="text-md text-center pb-2">Reports Against User</h2> <h2 className="text-md text-center pb-2">Reports Against User</h2>
<ListCompactor <ListCompactor
data={forUser} data={forUser}
Component={({ item }) => <ReportCard report={item} />} Component={({ item }) => (
<CardLink href={`/panel/reports/${item._id}`}>
<ReportCard report={item} />
</CardLink>
)}
/> />
</div> </div>
</div> </div>

View File

@ -0,0 +1,83 @@
"use client";
import { Report } from "revolt-api";
import { Textarea } from "../ui/textarea";
import { Button } from "../ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import { useRef, useState } from "react";
import { useToast } from "../ui/use-toast";
import { updateReportNotes } from "@/lib/actions";
export function ReportActions({ report }: { report: Report }) {
const { toast } = useToast();
const [reportDraft, setDraft] = useState(report);
return (
<>
<Textarea
placeholder="Enter notes here... (save on unfocus)"
className="!min-h-0 !h-[76px]"
defaultValue={report.notes}
onBlur={async (e) => {
const notes = e.currentTarget.value;
if (notes === reportDraft.notes ?? "") return;
try {
await updateReportNotes(report._id, notes);
setDraft((report) => ({ ...report, notes }));
toast({
title: "Updated report notes",
});
} catch (err) {
toast({
title: "Failed to update report notes",
description: String(err),
variant: "destructive",
});
}
}}
/>
<div className="flex gap-2">
{report.status === "Created" ? (
<>
<Button className="flex-1 bg-green-400 hover:bg-green-300">
Resolve
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="flex-1 bg-red-400 hover:bg-red-300">
Reject
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Custom Reason</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Presets</DropdownMenuLabel>
<DropdownMenuItem>Invalid</DropdownMenuItem>
<DropdownMenuItem>False or Spam</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuItem>Not Enough Evidence</DropdownMenuItem>
<DropdownMenuItem>Request Clarification</DropdownMenuItem>
<DropdownMenuItem>Acknowledge Only</DropdownMenuItem>
<DropdownMenuItem>Ignore</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</>
) : (
<>
<Button className="flex-1">Re-open</Button>
<Button className="flex-1">Send resolution notification</Button>
</>
)}
</div>
</>
);
}

View File

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Card = React.forwardRef< const Card = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -8,14 +8,11 @@ const Card = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div <div
ref={ref} ref={ref}
className={cn( className={cn("rounded-lg border bg-card text-card-foreground", className)}
"rounded-lg border bg-card text-card-foreground shadow-sm",
className
)}
{...props} {...props}
/> />
)) ));
Card.displayName = "Card" Card.displayName = "Card";
const CardHeader = React.forwardRef< const CardHeader = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -26,8 +23,8 @@ const CardHeader = React.forwardRef<
className={cn("flex flex-col space-y-1.5 p-6", className)} className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props} {...props}
/> />
)) ));
CardHeader.displayName = "CardHeader" CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef< const CardTitle = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -41,8 +38,8 @@ const CardTitle = React.forwardRef<
)} )}
{...props} {...props}
/> />
)) ));
CardTitle.displayName = "CardTitle" CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef< const CardDescription = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -53,16 +50,16 @@ const CardDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)} className={cn("text-sm text-muted-foreground", className)}
{...props} {...props}
/> />
)) ));
CardDescription.displayName = "CardDescription" CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef< const CardContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
)) ));
CardContent.displayName = "CardContent" CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef< const CardFooter = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -73,7 +70,14 @@ const CardFooter = React.forwardRef<
className={cn(" flex items-center p-6 pt-0", className)} className={cn(" flex items-center p-6 pt-0", className)}
{...props} {...props}
/> />
)) ));
CardFooter.displayName = "CardFooter" CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View File

@ -20,6 +20,7 @@ import {
File, File,
Member, Member,
Message, Message,
Report,
Server, Server,
SessionInfo, SessionInfo,
User, User,
@ -40,6 +41,20 @@ export async function sendAlert(userId: string, content: string) {
}); });
} }
export async function updateReportNotes(reportId: string, notes: string) {
return await mongo()
.db("revolt")
.collection<Report>("safety_reports")
.updateOne(
{ _id: reportId },
{
$set: {
notes,
},
}
);
}
export async function disableAccount(userId: string) { export async function disableAccount(userId: string) {
await mongo() await mongo()
.db("revolt") .db("revolt")

View File

@ -28,6 +28,7 @@
"dayjs": "^1.11.9", "dayjs": "^1.11.9",
"eslint": "8.45.0", "eslint": "8.45.0",
"eslint-config-next": "13.4.12", "eslint-config-next": "13.4.12",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.263.0", "lucide-react": "^0.263.0",
"mongodb": "^5.7.0", "mongodb": "^5.7.0",
"next": "13.4.12", "next": "13.4.12",
@ -45,6 +46,7 @@
"ulid": "^2.3.0" "ulid": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash.debounce": "^4.0.7",
"revolt.js": "7.0.0-beta.9" "revolt.js": "7.0.0-beta.9"
} }
} }

View File

@ -58,6 +58,9 @@ dependencies:
eslint-config-next: eslint-config-next:
specifier: 13.4.12 specifier: 13.4.12
version: 13.4.12(eslint@8.45.0)(typescript@5.1.6) version: 13.4.12(eslint@8.45.0)(typescript@5.1.6)
lodash.debounce:
specifier: ^4.0.8
version: 4.0.8
lucide-react: lucide-react:
specifier: ^0.263.0 specifier: ^0.263.0
version: 0.263.0(react@18.2.0) version: 0.263.0(react@18.2.0)
@ -105,6 +108,9 @@ dependencies:
version: 2.3.0 version: 2.3.0
devDependencies: devDependencies:
'@types/lodash.debounce':
specifier: ^4.0.7
version: 4.0.7
revolt.js: revolt.js:
specifier: 7.0.0-beta.9 specifier: 7.0.0-beta.9
version: 7.0.0-beta.9(typescript@5.1.6) version: 7.0.0-beta.9(typescript@5.1.6)
@ -1352,6 +1358,16 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: false dev: false
/@types/lodash.debounce@4.0.7:
resolution: {integrity: sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==}
dependencies:
'@types/lodash': 4.14.196
dev: true
/@types/lodash@4.14.196:
resolution: {integrity: sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==}
dev: true
/@types/node@20.4.4: /@types/node@20.4.4:
resolution: {integrity: sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew==} resolution: {integrity: sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew==}
dev: false dev: false
@ -2947,6 +2963,10 @@ packages:
p-locate: 5.0.0 p-locate: 5.0.0
dev: false dev: false
/lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
dev: false
/lodash.defaultsdeep@4.6.1: /lodash.defaultsdeep@4.6.1:
resolution: {integrity: sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==} resolution: {integrity: sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==}