forked from OfficeDev/Microsoft-Teams-Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Meeting Signing: Prevent multiple graph consent pop-ups (OfficeDev#465)
* Meeting Signing: Prevent Multiple Graph Consents
- Loading branch information
1 parent
121b373
commit 4cf61d9
Showing
9 changed files
with
267 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
...harp/Source/MeetingSigning.Web/ClientApp/src/components/ConsentRequest/ConsentRequest.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import * as microsoftTeams from '@microsoft/teams-js'; | ||
import { Button, Flex, Header, Text } from '@fluentui/react-northstar'; | ||
|
||
type ConsentRequestProps = { | ||
callback: (error?: string, result?: string) => void; | ||
}; | ||
|
||
function ConsentRequest({ callback }: ConsentRequestProps) { | ||
const callConsentAuth = async () => { | ||
try { | ||
const result = await microsoftTeams.authentication.authenticate({ | ||
url: `${window.location.origin}/auth-start`, | ||
width: 600, | ||
height: 535, | ||
}); | ||
|
||
console.log('Consent provided.'); | ||
callback(undefined, result); | ||
} catch (error: any) { | ||
console.error(`Failed to get consent: "${error}"`); | ||
callback(error); | ||
} | ||
}; | ||
|
||
return ( | ||
<Flex column> | ||
<Header as="h2" content="To complete that action you must consent" /> | ||
<Text | ||
as="p" | ||
content="We need your permission to access some data from your account." | ||
/> | ||
<Button primary content="Consent" onClick={callConsentAuth} /> | ||
</Flex> | ||
); | ||
} | ||
|
||
export { ConsentRequest }; |
3 changes: 3 additions & 0 deletions
3
...signing/csharp/Source/MeetingSigning.Web/ClientApp/src/components/ConsentRequest/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { ConsentRequest } from './ConsentRequest'; | ||
|
||
export { ConsentRequest }; |
173 changes: 173 additions & 0 deletions
173
...MeetingSigning.Web/ClientApp/src/components/CreateDocumentButton/CreateDocumentButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import { Alert, Button, Flex } from '@fluentui/react-northstar'; | ||
import { useState } from 'react'; | ||
import { useMutation } from 'react-query'; | ||
import { TaskInfo } from '@microsoft/teams-js'; | ||
import * as microsoftTeams from '@microsoft/teams-js'; | ||
import * as ACData from 'adaptivecards-templating'; | ||
import { CreateDocumentCard } from 'adaptive-cards'; | ||
import { createDocument } from 'api/documentApi'; | ||
import { | ||
ApiErrorCode, | ||
Document, | ||
DocumentInput, | ||
DocumentType, | ||
User, | ||
} from 'models'; | ||
import { apiRetryQuery, isApiErrorCode } from 'utils/UtilsFunctions'; | ||
import { ConsentRequest } from 'components/ConsentRequest'; | ||
|
||
type Choice = { | ||
name: string; | ||
value: string; | ||
}; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const createTaskInfo = (card: any): TaskInfo => { | ||
return { | ||
card: JSON.stringify(card), | ||
}; | ||
}; | ||
|
||
const createDocumentTypeArray = () => { | ||
const documents: Choice[] = Object.entries(DocumentType).map( | ||
([value, name]) => { | ||
return { name, value } as Choice; | ||
}, | ||
); | ||
|
||
return documents; | ||
}; | ||
|
||
const createUserArray = ( | ||
commaArrayOfUsers?: string, | ||
isEmail?: boolean, | ||
): User[] => { | ||
if (!commaArrayOfUsers) { | ||
return []; | ||
} | ||
|
||
return commaArrayOfUsers.split(',').map((u: string) => { | ||
return { | ||
userId: isEmail ? undefined : u, | ||
name: '', | ||
} as User; | ||
}); | ||
}; | ||
|
||
/** | ||
* Content that is shown in the Meeting Tab | ||
* Includes the ability to open a Task Module to create a Document. | ||
* | ||
* @returns a component with a simple header and button to create a document | ||
*/ | ||
export function CreateDocumentButton() { | ||
const [userHasConsented, setUserHasConsented] = useState<boolean>(false); | ||
const [documentInput, setDocumentInput] = useState<DocumentInput | undefined>( | ||
undefined, | ||
); | ||
|
||
const createDocumentMutation = useMutation<Document, Error, DocumentInput>( | ||
(documentInput: DocumentInput) => createDocument(documentInput), | ||
{ | ||
retry: (failureCount: number, error: Error) => | ||
apiRetryQuery( | ||
failureCount, | ||
error, | ||
userHasConsented, | ||
setUserHasConsented, | ||
), | ||
}, | ||
); | ||
|
||
const createDocumentsTaskModule = () => { | ||
const template = new ACData.Template(CreateDocumentCard); | ||
const documentsCard = template.expand({ | ||
$root: { | ||
title: 'Select the documents that needs to be reviewed in the meeting', | ||
error: 'At least one document is required', | ||
choices: createDocumentTypeArray(), | ||
successButtonText: 'Next', | ||
id: 'documents', | ||
}, | ||
}); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const createDocumentsSubmitHandler = (error: string, result: any) => { | ||
if (error !== null) { | ||
console.log(`Document handler - error: '${error}'`); | ||
} else if (result !== undefined) { | ||
const documents: string[] = result.documentsValue.split(','); | ||
|
||
const viewers: User[] = createUserArray(result.viewersValue); | ||
const signers: User[] = createUserArray(result.signersValue); | ||
|
||
documents.forEach(async (d: string) => { | ||
const documentInput: DocumentInput = { | ||
documentType: DocumentType[d as keyof typeof DocumentType], | ||
viewers: viewers, | ||
signers: signers, | ||
}; | ||
|
||
setDocumentInput(documentInput); | ||
createDocumentMutation.mutate(documentInput); | ||
}); | ||
} | ||
}; | ||
|
||
// tasks.startTasks is deprecated, but the 2.0 of SDK's dialog.open does not support opening adaptive cards yet. | ||
microsoftTeams.tasks.startTask( | ||
createTaskInfo(documentsCard), | ||
createDocumentsSubmitHandler, | ||
); | ||
}; | ||
|
||
const consentCallback = (error?: string, result?: string) => { | ||
if (error) { | ||
console.log(`Error: ${error}`); | ||
} | ||
if (result) { | ||
setUserHasConsented(true); | ||
if (documentInput !== undefined) { | ||
createDocumentMutation.mutate(documentInput); | ||
} | ||
} | ||
}; | ||
|
||
const displayConsentRequest = | ||
isApiErrorCode( | ||
ApiErrorCode.AuthConsentRequired, | ||
createDocumentMutation.error, | ||
) && !userHasConsented; | ||
|
||
return ( | ||
<Flex column> | ||
{createDocumentMutation.isError && displayConsentRequest && ( | ||
<ConsentRequest callback={consentCallback} /> | ||
)} | ||
|
||
{!displayConsentRequest && ( | ||
<Button | ||
content="Create Documents" | ||
onClick={() => createDocumentsTaskModule()} | ||
primary | ||
loading={createDocumentMutation.isLoading} | ||
/> | ||
)} | ||
{createDocumentMutation.isError && !displayConsentRequest && ( | ||
<Alert | ||
header="Error" | ||
content={ | ||
createDocumentMutation.error?.message ?? | ||
'Something went wrong while creating your document' | ||
} | ||
danger | ||
visible | ||
/> | ||
)} | ||
|
||
{createDocumentMutation.data && ( | ||
<Alert header="Success" content="Document Created" success visible /> | ||
)} | ||
</Flex> | ||
); | ||
} |
2 changes: 2 additions & 0 deletions
2
...g/csharp/Source/MeetingSigning.Web/ClientApp/src/components/CreateDocumentButton/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import { CreateDocumentButton } from './CreateDocumentButton'; | ||
export { CreateDocumentButton }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.