1
# Copyright (C) 2010 Canonical
7
# This program is free software; you can redistribute it and/or modify it under
8
# the terms of the GNU General Public License as published by the Free Software
9
# Foundation; version 3.
11
# This program is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16
# You should have received a copy of the GNU General Public License along with
17
# this program; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30
from gettext import gettext as _
32
from softwarecenter.backend import get_install_backend
34
LOG = logging.getLogger(__name__)
36
class ScrolledWebkitWindow(gtk.ScrolledWindow):
39
super(ScrolledWebkitWindow, self).__init__()
40
self.webkit = webkit.WebView()
41
settings = self.webkit.get_settings()
42
settings.set_property("enable-plugins", False)
44
# embed the webkit view in a scrolled window
46
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
48
class PurchaseView(gtk.VBox):
50
View that displays the webkit-based UI for purchasing an item.
58
<style type="text/css">
74
vertical-align: middle;
77
background: url(file:///usr/share/software-center/images/spinner.gif) top center no-repeat;
78
padding-top: 48px; /* leaves room for the spinner above */
87
""" % _("Connecting to payment service...")
90
'purchase-succeeded' : (gobject.SIGNAL_RUN_LAST,
93
'purchase-failed' : (gobject.SIGNAL_RUN_LAST,
96
'purchase-cancelled-by-user' : (gobject.SIGNAL_RUN_LAST,
102
gtk.VBox.__init__(self)
107
self.wk = ScrolledWebkitWindow()
108
self.wk.webkit.connect("create-web-view",
109
self._on_create_webview_request)
110
# a possible way to do IPC (script or title change)
111
self.wk.webkit.connect("script-alert", self._on_script_alert)
112
self.wk.webkit.connect("title-changed", self._on_title_changed)
114
def initiate_purchase(self, app, iconname, url=None, html=None):
116
initiates the purchase workflow inside the embedded webkit window
117
for the item specified
121
self.iconname = iconname
122
self.wk.webkit.load_html_string(self.LOADING_HTML, "file:///")
124
while gtk.events_pending():
127
self.wk.webkit.load_uri(url)
129
self.wk.webkit.load_html_string(html, "file:///")
131
self.wk.webkit.load_html_string(DUMMY_HTML, "file:///")
132
self.pack_start(self.wk)
134
if os.environ.get("SOFTWARE_CENTER_DEBUG_BUY"):
135
glib.timeout_add_seconds(1, _generate_events, self)
137
def _on_create_webview_request(self, view, frame, parent=None):
138
LOG.debug("_on_create_webview_request")
140
popup.set_size_request(750,400)
142
popup.set_modal(True)
143
popup.set_transient_for(None)
144
wk = ScrolledWebkitWindow()
146
popup.vbox.pack_start(wk)
150
def _on_script_alert(self, view, frame, message):
151
self._process_json(message)
152
# stop further processing to avoid actually showing the alter
155
def _on_title_changed(self, view, frame, title):
156
#print "on_title_changed", view, frame, title
157
# see wkwidget.py _on_title_changed() for a code example
158
self._process_json(title)
160
def _process_json(self, json_string):
162
LOG.debug("server returned: '%s'" % json_string)
163
res = simplejson.loads(json_string)
166
LOG.debug("error processing json: '%s'" % json_string)
168
if res["successful"] == False:
169
if res.get("user_canceled", False):
170
self.emit("purchase-cancelled-by-user")
172
# this is what the agent implements
173
elif "failures" in res:
174
LOG.error("the server returned a error: '%s'" % res["failures"])
175
# show a generic error, the "failures" string we get from the
176
# server is way too technical to show, but we do log it
177
self.emit("purchase-failed")
180
self.emit("purchase-succeeded")
181
# gather data from response
182
deb_line = res["deb_line"]
183
signing_key_id = res["signing_key_id"]
185
get_install_backend().add_repo_add_key_and_install_app(deb_line,
190
# just used for testing --------------------------------------------
192
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
193
"http://www.w3.org/TR/html4/loose.dtd">
199
<script type="text/javascript">
200
function changeTitle(title) { document.title = title; }
201
function success() { changeTitle('{ "successful" : true, \
202
"deb_line" : "deb https://user:pass@private-ppa.launchpad.net/mvo/ubuntu lucid main", \
203
"package_name" : "2vcard", \
204
"application_name" : "The 2vcard app", \
205
"signing_key_id" : "1024R/0EB12F05"\
207
function cancel() { changeTitle('{ "successful" : false }') }
209
<h1>Purchase test page</h1>
210
<p> To buy Frobunicator for 99$ you need to enter your credit card info</p>
211
<p> Enter your credit card info </p>
215
<input type="button" name="test_button2"
219
<input type="button" name="test_button"
227
# synthetic key event generation
228
def _send_keys(view, s):
229
print "_send_keys", s
230
MAPPING = { '@' : 'at',
235
'\a' : 'Down', # fake
237
'\v' : 'Page_Down', # fake
241
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
242
event.window = view.window
245
if hasattr(gtk.keysyms, key):
246
event.keyval = getattr(gtk.keysyms, key)
248
event.keyval = getattr(gtk.keysyms, MAPPING[key])
249
gtk.main_do_event(event)
252
# \a means down key - its a just a fake to get it working
253
LOGIN = os.environ.get("SOFTWARE_CENTER_LOGIN") or "michael.vogt@ubuntu.com"
254
# for some reason the "space" key before on checkbox does not work when
255
# the event is generated, so this needs to be done manually :/
256
PAYMENT_DETAILS = "\tstreet1\tstreet2\tcity\tstate\t1234\t\a\t\a\a\t"\
257
"ACCEPTED\t4111111111111111\t1234\t\a\t\a\a\t\t\t \v"
258
# state-name, window title, keys
259
STATES = [ ('login', 'Log in', LOGIN+"\t"),
260
('confirm-sso', 'Authenticate to', '\n'),
261
('enter-payment', 'Confirm Payment Details', PAYMENT_DETAILS),
262
('confirm-payment', 'title-the-same-as-before', '\t\n'),
263
('end-state', 'no-title', ''),
265
def _generate_events(view):
268
(state, title, keys) = STATES[0]
270
print "_generate_events: in state", state
272
current_title = view.wk.webkit.get_property("title")
273
if current_title and current_title.startswith(title):
274
print "found state", state
275
_send_keys(view, keys)
280
# # for debugging only
281
# def _on_key_press(dialog, event):
282
# print event, event.keyval
284
if __name__ == "__main__":
285
#url = "http://www.animiertegifs.de/java-scripts/alertbox.php"
286
#url = "http://www.ubuntu.com"
287
#d = PurchaseDialog(app=None, html=DUMMY_HTML)
288
#d = PurchaseDialog(app=None, url="http://spiegel.de")
289
from softwarecenter.enums import BUY_SOMETHING_HOST
290
url = BUY_SOMETHING_HOST+"/subscriptions/en/ubuntu/maverick/+new/?%s" % (
292
'archive_id' : "mvo/private-test",
295
# use cmdline if available
296
if len(sys.argv) > 1:
298
# useful for debugging
299
#d.connect("key-press-event", _on_key_press)
300
#glib.timeout_add_seconds(1, _generate_events, d)
302
widget = PurchaseView()
303
widget.initiate_purchase(app=None, iconname=None, html=DUMMY_HTML)
305
window = gtk.Window()
307
window.set_size_request(600, 500)
308
window.set_position(gtk.WIN_POS_CENTER)
310
window.connect('destroy', gtk.main_quit)