[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confluence integration #281

Draft
wants to merge 132 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
42e9e32
added atlassian connect config
LucasMGo May 14, 2024
343956b
Merge pull request #280 from LucasMGo/test
LucasMGo May 15, 2024
75be700
use staging url as baseUrl
LucasMGo May 15, 2024
4646128
change cookie settings to allow cross-domain access
LucasMGo May 15, 2024
d7e39ca
skip testing in github workflows
LucasMGo May 15, 2024
b5ffc40
fix cookie settings
LucasMGo May 19, 2024
d74a03a
added macro
LucasMGo May 21, 2024
c14479e
use next/navigation and use client
LucasMGo May 21, 2024
500e84a
use correct macro term
LucasMGo May 21, 2024
bf54727
added logs
LucasMGo May 21, 2024
fbf2ee8
added bodytype in atlassian connect
LucasMGo May 21, 2024
c5a1feb
call confluence API
LucasMGo May 21, 2024
b310ae4
use macro component n saveMacro
LucasMGo May 21, 2024
efb74e4
use macro as module
LucasMGo May 21, 2024
5894399
use dynamicContentMacros
LucasMGo May 21, 2024
7c94a64
change bodytype to none
LucasMGo May 21, 2024
5e3660f
added outputtype
LucasMGo May 21, 2024
f6a05ac
added missing cookie attributes
LucasMGo May 21, 2024
5f08f91
use viewer for macro
LucasMGo May 21, 2024
83ff6ce
try using delivered processId of macro editor in macro
LucasMGo May 21, 2024
640637d
added logs
LucasMGo May 21, 2024
23ad86d
added head with atlassian cdn in macro
LucasMGo May 21, 2024
8d4d395
move Head to macro component instead of page.tsx
LucasMGo May 21, 2024
002f3c1
add processId in route for confluence macro
LucasMGo May 22, 2024
c838995
bugfix
LucasMGo May 22, 2024
e3c2e25
use confluence functions
LucasMGo May 22, 2024
38c5da1
useQuery to fetch updated BPMN in macro
LucasMGo May 22, 2024
4270a9e
added second macro for creation of processes in confluence
LucasMGo May 23, 2024
cdb5c37
added processlist in atlassian design for confluence
LucasMGo May 23, 2024
e8d1654
make use of confluence processlist page
LucasMGo May 23, 2024
43a4f29
added processlist in macro editor
LucasMGo May 24, 2024
65d45dd
use full width for searchbar and filter
LucasMGo May 24, 2024
dea7049
use button with primary appearance
LucasMGo May 24, 2024
69d1b3c
added modal for process creation in confluence
LucasMGo May 24, 2024
1e98a5b
create process form component with multiple sub-components
LucasMGo May 24, 2024
9ba8eab
cleanup macro editor
LucasMGo May 24, 2024
2b4ab93
use modeler in macro
LucasMGo May 24, 2024
d6c8bc3
change description and name for macro
LucasMGo May 24, 2024
71f95d8
resize macro editor for modeler
LucasMGo May 24, 2024
3815c3e
use window size for resizing macro editor
LucasMGo May 24, 2024
9196fe7
test fixed pixel values for resize of dialog
LucasMGo May 24, 2024
3bdea05
Merge branch 'main' into confluence-integration
LucasMGo May 27, 2024
6f11818
retrieve jwt token from confluence
LucasMGo May 29, 2024
80caaf9
import getSpaces function in process list
LucasMGo May 29, 2024
2fc3bea
added JWT authentication
LucasMGo May 29, 2024
c67ac99
verify jwt token in proceed
LucasMGo May 29, 2024
cdd0243
change type of sharedSecret and baseUrl
LucasMGo May 29, 2024
41810bd
initialize sharedSecret object
LucasMGo May 29, 2024
732a398
log sharedSecret info to store them
LucasMGo May 29, 2024
abfed84
added further logs
LucasMGo May 29, 2024
a9d171f
remove getSpaces
LucasMGo May 29, 2024
54886ea
remove linting job from github workflow to save time
LucasMGo May 29, 2024
942e850
return clientKey, sharedSecret, baseUrl to make them visible to me
LucasMGo May 29, 2024
b9b36a1
revert
LucasMGo May 29, 2024
23030bb
move sharedSecrets management to lib
LucasMGo May 29, 2024
0bebb15
move sharedSecret handling to route handler
LucasMGo May 30, 2024
3de54f7
fix route export
LucasMGo May 30, 2024
f4b5320
use routes for sharedSecret
LucasMGo May 30, 2024
59b5397
store secret in variable
LucasMGo May 30, 2024
fc1239b
write to json file directly
LucasMGo May 30, 2024
95200ae
test with ngrok
LucasMGo May 30, 2024
f3ea926
Revert "test with ngrok"
LucasMGo May 30, 2024
1737ea5
store sharedSecret in filesystem
LucasMGo May 30, 2024
21900bb
check if path exists before opening sharedSecret file
LucasMGo May 30, 2024
06adfe4
change PUT to POST
LucasMGo May 30, 2024
b4818b1
return error if file wasnt found
LucasMGo May 30, 2024
88f72fc
call getSpaces
LucasMGo May 31, 2024
ea39f57
fix sharedSecret extraction
LucasMGo May 31, 2024
09af42e
cleanup
LucasMGo May 31, 2024
dc4158f
Merge branch 'main' into confluence-integration
LucasMGo Jun 12, 2024
61fc915
Merge branch 'main' into confluence-integration
LucasMGo Jun 21, 2024
59c26d3
added user creation based on JWT Token; configuration for app; and more
LucasMGo Jun 22, 2024
6547ad4
use atlaskit modals for macro editor
LucasMGo Jun 22, 2024
31a5eda
fix error with new confluence account
LucasMGo Jun 22, 2024
0bc6294
use correct baseUrl
LucasMGo Jun 22, 2024
e05ce7e
fix prettier issue
LucasMGo Jun 22, 2024
0df1524
use full height for macro view
LucasMGo Jun 22, 2024
dc5c777
hide blanket in modal
LucasMGo Jun 22, 2024
b40f4f0
added pdf render mode
LucasMGo Jun 23, 2024
095df6b
improve macro view; added pdf export view for macro
LucasMGo Jun 23, 2024
734569b
fix bug with scheme in generated url
LucasMGo Jun 23, 2024
90ca1d6
add render mode for embed macro
LucasMGo Jun 23, 2024
05ceb1f
Revert "add render mode for embed macro"
LucasMGo Jun 23, 2024
eaab4cf
check for existing process in macro
LucasMGo Jun 23, 2024
3241fae
return cookies and headers for checking
LucasMGo Jun 23, 2024
e826131
return sharedViewer with process when calling pdf-export
LucasMGo Jun 24, 2024
3af48e4
use bpmnsharedviwer directly instead of redirecting url
LucasMGo Jun 24, 2024
a2446ce
revert cookie and header logging in confluence process list
LucasMGo Jun 24, 2024
f2c25eb
refresh macro if macrodata updated
LucasMGo Jun 24, 2024
7719a42
Merge branch 'main' into confluence-integration
LucasMGo Jun 24, 2024
3f805bc
improve style of macro with header and footer
LucasMGo Jul 3, 2024
cb30fbf
set min height of confluence list
LucasMGo Jul 3, 2024
052c21f
use customContent module for confluence process-list
LucasMGo Jul 4, 2024
4f34d8b
store process in attachment as png and bpmn
LucasMGo Jul 4, 2024
f74f467
use attachment in pdf export
LucasMGo Jul 4, 2024
7435cd9
Merge main into branch
LucasMGo Jul 4, 2024
bb83985
fix error with confluence in user
LucasMGo Jul 4, 2024
e4eabb9
use pdf export in embed macro; remove proceed from description of macros
LucasMGo Jul 4, 2024
81afe16
store process in attachment for embed macro
LucasMGo Jul 4, 2024
959f6f6
close editor after creating process
LucasMGo Jul 4, 2024
e0c306b
retrieve process information from confluence-stored bpmn
LucasMGo Jul 4, 2024
a177f8d
retrieve bpmn from confluence
LucasMGo Jul 4, 2024
460f86f
use px instead of rem for export
LucasMGo Jul 4, 2024
91bb3ff
improve export for confluence
LucasMGo Jul 4, 2024
37077df
improve pdf export
LucasMGo Jul 4, 2024
1ec570a
login user using jwt token in confluence page
LucasMGo Jul 5, 2024
edd27b0
login user using jwt token in all confluence pages
LucasMGo Jul 5, 2024
f0f526d
improve pdf export style
LucasMGo Jul 5, 2024
3884bd1
store selected proceed space for confluence site
LucasMGo Jul 5, 2024
febf725
set telephone number as optional for space to allow creation
LucasMGo Jul 5, 2024
c025221
show initial selected environment in config menu
LucasMGo Jul 5, 2024
5b71925
store created processes in selected space for confluence
LucasMGo Jul 6, 2024
a0e2f2a
add role to confluence user in space
LucasMGo Jul 6, 2024
0bd8fb9
add role to existing confluence user in space
LucasMGo Jul 6, 2024
f201102
include bpmn in embedded editor
LucasMGo Jul 6, 2024
379ef4d
show page container for proceed processes in confluence
LucasMGo Jul 7, 2024
ac780be
added export to confluence process list
LucasMGo Jul 7, 2024
402b4cb
Merge main into branch
LucasMGo Jul 7, 2024
a7ce4fa
remove origin from process list in confluence
LucasMGo Jul 7, 2024
a4588c5
remove console logs
LucasMGo Jul 7, 2024
e83cb6f
make use of query parameters from confluence
LucasMGo Jul 7, 2024
06dccf4
added import button to embed macro editor
LucasMGo Jul 7, 2024
3ee5fac
get confluence Page Id from confluence
LucasMGo Jul 7, 2024
da6f543
dont show container in embed process list
LucasMGo Jul 7, 2024
a8fc066
show page title in container column
LucasMGo Jul 7, 2024
a1dfe98
bugfix: remove duplicate cells
LucasMGo Jul 7, 2024
b709857
use environmentId in proceed href
LucasMGo Jul 7, 2024
bff90c7
added icons
LucasMGo Jul 7, 2024
8d03ad1
use correct url for proceed view
LucasMGo Jul 7, 2024
6ea422e
Merge branch 'main' into confluence-integration
LucasMGo Jul 7, 2024
3a50bcf
add contentId to embed macro pdf export
LucasMGo Jul 7, 2024
0fce7f9
do not cache result from confluence rest API
LucasMGo Jul 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
store selected proceed space for confluence site
  • Loading branch information
LucasMGo committed Jul 5, 2024
commit 3884bd1b56f2d8abf2939d686469a69c48f3c6c3
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { sendEmail } from '@/lib/email/mailer';
import { randomUUID } from 'crypto';
import renderSigninLinkEmail from './signin-link-email';
import { verifyJwt } from '@/app/confluence/helpers';
import { getConfluenceClientInfos } from '@/lib/data/legacy/fileHandling';
import { addMember, isMember } from '@/lib/data/legacy/iam/memberships';

const nextAuthOptions: AuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
Expand All @@ -37,16 +39,24 @@ const nextAuthOptions: AuthOptions = {
if (credentials) {
try {
const decodedToken = await verifyJwt(credentials.token);
const confluenceClientInfos = await getConfluenceClientInfos(decodedToken.iss);
console.log('deocedToken', decodedToken);

const existingUser = getUserById(decodedToken.sub as string);

if (!existingUser) {
return addUser({
const user = addUser({
id: decodedToken.sub as string,
username: `Confluence_User_${decodedToken.sub}`,
confluence: true,
guest: false,
});

if (confluenceClientInfos.proceedSpace) {
addMember(confluenceClientInfos.proceedSpace, user.id);
}
} else if (!isMember(confluenceClientInfos.proceedSpace, existingUser.id)) {
addMember(confluenceClientInfos.proceedSpace, existingUser.id);
}
return existingUser;
} catch (err) {
Expand Down
10 changes: 3 additions & 7 deletions src/management-system-v2/app/api/confluence/installed/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { NextRequest, NextResponse } from 'next/server';
import { saveSharedSecret } from '@/lib/data/legacy/fileHandling';
import { addConfluenceClient } from '@/lib/data/legacy/fileHandling';

export async function POST(request: NextRequest) {
const bodyData = await request.json();
const { clientKey, sharedSecret, baseUrl } = bodyData;

await saveSharedSecret(
clientKey || 'DIDNOTWORK-KEY',
sharedSecret || 'DIDNOTWORK-SECRET',
baseUrl || 'DIDNOTWORK-BASEURL',
);
await addConfluenceClient(clientKey, sharedSecret, baseUrl);

return NextResponse.json({ clientKey, sharedSecret, baseUrl });
return new NextResponse(null, { status: 201, statusText: 'Created' });
}
16 changes: 0 additions & 16 deletions src/management-system-v2/app/api/confluence/sharedSecret/route.ts

This file was deleted.

10 changes: 9 additions & 1 deletion src/management-system-v2/app/confluence/config/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Tabs, { Tab, TabList, TabPanel } from '@atlaskit/tabs';
import { Label } from '@atlaskit/form';
import Select from '@atlaskit/select';
import { createFolder } from '@/lib/data/folders';
import { updateConfluenceClientSelectedSpace } from '@/lib/data/confluence';

const SpaceSelectionTab = ({
userEnvironments,
Expand Down Expand Up @@ -44,7 +45,13 @@ const SpaceSelectionTab = ({
);
};

const Config = ({ userEnvironments }: { userEnvironments: Environment[] }) => {
const Config = ({
userEnvironments,
clientKey,
}: {
userEnvironments: Environment[];
clientKey: string;
}) => {
console.log('environments', userEnvironments);
const selectSpace = async (selectedSpace: { label: string; value: string } | null) => {
console.log('selectedSpace', selectedSpace);
Expand All @@ -58,6 +65,7 @@ const Config = ({ userEnvironments }: { userEnvironments: Environment[] }) => {
environmentId: selectedSpace.value,
});
console.log('res', res);
await updateConfluenceClientSelectedSpace(clientKey, selectedSpace.value);
}
const users = JSON.parse((await getConfluenceUsers()) as string).results;
const atlassianUsers = users.filter(
Expand Down
14 changes: 13 additions & 1 deletion src/management-system-v2/app/confluence/config/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ import { Environment } from '@/lib/data/environment-schema';
import { getEnvironmentById } from '@/lib/data/legacy/iam/environments';
import { getUserOrganizationEnvironments } from '@/lib/data/legacy/iam/memberships';
import Config from './config';
import jwt, { JwtPayload } from 'jsonwebtoken';

const ConfigPage = async ({ params, searchParams }: { params: any; searchParams: any }) => {
console.log('searchparams', searchParams.jwt);
const jwtToken = searchParams.jwt;
const decoded = jwt.decode(jwtToken, { complete: true });
const { iss: clientKey } = decoded!.payload as JwtPayload;
console.log('clientKey', clientKey);

if (!clientKey) {
throw new Error('Could not extract ClientKey from given JWT Token');
}

const { userId } = await getCurrentUser();
console.log('userId', userId);

if (userId) {
const userEnvironments: Environment[] = [getEnvironmentById(userId)];
Expand All @@ -27,7 +39,7 @@ const ConfigPage = async ({ params, searchParams }: { params: any; searchParams:
activeSpace={{ spaceId: userId || '', isOrganization: false }}
>
<div style={{ padding: '1rem', width: '100%' }}>
<Config userEnvironments={userEnvironments}></Config>
<Config userEnvironments={userEnvironments} clientKey={clientKey}></Config>
</div>
</Layout>
);
Expand Down
118 changes: 50 additions & 68 deletions src/management-system-v2/app/confluence/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use server';
import jwt, { JwtPayload } from 'jsonwebtoken';
import * as AtlassianJwt from 'atlassian-jwt';
import { getConfluenceClientInfos } from '@/lib/data/legacy/fileHandling';

export const createAttachment = async (pageId: string, attachmentFormData: FormData) => {
const processId = attachmentFormData.get('id');
Expand Down Expand Up @@ -125,82 +126,63 @@ export const getSpaces = async (jwtToken: any) => {

const decoded = jwt.decode(jwtToken, { complete: true });
const { iss: clientKey } = decoded!.payload as JwtPayload;
const req: AtlassianJwt.Request = AtlassianJwt.fromMethodAndUrl(
'GET',
'https://proceed-test.atlassian.net/wiki/api/v2/pages',
);
const tokenData = {
iss: clientKey,
iat: Math.floor(+new Date() / 1000), // The time the token is generated
exp: Math.floor((+new Date() + 1000 * 60 * 60 * 5) / 1000), // Token expiry time (recommend 3 minutes after issuing)
sub: '712020:3a3f17e3-744f-4cd0-accc-1311bd5daad6',
qsh: AtlassianJwt.createQueryStringHash({
method: 'GET',
pathname: 'https://proceed-test.atlassian.net/wiki/api/v2/pages',
}), // [Query String Hash](https://developer.atlassian.com/cloud/jira/platform/understanding-jwt/#a-name-qsh-a-creating-a-query-string-hash)
};

const { sharedSecrets } = await fetch(
'https://pr-281---ms-server-staging-c4f6qdpj7q-ew.a.run.app/api/confluence/sharedSecret',
{
if (clientKey) {
const req: AtlassianJwt.Request = AtlassianJwt.fromMethodAndUrl(
'GET',
'https://proceed-test.atlassian.net/wiki/api/v2/pages',
);
const tokenData = {
iss: clientKey,
iat: Math.floor(+new Date() / 1000), // The time the token is generated
exp: Math.floor((+new Date() + 1000 * 60 * 60 * 5) / 1000), // Token expiry time (recommend 3 minutes after issuing)
sub: '712020:3a3f17e3-744f-4cd0-accc-1311bd5daad6',
qsh: AtlassianJwt.createQueryStringHash({
method: 'GET',
pathname: 'https://proceed-test.atlassian.net/wiki/api/v2/pages',
}), // [Query String Hash](https://developer.atlassian.com/cloud/jira/platform/understanding-jwt/#a-name-qsh-a-creating-a-query-string-hash)
};

const confluenceClientData = await getConfluenceClientInfos(clientKey);
const sharedSecret = confluenceClientData.sharedSecret;

const newToken = AtlassianJwt.encodeSymmetric(tokenData, sharedSecret);
console.log('newToken encodes with atlassianjwt', newToken);

const decodedNewToken = AtlassianJwt.decodeSymmetric(
newToken,
sharedSecret,
AtlassianJwt.SymmetricAlgorithm.HS256,
);
console.log('decoded newtoken', decodedNewToken);

const res = await fetch('https://proceed-test.atlassian.net/wiki/api/v2/pages', {
method: 'GET',
},
).then((res) => {
return res.json();
});

const sharedSecret = Object.entries(sharedSecrets).map(([key, val]) => {
const values = val as { sharedSecret: string; baseUrl: string };
console.log('clientKey', key);
console.log('sharedSecret', values.sharedSecret);
console.log('baseUrl', values.baseUrl);
return values.sharedSecret;
})[0];

const newToken = AtlassianJwt.encodeSymmetric(tokenData, sharedSecret);
console.log('newToken encodes with atlassianjwt', newToken);

const decodedNewToken = AtlassianJwt.decodeSymmetric(
newToken,
sharedSecret,
AtlassianJwt.SymmetricAlgorithm.HS256,
);
console.log('decoded newtoken', decodedNewToken);

const res = await fetch('https://proceed-test.atlassian.net/wiki/api/v2/pages', {
method: 'GET',
headers: {
Authorization: `JWT ${newToken}`,
},
});
console.log('res', res);
console.log('res json', await res.json());
return res;
headers: {
Authorization: `JWT ${newToken}`,
},
});
console.log('res', res);
console.log('res json', await res.json());
return res;
}
};

export const verifyJwt = async (jwtToken: any) => {
const decoded = jwt.decode(jwtToken, { complete: true });
const { iss: clientKey } = decoded!.payload as JwtPayload;

const { sharedSecrets } = await fetch(
'https://pr-281---ms-server-staging-c4f6qdpj7q-ew.a.run.app/api/confluence/sharedSecret',
{
method: 'GET',
},
).then((res) => {
return res.json();
});
if (clientKey) {
const confluenceClientData = await getConfluenceClientInfos(clientKey);
const sharedSecret = confluenceClientData.sharedSecret;

const sharedSecret = Object.entries(sharedSecrets).map(([key, val]) => {
const values = val as { sharedSecret: string; baseUrl: string };
return values.sharedSecret;
})[0];
const verified = AtlassianJwt.decodeSymmetric(
jwtToken,
sharedSecret,
AtlassianJwt.SymmetricAlgorithm.HS256,
);

const verified = AtlassianJwt.decodeSymmetric(
jwtToken,
sharedSecret,
AtlassianJwt.SymmetricAlgorithm.HS256,
);

return verified;
return verified;
}
return false;
};
10 changes: 10 additions & 0 deletions src/management-system-v2/lib/data/confluence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use server';

import { updateConfluenceClientInfos } from './legacy/fileHandling';

export const updateConfluenceClientSelectedSpace = async (
clientKey: string,
selectedSpace: string,
) => {
await updateConfluenceClientInfos(clientKey, { proceedSpace: selectedSpace });
};
53 changes: 38 additions & 15 deletions src/management-system-v2/lib/data/legacy/fileHandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export function getAppDataPath() {
* Find the path to the folder where the info about all Processes is stored
* @returns {String}
*/
function getSharedSecretFolder() {
return path.join(getAppDataPath(), 'SharedSecret');
function getConfluenceClientFolder() {
return path.join(getAppDataPath(), 'Confluence');
}
/**
* Find the path to the folder where the info about all Processes is stored
Expand Down Expand Up @@ -115,34 +115,57 @@ function getUserTaskDir(id) {
}

/**
* Saves sharedSecret
* Adds new confluence client
*
* @param {String} clientKey
* @param {String} sharedSecret
* @param {String} baseUrl
*/
export async function saveSharedSecret(clientKey, sharedSecret, baseUrl) {
const sharedSecretDir = getSharedSecretFolder();
export async function addConfluenceClient(clientKey, sharedSecret, baseUrl) {
const confluenceClientDir = getConfluenceClientFolder();

fse.ensureDirSync(sharedSecretDir);
fse.ensureDirSync(confluenceClientDir);

const sharedSecretData = JSON.stringify({ [clientKey]: { sharedSecret, baseUrl } });
fse.writeFileSync(path.join(sharedSecretDir, `sharedSecret.json`), sharedSecretData);
const sharedSecretData = JSON.stringify({ clientKey, sharedSecret, baseUrl });
fse.writeFileSync(path.join(confluenceClientDir, `${clientKey}.json`), sharedSecretData);
}

/**
* Get sharedSecret
* Update confluence client infos
*
* @param {String} clientKey
* @param {object} clientInfos
*/
export async function getSharedSecret() {
const sharedSecretDir = getSharedSecretFolder();
const sharedSecretFilePath = path.join(sharedSecretDir, 'sharedSecret.json');
export async function updateConfluenceClientInfos(clientKey, newClientInfos) {
const initialConfluenceClientInfos = await getConfluenceClientInfos(clientKey);

if (fse.existsSync(sharedSecretFilePath)) {
const sharedSecretData = JSON.parse(fse.readFileSync(sharedSecretFilePath, 'utf-8'));
if (initialConfluenceClientInfos) {
const confluenceClientDir = getConfluenceClientFolder();

return sharedSecretData;
fse.ensureDirSync(confluenceClientDir);

const sharedSecretData = JSON.stringify({
...initialConfluenceClientInfos,
...newClientInfos,
clientKey,
});
fse.writeFileSync(path.join(confluenceClientDir, `${clientKey}.json`), sharedSecretData);
}
}

/**
* Get infos of confluence client
*
* @param {String} clientKey
*/
export async function getConfluenceClientInfos(clientKey) {
const confluenceClientDir = getConfluenceClientFolder();
const confluenceClientFilePath = path.join(confluenceClientDir, `${clientKey}.json`);

if (fse.existsSync(confluenceClientFilePath)) {
const confluenceClientData = JSON.parse(fse.readFileSync(confluenceClientFilePath, 'utf-8'));

return confluenceClientData;
}
return { error: 'Does not exist' };
}
Expand Down