Removes python client. https://reviews.apache.org/r/45976
Project: http://git-wip-us.apache.org/repos/asf/incubator-wave/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-wave/commit/78cbf78f Tree: http://git-wip-us.apache.org/repos/asf/incubator-wave/tree/78cbf78f Diff: http://git-wip-us.apache.org/repos/asf/incubator-wave/diff/78cbf78f Branch: refs/heads/master Commit: 78cbf78fb74ee739f177920c8c5f25bc6a59af81 Parents: 4070747 Author: Yuri Zelikov <[email protected]> Authored: Mon Apr 25 21:09:24 2016 +0300 Committer: Yuri Zelikov <[email protected]> Committed: Mon Apr 25 21:09:24 2016 +0300 ---------------------------------------------------------------------- .gitignore | 2 - LICENSE | 46 - wave/dist/CHANGES | 180 ---- wave/src/main/java/python/api/__init__.py | 20 - .../java/python/api/appengine_robot_runner.py | 204 ---- wave/src/main/java/python/api/blip.py | 949 ------------------- wave/src/main/java/python/api/blip_test.py | 383 -------- .../java/python/api/commandline_robot_runner.py | 84 -- .../python/api/commandline_robot_runner_test.py | 93 -- wave/src/main/java/python/api/django_oauth.py | 114 --- wave/src/main/java/python/api/element.py | 370 -------- wave/src/main/java/python/api/element_test.py | 218 ----- wave/src/main/java/python/api/errors.py | 31 - wave/src/main/java/python/api/events.py | 304 ------ .../main/java/python/api/module_test_runner.py | 43 - wave/src/main/java/python/api/oauth/LICENSE | 22 - wave/src/main/java/python/api/oauth/__init__.py | 541 ----------- wave/src/main/java/python/api/ops.py | 482 ---------- wave/src/main/java/python/api/ops_test.py | 75 -- wave/src/main/java/python/api/robot.py | 343 ------- wave/src/main/java/python/api/robot_test.py | 257 ----- wave/src/main/java/python/api/run_unit_tests.py | 49 - wave/src/main/java/python/api/search.py | 153 --- wave/src/main/java/python/api/search_test.py | 79 -- .../src/main/java/python/api/simplejson/LICENSE | 19 - .../main/java/python/api/simplejson/__init__.py | 424 --------- .../main/java/python/api/simplejson/decoder.py | 431 --------- .../main/java/python/api/simplejson/encoder.py | 476 ---------- .../java/python/api/simplejson/jsonfilter.py | 60 -- .../java/python/api/simplejson/ordered_dict.py | 139 --- .../main/java/python/api/simplejson/scanner.py | 87 -- .../src/main/java/python/api/simplejson/tool.py | 57 -- wave/src/main/java/python/api/testdata.py | 225 ----- wave/src/main/java/python/api/util.py | 198 ---- wave/src/main/java/python/api/util_test.py | 187 ---- wave/src/main/java/python/api/wavelet.py | 481 ---------- wave/src/main/java/python/api/wavelet_test.py | 199 ---- wave/src/main/java/python/api/waveservice.py | 468 --------- .../main/java/python/api/waveservice_test.py | 72 -- 39 files changed, 8565 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index 267def7..a9cec8c 100755 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ */gwt-unitCache war/WEB-INF *.old -*.log* .DS_Store ### IntelliJ Idea @@ -50,7 +49,6 @@ reports/ ### Generated Sources **/generated/ ### Gwt Testing -wave/gwt-unitCache ### config wave/local.net.cfg.lua wave/config/wave.conf http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/LICENSE ---------------------------------------------------------------------- diff --git a/LICENSE b/LICENSE index a2be50d..6bf7059 100644 --- a/LICENSE +++ b/LICENSE @@ -201,52 +201,6 @@ limitations under the License. ***THE FOLLOWING LICENSE APPLIES TO*** -- The OAuth python library located at /src/python/api/oauth/ - Copyright (c) 2007 Andy Smith - -The MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -***THE FOLLOWING LICENSE APPLIES TO*** -- SimpleJSON located at /src/python/api/simplejson/ - Copyright (c) 2006 Bob Ippolito - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -***THE FOLLOWING LICENSE APPLIES TO*** - Protobuf Descriptors located at /src/google/protobuf/descriptor.proto Protocol Buffers - Google's data interchange format http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/dist/CHANGES ---------------------------------------------------------------------- diff --git a/wave/dist/CHANGES b/wave/dist/CHANGES index cf47949..a2d6c8e 100644 --- a/wave/dist/CHANGES +++ b/wave/dist/CHANGES @@ -437,147 +437,6 @@ Author: Yuri Zelikov <[email protected]> Date: Sat Jan 18 16:06:56 2014 +0200 Merge branch 'wave-0.4-release' into master - - Conflicts: - .classpath - .gitignore - .project_template - CHANGES - NOTICE - README - build.properties - build.xml - jaas.config - prosody.cfg.lua.example - proto_src/org/waveprotocol/box/attachment/AttachmentProto.java - proto_src/org/waveprotocol/box/server/persistence/protos/ProtoAccountStoreData.java - run-server.bat - server-config.xml - server.federation.config - src/com/google/gwt/build.xml - src/com/google/gwt/websockets/WebSockets.gwt.xml - src/com/google/wave/api/data/Data.gwt.xml - src/com/google/wave/api/robot/Robot.gwt.xml - src/org/waveprotocol/box/server/frontend/WaveletInfo.java - src/org/waveprotocol/box/server/persistence/protos/delta-store.proto - src/org/waveprotocol/box/server/waveserver/SimpleSearchProviderImpl.java - src/org/waveprotocol/box/server/waveserver/Wave.java - src/org/waveprotocol/box/webclient/search/i18n/SearchPresenterMessages_sl.properties - src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_sl.properties - src/org/waveprotocol/box/webclient/search/mock/search.html - src/org/waveprotocol/protobuf/build.xml - src/org/waveprotocol/pst/templates/api/properties - src/org/waveprotocol/pst/templates/builder/properties - src/org/waveprotocol/pst/templates/gson/properties - src/org/waveprotocol/pst/templates/jso/properties - src/org/waveprotocol/pst/templates/pojo/properties - src/org/waveprotocol/pst/templates/proto/properties - src/org/waveprotocol/pst/templates/util/properties - src/org/waveprotocol/wave/client/build.xml - src/org/waveprotocol/wave/client/common/build.xml - src/org/waveprotocol/wave/client/scheduler/build.xml - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/ComplexColorPicker.css - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/SimpleColorPicker.css - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/i18n/ColorPickerMessages_en.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/color/i18n/ColorPickerMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_fr.properties - src/org/waveprotocol/wave/common/build.xml - src/org/waveprotocol/wave/communication/build.xml - src/org/waveprotocol/wave/concurrencycontrol/build.xml - src/org/waveprotocol/wave/crypto/build.xml - src/org/waveprotocol/wave/diff/build.xml - src/org/waveprotocol/wave/federation/build.xml - src/org/waveprotocol/wave/media/build.xml - src/org/waveprotocol/wave/model/build.xml - src/org/waveprotocol/wave/testing/build.xml - src/org/waveprotocol/wave/util/build.xml - src/python/api/__init__.py - src/python/api/appengine_robot_runner.py - src/python/api/blip.py - src/python/api/blip_test.py - src/python/api/commandline_robot_runner.py - src/python/api/commandline_robot_runner_test.py - src/python/api/django_oauth.py - src/python/api/element.py - src/python/api/element_test.py - src/python/api/errors.py - src/python/api/events.py - src/python/api/module_test_runner.py - src/python/api/ops.py - src/python/api/ops_test.py - src/python/api/robot.py - src/python/api/robot_test.py - src/python/api/run_unit_tests.py - src/python/api/search.py - src/python/api/search_test.py - src/python/api/testdata.py - src/python/api/util.py - src/python/api/util_test.py - src/python/api/wavelet.py - src/python/api/wavelet_test.py - src/python/api/waveservice.py - src/python/api/waveservice_test.py - test/org/waveprotocol/wave/concurrencycontrol/Tests.gwt.xml - test/org/waveprotocol/wave/model/experimental/schema/bad1.schema - test/org/waveprotocol/wave/model/experimental/schema/bad10.schema - test/org/waveprotocol/wave/model/experimental/schema/bad11.schema - test/org/waveprotocol/wave/model/experimental/schema/bad12.schema - test/org/waveprotocol/wave/model/experimental/schema/bad13.schema - test/org/waveprotocol/wave/model/experimental/schema/bad14.schema - test/org/waveprotocol/wave/model/experimental/schema/bad15.schema - test/org/waveprotocol/wave/model/experimental/schema/bad16.schema - test/org/waveprotocol/wave/model/experimental/schema/bad17.schema - test/org/waveprotocol/wave/model/experimental/schema/bad18.schema - test/org/waveprotocol/wave/model/experimental/schema/bad19.schema - test/org/waveprotocol/wave/model/experimental/schema/bad2.schema - test/org/waveprotocol/wave/model/experimental/schema/bad20.schema - test/org/waveprotocol/wave/model/experimental/schema/bad21.schema - test/org/waveprotocol/wave/model/experimental/schema/bad22.schema - test/org/waveprotocol/wave/model/experimental/schema/bad23.schema - test/org/waveprotocol/wave/model/experimental/schema/bad24.schema - test/org/waveprotocol/wave/model/experimental/schema/bad3.schema - test/org/waveprotocol/wave/model/experimental/schema/bad4.schema - test/org/waveprotocol/wave/model/experimental/schema/bad5.schema - test/org/waveprotocol/wave/model/experimental/schema/bad6.schema - test/org/waveprotocol/wave/model/experimental/schema/bad7.schema - test/org/waveprotocol/wave/model/experimental/schema/bad8.schema - test/org/waveprotocol/wave/model/experimental/schema/bad9.schema - test/org/waveprotocol/wave/model/experimental/schema/good1.schema - test/org/waveprotocol/wave/model/experimental/schema/good10.schema - test/org/waveprotocol/wave/model/experimental/schema/good11.schema - test/org/waveprotocol/wave/model/experimental/schema/good12.schema - test/org/waveprotocol/wave/model/experimental/schema/good13.schema - test/org/waveprotocol/wave/model/experimental/schema/good14.schema - test/org/waveprotocol/wave/model/experimental/schema/good15.schema - test/org/waveprotocol/wave/model/experimental/schema/good16.schema - test/org/waveprotocol/wave/model/experimental/schema/good2.schema - test/org/waveprotocol/wave/model/experimental/schema/good3.schema - test/org/waveprotocol/wave/model/experimental/schema/good4.schema - test/org/waveprotocol/wave/model/experimental/schema/good5.schema - test/org/waveprotocol/wave/model/experimental/schema/good6.schema - test/org/waveprotocol/wave/model/experimental/schema/good7.schema - test/org/waveprotocol/wave/model/experimental/schema/good8.schema - test/org/waveprotocol/wave/model/experimental/schema/good9.schema - test/org/waveprotocol/wave/model/supplement/tests.gwt.xml - test/org/waveprotocol/wave/model/tests.gwt.xml - third_party/codegen/gwt/README.google - third_party/codegen/gwt/gwt-dev.jar - third_party/codegen/gwt/gwt-user.jar - third_party/runtime/bouncycastle/LICENSE.html - third_party/runtime/gson/LICENSE - third_party/runtime/guava/README.google - third_party/runtime/jetty/README.google - third_party/runtime/libidn/LICENSE - third_party/runtime/libidn/README.google - third_party/runtime/libidn/libidn-1.26.jar - third_party/runtime/mongo-driver/README.google - third_party/runtime/protobuf/README.google - third_party/test/jmock/README.google - third_party/test/mockito/README.google - third_party/test/mockito/mockito-all-1.9.5.jar - tools/eclipse-launch/src.org.waveprotocol.wave.client.editor.examples.img.Img_Example-launch - tools/eclipse-launch/src.org.waveprotocol.wave.client.editor.harness.EditorTest-launch - war/.gitignore commit 0b550672da3c923fbc6be0a963d2bf54c735b783 Author: Yuri Zelikov <[email protected]> @@ -911,45 +770,6 @@ Author: Ali Lown <[email protected]> Date: Tue Aug 27 19:14:34 2013 +0000 Merge branch 'trunk' into 0.4-release-staging - - Conflicts: - README - src/org/waveprotocol/box/waveimport/WaveExport.java - src/org/waveprotocol/box/waveimport/WaveImport.java - src/org/waveprotocol/box/waveimport/google/RobotApi.java - src/org/waveprotocol/box/waveimport/google/RobotSearchDigest.java - src/org/waveprotocol/box/waveimport/google/RobotSearchDigestGsonImpl.java - src/org/waveprotocol/box/waveimport/google/RobotSearchDigestImpl.java - src/org/waveprotocol/box/waveimport/google/RobotSearchDigestUtil.java - src/org/waveprotocol/box/waveimport/google/oauth/NeedNewOAuthTokenException.java - src/org/waveprotocol/box/waveimport/google/oauth/OAuthCredentials.java - src/org/waveprotocol/box/waveimport/google/oauth/OAuthRequestHelper.java - src/org/waveprotocol/box/waveimport/google/oauth/OAuthedFetchService.java - src/org/waveprotocol/box/waveimport/google/oauth/StableUserId.java - src/org/waveprotocol/box/waveimport/google/oauth/UserContext.java - src/org/waveprotocol/box/webclient/client/i18n/SessionMessages_es.properties - src/org/waveprotocol/box/webclient/client/i18n/SessionMessages_fr.properties - src/org/waveprotocol/box/webclient/client/i18n/WebClientMessages_es.properties - src/org/waveprotocol/box/webclient/client/i18n/WebClientMessages_fr.properties - src/org/waveprotocol/box/webclient/search/i18n/SearchPresenterMessages_sl.properties - src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_es.properties - src/org/waveprotocol/box/webclient/search/i18n/SearchWidgetMessages_sl.properties - src/org/waveprotocol/box/webclient/widget/error/i18n/ErrorMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/impl/edit/i18n/ActionMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/impl/menu/i18n/MenuMessages_fr.properties - src/org/waveprotocol/wave/client/wavepanel/impl/menu/i18n/MenuMessages_sl.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/attachment/i18n/AttachmentMessages_fr.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/attachment/i18n/AttachmentMessages_sl.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/gadget/i18n/GadgetCategoryMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/gadget/i18n/GadgetSelectorMessages_sl.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/LinkerMessages_fr.properties - src/org/waveprotocol/wave/client/wavepanel/impl/toolbar/i18n/ToolbarMessages_fr.properties - src/org/waveprotocol/wave/client/wavepanel/view/dom/full/i18n/ReplyBoxMessages_es.properties - src/org/waveprotocol/wave/client/wavepanel/view/dom/full/i18n/ReplyBoxMessages_fr.properties - src/org/waveprotocol/wave/client/widget/profile/i18n/ProfilePopupMessages_es.properties - src/org/waveprotocol/wave/migration/build.xml - git-svn-id: https://svn.apache.org/repos/asf/incubator/wave/branches/wave-0.4-release@1517927 13f79535-47bb-0310-9956-ffa450edef68 commit 615d44352fccf53db12bc43829d7d7f2c2155410 http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/__init__.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/__init__.py b/wave/src/main/java/python/api/__init__.py deleted file mode 100644 index a92a86c..0000000 --- a/wave/src/main/java/python/api/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Declares the api package.""" http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/appengine_robot_runner.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/appengine_robot_runner.py b/wave/src/main/java/python/api/appengine_robot_runner.py deleted file mode 100644 index 776f825..0000000 --- a/wave/src/main/java/python/api/appengine_robot_runner.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/python -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""A module to run wave robots on app engine.""" - - -import logging -import sys - -import events - -from google.appengine.api import urlfetch -from google.appengine.ext import webapp -from google.appengine.ext.webapp.util import run_wsgi_app - - -class CapabilitiesHandler(webapp.RequestHandler): - """Handler to forward a request ot a handler of a robot.""" - - def __init__(self, method, contenttype): - """Initializes this handler with a specific robot.""" - self._method = method - self._contenttype = contenttype - - def get(self): - """Handles HTTP GET request.""" - self.response.headers['Content-Type'] = self._contenttype - self.response.out.write(self._method()) - -class ProfileHandler(webapp.RequestHandler): - """Handler to forward a request ot a handler of a robot.""" - - def __init__(self, method, contenttype): - """Initializes this handler with a specific robot.""" - self._method = method - self._contenttype = contenttype - - def get(self): - """Handles HTTP GET request.""" - self.response.headers['Content-Type'] = self._contenttype - # Respond with proxied profile if name specified - if self.request.get('name'): - self.response.out.write(self._method(self.request.get('name'))) - else: - self.response.out.write(self._method()) - -class RobotEventHandler(webapp.RequestHandler): - """Handler for the dispatching of events to various handlers to a robot. - - This handler only responds to post events with a JSON post body. Its primary - task is to separate out the context data from the events in the post body - and dispatch all events in order. Once all events have been dispatched - it serializes the context data and its associated operations as a response. - """ - - def __init__(self, robot): - """Initializes self with a specific robot.""" - self._robot = robot - - def get(self): - """Handles the get event for debugging. - - This is useful for debugging but since event bundles tend to be - rather big it often won't fit for more complex requests. - """ - ops = self.request.get('events') - if ops: - self.request.body = events - self.post() - - def post(self): - """Handles HTTP POST requests.""" - json_body = self.request.body - if not json_body: - # TODO(davidbyttow): Log error? - return - - # Redirect stdout to stderr while executing handlers. This way, any stray - # "print" statements in bot code go to the error logs instead of breaking - # the JSON response sent to the HTTP channel. - saved_stdout, sys.stdout = sys.stdout, sys.stderr - - json_body = unicode(json_body, 'utf8') - logging.info('Incoming: %s', json_body) - json_response = self._robot.process_events(json_body) - logging.info('Outgoing: %s', json_response) - - sys.stdout = saved_stdout - - # Build the response. - self.response.headers['Content-Type'] = 'application/json; charset=utf-8' - self.response.out.write(json_response.encode('utf-8')) - - -def operation_error_handler(event, wavelet): - """Default operation error handler, logging what went wrong.""" - if isinstance(event, events.OperationError): - logging.error('Previously operation failed: id=%s, message: %s', - event.operation_id, event.error_message) - - -def appengine_post(url, data, headers): - result = urlfetch.fetch( - method='POST', - url=url, - payload=data, - headers=headers, - deadline=10) - return result.status_code, result.content - - -class RobotVerifyTokenHandler(webapp.RequestHandler): - """Handler for the token_verify request.""" - - def __init__(self, robot): - """Initializes self with a specific robot.""" - self._robot = robot - - def get(self): - """Handles the get event for debugging. Ops usually too long.""" - token, st = self._robot.get_verification_token_info() - logging.info('token=' + token) - if token is None: - self.error(404) - self.response.out.write('No token set') - return - if st is not None: - if self.request.get('st') != st: - self.response.out.write('Invalid st value passed') - return - self.response.out.write(token) - - -def create_robot_webapp(robot, debug=False, extra_handlers=None): - """Returns an instance of webapp.WSGIApplication with robot handlers.""" - if not extra_handlers: - extra_handlers = [] - return webapp.WSGIApplication([('.*/_wave/capabilities.xml', - lambda: CapabilitiesHandler( - robot.capabilities_xml, - 'application/xml')), - ('.*/_wave/robot/profile', - lambda: ProfileHandler( - robot.profile_json, - 'application/json')), - ('.*/_wave/robot/jsonrpc', - lambda: RobotEventHandler(robot)), - ('.*/_wave/verify_token', - lambda: RobotVerifyTokenHandler(robot)), - ] + extra_handlers, - debug=debug) - - -def run(robot, debug=False, log_errors=True, extra_handlers=None): - """Sets up the webapp handlers for this robot and starts listening. - - A robot is typically setup in the following steps: - 1. Instantiate and define robot. - 2. Register various handlers that it is interested in. - 3. Call Run, which will setup the handlers for the app. - For example: - robot = Robot('Terminator', - image_url='http://www.sky.net/models/t800.png', - profile_url='http://www.sky.net/models/t800.html') - robot.register_handler(WAVELET_PARTICIPANTS_CHANGED, KillParticipant) - run(robot) - - Args: - robot: the robot to run. This robot is modified to use app engines - urlfetch for posting http. - debug: Optional variable that defaults to False and is passed through - to the webapp application to determine if it should show debug info. - log_errors: Optional flag that defaults to True and determines whether - a default handlers to catch errors should be setup that uses the - app engine logging to log errors. - extra_handlers: Optional list of tuples that are passed to the webapp - to install more handlers. For example, passing - [('/about', AboutHandler),] would install an extra about handler - for the robot. - """ - # App Engine expects to construct a class with no arguments, so we - # pass a lambda that constructs the appropriate handler with - # arguments from the enclosing scope. - if log_errors: - robot.register_handler(events.OperationError, operation_error_handler) - robot.set_http_post(appengine_post) - app = create_robot_webapp(robot, debug, extra_handlers) - run_wsgi_app(app) http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/blip.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/blip.py b/wave/src/main/java/python/api/blip.py deleted file mode 100644 index 7f103d9..0000000 --- a/wave/src/main/java/python/api/blip.py +++ /dev/null @@ -1,949 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -import UserDict - -import element -import errors - -import util - -class Annotation(object): - """Models an annotation on a document. - - Annotations are key/value pairs over a range of content. Annotations - can be used to store data or to be interpreted by a client when displaying - the data. - """ - - # Use the following constants to control the display of the client - - #: Reserved annotation for setting background color of text. - BACKGROUND_COLOR = "style/backgroundColor" - #: Reserved annotation for setting color of text. - COLOR = "style/color" - #: Reserved annotation for setting font family of text. - FONT_FAMILY = "style/fontFamily" - #: Reserved annotation for setting font family of text. - FONT_SIZE = "style/fontSize" - #: Reserved annotation for setting font style of text. - FONT_STYLE = "style/fontStyle" - #: Reserved annotation for setting font weight of text. - FONT_WEIGHT = "style/fontWeight" - #: Reserved annotation for setting text decoration. - TEXT_DECORATION = "style/textDecoration" - #: Reserved annotation for setting vertical alignment. - VERTICAL_ALIGN = "style/verticalAlign" - #: Reserved annotation for setting link. - LINK = "link/manual" - - def __init__(self, name, value, start, end): - self._name = name - self._value = value - self._start = start - self._end = end - - @property - def name(self): - return self._name - - @property - def value(self): - return self._value - - @property - def start(self): - return self._start - - @property - def end(self): - return self._end - - def _shift(self, where, inc): - """Shift annotation by 'inc' if it (partly) overlaps with 'where'.""" - if self._start >= where: - self._start += inc - if self._end >= where: - self._end += inc - - def serialize(self): - """Serializes the annotation. - - Returns: - A dict containing the name, value, and range values. - """ - return {'name': self._name, - 'value': self._value, - 'range': {'start': self._start, - 'end': self._end}} - - -class Annotations(object, UserDict.DictMixin): - """A dictionary-like object containing the annotations, keyed by name.""" - - def __init__(self, operation_queue, blip): - self._operation_queue = operation_queue - self._blip = blip - self._store = {} - - def __contains__(self, what): - if isinstance(what, Annotation): - what = what.name - return what in self._store - - def _add_internal(self, name, value, start, end): - """Internal add annotation does not send out operations.""" - if name in self._store: - # TODO: use bisect to make this more efficient. - new_list = [] - for existing in self._store[name]: - if start > existing.end or end < existing.start: - new_list.append(existing) - else: - if existing.value == value: - # merge the annotations: - start = min(existing.start, start) - end = max(existing.end, end) - else: - # chop the bits off the existing annotation - if existing.start < start: - new_list.append(Annotation( - existing.name, existing.value, existing.start, start)) - if existing.end > end: - new_list.append(Annotation( - existing.name, existing.value, existing.end, end)) - new_list.append(Annotation(name, value, start, end)) - self._store[name] = new_list - else: - self._store[name] = [Annotation(name, value, start, end)] - - def _delete_internal(self, name, start=0, end=-1): - """Remove the passed annotaion from the internal representation.""" - if not name in self._store: - return - if end < 0: - end = len(self._blip) + end - - new_list = [] - for a in self._store[name]: - if start > a.end or end < a.start: - new_list.append(a) - elif start < a.start and end > a.end: - continue - else: - if a.start < start: - new_list.append(Annotation(name, a.value, a.start, start)) - if a.end > end: - new_list.append(Annotation(name, a.value, end, a.end)) - if new_list: - self._store[name] = new_list - else: - del self._store[name] - - def _shift(self, where, inc): - """Shift annotation by 'inc' if it (partly) overlaps with 'where'.""" - for annotations in self._store.values(): - for annotation in annotations: - annotation._shift(where, inc) - - # Merge fragmented annotations that should be contiguous, for example: - # Annotation('foo', 'bar', 1, 2) and Annotation('foo', 'bar', 2, 3). - for name, annotations in self._store.items(): - new_list = [] - for i, annotation in enumerate(annotations): - name = annotation.name - value = annotation.value - start = annotation.start - end = annotation.end - - # Find the last end index. - for j, next_annotation in enumerate(annotations[i + 1:]): - # Not contiguous, skip. - if (end < next_annotation.start): - break - - # Contiguous, merge. - if (end == next_annotation.start and value == next_annotation.value): - end = next_annotation.end - del annotations[j] - new_list.append(Annotation(name, value, start, end)) - self._store[name] = new_list - - def __len__(self): - return len(self._store) - - def __getitem__(self, key): - return self._store[key] - - def __iter__(self): - for l in self._store.values(): - for ann in l: - yield ann - - def names(self): - """Return the names of the annotations in the store.""" - return self._store.keys() - - def serialize(self): - """Return a list of the serialized annotations.""" - res = [] - for v in self._store.values(): - res += [a.serialize() for a in v] - return res - - -class Blips(object, UserDict.DictMixin): - """A dictionary-like object containing the blips, keyed on blip ID.""" - - def __init__(self, blips): - self._blips = blips - - def __contains__(self, blip_id): - return blip_id in self._blips - - def __getitem__(self, blip_id): - return self._blips[blip_id] - - def __iter__(self): - return self._blips.__iter__() - - def __len__(self): - return len(self._blips) - - def _add(self, ablip): - self._blips[ablip.blip_id] = ablip - - def _remove_with_id(self, blip_id): - del_blip = self._blips[blip_id] - if del_blip: - # Remove the reference to this blip from its parent. - parent_blip = self._blips[blip_id].parent_blip - if parent_blip: - parent_blip._child_blip_ids.remove(blip_id) - del self._blips[blip_id] - - def get(self, blip_id, default_value=None): - """Retrieves a blip. - - Returns: - A Blip object. If none found for the ID, it returns None, - or if default_value is specified, it returns that. - """ - return self._blips.get(blip_id, default_value) - - def serialize(self): - """Serializes the blips. - Returns: - A dict of serialized blips. - """ - res = {} - for blip_id, item in self._blips.items(): - res[blip_id] = item.serialize() - return res - - def values(self): - """Return the blips themselves.""" - return self._blips.values() - - -class BlipRefs(object): - """Represents a set of references to contents in a blip. - - For example, a BlipRefs instance can represent the results - of a search, an explicitly set range, a regular expression, - or refer to the entire blip. BlipRefs are used to express - operations on a blip in a consistent way that can easily - be transfered to the server. - - The typical way of creating a BlipRefs object is to use - selector methods on the Blip object. Developers will not - usually instantiate a BlipRefs object directly. - """ - - DELETE = 'DELETE' - REPLACE = 'REPLACE' - INSERT = 'INSERT' - INSERT_AFTER = 'INSERT_AFTER' - ANNOTATE = 'ANNOTATE' - CLEAR_ANNOTATION = 'CLEAR_ANNOTATION' - UPDATE_ELEMENT = 'UPDATE_ELEMENT' - - def __init__(self, blip, maxres=1): - self._blip = blip - self._maxres = maxres - - @classmethod - def all(cls, blip, findwhat, maxres=-1, **restrictions): - """Construct an instance representing the search for text or elements.""" - obj = cls(blip, maxres) - obj._findwhat = findwhat - obj._restrictions = restrictions - obj._hits = lambda: obj._find(findwhat, maxres, **restrictions) - if findwhat is None: - # No findWhat, take the entire blip - obj._params = {} - else: - query = {'maxRes': maxres} - if isinstance(findwhat, basestring): - query['textMatch'] = findwhat - else: - query['elementMatch'] = findwhat.class_type - query['restrictions'] = restrictions - obj._params = {'modifyQuery': query} - return obj - - @classmethod - def range(cls, blip, begin, end): - """Constructs an instance representing an explicitly set range.""" - obj = cls(blip) - obj._begin = begin - obj._end = end - obj._hits = lambda: [(begin, end)] - obj._params = {'range': {'start': begin, 'end': end}} - return obj - - def _elem_matches(self, elem, clz, **restrictions): - if not isinstance(elem, clz): - return False - for key, val in restrictions.items(): - if getattr(elem, key) != val: - return False - return True - - def _find(self, what, maxres=-1, **restrictions): - """Iterates where 'what' occurs in the associated blip. - - What can be either a string or a class reference. - Examples: - self._find('hello') will return the first occurence of the word hello - self._find(element.Gadget, url='http://example.com/gadget.xml') - will return the first gadget that has as url example.com. - - Args: - what: what to search for. Can be a class or a string. The class - should be an element from element.py - maxres: number of results to return at most, or <= 0 for all. - restrictions: if what specifies a class, further restrictions - of the found instances. - Yields: - Tuples indicating the range of the matches. For a one - character/element match at position x, (x, x+1) is yielded. - """ - blip = self._blip - if what is None: - yield 0, len(blip) - raise StopIteration - if isinstance(what, basestring): - idx = blip._content.find(what) - count = 0 - while idx != -1: - yield idx, idx + len(what) - count += 1 - if count == maxres: - raise StopIteration - idx = blip._content.find(what, idx + len(what)) - else: - count = 0 - for idx, el in blip._elements.items(): - if self._elem_matches(el, what, **restrictions): - yield idx, idx + 1 - count += 1 - if count == maxres: - raise StopIteration - - def _execute(self, modify_how, what, bundled_annotations=None): - """Executes this BlipRefs object. - - Args: - modify_how: What to do. Any of the operation declared at the top. - what: Depending on the operation. For delete, has to be None. - For the others it is a singleton, a list or a function returning - what to do; for ANNOTATE tuples of (key, value), for the others - either string or elements. - If what is a function, it takes three parameters, the content of - the blip, the beginning of the matching range and the end. - bundled_annotations: Annotations to apply immediately. - Raises: - IndexError when trying to access content outside of the blip. - ValueError when called with the wrong values. - Returns: - self for chainability. - """ - blip = self._blip - - if modify_how != BlipRefs.DELETE: - if not isinstance(what, list): - what = [what] - next_index = 0 - - matched = [] - # updated_elements is used to store the element type of the - # element to update - updated_elements = [] - - # For now, if we find one markup, we'll use it everywhere. - next = None - hit_found = False - - for start, end in self._hits(): - hit_found = True - if start < 0: - start += len(blip) - if end == 0: - end += len(blip) - if end < 0: - end += len(blip) - if len(blip) == 0: - if start != 0 or end != 0: - raise IndexError('Start and end have to be 0 for empty document') - elif start < 0 or end < 1 or start >= len(blip) or end > len(blip): - raise IndexError('Position outside the document') - if modify_how == BlipRefs.DELETE: - for i in range(start, end): - if i in blip._elements: - del blip._elements[i] - blip._delete_annotations(start, end) - blip._shift(end, start - end) - blip._content = blip._content[:start] + blip._content[end:] - else: - if callable(what): - next = what(blip._content, start, end) - matched.append(next) - else: - next = what[next_index] - next_index = (next_index + 1) % len(what) - if isinstance(next, str): - next = util.force_unicode(next) - if modify_how == BlipRefs.ANNOTATE: - key, value = next - blip.annotations._add_internal(key, value, start, end) - elif modify_how == BlipRefs.CLEAR_ANNOTATION: - blip.annotations._delete_internal(next, start, end) - elif modify_how == BlipRefs.UPDATE_ELEMENT: - el = blip._elements.get(start) - if not el: - raise ValueError('No element found at index %s' % start) - # the passing around of types this way feels a bit dirty: - updated_elements.append(element.Element.from_json({'type': el.type, - 'properties': next})) - for k, b in next.items(): - setattr(el, k, b) - else: - if modify_how == BlipRefs.INSERT: - end = start - elif modify_how == BlipRefs.INSERT_AFTER: - start = end - elif modify_how == BlipRefs.REPLACE: - pass - else: - raise ValueError('Unexpected modify_how: ' + modify_how) - - if isinstance(next, element.Element): - text = ' ' - else: - text = next - - # in the case of a replace, and the replacement text is shorter, - # delete the delta. - if start != end and len(text) < end - start: - blip._delete_annotations(start + len(text), end) - - blip._shift(end, len(text) + start - end) - blip._content = blip._content[:start] + text + blip._content[end:] - if bundled_annotations: - end_annotation = start + len(text) - blip._delete_annotations(start, end_annotation) - for key, value in bundled_annotations: - blip.annotations._add_internal(key, value, start, end_annotation) - - if isinstance(next, element.Element): - blip._elements[start] = next - - # No match found, return immediately without generating op. - if not hit_found: - return - - operation = blip._operation_queue.document_modify(blip.wave_id, - blip.wavelet_id, - blip.blip_id) - for param, value in self._params.items(): - operation.set_param(param, value) - - modify_action = {'modifyHow': modify_how} - if modify_how == BlipRefs.DELETE: - pass - elif modify_how == BlipRefs.UPDATE_ELEMENT: - modify_action['elements'] = updated_elements - elif (modify_how == BlipRefs.REPLACE or - modify_how == BlipRefs.INSERT or - modify_how == BlipRefs.INSERT_AFTER): - if callable(what): - what = matched - if what: - if not isinstance(next, element.Element): - modify_action['values'] = [util.force_unicode(value) for value in what] - else: - modify_action['elements'] = what - elif modify_how == BlipRefs.ANNOTATE: - modify_action['values'] = [x[1] for x in what] - modify_action['annotationKey'] = what[0][0] - elif modify_how == BlipRefs.CLEAR_ANNOTATION: - modify_action['annotationKey'] = what[0] - if bundled_annotations: - modify_action['bundledAnnotations'] = [ - {'key': key, 'value': value} for key, value in bundled_annotations] - operation.set_param('modifyAction', modify_action) - - return self - - def insert(self, what, bundled_annotations=None): - """Inserts what at the matched positions.""" - return self._execute( - BlipRefs.INSERT, what, bundled_annotations=bundled_annotations) - - def insert_after(self, what, bundled_annotations=None): - """Inserts what just after the matched positions.""" - return self._execute( - BlipRefs.INSERT_AFTER, what, bundled_annotations=bundled_annotations) - - def replace(self, what, bundled_annotations=None): - """Replaces the matched positions with what.""" - return self._execute( - BlipRefs.REPLACE, what, bundled_annotations=bundled_annotations) - - def delete(self): - """Deletes the content at the matched positions.""" - return self._execute(BlipRefs.DELETE, None) - - def annotate(self, name, value=None): - """Annotates the content at the matched positions. - - You can either specify both name and value to set the - same annotation, or supply as the first parameter something - that yields name/value pairs. The name and value should both be strings. - """ - if value is None: - what = name - else: - what = (name, value) - return self._execute(BlipRefs.ANNOTATE, what) - - def clear_annotation(self, name): - """Clears the annotation at the matched positions.""" - return self._execute(BlipRefs.CLEAR_ANNOTATION, name) - - def update_element(self, new_values): - """Update an existing element with a set of new values. - - For example, this code would update a button value: - button.update_element({'value': 'Yes'}) - This code would update the 'seen' key in a gadget's state: - gadget.update_element({'seen': 'yes'}) - - Args: - new_values: A dictionary of property names and values. - """ - return self._execute(BlipRefs.UPDATE_ELEMENT, new_values) - - def __nonzero__(self): - """Return whether we have a value.""" - for start, end in self._hits(): - return True - return False - - def value(self): - """Convenience method to convert a BlipRefs to value of its first match.""" - for start, end in self._hits(): - if end - start == 1 and start in self._blip._elements: - return self._blip._elements[start] - else: - return self._blip.text[start:end] - raise ValueError('BlipRefs has no values') - - def __getattr__(self, attribute): - """Mirror the getattr of value(). - - This allows for clever things like - first(IMAGE).url - - or - - blip.annotate_with(key, value).upper() - """ - return getattr(self.value(), attribute) - - def __radd__(self, other): - """Make it possible to add this to a string.""" - return other + self.value() - - def __cmp__(self, other): - """Support comparision with target.""" - return cmp(self.value(), other) - - def __iter__(self): - for start_end in self._hits(): - yield start_end - - -class Blip(object): - """Models a single blip instance. - - Blips are essentially the documents that make up a conversation. Blips can - live in a hierarchy of blips. A root blip has no parent blip id, but all - blips have the ids of the wave and wavelet that they are associated with. - - Blips also contain annotations, content and elements, which are accessed via - the Document object. - """ - - def __init__(self, json, other_blips, operation_queue, thread=None, - reply_threads=None): - """Inits this blip with JSON data. - - Args: - json: JSON data dictionary from Wave server. - other_blips: A dictionary like object that can be used to resolve - ids of blips to blips. - thread: The BlipThread object that this blip belongs to. - reply_threads: A list BlipThread objects that are replies to this blip. - operation_queue: An OperationQueue object to store generated operations - in. - """ - self._blip_id = json.get('blipId') - self._reply_threads = reply_threads or [] - self._thread = thread - self._operation_queue = operation_queue - self._child_blip_ids = list(json.get('childBlipIds', [])) - self._content = json.get('content', '') - self._contributors = set(json.get('contributors', [])) - self._creator = json.get('creator') - self._last_modified_time = json.get('lastModifiedTime', 0) - self._version = json.get('version', 0) - self._parent_blip_id = json.get('parentBlipId') - self._wave_id = json.get('waveId') - self._wavelet_id = json.get('waveletId') - if isinstance(other_blips, Blips): - self._other_blips = other_blips - else: - self._other_blips = Blips(other_blips) - self._annotations = Annotations(operation_queue, self) - for annjson in json.get('annotations', []): - r = annjson['range'] - self._annotations._add_internal(annjson['name'], - annjson['value'], - r['start'], - r['end']) - self._elements = {} - json_elements = json.get('elements', {}) - for elem in json_elements: - self._elements[int(elem)] = element.Element.from_json(json_elements[elem]) - self.raw_data = json - - @property - def blip_id(self): - """The id of this blip.""" - return self._blip_id - - @property - def wave_id(self): - """The id of the wave that this blip belongs to.""" - return self._wave_id - - @property - def wavelet_id(self): - """The id of the wavelet that this blip belongs to.""" - return self._wavelet_id - - @property - def child_blip_ids(self): - """The list of the ids of this blip's children.""" - return self._child_blip_ids - - @property - def child_blips(self): - """The list of blips that are children of this blip.""" - return [self._other_blips[blid_id] for blid_id in self._child_blip_ids - if blid_id in self._other_blips] - - @property - def thread(self): - """The thread that this blip belongs to.""" - return self._thread - - @property - def reply_threads(self): - """The list of threads that are replies to this blip.""" - return self._reply_threads - - @property - def inline_reply_threads(self): - # TODO: Consider moving to constructor - inline_reply_threads = [] - for reply_thread in self._reply_threads: - if reply_thread.location > -1: - inline_reply_threads.append(reply_thread) - return inline_reply_threads - - @property - def contributors(self): - """The set of participant ids that contributed to this blip.""" - return self._contributors - - @property - def creator(self): - """The id of the participant that created this blip.""" - return self._creator - - @property - def last_modified_time(self): - """The time in seconds since epoch when this blip was last modified.""" - return self._last_modified_time - - @property - def version(self): - """The version of this blip.""" - return self._version - - @property - def parent_blip_id(self): - """The parent blip_id or None if this is the root blip.""" - return self._parent_blip_id - - @property - def parent_blip(self): - """The parent blip or None if it is the root.""" - # if parent_blip_id is None, get will also return None - return self._other_blips.get(self._parent_blip_id) - - @property - def inline_blip_offset(self): - """The offset in the parent if this blip is inline or -1 if not. - - If the parent is not in the context, this function will always - return -1 since it can't determine the inline blip status. - """ - parent = self.parent_blip - if not parent: - return -1 - for offset, el in parent._elements.items(): - if el.type == element.Element.INLINE_BLIP_TYPE and el.id == self.blip_id: - return offset - return -1 - - def is_root(self): - """Returns whether this is the root blip of a wavelet.""" - return self._parent_blip_id is None - - @property - def annotations(self): - """The annotations for this document.""" - return self._annotations - - @property - def elements(self): - """Returns a list of elements for this document. - The elements of a blip are things like forms elements and gadgets - that cannot be expressed as plain text. In the text of the blip, you'll - typically find a space as a place holder for the element. - If you want to retrieve the element at a particular index in the blip, use - blip[index].value(). - """ - return self._elements.values() - - def __len__(self): - return len(self._content) - - def __getitem__(self, item): - """returns a BlipRefs for the given slice.""" - if isinstance(item, slice): - if item.step: - raise errors.Error('Step not supported for blip slices') - return self.range(item.start, item.stop) - else: - return self.at(item) - - def __setitem__(self, item, value): - """short cut for self.range/at().replace(value).""" - self.__getitem__(item).replace(value) - - def __delitem__(self, item): - """short cut for self.range/at().delete().""" - self.__getitem__(item).delete() - - def _shift(self, where, inc): - """Move element and annotations after 'where' up by 'inc'.""" - new_elements = {} - for idx, el in self._elements.items(): - if idx >= where: - idx += inc - new_elements[idx] = el - self._elements = new_elements - self._annotations._shift(where, inc) - - def _delete_annotations(self, start, end): - """Delete all annotations between 'start' and 'end'.""" - for annotation_name in self._annotations.names(): - self._annotations._delete_internal(annotation_name, start, end) - - def all(self, findwhat=None, maxres=-1, **restrictions): - """Returns a BlipRefs object representing all results for the search. - If searching for an element, the restrictions can be used to specify - additional element properties to filter on, like the url of a Gadget. - """ - return BlipRefs.all(self, findwhat, maxres, **restrictions) - - def first(self, findwhat=None, **restrictions): - """Returns a BlipRefs object representing the first result for the search. - If searching for an element, the restrictions can be used to specify - additional element properties to filter on, like the url of a Gadget. - """ - return BlipRefs.all(self, findwhat, 1, **restrictions) - - def at(self, index): - """Returns a BlipRefs object representing a 1-character range.""" - return BlipRefs.range(self, index, index + 1) - - def range(self, start, end): - """Returns a BlipRefs object representing the range.""" - return BlipRefs.range(self, start, end) - - def serialize(self): - """Return a dictionary representation of this blip ready for json.""" - return {'blipId': self._blip_id, - 'childBlipIds': list(self._child_blip_ids), - 'content': self._content, - 'creator': self._creator, - 'contributors': list(self._contributors), - 'lastModifiedTime': self._last_modified_time, - 'version': self._version, - 'parentBlipId': self._parent_blip_id, - 'waveId': self._wave_id, - 'waveletId': self._wavelet_id, - 'annotations': self._annotations.serialize(), - 'elements': dict([(index, e.serialize()) - for index, e in self._elements.items()]) - } - - def proxy_for(self, proxy_for_id): - """Return a view on this blip that will proxy for the specified id. - - A shallow copy of the current blip is returned with the proxy_for_id - set. Any modifications made to this copy will be done using the - proxy_for_id, i.e. the robot+<proxy_for_id>@appspot.com address will - be used. - """ - util.check_is_valid_proxy_for_id(proxy_for_id) - operation_queue = self._operation_queue.proxy_for(proxy_for_id) - res = Blip(json={}, - other_blips={}, - operation_queue=operation_queue) - res._blip_id = self._blip_id - res._child_blip_ids = self._child_blip_ids - res._content = self._content - res._contributors = self._contributors - res._creator = self._creator - res._last_modified_time = self._last_modified_time - res._version = self._version - res._parent_blip_id = self._parent_blip_id - res._wave_id = self._wave_id - res._wavelet_id = self._wavelet_id - res._other_blips = self._other_blips - res._annotations = self._annotations - res._elements = self._elements - res.raw_data = self.raw_data - return res - - @property - def text(self): - """Returns the raw text content of this document.""" - return self._content - - def find(self, what, **restrictions): - """Iterate to matching bits of contents. - - Yield either elements or pieces of text. - """ - br = BlipRefs.all(self, what, **restrictions) - for start, end in br._hits(): - if end - start == 1 and start in self._elements: - yield self._elements[start] - else: - yield self._content[start:end] - raise StopIteration - - def append(self, what, bundled_annotations=None): - """Convenience method covering a common pattern.""" - return BlipRefs.all(self, findwhat=None).insert_after( - what, bundled_annotations=bundled_annotations) - - def continue_thread(self): - """Create and return a blip in the same thread as this blip.""" - blip_data = self._operation_queue.blip_continue_thread(self.wave_id, - self.wavelet_id, - self.blip_id) - new_blip = Blip(blip_data, self._other_blips, self._operation_queue, - thread=self._thread) - if self._thread: - self._thread._add_internal(new_blip) - self._other_blips._add(new_blip) - return new_blip - - def reply(self): - """Create and return a reply to this blip.""" - blip_data = self._operation_queue.blip_create_child(self.wave_id, - self.wavelet_id, - self.blip_id) - new_blip = Blip(blip_data, self._other_blips, self._operation_queue) - self._other_blips._add(new_blip) - return new_blip - - def append_markup(self, markup): - """Interpret the markup text as xhtml and append the result to the doc. - - Args: - markup: The markup'ed text to append. - """ - markup = util.force_unicode(markup) - self._operation_queue.document_append_markup(self.wave_id, - self.wavelet_id, - self.blip_id, - markup) - self._content += util.parse_markup(markup) - - def insert_inline_blip(self, position): - """Inserts an inline blip into this blip at a specific position. - - Args: - position: Position to insert the blip at. This has to be greater than 0. - - Returns: - The JSON data of the blip that was created. - """ - if position <= 0: - raise IndexError(('Illegal inline blip position: %d. Position has to ' + - 'be greater than 0.') % position) - - blip_data = self._operation_queue.document_inline_blip_insert( - self.wave_id, - self.wavelet_id, - self.blip_id, - position) - new_blip = Blip(blip_data, self._other_blips, self._operation_queue) - self._other_blips._add(new_blip) - return new_blip http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/blip_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/blip_test.py b/wave/src/main/java/python/api/blip_test.py deleted file mode 100644 index 7cd66e0..0000000 --- a/wave/src/main/java/python/api/blip_test.py +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Unit tests for the blip module.""" - - -import unittest - -import blip -import element -import ops -import simplejson - -TEST_BLIP_DATA = { - 'childBlipIds': [], - 'content': '\nhello world!\nanother line', - 'contributors': ['[email protected]', '[email protected]'], - 'creator': '[email protected]', - 'lastModifiedTime': 1000, - 'parentBlipId': None, - 'annotations': [{'range': {'start': 2, 'end': 3}, - 'name': 'key', 'value': 'val'}], - 'waveId': 'test.com!w+g3h3im', - 'waveletId': 'test.com!root+conv', - 'elements':{'14':{'type':'GADGET','properties':{'url':'http://a/b.xml'}}}, -} - -CHILD_BLIP_ID = 'b+42' -ROOT_BLIP_ID = 'b+43' - - -class TestBlip(unittest.TestCase): - """Tests the primary data structures for the wave model.""" - - def assertBlipStartswith(self, expected, totest): - actual = totest.text[:len(expected)] - self.assertEquals(expected, actual) - - def new_blip(self, **args): - """Create a blip for testing.""" - data = TEST_BLIP_DATA.copy() - data.update(args) - res = blip.Blip(data, self.all_blips, self.operation_queue) - self.all_blips[res.blip_id] = res - return res - - def setUp(self): - self.all_blips = {} - self.operation_queue = ops.OperationQueue() - - def testBlipProperties(self): - root = self.new_blip(blipId=ROOT_BLIP_ID, - childBlipIds=[CHILD_BLIP_ID]) - child = self.new_blip(blipId=CHILD_BLIP_ID, - parentBlipId=ROOT_BLIP_ID) - self.assertEquals(ROOT_BLIP_ID, root.blip_id) - self.assertEquals([CHILD_BLIP_ID], root.child_blip_ids) - self.assertEquals(set(TEST_BLIP_DATA['contributors']), root.contributors) - self.assertEquals(TEST_BLIP_DATA['creator'], root.creator) - self.assertEquals(TEST_BLIP_DATA['content'], root.text) - self.assertEquals(TEST_BLIP_DATA['lastModifiedTime'], - root.last_modified_time) - self.assertEquals(TEST_BLIP_DATA['parentBlipId'], root.parent_blip_id) - self.assertEquals(TEST_BLIP_DATA['waveId'], root.wave_id) - self.assertEquals(TEST_BLIP_DATA['waveletId'], root.wavelet_id) - self.assertEquals(TEST_BLIP_DATA['content'][3], root[3]) - self.assertEquals(element.Gadget.class_type, root[14].type) - self.assertEquals('http://a/b.xml', root[14].url) - self.assertEquals('a', root.text[14]) - self.assertEquals(len(TEST_BLIP_DATA['content']), len(root)) - self.assertTrue(root.is_root()) - self.assertFalse(child.is_root()) - self.assertEquals(root, child.parent_blip) - - def testBlipSerialize(self): - root = self.new_blip(blipId=ROOT_BLIP_ID, - childBlipIds=[CHILD_BLIP_ID]) - serialized = root.serialize() - unserialized = blip.Blip(serialized, self.all_blips, self.operation_queue) - self.assertEquals(root.blip_id, unserialized.blip_id) - self.assertEquals(root.child_blip_ids, unserialized.child_blip_ids) - self.assertEquals(root.contributors, unserialized.contributors) - self.assertEquals(root.creator, unserialized.creator) - self.assertEquals(root.text, unserialized.text) - self.assertEquals(root.last_modified_time, unserialized.last_modified_time) - self.assertEquals(root.parent_blip_id, unserialized.parent_blip_id) - self.assertEquals(root.wave_id, unserialized.wave_id) - self.assertEquals(root.wavelet_id, unserialized.wavelet_id) - self.assertTrue(unserialized.is_root()) - - def testDocumentOperations(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - newlines = [x for x in blip.find('\n')] - self.assertEquals(2, len(newlines)) - blip.first('world').replace('jupiter') - bits = blip.text.split('\n') - self.assertEquals(3, len(bits)) - self.assertEquals('hello jupiter!', bits[1]) - blip.range(2, 5).delete() - self.assertBlipStartswith('\nho jupiter', blip) - - blip.first('ho').insert_after('la') - self.assertBlipStartswith('\nhola jupiter', blip) - blip.at(3).insert(' ') - self.assertBlipStartswith('\nho la jupiter', blip) - - def testElementHandling(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - url = 'http://www.test.com/image.png' - - org_len = len(blip) - blip.append(element.Image(url=url)) - - elems = [elem for elem in blip.find(element.Image, url=url)] - self.assertEquals(1, len(elems)) - elem = elems[0] - self.assertTrue(isinstance(elem, element.Image)) - blip.at(1).insert('twelve chars') - self.assertTrue(blip.text.startswith('\ntwelve charshello')) - - elem = blip[org_len + 12].value() - self.assertTrue(isinstance(elem, element.Image)) - - blip.first('twelve ').delete() - self.assertTrue(blip.text.startswith('\nchars')) - - elem = blip[org_len + 12 - len('twelve ')].value() - self.assertTrue(isinstance(elem, element.Image)) - - blip.first('chars').replace(element.Image(url=url)) - elems = [elem for elem in blip.find(element.Image, url=url)] - self.assertEquals(2, len(elems)) - self.assertTrue(blip.text.startswith('\n hello')) - elem = blip[1].value() - self.assertTrue(isinstance(elem, element.Image)) - - def testAnnotationHandling(self): - key = 'style/fontWeight' - - def get_bold(): - for an in blip.annotations[key]: - if an.value == 'bold': - return an - return None - - json = ('[{"range":{"start":3,"end":6},"name":"%s","value":"bold"}]' - % key) - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json)) - self.assertEquals(1, len(blip.annotations)) - self.assertNotEqual(None, get_bold().value) - self.assertTrue(key in blip.annotations) - - # extend the bold annotation by adding: - blip.range(5, 8).annotate(key, 'bold') - self.assertEquals(1, len(blip.annotations)) - self.assertEquals(8, get_bold().end) - - # clip by adding a same keyed: - blip[4:12].annotate(key, 'italic') - self.assertEquals(2, len(blip.annotations[key])) - self.assertEquals(4, get_bold().end) - - # now split the italic one: - blip.range(6, 7).clear_annotation(key) - self.assertEquals(3, len(blip.annotations[key])) - - # test names and iteration - self.assertEquals(1, len(blip.annotations.names())) - self.assertEquals(3, len([x for x in blip.annotations])) - blip[3: 5].annotate('foo', 'bar') - self.assertEquals(2, len(blip.annotations.names())) - self.assertEquals(4, len([x for x in blip.annotations])) - blip[3: 5].clear_annotation('foo') - - # clear the whole thing - blip.all().clear_annotation(key) - # getting to the key should now throw an exception - self.assertRaises(KeyError, blip.annotations.__getitem__, key) - - def testBlipOperations(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - self.assertEquals(1, len(self.all_blips)) - - otherblip = blip.reply() - otherblip.append('hello world') - self.assertEquals('hello world', otherblip.text) - self.assertEquals(blip.blip_id, otherblip.parent_blip_id) - self.assertEquals(2, len(self.all_blips)) - - another = blip.continue_thread() - another.append('hello world') - self.assertEquals('hello world', another.text) - self.assertEquals(blip.parent_blip_id, another.parent_blip_id) - self.assertEquals(3, len(self.all_blips)) - - inline = blip.insert_inline_blip(3) - self.assertEquals(blip.blip_id, inline.parent_blip_id) - self.assertEquals(4, len(self.all_blips)) - - def testInsertInlineBlipCantInsertAtTheBeginning(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - self.assertEquals(1, len(self.all_blips)) - self.assertRaises(IndexError, blip.insert_inline_blip, 0) - self.assertEquals(1, len(self.all_blips)) - - def testDocumentModify(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - blip.all().replace('a text with text and then some text') - blip[7].insert('text ') - blip.all('text').replace('thing') - self.assertEquals('a thing thing with thing and then some thing', - blip.text) - - def testIteration(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - blip.all().replace('aaa 012 aaa 345 aaa 322') - count = 0 - prev = -1 - for start, end in blip.all('aaa'): - count += 1 - self.assertTrue(prev < start) - prev = start - self.assertEquals(3, count) - - - def testBlipRefValue(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - content = blip.text - content = content[:4] + content[5:] - del blip[4] - self.assertEquals(content, blip.text) - - content = content[:2] + content[3:] - del blip[2:3] - self.assertEquals(content, blip.text) - - blip[2:3] = 'bike' - content = content[:2] + 'bike' + content[3:] - self.assertEquals(content, blip.text) - - url = 'http://www.test.com/image.png' - blip.append(element.Image(url=url)) - self.assertEqual(url, blip.first(element.Image).url) - - url2 = 'http://www.test.com/another.png' - blip[-1].update_element({'url': url2}) - self.assertEqual(url2, blip.first(element.Image).url) - - self.assertTrue(blip[3:5] == blip.text[3:5]) - - blip.append('geheim') - self.assertTrue(blip.first('geheim')) - self.assertFalse(blip.first(element.Button)) - blip.append(element.Button(name='test1', value='Click')) - button = blip.first(element.Button) - button.update_element({'name': 'test2'}) - self.assertEqual('test2', button.name) - - def testReplace(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - blip.all().replace('\nxxxx') - blip.all('yyy').replace('zzz') - self.assertEqual('\nxxxx', blip.text) - - def testDeleteRangeThatSpansAcrossAnnotationEndPoint(self): - json = ('[{"range":{"start":1,"end":3},"name":"style","value":"bold"}]') - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json), - content='\nFoo bar.') - blip.range(2, 4).delete() - self.assertEqual('\nF bar.', blip.text) - self.assertEqual(1, blip.annotations['style'][0].start) - self.assertEqual(2, blip.annotations['style'][0].end) - - def testInsertBeforeAnnotationStartPoint(self): - json = ('[{"range":{"start":4,"end":9},"name":"style","value":"bold"}]') - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json), - content='\nFoo bar.') - blip.at(4).insert('d and') - self.assertEqual('\nFood and bar.', blip.text) - self.assertEqual(9, blip.annotations['style'][0].start) - self.assertEqual(14, blip.annotations['style'][0].end) - - def testDeleteRangeInsideAnnotation(self): - json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]') - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json), - content='\nFoo bar.') - blip.range(2, 4).delete() - - self.assertEqual('\nF bar.', blip.text) - self.assertEqual(1, blip.annotations['style'][0].start) - self.assertEqual(3, blip.annotations['style'][0].end) - - def testReplaceInsideAnnotation(self): - json = ('[{"range":{"start":1,"end":5},"name":"style","value":"bold"}]') - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json), - content='\nFoo bar.') - blip.range(2, 4).replace('ooo') - self.assertEqual('\nFooo bar.', blip.text) - self.assertEqual(1, blip.annotations['style'][0].start) - self.assertEqual(6, blip.annotations['style'][0].end) - - blip.range(2, 5).replace('o') - self.assertEqual('\nFo bar.', blip.text) - self.assertEqual(1, blip.annotations['style'][0].start) - self.assertEqual(4, blip.annotations['style'][0].end) - - def testReplaceSpanAnnotation(self): - json = ('[{"range":{"start":1,"end":4},"name":"style","value":"bold"}]') - blip = self.new_blip(blipId=ROOT_BLIP_ID, - annotations=simplejson.loads(json), - content='\nFoo bar.') - blip.range(2, 9).replace('') - self.assertEqual('\nF', blip.text) - self.assertEqual(1, blip.annotations['style'][0].start) - self.assertEqual(2, blip.annotations['style'][0].end) - - def testSearchWithNoMatchShouldNotGenerateOperation(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID) - self.assertEqual(-1, blip.text.find(':(')) - self.assertEqual(0, len(self.operation_queue)) - blip.all(':(').replace(':)') - self.assertEqual(0, len(self.operation_queue)) - - def testBlipsRemoveWithId(self): - blip_dict = { - ROOT_BLIP_ID: self.new_blip(blipId=ROOT_BLIP_ID, - childBlipIds=[CHILD_BLIP_ID]), - CHILD_BLIP_ID: self.new_blip(blipId=CHILD_BLIP_ID, - parentBlipId=ROOT_BLIP_ID) - } - blips = blip.Blips(blip_dict) - blips._remove_with_id(CHILD_BLIP_ID) - self.assertEqual(1, len(blips)) - self.assertEqual(0, len(blips[ROOT_BLIP_ID].child_blip_ids)) - - def testAppendMarkup(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.') - markup = '<p><span>markup<span> content</p>' - blip.append_markup(markup) - self.assertEqual(1, len(self.operation_queue)) - self.assertEqual('\nFoo bar.\nmarkup content', blip.text) - - def testBundledAnnotations(self): - blip = self.new_blip(blipId=ROOT_BLIP_ID, content='\nFoo bar.') - blip.append('not bold') - blip.append('bold', bundled_annotations=[('style/fontWeight', 'bold')]) - self.assertEqual(2, len(blip.annotations)) - self.assertEqual('bold', blip.annotations['style/fontWeight'][0].value) - - def testInlineBlipOffset(self): - offset = 14 - self.new_blip(blipId=ROOT_BLIP_ID, - childBlipIds=[CHILD_BLIP_ID], - elements={str(offset): - {'type': element.Element.INLINE_BLIP_TYPE, - 'properties': {'id': CHILD_BLIP_ID}}}) - child = self.new_blip(blipId=CHILD_BLIP_ID, - parentBlipId=ROOT_BLIP_ID) - self.assertEqual(offset, child.inline_blip_offset) - -if __name__ == '__main__': - unittest.main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/commandline_robot_runner.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/commandline_robot_runner.py b/wave/src/main/java/python/api/commandline_robot_runner.py deleted file mode 100644 index 9cb3eab..0000000 --- a/wave/src/main/java/python/api/commandline_robot_runner.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Run robot from the commandline for testing. - -This robot_runner let's you define event handlers using flags and takes the -json input from the std in and writes out the json output to stdout. - -for example - cat events | commandline_robot_runner.py \ - --eventdef-blip_submitted="wavelet.title='title'" -""" - -__author__ = '[email protected] (Douwe Osinga)' - -import sys -import urllib - -from google3.pyglib import app -from google3.pyglib import flags - -from google3.walkabout.externalagents import api - -from google3.walkabout.externalagents.api import blip -from google3.walkabout.externalagents.api import element -from google3.walkabout.externalagents.api import errors -from google3.walkabout.externalagents.api import events -from google3.walkabout.externalagents.api import ops -from google3.walkabout.externalagents.api import robot -from google3.walkabout.externalagents.api import util - -FLAGS = flags.FLAGS - -for event in events.ALL: - flags.DEFINE_string('eventdef_' + event.type.lower(), - '', - 'Event definition for the %s event' % event.type) - - -def handle_event(src, bot, e, w): - """Handle an event by executing the source code src.""" - globs = {'e': e, 'w': w, 'api': api, 'bot': bot, - 'blip': blip, 'element': element, 'errors': errors, - 'events': events, 'ops': ops, 'robot': robot, - 'util': util} - exec src in globs - - -def run_bot(input_file, output_file): - """Run a robot defined on the command line.""" - cmdbot = robot.Robot('Commandline bot') - for event in events.ALL: - src = getattr(FLAGS, 'eventdef_' + event.type.lower()) - src = urllib.unquote_plus(src) - if src: - cmdbot.register_handler(event, - lambda event, wavelet, src=src, bot=cmdbot: - handle_event(src, bot, event, wavelet)) - json_body = unicode(input_file.read(), 'utf8') - json_response = cmdbot.process_events(json_body) - output_file.write(json_response) - - -def main(argv): - run_bot(sys.stdin, sys.stdout) - -if __name__ == '__main__': - app.run() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/commandline_robot_runner_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/commandline_robot_runner_test.py b/wave/src/main/java/python/api/commandline_robot_runner_test.py deleted file mode 100644 index 3acbca5..0000000 --- a/wave/src/main/java/python/api/commandline_robot_runner_test.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Tests for google3.walkabout.externalagents.api.commandline_robot_runner.""" - -__author__ = '[email protected] (Douwe Osinga)' - -import StringIO - -from google3.pyglib import app -from google3.pyglib import flags - -from google3.testing.pybase import googletest -from google3.walkabout.externalagents.api import commandline_robot_runner -from google3.walkabout.externalagents.api import events - -FLAGS = flags.FLAGS - - -BLIP_JSON = ('{"wdykLROk*13":' - '{"lastModifiedTime":1242079608457,' - '"contributors":["[email protected]"],' - '"waveletId":"test.com!conv+root",' - '"waveId":"test.com!wdykLROk*11",' - '"parentBlipId":null,' - '"version":3,' - '"creator":"[email protected]",' - '"content":"\\nContent!",' - '"blipId":"wdykLROk*13",' - '"annotations":[{"range":{"start":0,"end":1},' - '"name":"user/e/[email protected]","value":"Other"}],' - '"elements":{},' - '"childBlipIds":[]}' - '}') - -WAVELET_JSON = ('{"lastModifiedTime":1242079611003,' - '"title":"A title",' - '"waveletId":"test.com!conv+root",' - '"rootBlipId":"wdykLROk*13",' - '"dataDocuments":null,' - '"creationTime":1242079608457,' - '"waveId":"test.com!wdykLROk*11",' - '"participants":["[email protected]","[email protected]"],' - '"creator":"[email protected]",' - '"rootThread": ' - '{"id":"", "location": "-1", "blipIds": ["wdykLROk*13"]},' - '"version":5}') - -EVENTS_JSON = ('[{"timestamp":1242079611003,' - '"modifiedBy":"[email protected]",' - '"properties":{"participantsRemoved":[],' - '"participantsAdded":["[email protected]"]},' - '"type":"WAVELET_PARTICIPANTS_CHANGED"}]') - -TEST_JSON = '{"blips":%s,"wavelet":%s,"events":%s}' % ( - BLIP_JSON, WAVELET_JSON, EVENTS_JSON) - - -class CommandlineRobotRunnerTest(googletest.TestCase): - - def testSimpleFlow(self): - FLAGS.eventdef_wavelet_participants_changed = 'x' - flag = 'eventdef_' + events.WaveletParticipantsChanged.type.lower() - setattr(FLAGS, flag, 'w.title="New title!"') - input_stream = StringIO.StringIO(TEST_JSON) - output_stream = StringIO.StringIO() - commandline_robot_runner.run_bot(input_stream, output_stream) - res = output_stream.getvalue() - self.assertTrue('wavelet.setTitle' in res) - - -def main(unused_argv): - googletest.main() - - -if __name__ == '__main__': - app.run() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/django_oauth.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/django_oauth.py b/wave/src/main/java/python/api/django_oauth.py deleted file mode 100644 index 6fd8a3f..0000000 --- a/wave/src/main/java/python/api/django_oauth.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Filter and decorator to wave enable django sites. - -If you want to require wave authentication for every handler, just add -WaveOAuthMiddleware to your middleware. If you only want to require -authentication for specific handlers, decorate those with @waveoauth. - -In any wave authenticated handler the request object should have a -waveservice field that can be used to talk to wave. - -You can specify the following in your settings: -WAVE_CONSUMER_KEY: the consumer key passed to the waveservice. defaults to - anonymous if not set. -WAVE_CONSUMER_SECRET: the consumer key passed to the waveservice. defaults to - anonymous if not set. -WAVE_USE_SANDBOX: whether to use the sandbox for this app. Defaults to false. -""" - -from django.conf import settings -from django.http import HttpResponse, HttpResponseRedirect -from django.contrib.auth import authenticate - -import base64 -import logging -from functools import wraps - -import waveservice - - -class WaveOAuthMiddleware(object): - """Wave middleware to authenticate all requests at this site.""" - def process_request(self, request): - return _oauth_helper(request) - - -def waveoauth(func): - """Decorator used to specify that a handler requires wave authentication.""" - @wraps(func) - def inner(request, *args, **kwargs): - result = _oauth_helper(request) - if result is not None: - return result - return func(request, *args, **kwargs) - return inner - - -def _oauth_helper(request): - "Check if we're authenticated and if not, execute the oauth dance." - - consumer_key = getattr(settings, 'WAVE_CONSUMER_KEY', 'anonymous') - consumer_secret = getattr(settings, 'WAVE_CONSUMER_SECRET', 'anonymous') - use_sandbox = getattr(settings, 'WAVE_USE_SANDBOX', False) - - service = waveservice.WaveService( - consumer_key=consumer_key, consumer_secret=consumer_secret, use_sandbox=use_sandbox) - - access_token = request.COOKIES.get('WAVE_ACCESS_TOKEN') - if access_token: - service.set_access_token(access_token) - request.waveservice = service - return None - - # no access token. dance monkey dance. - oauth_token = request.GET.get('oauth_token') - verifier = request.GET.get('oauth_verifier') - request_token = request.COOKIES.get('WAVE_REQUEST_TOKEN') - meta = request.META - - # you'd think there would be something better than this madness: - this_url = meta.get('HTTP_HOST') - if not this_url: - this_url = meta.get('SERVER_NAME') - port = meta.get('SEVER_PORT') - if port: - this_url += ':' + port - this_url += request.path - schema = meta.get('wsgi.url_scheme', 'http') - this_url = schema + '://' + this_url - - if not oauth_token or not verifier or not request_token: - # we're here not returning from a callback. Start. - request_token = service.fetch_request_token(callback=this_url) - auth_url = service.generate_authorization_url() - response = HttpResponseRedirect(auth_url) - # set a session cookie - response.set_cookie('WAVE_REQUEST_TOKEN', request_token.to_string()) - return response - else: - logging.info('upgrading to access token') - access_token = service.upgrade_to_access_token(request_token=request_token, - verifier=verifier) - # This redirect could be avoided if the caller would set the cookie. This way - # however we keep the cgi arguments clean. - response = HttpResponseRedirect(this_url) - response.set_cookie('WAVE_ACCESS_TOKEN', access_token.to_string(), max_age=24*3600*365) - return response
