Compare commits

...
10 Commits
8 changed files with 230 additions and 95 deletions
@@ -1,5 +1,7 @@
function sanitizeFileName(fileName) { function sanitizeFileName(fileName) {
// Remove spaces and invalid characters // Remove spaces and invalid characters
return fileName.replace(/[^a-zA-Z0-9._-]/g, ""); const file = fileName.replace(/[^a-zA-Z0-9._-]/g, "");
const removedot = file.replace(/\.(?=.*\.)/g, "");
return removedot.replace(/[^a-zA-Z0-9._-]/g, "");
} }
export default sanitizeFileName; export default sanitizeFileName;
+26 -4
View File
@@ -4,13 +4,15 @@ import { fetchAppInfo, forgetPassword } from "../redux/actions";
import Title from "../components/Title"; import Title from "../components/Title";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import login_img from "../assets/images/login_img.svg"; import login_img from "../assets/images/login_img.svg";
import Parse from "parse";
import Alert from "../primitives/Alert";
function ForgotPassword(props) { function ForgotPassword(props) {
const [state, setState] = useState({ const [state, setState] = useState({
email: "", email: "",
password: "", password: "",
hideNav: "" hideNav: ""
}); });
const [sentStatus, setSentStatus] = useState("");
const handleChange = (event) => { const handleChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setState({ ...state, [name]: value }); setState({ ...state, [name]: value });
@@ -23,7 +25,7 @@ function ForgotPassword(props) {
} }
}; };
const handleSubmit = (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
localStorage.setItem("appLogo", props.appInfo.applogo); localStorage.setItem("appLogo", props.appInfo.applogo);
localStorage.setItem("appName", props.appInfo.appname); localStorage.setItem("appName", props.appInfo.appname);
@@ -33,9 +35,21 @@ function ForgotPassword(props) {
"userSettings", "userSettings",
JSON.stringify(props.appInfo.settings) JSON.stringify(props.appInfo.settings)
); );
if (state.email) { if (state.email) {
props.forgetPassword(state.email); const username = state.email;
let baseUrl = localStorage.getItem("BaseUrl12");
let parseAppId = localStorage.getItem("AppID12");
try {
Parse.serverURL = baseUrl;
Parse.initialize(parseAppId);
await Parse.User.requestPasswordReset(username);
setSentStatus("success");
} catch (err) {
console.log("err ", err.code);
setSentStatus("failed");
} finally {
setTimeout(() => setSentStatus(""), 1000);
}
} }
}; };
@@ -51,6 +65,14 @@ function ForgotPassword(props) {
return ( return (
<div className="bg-white"> <div className="bg-white">
<Title title="Forgot password page" /> <Title title="Forgot password page" />
{sentStatus === "success" && (
<Alert type="success">
Reset password link has been sent to your email id
</Alert>
)}
{sentStatus === "failed" && (
<Alert type={"danger"}>Please setup email adapter </Alert>
)}
<div> <div>
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 "> <div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
<div className="w-[250px] h-[66px] inline-block"> <div className="w-[250px] h-[66px] inline-block">
+1 -1
View File
@@ -124,7 +124,7 @@ function Webhook() {
type="button" type="button"
onClick={() => onClick={() =>
openInNewTab( openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1" "https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
) )
} }
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none" className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
@@ -47,53 +47,78 @@ async function uploadFile(req, res) {
const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID; const DO_ACCESS_KEY_ID = process.env.DO_ACCESS_KEY_ID;
const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY; const DO_SECRET_ACCESS_KEY = process.env.DO_SECRET_ACCESS_KEY;
const DO_SPACE = process.env.DO_SPACE; const DO_SPACE = process.env.DO_SPACE;
const spacesEndpoint = new aws.Endpoint(DO_ENDPOINT);
const s3 = new aws.S3({
endpoint: spacesEndpoint,
accessKeyId: DO_ACCESS_KEY_ID,
secretAccessKey: DO_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: process.env.DO_REGION,
});
const parseBaseUrl = process.env.SERVER_URL; const parseBaseUrl = process.env.SERVER_URL;
const parseAppId = process.env.APP_ID; const parseAppId = process.env.APP_ID;
let fileStorage;
if (process.env.USE_LOCAL == "TRUE") { if (process.env.USE_LOCAL == 'TRUE') {
var fileStorage = multer.diskStorage({ fileStorage = multer.diskStorage({
destination: function(req, file, cb) { destination: function (req, file, cb) {
cb(null, "files/files"); cb(null, 'files/files');
}, },
metadata: function (req, file, cb) { metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' }); cb(null, { fieldName: 'OPENSIGN_METADATA' });
}, },
filename: function(req, file, cb) { filename: function (req, file, cb) {
let filename = file.originalname; let filename = file.originalname;
let newFileName = filename.split('.')[0]; let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1]; let extension = filename.split('.')[1];
newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension) newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName); console.log(newFileName);
cb(null, newFileName); cb(null, newFileName);
} },
}); });
} else { } else {
var fileStorage = multerS3({ try {
acl: 'public-read', const spacesEndpoint = new aws.Endpoint(DO_ENDPOINT);
s3, const s3 = new aws.S3({
bucket: DO_SPACE, endpoint: spacesEndpoint,
metadata: function (req, file, cb) { accessKeyId: DO_ACCESS_KEY_ID,
cb(null, { fieldName: 'OPENSIGN_METADATA' }); secretAccessKey: DO_SECRET_ACCESS_KEY,
}, signatureVersion: 'v4',
key: function (req, file, cb) { region: process.env.DO_REGION,
//console.log(file); });
let filename = file.originalname; fileStorage = multerS3({
let newFileName = filename.split('.')[0]; acl: 'public-read',
let extension = filename.split('.')[1]; s3,
newFileName = sanitizeFileName(newFileName + '_' + new Date().toISOString() + '.' + extension) bucket: DO_SPACE,
console.log(newFileName); metadata: function (req, file, cb) {
cb(null, newFileName); cb(null, { fieldName: 'OPENSIGN_METADATA' });
} },
}); key: function (req, file, cb) {
//console.log(file);
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName);
cb(null, newFileName);
},
});
} catch (err) {
fileStorage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'files/files');
},
metadata: function (req, file, cb) {
cb(null, { fieldName: 'OPENSIGN_METADATA' });
},
filename: function (req, file, cb) {
let filename = file.originalname;
let newFileName = filename.split('.')[0];
let extension = filename.split('.')[1];
newFileName = sanitizeFileName(
newFileName + '_' + new Date().toISOString() + '.' + extension
);
console.log(newFileName);
cb(null, newFileName);
},
});
}
} }
// const s3 = new aws.S3(); // const s3 = new aws.S3();
@@ -122,7 +147,7 @@ async function uploadFile(req, res) {
const status = 'Success'; const status = 'Success';
//res.header("Access-Control-Allow-Headers", "Content-Type"); //res.header("Access-Control-Allow-Headers", "Content-Type");
//res.setHeader("Access-Control-Allow-Origin", "*"); //res.setHeader("Access-Control-Allow-Origin", "*");
if (process.env.USE_LOCAL == "TRUE") { if (process.env.USE_LOCAL == 'TRUE') {
console.log(req.file); console.log(req.file);
var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`; var fileUrl = `${parseBaseUrl}/files/${parseAppId}/${req.file.filename}`;
} else { } else {
@@ -68,7 +68,7 @@ export default async function getDocumentList(request, response) {
if (request.posthog) { if (request.posthog) {
request.posthog?.capture({ request.posthog?.capture({
distinctId: parseUser.userId.email, distinctId: parseUser.userId.email,
event: 'api_get_document_list_by_status', event: `api_get_document_list_${docType}`,
properties: { response_code: 200, doc_type: docType }, properties: { response_code: 200, doc_type: docType },
}); });
} }
@@ -111,7 +111,7 @@ export default async function getDocumentList(request, response) {
if (request.posthog) { if (request.posthog) {
request.posthog?.capture({ request.posthog?.capture({
distinctId: parseUser.userId.email, distinctId: parseUser.userId.email,
event: 'api_get_document_list_by_status', event: `api_get_document_list_${docType}`,
properties: { response_code: 400, doc_type: docType }, properties: { response_code: 400, doc_type: docType },
}); });
} }
@@ -123,7 +123,7 @@ export default async function getDocumentList(request, response) {
if (request.posthog) { if (request.posthog) {
request.posthog?.capture({ request.posthog?.capture({
distinctId: parseUser.userId.email, distinctId: parseUser.userId.email,
event: 'api_get_document_list_by_status', event: `api_get_document_list_${docType}`,
properties: { response_code: 404, doc_type: docType }, properties: { response_code: 404, doc_type: docType },
}); });
} }
@@ -4,30 +4,29 @@ import formData from 'form-data';
import Mailgun from 'mailgun.js'; import Mailgun from 'mailgun.js';
import { createTransport } from 'nodemailer'; import { createTransport } from 'nodemailer';
let transporterSMTP;
let mailgunClient;
let mailgunDomain;
if (process.env.SMTP_ENABLE) {
transporterSMTP = createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT || 465,
secure: process.env.SMTP_SECURE || true,
auth: {
user: process.env.SMTP_USER_EMAIL,
pass: process.env.SMTP_PASS,
},
});
} else {
const mailgun = new Mailgun(formData);
mailgunClient = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY,
});
mailgunDomain = process.env.MAILGUN_DOMAIN;
}
async function sendmail(req) { async function sendmail(req) {
try { try {
let transporterSMTP;
let mailgunClient;
let mailgunDomain;
if (process.env.SMTP_ENABLE) {
transporterSMTP = createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT || 465,
secure: process.env.SMTP_SECURE || true,
auth: {
user: process.env.SMTP_USER_EMAIL,
pass: process.env.SMTP_PASS,
},
});
} else {
const mailgun = new Mailgun(formData);
mailgunClient = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY,
});
mailgunDomain = process.env.MAILGUN_DOMAIN;
}
if (req.params.url) { if (req.params.url) {
let Pdf = fs.createWriteStream('test.pdf'); let Pdf = fs.createWriteStream('test.pdf');
const writeToLocalDisk = () => { const writeToLocalDisk = () => {
+45 -29
View File
@@ -21,24 +21,32 @@ import { exec } from 'child_process';
import { createTransport } from 'nodemailer'; import { createTransport } from 'nodemailer';
import { app as v1 } from './cloud/customRoute/v1/apiV1.js'; import { app as v1 } from './cloud/customRoute/v1/apiV1.js';
import { PostHog } from 'posthog-node'; import { PostHog } from 'posthog-node';
const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
// console.log("configuration ", configuration); // console.log("configuration ", configuration);
let fsAdapter;
if (process.env.USE_LOCAL !== 'TRUE') { if (process.env.USE_LOCAL !== 'TRUE') {
const s3Options = { try {
bucket: process.env.DO_SPACE, // globalConfig.S3FilesAdapter.bucket, const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT);
baseUrl: process.env.DO_BASEURL, const s3Options = {
region: process.env.DO_REGION, bucket: process.env.DO_SPACE, // globalConfig.S3FilesAdapter.bucket,
directAccess: true, baseUrl: process.env.DO_BASEURL,
preserveFileName: true, region: process.env.DO_REGION,
s3overrides: { directAccess: true,
accessKeyId: process.env.DO_ACCESS_KEY_ID, preserveFileName: true,
secretAccessKey: process.env.DO_SECRET_ACCESS_KEY, s3overrides: {
endpoint: spacesEndpoint, accessKeyId: process.env.DO_ACCESS_KEY_ID,
}, secretAccessKey: process.env.DO_SECRET_ACCESS_KEY,
}; endpoint: spacesEndpoint,
var fsAdapter = new S3Adapter(s3Options); },
};
fsAdapter = new S3Adapter(s3Options);
} catch (err) {
console.log('Please provide AWS credintials in env file! Defaulting to local storage.');
fsAdapter = new FSFilesAdapter({
filesSubDirectory: 'files', // optional, defaults to ./files
});
}
} else { } else {
var fsAdapter = new FSFilesAdapter({ fsAdapter = new FSFilesAdapter({
filesSubDirectory: 'files', // optional, defaults to ./files filesSubDirectory: 'files', // optional, defaults to ./files
}); });
} }
@@ -66,7 +74,6 @@ if (process.env.SMTP_ENABLE) {
mailgunDomain = process.env.MAILGUN_DOMAIN; mailgunDomain = process.env.MAILGUN_DOMAIN;
} }
export const config = { export const config = {
databaseURI: databaseURI:
process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev', process.env.DATABASE_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/dev',
@@ -75,17 +82,19 @@ export const config = {
}, },
appId: process.env.APP_ID || 'myAppId', appId: process.env.APP_ID || 'myAppId',
maxLimit: 500, maxLimit: 500,
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret! masterKey: process.env.MASTER_KEY, //Add your master key here. Keep it secret!
masterKeyIps: ['0.0.0.0/0', '::1'], // '::1' masterKeyIps: ['0.0.0.0/0', '::1'], // '::1'
serverURL: process.env.SERVER_URL || 'http://localhost:8080/app', // Don't forget to change to https if needed serverURL: process.env.SERVER_URL || 'http://localhost:8080/app', // Don't forget to change to https if needed
verifyUserEmails: true, verifyUserEmails: process.env.SMTP_ENABLE || process.env.MAILGUN_API_KEY ? true : false,
publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app', publicServerURL: process.env.SERVER_URL || 'http://localhost:8080/app',
// Your apps name. This will appear in the subject and body of the emails that are sent. // Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'Open Sign', appName: 'Open Sign',
allowClientClassCreation: false, allowClientClassCreation: false,
emailAdapter: allowExpiredAuthDataToken: false,
process.env.SMTP_ENABLE || process.env.MAILGUN_API_KEY encodeParseObjectInCloudFunction: true,
? { ...(process.env.SMTP_ENABLE || process.env.MAILGUN_API_KEY
? {
emailAdapter: {
module: 'parse-server-api-mail-adapter', module: 'parse-server-api-mail-adapter',
options: { options: {
// The email address from which emails are sent. // The email address from which emails are sent.
@@ -116,8 +125,9 @@ export const config = {
} else if (transporterMail) await transporterMail.sendMail(payload); } else if (transporterMail) await transporterMail.sendMail(payload);
}, },
}, },
} },
: null, }
: {}),
filesAdapter: fsAdapter, filesAdapter: fsAdapter,
auth: { auth: {
google: { google: {
@@ -170,9 +180,13 @@ app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix // Serve the Parse API on the /parse URL prefix
if (!process.env.TESTING) { if (!process.env.TESTING) {
const mountPath = process.env.PARSE_MOUNT || '/app'; const mountPath = process.env.PARSE_MOUNT || '/app';
const server = new ParseServer(config); try {
await server.start(); const server = new ParseServer(config);
app.use(mountPath, server.app); await server.start();
app.use(mountPath, server.app);
} catch (err) {
console.log(err);
}
} }
// Mount your custom express app // Mount your custom express app
app.use('/', customRoute); app.use('/', customRoute);
@@ -196,8 +210,12 @@ if (!process.env.TESTING) {
httpServer.headersTimeout = 100000; // in milliseconds httpServer.headersTimeout = 100000; // in milliseconds
httpServer.listen(port, function () { httpServer.listen(port, function () {
console.log('parse-server-example running on port ' + port + '.'); console.log('parse-server-example running on port ' + port + '.');
const migrate = `APPLICATION_ID=${process.env.APP_ID} SERVER_URL=http://localhost:8080/app MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`; const isWindows = process.platform === 'win32';
// console.log('isWindows', isWindows);
const migrate = isWindows
? `set APPLICATION_ID=${process.env.APP_ID}&& set SERVER_URL=http://localhost:8080/app&& set MASTER_KEY=${process.env.MASTER_KEY}&& npx parse-dbtool migrate`
: `APPLICATION_ID=${process.env.APP_ID} SERVER_URL=http://localhost:8080/app MASTER_KEY=${process.env.MASTER_KEY} npx parse-dbtool migrate`;
exec(migrate, (error, stdout, stderr) => { exec(migrate, (error, stdout, stderr) => {
if (error) { if (error) {
console.error(`Error: ${error.message}`); console.error(`Error: ${error.message}`);
@@ -211,6 +229,4 @@ if (!process.env.TESTING) {
console.log(`Command output: ${stdout}`); console.log(`Command output: ${stdout}`);
}); });
}); });
// This will enable the Live Query real-time server
await ParseServer.createLiveQueryServer(httpServer);
} }
@@ -84,6 +84,7 @@ function PlaceHolderSign() {
const [signerExistModal, setSignerExistModal] = useState(false); const [signerExistModal, setSignerExistModal] = useState(false);
const [isDontShow, setIsDontShow] = useState(false); const [isDontShow, setIsDontShow] = useState(false);
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [mailStatus, setMailStatus] = useState("");
const color = [ const color = [
"#93a3db", "#93a3db",
"#e6c3db", "#e6c3db",
@@ -724,6 +725,72 @@ function PlaceHolderSign() {
} }
if (sendMail.data.result.status === "success") { if (sendMail.data.result.status === "success") {
setMailStatus("success");
const signers = signersdata?.map((x) => {
return {
__type: "Pointer",
className: "contracts_Contactbook",
objectId: x.objectId
};
});
const addExtraDays = pdfDetails[0]?.TimeToCompleteDays
? pdfDetails[0].TimeToCompleteDays
: 15;
const currentUser = signersdata.find((x) => x.Email === currentId);
setCurrentId(currentUser?.objectId);
let updateExpiryDate, data;
updateExpiryDate = new Date();
updateExpiryDate.setDate(updateExpiryDate.getDate() + addExtraDays);
try {
if (updateExpiryDate) {
data = {
Placeholders: signerPos,
SignedUrl: pdfDetails[0].URL,
Signers: signers,
ExpiryDate: {
iso: updateExpiryDate,
__type: "Date"
}
};
} else {
data = {
Placeholders: signerPos,
SignedUrl: pdfDetails[0].URL,
Signers: signers
};
}
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${documentId}`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
}
}
)
.then((result) => {
setIsSend(true);
setIsMailSend(true);
const loadObj = {
isLoad: false
};
setIsLoading(loadObj);
})
.catch((err) => {
console.log("axois err ", err);
});
} catch (e) {
console.log("error", e);
}
} else {
setMailStatus("failed");
const signers = signersdata?.map((x) => { const signers = signersdata?.map((x) => {
return { return {
__type: "Pointer", __type: "Pointer",
@@ -1059,7 +1126,11 @@ function PlaceHolderSign() {
}} }}
> >
<div style={{ height: "100%", padding: 20 }}> <div style={{ height: "100%", padding: 20 }}>
<p>You have successfully sent mails to all recipients!</p> {mailStatus === "success" ? (
<p>You have successfully sent mails to all recipients!</p>
) : (
<p>Please setup mail adapter to send mail!</p>
)}
{currentId && ( {currentId && (
<p>Do you want to sign documents right now ?</p> <p>Do you want to sign documents right now ?</p>
)} )}