diff options
Diffstat (limited to 'rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch')
-rw-r--r-- | rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch b/rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch new file mode 100644 index 0000000..0df6344 --- /dev/null +++ b/rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch @@ -0,0 +1,384 @@ +From 8976c8e9cc399b83be1e28f7e4e958d93294af14 Mon Sep 17 00:00:00 2001 +From: Aleksey Lim <alsroot@member.fsf.org> +Date: Mon, 18 Jul 2011 20:29:49 +0200 +Subject: [PATCH sugar 52/74] Initial client implementation for feedback + feature + +See http://git.sugarlabs.org/feedback-server/ for the server side. + +[added link to server] +Signed-off-by: Sascha Silbe <silbe@activitycentral.com> +--- + bin/sugar-session | 8 +- + data/sugar.schemas.in | 44 +++++++ + src/jarabe/model/Makefile.am | 1 + + src/jarabe/model/feedback_collector.py | 201 ++++++++++++++++++++++++++++++++ + src/jarabe/model/shell.py | 17 +++ + src/jarabe/view/service.py | 5 + + 6 files changed, 275 insertions(+), 1 deletions(-) + create mode 100644 src/jarabe/model/feedback_collector.py + +diff --git a/bin/sugar-session b/bin/sugar-session +index a1d7cac..8e83d52 100755 +--- a/bin/sugar-session ++++ b/bin/sugar-session +@@ -233,7 +233,7 @@ def main(): + gettext.textdomain('sugar') + + from jarabe.desktop import homewindow +- from jarabe.model import sound ++ from jarabe.model import sound, feedback_collector + from jarabe import intro + + logger.start('shell') +@@ -242,6 +242,12 @@ def main(): + client.set_string('/apps/metacity/general/mouse_button_modifier', + '<Super>') + ++ if client.get_bool('/desktop/sugar/feedback/enabled'): ++ feedback_collector.start( ++ client.get_string('/desktop/sugar/feedback/server_host'), ++ client.get_int('/desktop/sugar/feedback/server_port'), ++ client.get_int('/desktop/sugar/feedback/auto_submit_delay')) ++ + timezone = client.get_string('/desktop/sugar/date/timezone') + if timezone is not None and timezone: + os.environ['TZ'] = timezone +diff --git a/data/sugar.schemas.in b/data/sugar.schemas.in +index 644678b..eecd1d8 100644 +--- a/data/sugar.schemas.in ++++ b/data/sugar.schemas.in +@@ -2,6 +2,50 @@ + <gconfschemafile> + <schemalist> + <schema> ++ <key>/schemas/desktop/sugar/feedback/enabled</key> ++ <applyto>/desktop/sugar/feedback/enabled</applyto> ++ <owner>sugar</owner> ++ <type>bool</type> ++ <default>true</default> ++ <locale name="C"> ++ <short>Enable of disable feedback feature</short> ++ <long>Setting value to false will disable any feedback reports.</long> ++ </locale> ++ </schema> ++ <schema> ++ <key>/schemas/desktop/sugar/feedback/server_host</key> ++ <applyto>/desktop/sugar/feedback/server_host</applyto> ++ <owner>sugar</owner> ++ <type>string</type> ++ <default>jita.sugarlabs.org</default> ++ <locale name="C"> ++ <short>Server host to send reports to</short> ++ <long>Server that will handle reports sent via HTTPS POST requests.</long> ++ </locale> ++ </schema> ++ <schema> ++ <key>/schemas/desktop/sugar/feedback/server_port</key> ++ <applyto>/desktop/sugar/feedback/server_port</applyto> ++ <owner>sugar</owner> ++ <type>int</type> ++ <default>8080</default> ++ <locale name="C"> ++ <short>Server port to send reports to</short> ++ <long>TCP port that will used to send HTTPS POST requests.</long> ++ </locale> ++ </schema> ++ <schema> ++ <key>/schemas/desktop/sugar/feedback/auto_submit_delay</key> ++ <applyto>/desktop/sugar/feedback/auto_submit_delay</applyto> ++ <owner>sugar</owner> ++ <type>int</type> ++ <default>0</default> ++ <locale name="C"> ++ <short>Delay in seconds to send anonymous reports automatically</short> ++ <long>Setting value to 0 will disable automatic submiting.</long> ++ </locale> ++ </schema> ++ <schema> + <key>/schemas/desktop/sugar/user/nick</key> + <applyto>/desktop/sugar/user/nick</applyto> + <owner>sugar</owner> +diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am +index 040b099..04c4826 100644 +--- a/src/jarabe/model/Makefile.am ++++ b/src/jarabe/model/Makefile.am +@@ -5,6 +5,7 @@ sugar_PYTHON = \ + accessibility.py \ + buddy.py \ + bundleregistry.py \ ++ feedback_collector.py \ + filetransfer.py \ + friends.py \ + invites.py \ +diff --git a/src/jarabe/model/feedback_collector.py b/src/jarabe/model/feedback_collector.py +new file mode 100644 +index 0000000..5e92fbd +--- /dev/null ++++ b/src/jarabe/model/feedback_collector.py +@@ -0,0 +1,201 @@ ++# Copyright (C) 2011, Aleksey Lim ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see <http://www.gnu.org/licenses/>. ++ ++import os ++import time ++import httplib ++import logging ++import tarfile ++import threading ++from cStringIO import StringIO ++from os.path import join, exists, basename ++from email.mime.multipart import MIMEMultipart ++from email.mime.application import MIMEApplication ++from email.generator import Generator ++from email.encoders import encode_noop ++ ++import gconf ++import gobject ++import simplejson ++ ++from sugar import logger, feedback, util ++ ++ ++_reports = {} ++_logs = set() ++_host = None ++_port = None ++ ++ ++def start(host, port, auto_submit_delay): ++ global _host ++ global _port ++ ++ _host = host ++ _port = port ++ ++ if auto_submit_delay > 0: ++ gobject.timeout_add_seconds(auto_submit_delay, _submit) ++ ++ ++def update(bundle_id, report, log_file): ++ if bundle_id not in _reports: ++ _reports[bundle_id] = {} ++ stat = _reports[bundle_id] ++ ++ for key, count in report.items(): ++ if key not in stat: ++ stat[key] = 0 ++ stat[key] += count ++ ++ if log_file: ++ _logs.add(log_file) ++ ++ ++def is_empty(): ++ report, shell_log = feedback.flush() ++ if report: ++ if shell_log: ++ shell_log = join(logger.get_logs_dir(), 'shell.log') ++ update('shell', report, shell_log) ++ ++ return not _reports ++ ++ ++def submit(message): ++ from jarabe.journal import misc ++ ++ client = gconf.client_get_default() ++ jabber = client.get_string('/desktop/sugar/collaboration/jabber_server') ++ nick = client.get_string("/desktop/sugar/user/nick") ++ ++ data = {'message': message, ++ 'serial_number': '', ++ 'nick': '', ++ 'jabber_server': jabber, ++ } ++ _submit(data) ++ ++ ++def anonymous_submit(): ++ _submit() ++ ++ ++def _submit(data=None): ++ if data: ++ _reports.update(data) ++ if is_empty(): ++ return True ++ ++ logging.debug('Sending feedback report: %r', _reports) ++ ++ report = simplejson.dumps(_reports) ++ _reports.clear() ++ ++ tar_file = util.TempFilePath() ++ tar = tarfile.open(tar_file, 'w:gz') ++ ++ while _logs: ++ log_file = _logs.pop() ++ if exists(log_file): ++ tar.add(log_file, arcname=basename(log_file)) ++ ++ report_file = tarfile.TarInfo('report') ++ report_file.mode = 0644 ++ report_file.mtime = int(time.time()) ++ report_file.size = len(report) ++ tar.addfile(report_file, StringIO(report)) ++ ++ tar.close() ++ ++ _SubmitThread(tar_file).run() ++ ++ return True ++ ++ ++class _SubmitThread(threading.Thread): ++ ++ def __init__(self, tar_file): ++ threading.Thread.__init__(self) ++ self._tar_file = tar_file ++ ++ def run(self): ++ try: ++ message = _FormData() ++ attachment = MIMEApplication(file(self._tar_file).read(), ++ _encoder=encode_noop) ++ message.attach_file(attachment, ++ name='report', filename='report.tar.gz') ++ body, headers = message.get_request_data() ++ ++ conn = httplib.HTTPSConnection(_host, _port) ++ conn.request('POST', '/', body, headers) ++ response = conn.getresponse() ++ ++ if response.status != 200: ++ logging.error('Incorrect feedback submit: %s, %s', ++ response.status, response.read()) ++ ++ except Exception: ++ logging.exception('Cannot submit feedback') ++ finally: ++ os.unlink(self._tar_file) ++ self._tar_file = None ++ ++ ++class _FormData(MIMEMultipart): ++ '''A simple RFC2388 multipart/form-data implementation. ++ ++ A snippet from http://bugs.python.org/issue3244 ++ ++ ''' ++ ++ def __init__(self, boundary=None, _subparts=None, **kwargs): ++ MIMEMultipart.__init__(self, _subtype='form-data', ++ boundary=boundary, _subparts=_subparts, **kwargs) ++ ++ def attach(self, subpart): ++ if 'MIME-Version' in subpart: ++ if subpart['MIME-Version'] != self['MIME-Version']: ++ raise ValueError('subpart has incompatible MIME-Version') ++ # Note: This isn't strictly necessary, but there is no point in ++ # including a MIME-Version header in each subpart. ++ del subpart['MIME-Version'] ++ MIMEMultipart.attach(self, subpart) ++ ++ def attach_file(self, subpart, name, filename): ++ ''' ++ Attach a subpart, setting it's Content-Disposition header to "file". ++ ''' ++ name = name.replace('"', '\\"') ++ filename = filename.replace('"', '\\"') ++ subpart['Content-Disposition'] = \ ++ 'form-data; name="%s"; filename="%s"' % (name, filename) ++ self.attach(subpart) ++ ++ def get_request_data(self, trailing_newline=True): ++ '''Return the encoded message body.''' ++ f = StringIO() ++ generator = Generator(f, mangle_from_=False) ++ # pylint: disable-msg=W0212 ++ generator._dispatch(self) ++ # HTTP needs a trailing newline. Since our return value is likely to ++ # be passed directly to an HTTP connection, we might as well add it ++ # here. ++ if trailing_newline: ++ f.write('\n') ++ body = f.getvalue() ++ headers = dict(self) ++ return body, headers +diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py +index 31605f7..1f980cf 100644 +--- a/src/jarabe/model/shell.py ++++ b/src/jarabe/model/shell.py +@@ -23,12 +23,15 @@ + import gobject + import gtk + import dbus ++import simplejson + + from sugar import wm + from sugar import dispatch + from sugar.graphics.xocolor import XoColor + + from jarabe.model.bundleregistry import get_registry ++from jarabe.model import feedback_collector ++ + + _SERVICE_NAME = 'org.laptop.Activity' + _SERVICE_PATH = '/org/laptop/Activity' +@@ -234,6 +237,12 @@ def get_bundle_path(self): + else: + return self._activity_info.get_path() + ++ def get_bundle_id(self): ++ if self._activity_info is None: ++ return None ++ else: ++ return self._activity_info.get_bundle_id() ++ + def get_activity_name(self): + """Returns the activity's bundle name""" + if self._activity_info is None: +@@ -654,6 +663,14 @@ def notify_launch_failed(self, activity_id): + logging.error('Model for activity id %s does not exist.', + activity_id) + ++ def notify_feedback(self, activity_id, report, log_file): ++ home_activity = self.get_activity_by_id(activity_id) ++ if home_activity is not None: ++ feedback_collector.update(home_activity.get_bundle_id(), ++ simplejson.loads(report), log_file) ++ else: ++ logging.error('No %s activity for sending feedback', activity_id) ++ + def _check_activity_launched(self, activity_id): + home_activity = self.get_activity_by_id(activity_id) + +diff --git a/src/jarabe/view/service.py b/src/jarabe/view/service.py +index 29e46b2..0f5e94f 100644 +--- a/src/jarabe/view/service.py ++++ b/src/jarabe/view/service.py +@@ -88,3 +88,8 @@ def NotifyLaunch(self, bundle_id, activity_id): + in_signature='s', out_signature='') + def NotifyLaunchFailure(self, activity_id): + shell.get_model().notify_launch_failed(activity_id) ++ ++ @dbus.service.method(_DBUS_SHELL_IFACE, ++ in_signature='sss', out_signature='') ++ def Feedback(self, activity_id, report, log_file): ++ shell.get_model().notify_feedback(activity_id, report, log_file) +-- +1.7.6 + |