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