Chapter 14: Outras receitas
Outras receitas
Atualizando
Na página "site" da interface administrativa, há um botão "atualizar agora". Caso isso não seja viável ou não funcione (por exemplo, devido a um problema de bloqueio de arquivo), atualizar o web2py manualmente é muito fácil.
Simplesmente descompacte a última versão do web2py sobre a instalação antiga.
Isso atualizará todas as bibliotecas, bem como os aplicativos admin, exemplos, bem vinda. Ele também criará um novo arquivo vazio "NEWINSTALL". Ao reiniciar, o web2py excluirá o arquivo vazio e empacotará o aplicativo de boas-vindas em "welcome.w2p", que será usado como o novo aplicativo de andaimes.
O web2py não atualiza nenhum arquivo em seus aplicativos. Algumas partes importantes da estrutura não fazem parte das bibliotecas, mas fazem parte do aplicativo Bem-vindo. Novos aplicativos herdarão essas mudanças de estrutura, mas não os aplicativos existentes. Você precisa copiar ou mesclar as alterações manualmente. Às vezes isso é necessário para aproveitar as novas funcionalidades, e às vezes é necessário para compatibilidade com novas versões, especialmente se você estiver usando recursos experimentais. O grupo web2py no Grupos do Google é uma boa maneira de acompanhar as alterações necessárias. Partes do aplicativo de boas-vindas a serem copiadas para aplicativos existentes são o controlador appadmin, as visualizações de nível superior, incluindo appadmin.html e as visualizações genéricas, e o conteúdo da pasta estática que contém a versão mais recente de arquivos javascript importantes. Obviamente, você precisa mesclar suas alterações (se houver). Manter backups ou usar um sistema de controle de versão é uma boa ideia.
# When you upgrade web2py your should update app files that are important to web2py for properly functioning
#
# views/
# appadmin.html
# generic.ics
# generic.load
# generic.rss
# layout.html
# generic.json
# generic.map
# generic.xml
# web2py_ajax.html
# generic.html
# generic.jsonp
# generic.pdf
#
# controller/
# appadmin.py
#
# static/
# css/*
# images/*
# js/*
#
# You can do it with the following bash commands :
# NOTE: Please make a backup of your app before to make sure you don't break anything
#
# From web2py/applications/
cp -R welcome/static/* YOURAPP/static/
cp welcome/controllers/appadmin.py YOURAPP/controllers/
cp -R welcome/views/* YOURAPP/views/
Como distribuir seus aplicativos como binários
É possível agrupar seu aplicativo com a distribuição binária web2py e distribuí-los juntos. A licença permite isso contanto que você deixe claro na licença do seu aplicativo que você está empacotando com o web2py e adicione um link ao web2py.com
.
Aqui explicamos como fazer isso no Windows:
- Crie seu aplicativo como de costume
- usando admin, bytecode compile seu aplicativo (um clique)
- usando admin, embale seu aplicativo compilado (outro clique)
- Crie uma pasta "myapp"
- Faça o download de uma distribuição binária do windows webpy
- Descompacte-o na pasta "myapp" e inicie-o (dois cliques)
- Carregar usando admin o aplicativo previamente empacotado e compilado com o nome "init" (um clique)
- Crie um arquivo "myapp/start.bat" que contenha "web2py/web2py.exe"
- Crie um arquivo "myapp/license" que contenha uma licença para o seu aplicativo e certifique-se de que ele está sendo "distribuído com uma cópia não modificada do web2py do web2py.com"
- Zip a pasta myapp em um arquivo "myapp.zip"
- Distribuir e/ou vender "myapp.zip"
Quando os usuários descompactarão "myapp.zip" e clicarem em "executar", eles verão seu aplicativo em vez do aplicativo "bem-vindo". Não há exigência no lado do usuário, nem mesmo o Python pré-instalado.
Para binários do Mac, o processo é o mesmo, mas não há necessidade do arquivo "bat".
Desenvolvendo com IDEs: WingIDE, Rad2Py, Eclipse e PyCharm
Você pode usar o web2py com IDEs de terceiros, como WingIDE, Rad2Py, Eclipse e PyCharm.
PyCharm
PyCharm v3 Professional Edition introduz suporte embutido para web2py.
A partir de v3.0, PyCharm reconhecerá aplicações web2py pertence a um diretório web2py pai, e isso irá ativar o suporte web2py. Suporte significa que a biblioteca web2py é adicionada ao projeto.
Inicie um projeto PyCharm abrindo o diretório da instalação web2py e navegue pelo diretório de aplicativos.
A integração do git do PyCharm lida com isso; ele suporta vários repositórios git dentro da estrutura de diretórios de um projeto. Mantenha cada aplicativo em seu próprio repositório git para facilitar a implementação.
A edição Professional inclui um lançador padrão para um projeto web2py que inicia o web2py.py e, portanto, lança o servidor de foguete integrado.
Dicas de depuração do PyCharm
Você pode cair no depurador do PyCharm como qualquer outra sessão do Python. Isso significa que você pode iniciar a depuração do script web2py.py, que executará o servidor de foguetes, com o PyCharm conectado a esse processo. Use o seu navegador para ativar a função do controlador de seu interesse.
Quando um ponto de interrupção é encontrado durante a solicitação, você chegará no depurador do PyCharm.
No entanto, isso requer a remoção de from gluon.debug import dbg
afirmações.
Pycharm: Depurando um módulo no contexto do web2py
Pode ser conveniente depurar diretamente um módulo com código de teste isoladamente do resto do web2py. Você pode fazer uma configuração de execução/depuração PyCharm padrão para executar um arquivo de módulo como um script Python independente e colocar seu código de teste em
if __name__ == "__main__":
mas você não obtém os modelos e conexões de banco de dados do web2py.
Você pode fazer com que os controladores e pontos de interrupção fictícios sejam inseridos em seu módulo depois de executar a função de controlador fictício por meio de seu navegador, conforme descrito acima, mas existe uma opção mais conveniente:
Imagine que você tem esse bloco de teste em um módulo module_1.py
:
if __name__ == "__main__":
... code which tests things
e, ao mesmo tempo, você deseja que as conexões e modelos do banco de dados estejam disponíveis da mesma forma que o web2py normalmente.
Usando as opções de linha de comando do web2py, você pode fazer uma configuração de execução/depuração do PyCharm fazer isso. Faça o script: web2py.py
Faça os parâmetros do script: -S <your_app_name> -M -R /path/to/your_module/module_1.py
`: code
Isso executará os modelos web2py e, em seguida, carregará seu módulo, que então executará o __main__
código em um contexto semelhante a um aplicativo web2py em execução. Essas opções de linha de comando estão documentadas no capítulo 4.
WingIDE
Aqui está uma captura de tela do uso do web2py com o WingIDE:
Usando IDEs de finalidade geral com web2py
O problema geral com esses IDEs (exceto aqueles que suportam web2py) é que eles não entendem o contexto no qual modelos e controladores são executados e, portanto, o preenchimento automático não funciona imediatamente.
Para fazer o preenchimento automático funcionar, o truque geral consiste em editar seus modelos e controladores e adicionar o seguinte código:
if False:
from gluon import *
request = current.request
response = current.response
session = current.session
cache = current.cache
T = current.T
O bloco de importação não altera a lógica, pois isso nunca é executado, mas força o IDE a analisá-lo e entender de onde os objetos no namespace global vêm (o gluon
módulo), fazendo com que o preenchimento automático funcione.
Se você estiver confiando em variáveis em seus modelos (como definições de banco de dados), considere adicionar à lista da seguinte forma:
from db import *
Você também pode considerar importar todos os modelos.
if False:
from gluon import *
from db import * #repeat for all models
from menu import *
Além disso, se estiver usando o Eclipse com PyDev, você deve adicionar a pasta web2py ao caminho do sistema python (nas preferências do PyDev para o interpretador python). Em algumas versões do PyDev, foi possível usar o suporte de depuração dentro do Eclipse, lançando o web2py.py. Provavelmente, é aconselhável remover a importação do módulo de depuração gluon. Além disso, para fazer isso, você deve tornar o projeto pydev o diretório web2py, não seu aplicativo específico.
A integração do git do PyDev lida com isso; ele suporta vários repositórios git dentro da estrutura de diretórios de um projeto.
SQLDesigner
Existe um software chamado SQLDesigner que permite criar visualmente modelos web2py e depois gerar o código correspondente. Aqui está uma captura de tela.
A versão do SQLDesigner que funciona com o web2py pode ser encontrada aqui:
https://github.com/elcio/visualdal
Publicando uma pasta
Considere o problema de compartilhar uma pasta (e subpastas) na web. O web2py torna isso muito fácil. Você só precisa de um controlador como este:
from gluon.tools import Expose
def myfolder():
return dict(files=Expose('/path/to/myfolder'))
que você pode renderizar em uma visão com {{=files}}
. Ele criará uma interface para visualizar os arquivos e pastas e navegar na estrutura da árvore. Imagens terão uma prévia.
O prefixo do caminho "/ caminho/para/minhapasta" ficará oculto para os visitantes. Por exemplo, um arquivo chamado "/path/to/myfolder/a/b.txt" será substituído por "base/a/b.txt". O prefixo "base" pode ser especificado usando o basename
argumento da função Expose. Usando o argumento extensions
pode especificar uma lista de extensões de arquivos a serem listadas, outros arquivos serão ocultados. Por exemplo:
def myfolder():
return dict(files=Expose('/path/to/myfolder', basename='.',
extensions=['.py', '.jpg']))
Arquivos e pastas que contenham a palavra "private" no caminho ou que tenham um arquivo iniciado com "." ou terminar em "~" estão sempre ocultos.
Teste funcional
web2py vem com um módulo gluon.contrib.webclient
que permite testes funcionais de aplicativos web2py locais e remotos. Na verdade, este módulo não é específico para o web2py e pode ser usado para testar e interagir programaticamente com qualquer aplicativo da Web, mas foi projetado para entender a sessão web2py e os postbacks do web2py.
Aqui está um exemplo de uso. O programa abaixo cria um cliente, conecta-se à ação "index" para estabelecer uma sessão, registra um novo usuário, depois faz logout e logins novamente usando o credenciais recém-criadas:
from gluon.contrib.webclient import WebClient
client = WebClient('http://127.0.0.1:8000/welcome/default/',
postbacks=True)
client.get('index')
# register
data = dict(first_name='Homer',
last_name='Simpson',
email='homer@web2py.com',
password='test',
password_two='test',
_formname='register')
client.post('user/register', data=data)
# logout
client.get('user/logout')
# login again
data = dict(email='homer@web2py.com',
password='test',
_formname='login')
client.post('user/login', data=data)
# check registration and login were successful
client.get('index')
assert('Welcome Homer' in client.text)
O construtor WebClient usa um prefixo de URL como argumento. No exemplo que é "http://127.0.0.1:8000/welcome/default/". Não executa nenhum IO de rede. o postbacks
argumento padrão para True
e informa ao cliente como lidar com postagens web2py.
O objeto WebClient, client
, tem apenas dois métodos: get
e post
. O primeiro argumento é sempre um postfix de URL. A URL completa para o pedido GET de POST é construída simplesmente pela concatenação do prefixo e do postfix. O propósito disso é tornar a sintaxe menos detalhada para longas conversas entre cliente e servidor.
data
é um parâmetro específico da solicitação POST e contém um dicionário dos dados a serem postados. Formulários Web2py têm um oculto _formname
campo e seu valor deve ser fornecido, a menos que haja um único formulário na página. Os formulários Web2py também contêm um _formkey
campo que é projetado para evitar CSRF atacado. É tratado automaticamente pelo WebClient.
Ambos client.get
e client.post
aceite os seguintes argumentos extras:
headers
: um dicionário de cabeçalhos HTTP opcionais.cookies
: um dicionário de cookies HTTP opcionais.auth
: um dicionário de parâmetros a serem passados paraurllib2.HTTPBasicAuthHandler().add_password(**auth)
para executar a autenticação básica. Para mais informações sobre isso, nos referimos à documentação do Python para o módulo urllib2.
o client
objeto no exemplo realiza uma conversa com o servidor especificado no construtor, fazendo solicitações GET e POST. Ele automaticamente manipula todos os cookies e os envia de volta para manter as sessões. Se detectar que um novo cookie de sessão é emitido enquanto um já existente já está presente, ele o interpreta como uma sessão quebrada e gera uma exceção. Se o servidor retornar um erro HTTP, ele gerará uma exceção. Se o servidor retornar um erro HTTP que contenha um ticket web2py, ele retornará uma exceção RuntimeError contendo o código do ticket.
o client
objeto mantém um log de solicitações em client.history
e um estado associado ao seu último pedido bem-sucedido. O estado consiste em:
client.status
: o código de status retornadoclient.text
: o conteúdo da páginaclient.headers
: um dicionário de cabeçalhos analisadosclient.cookies
: um dicionário de cookies analisadosclient.sessions
: um dicionário de sessões web2py no formulário{appname: session_id}
.client.forms
: um dicionário de formulários web2py detectados noclient.text
. O dicionário tem a forma{_formname, _formkey}
.
O objeto WebClient não executa nenhuma análise do client.text
retornado pelo servidor, mas isso pode ser feito facilmente com muitos módulos de terceiros, como o BeautifulSoup. Por exemplo, aqui está um código de exemplo que encontra todos os links em uma página baixada pelo cliente e verifica todos eles:
from BeautifulSoup import BeautifulSoup
dom = BeautifulSoup(client.text)
for link in dom.findAll('a'):
new_client = WebClient()
new_client.get(a.href)
print new_client.status
Construindo um web2py minimalista
Algumas vezes precisamos implantar o web2py em um servidor com pouca memória. Neste caso, queremos reduzir o web2py ao seu mínimo.
Uma maneira fácil de fazer isso é o seguinte:
- Em uma máquina de produção, instale o web2py completo da fonte
- De dentro da pasta web2py principal
python scripts/make_min_web2py.py /path/to/minweb2py
- Agora copie em "/ path/to/minweb2py/applications" os aplicativos que você deseja implantar
- Implantar "/ path/to/minweb2py" no servidor de pequena dimensão
O script "make_min_web2py.py" cria uma distribuição web2py minimalista que não inclui:
- admin
- exemplos
- bem vinda
- scripts
- raramente usados módulos contrib
Ele inclui um aplicativo "bem-vindo" que consiste em um único arquivo para permitir a implantação de testes. Olhe para este script. No topo, contém uma lista detalhada do que está incluído e do que é ignorado. Você pode facilmente modificá-lo e adaptá-lo às suas necessidades.
Buscando um URL externo
Python inclui o urllib
biblioteca para buscar urls:
import urllib
page = urllib.urlopen('http://www.web2py.com').read()
Isso geralmente é bom, mas o urllib
O módulo não funciona no Google App Engine. O Google fornece uma API diferente para fazer o download de URLs que funcionem apenas no GAE. Para tornar seu código portátil, o web2py inclui um fetch
função que funciona no GAE, assim como em outras instalações do Python:
from gluon.tools import fetch
page = fetch('http://www.web2py.com')
Datas bonitas
Muitas vezes é útil representar um datetime não como "2009-07-25 14:34:56" mas como "um ano atrás". O web2py fornece uma função de utilidade para isso:
import datetime
d = datetime.datetime(2009, 7, 25, 14, 34, 56)
from gluon.tools import prettydate
pretty_d = prettydate(d, T)
O segundo argumento (T) deve ser passado para permitir a internacionalização da saída.
Geocodificação
Se você precisar converter um endereço (por exemplo: "243 S Wabash Ave, Chicago, IL, EUA") em coordenadas geográficas (latitude e longitude), o web2py fornecerá uma função para isso.
from gluon.tools import geocode
address = '243 S Wabash Ave, Chicago, IL, USA'
(latitude, longitude) = geocode(address)
A função geocode
requer uma conexão de rede e se conecta ao serviço de geocodificação do Google para a geocodificação. A função retorna (0,0)
em caso de falha. Observe que o serviço de geocodificação do Google reduz o número de solicitações, portanto, você deve verificar o contrato de serviço. o geocode
função é construída em cima do fetch
função e, portanto, funciona no GAE.
Paginação
Essa receita é um truque útil para minimizar o acesso ao banco de dados no caso de paginação, por exemplo, quando você precisa exibir uma lista de linhas de um banco de dados, mas deseja distribuir as linhas em várias páginas.
Comece criando um primos aplicativo que armazena os primeiros 1000 números primos em um banco de dados.
Aqui é o modelo db.py
:
db = DAL('sqlite://primes.db')
db.define_table('prime', Field('value', 'integer'))
def isprime(p):
for i in range(2, p):
if p%i==0: return False
return True
if len(db().select(db.prime.id))==0:
p=2
for i in range(1000):
while not isprime(p): p+=1
db.prime.insert(value=p)
p+=1
Agora crie uma ação list_items
no controlador "default.py" que se lê assim:
def list_items():
if len(request.args): page=int(request.args[0])
else: page=0
items_per_page=20
limitby=(page*items_per_page, (page+1)*items_per_page+1)
rows=db().select(db.prime.ALL, limitby=limitby)
return dict(rows=rows, page=page, items_per_page=items_per_page)
Observe que esse código seleciona mais um item do que o necessário, 20 + 1. O elemento extra diz à visão se existe uma próxima página.
Aqui está a visualização "default/list_items.html":
{{extend 'layout.html'}}
{{for i, row in enumerate(rows):}}
{{if i==items_per_page: break}}
{{=row.value}}<br />
{{pass}}
{{if page:}}
<a href="{{=URL(args=[page-1])}}">previous</a>
{{pass}}
{{if len(rows)>items_per_page:}}
<a href="{{=URL(args=[page+1])}}">next</a>
{{pass}}
Desta forma, obtivemos paginação com uma única seleção por ação, e essa seleção apenas seleciona uma linha a mais do que precisamos.
httpserver.log e o formato de arquivo de log
O servidor web web2py registra todas as solicitações em um arquivo chamado:
httpserver.log
no diretório web2py raiz. Um nome de arquivo e localização alternativos pode ser especificado via opções de linha de comando web2py.
Novas entradas são anexadas ao final do arquivo sempre que uma solicitação é feita. Cada linha se parece com isso:
127.0.0.1, 2008-01-12 10:41:20, GET, /admin/default/site, HTTP/1.1, 200, 0.270000
O formato é:
ip, timestamp, method, path, protocol, status, time_taken
Onde
- ip é o endereço IP do cliente que fez o pedido
- timestamp é a data e a hora da solicitação no formato ISO 8601, AAAA-MM-DDT HH: MM: SS
- o método é GET ou POST
- path é o caminho solicitado pelo cliente
- protocol é o protocolo HTTP usado para enviar para o cliente, geralmente HTTP/1.1
- status é um dos códigos de status HTTP [status]
- time_taken é a quantidade de tempo que o servidor levou para processar a solicitação, em segundos, sem incluir o tempo de upload/download.
No repositório de appliances [appliances] , você encontrará um appliance para análise de log.
Esse log está desabilitado por padrão ao usar o mod_wsgi, pois seria o mesmo que o log do Apache.
Preenchendo banco de dados com dados fictícios
Para fins de teste, é conveniente poder preencher tabelas de banco de dados com dados fictícios. O web2py inclui um classificador bayesiano já treinado para gerar texto fictício, mas legível, para esse propósito.
Aqui está a maneira mais simples de usá-lo:
from gluon.contrib.populate import populate
populate(db.mytable, 100)
Ele irá inserir 100 registros fictícios em db.mytable. Ele tentará fazer de forma inteligente gerando texto curto para campos de string, texto mais longo para campos de texto, inteiros, duplos, datas, tempos de dados, horas, booleanos, etc. para os campos correspondentes. Ele tentará respeitar os requisitos impostos pelos validadores. Para campos contendo a palavra "nome", ele tentará gerar nomes fictícios. Para campos de referência, ele gerará referências válidas.
Se você tiver duas tabelas (A e B) onde B referencia A, certifique-se de preencher A primeiro e B segundo.
Como a população é feita em uma transação, não tente preencher muitos registros de uma só vez, principalmente se houver referências. Em vez disso, preencha 100 de cada vez, efetue o loop.
for i in range(10):
populate(db.mytable, 100)
db.commit()
Você pode usar o classificador bayesiano para aprender um texto e gerar um texto falso que soa semelhante, mas não deve fazer sentido:
from gluon.contrib.populate import Learner, IUP
ell=Learner()
ell.learn('some very long input text ...')
print ell.generate(1000, prefix=None)
Aceitando pagamentos com cartão de crédito
Existem várias maneiras de aceitar pagamentos com cartão de crédito on-line. O web2py fornece APIs específicas para alguns dos mais populares e práticos:
- Google Wallet [googlewallet]
- PayPal [paypal]
- Stripe.com [stripe]
- Authorize.net [authorizenet]
- DowCommerece [dowcommerce]
Os dois primeiros mecanismos acima delegam o processo de autenticação do beneficiário a um serviço externo. Embora essa seja a melhor solução para segurança (seu aplicativo não manipula nenhuma informação de cartão de crédito), torna o processo incômodo (o usuário deve fazer login duas vezes; por exemplo, uma vez com o aplicativo e uma vez com o Google) e não permite seu aplicativo para lidar com pagamentos recorrentes de maneira automatizada.
Há momentos em que você precisa de mais controle e deseja gerar o formulário de entrada para as informações do cartão de crédito e, de forma programática, solicitar ao processador que transfira dinheiro do cartão de crédito para sua conta.
Por esse motivo, o web2py fornece integração imediata com Stripe, Authorize.net (o módulo foi desenvolvido por John Conde e ligeiramente modificado) e DowCommerce. Stripe é o mais simples de usar e também o mais barato para baixo volume de transações (eles cobram nenhum custo fixo, mas cobram cerca de 3% por transação). Authorize.net é melhor para grandes volumes (tem um custo fixo anual mais um custo menor por transação).
Lembre-se de que, no caso de Stripe e Authorize.net, o seu programa aceitará informações sobre cartões de crédito. Você não tem que armazenar essas informações e nós recomendamos que você não por causa das exigências legais envolvidos (verifique com Visa ou MasterCard), mas há momentos em que você pode querer armazenar as informações de pagamentos recorrentes ou para reproduzir o Amazon um- clique no botão pagar.
Google Wallet
A maneira mais simples de usar a Carteira virtual do Google (nível 1) consiste em incorporar um botão em sua página que, quando clicado, redireciona o visitante para uma página de pagamento fornecida pelo Google.
Primeiro de tudo você precisa registrar uma conta do Google Merchant no URL:
https://checkout.google.com/sell
Você precisará fornecer ao Google suas informações bancárias. O Google irá atribuir-lhe um merchant_id
e um merchant_key
(não os confunda, mantenha-os em segredo).
Então você simplesmente precisa criar o seguinte código em sua visão:
{{from gluon.contrib.google_wallet import button}}
{{=button(merchant_id="123456789012345",
products=[dict(name="shoes",
quantity=1,
price=23.5,
currency='USD',
description="running shoes black")])}}
Quando um visitante clica no botão, o visitante será redirecionado para a página do Google, onde ele poderá pagar pelos itens. Aqui, os produtos são uma lista de produtos e cada produto é um dicionário de parâmetros que você deseja transmitir descrevendo seus itens (nome, quantidade, preço, moeda, descrição e outros itens opcionais que você pode encontrar descritos na documentação do Google Wallet).
Se você optar por usar esse mecanismo, convém gerar os valores passados para o botão programaticamente com base em seu inventário e no gráfico de compras do visitante.
Todas as informações sobre impostos e envio serão processadas no lado do Google. O mesmo para informações contábeis. Por padrão, seu aplicativo não é notificado de que a transação foi concluída, portanto, você terá que visitar o site do Google Merchant para ver quais produtos foram comprados e pagos e quais produtos você precisa enviar para seus compradores. O Google também enviará um e-mail com as informações.
Se você deseja uma integração mais precisa, é necessário usar a API de notificação do nível 2. Nesse caso, você pode passar mais informações para o Google e o Google chamará sua API para notificar sobre as compras. Isso permite que você mantenha informações contábeis em seu aplicativo, mas exige que você exponha serviços da web que podem conversar com a Google Wallet.
Este é um problema consideravelmente mais difícil, mas essa API já foi implementada e está disponível como plugin de
http://web2py.com/plugins/static/web2py.plugin.google_checkout.w2p
Você pode encontrar a documentação do plugin no próprio plugin.
Paypal
A integração do Paypal não é descrita aqui, mas você pode encontrar mais informações sobre isso neste recurso:
http://www.web2pyslices.com/main/slices/take_slice/9
Stripe.com
Esta é provavelmente uma das formas mais fáceis e flexíveis de aceitar pagamentos com cartão de crédito.
Você precisa se registrar no Stripe.com e esse é um processo muito fácil. Na verdade, o Stripe atribuirá a você uma chave de API para tentar antes mesmo de criar qualquer credencial.
Depois de ter a chave da API, você pode aceitar cartões de crédito com o seguinte código:
from gluon.contrib.stripe import Stripe
stripe = Stripe(api_key)
d = stripe.charge(amount=100,
currency='usd',
card_number='4242424242424242',
card_exp_month='5',
card_exp_year='2012',
card_cvc_check='123',
description='the usual black shoes')
if d.get('paid', False):
# payment accepted
elif:
# error is in d.get('error', 'unknown')
A resposta, d
é um dicionário que você pode explorar. O número do cartão usado no exemplo é uma sandbox e sempre será bem-sucedido. Cada transação é associada a um ID de transação armazenado em d['id']
.
O Stripe também permite que você verifique uma transação mais tarde:
d = Stripe(key).check(d['id'])
e reembolsar uma transação:
r = Stripe(key).refund(d['id'])
if r.get('refunded', False):
# refund was successful
elif:
# error is in d.get('error', 'unknown')
A listra torna muito fácil manter a contabilidade dentro de sua aplicação.
Todas as comunicações entre seu aplicativo e o Stripe passam por serviços da Web RESTful. O Stripe na verdade expõe ainda mais serviços e fornece um conjunto maior de API do Python. Você pode ler mais em seu site.
Authorize.Net
Outra maneira simples de aceitar cartões de crédito é usar o Authorize.Net. Como de costume, você precisa se registrar e obterá um login
e uma chave de transação ( transkey
. Depois de tê-los, funciona muito bem como o Stripe:
from gluon.contrib.AuthorizeNet import process
if process(creditcard='4427802641004797',
expiration="122012",
total=100.0, cvv='123', tax=None, invoice=None,
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
# payment was processed
else:
# payment was rejected
Se você tiver uma conta Authorize.Net válida, deverá substituir a sandbox login
e transkey
com os da sua conta, defina testmode=False
para ser executado na plataforma real em vez da caixa de proteção e usar as informações do cartão de crédito fornecidas pelo visitante.
E se process
retorna True
, o dinheiro foi transferido da conta do cartão de crédito do visitante para sua conta do Authorize.Net. invoice
é apenas uma string que você pode definir e será armazenada pelo Authorize.Net com essa transação para que você possa reconciliar os dados com as informações em seu aplicativo.
Aqui está um exemplo mais complexo de fluxo de trabalho, onde mais variáveis são expostas:
from gluon.contrib.AuthorizeNet import AIM
payment = AIM(login='cnpdev4289',
transkey='SR2P8g4jdEn7vFLQ',
testmod=True)
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows
payment.setParameter('x_cust_id', '1324') # customer ID
payment.setParameter('x_first_name', 'Agent')
payment.setParameter('x_last_name', 'Smith')
payment.setParameter('x_company', 'Test Company')
payment.setParameter('x_address', '1234 Main Street')
payment.setParameter('x_city', 'Townsville')
payment.setParameter('x_state', 'NJ')
payment.setParameter('x_zip', '12345')
payment.setParameter('x_country', 'US')
payment.setParameter('x_phone', '800-555-1234')
payment.setParameter('x_description', 'Test Transaction')
payment.setParameter('x_customer_ip', socket.gethostbyname(socket.gethostname()))
payment.setParameter('x_email', 'you@example.com')
payment.setParameter('x_email_customer', False)
payment.process()
if payment.isApproved():
print 'Response Code: ', payment.response.ResponseCode
print 'Response Text: ', payment.response.ResponseText
print 'Response: ', payment.getResultResponseFull()
print 'Transaction ID: ', payment.response.TransactionID
print 'CVV Result: ', payment.response.CVVResponse
print 'Approval Code: ', payment.response.AuthCode
print 'AVS Result: ', payment.response.AVSResponse
elif payment.isDeclined():
print 'Your credit card was declined by your bank'
elif payment.isError():
print 'It did not work'
print 'approved', payment.isApproved()
print 'declined', payment.isDeclined()
print 'error', payment.isError()
Observe que o código acima usa uma conta de teste fictícia. Você precisa se registrar no Authorize.Net (não é um serviço gratuito) e fornecer seu próprio login, transkey, testmode = True ou False para o construtor AIM.
API do Dropbox
O Dropbox é um serviço de armazenamento muito popular. Ele não apenas armazena seus arquivos, mas mantém o armazenamento em nuvem em sincronia com todas as suas máquinas. Ele permite que você crie grupos e conceda permissões de leitura/gravação às várias pastas para usuários individuais ou grupos. Também mantém o histórico de versões de todos os seus arquivos. Inclui uma pasta chamada "Público" e cada arquivo que você colocar lá terá seu próprio URL público. O Dropbox é uma ótima maneira de colaborar.
Você pode acessar a caixa de depósito facilmente registrando-se em
https://www.dropbox.com/developers
você vai ter um APP_KEY
e um APP_SECRET
. Depois de tê-los, você pode usar o Dropbox para autenticar seus usuários.
Crie um arquivo chamado "yourapp/private/dropbox.key" e nele escreva
<APP_KEY>:<APP_SECRET>:app_folder
Onde <APP_KEY>
e <APP_SECRET>
são sua chave e segredo. A terceira parte poderia ser app_folder
ou dropbox
ou auto
.
Instale o sdk do dropbox em "https://www.dropbox.com/developers/core/sdks/python".
Então em "models/db.py" faça:
from gluon.contrib.login_methods.dropbox_account import use_dropbox
use_dropbox(auth, filename='private/dropbox.key')
mydropbox = auth.settings.login_form
Isso permitirá que os usuários façam login no seu aplicativo usando as credenciais da caixa de depósito, e seu programa poderá enviar arquivos para a conta da caixa de depósito:
stream = open('localfile.txt', 'rb')
mydropbox.put('destfile.txt', stream)
baixar arquivos:
stream = mydropbox.get('destfile.txt')
open('localfile.txt', 'wb').write(read)
e obtenha listagens de diretórios:
contents = mydropbox.dir(path = '/')['contents']
Streaming de arquivos virtuais
É comum que invasores mal-intencionados digitalizem sites da Web em busca de vulnerabilidades. Eles usam scanners de segurança, como o Nessus, para explorar os sites-alvo de scripts conhecidos por terem vulnerabilidades. Uma análise dos registros do servidor da web de uma máquina digitalizada ou diretamente no banco de dados do Nessus revela que a maioria das vulnerabilidades conhecidas está em scripts PHP e scripts ASP. Como estamos executando o web2py, não temos essas vulnerabilidades, mas ainda seremos verificadas por eles. Isso é irritante, então gostamos de responder a essas varreduras de vulnerabilidades e fazer com que o invasor entenda que seu tempo está sendo desperdiçado.
Uma possibilidade é redirecionar todos os pedidos de .php, .asp e qualquer coisa suspeita para uma ação fictícia que responda ao ataque, mantendo o atacante ocupado por um grande período de tempo. Eventualmente, o atacante desistirá e não nos examinará novamente.
Esta receita requer duas partes.
Um aplicativo dedicado chamado jammer com um controlador "default.py" da seguinte forma:
class Jammer():
def read(self, n): return 'x'*n
def jam(): return response.stream(Jammer(), 40000)
Quando essa ação é chamada, ela responde com um fluxo de dados infinito cheio de "x" -es. 40000 caracteres de cada vez.
O segundo ingrediente é um arquivo "route.py" que redireciona qualquer pedido terminado em .php, .asp, etc. (em maiúsculas e minúsculas) para este controlador.
route_in=(
('.*.(php|PHP|asp|ASP|jsp|JSP)', 'jammer/default/jam'),
)
A primeira vez que você é atacado você pode incorrer em uma pequena sobrecarga, mas nossa experiência é que o mesmo atacante não tentará duas vezes.