The branch, frodo has been updated
       via  8755ee52e6119e7c8ff8dd367819901f4af27f7a (commit)
       via  431cfd4572aa50d4fa550b189c59754e10a67d43 (commit)
      from  efcbf7e37e56d3b263f4cf0466c22b628f954917 (commit)

- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=8755ee52e6119e7c8ff8dd367819901f4af27f7a

commit 8755ee52e6119e7c8ff8dd367819901f4af27f7a
Author: beenje <[email protected]>
Date:   Sun Jan 5 15:32:37 2014 +0100

    [plugin.video.udacity] updated to version 1.0.4

diff --git a/plugin.video.udacity/README.md b/plugin.video.udacity/README.md
index 42c8f19..849d955 100644
--- a/plugin.video.udacity/README.md
+++ b/plugin.video.udacity/README.md
@@ -9,7 +9,7 @@ From http://udacity.com/how-it-works:
 
 ## Setup/Installation
 
-Coming soon
+Available via official repo. Installation info available 
[here](http://wiki.xbmc.org/index.php?title=Add-ons).
 
 ## XBMC Version
 
@@ -17,6 +17,7 @@ Frodo
 
 ## Tests
 
+    > pip install xbmcswift2
     > python resources/tests/test_addon.py
 
 ## License
diff --git a/plugin.video.udacity/addon.py b/plugin.video.udacity/addon.py
index e394530..eca9894 100644
--- a/plugin.video.udacity/addon.py
+++ b/plugin.video.udacity/addon.py
@@ -12,12 +12,30 @@ def index():
     items = [
         {'label': plugin.get_string(30004),
          'path': plugin.url_for('course_catalog')},
-        {'label': plugin.get_string(30005),
-         'path': plugin.url_for('my_courses')},
-        {'label': plugin.get_string(30006),
-         'path': plugin.url_for('open_settings')}
     ]
 
+    auth_storage = plugin.get_storage('auth')
+    auth = UdacityAuth(auth_storage)
+    username = plugin.get_setting('username')
+    password = plugin.get_setting('user_password')
+
+    # Default settings string displays Login unless logged in
+    setting_string_id = 30012
+    if username and password:
+        if auth.authenticate(username, password):
+            items.append(
+                {'label': plugin.get_string(30005),
+                 'path': plugin.url_for('my_courses')})
+            setting_string_id = 30006
+        else:
+            plugin.notify(auth.error)
+            plugin.set_setting('user_password', '')
+
+    items.append(
+        {'label': plugin.get_string(setting_string_id),
+         'path': plugin.url_for('open_settings')}
+    )
+
     return items
 
 
@@ -54,11 +72,8 @@ def open_lesson(course_id, lesson_id):
     items = []
     auth_storage = plugin.get_storage('auth')
     auth = UdacityAuth(auth_storage)
-    auth.authenticate(
-        plugin.get_setting('username'),
-        plugin.get_setting('user_password')
-    )
     udacity = Udacity(auth)
+
     contents = udacity.get_lesson_contents(lesson_id)
     for content in contents:
         if content['model'] == 'Video':
@@ -107,7 +122,17 @@ def my_courses():
 
 @plugin.route('/open_settings/')
 def open_settings():
-    return plugin.open_settings()
+    old_username = plugin.get_setting('username')
+    old_password = plugin.get_setting('user_password')
+    plugin.open_settings()
+    # If the username or password was changed, flush any saved cookies/tokens
+    if (old_username != plugin.get_setting('username') or
+            old_password != plugin.get_setting('user_password')):
+        auth_storage = plugin.get_storage('auth')
+        auth_storage['cookies'] = None
+        auth_storage['xsrf-token'] = None
+        auth_storage.sync()
+    return plugin.redirect(plugin.url_for('index'))
 
 
 @plugin.route((
@@ -177,6 +202,7 @@ def play_video(course_id, lesson_id, asset_id, youtube_id):
     youtube_url = (
         "plugin://plugin.video.youtube/"
         "?action=play_video&videoid={0}").format(youtube_id)
+
     return plugin.set_resolved_url(youtube_url)
 
 if __name__ == '__main__':
diff --git a/plugin.video.udacity/addon.xml b/plugin.video.udacity/addon.xml
index b10b056..35bc973 100644
--- a/plugin.video.udacity/addon.xml
+++ b/plugin.video.udacity/addon.xml
@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.udacity" name="Udacity" version="1.0.2" 
provider-name="Lex Toumbourou (@lexandstuff)">
+<addon id="plugin.video.udacity" name="Udacity" version="1.0.4" 
provider-name="Lex Toumbourou (@lexandstuff)">
   <requires>
     <import addon="xbmc.python" version="2.1.0"/>
     <import addon="script.module.xbmcswift2" version="2.4.0"/>
     <import addon="script.module.requests" version="1.1.0"/>
+    <import addon="script.module.beautifulsoup" version="3.2.1"/>
     <import addon="plugin.video.youtube" version="4.4.6"/>
   </requires>
   <extension point="xbmc.python.pluginsource" library="addon.py">
diff --git a/plugin.video.udacity/changelog.txt 
b/plugin.video.udacity/changelog.txt
index f5eecd8..eccc896 100644
--- a/plugin.video.udacity/changelog.txt
+++ b/plugin.video.udacity/changelog.txt
@@ -1,3 +1,14 @@
+1.0.4
+- Use strings.xml for buttons in quizzes
+- Display Loading... after submitting quiz
+
+1.0.3
+- Added BeautifulSoup dependancy
+- No longer fail when certain steps are missing (fixing some broken lessons)
+- Hide My Courses when user not authenticated
+- Changed strings to better match Udacity's interface
+- Update Udacity's servers when quizzes are submitted
+
 1.0.2
 - Corrected string ID range
 - Removed fake user-agent
diff --git a/plugin.video.udacity/resources/language/English/strings.xml 
b/plugin.video.udacity/resources/language/English/strings.xml
index cf6f9a5..31fe410 100644
--- a/plugin.video.udacity/resources/language/English/strings.xml
+++ b/plugin.video.udacity/resources/language/English/strings.xml
@@ -2,7 +2,7 @@
 <strings>
   <string id="30000">Udacity</string>
   <string id="30001">General</string>
-  <string id="30002">Username</string>
+  <string id="30002">Email</string>
   <string id="30003">Password</string>
   <string id="30004">Course Catalog</string>
   <string id="30005">My Courses</string>
@@ -12,4 +12,8 @@
   <string id="30009">Answer</string>
   <string id="30010">Please complete online</string>
   <string id="30011">Programming Quizzes are not supported on XBMC</string>
+  <string id="30012">Login</string>
+  <string id="30013">Submit</string>
+  <string id="30014">Cancel</string>
+  <string id="30015">Loading...</string>
 </strings>
diff --git a/plugin.video.udacity/resources/lib/controls.py 
b/plugin.video.udacity/resources/lib/controls.py
index b48d4d2..9ddd06c 100644
--- a/plugin.video.udacity/resources/lib/controls.py
+++ b/plugin.video.udacity/resources/lib/controls.py
@@ -2,6 +2,8 @@ from xbmcswift2 import xbmcgui, xbmc
 import math
 import os
 
+import utils
+
 
 class TextBox(xbmcgui.ControlButton):
     """
@@ -68,9 +70,11 @@ class FormQuiz(xbmcgui.WindowDialog):
         self.udacity = udacity
         self.data = quiz_data['data']
         self.widgets = []
-        self.udacity.update_activity(
-            course_id, lesson_id, group_id, quiz_id, 'NodeVisit')
         self.plugin = plugin
+        self.course_id = course_id
+        self.lesson_id = lesson_id
+        self.group_id = group_id
+        self.quiz_id = quiz_id
 
         bg_image_path = (
             plugin.addon.getAddonInfo('path') + os.sep +
@@ -122,11 +126,13 @@ class FormQuiz(xbmcgui.WindowDialog):
         self.submit_button = xbmcgui.ControlButton(
             x=self.button_x_pos, y=self.button_y_pos, width=self.button_width,
             height=self.button_height, shadowColor='0xFF000000',
-            label='Submit', font='font13', textColor=self.button_text_colour)
+            label=self.plugin.get_string(30013), font='font13',
+            textColor=self.button_text_colour)
+
         self.back_button = xbmcgui.ControlButton(
             x=self.button_x_pos - self.button_spacing,
             y=self.button_y_pos, width=self.button_width,
-            height=self.button_height, label='Back',
+            height=self.button_height, label=self.plugin.get_string(30014),
             font='font13', textColor=self.button_text_colour)
 
         self.addControl(self.submit_button)
@@ -137,9 +143,23 @@ class FormQuiz(xbmcgui.WindowDialog):
             self.close()
             return
         elif control == self.submit_button:
-            result = self.udacity.submit_quiz(self.data['key'], self.widgets)
+            control.setLabel(self.plugin.get_string(30015))
+            answer_data = utils.widgets_to_answer(self.widgets)
+            result = self.udacity.submit_quiz(self.data['key'], answer_data)
+            if self.udacity.auth.is_authenticated:
+                if not self.udacity.update_submission_activity(
+                    self.course_id, self.lesson_id, self.group_id,
+                        self.quiz_id, result['evaluation'],
+                        answer_data['submission']):
+                    # Submission wasn't updated correctly
+                    self.plugin.log.error(self.udacity.error)
             dialog = xbmcgui.Dialog()
             dialog.ok('Result', result['evaluation']['comment'])
+            if result['evaluation']['passed'] is not False:
+                self.close()
+                return
+            else:
+                control.setLabel(self.plugin.get_string(30013))
         else:
             for count, widget in enumerate(self.widgets):
                 if control == widget['obj'] and widget['obj'].canUpdateLabel:
diff --git a/plugin.video.udacity/resources/lib/udacity.py 
b/plugin.video.udacity/resources/lib/udacity.py
index 2293b8e..79e846c 100644
--- a/plugin.video.udacity/resources/lib/udacity.py
+++ b/plugin.video.udacity/resources/lib/udacity.py
@@ -11,17 +11,33 @@ class Udacity(object):
     def __init__(self, auth):
         self.auth = auth
 
-    def update_activity(
-            self, course_id, lesson_id, group_id, asset_id, activity_type):
+    def update_submission_activity(
+        self, course_id, lesson_id, group_id,
+            quiz_id, quiz_result, answer_data):
+        """
+        Send submitted quiz data to Udacity
+        """
         occurence_time = dt.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')
-
-        data = {'items': [
-            {'occurrence_time': occurence_time, 'content_context': [
-                {'tag': 'c-', 'node_key': course_id},
-                {'tag': 'l-', 'node_key': lesson_id},
-                {'tag': "e-", "node_key": group_id},
-                {'tag': "m-", "node_key": asset_id}],
-                'data': {'model': activity_type}}],
+        quiz_result['model'] = 'SubmissionEvaluation'
+
+        current_context = [
+            {'tag': 'c-', 'node_key': course_id},
+            {'tag': 'l-', 'node_key': lesson_id},
+            {'tag': "e-", "node_key": group_id},
+            {'tag': "m-", "node_key": quiz_id}
+        ]
+
+        data = {
+            'items': [{
+                'occurrence_time': occurence_time,
+                'content_context': current_context,
+                'data': answer_data
+                }, {
+                'occurrence_time': occurence_time,
+                'content_context': current_context,
+                'data': quiz_result,
+                }
+            ],
             'current_time': occurence_time}
 
         r = requests.post(
@@ -30,7 +46,7 @@ class Udacity(object):
             cookies=self.auth.get_cookies())
 
         if not r.status_code == 200:
-            self.error = r.text
+            self.error = json.loads(r.text[5:])['error']
             return False
 
         return True
@@ -73,7 +89,10 @@ class Udacity(object):
         data = json.loads(r.text[5:])['references']['Node']
         steps = data[section]['steps_refs']
         for step in steps:
-            node = data[step['key']]
+            try:
+                node = data[step['key']]
+            except KeyError:
+                continue
 
             # Push the quiz and lecture data into the dictionary
             # to support XBMC's stateless nature
@@ -133,26 +152,14 @@ class Udacity(object):
 
         return output
 
-    def submit_quiz(self, quiz_id, widgets):
+    def submit_quiz(self, quiz_id, answer_data):
         url = "{0}/api/nodes/{1}/evaluation?_method=GET".format(
             UDACITY_URL, quiz_id)
-        parts = []
-        for widget in widgets:
-            parts.append(
-                {"model": "SubmissionPart",
-                 "marker": widget['data']['marker'],
-                 "content": widget['obj'].getContent()})
-
-        answer_data = {
-            "submission": {
-                "model": "Submission",
-                "operation": "GRADE",
-                "parts": parts
-            }
-        }
         r = requests.post(
             url, data=json.dumps(answer_data),
-            headers=self.auth.get_request_headers())
+            headers=self.auth.get_request_headers(),
+            cookies=self.auth.get_cookies())
+
         return json.loads(r.text[5:])
 
     def get_last_quiz_submission(self, quiz_id):
@@ -213,14 +220,16 @@ class UdacityAuth(object):
         if r.status_code == 200:
             self.is_authenticated = True
             self.auth_stored['cookies'] = r.cookies
+            self.auth_stored['xsrf_token'] = r.cookies['XSRF-TOKEN']
             return True
         else:
             result = json.loads(r.text[5:])
+            self.is_authenticated = False
             self.error = result['error']
             return False
 
     def get_request_headers(self):
         return {
-            'xsrf_token': self.get_xsrf_token(),
+            'x-xsrf-token': self.get_xsrf_token(),
             'content-type': 'application/json;charset=UTF-8',
         }
diff --git a/plugin.video.udacity/resources/tests/test_addon.py 
b/plugin.video.udacity/resources/tests/test_addon.py
index 76a63b7..a790952 100644
--- a/plugin.video.udacity/resources/tests/test_addon.py
+++ b/plugin.video.udacity/resources/tests/test_addon.py
@@ -3,6 +3,27 @@ import sys, os
 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
 
 from resources.lib.udacity import Udacity, UdacityAuth
+from resources.lib.utils import widgets_to_answer
+
+class MockWidget():
+    def getContent(self):
+        return True
+
+
+class UnitTests(unittest.TestCase):
+    def test_return_answer_data_from_list_of_widgets(self):
+        mock_1 = MockWidget()
+        mock_2 = MockWidget()
+        widgets = [
+            {'data': {'marker': True},
+             'obj': mock_1},
+            {'data': {'marker': True},
+             'obj': mock_2},
+        ]
+        result = widgets_to_answer(widgets)
+        self.assertTrue('submission' in result)
+        self.assertTrue(result['submission']['parts'][0]['content'])
+
 
 class OfflineTest(unittest.TestCase):
     def test_return_true_when_cookies_and_token_are_set(self):

http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/plugins;a=commit;h=431cfd4572aa50d4fa550b189c59754e10a67d43


-----------------------------------------------------------------------

Summary of changes:
 .../LICENSE.txt                                    |    0
 plugin.audio.tilos/addon.py                        |  195 ++++++++++++++++++++
 plugin.audio.tilos/addon.xml                       |   23 +++
 plugin.audio.tilos/changelog.txt                   |    5 +
 plugin.audio.tilos/fanart.jpg                      |  Bin 0 -> 12737 bytes
 plugin.audio.tilos/icon.png                        |  Bin 0 -> 26930 bytes
 .../resources/language/English/strings.po          |   48 +++++
 .../resources/language/Hungarian/strings.po        |   48 +++++
 plugin.video.udacity/README.md                     |    3 +-
 plugin.video.udacity/addon.py                      |   44 ++++-
 plugin.video.udacity/addon.xml                     |    3 +-
 plugin.video.udacity/changelog.txt                 |   11 +
 .../resources/language/English/strings.xml         |    6 +-
 plugin.video.udacity/resources/lib/controls.py     |   30 +++-
 plugin.video.udacity/resources/lib/udacity.py      |   67 ++++---
 plugin.video.udacity/resources/lib/utils.py        |   22 +++
 plugin.video.udacity/resources/tests/test_addon.py |   21 ++
 17 files changed, 480 insertions(+), 46 deletions(-)
 copy {plugin.audio.abradio.cz => plugin.audio.tilos}/LICENSE.txt (100%)
 create mode 100644 plugin.audio.tilos/addon.py
 create mode 100644 plugin.audio.tilos/addon.xml
 create mode 100644 plugin.audio.tilos/changelog.txt
 create mode 100644 plugin.audio.tilos/fanart.jpg
 create mode 100644 plugin.audio.tilos/icon.png
 create mode 100644 plugin.audio.tilos/resources/language/English/strings.po
 create mode 100644 plugin.audio.tilos/resources/language/Hungarian/strings.po
 create mode 100644 plugin.video.udacity/resources/lib/utils.py


hooks/post-receive
-- 
Plugins

------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons

Reply via email to