diff --git a/apps/OpenSign/src/App.js b/apps/OpenSign/src/App.js index cbfc5141a..3e0119d85 100644 --- a/apps/OpenSign/src/App.js +++ b/apps/OpenSign/src/App.js @@ -15,6 +15,7 @@ import ForgetPassword from "./routes/ForgetPassword"; import ChangePassword from "./routes/ChangePassword"; import ReportMicroapp from "./components/ReportMicroapp"; import LoadMf from "./routes/LoadMf"; +import GenerateToken from "./routes/GenerateToken"; import ValidateRoute from "./primitives/ValidateRoute"; function App() { @@ -155,6 +156,14 @@ function App() { } /> + + + + } + /> } /> {/* } /> */} diff --git a/apps/OpenSign/src/routes/GenerateToken.js b/apps/OpenSign/src/routes/GenerateToken.js new file mode 100644 index 000000000..ce74313d4 --- /dev/null +++ b/apps/OpenSign/src/routes/GenerateToken.js @@ -0,0 +1,152 @@ +import React, { useEffect, useState } from "react"; +import Title from "../components/Title"; +import axios from "axios"; +import Alert from "../primitives/Alert"; + +function GenerateToken() { + const [parseBaseUrl] = useState(localStorage.getItem("baseUrl")); + const [parseAppId] = useState(localStorage.getItem("parseAppId")); + const [apiToken, SetApiToken] = useState(""); + const [isLoader, setIsLoader] = useState(true); + const [copied, setCopied] = useState(false); + const [isGenerate, setIsGenerate] = useState(false); + const [isErr, setIsErr] = useState(false); + + useEffect(() => { + fetchToken(); + // eslint-disable-next-line + }, []); + + const fetchToken = async () => { + try { + const url = parseBaseUrl + "functions/getapitoken"; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessiontoken: localStorage.getItem("accesstoken") + }; + const res = await axios.post(url, {}, { headers: headers }); + if (res) { + SetApiToken(res.data.result.result); + } + setIsLoader(false); + } catch (err) { + SetApiToken(); + setIsLoader(false); + console.log("Err", err); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + setIsLoader(true); + try { + const url = parseBaseUrl + "functions/generateapitoken"; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": parseAppId, + sessiontoken: localStorage.getItem("accesstoken") + }; + await axios.post(url, {}, { headers: headers }).then((res) => { + if (res) { + SetApiToken(res.data.result.token); + // localStorage.setItem("apiToken", res.data.result.token); + setIsGenerate(true); + setTimeout(() => { + setIsGenerate(false); + }, 1500); + setIsLoader(false); + } else { + console.error("Error while generating Token"); + setIsLoader(false); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); + } + }); + } catch (error) { + setIsLoader(false); + setIsErr(true); + setTimeout(() => { + setIsErr(false); + }, 1500); + + console.log("err", error); + } + }; + + const copytoclipboard = (text) => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1500); // Reset copied state after 1.5 seconds + }; + return ( + + + {isGenerate && ( + <Alert type="success">Token generated successfully!</Alert> + )} + {copied && <Alert type="success">Copied</Alert>} + {isErr && <Alert type="danger">Something went wrong!</Alert>} + {isLoader ? ( + <div + style={{ + height: "100vh", + display: "flex", + alignItems: "center", + justifyContent: "center" + }} + > + <div + style={{ + fontSize: "45px", + color: "#3dd3e0" + }} + className="loader-37" + ></div> + </div> + ) : ( + <div className="bg-white flex flex-col justify-center shadow rounded"> + <ul className="w-full flex flex-col p-2 text-sm"> + <li + className={`flex justify-between items-center border-t-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Api Token:</span>{" "} + <span + id="token" + className="w-[60%] md:text-end cursor-pointer" + onClick={() => copytoclipboard(apiToken)} + > + {apiToken && apiToken} + </span> + </li> + <li + className={`flex justify-between items-center border-y-[1px] border-gray-300 break-all py-2`} + > + <span className="w-[40%]">Application Id:</span>{" "} + <span + className="w-[60%] md:text-end cursor-pointer" + onClick={() => copytoclipboard(localStorage.getItem("AppID12"))} + > + {localStorage.getItem("AppID12")} + </span> + </li> + </ul> + <div className="flex justify-center pb-4"> + <button + type="button" + onClick={handleSubmit} + className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-4 py-2 text-xs md:text-base" + > + {apiToken ? "Regenerate Token" : "Generate Token"} + </button> + </div> + </div> + )} + </React.Fragment> + ); +} + +export default GenerateToken; diff --git a/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js new file mode 100644 index 000000000..84418f549 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/apiV1.js @@ -0,0 +1,76 @@ +//--npm modules +import express from 'express'; +import cors from 'cors'; +export const app = express(); +import dotenv from 'dotenv'; +import getUser from './routes/getUser.js'; +import getDocumentList from './routes/getDocumentList.js'; +import getDocument from './routes/getDocument.js'; +import getContact from './routes/getContact.js'; +import deleteContact from './routes/deleteContact.js'; +import getContactList from './routes/getContactList.js'; +import createDocument from './routes/createDocument.js'; +import createTemplate from './routes/createTemplate.js'; +import getTemplate from './routes/getTemplate.js'; +import deletedTemplate from './routes/deleteTemplate.js'; +import getTemplatetList from './routes/getTemplateList.js'; +import updateTemplate from './routes/updateTemplate.js'; +import createContact from './routes/createContact.js'; +import multer from 'multer'; +import fs from 'node:fs'; +import updateDocument from './routes/updateDocument.js'; +import deleteDocument from './routes/deleteDocument.js'; + +dotenv.config(); +const storage = multer.memoryStorage(); +const upload = multer({ storage: storage }); + +app.use(cors()); +app.use(express.json({ limit: '50mb' })); +app.use(express.urlencoded({ limit: '50mb', extended: true })); + +// get user details whose api token used +app.get('/getuser', getUser); + +// get contact on the basis of id +app.post('/createcontact', createContact); + +// get contact on the basis of id +app.get('/contact/:contact_id', getContact); + +// soft delete contact +app.delete('/contact/:contact_id', deleteContact); + +// get list of contacts +app.get('/contactlist', getContactList); + +// create Document +app.post('/createdocument', upload.array('file', 1), createDocument); + +// get Document on the basis of id +app.get('/document/:document_id', getDocument); + +// get document on the basis of id +app.put('/document/:document_id', updateDocument); + +// get document on the basis of id +app.delete('/document/:document_id', deleteDocument); + +// get all types of documents on the basis of doctype +app.get('/documentlist/:doctype', getDocumentList); + +// create Template +app.post('/createtemplate',upload.array('file', 1), createTemplate); + +// get template on the basis of id +app.get('/template/:template_id', getTemplate); + +// get template on the basis of id +app.put('/template/:template_id', updateTemplate); + +// get template on the basis of id +app.delete('/template/:template_id', deletedTemplate); + +// get all types of documents on the basis of doctype +app.get('/templatelist', getTemplatetList); + diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js new file mode 100644 index 000000000..b335f4889 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createContact.js @@ -0,0 +1,133 @@ +import axios from 'axios'; +export default async function createContact(request, response) { + const serverUrl = process.env.SERVER_URL; + const appId = process.env.APP_ID; + const name = request.body.name; + const phone = request.body.phone; + const email = request.body.email; + + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + try { + const Tenant = new Parse.Query('partners_Tenant'); + Tenant.equalTo('UserId', userId); + const tenantRes = Tenant.first({ useMasterKey: true }); + + const contactQuery = new Parse.Object('contracts_Contactbook'); + contactQuery.set('Name', name); + contactQuery.set('Phone', phone); + contactQuery.set('Email', email); + contactQuery.set('UserRole', 'contracts_Guest'); + + if (tenantRes) { + contactQuery.set('TenantId', { + __type: 'Pointer', + className: 'partners_Tenant', + objectId: tenantRes.id, + }); + } + try { + const _users = Parse.Object.extend('User'); + const _user = new _users(); + _user.set('name', name); + _user.set('username', email); + _user.set('email', email); + _user.set('phone', phone); + _user.set('password', phone); + + const user = await _user.save(); + if (user) { + const roleurl = `${serverUrl}/functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: user.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); + + contactQuery.set('UserId', user); + const acl = new Parse.ACL(); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(user.id, true); + acl.setWriteAccess(user.id, true); + + contactQuery.setACL(acl); + + const contactRes = await contactQuery.save(); + // const parseData = JSON.parse(JSON.stringify(res)); + return response.json({ + message: 'Contact created sucessfully!', + result: { objectId: contactRes.id }, + }); + } + } catch (err) { + console.log('err ', err); + if (err.code === 202) { + const params = { email: email }; + const userRes = await Parse.Cloud.run('getUserId', params); + const roleurl = `${parseBaseUrl}functions/AddUserToRole`; + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': parseAppId, + // sessionToken: localStorage.getItem('accesstoken'), + }; + const body = { + appName: 'contracts', + roleName: 'contracts_Guest', + userId: userRes.id, + }; + await axios.post(roleurl, body, { headers: headers }); + const currentUser = Parse.User.current(); + contactQuery.set('CreatedBy', Parse.User.createWithoutData(currentUser.id)); + + contactQuery.set('UserId', { + __type: 'Pointer', + className: '_User', + objectId: userRes.id, + }); + const acl = new Parse.ACL(); + acl.setReadAccess(currentUser.id, true); + acl.setWriteAccess(currentUser.id, true); + acl.setReadAccess(userRes.id, true); + acl.setWriteAccess(userRes.id, true); + + contactQuery.setACL(acl); + const contactRes = await contactQuery.save(); + if (contactRes) { + const parseRes = JSON.parse(JSON.stringify(contactRes)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updateAt: parseRes.updateAt, + }); + } + // const parseData = JSON.parse(JSON.stringify(res)); + } + } + } catch (err) { + return response.status(404).json({ error: 'Something went wrong, please try again later!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js new file mode 100644 index 000000000..0c7b190c8 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createDocument.js @@ -0,0 +1,78 @@ +const randomId = () => Math.floor(1000 + Math.random() * 9000); +export default async function createDocument(request, response) { + const name = request.body.Title; + const note = request.body.Note; + const description = request.body.Description; + const signers = request.body.Signers; + const folderId = request.body.FolderId; + // const file = request.body.file; + const url = process.env.SERVER_URL; + const fileData = request.files[0] ? request.files[0].buffer : null; + try { + const file = new Parse.File(request.files[0].originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); + + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userId); + const extUser = await contractsUser.first({ useMasterKey: true }); + const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; + + const folderPtr = { __type: 'Pointer', className: 'contracts_Document', objectId: folderId }; + + const object = new Parse.Object('contracts_Document'); + object.set('Name', name); + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', fileUrl); + object.set('CreatedBy', userId); + object.set('ExtUserPtr', extUserPtr); + if (signers) { + const placeholders = signers.map(x => ({ + email: x, + Id: randomId(), + Role: '', + blockColor: '', + signerObjId: '', + signerPtr: {}, + placeHolder: [], + })); + object.set('Placeholders', placeholders); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(id, true); + newACL.setWriteAccess(id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + return response.json({ objectId: res.id, url: url }); + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js new file mode 100644 index 000000000..c477cdf9d --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/createTemplate.js @@ -0,0 +1,77 @@ +const randomId = () => Math.floor(1000 + Math.random() * 9000); +export default async function createTemplate(request, response) { + const name = request.body.Title; + const note = request.body.Note; + const description = request.body.Description; + const signers = request.body.Signers; + const folderId = request.body.FolderId; + // const file = request.body.file; + const url = process.env.SERVER_URL; + const fileData = request.files[0] ? request.files[0].buffer : null; + try { + const file = new Parse.File(request.files[0].originalname, { + base64: fileData.toString('base64'), + }); + await file.save({ useMasterKey: true }); + const fileUrl = file.url(); + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + + const contractsUser = new Parse.Query('contracts_Users'); + contractsUser.equalTo('UserId', userId); + const extUser = await contractsUser.first({ useMasterKey: true }); + const extUserPtr = { __type: 'Pointer', className: 'contracts_Users', objectId: extUser.id }; + + const folderPtr = { __type: 'Pointer', className: 'contracts_Template', objectId: folderId }; + + const object = new Parse.Object('contracts_Template'); + object.set('Name', name); + if (note) { + object.set('Note', note); + } + if (description) { + object.set('Description', description); + } + object.set('URL', fileUrl); + object.set('CreatedBy', userId); + object.set('ExtUserPtr', extUserPtr); + if (signers) { + const placeholders = signers.map((x, i) => ({ + email: x, + Id: randomId(), + Role: 'User ' + (i + 1), + blockColor: '', + signerObjId: '', + signerPtr: {}, + placeHolder: [], + })); + object.set('Placeholders', placeholders); + } + if (folderId) { + object.set('Folder', folderPtr); + } + const newACL = new Parse.ACL(); + newACL.setPublicReadAccess(false); + newACL.setPublicWriteAccess(false); + newACL.setReadAccess(id, true); + newACL.setWriteAccess(id, true); + object.setACL(newACL); + const res = await object.save(null, { useMasterKey: true }); + return response.json({ objectId: res.id, url: url }); + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js new file mode 100644 index 000000000..e0997f160 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteContact.js @@ -0,0 +1,45 @@ +export default async function deleteContact(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('objectId', request.params.contact_id); + Contactbook.equalTo('CreatedBy', userId); + const res = await Contactbook.first({ useMasterKey: true }); + if (res) { + const isDeleted = res.get('IsDeleted'); + if (isDeleted && isDeleted) { + return response.status(404).json({ error: 'Contact not found!' }); + } else { + const Contactbook = Parse.Object.extend('contracts_Contactbook'); + const deleteQuery = new Contactbook(); + deleteQuery.id = request.params.contact_id; + deleteQuery.set('IsDeleted', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ + objectId: request.params.contact_id, + deletedAt: deleteRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Contact not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js new file mode 100644 index 000000000..d3faa0c9d --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteDocument.js @@ -0,0 +1,45 @@ +export default async function deleteDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Document'); + Document.equalTo('objectId', request.params.document_id); + Document.equalTo('CreatedBy', userId); + const res = await Document.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ error: 'Document not found!' }); + } else { + const Document = Parse.Object.extend('contracts_Document'); + const deleteQuery = new Document(); + deleteQuery.id = request.params.document_id; + deleteQuery.set('IsArchive', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ + objectId: request.params.document_id, + deletedAt: deleteRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Document not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js new file mode 100644 index 000000000..f8e1c5ade --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/deleteTemplate.js @@ -0,0 +1,45 @@ +export default async function deletedTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', request.params.template_id); + template.equalTo('CreatedBy', userId); + const res = await template.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ error: 'Template not found!' }); + } else { + const template = Parse.Object.extend('contracts_Template'); + const deleteQuery = new template(); + deleteQuery.id = request.params.template_id; + deleteQuery.set('IsArchive', true); + const deleteRes = await deleteQuery.save(null, { useMasterKey: true }); + if (deleteRes) { + return response.json({ + objectId: request.params.template_id, + deletedAt: deleteRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Template not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js new file mode 100644 index 000000000..e0438036a --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContact.js @@ -0,0 +1,41 @@ +export default async function getContact(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('objectId', request.params.contact_id); + Contactbook.equalTo('CreatedBy', userId); + Contactbook.notEqualTo('IsDeleted', true); + Contactbook.select('Name,Email,Phone'); + + const res = await Contactbook.first({ useMasterKey: true }); + if (res) { + const parseRes = JSON.parse(JSON.stringify(res)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + createdAt: parseRes.createdAt, + updatedAt: parseRes.updatedAt, + }); + } else { + return response.status(404).json({ error: 'Contact not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js new file mode 100644 index 000000000..93a28b757 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getContactList.js @@ -0,0 +1,43 @@ +export default async function getContactList(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; + const Contactbook = new Parse.Query('contracts_Contactbook'); + Contactbook.equalTo('CreatedBy', userId); + Contactbook.notEqualTo('IsDeleted', true); + Contactbook.limit(limit); + Contactbook.skip(skip); + const res = await Contactbook.find({ useMasterKey: true }); + if (res && res.length > 0) { + const parseRes = JSON.parse(JSON.stringify(res)); + const contactlist = parseRes.map(x => ({ + objectId: x.objectId, + Name: x.Name, + Email: x.Email, + Phone: x.Phone, + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + return response.json({ result: contactlist }); + } else { + return response.json({ result: [] }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js new file mode 100644 index 000000000..0417dd354 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocument.js @@ -0,0 +1,45 @@ +export default async function getDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Document = new Parse.Query('contracts_Document'); + Document.equalTo('objectId', request.params.document_id); + Document.equalTo('CreatedBy', userId); + Document.notEqualTo('IsArchive', true); + Document.include('Signers'); + Document.include('Folder'); + Document.include('ExtUserPtr'); + const res = await Document.first({ useMasterKey: true }); + if (res) { + const document = JSON.parse(JSON.stringify(res)); + return response.json({ + objectId: document.objectId, + Title: document.Name, + Note: document.Note || '', + Folder: document?.Folder?.Name || 'OpenSign™ Drive', + File: document?.SignedUrl || document.URL, + Owner: document?.ExtUserPtr?.Name, + Signers: document?.Signers?.map(y => y?.Name) || '', + createdAt: document.createdAt, + updatedAt: document.updatedAt, + }); + } else { + return response.status(404).json({ error: 'Document not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js new file mode 100644 index 000000000..3ef4d338c --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getDocumentList.js @@ -0,0 +1,80 @@ +import axios from 'axios'; +import reportJson from '../../../parsefunction/reportsJson.js'; +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getDocumentList(request, response) { + const reqToken = request.headers['x-api-token']; + const appId = process.env.APP_ID; + const serverUrl = process.env.SERVER_URL; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const docType = request.params.doctype; + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; + let reportId; + switch (docType) { + case 'draftdocuments': + reportId = 'ByHuevtCFY'; + break; + case 'signaturerequest': + reportId = '4Hhwbp482K'; + break; + case 'inprogressdocuments': + reportId = '1MwEuxLEkF'; + break; + case 'completedocuments': + reportId = 'kQUoW4hUXz'; + break; + case 'expiredocuments': + reportId = 'zNqBHXHsYH'; + break; + case 'declinedocuments': + reportId = 'UPr2Fm5WY3'; + break; + default: + reportId = ''; + } + const json = reportId && reportJson(reportId, userId); + const clsName = 'contracts_Document'; + if (reportId && json) { + const { params, keys } = json; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results.length > 0) { + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + title: x.Name, + note: x.Note || '', + folder: x?.Folder?.Name || 'OpenSign™ Drive', + file: x?.SignedUrl || x.URL, + owner: x?.ExtUserPtr?.Name, + signers: x?.Signers?.map(y => y?.Name) || '', + created_at: x.createdAt, + updated_at: x.updatedAt, + })); + return response.json({ result: updateRes }); + } else { + return response.json({ result: [] }); + } + } else { + return response.status(404).json({ error: 'Report not available!' }); + } + } + return response.status(405).json({ error: 'Invalid API Token!' }); +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js new file mode 100644 index 000000000..8a7b4ec79 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplate.js @@ -0,0 +1,45 @@ +export default async function getTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const Template = new Parse.Query('contracts_Template'); + Template.equalTo('objectId', request.params.template_id); + Template.equalTo('CreatedBy', userId); + Template.notEqualTo('IsArchive', true); + Template.include('Signers'); + Template.include('Folder'); + Template.include('ExtUserPtr'); + const res = await Template.first({ useMasterKey: true }); + if (res) { + const template = JSON.parse(JSON.stringify(res)); + return response.json({ + objectId: template.objectId, + Title: template.Name, + Note: template.Note || '', + Folder: template?.Folder?.Name || 'OpenSign™ Drive', + File: template?.SignedUrl || x.URL, + Owner: template?.ExtUserPtr?.Name, + Signers: template?.Signers?.map(y => y?.Name) || '', + createdAt: template.createdAt, + updatedAt: template.updatedAt, + }); + } else { + return response.status(404).json({ error: 'Template not found!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js new file mode 100644 index 000000000..d8e046853 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getTemplateList.js @@ -0,0 +1,70 @@ +import axios from 'axios'; +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getTemplatetList(request, response) { + const reqToken = request.headers['x-api-token']; + const appId = process.env.APP_ID; + const serverUrl = process.env.SERVER_URL; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const limit = request?.query?.limit ? request.query.limit : 100; + const skip = request?.query?.skip ? request.query.skip : 0; + + const clsName = 'contracts_Template'; + const params = { + Type: { $ne: 'Folder' }, + CreatedBy: { + __type: 'Pointer', + className: '_User', + objectId: userId, + }, + IsArchive: { $ne: true }, + }; + const keys = [ + 'Name', + 'Note', + 'Description', + 'Folder.Name', + 'URL', + 'SignedUrl', + 'ExtUserPtr.Name', + 'Signers.Name', + ]; + const orderBy = '-updatedAt'; + const strParams = JSON.stringify(params); + const strKeys = keys.join(); + const headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': appId, + 'X-Parse-Master-Key': process.env.MASTER_KEY, + }; + const url = `${serverUrl}/classes/${clsName}?where=${strParams}&keys=${strKeys}&order=${orderBy}&skip=${skip}&limit=${limit}&include=AuditTrail.UserPtr`; + const res = await axios.get(url, { headers: headers }); + if (res.data && res.data.results.length > 0) { + const updateRes = res.data.results.map(x => ({ + objectId: x.objectId, + Title: x.Name, + Note: x.Note || '', + Folder: x?.Folder?.Name || 'OpenSign™ Drive', + File: x?.SignedUrl || x.URL, + Owner: x?.ExtUserPtr?.Name, + Signers: x?.Signers?.map(y => y?.Name) || '', + createdAt: x.createdAt, + updatedAt: x.updatedAt, + })); + + return response.json({ result: updateRes }); + } else { + return response.json({ result: [] }); + } + } + return response.status(405).json({ error: 'Invalid API Token!' }); +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js new file mode 100644 index 000000000..20015f0b9 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/getUser.js @@ -0,0 +1,36 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +export default async function getUser(request, response) { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const userId = token.get('Id'); + const query = new Parse.Query('contracts_Users'); + query.equalTo('UserId', { __type: 'Pointer', className: '_User', objectId: userId }); + query.exclude('IsContactEntry,TourStatus,UserRole,TenantId,UserId,CreatedBy,Plan'); + const user = await query.first({ useMasterKey: true }); + if (user) { + const parseRes = JSON.parse(JSON.stringify(user)); + return response.json({ + objectId: parseRes.objectId, + Name: parseRes.Name, + Email: parseRes.Email, + Phone: parseRes.Phone, + JobTitle: parseRes.JobTitle, + Company: parseRes.Company, + createdAt: parseRes.createdAt, + updateAt: parseRes.updateAt, + }); + } else { + return response.status(404).json({ error: 'User not found!' }); + } + } + return response.status(405).json({ error: 'Invalid API Token!' }); +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js new file mode 100644 index 000000000..c4dcf6279 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateDocument.js @@ -0,0 +1,67 @@ +export default async function updateDocument(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const allowedKeys = ['Name', 'Note', 'Description']; + const objectKeys = Object.keys(request.body); + const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + if (isValid) { + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const document = new Parse.Query('contracts_Document'); + document.equalTo('objectId', request.params.document_id); + document.equalTo('CreatedBy', userId); + const res = await document.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ message: 'Document not found!' }); + } else { + const document = Parse.Object.extend('contracts_Document'); + const updateQuery = new document(); + updateQuery.id = request.params.document_id; + if (request?.body?.Name) { + updateQuery.set('Name', request?.body?.Name); + } + if (request?.body?.Note) { + updateQuery.set('Note', request?.body?.Note); + } + if (request?.body?.Description) { + updateQuery.set('Name', request?.body?.Description); + } + if (request?.body?.FolderId) { + updateQuery.set('Folder', { + __type: 'Pointer', + className: 'contracts_Document', + objectId: request?.body?.FolderId, + }); + } + const updatedRes = await updateQuery.save(null, { useMasterKey: true }); + if (updatedRes) { + return response.json({ + objectId: updatedRes.id, + updatedAt: updatedRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Document not found!' }); + } + } else { + return response.status(400).json({ error: 'Please provide valid field names!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js new file mode 100644 index 000000000..072e07e12 --- /dev/null +++ b/apps/OpenSignServer/cloud/customRoute/v1/routes/updateTemplate.js @@ -0,0 +1,67 @@ +export default async function updateTemplate(request, response) { + try { + const reqToken = request.headers['x-api-token']; + if (!reqToken) { + return response.status(400).json({ error: 'Please Provide API Token' }); + } + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('token', reqToken); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // Valid Token then proceed request + const id = token.get('Id'); + const allowedKeys = ['Name', 'Note', 'Description']; + const objectKeys = Object.keys(request.body); + const isValid = objectKeys.every(key => allowedKeys.includes(key)) && objectKeys.length > 0; + if (isValid) { + const userId = { __type: 'Pointer', className: '_User', objectId: id }; + const template = new Parse.Query('contracts_Template'); + template.equalTo('objectId', request.params.template_id); + template.equalTo('CreatedBy', userId); + const res = await template.first({ useMasterKey: true }); + if (res) { + const isArchive = res.get('IsArchive'); + if (isArchive && isArchive) { + return response.status(404).json({ message: 'Template not found!' }); + } else { + const template = Parse.Object.extend('contracts_Template'); + const updateQuery = new template(); + updateQuery.id = request.params.template_id; + if (request?.body?.Name) { + updateQuery.set('Name', request?.body?.Name); + } + if (request?.body?.Note) { + updateQuery.set('Note', request?.body?.Note); + } + if (request?.body?.Description) { + updateQuery.set('Name', request?.body?.Description); + } + if (request?.body?.FolderId) { + updateQuery.set('Folder', { + __type: 'Pointer', + className: 'contracts_Template', + objectId: request?.body?.FolderId, + }); + } + const updatedRes = await updateQuery.save(null, { useMasterKey: true }); + if (updatedRes) { + return response.json({ + objectId: updatedRes.id, + updatedAt: updatedRes.get('updatedAt'), + }); + } + } + } else { + return response.status(404).json({ error: 'Template not found!' }); + } + } else { + return response.status(400).json({ error: 'Please provide valid field names!' }); + } + } else { + return response.status(405).json({ error: 'Invalid API Token!' }); + } + } catch (err) { + console.log('err ', err); + return response.json(err); + } +} diff --git a/apps/OpenSignServer/cloud/main.js b/apps/OpenSignServer/cloud/main.js index 7532bc00d..b6ff1ed7a 100644 --- a/apps/OpenSignServer/cloud/main.js +++ b/apps/OpenSignServer/cloud/main.js @@ -17,6 +17,8 @@ import getUserDetails from './parsefunction/getUserDetails.js'; import getDocument from './parsefunction/getDocument.js'; import getDrive from './parsefunction/getDrive.js'; import getReport from './parsefunction/getReport.js'; +import generateApiToken from './parsefunction/generateApiToken.js'; +import getapitoken from './parsefunction/getapitoken.js'; import TemplateAfterSave from './parsefunction/TemplateAfterSave.js'; import GetTemplate from './parsefunction/GetTemplate.js'; @@ -34,10 +36,12 @@ Parse.Cloud.define('AuthLoginAsMail', AuthLoginAsMail); Parse.Cloud.define('getUserId', getUserId); Parse.Cloud.define('getUserDetails', getUserDetails); Parse.Cloud.define('getDocument', getDocument); -Parse.Cloud.define('getDrive', getDrive) -Parse.Cloud.define('getReport', getReport) -Parse.Cloud.define("getTemplate", GetTemplate) +Parse.Cloud.define('getDrive', getDrive); +Parse.Cloud.define('getReport', getReport); +Parse.Cloud.define('generateapitoken', generateApiToken); +Parse.Cloud.define('getapitoken', getapitoken); +Parse.Cloud.define('getTemplate', GetTemplate); Parse.Cloud.afterSave('contracts_Document', DocumentAftersave); Parse.Cloud.afterSave('contracts_Contactbook', ContactbookAftersave); Parse.Cloud.afterSave('contracts_Users', ContractUsersAftersave); -Parse.Cloud.afterSave("contracts_Template", TemplateAfterSave) \ No newline at end of file +Parse.Cloud.afterSave('contracts_Template', TemplateAfterSave); diff --git a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js index 3fd3ad125..701ebd608 100644 --- a/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js +++ b/apps/OpenSignServer/cloud/parsefunction/DocumentAftersave.js @@ -43,7 +43,9 @@ async function DocumentAftersave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id && request.user) { + await updateSelfDoc(request.object.id); + } } } else { if (request.user) { @@ -51,7 +53,9 @@ async function DocumentAftersave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id) { + await updateSelfDoc(request.object.id); + } } } } diff --git a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js index 7d22ccb86..d5bcc168a 100644 --- a/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js +++ b/apps/OpenSignServer/cloud/parsefunction/TemplateAfterSave.js @@ -8,7 +8,9 @@ export default async function TemplateAfterSave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id && request.user) { + await updateSelfDoc(request.object.id); + } } } else { if (request.user) { @@ -16,7 +18,9 @@ export default async function TemplateAfterSave(request) { if (signers && signers.length > 0) { await updateAclDoc(request.object.id); } else { - await updateSelfDoc(request.object.id); + if (request?.object?.id) { + await updateSelfDoc(request.object.id); + } } } } @@ -66,7 +70,7 @@ export default async function TemplateAfterSave(request) { async function updateSelfDoc(objId) { // console.log("Inside updateSelfDoc func") - + const Query = new Parse.Query('contracts_Template'); const updateACL = await Query.get(objId, { useMasterKey: true }); // const res = JSON.parse(JSON.stringify(updateACL)); diff --git a/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js new file mode 100644 index 000000000..bdf7842cc --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/generateApiToken.js @@ -0,0 +1,44 @@ +import { generateApiKey } from 'generate-api-key'; +import axios from 'axios'; +export default async function generateApiToken(request) { + const serverUrl = process.env.SERVER_URL; + try { + const userRes = await axios.get(serverUrl + '/users/me', { + headers: { + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Session-Token': request.headers['sessiontoken'], + }, + }); + const userId = userRes.data && userRes.data.objectId; + if (userId) { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('Id', userId); + const token = await tokenQuery.first({ useMasterKey: true }); + if (token !== undefined) { + // return exsiting Token + console.log('Regenerate API Token'); + const AppToken = Parse.Object.extend('appToken'); + const updateToken = new AppToken(); + updateToken.id = token.id; + const newToken = generateApiKey({ method: 'base62', prefix: 'opensign' }); + updateToken.set('token', newToken); + const updatedRes = await updateToken.save(null, { useMasterKey: true }); + return updatedRes; + } else { + // Create New Token + console.log('New API Token Generation'); + const appToken = Parse.Object.extend('appToken'); + const appTokenQuery = new appToken(); + const token = generateApiKey({ method: 'base62', prefix: 'opensign' }); + appTokenQuery.set('token', token); + appTokenQuery.set('Id', userId); + const newRes = await appTokenQuery.save(null, { useMasterKey: true }); + return newRes; + } + } else { + return 'User not found!'; + } + } catch (err) { + console.log('err ', err); + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/getapitoken.js b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js new file mode 100644 index 000000000..5e12d6a39 --- /dev/null +++ b/apps/OpenSignServer/cloud/parsefunction/getapitoken.js @@ -0,0 +1,24 @@ +import axios from 'axios'; +export default async function getapitoken(request) { + const serverUrl = process.env.SERVER_URL; + try { + const userRes = await axios.get(serverUrl + '/users/me', { + headers: { + 'X-Parse-Application-Id': process.env.APP_ID, + 'X-Parse-Session-Token': request.headers['sessiontoken'], + }, + }); + const userId = userRes.data && userRes.data.objectId; + if (userId) { + const tokenQuery = new Parse.Query('appToken'); + tokenQuery.equalTo('Id', userId); + const res = await tokenQuery.first({ useMasterKey: true }); + if (res) { + return { status: 'success', result: res.get('token') }; + } + } + } catch (err) { + console.log('Err', err); + return { status: 'error', result: err }; + } +} diff --git a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js index 2031cd076..24bc07dae 100644 --- a/apps/OpenSignServer/cloud/parsefunction/reportsJson.js +++ b/apps/OpenSignServer/cloud/parsefunction/reportsJson.js @@ -11,7 +11,11 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], + $or: [ + { Signers: { $eq: [] } }, + { Signers: null }, + { Signers: { $exists: true }, Placeholders: null }, + ], CreatedBy: { __type: 'Pointer', className: '_User', @@ -99,6 +103,7 @@ export default function reportJson(id, userId) { 'Note', 'Folder.Name', 'URL', + 'SignedUrl', 'ExtUserPtr.Name', 'Signers.Name', 'TimeToCompleteDays', @@ -211,7 +216,11 @@ export default function reportJson(id, userId) { IsCompleted: { $ne: true }, IsDeclined: { $ne: true }, IsArchive: { $ne: true }, - $or: [{Signers:{$eq:[]}}, { Signers: null }, { Signers: { $exists: true }, Placeholders: null }], + $or: [ + { Signers: { $eq: [] } }, + { Signers: null }, + { Signers: { $exists: true }, Placeholders: null }, + ], CreatedBy: { __type: 'Pointer', className: '_User', diff --git a/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs new file mode 100644 index 000000000..0059b0a6a --- /dev/null +++ b/apps/OpenSignServer/databases/migrations/20240116170302-add_generatetoken_menu_cjs.cjs @@ -0,0 +1,652 @@ +/** + * + * @param {Parse} Parse + */ +exports.up = async Parse => { + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const updateUserMenu = await userMenu.get('H9vRfEYKhT'); + updateUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'fa-solid fa-key', + title: 'Generate token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + + const AdminMenu = new Parse.Query(className); + const updateAdminMenu = await AdminMenu.get('VPh91h0ZHk'); + updateAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + { + icon: 'fa-solid fa-key', + title: 'Generate token', + target: '_self', + pageType: 'generatetoken', + description: '', + objectId: '', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [updateUserMenu, updateAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; + +/** + * + * @param {Parse} Parse + */ +exports.down = async Parse => { + // TODO: set className here + const className = 'w_menu'; + const userMenu = new Parse.Query(className); + const revertUserMenu = await userMenu.get('H9vRfEYKhT'); + revertUserMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + ], + }, + ]); + + const adminMenu = new Parse.Query(className); + const revertAdminMenu = await adminMenu.get('VPh91h0ZHk'); + revertAdminMenu.set('menuItems', [ + { + icon: 'fas fa-tachometer-alt', + title: 'Dashboard', + target: '', + pageType: 'dashboard', + description: '', + objectId: '35KBoSgoAK', + }, + { + icon: 'far fa-newspaper', + title: 'New Document', + target: '_self', + pageType: null, + description: null, + objectId: null, + children: [ + { + icon: 'fas fa-pen-nib', + title: 'Sign yourself', + target: '_self', + pageType: 'form', + description: '', + objectId: 'sHAnZphf69', + }, + { + icon: 'fa-solid fa-paper-plane', + title: 'Request signatures', + target: '_self', + pageType: 'form', + description: '', + objectId: '8mZzFxbG1z', + }, + { + icon: 'fas fa-file-signature', + title: 'New template', + target: '_self', + pageType: 'form', + description: '', + objectId: 'template', + }, + ], + }, + { + icon: 'fa-solid fa-file-contract', + title: 'Templates', + target: '_self', + pageType: 'report', + description: '', + objectId: '6TeaPr321t', + }, + { + icon: 'fas fa-folder', + title: 'OpenSign™ Drive', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive', + }, + { + icon: 'fas fa-address-card', + title: 'Reports', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-signature', + title: 'Need your sign', + target: '_self', + pageType: 'report', + description: '', + objectId: '4Hhwbp482K', + }, + { + icon: 'fas fa-tasks', + title: 'In Progress', + target: '_self', + pageType: 'report', + description: '', + objectId: '1MwEuxLEkF', + }, + { + icon: 'fas fa-check-circle', + title: 'Completed', + target: '_self', + pageType: 'report', + description: '', + objectId: 'kQUoW4hUXz', + }, + { + icon: 'fas fa-edit', + title: 'Drafts', + target: '_self', + pageType: 'report', + description: '', + objectId: 'ByHuevtCFY', + }, + { + icon: 'fas fa-times-circle', + title: 'Declined', + target: '_self', + pageType: 'report', + description: '', + objectId: 'UPr2Fm5WY3', + }, + { + icon: 'fas fa-hourglass-end', + title: 'Expired', + target: '_self', + pageType: 'report', + description: '', + objectId: 'zNqBHXHsYH', + }, + { + icon: 'fa-solid fa-address-book', + title: 'Contactbook', + target: '_self', + pageType: 'report', + description: '', + objectId: '5KhaPr482K', + }, + ], + }, + { + icon: 'fas fa-cog', + title: 'Settings', + target: '_self', + pageType: null, + description: '', + objectId: null, + children: [ + { + icon: 'fas fa-pen-fancy', + title: 'My Signature', + target: '_self', + pageType: 'mf', + description: '', + objectId: + 'remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/managesign', + }, + { + icon: 'far fa-user', + title: 'Add User', + target: '_self', + pageType: 'form', + description: '', + objectId: 'lM0xRnM3iE', + }, + ], + }, + ]); + // TODO: Set the schema here + // Example: + // schema.addString('name').addNumber('cash'); + const batch = [revertUserMenu, revertAdminMenu]; + return Parse.Object.saveAll(batch, { useMasterKey: true }); +}; diff --git a/apps/OpenSignServer/index.js b/apps/OpenSignServer/index.js index ae3e75bce..b69429e59 100644 --- a/apps/OpenSignServer/index.js +++ b/apps/OpenSignServer/index.js @@ -19,6 +19,7 @@ import AWS from 'aws-sdk'; import { app as customRoute } from './cloud/customRoute/customApp.js'; import { exec } from 'child_process'; import { createTransport } from 'nodemailer'; +import { app as v1 } from './cloud/customRoute/v1/apiV1.js'; const spacesEndpoint = new AWS.Endpoint(process.env.DO_ENDPOINT); // console.log("configuration ", configuration); @@ -164,6 +165,9 @@ if (!process.env.TESTING) { // Mount your custom express app app.use('/', customRoute); +// Mount v1 +app.use('/v1', v1); + // Parse Server plays nicely with the rest of your web routes app.get('/', function (req, res) { // res.statusCode = 200; diff --git a/apps/OpenSignServer/package-lock.json b/apps/OpenSignServer/package-lock.json index e57104d95..fac7ba41c 100644 --- a/apps/OpenSignServer/package-lock.json +++ b/apps/OpenSignServer/package-lock.json @@ -17,6 +17,7 @@ "express": "4.18.2", "express-sse": "^0.5.3", "form-data": "^4.0.0", + "generate-api-key": "^1.0.2", "jsonschema": "^1.4.1", "mailgun.js": "^9.3.0", "mongoose": "^7.2.1", @@ -2037,6 +2038,11 @@ "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==" }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2401,6 +2407,11 @@ "node": ">=4" } }, + "node_modules/chance": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz", + "integrity": "sha512-kqTg3WWywappJPqtgrdvbA380VoXO2eu9VCV895JgbyHsaErXdyHK9LOZ911OvAk6L0obK7kDk9CGs8+oBawVA==" + }, "node_modules/charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -4373,6 +4384,20 @@ "lodash.padstart": "^4.1.0" } }, + "node_modules/generate-api-key": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/generate-api-key/-/generate-api-key-1.0.2.tgz", + "integrity": "sha512-4rPSpXyboIXfugOTN3/0Qaoqpzbk0sepzPS0XyxPh3UMuu+Trk+0JMyJ6mB/7FEgp7oZ1juqsRW+8wSYeKDbfA==", + "dependencies": { + "base-x": "^4.0.0", + "chance": "^1.1.8", + "rfc4648": "^1.5.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -8804,6 +8829,11 @@ "node": ">=0.10.0" } }, + "node_modules/rfc4648": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.3.tgz", + "integrity": "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -9897,7 +9927,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, "bin": { "uuid": "dist/bin/uuid" } diff --git a/apps/OpenSignServer/package.json b/apps/OpenSignServer/package.json index 4725d28d5..350f10979 100644 --- a/apps/OpenSignServer/package.json +++ b/apps/OpenSignServer/package.json @@ -26,6 +26,7 @@ "express": "4.18.2", "express-sse": "^0.5.3", "form-data": "^4.0.0", + "generate-api-key": "^1.0.2", "jsonschema": "^1.4.1", "mailgun.js": "^9.3.0", "mongoose": "^7.2.1", diff --git a/apps/OpenSignServer/public/openapi.json b/apps/OpenSignServer/public/openapi.json new file mode 100644 index 000000000..de11c91e4 --- /dev/null +++ b/apps/OpenSignServer/public/openapi.json @@ -0,0 +1,934 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "OpenSign API v1", + "description": "This is API documentation for OpenSign API v1 based on the OpenAPI 3.1 specification. \n\nSome useful links:\n- [Official Website](https://www.opensignlabs.com)\n- [Github repo](https://github.com/opensignlabs/opensign)", + "termsOfService": "http://www.opensignlabs.com/terms/", + "contact": { + "email": "contact@opensignlabs.com" + }, + "license": { + "name": "AGPL 3.0", + "url": "http://github.com/opensignlabs/opensign/LICENSE" + }, + "version": "1.0.0" + }, + "externalDocs": { + "description": "Find out more about OpenSign", + "url": "http://docs.opensignlabs.com" + }, + "servers": [ + { + "url": "https://app.opensignlabs.com/api/v1" + } + ], + "tags": [ + { + "name": "OpenSign", + "description": "OpenSource DocuSign alternative", + "externalDocs": { + "description": "Find out more", + "url": "http://www.opensignlabs.com" + } + }, + { + "name": "Github repo", + "description": "Access the source code", + "externalDocs": { + "description": "Visit github", + "url": "http://github.com/opensignlabs/opensign" + } + }, + { + "name": "templates", + "description": "Operations about templates" + }, + { + "name": "users", + "description": "Operations about users" + }, + { + "name": "documents", + "description": "Operations about documents" + } + ], + "paths": { + "/getuser": { + "put": { + "tags": [ + "users" + ], + "summary": "Update an existing pet", + "description": "Update an existing pet by Id", + "operationId": "updatePet", + "requestBody": { + "description": "Update an existent pet in the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "post": { + "tags": [ + "users" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPet", + "requestBody": { + "description": "Create a new pet in the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/documentlist": { + "get": { + "tags": [ + "documents" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "Status values that need to be considered for filter", + "required": false, + "explode": true, + "schema": { + "type": "string", + "default": "available", + "enum": [ + "available", + "pending", + "sold" + ] + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid status value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/document/": { + "get": { + "tags": [ + "documents" + ], + "summary": "Finds Pets by tags", + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "Tags to filter by", + "required": false, + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid tag value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/contact/{contact_id}": { + "get": { + "tags": [ + "contacts" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet", + "operationId": "getPetById", + "parameters": [ + { + "name": "contact_id", + "in": "path", + "description": "ID of pet to return", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "post": { + "tags": [ + "contacts" + ], + "summary": "Updates a pet in the store with form data", + "description": "", + "operationId": "updatePetWithForm", + "parameters": [ + { + "name": "contact_id", + "in": "path", + "description": "ID of pet that needs to be updated", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "name", + "in": "query", + "description": "Name of pet that needs to be updated", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Status of pet that needs to be updated", + "schema": { + "type": "string" + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "delete": { + "tags": [ + "contacts" + ], + "summary": "Deletes a pet", + "description": "delete a pet", + "operationId": "deletePet", + "parameters": [ + { + "name": "api_key", + "in": "header", + "description": "", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "contact_id", + "in": "path", + "description": "Pet id to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "400": { + "description": "Invalid pet value" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/contactlist": { + "post": { + "tags": [ + "contacts" + ], + "summary": "uploads an image", + "description": "", + "operationId": "uploadFile", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/createdocument": { + "get": { + "tags": [ + "documents" + ], + "summary": "Returns pet inventories by status", + "description": "Returns a map of status codes to quantities", + "operationId": "getInventory", + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/createtemplate": { + "post": { + "tags": [ + "templates" + ], + "summary": "Place an order for a pet", + "description": "Place a new order in the store", + "operationId": "placeOrder", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "405": { + "description": "Invalid input" + } + } + } + }, + "/template/{template_id}": { + "get": { + "tags": [ + "templates" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderById", + "parameters": [ + { + "name": "template_id", + "in": "path", + "description": "ID of order that needs to be fetched", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + }, + "delete": { + "tags": [ + "templates" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "operationId": "deleteOrder", + "parameters": [ + { + "name": "template_id", + "in": "path", + "description": "ID of the order that needs to be deleted", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + }, + "/templatelist": { + "post": { + "tags": [ + "templates" + ], + "summary": "Create user", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "requestBody": { + "description": "Created user object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + }, + "responses": { + "default": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "petId": { + "type": "integer", + "format": "int64", + "example": 198772 + }, + "quantity": { + "type": "integer", + "format": "int32", + "example": 7 + }, + "shipDate": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Order Status", + "example": "approved", + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": "boolean" + } + }, + "xml": { + "name": "order" + } + }, + "Customer": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 100000 + }, + "username": { + "type": "string", + "example": "fehguy" + }, + "address": { + "type": "array", + "xml": { + "name": "addresses", + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Address" + } + } + }, + "xml": { + "name": "customer" + } + }, + "Address": { + "type": "object", + "properties": { + "street": { + "type": "string", + "example": "437 Lytton" + }, + "city": { + "type": "string", + "example": "Palo Alto" + }, + "state": { + "type": "string", + "example": "CA" + }, + "zip": { + "type": "string", + "example": "94301" + } + }, + "xml": { + "name": "address" + } + }, + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 1 + }, + "name": { + "type": "string", + "example": "Dogs" + } + }, + "xml": { + "name": "category" + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "username": { + "type": "string", + "example": "theUser" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "James" + }, + "email": { + "type": "string", + "example": "john@email.com" + }, + "password": { + "type": "string", + "example": "12345" + }, + "phone": { + "type": "string", + "example": "12345" + }, + "userStatus": { + "type": "integer", + "description": "User Status", + "format": "int32", + "example": 1 + } + }, + "xml": { + "name": "user" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "tag" + } + }, + "Pet": { + "required": [ + "name", + "photoUrls" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "name": { + "type": "string", + "example": "doggie" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "photoUrls": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "photoUrl" + } + } + }, + "tags": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "xml": { + "name": "pet" + } + }, + "ApiResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "xml": { + "name": "##default" + } + } + }, + "requestBodies": { + "Pet": { + "description": "Pet object that needs to be added to the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "UserArray": { + "description": "List of user object", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + }, + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "X-Parse-ApiKey", + "in": "header" + } + } + } +} \ No newline at end of file