mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 16:23:06 +10:00
Merge branch 'main' into doc-162
This commit is contained in:
@ -18,4 +18,8 @@ NEXTAUTH_URL='http://localhost:3000'
|
|||||||
# You can also configure you own SMTP server using Nodemailer in sendMailts. (currently not possible via config)
|
# You can also configure you own SMTP server using Nodemailer in sendMailts. (currently not possible via config)
|
||||||
SENDGRID_API_KEY=''
|
SENDGRID_API_KEY=''
|
||||||
# Sender for signing requests and completion mails.
|
# Sender for signing requests and completion mails.
|
||||||
MAIL_FROM=''
|
MAIL_FROM=''
|
||||||
|
|
||||||
|
#FEATURE FLAGS
|
||||||
|
# Allow users to register via the /signup page. Otherwise they will be redirect to the home page.
|
||||||
|
ALLOW_SIGNUP=true
|
||||||
@ -10,7 +10,7 @@ If you plan to contribute to Documenso, please take a moment to feel awesome ✨
|
|||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
The development branch is <code>development</code>. All pull request should be made against this branch. If you need help getting started, [join us on Slack](https://join.slack.com/t/documenso/shared_invite/zt-1qwxxsvli-nDyojjt~wakhgBGl9JRl2w).
|
The development branch is <code>main</code>. All pull request should be made against this branch. If you need help getting started, [join us on Slack](https://join.slack.com/t/documenso/shared_invite/zt-1qwxxsvli-nDyojjt~wakhgBGl9JRl2w).
|
||||||
|
|
||||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your
|
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your
|
||||||
own GitHub account and then
|
own GitHub account and then
|
||||||
|
|||||||
@ -173,7 +173,11 @@ export default function PDFSigner(props: any) {
|
|||||||
FieldType.FREE_SIGNATURE
|
FieldType.FREE_SIGNATURE
|
||||||
);
|
);
|
||||||
|
|
||||||
createOrUpdateField(props.document, freeSignatureField).then((res) => {
|
createOrUpdateField(
|
||||||
|
props.document,
|
||||||
|
freeSignatureField,
|
||||||
|
recipient.token
|
||||||
|
).then((res) => {
|
||||||
setFields((prevState) => [...prevState, res]);
|
setFields((prevState) => [...prevState, res]);
|
||||||
setDialogField(res);
|
setDialogField(res);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { Document, Page } from "react-pdf/dist/esm/entry.webpack5";
|
|||||||
import EditableField from "./editable-field";
|
import EditableField from "./editable-field";
|
||||||
import SignableField from "./signable-field";
|
import SignableField from "./signable-field";
|
||||||
import short from "short-uuid";
|
import short from "short-uuid";
|
||||||
|
import { FieldType } from "@prisma/client";
|
||||||
|
|
||||||
export default function PDFViewer(props) {
|
export default function PDFViewer(props) {
|
||||||
const [numPages, setNumPages] = useState(null);
|
const [numPages, setNumPages] = useState(null);
|
||||||
@ -71,21 +72,25 @@ export default function PDFViewer(props) {
|
|||||||
onRenderError={() => setLoading(false)}
|
onRenderError={() => setLoading(false)}
|
||||||
></Page>
|
></Page>
|
||||||
{props?.fields
|
{props?.fields
|
||||||
.filter((item) => item.page === index)
|
.filter((field) => field.page === index)
|
||||||
.map((item) =>
|
.map((field) =>
|
||||||
props.readonly ? (
|
props.readonly ? (
|
||||||
<SignableField
|
<SignableField
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
key={item.id}
|
key={field.id}
|
||||||
field={item}
|
field={field}
|
||||||
className="absolute"
|
className="absolute"
|
||||||
onDelete={onDeleteHandler}
|
onDelete={onDeleteHandler}
|
||||||
></SignableField>
|
></SignableField>
|
||||||
) : (
|
) : (
|
||||||
<EditableField
|
<EditableField
|
||||||
hidden={item.Signature || item.inserted}
|
hidden={
|
||||||
key={item.id}
|
field.Signature ||
|
||||||
field={item}
|
field.inserted ||
|
||||||
|
field.type === FieldType.FREE_SIGNATURE
|
||||||
|
}
|
||||||
|
key={field.id}
|
||||||
|
field={field}
|
||||||
className="absolute"
|
className="absolute"
|
||||||
onPositionChanged={onPositionChangedHandler}
|
onPositionChanged={onPositionChangedHandler}
|
||||||
onDelete={onDeleteHandler}
|
onDelete={onDeleteHandler}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React, { useState } from "react";
|
|||||||
import Draggable from "react-draggable";
|
import Draggable from "react-draggable";
|
||||||
import { IconButton } from "@documenso/ui";
|
import { IconButton } from "@documenso/ui";
|
||||||
import { XCircleIcon } from "@heroicons/react/20/solid";
|
import { XCircleIcon } from "@heroicons/react/20/solid";
|
||||||
|
import { classNames } from "@documenso/lib";
|
||||||
const stc = require("string-to-color");
|
const stc = require("string-to-color");
|
||||||
|
|
||||||
type FieldPropsType = {
|
type FieldPropsType = {
|
||||||
@ -43,13 +44,19 @@ export default function SignableField(props: FieldPropsType) {
|
|||||||
if (!field?.signature) props.onClick(props.field);
|
if (!field?.signature) props.onClick(props.field);
|
||||||
}}
|
}}
|
||||||
ref={nodeRef}
|
ref={nodeRef}
|
||||||
className="cursor-pointer opacity-80 m-auto w-48 h-16 flex-row-reverse text-lg font-bold text-center absolute top-0 left-0 select-none hover:brightness-50"
|
className={classNames(
|
||||||
|
"opacity-80 m-auto w-48 h-16 flex-row-reverse text-lg font-bold text-center absolute top-0 left-0 select-none",
|
||||||
|
field.type === "SIGNATURE"
|
||||||
|
? "cursor-pointer hover:brightness-50"
|
||||||
|
: "cursor-not-allowed"
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
background: stc(props.field.Recipient.email),
|
background: stc(props.field.Recipient.email),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div hidden={field?.signature} className="font-medium my-4">
|
<div hidden={field?.signature} className="font-medium my-4">
|
||||||
{field.type === "SIGNATURE" ? "SIGN HERE" : ""}
|
{field.type === "SIGNATURE" ? "SIGN HERE" : ""}
|
||||||
|
{field.type === "DATE" ? <small>Date (filled on sign)</small> : ""}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
hidden={!field?.signature}
|
hidden={!field?.signature}
|
||||||
|
|||||||
@ -17,12 +17,11 @@ interface LoginValues {
|
|||||||
csrfToken: string;
|
csrfToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login(props: any) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const methods = useForm<LoginValues>();
|
const methods = useForm<LoginValues>();
|
||||||
const { register, formState } = methods;
|
const { register, formState } = methods;
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||||
|
|
||||||
let callbackUrl =
|
let callbackUrl =
|
||||||
typeof router.query?.callbackUrl === "string"
|
typeof router.query?.callbackUrl === "string"
|
||||||
? router.query.callbackUrl
|
? router.query.callbackUrl
|
||||||
@ -117,7 +116,6 @@ export default function Login() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
<a href="#" className="font-medium text-neon hover:text-neon">
|
<a href="#" className="font-medium text-neon hover:text-neon">
|
||||||
@ -125,7 +123,6 @@ export default function Login() {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
@ -152,15 +149,27 @@ export default function Login() {
|
|||||||
<div className="relative flex justify-center"></div>
|
<div className="relative flex justify-center"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-center text-sm text-gray-600">
|
{props.allowSignup ? (
|
||||||
Are you new here?{" "}
|
<p className="mt-2 text-center text-sm text-gray-600">
|
||||||
<Link
|
Are you new here?{" "}
|
||||||
href="/signup"
|
<Link
|
||||||
className="font-medium text-neon hover:text-neon"
|
href="/signup"
|
||||||
>
|
className="font-medium text-neon hover:text-neon"
|
||||||
Create a new Account
|
>
|
||||||
</Link>
|
Create a new Account
|
||||||
</p>
|
</Link>
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p className="mt-2 text-center text-sm text-gray-600">
|
||||||
|
Like Documenso{" "}
|
||||||
|
<Link
|
||||||
|
href="https://documenso.com"
|
||||||
|
className="font-medium text-neon hover:text-neon"
|
||||||
|
>
|
||||||
|
Hosted Documenso will be availible soon™
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -115,9 +115,13 @@ export default function Setttings() {
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
className="divide-y divide-gray-200 lg:col-span-9"
|
className="divide-y divide-gray-200 lg:col-span-9 min-h-[251px]"
|
||||||
action="#"
|
action="#"
|
||||||
method="POST"
|
method="POST"
|
||||||
|
hidden={
|
||||||
|
subNavigation.filter((e) => e.current)[0]?.name !==
|
||||||
|
subNavigation[0].name
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{/* Profile section */}
|
{/* Profile section */}
|
||||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
@ -170,6 +174,26 @@ export default function Setttings() {
|
|||||||
<Button onClick={() => updateUser(user)}>Save</Button>
|
<Button onClick={() => updateUser(user)}>Save</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<div
|
||||||
|
hidden={
|
||||||
|
subNavigation.filter((e) => e.current)[0]?.name !==
|
||||||
|
subNavigation[1].name
|
||||||
|
}
|
||||||
|
className="divide-y divide-gray-200 lg:col-span-9 min-h-[251px]"
|
||||||
|
>
|
||||||
|
{/* Passwords section */}
|
||||||
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-lg font-medium leading-6 text-gray-900">
|
||||||
|
Password
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm text-gray-500">
|
||||||
|
Forgot your passwort? Email <b>hi@documenso.com</b> to reset
|
||||||
|
it.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,10 +18,10 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let user = null;
|
let user = null;
|
||||||
|
let recipient = null;
|
||||||
if (recipientToken) {
|
if (recipientToken) {
|
||||||
// Request from signing page without login
|
// Request from signing page without login
|
||||||
const recipient = await prisma.recipient.findFirst({
|
recipient = await prisma.recipient.findFirst({
|
||||||
where: {
|
where: {
|
||||||
token: recipientToken?.toString(),
|
token: recipientToken?.toString(),
|
||||||
},
|
},
|
||||||
@ -37,7 +37,14 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
|
|
||||||
if (!user) return res.status(401).end();
|
if (!user) return res.status(401).end();
|
||||||
|
|
||||||
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
let document: PrismaDocument | null = null;
|
||||||
|
if (recipientToken) {
|
||||||
|
document = await prisma.document.findFirst({
|
||||||
|
where: { id: recipient?.Document?.id },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
document = await getDocument(+documentId, req, res);
|
||||||
|
}
|
||||||
|
|
||||||
if (!document)
|
if (!document)
|
||||||
res.status(404).end(`No document with id ${documentId} found.`);
|
res.status(404).end(`No document with id ${documentId} found.`);
|
||||||
@ -45,16 +52,18 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
const signaturesCount = await prisma.signature.count({
|
const signaturesCount = await prisma.signature.count({
|
||||||
where: {
|
where: {
|
||||||
Field: {
|
Field: {
|
||||||
documentId: document.id,
|
documentId: document?.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let signedDocumentAsBase64 = document.document;
|
let signedDocumentAsBase64 = document?.document || "";
|
||||||
|
|
||||||
// No need to add a signature, if no one signed yet.
|
// No need to add a signature, if no one signed yet.
|
||||||
if (signaturesCount > 0) {
|
if (signaturesCount > 0) {
|
||||||
signedDocumentAsBase64 = await addDigitalSignature(document.document);
|
signedDocumentAsBase64 = await addDigitalSignature(
|
||||||
|
document?.document || ""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const buffer: Buffer = Buffer.from(signedDocumentAsBase64, "base64");
|
const buffer: Buffer = Buffer.from(signedDocumentAsBase64, "base64");
|
||||||
@ -62,7 +71,7 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
res.setHeader("Content-Length", buffer.length);
|
res.setHeader("Content-Length", buffer.length);
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
"Content-Disposition",
|
"Content-Disposition",
|
||||||
`attachment; filename=${document.title}`
|
`attachment; filename=${document?.title}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).send(buffer);
|
return res.status(200).send(buffer);
|
||||||
|
|||||||
@ -36,8 +36,10 @@ async function getHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const user = await getUserFromToken(req, res);
|
const { token: recipientToken } = req.query;
|
||||||
const { id: documentId } = req.query;
|
let user = null;
|
||||||
|
if (!recipientToken) user = await getUserFromToken(req, res);
|
||||||
|
if (!user && !recipientToken) return res.status(401).end();
|
||||||
const body: {
|
const body: {
|
||||||
id: number;
|
id: number;
|
||||||
type: FieldType;
|
type: FieldType;
|
||||||
@ -48,18 +50,30 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
customText: string;
|
customText: string;
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
if (!user) return;
|
const { id: documentId } = req.query;
|
||||||
|
|
||||||
if (!documentId) {
|
if (!documentId) {
|
||||||
res.status(400).send("Missing parameter documentId.");
|
return res.status(400).send("Missing parameter documentId.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
if (recipientToken) {
|
||||||
|
const recipient = await prisma.recipient.findFirst({
|
||||||
|
where: { token: recipientToken?.toString() },
|
||||||
|
});
|
||||||
|
|
||||||
// todo entity ownerships checks
|
if (!recipient || recipient?.documentId !== +documentId)
|
||||||
if (document.userId !== user.id) {
|
return res
|
||||||
return res.status(401).send("User does not have access to this document.");
|
.status(401)
|
||||||
|
.send("Recipient does not have access to this document.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
const document: PrismaDocument = await getDocument(+documentId, req, res);
|
||||||
|
// todo entity ownerships checks
|
||||||
|
if (document.userId !== user.id) {
|
||||||
|
return res
|
||||||
|
.status(401)
|
||||||
|
.send("User does not have access to this document.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const field = await prisma.field.upsert({
|
const field = await prisma.field.upsert({
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
import {
|
import { defaultHandler, defaultResponder } from "@documenso/lib/server";
|
||||||
defaultHandler,
|
|
||||||
defaultResponder,
|
|
||||||
getUserFromToken,
|
|
||||||
} from "@documenso/lib/server";
|
|
||||||
import prisma from "@documenso/prisma";
|
import prisma from "@documenso/prisma";
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { SigningStatus, DocumentStatus } from "@prisma/client";
|
import { SigningStatus, DocumentStatus } from "@prisma/client";
|
||||||
@ -12,7 +8,6 @@ import { insertImageInPDF, insertTextInPDF } from "@documenso/pdf";
|
|||||||
import { sendSigningDoneMail } from "@documenso/lib/mail";
|
import { sendSigningDoneMail } from "@documenso/lib/mail";
|
||||||
|
|
||||||
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const existingUser = await getUserFromToken(req, res);
|
|
||||||
const { token: recipientToken } = req.query;
|
const { token: recipientToken } = req.query;
|
||||||
const { signatures: signaturesFromBody }: { signatures: any[] } = req.body;
|
const { signatures: signaturesFromBody }: { signatures: any[] } = req.body;
|
||||||
|
|
||||||
@ -29,11 +24,19 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
return res.status(401).send("Recipient not found.");
|
return res.status(401).send("Recipient not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const document: PrismaDocument = await getDocument(
|
const document: PrismaDocument = await prisma.document.findFirstOrThrow({
|
||||||
recipient.documentId,
|
where: {
|
||||||
req,
|
id: recipient.documentId,
|
||||||
res
|
},
|
||||||
);
|
include: {
|
||||||
|
Recipient: {
|
||||||
|
orderBy: {
|
||||||
|
id: "asc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Field: { include: { Recipient: true, Signature: true } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!document) res.status(404).end(`No document found.`);
|
if (!document) res.status(404).end(`No document found.`);
|
||||||
|
|
||||||
@ -70,6 +73,8 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Don't check for inserted, because currently no "sign again" scenarios exist and
|
||||||
|
// this is probably the expected behaviour in unclean states.
|
||||||
const nonSignatureFields = await prisma.field.findMany({
|
const nonSignatureFields = await prisma.field.findMany({
|
||||||
where: {
|
where: {
|
||||||
documentId: document.id,
|
documentId: document.id,
|
||||||
|
|||||||
@ -107,7 +107,6 @@ export async function getServerSideProps(context: any) {
|
|||||||
where: {
|
where: {
|
||||||
documentId: recipient.Document.id,
|
documentId: recipient.Document.id,
|
||||||
recipientId: recipient.id,
|
recipientId: recipient.id,
|
||||||
type: { in: [FieldType.SIGNATURE] },
|
|
||||||
Signature: { is: null },
|
Signature: { is: null },
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { Button, IconButton } from "@documenso/ui";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
const SignPage: NextPageWithLayout = (props: any) => {
|
const Signed: NextPageWithLayout = (props: any) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const allRecipientsSigned = props.document.Recipient?.every(
|
const allRecipientsSigned = props.document.Recipient?.every(
|
||||||
(r: any) => r.signingStatus === "SIGNED"
|
(r: any) => r.signingStatus === "SIGNED"
|
||||||
@ -47,7 +47,12 @@ const SignPage: NextPageWithLayout = (props: any) => {
|
|||||||
onClick={(event: any) => {
|
onClick={(event: any) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
router.push("/api/documents/" + props.document.id);
|
router.push(
|
||||||
|
"/api/documents/" +
|
||||||
|
props.document.id +
|
||||||
|
"?token=" +
|
||||||
|
props.recipient.token
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Download "{props.document.title}"
|
Download "{props.document.title}"
|
||||||
@ -103,8 +108,9 @@ export async function getServerSideProps(context: any) {
|
|||||||
props: {
|
props: {
|
||||||
document: JSON.parse(JSON.stringify(recipient.Document)),
|
document: JSON.parse(JSON.stringify(recipient.Document)),
|
||||||
fields: JSON.parse(JSON.stringify(fields)),
|
fields: JSON.parse(JSON.stringify(fields)),
|
||||||
|
recipient: JSON.parse(JSON.stringify(recipient)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SignPage;
|
export default Signed;
|
||||||
|
|||||||
@ -1,13 +1,23 @@
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Login from "../components/login";
|
import Login from "../components/login";
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage(props: any) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Login | Documenso</title>
|
<title>Login | Documenso</title>
|
||||||
</Head>
|
</Head>
|
||||||
<Login></Login>
|
<Login allowSignup={props.ALLOW_SIGNUP}></Login>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getServerSideProps(context: any) {
|
||||||
|
const ALLOW_SIGNUP = process.env.ALLOW_SIGNUP === "true";
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
ALLOW_SIGNUP: ALLOW_SIGNUP,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -14,6 +14,14 @@ export default function SignupPage(props: { source: string }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context: any) {
|
export async function getServerSideProps(context: any) {
|
||||||
|
if (process.env.ALLOW_SIGNUP !== "true")
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: "/login",
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const signupSource: string = context.query["source"];
|
const signupSource: string = context.query["source"];
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
13
package-lock.json
generated
13
package-lock.json
generated
@ -40,6 +40,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"apps/web": {
|
"apps/web": {
|
||||||
|
"name": "@documenso/web",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@documenso/pdf": "*",
|
"@documenso/pdf": "*",
|
||||||
@ -3555,7 +3556,8 @@
|
|||||||
"node_modules/json-parse-even-better-errors": {
|
"node_modules/json-parse-even-better-errors": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/json-schema": {
|
"node_modules/json-schema": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@ -8639,18 +8641,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/features": {
|
"packages/features": {
|
||||||
|
"name": "@documenso/features",
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
},
|
},
|
||||||
"packages/lib": {
|
"packages/lib": {
|
||||||
|
"name": "@documenso/lib",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcryptjs": "^2.4.3"
|
"bcryptjs": "^2.4.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packages/pdf": {
|
"packages/pdf": {
|
||||||
|
"name": "@documenso/pdf",
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
},
|
},
|
||||||
"packages/prisma": {
|
"packages/prisma": {
|
||||||
|
"name": "@documenso/prisma",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.8.1",
|
"@prisma/client": "^4.8.1",
|
||||||
@ -8669,9 +8675,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"packages/signing": {
|
"packages/signing": {
|
||||||
|
"name": "@documenso/signing",
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
|
"name": "@documenso/ui",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"devDependencies": {}
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
@ -11283,7 +11291,8 @@
|
|||||||
"json-parse-even-better-errors": {
|
"json-parse-even-better-errors": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"json-schema": {
|
"json-schema": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
|
|||||||
@ -2,11 +2,12 @@ import toast from "react-hot-toast";
|
|||||||
|
|
||||||
export const createOrUpdateField = async (
|
export const createOrUpdateField = async (
|
||||||
document: any,
|
document: any,
|
||||||
field: any
|
field: any,
|
||||||
|
recipientToken: string = ""
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
const created = await toast.promise(
|
const created = await toast.promise(
|
||||||
fetch("/api/documents/" + document.id + "/fields", {
|
fetch("/api/documents/" + document.id + "/fields?token=" + recipientToken, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export async function getUserFromToken(
|
|||||||
const tokenEmail = token?.email?.toString();
|
const tokenEmail = token?.email?.toString();
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
res.status(401).send("No session token found for request.");
|
if (res.status) res.status(401).send("No session token found for request.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user