merge: branch 'quark/permissions'

This commit is contained in:
Paul Makles
2022-04-29 13:48:38 +01:00
117 changed files with 10609 additions and 6253 deletions

View File

@@ -1,13 +1,6 @@
import { Prompt } from "react-router";
import { useHistory } from "react-router-dom";
import type { Attachment } from "revolt-api/types/Autumn";
import { Bot } from "revolt-api/types/Bots";
import { TextChannel, VoiceChannel } from "revolt-api/types/Channels";
import type { EmbedImage } from "revolt-api/types/January";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { API, Channel, Message, Server, User } from "revolt.js";
import { createContext } from "preact";
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
@@ -61,7 +54,11 @@ export type Screen =
| {
type: "create_channel";
target: Server;
cb?: (channel: TextChannel | VoiceChannel) => void;
cb?: (
channel: Channel & {
channel_type: "TextChannel" | "VoiceChannel";
},
) => void;
}
| { type: "create_category"; target: Server }
))
@@ -101,11 +98,11 @@ export type Screen =
omit?: string[];
callback: (users: string[]) => Promise<void>;
}
| { id: "image_viewer"; attachment?: Attachment; embed?: EmbedImage }
| { id: "image_viewer"; attachment?: API.File; embed?: API.Image }
| { id: "channel_info"; channel: Channel }
| { id: "pending_requests"; users: User[] }
| { id: "modify_account"; field: "username" | "email" | "password" }
| { id: "create_bot"; onCreate: (bot: Bot) => void }
| { id: "create_bot"; onCreate: (bot: API.Bot) => void }
| {
id: "server_identity";
server: Server;

View File

@@ -11,7 +11,7 @@ export function ErrorModal({ onClose, error }: Props) {
return (
<Modal
visible={true}
onClose={() => false}
onClose={onClose}
title={<Text id="app.special.modals.error" />}
actions={[
{

View File

@@ -1,5 +1,5 @@
import { useHistory } from "react-router";
import { Server } from "revolt.js/dist/maps/Servers";
import { Server } from "revolt.js";
import { ulid } from "ulid";
import { Text } from "preact-i18n";
@@ -69,6 +69,7 @@ export function InputModal({
)}
<InputBox
value={value}
style={{ width: "100%" }}
onChange={(e) => setValue(e.currentTarget.value)}
/>
</Modal>
@@ -101,7 +102,6 @@ export function SpecialInputModal(props: SpecialProps) {
callback={async (name) => {
const group = await client.channels.createGroup({
name,
nonce: ulid(),
users: [],
});
@@ -130,7 +130,6 @@ export function SpecialInputModal(props: SpecialProps) {
callback={async (name) => {
const server = await client.servers.createServer({
name,
nonce: ulid(),
});
history.push(`/server/${server._id}`);
@@ -159,7 +158,7 @@ export function SpecialInputModal(props: SpecialProps) {
onClose={onClose}
question={<Text id="app.context_menu.set_custom_status" />}
field={<Text id="app.context_menu.custom_status" />}
defaultValue={client.user?.status?.text}
defaultValue={client.user?.status?.text ?? undefined}
callback={(text) =>
client.users.edit({
status: {
@@ -177,11 +176,8 @@ export function SpecialInputModal(props: SpecialProps) {
onClose={onClose}
question={"Add Friend"}
callback={(username) =>
client
.req(
"PUT",
`/users/${username}/friend` as "/users/id/friend",
)
client.api
.put(`/users/${username as ""}/friend`)
.then(undefined)
}
/>

View File

@@ -16,6 +16,10 @@
h1 {
margin: 0;
}
img {
max-height: 80px;
}
}
&.form {

View File

@@ -1,10 +1,6 @@
import { observer } from "mobx-react-lite";
import { useHistory } from "react-router-dom";
import { TextChannel, VoiceChannel } from "revolt-api/types/Channels";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message as MessageI } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { Channel, Message as MessageI, Server, User } from "revolt.js";
import { ulid } from "ulid";
import styles from "./Prompt.module.scss";
@@ -74,7 +70,11 @@ type SpecialProps = { onClose: () => void } & (
| {
type: "create_channel";
target: Server;
cb?: (channel: TextChannel | VoiceChannel) => void;
cb?: (
channel: Channel & {
channel_type: "TextChannel" | "VoiceChannel";
},
) => void;
}
| { type: "create_category"; target: Server }
);
@@ -254,7 +254,7 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
props.target
.createInvite()
.then((code) => setCode(code))
.then(({ _id }) => setCode(_id))
.catch((err) => setError(takeError(err)))
.finally(() => setProcessing(false));
}, [props.target]);
@@ -429,11 +429,10 @@ export const SpecialPromptModal = observer((props: SpecialProps) => {
await props.target.createChannel({
type,
name,
nonce: ulid(),
});
if (props.cb) {
props.cb(channel);
props.cb(channel as any);
} else {
history.push(
`/server/${props.target._id}/channel/${channel._id}`,

View File

@@ -1,6 +1,6 @@
import { X } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Channel } from "revolt.js";
import styles from "./ChannelInfo.module.scss";

View File

@@ -1,5 +1,5 @@
import { SubmitHandler, useForm } from "react-hook-form";
import { Bot } from "revolt-api/types/Bots";
import { API } from "revolt.js";
import { Text } from "preact-i18n";
import { useContext, useState } from "preact/hooks";
@@ -13,7 +13,7 @@ import { takeError } from "../../revoltjs/util";
interface Props {
onClose: () => void;
onCreate: (bot: Bot) => void;
onCreate: (bot: API.Bot) => void;
}
interface FormInputs {

View File

@@ -1,6 +1,5 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { Attachment, AttachmentMetadata } from "revolt-api/types/Autumn";
import { EmbedImage } from "revolt-api/types/January";
import { API } from "revolt.js";
import styles from "./ImageViewer.module.scss";
@@ -12,11 +11,11 @@ import { useClient } from "../../revoltjs/RevoltClient";
interface Props {
onClose: () => void;
embed?: EmbedImage;
attachment?: Attachment;
embed?: API.Image;
attachment?: API.File;
}
type ImageMetadata = AttachmentMetadata & { type: "Image" };
type ImageMetadata = API.Metadata & { type: "Image" };
export function ImageViewer({ attachment, embed, onClose }: Props) {
if (attachment && attachment.metadata.type !== "Image") {

View File

@@ -43,19 +43,19 @@ export function ModifyAccountModal({ onClose, field }: Props) {
try {
if (field === "email") {
await client.req("PATCH", "/auth/account/change/email", {
await client.api.patch("/auth/account/change/email", {
current_password: password,
email: new_email,
});
onClose();
} else if (field === "password") {
await client.req("PATCH", "/auth/account/change/password", {
await client.api.patch("/auth/account/change/password", {
current_password: password,
password: new_password,
});
onClose();
} else if (field === "username") {
await client.req("PATCH", "/users/id/username", {
await client.api.patch("/users/@me/username", {
username: new_username,
password,
});

View File

@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { User } from "revolt.js/dist/maps/Users";
import { User } from "revolt.js";
import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n";

View File

@@ -1,11 +1,12 @@
import { observer } from "mobx-react-lite";
import { Server } from "revolt.js/dist/maps/Servers";
import styled, { css } from "styled-components/macro";
import { Server } from "revolt.js";
import styles from "./ServerIdentityModal.module.scss";
import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import { noop } from "../../../lib/js";
import Button from "../../../components/ui/Button";
import InputBox from "../../../components/ui/InputBox";
import Modal from "../../../components/ui/Modal";
@@ -57,8 +58,12 @@ export const ServerIdentityModal = observer(({ server, onClose }: Props) => {
fileType="avatars"
behaviour="upload"
maxFileSize={4_000_000}
onUpload={(avatar) => member.edit({ avatar })}
remove={() => member.edit({ remove: "Avatar" })}
onUpload={(avatar) =>
member.edit({ avatar }).then(noop)
}
remove={() =>
member.edit({ remove: ["Avatar"] }).then(noop)
}
defaultPreview={client.user?.generateAvatarURL(
{
max_side: 256,
@@ -92,7 +97,7 @@ export const ServerIdentityModal = observer(({ server, onClose }: Props) => {
<Button
plain
onClick={() =>
member.edit({ remove: "Nickname" })
member.edit({ remove: ["Nickname"] })
}>
<Text id="app.special.modals.actions.remove" />
</Button>

View File

@@ -1,5 +1,3 @@
import { RelationshipStatus } from "revolt-api/types/Users";
import styles from "./UserPicker.module.scss";
import { Text } from "preact-i18n";
import { useState } from "preact/hooks";
@@ -37,7 +35,7 @@ export function UserPicker(props: Props) {
.filter(
(x) =>
x &&
x.relationship === RelationshipStatus.Friend &&
x.relationship === "Friend" &&
!omit.includes(x._id),
)
.map((x) => (

View File

@@ -9,9 +9,7 @@ import {
} from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite";
import { Link, useHistory } from "react-router-dom";
import { Profile, RelationshipStatus } from "revolt-api/types/Users";
import { UserPermission } from "revolt.js/dist/api/permissions";
import { Route } from "revolt.js/dist/api/routes";
import { UserPermission, API } from "revolt.js";
import styles from "./UserProfile.module.scss";
import { Localizer, Text } from "preact-i18n";
@@ -44,18 +42,18 @@ interface Props {
user_id: string;
dummy?: boolean;
onClose?: () => void;
dummyProfile?: Profile;
dummyProfile?: API.UserProfile;
}
export const UserProfile = observer(
({ user_id, onClose, dummy, dummyProfile }: Props) => {
const { openScreen, writeClipboard } = useIntermediate();
const [profile, setProfile] = useState<undefined | null | Profile>(
undefined,
);
const [profile, setProfile] = useState<
undefined | null | API.UserProfile
>(undefined);
const [mutual, setMutual] = useState<
undefined | null | Route<"GET", "/users/id/mutual">["response"]
undefined | null | API.MutualResponse
>(undefined);
const [isPublicBot, setIsPublicBot] = useState<
undefined | null | boolean
@@ -139,7 +137,11 @@ export const UserProfile = observer(
const backgroundURL =
profile &&
client.generateFileURL(profile.background, { width: 1000 }, true);
client.generateFileURL(
profile.background as any,
{ width: 1000 },
true,
);
const badges = user.badges ?? 0;
const flags = user.flags ?? 0;
@@ -198,7 +200,7 @@ export const UserProfile = observer(
</Button>
</Link>
)}
{user.relationship === RelationshipStatus.Friend && (
{user.relationship === "Friend" && (
<Localizer>
<Tooltip
content={
@@ -214,28 +216,25 @@ export const UserProfile = observer(
</Tooltip>
</Localizer>
)}
{user.relationship === RelationshipStatus.User &&
!dummy && (
<IconButton
onClick={() => {
onClose?.();
history.push(`/settings/profile`);
}}>
<Edit size={28} />
</IconButton>
)}
{user.relationship === "User" && !dummy && (
<IconButton
onClick={() => {
onClose?.();
history.push(`/settings/profile`);
}}>
<Edit size={28} />
</IconButton>
)}
{!user.bot &&
flags != 2 &&
flags != 4 &&
(user.relationship ===
RelationshipStatus.Incoming ||
user.relationship ===
RelationshipStatus.None) && (
(user.relationship === "Incoming" ||
user.relationship === "None") && (
<IconButton onClick={() => user.addFriend()}>
<UserPlus size={28} />
</IconButton>
)}
{user.relationship === RelationshipStatus.Outgoing && (
{user.relationship === "Outgoing" && (
<IconButton onClick={() => user.removeFriend()}>
<UserX size={28} />
</IconButton>
@@ -247,7 +246,7 @@ export const UserProfile = observer(
onClick={() => setTab("profile")}>
<Text id="app.special.popovers.user_profile.profile" />
</div>
{user.relationship !== RelationshipStatus.User && (
{user.relationship !== "User" && (
<>
<div
data-active={tab === "friends"}