Chapter 14: Autres possibilités
Autres possibilités
Mise à jour
Sur la page "site" de l'interface d'administration il y a un bouton "mettre à jour maintenant". Dans le cas où ce ne soit pas faisable ou que ça ne fonctionne pas (par exemple à cause d'un verrou sur un fichier), mettre à jour web2py manuellement est très facile.
Décompressez simplement la dernière version de web2py par dessus l'ancienne installation.
Ceci mettra à jour toutes les librairies en plus des applications admin, examples, welcome. Ceci créera également un nouveau fichier vide "NEWINSTALL". Au redémarrage, web2py supprimera le fichier vide et packagera l'application welcome en "welcome.w2p" qui sera utilisé comme nouvelle application de base.
web2py ne met à jour aucune fichier dans vos applications. Certaines parties importantes du framework ne sont pas dans les librairies, mais dans l'application Welcome. Les nouvelles applications hériteront de ces changement de framework, mais pas celles existantes. Vous avez besoin de copier ou rassembler des changements manuellement. Parfois, c'est nécessaire de profiter de nouvelle fonctionnalité, et parfois c'est nécessaire pour des raisons de compatibilité avec les nouvelles releases, particulièrement dans le cas où vous utilisez des fonctionnalités expérimentales. Le groupe Web2py sur Google Groups est un bon moyen de garder une trace des changements nécessaires. Certaines parties de l'application welcome à copier vers les applications existantes sont le contrôleur appadmin, les vues de haut-niveau incluant appadmin.html et les vues génériques, et les contenus du dossier statique qui contient la dernière version des fichiers javascript importants. Evidemment, vous avez besoin de rassembler vos changements (s'il y a). Conserver les backups et utiliser un système de contrôle de version est une bonne idée.
Comment distribuer vos applications en binaires
Il est possible de préparer votre application avec le binaire de distribution web2py et de les distribuer ensemble. La licence autorise ceci tant que vous êtes clair dans la licence de votre application que vous préparez avec web2py et que vous ajoutez un lien vers web2py.com
.
Nous expliquons ici comment le faire pour Windows :
- Crééz votre application comme d'habitude
- Utiliser admin, compile votre application en bytecode (un clic)
- Utiliser admin, package votre application compilée (un autre clic)
- Créez un dossier "myapp"
- Téléchargez une distribution binaire de web2py
- Décompressez la dans le répertoire "myapp" et démarrez-le (2 clics)
- Uploader l'application précédemment packagée et compilée en utilisant admin avec le nom "init" (un clic)
- Créez un fichier "myapp/start.bat" qui contient "web2py/web2py.exe"
- Créez un fichier "myapp/license" qui contient une licence pour votre application et assurez-vous qu'il soit indiqué "distribué avec une copie non modifiée de web2py depuis web2py.com"
- Zippez le dossier myapp en "myapp.zip"
- Distribuez et/ou vendez "myapp.zip"
Lorsque les utilisation dézipperont "myapp.zip" et cliqueront "run" ils verront votre application plutôt que l'application "welcome". Il n'y a pas de pré-requis côté utilisateur, même pas un Python pré-installé.
Pour les binaires Mac, le process est le même mais il n'y a pas besoin du fichier "bat".
WingIDE, Rad2Py, Eclipse et PyCharm
Vous pouvez utiliser web2py avec des IDEs tiers tels que WingIDE, Rad2Py, Eclipse et PyCharm.
PyCharm
PyCharm v3 Professional Edition a annoncé le support intégré pour web2py.
Comme pour la v3.0, PyCharm reconnaîtra les applications web2py appartenant à un répertoire parent web2py, et ceci activera le support web2py. Cependant, actuellement il ne reconnaîtra pas les répertoires web2py qui ont un nom différent (selon les développeurs, va être corrigé). Dans ce cas, démarrez un projet PyCharm en ouvrant le répertoire d'installation web2py, et naviguez ensuire à travers le répertoire des applications. L'intégration au git PyCharm fait face à cela ; il supporte de multiple dépôts fit au sein de la structure d'un seul répertoire de projet.
Le lanceur par défaut pour un projet web2py démarre avec web2py.py et lance ensuite le server intégré rocket. Vous pouvez aussi lancer le débugueur PyCharm comme toute autre session Python. Cependant, ceci semble nécessiter la suppression des déclarations
from gluon.debug import `.
Notez que le support web2py n'est pas inclus dans la version opensource de PyCharm 3. Dans ce cas, merci de considérer les notes ci-après.
#### WingIDE
Voici une capture d'écran de l'utilisation de web2py avec WingIDE :
[[image https://web2py.com/books/default/image/38/wingide.png center 480px]]
#### Utiliser les IDEs standard avec web2py
Le problème général avec ces IDEs (sauf ceux qui supportent web2py) est qu'ils ne comprennent pas le contexte dans lesquels les modèles et les contrôleurs sont exécutés et ainsi l'autocomplétion ne fonctionne pas directement.
Pour rendre l'autocomplétion stable, le principal contournement consiste en l'édition des modèles et des contrôleurs et ajouter le code suivant :
if False: from gluon import * request = current.request response = current.response session = current.session cache = current.cache T = current.T :code
Le bloc d'import ne change pas la logique puisqu'il n'est jamais exécuté mais il force l'IDE à le parser et à comprendre d'où proviennent les objets de l'espace de nom global (le module
gluon) rendant ainsi l'autocomplétion fonctionnelle.
Si vous vous basez sur des variables dans vos modèles (telles que les définitions de base de données) vous pouvez considérer l'ajout à la liste comme ceci :
from db import *
:code
Vous pouvez également considérer l'import de tous les modèles.
if False: from gluon import * from db import * #repeat for all models from menu import * :code
De même, si vous utilisez Eclipse avec PyDev vous devriez ajouter le dossier web2py au chemin système de python (dans les préférence PyDev pour l'interpréteur Python).
Dans certaines versions de PyDev, il a été possible d'utiliser le support de debug intégré à Eclipse en lançant web2py.py.
Il est probablement sage de supprimer l'import du module de debug gluon. Aussi, pour faire ceci vous devriez du projet pydev le répertoire web2py, et non votre application spécifique.
L'intégration du git PyDev fait face à cela ; il supporte de multiples dépôts git à l'intérieur de la structure d'un seul répertoire de projet.
### SQLDesigner
Il y a un logiciel appelé SQLDesigner qui permet de construire des modèles web2py visuellement et ensuite générer le code correspondant. Voici une capture.
[[image https://web2py.com/books/default/image/38/designer.png center 480px]]
La version de SQLDesigner qui fonctionne avec web2py peut être trouvé ici :
https://github.com/elcio/visualdal
### Publier un dossier
Considérons le problème de partage d'un dossier (et de sous-dossiers) sur le web. web2py rend cela très facile. Vous avez juste besoin d'un contrôleur tel que :
from gluon.tools import Expose def myfolder(): return dict(files=Expose('/path/to/myfolder')) :code
qui peut renvoyer une vue avec
{{=files}}. Il créera une interface pour voir les fichiers et dossiers, ainsi que la possibilité de naviguer dans la structure. Les images auront une prévisualisation.
Le préfixe du chemin "/path/to/myfolder" sera caché aux visiteurs. Par exemple, un fichier appelé "/path/to/myfolder/a/b.txt" sera remplacé par "base/a/b.txt". Le préfixe "base" peut être spécifié en utilisant l'argument
basename de la fonction Expose. Utiliser l'argument
extensions peut spécifier une liste d'extensions de fichiers à lister, les autres fichiers seront cachés. Par exemple :
def myfolder(): return dict(files=Expose('/path/to/myfolder',basename='.', extensions=['.py', '.jpg'])) :code
Les fichiers et dossiers qui contiennent le mot "private" dans le chemin ou qui ont un fichier qui commence avec "." ou terminant par "~" seront toujours cachés.
### Test fonctionnel
web2py est fourni avec un module
gluon.contrib.webclient qui permet le test fonctionnel d'applications web2py locales et distantes. En fait, ce module n'est pas spécifique à web2py et peut être utilisé pour des tests et interagir (en programmation) avec toute autre application web, bien qu'il soit prévu pour comprendre les sessions et postbacks web2py.
Voici un exemple d'usage. Le programm ci-après créé un client, se connecte à l'action "index" afin d'établir une session, enregistre un nouvel utilisateur, puis se déconnecte, et se re-connecte en utilisant les nouveaux identifiants créés :
from gluon.contrib.webclient import WebClientclient = 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) :code
Le constructeur WebClient prend un préfixe URL comme argument. Dans l'exemple qui est "http://127.0.0.1:8000py./welcome/default/", il n'effectue aucun IO réseau. L'argument
postbacks est par défaut à
True et indique au client comment gérer les postbacks web2py.
L'objet WebClient,
client, a seulement deux méthodes :
get et
post. Le premier argument est toujours un postfix URL.
L'URL complète pour le GET de requête POST est construit simplement en concaténant le préfixe et le postfix. Le but de ceci est de rendre la syntaxe moins verbeuse pour les longs échanges entre le client et le serveur.
data est un paramètre spécifique de requête POST et contient un dictionnaire des données postées. Les formulaires Web2py ont un champ caché
_formname et sa valeur doit être fournie à moins qu'il n'y ait qu'un seul formulaire sur la page. Les formulaires Web2py contiennent également un champ caché
_formkey qui est prévu pour éviter les attaques CSRF. Ceci est géré automatiquement par WebClient.
Aussi bien
client.get que
client.post acceptent les arguments extra suivants :
-
headers: un dictionnaire des en-têtes optionnelles HTTP.
-
cookies: un dictionnaire des cookies optionnels HTTP.
-
auth: un dictionnaire des paramètres devant être passés à
urllib2.HTTPBasicAuthHandler().add_password(**auth) afin d'effectuer une authentification basique. Pour plus d'informations à ce sujet, nous vous renvoyons vers la documentation officielle Python pour le module urllib2.
L'objet
client dans l'exemple porte sur la conversation avec le serveur spécifié dans le constructeur en faisant des requêtes GET et POST. Il gère automatiquement tous les cookies et les leur renvoie pour maintenir les sessions. Si il détecte qu'un nouveau cookie de session est préparé alors qu'un existant est déjà présent, il l'interprète alors comme une session cassée et lève une exception. Si le serveur retourne une erreur HTTP, il lève une exception. Si le serveur retourne une erreur HTTP qui contient le ticket web2py, il retourne une exception RuntimeError contenant le code de ticket.
L'objet
client maintient un log des requêtes dans
client.history et un état associé avec sa dernière requête réussie. L'état consiste en :
-
client.status: le code de statut retourné
-
client.text: le contenu de la page
-
client.headers: un dictionnaire des en-têtes parsées
-
client.cookies: un dictionnaire des cookies parsés
-
client.sessions: un dictionnaire des sessions web2py dans la forme
{appname: session_id}.
-
client.forms: un dictionnaire des formulaires détectés dans le
client.text. Le dictionnaire a la forme
{_formname,_formkey}.
L'objet WebClient n'effectue aucun parsing du
client.text retourné par le serveur mais ceci peut être accompli facilement avec de nombreux modules tiers tels que BeautifulSoup. Par exemple, voici un exemple de code qui trouve tous les liens dans une page téléchargée par le client les les vérifie tous :
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
### Construire un web2py minimaliste
Parfois, nous avons besoin de déployer web2py dans un serveur avec une très petite empreinte mémoire. Dans ce cas, l'on souhaite réduire web2py à son strict minimum.
Un moyen facile de le faire est le suivant :
- Sur une machine de production, installez le web2py complet depuis les sources
- De l'intérieur du répertoire web2py principal, lancez
python scripts/make_min_web2py.py /path/to/minweb2py
- Copiez maintenant sous "/path/to/minweb2py/applications" les applications que vous souhaitez déployer
- Déployez "/path/to/minweb2py" vers le serveur à petite empreinte
Le script "make_min_web2py.py" construit une distribution minimaliste de web2py qui n'inclut pas :
- admin
- examples
- welcome
- scripts
- les modules contrib rarement utilisés
Il inclut une application "welcome" qui consiste en un simple fichier pour permettre le déploiement de test.
Regardez dans ce script. En haut, il contient une liste détaillée de ce qui est inclus et ce qui doit être ignoré. Vous pouvez facilement le modifier et l'adapter à vos besoins.
### Récupérer une URL externe
fetch:inxx
Python inclut la librairie
urllib pour récupérer des urls :
import urllib page = urllib.urlopen('http://www.web2py.com').read() :code
API:inxx
Ceci est souvent correct, mais le module
urllib ne fonctionne pas sur le Google App Engine. Google fournit une API différente pour télécharger des URLs qui fonctionne sur GAE uniquement. Afin de rendre votre code portable, web2py inclut une fonction
fetch qui fonction sur GAE ainsi que sur les autres installations Python :
from gluon.tools import fetch page = fetch('http://www.web2py.com') :code
### Affichage des dates
prettydate:inxx
Il est souvent utile de représenter un datetime non pas comme "2009-07-25 14:34:56" mais plutôt comme "il y a un an". web2py fournit une fonction utilitaire pour cela :
import datetime d = datetime.datetime(2009,7,25,14,34,56) from gluon.tools import prettydate pretty_d = prettydate(d,T) :code
Le second argument (T) doit être passé pour autoriser l'internationalisation de la sortie.
### Geocodage
geocode:inxx
Si vous avez besoin de convertir une adresse (par exemple : "243 S Wabash Ave, Chicago, IL, USA") en coordonnées géographiques (latitude et longitude), web2py fournit une fonction pour cela.
from gluon.tools import geocode address = '243 S Wabash Ave, Chicago, IL, USA' (latitude, longitude) = geocode(address) :code
La fonction
geocode nécessite une connexion réseau et se connecte au service de géocodage Google. La fonction retourne
(0,0) en cas d'échec. Notez que le service de géocoding Google limite le nombre de requêtes, vous devriez donc vérifier leur service agreement. La fonction
geocode est basée sur la fonction
fetch et fonctionne ainsi sur GAE.
### Pagination
pagination:inxx
Cette possibilité est un moyen utile de minimiser les accès à la base de données dans le cas de pagination, e.g., lorsque vous avez besoin d'afficher une liste de lignes depuis une base mais que vous voulez distribuer les lignes sur de multiples pages.
Commencez par créer une application **primes** qui stocke les 1000 premiers nombres premiers dans une base de données.
Voici le modèle
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 :code
Créez maintenant une action
list_items dans le contrôleur "default.py" qui lit comme ceci :
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):code
Notez que ce code sélectionne un objet supplémentaire que nécessaire, 20+1. L'élément additionnel indique la vue dnas le cas où il y ait une page suivante.
Voici la vue "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}} :code
De cette manière, nous avons obtenu la pagination avec un simple select par action, et qu'un select sélectionne uniquement une ligne de plus que ce que nous avons besoin.
### httpserver.log et le Format de Fichier de Log
httpserver.log:inxx
Le serveur web web2py log toutes les requêtes vers un fichier appelé :
httpserver.log
:code
dans le répertoire racine de web2py. Un nom de fichier et une localisation alternatifs peuvent être spécifiés via les options en ligne de commande de web2py.
Les nouvelles entrées sont ajoutées à la fin du fichier chaque fois qu'une requête est faite. Chaque line ressemble à :
127.0.0.1, 2008-01-12 10:41:20, GET, /admin/default/site, HTTP/1.1, 200, 0.270000
:code
Le format est :
ip, timestamp, method, path, protocol, status, time_taken :code
Où
- ip est l'adresse IP du client qui a fait la requête
- timestamp est la date et le temps de la requête en format ISO 8601, YYYY-MM-DDT HH:MM:SS
- method est soit GET soit POST
- path est le chemin demandé par le client
- protocol est le protocole HTTP utilisé pour envoyer au client, habituellement HTTP/1.1
- status est l'un des codes de statut HTTP
status:cite
- time_taken est la quantité de temps que le serveur prend pour procéder à la requête, en secondes, n'incluant pas le temps d'upload/download.
Dans le dépôt des appliances
appliances:cite , vous trouverez une appliace pour l'analyse de log.
Ce système de logging est désactivé par défaut lorsque le mod_wsgi est utilisé puisqu'il reviendrait au même qu'utiliser les logs Apache.
### Peupler une base de données avec des données imaginaires
Pour des raisons de test, il est pratique de pouvoir peupler les tables d'une base de données avec des fausses données. web2py inclut un classificateur Bayesian déjà formé pour générer des fausses données avec du texte lisible pour cet usage.
Voici le moyen le plus simple de l'utiliser :
from gluon.contrib.populate import populate populate(db.mytable,100)
:code
Ceci insèrera 100 faux enregistrements dans db.mytable. Il essaiera de le faire intelligemment en générant des textes courts pour des champs string, des textes longs pour des champs text, des entiers, des doubles, des dates, des datetimes, des times, des booléens, etc.... pour les champs correspondants. Il essaiera de respecter les pré-requis imposés par les validateurs. Pour les champs contenant le mot "name" il essaiera de générer des faux noms. Pour les champs de référence il génèrera des références valides.
Si vous avez deux tables (A et B) où B référence A, assurez-vous de peupler A en premier et B en deuxième.
Puisque le peuplement est fait dans une transaction, n'essayez pas de peupler trop d'enregistrements en une fois, notamment si des références sont en jeu. A la place, peuplez 100 enregistrements en une fois, commitez, puis recommencez.
for i in range(10): populate(db.mytable,100) db.commit()
:code
Vous pouvez utiliser le classificateur Bauesian pour apprendre certains textes et générer du faux texte qui se ressemble mais ne devrait pas avoir de sens :
from gluon.contrib.populate import Learner, IUP ell=Learner() ell.learn('some very long input text ...') print ell.generate(1000,prefix=None) :code
### Accepter les paiements par carte de crédit
Google Wallet:inxx
Paypal:inxx
Stripe.com:inxx
Authorize.net:inxx
DowCommerce:inxx
Il y a de multiples façons d'accepter les paiements par carte de crédit en ligne. web2py fournit des APIs spécifiques pour les plus pratiques et les plus populaires :
- Google Wallet
googlewallet:cite
- PayPal
paypal:cite
- Stripe.com
stripe:cite
- Authorize.net
authorizenet:cite
- DowCommerece
dowcommerce:cite
Les deux premiers mécanismes ci-dessus délèguent le processus d'authentification du payeur vers un service externe. Bien que ce soit la meilleure solution niveau sécurité (votr eapplication ne gère aucune information de carte de crédit) il rend le processus lourd (l'utilisateur doit se loguer 2 fois ; par exemple, une fois pour votre application, et une fois avec Google) et n'autorise pas votre application à gérer les paiements récurrents de manière automatique.
Il y a des fois lorsque vous avez besoin de plus de contrôle et où vous préférez générer vous-même votre formulaire pour les informations de carte de crédit et ensuite développer vos requêtes pour procéder au transfert d'argent entre la carte de crédit et votre compte.
Pour cette raison, web2py fournit une intégration prête avec Stripe, Authorize.net (le module qui a été développé par John Conde est légèrement modifié) et DowCommerce. Stripe est le plus simple à utiliser et aussi le moins cher pour les faibles volumes de transactions (ils ne chargent pas de coùut fixe mais environ 3% par transaction). Authorize.net est meilleur pour les gros volumes (il a des coûts fixes annuels mais un coût par transaction plus faible).
Gardez à l'esprit que dans le cas de Stripe et Authorize.net votre programme acceptera les informations de cartes de crédit. Vous ne devez en aucun cas stocker ces informations et nous vous déconseillons de le faire car des pré-requis légaux sont engendrés (vérifiez avec Visa et MasterCard), mais il y a des fois où vous pourriez vouloir stocker les informations pour des paiements récurrents ou pour reproduire le bouton de paiement en un clic d'Amazon.
#### Google Wallet
Le moyen le plus simple d'utiliser Google Wallet (Level 1) consistet à embarquer un bouton sur votre page, qui, lorsqu'il est cliqué, redirige votre visiteur vers une page de paiement fournie par Google.
Tout d'abord, vous avez besoin d'enregistrer un compte Google Merchant à l'URL :
https://checkout.google.com/sell
Vous aurez besoin de fournir à Google vos informations bancaires. Google vous assignera un
merchant_id et un
merchant_key (ne les confondez pas, gardez-les secrets).
Ensuite vous avez simplement besoin de créer le code suivant dans votre vue :
{{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")])}}
Lorsqu'un visiteur clique sur le bouton, le visisteur sera redirigé vers la page Google où il/elle peut payer pour les objets. Ici, les produits sont une liste de produits et chaque produit un dictionnaire de paramètres que vous souhaitez passer pour décrire vos objets (nom, quantité, prix, devise, description, et tout autre champ optionnel que vous pouvez trouver dans la documentation Google Wallet).
Si vous choisissez d'utiliser ce mécanisme, vous pouvez vouloir générer les valeurs passées au bouton automatiquement en se basant sur votre inventaire et le panier d'achat du visiteur.
Toutes les taxes et les informations d'envoi seront gérées côté Google. De même pour les informations de compte. Par défaut, votre application n'est pas notifiée que la transaction a été complétée et vous aurez alors besoin de vous rendre sur votre site Google Merchant pour connaître les produits achetés et payés, et quels sont les produits que vous devez livrer aux acheteurs ici. Google enverra également un mail avec les informations.
Si vous voulez un intégration plus proche, vous devez utiliser l'API de notification niveau 2. Dans ce cas, vous pouvez passer plus d'informations à Google et Google appellera votre API pour notifier des achats et des paiements. Ceci vous permet de conserver les informations de compte dans votre application mais requiert que vous exposiez des web services qui puissent parler avec Google Wallet.
C'est un problème considérablement plus difficile mais une telle API a déjà été implémentée et est disponible sous forme de plugin
http://web2py.com/plugins/static/web2py.plugin.google_checkout.w2p
Vous pouvez trouver la documentation du plugin dans le plugin lui-même.
#### Paypal
L'intégration Paypal n'est pas décrite ici mais vous pouvez trouver plus d'information à ce sujet ici :
http://www.web2pyslices.com/main/slices/take_slice/9
#### Stripe.com
C'est probablement l'un des moyens les plus facile et flexible d'accepter les paiements par carte de crédit.
Vous avez besoin de vous enregistrer sur Stripe.com et c'est un processus simple, en fait Stripe vous assignera une clé API pour essayer même avant que vous ayez créé des identifiants.
Une fois que vous avez la clé API, vous pouvez accepter des cartes de crédit avec le code suivant :
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')
La réponse,
d, est un dictionnaire que vous pouvez explorer vous-même. Le numéro de carte utilisé dans l'exemple est un bac à sable et fonctionnera toujours. Chaque transation est associée à un id de transaction stocké dans
d['id'].
Stripe permet également de vérifier une transaction plus tard :
d = Stripe(key).check(d['id'])
et de reconstruire une transaction :
r = Stripe(key).refund(d['id']) if r.get('refunded',False):
refund was successful
elif:
error is in d.get('error','unknown')
Stripe rend vraiment simple la conservation des comptes au sein de votre application.
Toutes les communications entre votre application et Stripe fonctionnent sur des web services RESTful. Strip expose en fait encore plus de services et fournit un large ensemble d'API Python. Vous pouvez en lire plus sur leur site web.
#### Authorize.Net
Un autre moyen simple d'accepter les cartes de crédit est d'utiliser Authorize.Net. Comme d'habitude vous avez besoin de vous enregistrer et vous obtiendrez un
login et une clé de transaction (
transkey). Une fois que vous les avez, le fonctionnement est très similaire à celui de 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
:code
Si vous avez un compte Authorize.Net, vous devriez remplacer le bac à sable
login et le
transkey avec ceux de votre compte, définir
testmode=False pour démarrer sur la plateforme réelle au lieu du bac à sable, et utiliser les informations de carte de crédit fournies par le visiteur.
Si
process retourne
True, l'argent a été transféré du compte de la carte de crédit du visiteur vers votre compte Authorize.Net.
invoice est juste une chaîne que vous pouvez définir et qui sera stockée par Authorize.Net avec cette transaction afin que vous puissiez recroiser les données avec les informations de votre applications.
Voici un exemple plus complexe de workflow lorsque plus de variables sont exposées :
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() :code
Notez que le code ci-dessus utilise des faux données de compte. Vous aurez besoin de vous enregistrer auprès d'Authorize.Net (ce n'est pas un service gratuit) et fournir votre propre login, transkey testmode=True ou False au constructeur AIM.
### API Dropbox
Dropbox.com:inxx
Dropbox est service de stockage très populaire. Il ne stocke pas uniquement vos fichiers mais il conserver votre stockage dans le cloud en le synchronisant avec toutes vos machines. Il vous permet de créer des groupes et donner des permissions de lecture/écriture aux différents dossiers des utilisateurs individuels ou des groupes. Il conserver également un historique de version de tous vos fichiers. Il inclut un dossier appelé "Public" et chaque fichier que vous mettez dedans aura sa propre URL publique. Dropbox est un moyen simple de collaborer.
Vous pouvez facilement accéder à dropbox en vous enregistrant sur
https://www.dropbox.com/developers
vous obtiendrez une
APP_KEY et une
APP_SECRET. Une fois que vous les avez vous pouvez utiliser Dropbox pour authentifier vos utilisateurs.
Créez un fichier appelé "yourapp/private/dropbox.key" et écrivez dedans
<APP_KEY>:<APP_SECRET>:app_folder où
<APP_KEY> et
<APP_SECRET> sont votre clé et secret.
Ensuite, dans "models/db.py" faites :
from gluon.contrib.login_methods.dropbox_account import use_dropbox use_janrain(auth,filename='private/dropbox.key') mydropbox = auth.settings.login_form
Ceci permettra aux utilisateurs de s'identifier dans votre application en utilisant les identifiants dropbox, et votre programme sera capable d'uploader des fichiers dans votre compte dropbox :
stream = open('localfile.txt','rb') mydropbox.put('destfile.txt',stream)
télécharger des fichiers :
stream = mydropbox.get('destfile.txt') open('localfile.txt','wb').write(read)
et obtenir les listings de répertoire :
contents = mydropbox.dir(path = '/')['contents']
### API Twitter
Voici ici quelques exemples rapides pour récupérer/poster des tweets. Aucune librairie tierce n'est requise, puisque Twitter utiliser des APIs RESTful.
Voici un exemple de comment poster un tweet :
def post_tweet(username,password,message): import urllib, urllib2, base64 import gluon.contrib.simplejson as sj args= urllib.urlencode([('status',message)]) headers={} headers['Authorization'] = 'Basic '+base64.b64encode( username+':'+password) req = urllib2.Request( 'http://twitter.com/statuses/update.json', args, headers) return sj.loads(urllib2.urlopen(req).read())
:code
Voici un exemple de comment recevoir des tweets :
def get_tweets(): user='web2py' import urllib import gluon.contrib.simplejson as sj page = urllib.urlopen('http://twitter.com/%s?format=json' % user).read() tweets=XML(sj.loads(page)['#timeline']) return dict(tweets=tweets) :code
Pour plus d'opérations complexes, vous pouvez vous référer à la documentation des API Twitter.
### Streaming de fichiers virtuels
streaming:inxx
Il est commun pour des attaqueurs malicieux de scanner les sites web pour des vulnérabilités. Ils utilisent des scanners de sécurité tels que Nessus pour explorer la cible des sites web pour des scripts qui sont connus pour avoir des vulnérabilités. Une analyse des logs de serveur web depuis une machine scannée ou directement dans la base de données Nessus révèle que la plupart des vulnérabilités connues sont en scripts PHP et en scripts ASP. Tant que nous fonctionnons sur web2py, nous n'avons pas ces vulnérabilités, mais nous serons toujours scannés pour. C'est ennuyant, et nous aimerions donc répondre à ces scans de vulnérabilité et faire comprendre à l'attaquant que leur temps va être perdu.
Une possibilité est de rediriger toutes les requêtes pour .php, .asp et toute autre requête suspicieuse vers une fausse action qui répondra à l'attaque en conservant l'attaquant occupé pour un long moment. L'attaquant abandonnera éventuellement et ne rescannera pas.
Cette solution nécessite deux parties.
Une application dédiée appelée **jammer** avec un contrôleur "default.py" tel que :
class Jammer(): def read(self,n): return 'x'*n def jam(): return response.stream(Jammer(),40000)
:code
Lorsque cette action est appelée, elle répond avec un flux de données infini rempli de "x". 40000 caractères à chaque fois.
Le deuxième ingrédient est un fichier "route.py" qui redirige toutes les requêtes finissant en .php, .asp, etc. (les deux en majuscule et minuscule) vers ce contrôleur.
route_in=( ('.*.(php|PHP|asp|ASP|jsp|JSP)','jammer/default/jam'), ) ``:code
La première fois où vous recevrez une attaque, vous pouvez ressentir un léger overhead, mais notre expérience est que le même attaquant n'essaiera pas 2 fois.