# EasyProctor

O componente web EasyProctor permite que qualquer plataforma de execução de exames registre sessões de proctoring.

## Instalação

Via NPM:

```bash
npm install --save easyproctor
```

Via CDN

```html
<script src="https://cdn.jsdelivr.net/npm/easyproctor/unpkg/easyproctor.min.js"></script>
```

## Utilização

Para utilizar o componente será necessário utilizar os seguintes parâmetros:

- examId: identificador do exame
- clientId: identificador do parceiro
- token: token de autenticação biométrica (utilizar SDK biométrico do EasyProctor)

Ao inicializar a sessão de proctoring através do método start do componente você receberá o objeto do tipo StartProctoringDTO que possui o identificador da sessão.

Após finalizar a sessão de proctoring através do método finish você poderá consultar os dados de proctoring através da nossa API.

https://proctoring-api.easyproctor.tech/index.html

Em um bundler

```javascript
import { useProctoring } from "easyproctor";

const {
  login,
  start,
  finish,
  checkDevices,
  capturePhoto,
  checkPermissions,
  enumarateDevices,
  checkIfhasMultipleMonitors,
  onFocus,
  onLostFocus,
  onChangeDevices,
  onRealtimeAlerts,
  onBufferSizeError,
  onStopSharingScreen,
} = useProctoring({
  examId: "00001",
  clientId: "000001",
  token: "...",
});
```

Via CDN: A função "useProctoring" é injetada para ser utilizada globalmente

```html
<script src="https://cdn.jsdelivr.net/npm/easyproctor/unpkg/easyproctor.min.js"></script>
<script>
const {
  login,
  start,
  finish,
  checkDevices,
  capturePhoto,
  checkPermissions,
  enumarateDevices,
  checkIfhasMultipleMonitors,
  onFocus,
  onLostFocus,
  onChangeDevices,
  onRealtimeAlerts,
  onBufferSizeError,
  onStopSharingScreen,
} = useProctoring({
  examId: "00001",
  clientId: "000001",
  token: "...",
});
</script>
```

## Exemplo completo

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="dist/unpkg/easyproctor.min.js"></script>
    <script>
    const {
        login,
        start,
        finish,
        checkDevices,
        capturePhoto,
        checkPermissions,
        enumarateDevices,
        checkIfhasMultipleMonitors,
        onFocus,
        onLostFocus,
        onChangeDevices,
        onRealtimeAlerts,
        onBufferSizeError,
        onStopSharingScreen
    } = useProctoring({
        examId: "00001",
        clientId: "000001",
        token: "...",
      });

      async function startExam() {
        try {
          // Verificar se existem dispositívos disponíveis
          if (devices.cameras.length == 0 || devices.microphones.length == 0) {
            throw "Você precisa possuir ao menos uma câmera e um microfone";
          }

          // Verificar se foram setados
          const selectedCamera = cameras.value;
          const selectedMicrophone = microphones.value;

          if (!selectedCamera || !selectedMicrophone) {
            throw "Você precisa selecionar uma camera e um microfone";
          }

          startButton.innerHTML = "Carregando";

          onFocus(() => generateAlert(false));
          onLostFocus(() => generateAlert(true));
          // Adicionar o dispositivo selecionado é opcional
          const { cameraStream } = await start({
            cameraId: selectedCamera,
            microphoneId: selectedMicrophone,
          });
        } catch (error) {
          alert(error);
        }
      }

      async function finishExam() {
        try {
          await finish({ onProgress: (percentage) => console.log(percentage) });
          console.log("EXAME FINALIZADO");
        } catch (error) {
          alert(error);
        }
      }

      // Verificar permissões
      let devices = { cameras: [], microphones: [] };
      async function verifyPermissions() {
        // Checar permissões
        var hasPermissions = await checkPermissions();

        if (!hasPermissions) {
          window.alert("Para continuar você precisa conceder as permissões");
          return;
        }

        // Listar os dispositivos
        devices = await enumarateDevices();

        const generateOption = (text, value) => {
          const el = document.createElement("option");
          el.setAttribute("value", value);
          el.innerHTML = text;
          return el;
        };

        devices.cameras.forEach((camera) => {
          const option = generateOption(camera.label, camera.id);
          cameras.appendChild(option);
        });

        devices.microphones.forEach((microphone) => {
          const option = generateOption(microphone.label, microphone.id);
          microphones.appendChild(option);
        });
      }

      // Gerar alerta
      function generateAlert(lostFocus) {
        const p = document.createElement("p");
        if (lostFocus) {
          p.classList.add("text-red-500");
          p.innerHTML = `Perdeu o foco em: ${new Date().toLocaleTimeString()}`;
        } else {
          p.classList.add("text-green-500");
          p.innerHTML = `Retomou o foco em: ${new Date().toLocaleTimeString()}`;
        }
        alerts.appendChild(p);
      }
    </script>
  </head>

  <body>
    <div
      style="height: 100vh; display: flex; align-items: center; justify-content: center;"
    >
      <button onclick="startExam()">Iniciar</button>
      <button onclick="finishExam()">Finalizar</button>
      <button onclick="verifyPermissions()">Verificar permissões</button>
    </div>
  </body>
</html>
```

## API

```javascript
const {
  // Inicia a gravação da prova
  start,

  // Finaliza a gravação da prova retornando os arquivos gerados
  finish,

  // Adiciona uma função callback para ser executada quando o usuário recupera o foco da tela
  onFocus,

  // Adiciona uma função de callback para ser executada quando ...
  onBufferSizeError,

  // Adiciona um função de callback para ser executada quando o usuário altera os dispositivos
  onChangeDevices,

  // Adiciona uma função callback para ser executada quando o usuário perde o foco da tela
  onLostFocus,

  // Adiciona uma função de callback para ser executada quando ocorrem alertas durante o exame
  onRealtimeAlerts,

  // Adiciona uma função callback para ser executada quando o usuário cancela o compartilhamento de tela
  onStopSharingScreen

  // Realiza uma captura de foto do usuário e a utiliza para fazer o resgistro ou login biométrico.
  capturePhoto

  // Checa se os dispositivos (câmera, microfone, stream da tela) estão funcionando corretamente
  checkDevices,

  // Checa se existe mais de um monitor
  checkIfhasMultipleMonitors,

  // Checa as permissões de camera e microfone
  checkPermissions,

  // Enumera os dispositivos de camera e microfone
  enumarateDevices,
} = useProctoring({
  examId: "00001",
  clientId: "000001",
  token: "...",
});
```

## Release Note V 2.5.4
- Fix: Correção sobre as imagens do realtime

## Release Note V 2.5.4
- Novos alertas de tela (Clipboard, SplitScreen)
- Ajustes na detecção de foco da tela
- Melhorias na analise biométrica
- Melhorias na analise do uso de dispositivos
- Correção do uso de câmera externa no ambiente de produção 

## Release Note V 2.5.3
- Fix: Resolução do video
- Melhorias no proctoring do tipo REALTIME

## Release Note V 2.5.2
- Alteração do nome do callback 'onFinish' para 'onResultAvailable'
- Melhorias no proctoring do tipo REALTIME

## Release Note V 2.5.1
- Novos atributos no callback de 'onFinish'
 - scoreThreshold: limiar de aprovação da sessão de proctoring
 - justification: em caso de reprovação, esse campo traz o resumo das irregularidades

## Release Note V 2.5.0
- Callback de 'onFinish' no hook de finish que permite o acesso ao resultado da auditoria de forma imediata
- Melhorias no proctoring em tempo real
- Melhorias no monitoramento ativo durante o exame
  - Novos tipos de alertas do onRealtimeAlerts:
    - position_detection_on_stream:
     - wrong_face_size_detected: Face muito perto da câmera, afaste-se um pouco mais
     - wrong_face_position_edge_detected: Face muito próxima da borda, mova-se para o centro da tela
     - wrong_face_position_move_right_detected: Face não centralizada, mova-se para a direita
     - wrong_face_position_move_top_detected: Face não centralizada, mova-se para cima
     - wrong_face_position_move_left_detected: Face não centralizada, mova-se para a esquerda
     - wrong_face_position_move_bottom_detected: Face não centralizada, mova-se para baixo


## Release Note V 2.4.0
- Compatibilidade com dispositivos móveis

## Release Note V 2.3.3
- Correção do reset no startSession

## Release Note V 2.3.2
- Melhorias no fluxo da câmera externa (reset e goToExternalCameraPositionStep)

## Release Note V 2.3.1
- Implementação da funcionalidade de transmissão com câmera externa

## Release Note V 2.3.0
- Implementação da funcionalidade de câmera externa (apenas checagem)

## Release Note V 2.2.0
- Retry para stream iniciados com falhas
- Criação da janela para termo de consentimento
- Criação da funcionalidade de varredura de ambiente em busca de cameras espiãs
- Melhorias nos logs

## Release Note V 2.1.1
- Escolha automatica do codec suportado (vp8/vp9)
- Não é mais obrigatório passar width e height no check devices
- Melhorias nos logs

## Release Note V 2.1.0
- Criação do runCheckDevicesFlow que permite que o usuário receba a lógica do checkDevices() em um modal próprio

## Release Note V 2.0.3
- Otimização na gravação de áudio removendo necessidade de download de scripts

## Release Note V 2.0.2
- Tratamento para fechamento de streams
- console.log() configuravel

## Release Note V 2.0.1
- Tratamento para duplo clique no checkDevices
- Ajuste de CORS no NoiseRecorder

## Release Note V 2.0.0
- Remoção do script deprecated AudioProcessor
- Monitoramento ativo durante o exame
  - Novos tipos de alertas do onRealtimeAlerts:
    - audio_detection_on_stream
    - face_detection_on_stream
    - mobile_detection_on_stream
    - person_detection_on_stream
    - position_detection_on_stream
- Nova forma de gravação de áudio
- Remoção das funções `pause()` e `resume()`
- Análise de posicionamento da face no modal do `checkDevices()`
- Novas propriedades adicionadas no retorno do `checkDevices()`:

```ts
{
    allowedAmbient: boolean,
    allowedMicrophone: boolean,
    allowedPositionFace: boolean,
    allowedResolution: boolean,
    cameraId: string,
    michophoneId: string,
    volumeRange: number,
    faceDetectionAlerts: { status: 'OK' | 'ALERT', type: string, description?: string },
    result: boolean,
}
```

## Release Note V 1.1.6

- - Adiciona o botão de cancelar captura no `capturePhoto()`.
  - Se a captura for cancelada, ela lancará uma exceção.

## Release Note V 1.1.5

- Captura da Geolocalização
- Login via componente (Credentials)
- Bloquear navegadores sem suporte
- Bloquear exame quando camera estiver em uso
- Gravação de vídeo opcional
- Atualização Interface do CapturePhoto
- Criação do callback onBufferSizeError
- Criação do callback onRealtimeAlerts
- Bloqueio das cameras simuladas da listagem de devices
- Aviso de camera ocupada

## Release Note V 1.1.4

- Adicionado resolução de 480p na gravação da tela
- Melhorias no finish

## Release Note V 1.1.0

- Adicionado fotos durante a execução da prova
- Adicionado o modal de capturePhoto, para cadastramento e autenticação biométrica
- Correção de interface do modal checkDevices com problema no lts

## License

[MIT](https://choosealicense.com/licenses/mit/)
