Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/rpms/sugar/0052-Initial-client-implementation-for-feedback-feature.patch
diff options
context:
space:
mode:
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.patch384
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
+