From 0363c0e81ff3c9e716d51e652d39c5ee5cca4cea Mon Sep 17 00:00:00 2001
From: Vivek Pabani <vivek.pabani@nexedi.com>
Date: Wed, 1 Jul 2015 09:59:07 +0000
Subject: [PATCH] jabberclient: made offline contacts visible. added password
 reset. updated error handling.

---
 .../jabber_gadget_jabberclient_html.xml       |  59 ++++-
 .../jabber_gadget_jabberclient_js.xml         | 205 +++++++++++++++---
 .../jabber_gadget_jabberconnection_js.xml     | 108 +++++----
 3 files changed, 285 insertions(+), 87 deletions(-)

diff --git a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_html.xml b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_html.xml
index 29160a4b46..eec6ede29b 100644
--- a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_html.xml
+++ b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_html.xml
@@ -135,14 +135,26 @@
           <ul data-role="listview" data-inset="true">\n
             {{#each contact}}\n
               <li>\n
-              {{#if url}}\n
-                <a href="{{url}}">\n
-                {{#if new_message}}\n
-                  <span class="ui-li-count">!</span>\n
+              {{#if status}}\n
+                {{#if url}}\n
+                  <a href="{{url}}" class="ui-btn ui-btn-icon-left ui-icon-check">\n
+                  {{#if new_message}}\n
+                    <span class="ui-li-count">!</span>\n
+                  {{/if}}\n
+                  {{jid}}</a>\n
+                {{else}}\n
+                  {{jid}}\n
                 {{/if}}\n
-                {{jid}}</a>\n
               {{else}}\n
-                {{jid}}\n
+                {{#if url}}\n
+                  <a href="{{url}}" class="ui-btn ui-btn-icon-left ui-icon-forbidden">\n
+                  {{#if new_message}}\n
+                    <span class="ui-li-count">!</span>\n
+                  {{/if}}\n
+                  {{jid}}</a>\n
+                {{else}}\n
+                  {{jid}}\n
+                {{/if}}\n
               {{/if}}\n
               </li>\n
             {{/each}}\n
@@ -207,10 +219,37 @@
       </div>\n
     </script>\n
 \n
+    <script class="reset-password-template" type="text/x-handlebars-template">\n
+      <div class="ui-grid-b ui-responsive">\n
+        <div class="ui-block-a"></div>\n
+        <div class="ui-block-b">\n
+          <h2>Reset Password</h2>\n
+          <form class="reset-password-form">\n
+            <div class="ui-field-contain">\n
+              <label>Server URL</label>\n
+              <input type="text" name="server" placeholder="Server URL" value="tiolive.com" required>\n
+            </div>\n
+            <div class="ui-field-contain">\n
+              <label>New Password</label>\n
+              <input type="password" name="new_passwd" placeholder="New Password" value="" required>\n
+            </div>\n
+            <div class="ui-field-contain">\n
+              <label>Repeat Password</label>\n
+              <input type="password" name="repeat_passwd" placeholder="Repeat Password" value="" required>\n
+            </div>\n
+            <input data-inline="true" type="submit" value="Submit" data-theme="b">\n
+          </form>\n
+          <pre style="white-space: pre-wrap;">{{message}}</pre>\n
+        </div>\n
+        <div class="ui-block-c">\n
+        </div>\n
+      </div>\n
+    </script>\n
     <script class="message-template" type="text/x-handlebars-template"><li data-theme="{{theme}}" style="{{style}}"><pre style="white-space: pre-wrap;">{{text}}</pre></li></script>\n
     \n
     <script class="history-template" type="text/x-handlebars-template"><pre style="white-space: pre-wrap;">{{text}}</pre></script>\n
 \n
+    <script class="error-template" type="text/x-handlebars-template"><pre style="white-space: pre-wrap;">{{error_message}}</pre></script>\n
     <script class="header-template" type="text/x-handlebars-template">\n
       {{#if left_url}}\n
         <a href="{{left_url}}" class="ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all">{{left_title}}</a>\n
@@ -368,7 +407,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>klaus.woelfel</string> </value>
+                <value> <string>zope</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -382,7 +421,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>942.15924.54448.8823</string> </value>
+                <value> <string>944.5553.6477.32460</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -400,8 +439,8 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1428669417.76</float>
-                        <string>UTC</string>
+                        <float>1435739472.1</float>
+                        <string>GMT</string>
                       </tuple>
                     </state>
                   </object>
diff --git a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_js.xml b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_js.xml
index de61021cf4..160ef17cdd 100644
--- a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_js.xml
+++ b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberclient_js.xml
@@ -124,6 +124,7 @@
     PAGE_DIALOG = "dialog",\n
     PAGE_HISTORY = "history",\n
     PAGE_NEW_CONTACT = "subscribe",\n
+    PAGE_PASSWORD = "password",\n
     DEFAULT_PAGE = PAGE_CONTACT,\n
     CONNECTION_GADGET_URL = "./gadget_jabberconnection.html",\n
     CONNECTION_GADGET_SCOPE = "connection",\n
@@ -139,6 +140,10 @@
       result = -1;\n
     } else if (b.new_message && (!a.new_message)) {\n
       result = 1;\n
+    } else if (a.status && (!b.status)) {\n
+      result = -1;\n
+    } else if (b.status && (!a.status)) {\n
+      result = 1;\n
     } else if (b.jid < a.jid) {\n
       result = 1;\n
     } else if (a.jid < b.jid) {\n
@@ -149,6 +154,13 @@
     return result;\n
   }\n
 \n
+  function validatePassword(password1, password2) {\n
+    if(password1 === password2) {\n
+      return true;\n
+    } else {\n
+      return false;\n
+    }\n
+  }\n
   function initializeContact(gadget, jid) {\n
     if (!(gadget.props.contact_dict.hasOwnProperty(jid))) {\n
       gadget.props.contact_dict[jid] = {\n
@@ -296,39 +308,36 @@
     return RSVP.Queue()\n
       .push(function () {\n
         var promise_list = [\n
+          gadget.aq_pleasePublishMyState({page: PAGE_PASSWORD}),\n
           gadget.aq_pleasePublishMyState({page: PAGE_NEW_CONTACT})\n
         ],\n
           key;\n
         for (key in contact_dict) {\n
-          if (contact_dict.hasOwnProperty(key) &&\n
-              ((!contact_dict[key].offline) || (!contact_dict[key].read))) {\n
-            promise_list.push(\n
-              gadget.aq_pleasePublishMyState({page: PAGE_DIALOG, jid: key})\n
-            );\n
-          }\n
+          promise_list.push(\n
+            gadget.aq_pleasePublishMyState({page: PAGE_DIALOG, jid: key})\n
+          );\n
         }\n
         return RSVP.all(promise_list);\n
       })\n
       .push(function (result_list) {\n
-        var i = 1,\n
+        var i = 2,\n
           parameter = {contact: []},\n
           key2;\n
         for (key2 in contact_dict) {\n
-          if (contact_dict.hasOwnProperty(key2) &&\n
-              ((!contact_dict[key2].offline) || (!contact_dict[key2].read))) {\n
-            parameter.contact.push({\n
-              jid: key2,\n
-              url: result_list[i],\n
-              new_message: !contact_dict[key2].read\n
-            });\n
-            i += 1;\n
-          }\n
+          parameter.contact.push({\n
+            jid: key2,\n
+            url: result_list[i],\n
+            new_message: !contact_dict[key2].read,\n
+            status: !contact_dict[key2].offline\n
+          });\n
+          i += 1;\n
         }\n
         parameter.contact.sort(compareContact);\n
-        // XXX sort\n
         gadget.props.header_element.innerHTML = gadget.props.header_template({\n
+          left_url: result_list[0],\n
+          left_title: "Reset Password",\n
           title: "Contact",\n
-          right_url: result_list[0],\n
+          right_url: result_list[1],\n
           right_title: "New"\n
         });\n
         gadget.props.content_element.innerHTML =\n
@@ -404,6 +413,25 @@
         $(gadget.props.element).trigger("create");\n
       });\n
   }\n
+\n
+  function renderErrorPage(gadget, error) {\n
+    var error_text = error;\n
+    return RSVP.Queue()\n
+      .push(function () {\n
+        return gadget.aq_pleasePublishMyState({page: PAGE_CONNECTION});\n
+      })\n
+      .push(function (connection_url) {\n
+        gadget.props.header_element.innerHTML = gadget.props.header_template({\n
+          left_url: connection_url,\n
+          left_title: "Login",\n
+          title: "Error Message"\n
+        });\n
+        gadget.props.content_element.innerHTML = gadget.props.error_template({\n
+          error_message: error_text\n
+        });\n
+        $(gadget.props.element).trigger("create");\n
+      });\n
+  }\n
 \n
   function renderDialogPage(gadget, connection_gadget) {\n
     var jid,\n
@@ -484,10 +512,8 @@
         gadget.props.content_element.innerHTML =\n
           gadget.props.login_template({});\n
         $(gadget.props.element).trigger("create");\n
-        gadget.props.content_element.querySelector("input[type=password]")\n
+        gadget.props.content_element.querySelector("input[name=jid]")\n
                                  .focus();\n
-        gadget.props.content_element.querySelector("input[type=password]")\n
-                                 .select();\n
         return promiseEventListener(\n
           gadget.props.content_element.querySelector(\'form.login-form\'),\n
           \'submit\',\n
@@ -518,19 +544,26 @@
   }\n
 \n
   function renderNewContactPage(gadget, connection_gadget) {\n
-    gadget.props.header_element.innerHTML = gadget.props.header_template({\n
-      title: "New Contact"\n
-    });\n
-    gadget.props.content_element.innerHTML =\n
-      gadget.props.new_contact_template({});\n
-    $(gadget.props.element).trigger("create");\n
+    var contact_url;\n
+    return new RSVP.Queue()\n
+      .push(function () {\n
+        return gadget.aq_pleasePublishMyState({page: PAGE_CONTACT});\n
+      })\n
+      .push(function (contact) {\n
+        contact_url = contact;\n
+        gadget.props.header_element.innerHTML = gadget.props.header_template({\n
+          left_url: contact_url,\n
+          left_title: "Back",\n
+          title: "New Contact"\n
+        });\n
+        gadget.props.content_element.innerHTML =\n
+          gadget.props.new_contact_template({});\n
+        $(gadget.props.element).trigger("create");\n
 \n
-    gadget.props.content_element.querySelector("input[type=text]")\n
+        gadget.props.content_element.querySelector("input[type=text]")\n
                              .focus();\n
-    gadget.props.content_element.querySelector("input[type=text]")\n
+        gadget.props.content_element.querySelector("input[type=text]")\n
                              .select();\n
-    return new RSVP.Queue()\n
-      .push(function () {\n
         return promiseEventListener(\n
           gadget.props.content_element.querySelector(\'form.new-contact-form\'),\n
           \'submit\',\n
@@ -548,6 +581,65 @@
         return redirectToDefaultPage(gadget);\n
       });\n
   }\n
+\n
+  function renderResetPasswordPage(gadget, connection_gadget, status) {\n
+    if(!status) {\n
+      status = "";\n
+    }\n
+    return new RSVP.Queue()\n
+      .push(function () {\n
+        return gadget.aq_pleasePublishMyState({page: PAGE_CONTACT});\n
+      })\n
+      .push(function (contact_url) {\n
+        gadget.props.header_element.innerHTML = gadget.props.header_template({\n
+          left_url: contact_url,\n
+          left_title: "Back",\n
+          title: "Reset Password"\n
+        });\n
+        gadget.props.content_element.innerHTML =\n
+          gadget.props.reset_password_template({\n
+            message: status\n
+          });\n
+        $(gadget.props.element).trigger("create");\n
+        gadget.props.content_element.querySelector("input[type=submit]")\n
+                                 .disabled = false;\n
+        gadget.props.content_element.querySelector("input[name=new_passwd]")\n
+                             .value = "";\n
+        gadget.props.content_element.querySelector("input[name=repeat_passwd]")\n
+                             .value = "";\n
+        gadget.props.content_element.querySelector("input[name=new_passwd]")\n
+                             .focus();\n
+        return promiseEventListener(\n
+          gadget.props.content_element.querySelector(\'form.reset-password-form\'),\n
+          \'submit\',\n
+          false\n
+        );\n
+      })\n
+      .push(function (submit_event) {\n
+        var matched = false;\n
+        gadget.props.content_element.querySelector("input[type=submit]")\n
+                                 .disabled = true;\n
+        matched = validatePassword(\n
+          submit_event.target[1].value,\n
+          submit_event.target[2].value\n
+        );\n
+        if(matched) {\n
+          return connection_gadget.resetPassword(\n
+            submit_event.target[0].value,\n
+            submit_event.target[1].value\n
+            )\n
+            .push(function (status) {\n
+              return renderResetPasswordPage(gadget, connection_gadget, status);\n
+            }, function (error) {\n
+              var message = "Password Reset Failed.";\n
+              return renderResetPasswordPage(gadget, connection_gadget, message);\n
+          });\n
+        } else {\n
+          var message = "Password does not match.";\n
+          return renderResetPasswordPage(gadget, connection_gadget, message);\n
+        }\n
+      });\n
+  }\n
 \n
   rJS(window)\n
     .ready(function (g) {\n
@@ -575,6 +667,12 @@
           g.props.history_template = Handlebars.compile(\n
             document.querySelector(".history-template").innerHTML\n
           );\n
+          g.props.error_template = Handlebars.compile(\n
+            document.querySelector(".error-template").innerHTML\n
+          );\n
+          g.props.reset_password_template = Handlebars.compile(\n
+            document.querySelector(".reset-password-template").innerHTML\n
+          );\n
           g.props.message_template = Handlebars.compile(\n
             document.querySelector(".message-template").innerHTML\n
           );\n
@@ -596,6 +694,21 @@
       return gadget.getDeclaredGadget(CONNECTION_GADGET_SCOPE)\n
         .push(function (connection_gadget) {\n
           return connection_gadget.sendPresence();\n
+        })\n
+        .push(function (){\n
+          return gadget.getDeclaredGadget(CONNECTION_GADGET_SCOPE);\n
+        })\n
+        .push(function (connection_gadget) {\n
+          return connection_gadget.fetchRoster();\n
+        })\n
+        .push(function(all_contacts){\n
+          var key;\n
+          for (key in all_contacts) {\n
+            initializeContact(gadget, all_contacts[key].jid);\n
+          }\n
+        }, function (error) {\n
+          var error_text = "Roster Fetching Failed";\n
+          return renderErrorPage(gadget, error_text);\n
         });\n
     })\n
     .allowPublicAcquisition("notifyXMPPConnecting", function () {\n
@@ -673,6 +786,26 @@
                                   argument_list[2], true);\n
       })\n
 \n
+    .allowPublicAcquisition("notifyXMPPConnectingFail", function () {\n
+      var gadget = this,\n
+        error_text = \'XMPPConnectingFail\';\n
+      return renderErrorPage(gadget, error_text);\n
+    })\n
+    .allowPublicAcquisition("notifyXMPPDisconnecting", function () {\n
+      var gadget = this,\n
+        error_text = \'XMPPDisconnecting\';\n
+      return renderErrorPage(gadget, error_text);\n
+    })\n
+    .allowPublicAcquisition("notifyXMPPDisconnected", function () {\n
+      var gadget = this,\n
+        error_text = \'XMPPDisconnected\';\n
+      return renderErrorPage(gadget, error_text);\n
+    })\n
+    .allowPublicAcquisition("notifyXMPPAuthenticatingFailed", function (error_data) {\n
+      var gadget = this,\n
+        error_text = \'XMPPAuthenticatingFailed\';\n
+      return renderErrorPage(gadget, error_text);\n
+    })\n
     .declareService(function () {\n
 \n
       function dropNotification() {\n
@@ -715,6 +848,8 @@
           method = renderDialogPage;\n
         } else if (options.page === PAGE_HISTORY) {\n
           method = renderHistoryPage;\n
+        } else if (options.page === PAGE_PASSWORD) {\n
+          method = renderResetPasswordPage;\n
         } else {\n
           throw new Error("not implemented page " + options.page);\n
         }\n
@@ -863,7 +998,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>klaus.woelfel</string> </value>
+                <value> <string>zope</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -877,7 +1012,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>942.15804.3325.32187</string> </value>
+                <value> <string>944.5545.36219.41881</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -895,8 +1030,8 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1428663088.08</float>
-                        <string>UTC</string>
+                        <float>1435744547.72</float>
+                        <string>GMT</string>
                       </tuple>
                     </state>
                   </object>
diff --git a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberconnection_js.xml b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberconnection_js.xml
index d0af7b8c7d..2a0c21c077 100644
--- a/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberconnection_js.xml
+++ b/bt5/erp5_web_jabber_client/PathTemplateItem/web_page_module/jabber_gadget_jabberconnection_js.xml
@@ -347,45 +347,69 @@
         deferServerConnection(this);\n
       })\n
 \n
-//     .declareMethod(\'fetchRoster\', function () {\n
-//       var defer = RSVP.defer();\n
-// \n
-//       function jsonifyResponse(domElt) {\n
-//         try {\n
-//           var result = [],\n
-//             elt,\n
-//             json_elt,\n
-//             len,\n
-//             i,\n
-//             len2,\n
-//             j,\n
-//             item_list = domElt.querySelectorAll("item");\n
-//           len = item_list.length;\n
-//           for (i = 0; i < len; i += 1) {\n
-//             elt = item_list[i];\n
-//             len2 = elt.attributes.length;\n
-//             json_elt = {};\n
-//             for (j = 0; j < len2; j += 1) {\n
-//               json_elt[elt.attributes[j].name] = elt.attributes[j].value;\n
-//             }\n
-//             result.push(json_elt);\n
-//           }\n
-//           defer.resolve(result);\n
-//         } catch (error) {\n
-//           defer.reject(error);\n
-//         }\n
-//       }\n
-// \n
-//       this.props.connection.sendIQ(\n
-//         $iq({type: "get"}).c("query", {xmlns: Strophe.NS.ROSTER}),\n
-//         jsonifyResponse,\n
-//         defer.reject\n
-//       );\n
-// \n
-//       return defer.promise;\n
-// \n
-//     })\n
-\n
+    .declareMethod(\'fetchRoster\', function () {\n
+        var defer = RSVP.defer();\n
+        function jsonifyResponse(domElt) {\n
+          try {\n
+            var result = [],\n
+              elt,\n
+              json_elt,\n
+              len,\n
+              i,\n
+              len2,\n
+              j,\n
+              item_list = domElt.querySelectorAll("item");\n
+            len = item_list.length;\n
+            for (i = 0; i < len; i += 1) {\n
+              elt = item_list[i];\n
+              len2 = elt.attributes.length;\n
+              json_elt = {};\n
+              for (j = 0; j < len2; j += 1) {\n
+                json_elt[elt.attributes[j].name] = elt.attributes[j].value;\n
+              }\n
+              result.push(json_elt);\n
+            }\n
+            defer.resolve(result);\n
+          } catch (error) {\n
+          defer.reject(error);\n
+          }\n
+       }\n
+       this.props.connection.sendIQ(\n
+         $iq({type: "get"}).c("query", {xmlns: Strophe.NS.ROSTER}),\n
+         jsonifyResponse,\n
+         defer.reject\n
+       );\n
+       return defer.promise;\n
+     })\n
+\n
+    .declareMethod(\'resetPassword\', function (server, new_passwd) {\n
+        var defer = RSVP.defer();\n
+        function jsonifyResponse(domElt) {\n
+          try {\n
+            var result = [],\n
+              type = domElt.getAttribute(\'type\');\n
+            if(type === "result") {\n
+              result.push("Password Reset Success.");\n
+            }\n
+            else {\n
+              throw new Error("Password Reset Failure.");\n
+            }\n
+            defer.resolve(result);\n
+          } catch (error) {\n
+            defer.reject(error);\n
+          }\n
+        }\n
+        var uid = this.props.jid.split(\'@\')[0];\n
+        this.props.connection.sendIQ(\n
+          $iq({to: server, type: "set"})\n
+          .c("query", {xmlns: "jabber:iq:register"})\n
+          .c("username").t(uid).up()\n
+          .c("password").t(new_passwd).up(),\n
+          jsonifyResponse,\n
+          defer.reject\n
+       );\n
+       return defer.promise;\n
+     })\n
     .declareMethod(\'sendPresence\', function () {\n
       this.props.connection.send(\n
         $pres().tree()\n
@@ -545,7 +569,7 @@
             </item>
             <item>
                 <key> <string>actor</string> </key>
-                <value> <string>romain</string> </value>
+                <value> <string>zope</string> </value>
             </item>
             <item>
                 <key> <string>comment</string> </key>
@@ -559,7 +583,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>939.33961.3512.52974</string> </value>
+                <value> <string>944.5651.30805.18688</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -577,7 +601,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1418214516.59</float>
+                        <float>1435744650.8</float>
                         <string>GMT</string>
                       </tuple>
                     </state>
-- 
2.30.9