Foi implementado no Titan um Sistema de Alertas inspirado nas notificações do Android. Trata-se de uma API simples que possibilita avisar usuários específicos de ações executadas no sistema relacionadas a eles. Para que funcione de maneira adequada o ideal é que esteja habilitado o job ‘daily’ para rodar diariamente (ver e-mail com subject “Scheduler Jobs”).

O sistema de alertas envia notificações aos usuários de duas formas: por e-mail e por meio da interface da instância. A figura abaixo mostra como fica a interface com os alertas ativos.

Para habilitar o Sistema de Alertas, o primeiro passo é incluir algumas entidades mandatórias ao schema padrão do Titan no DB. Caso esteja criando uma instância nova utilizando o Composer, estas entidades já estarão criadas e você pode pular este passo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
CREATE TABLE _alert (
  _id SERIAL,
  _template VARCHAR(64) NOT NULL,
  _assign VARCHAR(64) NOT NULL,
  _until TIMESTAMP WITHOUT TIME ZONE,
  _parameters TEXT,
  _user INTEGER,
  _create TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL,
  _update TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL,
  CONSTRAINT _alert_idx UNIQUE(_template, _assign),
  CONSTRAINT _alert_pkey PRIMARY KEY(_id),
  CONSTRAINT _alert_user_fk FOREIGN KEY (_user)
	REFERENCES _user(_id)
	ON DELETE CASCADE
	ON UPDATE CASCADE
	NOT DEFERRABLE
);

CREATE TABLE _alert_user (
  _alert INTEGER NOT NULL,
  _user INTEGER NOT NULL,
  _read BIT(1) DEFAULT B'0'::"bit" NOT NULL,
  _delete BIT(1) DEFAULT B'0'::"bit" NOT NULL,
  CONSTRAINT _alert_user_idx PRIMARY KEY(_alert, _user),
  CONSTRAINT _alert_user_fk FOREIGN KEY (_alert)
	REFERENCES _alert(_id)
	ON DELETE CASCADE
	ON UPDATE CASCADE
	NOT DEFERRABLE,
  CONSTRAINT _alert_user_user_fk FOREIGN KEY (_user)
	REFERENCES _user(_id)
	ON DELETE CASCADE
	ON UPDATE CASCADE
	NOT DEFERRABLE
);

CREATE TABLE _alert_mail (
  _alert INTEGER NOT NULL,
  _trigger TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  _send BIT(1) DEFAULT B'0'::"bit" NOT NULL,
  CONSTRAINT _alert_mail_idx PRIMARY KEY(_alert, _trigger),
  CONSTRAINT _alert_mail_fk FOREIGN KEY (_alert)
	REFERENCES _alert(_id)
	ON DELETE CASCADE
	ON UPDATE CASCADE
	NOT DEFERRABLE
);

O passo posterior é inserir no ‘configure/titan.xml’ uma tag ‘alert’:

<alert
	xml-path="configure/alert.xml"
/>

E criar na pasta ‘configure/’ da instância um novo arquivo XML denominado ‘alert.xml’. Este arquivo deverá possuir a seguinte sintaxe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="ISO-8859-1"?>
<alert-mapping>
	<alert
		id="_OPORTUNITY_KNOWLEDGE_"
		message="Há uma nova oportunidade de estágio do(a) supervisor(a) [SUPERVISOR] na sua área de conhecimento ([KNOWLEDGE])"
		go="titan.php?target=body&toSection=trainee.oportunity.choose&toAction=list"
		icon="titan.php?target=loadFile&file=interface/alert/info.gif"
		subject="[Pandora] Disponibilizada uma oportunidade de estágio na sua área">
Olá [USER],
O supervisor [SUPERVISOR] disponibilizou uma oportunidade de estágio na sua área de conhecimento: [KNOWLEDGE].
Para ver mais informações desta oportunidade bem como outras propostas de estágio na Embrapa, acesse o Módulo de Estágios do Pandora clicando no link abaixo (ou copie e cole no seu navegador):
[URL]titan.php?toSection=trainee.oportunity.choose&toAction=list
Sem mais,
Equipe Pandora
	</alert>
	...
</alert-mapping>

Pode-se ter diversas tags “alert”, desde cada uma tenha um ‘id’ único. O atributo ‘message’ será a notificação que irá aparecer na interface da instância, o ‘go’ é para onde o usuário será redirecionado ao clicar na mensagem e o ‘icon’ é o ícone que aparece ao lado esquerdo da mensagem. O atributo ‘subject’ e o conteúdo da tag referem-se ao assunto e ao corpo do e-mail, respectivamente, que será enviado ao usuário.

Os atributos ‘message’, ‘go’, ‘subject’ e o conteúdo da tag podem utilizar hashtags para customizar as informações. Pode-se utilizar hashtags padrões e enviar novas hashtags no momento do registo do alerta. As hashtags padrões são:

  • [SYSTEM] - Nome da instância;
  • [URL] - URL da instância;
  • [AUTHOR] - O nome do usuário que acionou a ação que gerou o alerta;
  • [USER] - O nome do usuário que está sendo alertado;
  • [DAYS_MISSING] - Caso haja um limite para o alerta ser atendido, esta hash apresenta quantos dias faltam para o limite ser atingido. Ela é dinâmica, ou seja, utilizá-la em uma mensagem fará com que a os dias faltantes apresentados na mensagem sejam atualizados a medida em que a data se aproxima;
  • [UNTIL] - Data limite para o alerta ser atendido; e
  • [DATE] - Data de geração do alerta.

Agora, basta registrar o alerta em qualquer componente local da instância. Para isto, é disponibilizado o seguinte método estático:

Alert::add ($template, $assign, $users, $tags = NULL, $until = NULL, $author = NULL, $overwrite = TRUE, $mail = NULL);

Onde:

  • $template - É o ID da tag ‘alert’ do XML ‘configure/alert.xml’ que será utilizado no alerta;
  • $assign - É uma assinatura única para o alerta que identifique a entidade a qual está vinculado;
  • $users - Uma array com os usuários que receberão o alerta;
  • $tags - Uma array com novas hashtags e seus valores correspondentes (também pode-se passar uma hashtag homônima a alguma do sistema para sobreescrevê-la);
  • $until - A data limite para o alerta ser atendido. Caso não seja preenchido o alerta ficará visível ao usuário até que este o apague;
  • $author - Força o autor do alerta passando um novo ID de usuário. Caso seja passado NULL o sistema coloca, por padrão, o ID do usuário logado;
  • $overwrite - Caso esta opção seja TRUE (padrão), um alerta poderá ser sobreescrito (mesmo ID de template e assinatura) fazendo com que ele volte a ficar “não-lido” para os usuários e sobreescrevendo as demais informações; e
  • $mail - O sistema envia um e-mail no momento em que o alerta é registrado, entretanto, pode-se passar neste parâmetro um vetor com um ou mais Unix timestamp para que o sistema envie novos e-mails no caso do alerta ainda não ter sido atendido. Esta funcionalidade funcionará apenas se o scheduler job ‘daily’ estiver ativo.

Um exemplo de uso do método é mostrado a seguir. Nele, ao ser registrado uma nova proposta de estágio envio um alerta a todos usuários da mesma área de conhecimento:

1
2
3
4
5
6
7
8
9
10
11
$sql = "SELECT _id FROM _user WHERE _deleted = B'0' AND _active = B'1' AND knowledge IS NOT NULL AND knowledge IN (WITH RECURSIVE __all_know AS (SELECT id FROM metadata.knowledge WHERE father = '". $form->getField ('_KNOWLEDGE_')->getValue () ."' OR id = '". $form->getField ('_KNOWLEDGE_')->getValue () ."' UNION ALL SELECT b.id FROM __all_know a, metadata.knowledge b WHERE a.id = b.father) SELECT id FROM __all_know)";

$sth = Database::singleton ()->prepare ($sql);
$sth->execute ();
$users = array ();
while ($users [] = $sth->fetchColumn ());
Alert::add ('_OPORTUNITY_KNOWLEDGE_', $itemId, $users,
			array ('[KNOWLEDGE]' => Form::toText ($form->getField ('_KNOWLEDGE_')),
				   '[SUPERVISOR]' => Form::toText ($form->getField ('_SUPERVISOR_')),
				   '[ID]' => $itemId),
			NULL, $form->getField ('_SUPERVISOR_')->getValue (), FALSE);

Explicando com mais detalhes a figura já mostrada:

Pode ser interessante remover totalmente um alerta caso o usuário execute uma determinada ação que tire o sentido do alerta. No meu exemplo o usuário poderia se cadastrar na oportunidade ofertada. Para possibilitar isto foi criado o seguinte método estático:

Alert::remove ($template, $assign);

Também foi implementado um garbage collector que remove alertas cujo a data ‘until’ já tenha sido alcançada ou que todos os usuários envolvidos já tenham apagado a notificação de interface e todos os e-mails tenham sido enviados. Novamente, para que esta importante ferramenta de otimização funcione corretamente é necessário que o job ‘daily’ esteja ativo.