Chapter 14: Другие рецепты

Другие рецепты

Модернизация

upgrades

На странице "сайт" административного интерфейса есть кнопка "обновить сейчас". В случае, если это не представляется возможным или не работает (например, из-за блокировки файлов обновлений), обновить web2py вручную очень легко.

Просто разархивируйте последнюю версию web2py поверх старой установки.

Это позволит обновить все библиотеки, а также приложения admin, examples, welcome. Это также создаст новый пустой файл "NEWINSTALL". После перезагрузки, web2py удалит пустой файл и пакет приложения welcome в "welcome.w2p" который будет использоваться в качестве нового скаффолдинг-приложения.

web2py не обновляет любой файл в приложениях. Некоторые важные части фреймворка не являются частью библиотек, а частью Welcome приложения. Новые приложения унаследуют эти изменения фреймворка, но не существующие приложения. Вы должны сделать копию или слить изменения вручную. Иногда это необходимо, чтобы воспользоваться новыми функциональными возможностями, а иногда это необходимо для совместимости с новыми выпусками, особенно, если вы используете экспериментальные функции. Web2py группа в группах Google является хорошим способом для отслеживания необходимых изменений. Отдельные части welcome приложения копируются в существующие приложения, такие как appadmin контроллер, представления верхнего уровня включая appadmin.html и общие представления, и содержимое статической папки, которая содержит последнюю версию важных файлов JavaScript. Очевидно, что вам необходимо объединить ваши изменения (если таковые имеются). Сохранение резервных копий или использование системы управления версиями является здравой идеей.

Как распространять свои приложения в бинарных файлах

Можно связать приложение с бинарным дистрибутивом web2py и распространять их вместе. Лицензия позволяет это, при условии, что вы четко указываете в лицензии вашего приложения о связи с web2py и добавили ссылку на web2py.com.

Здесь мы объясним, как это сделать для Windows:

  • Создайте приложение, как обычно
  • Используя admin, скомпилируйте в байткод ваше приложение (один клик)
  • Используя admin, упакуйте ваше скомпилированное приложение (еще один клик)
  • Создайте папку "myapp"
  • Скачайте бинарный дистрибутив web2py для windows
  • Распакуйте его в папку "myapp" и запустите его (два клика)
  • Скачайте используя admin ранее упакованное и скомпилированое приложение с именем "init" (один клик)
  • Создайте файл "myapp/start.bat" который содержит "web2py/web2py.exe"
  • Создайте файл "myapp/license" который содержит лицензию для вашего приложения и убедитесь, что в нем говорится, что приложение "распространяется с неизмененной копией web2py от web2py.com"
  • Заархивируйте папку myapp в файл "myapp.zip"
  • Распространяйте и/или продавайте "myapp.zip"

Когда пользователи разархивируют "myapp.zip" и нажмут "run" они увидят ваше приложение вместо приложения "welcome". Здесь нет никаких требований со стороны пользователя, даже не требуется предварительно установленный Python.

Для двоичных файлов Mac процесс такой же, но нет никакой необходимости в файле "bat".

Разработка через интегрированные среды разработки (IDEs): WingIDE, Rad2Py, Eclipse и PyCharm

WingIDE
Eclipse
Rad2Py

Вы можете использовать web2py с интегрированными средами разработки (IDEs) от третей стороны, такие как WingIDE, Rad2Py, Eclipse и PyCharm.

PyCharm

PyCharm

PyCharm v3 Professional Edition включает встроенную поддержку для web2py.

По состоянию на v3.0, PyCharm распознает web2py приложения, принадлежащие родительскому каталогу web2py, и активирует поддержку web2py. Поддержка означает, что библиотека web2py добавляется к проекту.

Запустить проект PyCharm, открыв каталог установки web2py, а затем перемещайтесь по каталогу приложений.

Интегрированный в PyCharm Git отлично справляется с этим; он поддерживает несколько репозиториев Git внутри структуры каталогов одного проекта. Держите каждое приложение в своем собственном репозиторий Git для легкого развертывания.

Профессиональная версия по умолчанию включает в себя загрузчик проекта web2py, который запускает web2py.py и поэтому запускает встроенный rocket сервер.

Подсказки PyCharm по отладке

Вы можете заскочить в PyCharm отладчик как и в любой другой сессии Python. Это означает, что вы можете начать отладку web2py.py скрипта, который будет запускать сервер rocket с подключенным к этому процессу PyCharm. Используйте ваш браузер, чтобы активировать интересующую вас функцию контроллера.

При достижении точки останова во время запроса, вы попадете в отладчик PyCharm.

Тем не менее, это требует удаления объявлений from gluon.debug import dbg.

Pycharm: Отладка модуля в контексте web2py

Это может быть удобно для непосредственной отладки модуля с тестовым кодом в изоляции от остальной части web2py. Вы можете сделать стандартную конфигурацию запуска/отладки в PyCharm для запуска файла модуля как автономного питон скрипта, поместив ваш тестируемый код в

1
if __name__ == "__main__":

но тогда вы не получите модели web2py и соединения с базой данных.

Вы можете сделать фиктивные контроллеры и точки останова в вашем модуль и затем запускать фиктивные функции контроллера с помощью браузера, как описано выше, но есть более удобный вариант:

Представьте, что у вас есть этот блок тестирования в модуле module_1.py:

1
2
if __name__ == "__main__":
    ... код, который тестирует какие то вещи

и в то же время, вы хотите чтобы соединения с базой данных и модели были доступны так же, как это делается обычно в web2py.

Используя параметры командной строки web2py, вы можете создать конфигурацию PyCharm для запуска/отладки. Сделайте скрипт: web2py.py Сделайте параметры скрипта: -S <your_app_name> -M -R /path/to/your_module/module_1.py`:code

Это запустит модели web2py, а затем загрузить модуль, который затем запустит код в контексте __main__ по аналогии с запуском приложения web2py. Данные параметры командной строки описаны в главе 4.

WingIDE

Вот скриншот использование web2py с WingIDE:

image

Использование IDEs общего назначения с web2py

Общая проблема с этими IDEs (за исключением тех, которые поддерживают web2py) является то, что они не понимают контекст, в котором модели и контроллеры выполнены. и поэтому автозавершения не работают из коробки.

Для того, чтобы автозавершения работали, основной трюк заключается в редактировании моделей и контроллеров с добавлением следующего кода:

1
2
3
4
5
6
7
if False:
    from gluon import *
    request = current.request
    response = current.response
    session = current.session
    cache = current.cache
    T = current.T

Импортируемый блок не меняет логику, поскольку он никогда не выполняется, но это заставляет IDE разобрать его и понять, откуда приходят объекты в глобальное пространство имен (модуля gluon), таким образом заставляя работать автозавершения.

Если вы полагаетесь на переменные в моделях (например, определения базы данных) вы можете рассмотреть вопрос о включении в список вроде этого:

1
   from db import *

Можно также рассмотреть импорт всех моделей.

1
2
3
4
if False:  
    from gluon import *
    from db import *  #повторить для всех моделей
    from menu import *

Так же, при использовании Eclipse с PyDev вы должны добавить папку web2py в системный путь к Python (PyDev предпочитает интерпретатор Python). В некоторых версиях PyDev, стало возможным использование поддержки при отладке внутри Eclipse, запустив web2py.py. Возможно целесообразнее удалить импорт модуля отладки gluon. Кроме того, чтобы сделать это вы должны создать web2py каталог в проекте PyDev, а не конкретного приложения.

Интегрированный в PyDev Git отлично справляется с этим; он поддерживает несколько Git репозиториев внутри структуры каталогов одного проекта.

SQLDesigner

Существует программное обеспечение под названием SQL Designer, которое позволяет строить модели web2py визуально, а затем генерировать соответствующий код. Вот скриншот.

image

Версию SQLDesigner, которая работает с web2py можно найти здесь:

https://github.com/elcio/visualdal

Публикация папки

Рассмотрим проблему общего доступа к папке (и вложенным папкам) в Интернете. web2py делает это очень легко. Вам просто нужен контроллер вроде этого:

1
2
3
from gluon.tools import Expose
def myfolder():
    return dict(files=Expose('/path/to/myfolder'))

который вы можете визуализировать в представлении с {{=files}}. Это создаст интерфейс для просмотра файлов и папок, а также позволит перемещаться по структуре дерева. Изображения будут иметь предварительный просмотр.

Приставка пути "/path/to/myfolder" будет скрыта для посетителей. Например, файл с именем "/path/to/myfolder/a/b.txt" будет заменен "base/a/b.txt". Приставка "base" может быть определена с помощью аргумент basename функции Expose. Используя аргумент extensions можно указать список расширений файлов, которые будут перечислены, другие файлы будут скрыты. Например:

1
2
3
def myfolder():
    return dict(files=Expose('/path/to/myfolder',basename='.',
                             extensions=['.py', '.jpg']))

Файлы и папки, которые содержат слово "private" в пути или имеются файлы, которые начинаются с "." или заканчиваются на "~" всегда скрыты.

Функциональное тестирование

web2py поставляется с модулем gluon.contrib.webclient который позволяет выполнить функциональное тестирование локальных и удаленных приложений web2py. На самом деле, этот модуль не является специальным модулем web2py, и он может быть использован для тестирования и взаимодействия программно с любым веб-приложением, но он предназначен для понимания web2py сессий и web2py постбэков.

Здесь приведен пример использования. Программа ниже создает клиента, подключается к действию "index" для того, чтобы установить сессию, регистрирует нового пользователя, затем выходит и авторизируется снова, используя вновь созданные учетные данные:

 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
from gluon.contrib.webclient import WebClient

client = WebClient('http://127.0.0.1:8000/welcome/default/',
                   postbacks=True)

client.get('index')
# Регистрация
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)

# Выход из системы
client.get('user/logout')

# Повторная авторизация
data = dict(email='homer@web2py.com',
            password='test',
            _formname='login')
client.post('user/login', data=data)

# проверка успешного прохождения регистрации и авторизации
client.get('index')
assert('Welcome Homer' in client.text)

Конструктор WebClient принимает URL префикс в качестве аргумента. В данном примере "http://127.0.0.1:8000/welcome/default/". Он не выполняет каких-либо сетевых IO(вводов/выводов). Аргумент postbacks по умолчанию True и сообщает клиенту, как обращаться с web2py постбэками.

Объект WebClient, client, имеет только два метода: get и post. Первый аргумент всегда постфикс URL. Полный URL для GET и POST запросов строится простой конкатенацией префикса и постфикса. Целью этого является сделать синтаксис менее многословным для длительных разговоров между клиентом и сервером.

data является специфическим параметром запроса POST и содержит словарь данных, которые будут размещены. Web2py формы имеют скрытое поле _formname и его значение должно быть обеспечено, если не будет единой формы на странице. Web2py формы также содержат скрытое поле _formkey, которое предназначено для предотвращения CSRF атак. Оно обрабатывается автоматически WebClient.

Оба client.get и client.post принимают следующие дополнительные аргументы:

  • headers: словарь дополнительных заголовков HTTP.
  • cookies: словарь дополнительных HTTP-куки.
  • auth: словарь параметров для передачи в urllib2.HTTPBasicAuthHandler().add_password(**auth) для выполнения базовой аутентификации. Для получения дополнительной информации об этом, обратитесь к Python документации для модуля urllib2.

Объект client в примере ведет беседу с сервером, указанным в конструкторе путем GET и POST запросов. Он автоматически обрабатывает все куки и отправляет их обратно, чтобы поддерживать сессии. Если он обнаруживает, что куки новой сессии выпускаются в то время как существующие присутствуют, то он интерпретирует это как сломанную сессию и вызывает исключение. Если сервер возвращает ошибку HTTP, то он вызывает исключение. Если сервер возвращает ошибку HTTP, которая содержит билет web2py, то он возвращает исключение RuntimeError, содержащий код билета.

Объект client ведет журнал запросов в client.history и состояние, связанное с последним успешным запросом. Состояние состоит из:

  • client.status: возвращенный код состояния
  • client.text: содержание страницы
  • client.headers: словарь разобранных заголовков
  • client.cookies: словарь разобранных куки
  • client.sessions: словарь web2py сессий в форме {appname: session_id}.
  • client.forms: словарь web2py форм, обнаруженных в client.text. Словарь имеет форму {_formname,_formkey}.

Объект WebClient не выполняет синтаксический разбор client.text, возвращаемый сервером, но это может быть легко достигнуто с большим количеством сторонних модулей, таких как BeautifulSoup. Например, вот пример кода, который находит все ссылки на страницы, загруженные клиентом и проверяет все из них:

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

Построение web2py-минималиста

Иногда нам нужно развернуть web2py на сервере с очень небольшим объемом памяти. В этом случае нам необходимо раздеть web2py до его абсолютного минимума.

Самый простой способ сделать это заключается в следующем:

  • На производственной машине, установите полную версию web2py от источника
  • Изнутри основной папки web2py запустите
python scripts/make_min_web2py.py /path/to/minweb2py
  • Теперь скопируйте в "/path/to/minweb2py/applications" приложения, которые вы хотите развернуть
  • Разверните "/path/to/minweb2py" на малоразмерном сервере

Скрипт "make_min_web2py.py" строит дистрибутив web2py-минималиста, который не включает в себя:

  • admin
  • examples
  • welcome
  • scripts
  • редко используемые contrib модули

Он действительно включает "welcome" приложение, состоящее из одного файла, чтобы разрешить тестирования развертывание. Посмотрите на этот скрипт. В верхней части он содержит подробный перечень того, что включено и что игнорируется. Вы можете легко изменить его и адаптировать к вашим потребностям.

Извлечение внешнего URL

fetch

Python включает в себя библиотеку urllib для извлечения URL-адресов:

1
2
import urllib
page = urllib.urlopen('http://www.web2py.com').read()
API

Это часто хорошо, но модуль urllib не работает на Google App Engine. Google предоставляет различные API для загрузки URL-адресов, который работает на только GAE. Для того, чтобы сделать код переносимым, web2py включает fetch функцию, которая работает на GAE, а также другие объекты Python:

1
2
from gluon.tools import fetch
page = fetch('http://www.web2py.com')

Милые даты

prettydate

Часто бывает полезно представлять datetime не как "2009-07-25 14:34:56", а как "год назад". предоставляет полезную функцию для этого:

1
2
3
4
import datetime
d = datetime.datetime(2009,7,25,14,34,56)
from gluon.tools import prettydate
pretty_d = prettydate(d,T)

Второй аргумент (Т) должен быть передан, чтобы разрешить интернационализацию вывода.

Геокодирование

geocode

Если вам необходимо преобразовать адрес (например: "243 S Wabash Ave, Chicago, IL, USA") в географические координаты (широта и долгота), web2py обеспечивает функцию, чтобы сделать это.

1
2
3
from gluon.tools import geocode
address = '243 S Wabash Ave, Chicago, IL, USA'
(latitude, longitude) = geocode(address)

Функция geocode требует подключения к сети и подключается к службе геокодирования Google для геокодирования. Функция возвращает (0,0) в случае неудачи. Обратите внимание на то, что служба геокодирования Google ограничивает количество запросов, поэтому вы должны проверить их соглашение о предоставлении услуг. Функция geocode построена поверх fetch функции и, следовательно, она работает на GAE.

Разбиение на страницы (Pagination)

pagination

Этот рецепт является полезным трюком, чтобы минимизировать доступ к базе данных в случае разбиения на страницы, например, когда вам нужно отобразить список строк из базы данных, но вы хотите распределить строки на нескольких страницах.

Начните с создания приложение primes, которое хранит первые 1000 простых чисел в базе данных.

Вот модель db.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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

Теперь создать действие list_items в контроллере "default.py", который читает:

1
2
3
4
5
6
7
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)

Обратите внимание на то, что этот код выбирает на один элемент больше, чем требуется, 20 + 1. Дополнительный элемент указывает представлению, существует ли следующая страница.

Представление "default/list_items.html":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{{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}}

Таким образом, мы получили разбиение на страницы с помощью одного select в действии, и что один select только выбирает на одну строку больше, чем нам нужно.

httpserver.log и формат файла протоколирования

httpserver.log

Web2py веб-сервер регистрирует все запросы в файл с именем:

1
httpserver.log

в корневой директории web2py. Альтернативное имя файла и местоположение может быть определено с помощью web2py параметров командной строки.

Новые записи добавляются в конец файла каждый раз, когда запрос сделан. Каждая строка выглядит следующим образом:

1
127.0.0.1, 2008-01-12 10:41:20, GET, /admin/default/site, HTTP/1.1, 200, 0.270000

Формат:

1
ip, timestamp, method, path, protocol, status, time_taken

Где

  • ip это IP адрес клиента, который сделал запрос
  • timestamp является датой и временем запроса в формате ISO 8601, YYYY-MM-DDT HH:MM:SS
  • method это метод GET или POST
  • path это путь запрошенный клиентом
  • protocol является протоколом HTTP и используется для отправки клиенту, как правило, HTTP/1.1
  • status является одним из кодов состояния HTTP [status]
  • time_taken это количество времени, которое понадобилось серверу для обработки запроса, в секундах, не включая время загрузки/скачивания.

В репозитории оснастки [appliances] , вы найдете оснастку для анализа логов.

Ведение журнала по умолчанию отключено при использовании mod_wsgi, поскольку журнал будет такой же, как и журнал Apache.

Наполнение базы данных фиктивными данными

Для целей тестирования, это удобно, чтобы иметь возможность заполнения таблиц базы данных фиктивными данными. web2py включает в себя байесовский классификатор уже обученный для создания фиктивного, но читаемого текста для этой цели.

Вот простейший способ, чтобы использовать его:

1
2
from gluon.contrib.populate import populate
populate(db.mytable,100)

Он вставит 100 фиктивных записей в db.mytable. Он будет пытаться делать это разумно, производя короткий текст для строковых полей string, более длинный текст для текстовых полей text, целые числа для integers, числа типа double, даты date, дату и время datetimes, время times, булевые значения boolean и т.д. для соответствующих полей. Он будет стараться соблюдать требования, предъявляемые валидаторами. Для полей, содержащих слово "name" он будет пытаться сгенерировать фиктивные имена. Для ссылочных полей он будет генерировать правильные ссылки.

Если у вас есть две таблицы (A и B) где B ссылается на A, убедитесь, что A заполняется первой и B второй.

Поскольку заполнение делается в транзакции, не пытайтесь заполнить слишком много записей одновременно, особенно если ссылки участвуют. Вместо этого заполните 100 записей за один раз, сделайте фиксацию, затем повторите цикл.

1
2
3
for i in range(10):
    populate(db.mytable,100)
    db.commit()

Вы можете использовать байесовский классификатор для обучению какому-нибудь тексту и создавать фиктивный текст, который звучит похоже, но не должен иметь смысл:

1
2
3
4
from gluon.contrib.populate import Learner, IUP
ell=Learner()
ell.learn('some very long input text ...')
print ell.generate(1000,prefix=None)

Прием платежей по кредитным картам

Google Wallet
Paypal
Stripe.com
Authorize.net
DowCommerce

Есть несколько способов, чтобы принять платежи по кредитным картам через Интернет. web2py предоставляет специальные API интерфейсы для некоторых из самых популярных и практичных из них:

Первые два механизма выше делегирует процесс аутентификации получателя платежа к внешней службе. В то время как это является лучшим решением для обеспечения безопасности (ваше приложение не обрабатывает какую-либо информацию о кредитной карте), это делает процесс громоздким (пользователь должен войти в систему дважды, например, один раз в ваше приложение, и один раз с помощью Google) и не позволяет вашему приложению обрабатывать периодические платежи в автоматизированном режиме.

Есть моменты, когда вам нужно больше контроля, и вы захотите создать себе форму ввода для информации о кредитных картах и программно попросить процессор перевести деньги с кредитной карты на ваш счет.

По этой причине web2py предоставляет из коробки интеграцию со Stripe, Authorize.net (модуль был разработан Джоном Конде и слегка изменен) и DowCommerce. Stripe является самым простым в использовании, а также самым дешевым для низкого объема сделок (они не взимают фиксированные сборы, но снимают около 3% за транзакцию). Authorize.net лучше для больших объемов (имеет фиксированные ежегодные сборы плюс более низкую стоимость за транзакцию).

Имейте в виду, что в случае Stripe и Authorize.net ваша программа будет принимать информацию о кредитных карта. Вы не должны хранить эту информацию, и мы советуем вам не из-за юридических требований (проверка с помощью Visa или MasterCard), но бывают случаи, когда вы можете хранить информацию для покрытия текущих платежей или воспроизведения кнопки Amazon для покупки в один клик.

Google Wallet

Самый простой способ использовать Google Wallet (Уровень 1) состоит во вложении кнопки на вашу страницу, при нажатии которой посетитель перенаправляется на страницу оплаты, предоставленной Google.

Прежде всего, вам необходимо зарегистрировать аккаунт продавца Google по URL:

https://checkout.google.com/sell

Вам нужно будет предоставить Google вашу банковскую информации. Google назначит вам merchant_id и merchant_key (не путайте их, держите их в тайне).

Тогда вам необходимо просто создать следующий код в вашем представлении:

{{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")])}}

Когда посетитель нажимает на кнопку, то посетитель будет перенаправлен на страницу Google, где он/она сможет заплатить за выбранный элемент. Здесь продукция представляет собой список продуктов и каждый продукт представляет собой словарь параметров, которые вы хотите передать для описания ваших элементов (наименование, количество, цена, валюта, описание и другие необязательные параметры, описание которых вы можете найти в документации Google Wallet).

Если вы решили использовать этот механизм, то вы можете генерировать значения, передаваемые кнопкой программно на основе вашего инвентаря и диаграмме покупок посетителя.

Вся информация о ставках и доставке будет обрабатываться на стороне Google. То же самое для бухгалтерской информации. По умолчанию ваше приложение не уведомляется о том, что сделка была завершена, поэтому вам придется посетить ваш сайт продавца Google, чтобы узнать, какие продукты были приобретены и оплачены, а какие продукты вам необходимо отгрузить к вашим покупателям. Google также отправит вам электронное письмо с информацией.

Если вы хотите более тесной интеграции, вы должны использовать API уведомления 2-го уровня. В этом случае вы сможете передать больше информации в Google и Google будет вызывать API для уведомления о закупках. Это позволяет сохранить учетную информацию в вашем приложении, но это требует от вас предоставление веб-сервисов, которые могут говорить с Google Wallet.

Это является значительно более трудной задачей, но такие API уже реализованы и они доступны как плагины с

http://web2py.com/plugins/static/web2py.plugin.google_checkout.w2p

Вы можете найти документацию к плагину в самом плагине.

Paypal

Интеграция с Paypal не описывается здесь, но вы можете найти более подробную информацию об этом на этом ресурсе:

http://www.web2pyslices.com/main/slices/take_slice/9

Stripe.com

Это, вероятно, один из самых простых и гибкий способ принимать платежи по кредитным картам.

Вам необходимо зарегистрироваться на Stripe.com, что является в общем то очень простым процессом, по факту Stripe назначает вам пробный API ключ перед созданием учетных данных.

После того, как у вас появится API ключ вы можете принимать кредитные карты со следующим кодом:

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):
    # Платеж принят
elif:
    # ошибка в d.get('error','unknown')

Ответ d это словарь, который вы можете изучить самостоятельно. Номер карты, используемый в примере является песочницей и он всегда будет успешным. Каждая транзакция связана с id транзакции, хранящемся в d['id'].

Stripe также позволяет проверить транзакцию в более позднее время:

d = Stripe(key).check(d['id'])

и возврат транзакции:

r = Stripe(key).refund(d['id'])
if r.get('refunded',False):
    # возврат был успешным
elif:
    # ошибка в d.get('error','unknown')

Stripe предоставляет очень легкое ведение учета в вашем приложении.

Все коммуникации между вашим приложением и Stripe переходят на RESTful веб-сервисы. Stripe фактически предоставляет еще больше услуг и более широкий набор Python API. Вы можете прочитать больше на их веб-сайте.

Authorize.Net

Другим простым способом приема кредитных карт является использование Authorize.Net. Как обычно, вам нужно зарегистрироваться и получить login и ключ транзакции transkey. Однажды мы уже такое делали, это работает очень похоже на Stripe:

1
2
3
4
5
6
7
8
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):
   # платеж был обработан
else:
   # платеж был отклонен

Если у вас есть действующая учетная запись Authorize.Net, то вы должны заменить песочницу login и transkey на данные из вашей учетной записи, установите testmode=False для запуска на реальной платформе вместо песочницы, и используйте информацию о кредитной карте, предоставленную посетителем сайта.

Если process возвращает True, деньги были переведены со счета кредитной карты посетителя на ваш счет Authorize.Net. invoice это просто строка, которую вы можете установить и хранить с данной транзакцией посредством Authorize.Net, таким образом вы можете согласовать данные с информацией в вашем приложении.

Вот более сложный пример рабочего процесса, где выставляется большое количество переменных:

 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
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()

Обратите внимание, что приведенный выше код использует фиктивный тестовый аккаунт. Вам необходимо зарегистрироваться на Authorize.Net (это не бесплатная услуга) и предоставить свой собственный login, transkey, testmode=True или False конструктору AIM.

Dropbox API

Dropbox.com

Dropbox является очень популярным сервисом хранения. Он не только хранит ваши файлы, но он держит облако хранения в синхронизации со всеми своими машинами. Это позволяет создавать группы и давать разрешение на чтение/запись к различным папкам для отдельных пользователей или групп пользователей. Он также ведет историю версий всех файлов. Он включает в себя папку под названием "Public" и каждый файл, который вы положили туда будет иметь свой собственный публичный URL. Dropbox является отличным способом для совместной работы.

Вы можете легко получить доступ к Dropbox, зарегистрировавшись на

https://www.dropbox.com/developers

вы получаете APP_KEY и APP_SECRET. Однажды получив их, вы сможете использовать Dropbox для аутентификации пользователей.

Создайте файл с именем "yourapp/private/dropbox.key" и в нем напишите

<APP_KEY>:<APP_SECRET>:app_folder

где <APP_KEY> и <APP_SECRET> э то ваш ключ и секрет. Третья часть может быть app_folder или dropbox или auto.

Установите dropbox sdk из "https://www.dropbox.com/developers/core/sdks/python".

Затем в "models/db.py" сделайте:

from gluon.contrib.login_methods.dropbox_account import use_dropbox
use_dropbox(auth,filename='private/dropbox.key')
mydropbox = auth.settings.login_form

Это позволит пользователям войти в приложение, используя свои учетные данные Dropbox, и ваша программа будет иметь возможность загружать файлы в их аккаунт Dropbox:

stream = open('localfile.txt','rb')
mydropbox.put('destfile.txt',stream)

скачивать файлы:

stream = mydropbox.get('destfile.txt')
open('localfile.txt','wb').write(read)

и получать списки каталогов:

contents = mydropbox.dir(path = '/')['contents']

Потоковая передача виртуальных файлов

streaming

Ни для кого не секрет, что злоумышленники сканируют веб-сайты на наличие уязвимостей. Они используют сканеры безопасности, такие как Nessus для изучения сценариев целевых веб-сайтов, которые, как известно, имеют уязвимости. Анализ журналов веб-сервера из отсканированной машины или непосредственно в базе данных Nessus показывает, что большинство известных уязвимостей находится в PHP-скриптах и скриптах ASP. Так как мы запускаем web2py, то мы не имеем этих уязвимостей, но нас по-прежнему будут сканировать на наличие уязвимостей. Это раздражает, так что мы бы хотели ответить на эти сканирования уязвимостей и дать злоумышленнику понять, что они тратят время впустую.

Одним из возможных вариантов является перенаправление всех запросов на .php, .asp, и всех подозрительных на фиктивные действия, которые будут реагировать на атаки, держа злоумышленника занятым в течение большого количества времени. В конце концов злоумышленнику остается только сдастся и не прекратить повторение проверок.

Этот рецепт требует двух частей.

Выделенное приложение под названием jammer с контроллером "default.py" следующим образом:

1
2
3
class Jammer():
   def read(self,n): return 'x'*n
def jam(): return response.stream(Jammer(),40000)

Когда это действие вызывается, оно реагирует с бесконечным потоком данных, заполненными "х"-ми. 40000 символов одновременно.

Второй компонент представляет собой файл "route.py", который перенаправляет любой запрос, заканчивающийся на .php, .asp и т.д. (в верхнем и нижнем регистре) для этого контроллера.

1
2
3
route_in=(
 ('.*.(php|PHP|asp|ASP|jsp|JSP)','jammer/default/jam'),
)

Первый раз, когда вас атаковали, вы можете понести небольшие накладные расходы, но наш опыт показывает, что тот же самый злоумышленник не будет пытаться дважды.

 top