Usando o XML-RPC
1 - Definindo o XML-RPC
O XML-RPC é um protocolo de RPC codificado em XML. É um protocolo simples, definido com poucas linhas de códigos em oposição com a maioria dos sistemas de RPC, onde os documentos padrões são freqüentemente com milhares de páginas e exige apoio de softwares para serem usados.2 - Criando o formulário de solicitação
Para que possamos solicita um evento através do portal, teremos que criar um Controller Page Template (CPT). Com o CPT podemos definir as ações de sucesso, falha e informar o script validador do template. Os arquivos gerados serão o insere_novo_evento.cpt, insere_novo_evento.cpt.metadata e o validate python script valida_novo_evento.cpy.Código fonte: insere_novo_evento.cpt
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"Código fonte: insere_novo_evento.cpt.metadata
metal:use-macro="here/main_template/macros/master"
i18n:domain="plone">
<head>
<metal:block fill-slot="top_slot"
tal:define="dummy python:request.set('disable_border',1)" />
</head>
<body>
<div metal:fill-slot="main"
tal:define="errors options/state/getErrors;
DateTime python:modules['DateTime'].DateTime;
current python:DateTime();
year_current current/year;
days python:range(1,32);
months python:range(1,13);
years python:range(year_current,year_current+2);">
<h1 i18n:translate="solicitacao_evento">Solicitação de evento</h1>
<p class="documentDescriptionEvent" i18n:translate="description_eventos">
Forumlário para solicitação de eventos
</p>
<form action=""
method="post"
tal:attributes="action template/getId" >
<div class="field"
tal:define="error errors/responsavel | nothing;
responsavel python:request.get('responsavel');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="responsavel" i18n:translate="label_responsavel">Responsável</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<input type="text"
id="responsavel"
name="responsavel"
size="60"
tabindex=""
value="responsavel"
tal:attributes="value responsavel;
tabindex tabindex/next;"
/>
</div>
<div class="field"
tal:define="error errors/telefone | nothing;
telefone python:request.get('telefone');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="telefone" i18n:translate="label_telefone">Telefone</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<input type="text"
id="telefone"
name="telefone"
size="20"
tabindex=""
value="telefone"
tal:attributes="value telefone;
tabindex tabindex/next;"
/>
</div>
<div class="field"
tal:define="error errors/email | nothing;
email python:request.get('email');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="email" i18n:translate="label_email">E-mail</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<input type="text"
id="email"
name="email"
size="60"
tabindex=""
value="email"
tal:attributes="value email;
tabindex tabindex/next;"
/>
</div>
<div class="field"
tal:define="error errors/nome_evento | nothing;
nome_evento python:request.get('nome_evento');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="nome_evento" i18n:translate="label_nome_evento">Nome do Evento</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<input type="text"
id="nome_evento"
name="nome_evento"
size="60"
tabindex=""
value="nome_evento"
tal:attributes="value nome_evento;
tabindex tabindex/next;"
/>
</div>
<div class="field"
tal:define="error errors/data_evento | nothing;
dia python:request.get('dia_evento');
mes python:request.get('mes_evento');
ano python:request.get('ano_evento');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="data_evento" i18n:translate="label_data_evento">Data do Evento</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<select name="dia_evento">
<option value="0">--</option>
<tal:block repeat="day days">
<option tal:content="day"
tal:define="day python:str(day)"
tal:attributes="value day;
selected python:test(dia==day, 'selected', None);"
value="day">day</option>
</tal:block>
</select>
/
<select name="mes_evento"
id="mes_evento"
onchange="validate_date_event('ano_evento')">
<option value="0">--</option>
<tal:block repeat="month months">
<option tal:content="month"
tal:define="month python:str(month)"
tal:attributes="value month;
selected python:test(mes==month, 'selected', None);"
value="month">month</option>
</tal:block>
</select>
/
<select name="ano_evento"
id="ano_evento"
onchange="validate_date_event(this)">
<option value="0">----</option>
<tal:block repeat="year years">
<option tal:content="year"
tal:define="year python:str(year)"
tal:attributes="value year;
selected python:test(ano==year, 'selected', None);"
value="year">year</option>
</tal:block>
</select>
</div>
<div class="field"
tal:define="error errors/descricao | nothing;
descricao python:request.get('descricao');"
tal:attributes="class python:test(error, 'field error', 'field')">
<label for="descricao" i18n:translate="corpo">Descrição do evento</label>
<span class="fieldRequired" title="Required"
i18n:attributes="title title_required;"
i18n:translate="label_required">(Required)</span>
<div tal:content="error">Validation error output</div>
<textarea name="descricao"
tabindex=""
tal:content="descricao"
tal:attributes="value descricao;
tabindex tabindex/next;"></textarea>
</div>
<input class="context"
type="submit"
tabindex=""
name="form.button.Submit"
value="Enviar"
i18n:attributes="value label_submit;"
tal:attributes="tabindex tabindex/next;" />
<input class="context"
type="reset"
tabindex=""
name="form.button.Cancel"
value="Cancelar"
i18n:attributes="value label_cancel;"
tal:attributes="tabindex tabindex/next;" />
<input type="hidden" name="form.submitted" value="1" />
</form>
</div>
</body>
</html>
default]
title=Validate new event
border=None
[validators]
validators = valida_novo_evento
[actions]
action.success = traverse_to:string:insere_novo_evento_script
action.failure = traverse_to:string:insere_novo_evento

Código fonte: valida_novo_evento.cpy
## Script (Python) "valida_novo_evento"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind state=state
##bind subpath=traverse_subpath
##parameters=responsavel='',telefone='',email='',nome_evento='',dia_evento='',mes_evento='',ano_evento='',observacao=''
##title=Verifica os dados do evento cadastrado pelo portal
##
from DateTime import DateTime
data_minima=DateTime()+5
data=ano_evento+"/"+mes_evento+"/"+dia_evento
#DEFININDO OS METODOS DE ERROS
def missing(field):
state.setError(field, 'Campo obrigatório.', 'input_required')
def dateInvalid(field):
state.setError(field, 'Data inválida.', 'date_invalid')
#VALIDANDO OS DADOS DO FORMULARIO
if not responsavel:
missing('responsavel')
if not telefone:
missing('telefone')
if not email:
missing('email')
if not nome_evento:
missing('nome_evento')
if not observcao:
missing('observcao')
if dia_evento=="0" or mes_evento=="0" or ano_evento=="0":
missing('data_evento')
elif DateTime(data)<DateTime(data_minima):
dateInvalid("data_evento")
#RETORNANDO O STATUS
if state.getErrors():
return state.set(status='failure', portal_status_message='Por favor corrija os erros indicados.')
else:
return state.set(status='success', portal_status_message='')
Código fonte: insere_novo_evento_script.cpy
## Script (Python) "valida_novo_evento"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind state=state
##bind subpath=traverse_subpath
##parameters=responsavel='',telefone='',email='',nome_evento='',dia_evento='',mes_evento='',ano_evento='',observacao=''
##title=Verifica os dados do evento cadastrado pelo portal
##
#GERANDO UM DICIONARIO COM OS DADOS DO EVENTO
dados = {"instituicao":nome_instituicao,"nome_solicitante":nome_solicitante,"responsavel":responsavel, \
"telefone":telefone,"email":email,"nome_evento":nome_evento,"dia_evento":dia_evento, "mes_evento":mes_evento, \
"ano_evento":ano_evento,"horario_evento":horario,"observacao":observacao}
#CRIANDO O EVENTO NA INTRANET - CHAMA O EXTERNAL METHOD DO PORTAL
#CHAMADO CRIA_EVENTO, PASSANDO O DICIONARIO DE DADOS
try:
context.cria_evento(dados)
status='success'
message=''
except:
status='failure'
message='Problemas na comunicação, tente novamente mais tarde!'
return state.set(status=status, portal_status_message=message)
Código fonte: insere_novo_evento_script.cpy.metadata
[actions]
action.success=redirect_to:string:resposta_solicitacao_evento
action.failure=redirect_to:string:insere_novo_evento
Código fonte: resposta_solicitacao_evento.pt
s<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
lang="en"
metal:use-macro="here/main_template/macros/master"
i18n:domain="plone">
<body metal:fill-slot="main">
<div metal:use-macro="here/document_actions/macros/document_actions">
Document actions (print, sendto etc)
</div>
<h1>Solicitação de evento</h1>
<br />
<div align="center">
<p>Sua solicitação foi submetida com sucesso e está em análise.</p>
</div>
</body>
</html>
3 - Criando o external method
Por motivos de segurança, não podemos importar o módulo xmlrpclib dentro de um script python. Então se faz necessário a criação de método dentro da pasta extensions de seu produto e a criação de um external method na ZMI de sua aplicação. O id do extenal method será cria_evento. A variável server_url é o caminho de sua outra aplicação, que neste caso é um instancia da intranet. Na última linha ele invoca o script na intranet e passa o dicionário de dados. O script python é o create_new_event.Código fonte: cria_evento
from xmlrpclib import Server
def cria_evento(dados):
server_url = 'http://localhost:8081/intranet/agenda/'
server = Server(server_url)
server.create_new_event.add(dados)
4 - Criando o script para inserir o evento
Este script tem a finalidade de criar um objeto Event e editar suas propiedades de acordo com a solicitação efetuada através do portal.Código fonte: create_new_event
## Script (Python) "create_new_event"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=dados
##title=Insere um novo evento na intranet
##
from DateTime import DateTime
#GERANDO UM ID PARA O EVENTO
objetos = context.objectIds()
contador = len(objetos)+1
dia = DateTime().strftime('%d')
mes = DateTime().strftime('%m')
ano = DateTime().strftime('%Y')
id_evento = "evento_"+dia+"_"+mes+"_"+ano+"_"+str(contador)
#VARIAVEIS
nome_evento=dados["nome_evento"]
dia_evento=dados["dia_evento"]
mes_evento=dados["mes_evento"]
ano_evento=dados["ano_evento"]
data=DateTime(dia_evento+"/"+mes_evento+"/"+ano_evento)
#CRIANDO O NOVO EVENTO
context.invokeFactory('Event', id=id_evento, title=nome_evento)
#EDITANDO O FORMULARIO
newEvent = getattr(context, id_evento)
setTelefone
newEvent.setTitle(nome_evento)
newEvent.setContactName(dados["responsavel"])
newEvent.setContactPhone(dados["telefone"])
newEvent.setContactEmail(dados["email"])
newEvent.setStart(data)
newEvent.setEnd(data)
newEvent.setText(dados["observacao"])
5 - Conclusão
Neste exemplo, podemos observar como fazer a comunicação entre dois portais diferentes. Este foi um exemplo simple, que demonstra apenas a inclusão, mais usando a biblioteca xmlrpclib podemos deletar dados, recuperar dados de outros portais, efetuar autenticação em ouros sistemas e etc. Existe inúmeras possíbilidades é só adaptar a sua necessidade.
Plone
2.5.5