Confluência Atlassian: extensível em python

Em Alfastrakhovanie, usamos ativamente o "Wiki", cujo mecanismo é o Atlassian Confluence. A primeira vez que me deparei com isso (na tentativa de criar conteúdo nele), eu não tinha "dinamismo" - eu queria poder formar partes de páginas de forma programática, interagir com outros sistemas etc.


Por algum tempo, ele bateu a cabeça contra paredes diferentes, mas depois viu que "não havia uma parede na casa". Quero compartilhar minha experiência - como posso adicionar palestrantes ao Confluence. Espero que isso seja útil para quem usa. E, como sempre, para todos curiosos.


Wiki dinâmico


Inicialmente, o Confluence sugere uma maneira universal de expandir sua funcionalidade - plugins. Provavelmente, ele é bom, existe apenas uma desvantagem - um alto limite de entrada (você precisa aprender muito).


Após uma breve reflexão (pelos padrões de espaço), havia duas maneiras mais simples de expandir sua funcionalidade: a macro padrão "HTML" e "HTML Include". Neste artigo, focaremos mais detalhadamente no último.


Há um princípio de operação para esses métodos - o código HTML é incorporado na página do Confluence, pode ser estático (que também pode ser interessante, por exemplo, para formatação de página não padrão), pode ser dinâmico (incluindo componentes do servidor).


Exemplo: solicitação de reconciliação


Vejamos a maneira proposta de expandir os recursos do Confluence com um exemplo simples - uma lista de aprovação de documentos.


O que queremos fazer: adicione uma lista de aprovação à página para que todos possam ver quem deve coordenar o documento, se foi acordado e, se sim, quando.


Por conveniência, transformaremos o item da lista em um botão e escreveremos nele o nome do coordenador. O botão estará ativo se a página for visualizada pelo coordenador e não estará ativo em todos os outros casos.


Após a aprovação, o botão "deixará de ser um botão" - em vez do botão após a aprovação, desenharemos na página o fato da aprovação na forma de um texto (o nome do aprovador e a data da aprovação). Na versão mais rascunho (sem design), pode ser algo como isto:


imagem


Esquema de interação


imagem


Comentários - como funciona:


  • a página do Confluence contém várias macro "html include" - na verdade, solicitações HTTP GET com parâmetros (consideraremos mais detalhadamente abaixo)
  • ao renderizar uma página, essas solicitações (scripts python) são executadas no servidor de aplicativos, o resultado (HTML gerado) é desenhado na página
  • no processo de seu trabalho, o script, por exemplo, entra em contato com o banco de dados com o histórico de assinatura da página, se a página ainda não tiver sido "assinada" pelo assinante - o HTML conterá um botão (tudo como descrito acima)
  • quando você clica no botão, o envio ocorre - outro script python é chamado (um script para processar o fato da coordenação)
  • este script salva informações sobre o fato de entrar no banco de dados e redireciona o usuário de volta à página original (ao renderizar o fato de que o fato de assinar será levado em consideração - clicando no botão "assinar")

Um pouco complicado em palavras, vamos tentar esclarecer o código.


Então, precisamos criar dois scripts


  • o script para a formação do botão "sign" (vou chamá-lo de script "button")
  • um script para descobrir o fato de assinar (reação a um clique no botão - chamarei seu script de "manipulador")

Vamos criá-los, comece com o botão.


Botão Script


Esquematicamente, como o script do botão funciona:


date = getSignDate() if date: #       . else: if user==signee: #    else: #  inactive  

O script deve ser um documento HTML válido, cujo corpo, no formato mínimo, é um formulário


  • A ação do formulário contém a URL do script "manipulador"
  • o botão ativo é enviar
  • campos de formulário ocultos contêm parâmetros adicionais para o manipulador (no nosso caso, o nome da página e o login do signatário)

Uma visão aproximada do script (por questões de brevidade, joguei fora tudo o que era desnecessário - veja o código completo do github )


 form = cgi.FieldStorage() signee = form["signee"].value #   (  ) actual = form["actual"].value #    id = form["id"].value #  ,    resHtml = """ <!DOCTYPE HTML> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head> <body> <form name="input" action="http://172.16.108.216/misc/sign_proc.py" method="get"> """ server, token = wikiLogin() #   Confluence userName = getUserName(token, signee) #        res = getSignDate(id, signee) #     if res: #    resHtml += "<p> ({0}, {1})</p>".format(userName, res) #   else: #    if signee.lower() == actual.lower(): #      -   resHtml += '<input type="hidden" name="id" value="{0}">'.format(id) resHtml += '<input type="hidden" name="signee" value="{0}">'.format(signee) resHtml += "   <input type=\"submit\" value=\"{0}\">".format(userName) else: #      -    resHtml += "   <input disabled type=\"submit\" value=\"{0}\">".format(userName) resHtml += "</form></body></html>" #   HTML sys.stdout.buffer.write(b'Content-Type: text/html;charset=utf-8\n\n') sys.stdout.buffer.write(resHtml.encode("utf-8")) 

Script "manipulador"


A tarefa do manipulador é muito simples - para corrigir o fato de pressionar o botão "concordo". Em seguida, redirecione de volta para a página de onde a solicitação veio - ao renderizar a página, o fato de coordenação já será levado em consideração (veja a descrição acima).


Um exemplo (abreviado) de script "manipulador" (a versão completa - veja o github)


 form = cgi.FieldStorage() signee = form["signee"].value #   id = form["id"].value #  ,    addSignDate(id, signee) #    resHtml = """ <html> <head> <meta http-equiv="refresh" content="5;url=http://wiki.alfastrah.ru/display/DIT/{0}"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> </title> </head> <body> <p>    <b>{0}</b>  <b>{1}</b> . <br>      ...</p> </body> </html> """.format(id, signee) sys.stdout.buffer.write(b'Content-Type: text/html;charset=utf-8\n\n') sys.stdout.buffer.write(resHtml.encode("utf-8")) 

Página em Confluence


A página do Confluence contém três macro HTML incluídos com parâmetros diferentes (veja o código abaixo) e, na versão mais simples, fica assim:


imagem


Código da página no formato de marcação wiki - aqui você pode ver os parâmetros


 <h1> </h1> <p> ,  </p> <h1> </h1> <ul> <li> <ac:structured-macro ac:macro-id="..." ac:name="html-include" ac:schema-version="1"> <ac:parameter ac:name="url"> <ri:url ri:value="http://z14-0510-wiksap.vesta.ru/misc/sign_btn.py?signee=boss&amp;actual=korolevmv&amp;id=wikitools_sign"/> </ac:parameter> </ac:structured-macro> </li> <li> <ac:structured-macro ac:macro-id="..." ac:name="html-include" ac:schema-version="1"> <ac:parameter ac:name="url"> <ri:url ri:value="http://z14-0510-wiksap.vesta.ru/misc/sign_btn.py?signee=korolevmv&amp;actual=korolevmv&amp;id=wikitools_sign"/> </ac:parameter> </ac:structured-macro> </li> <li> <ac:structured-macro ac:macro-id="..." ac:name="html-include" ac:schema-version="1"> <ac:parameter ac:name="url"> <ri:url ri:value="http://z14-0510-wiksap.vesta.ru/misc/sign_btn.py?signee=maxvar&amp;actual=korolevmv&amp;id=wikitools_sign"/> </ac:parameter> </ac:structured-macro> </li> </ul> 

Um pouco sobre como configurar


Para que o esquema descrito funcione, é necessário levar em consideração os seguintes


Disponibilidade da macro de inclusão HTML


Às vezes, os administradores o ocultam - existem muitos problemas adicionais para ele (o outro lado das possibilidades).


Essa macro é gratuita e faz parte do Confluence - se você não tiver uma, entre em contato com os administradores, deixe-os procurar ...


Confluence White Lists


O Confluence não executará scripts hospedados em fontes desconhecidas; o host no qual o script está hospedado deve estar nas chamadas "listas brancas" (entre em contato com os administradores). Isso se aplica apenas ao script "button" - o script do manipulador já é chamado pelo botão, as restrições do Confluence não se aplicam a ele.


Execução de script


Os scripts (botões e manipulador) devem ser executáveis ​​- copie o URL para o navegador, ele deve funcionar e gerar HTML; se isso não acontecer, depure-o.


Erros de script


Se algum dos scripts travar com um erro - você não verá nada de bom, depure corretamente antes de publicar no Confluence.


Opções de script


Uma mente indagadora pode prestar atenção aos parâmetros do script - por um lado, são redundantes (por exemplo, o nome da página na qual o botão de aprovação está colocado - é conhecido, por que preenchê-lo?). Por outro lado, eles são inseguros (o "invasor" em nosso exemplo pode alterar o nome do aprovador por conta própria ou excluir o botão de reconciliação).


A redundância pode ser "superada" pelas macros de usuário (eu me pergunto há muito tempo - como elas podem ser praticamente úteis? Escreverei brevemente em um artigo separado). A segurança no Confluence é garantida pelo histórico da página - todos os "movimentos" são registrados, você pode alterar qualquer coisa; no Confluence permanece uma maravilhosa "trilha de auditoria" que permite entender em detalhes quem mudou o que e quando.


Interação da página


Em nossa prática, houve casos em que tivemos que analisar o código da página para coletar dados (por exemplo, é assim que gerenciamos o portfólio de projetos). É possível e nem muito difícil. Evolutivamente, chegamos à conclusão de que, se algumas informações em uma página são necessárias apenas para o código que interpreta essas informações, é mais fácil formular essas informações imediatamente no próprio código (na forma de JSON, por exemplo): editá-lo no modo de edição de página é bastante simples , é atraído pelo programa, mas as economias em análise e maior confiabilidade são significativas.


Mais exemplos


Por que mais usamos essas macros (como idéias - de repente, algo se mostra útil), muito brevemente


Design da página : se você deseja projetar a página de maneira não padrão - marcação usando CSS, que está contido no bloco HTML


Calendário de férias : usamos um calendário JS simples, preenche-o com dados do JSON, que editamos diretamente no código da página, obtemos um belo prato com as férias divididas (ano, mês, semana).


Impressão de cartões de tarefas para um quadro de scrum : definimos os parâmetros (números de tarefas no Jira e atributos adicionais) no formulário na página wiki (no bloco HTML), o lado do servidor forma os cartões de forma adequada para o envio a uma impressora.


Gerenciamento de portfólio de projetos : tínhamos essa ideia. Os mapas foram pontuados diretamente no wiki (o mapa de pontuação é uma página especialmente marcada), um plano de blocos grandes foi compilado a partir desses mapas de pontuação, que foram lindamente desenhados na forma de um gráfico de Gantt.


Glossário : a capacidade de visualizar termos - explicações para palavras individuais de uma página - de um dicionário comum e emitir entradas de dicionário na forma de "pop-ups". O próprio dicionário é coletado automaticamente na parte inferior da página.


Gráficos : se você precisar desenhar algum tipo de gráfico simples, é muito simples fazer isso incorporando o bloco HTML a qualquer um dos pacotes padrão (Google Charts, HighCharts, etc.)


Tabelas : em cima de qualquer mesa do Confluence você pode "pendurar" o Datatable - obtemos uma tabela filtrada com "paginação", muito agradável e conveniente.


A lista pode ser continuada por tempo suficiente; durante a operação, foi observado um inconveniente significativo: os erros no código do servidor são mal detectados - 500 erros são mal visualizados e praticamente não contêm informações. Caso contrário, experimente - é seguro o suficiente.


Resumir


A maneira simples descrita acima para aumentar o dinamismo do Confluence permite resolver muitos problemas diferentes. Para usá-lo, não são necessárias ferramentas e habilidades especiais. O uso é seguro o suficiente. Eu recomendo.


No próximo artigo, falarei sobre a experiência de usar macros personalizadas no Confluence - que, na minha opinião, pode realmente ser aprimorado com a ajuda delas.


Tudo é possível na programação - apenas uma questão de tempo e motivação.

Source: https://habr.com/ru/post/pt460929/


All Articles