Save Chat Messages using Realm in SUSI iOS

Fetching data from the server each time causes a network load which makes the app depend on the server and the network in order to display data. We use an offline database to store chat messages so that we can show messages to the user even if network is not present which makes the user experience better. Realm is used as a data storage solution due to its ease of usability and also, since it’s faster and more efficient to use. So in order to save messages received from the server locally in a database in SUSI iOS, we are using Realm and the reasons for using the same are mentioned below. The major upsides of Realm are: It’s absolutely free of charge, Fast, and easy to use. Unlimited use. Work on its own persistence engine for speed and performance Below are the steps to install and use Realm in the iOS Client: Installation: Install Cocoapods Run `pod repo update` in the root folder In your Podfile, add use_frameworks! and pod 'RealmSwift' to your main and test targets. From the command line run `pod install` Use the `.xcworkspace` file generated by Cocoapods in the project folder alongside `.xcodeproj` file After installation we start by importing `Realm` in the `AppDelegate` file and start configuring Realm as below: func initializeRealm() {         var config = Realm.Configuration(schemaVersion: 1,             migrationBlock: { _, oldSchemaVersion in                 if (oldSchemaVersion < 0) {                     // Nothing to do!                 }         })         config.fileURL = config.fileURL?.deletingLastPathComponent().appendingPathComponent("susi.realm")         Realm.Configuration.defaultConfiguration = config } Next, let’s head over to creating a few models which will be used to save the data to the DB as well as help retrieving that data so that it can be easily used. Since Susi server has a number of action types, we will cover some of the action types, their model and how they are used to store and retrieve data. Below are the currently available data types, that the server supports. enum ActionType: String { case answer case websearch case rss case table case map case anchor } Let’s start with the creation of the base model called `Message`. To make it a RealmObject, we import `RealmSwift` and inherit from `Object` class Message: Object { dynamic var queryDate = NSDate() dynamic var answerDate = NSDate() dynamic var message: String = "" dynamic var fromUser = true dynamic var actionType = ActionType.answer.rawValue dynamic var answerData: AnswerAction? dynamic var mapData: MapAction? dynamic var anchorData: AnchorAction? } Let’s study these properties of the message one by one. `queryDate`: saves the date-time the query was made `answerDate`: saves the date-time the query response was received `message`: stores the query/message that was sent to the server `fromUser`: a boolean which keeps track who created the message `actionType`: stores the action type `answerData`, `rssData`, `mapData`, `anchorData` are the data objects that actually store the respective action’s data To initialize this object, we need to create a method that takes input the data received from the server. // saves…

Continue ReadingSave Chat Messages using Realm in SUSI iOS

Utilizing Readiness Probes for loklak Dependencies in Kubernetes

When we use any application and fail to connect to it, we do not give up and retry connecting to it again and again. But in the reality we often face this kind of obstacles like application that break instantly or when connecting to an API or database that is not ready yet, the app gets upset and refuses to continue to work. So, something similar to this was happening with api.loklak.org. In such cases we can’t really re-write the whole application again every time the problem occurs.So for this we need to define dependencies of some kind that can handle the situation rather than disappointing the users of loklak app. Solution: We will just wait until a dependent API or backend of loklak is ready and then only start the loklak app. For this to be done, we used Kubernetes Health Checks. Kubernetes health checks are divided into liveness and readiness probes. The purpose of liveness probes are to indicate that your application is running. Readiness probes are meant to check if your application is ready to serve traffic. The right combination of liveness and readiness probes used with Kubernetes deployments can: Enable zero downtime deploys Prevent deployment of broken images Ensure that failed containers are automatically restarted Pod Ready to be Used? A Pod with defined readiness probe won’t receive any traffic until a defined request can be successfully fulfilled. This health checks are defined through the Kubernetes, so we don’t need any changes to be made in our services (APIs). We just need to setup a readiness probe for the APIs that loklak server is depending on. Here you can see the relevant part of the container spec you need to add (in this example we want to know when loklak is ready): readinessProbe: httpGet: path: /api/status.json port: 80 initialDelaySeconds: 30 timeoutSeconds: 3   Readiness Probes Updating deployments of loklak when something pushed into development without readiness probes can result in downtime as old pods are replaced by new pods in case of Kubernetes deployment. If the new pods are misconfigured or somehow broken, that downtime extends until you detect the problem and rollback. With readiness probes, Kubernetes will not send traffic to a pod until the readiness probe is successful. When updating a loklak deployment, it will also leave old one’s running until probes have been successful on new copy. That means that if loklak server new pods are broken in some way, they’ll never see traffic, instead old pods of loklak server will continue to serve all traffic for the deployment. Conclusion Readiness probes is a simple solution to ensure that Pods with dependencies do not get started before their dependencies are ready (in this case for loklak server). This also works with more than one dependency. Resources Code in loklak server: https://github.com/loklak/loklak_server . More about readiness and liveness probes at: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ Kubernetes Health checks: https://kubernetes-v1-4.github.io/docs/user-guide/production-pods/#liveness-and-readiness-probes-aka-health-checks Blog posts related to kubernetes: https://www.ianlewis.org/en/tag/kubernetes. Tutorial for creating and using Pods and probes: https://github.com/googlecodelabs/orchestrate-with-kubernetes/blob/master/labs/monitoring-and-health-checks.md

Continue ReadingUtilizing Readiness Probes for loklak Dependencies in Kubernetes

Skill History Component in Susi Skill CMS

SUSI Skill CMS is an editor to write and edit skill easily. It is built on ReactJS framework and follows an API centric approach where the Susi server acts as API server. Using Skill CMS we can browse history of a skill, where we get commit ID, commit message and name the author who made the changes to that skills. In this blog post, we will see how to add skill revision history component in Susi Skill CMS. One text file represents one skill, it may contain several intents which all belong together. Susi skills are stored in susi_skill_data repository. We can access any skill based on four tuples parameters model, group, language, skill. <Menu.Item key="BrowseRevision"> <Icon type="fork" /> Browse Skills Revision <Link to="/browseHistory"></Link> </Menu.Item> First let’s create a option in sidebar menu, and link it “/browseHistory” route created at index.js  <Route path="/browseHistory" component={BrowseHistory} /> Next we will be adding skill versioning using endpoints provided by Susi Server, to select a skill we will create a drop down list, for this we will be using Select Field a component of  Material UI. request('http://cors-anywhere.herokuapp.com/api.susi.ai/cms/getModel.json').then((data) => { console.log(data.data); data = data.data; for (let i = 0; i < data.length; i++) { models.push(<MenuItem value={i} key={data[i]} primaryText={`${data[i]}`}/>); } console.log(models); }); <SelectField floatingLabelText="Expert" style={{width: '50px'}} value={this.state.value} onChange={this.handleChange}> {experts} </SelectField> We store the models, groups and languages in array using the endpoints api.susi.ai/cms/getModel.json, api.susi.ai/cms/getGroups.json, api.susi.ai/cms/getAllLanguages.json set the values in respective select fields. The request functions takes the url as string and the parses the json and fetches the object containing data or error depending on the response from the server. Once run your project using npm start And you would be able to see the drop down list working Next, we will use Material UI tables for displaying the organized data. For using  table component we need to import table, it’s body, header and row column from Material ui class.  import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from "material-ui/Table"; We then make our header Columns, in our case it’s three, namely Commit ID, Commit Message, Author name. <TableRow> <TableHeaderColumn tooltip="Commit ID">Commit ID</TableHeaderColumn> <TableHeaderColumn tooltip="Commit Message">Commit Message</TableHeaderColumn> <TableHeaderColumn tooltip="Author Name">Author Name</TableHeaderColumn> </TableRow> To get the history of modification of a skill, we will use endpoint “http://api.susi.ai/cms/getSkillHistory.json”. It uses JGit for managing version control in skill data repository. JGit is a library which implements the Git functionality in Java. An endpoint is accessed based on userRoles, which can be Admin, Privilege, User, Anonymous. In our case it is Anonymous. Thus a User need not to log in to access this endpoint. url = "http://api.susi.ai/cms/getSkillHistory.json?model="+models[this.state.modelValue].key+"&group="+groups[this.state.groupValue].key+"&language="+languages[this.state.languageValue].key+"&skill="+this.state.expertValue; After getting the url, we will next make a ajax network call to get the modification history of skill., if the method returns success, we get the desired data in table array and display it in rows through its render() method, which checks if the data is set in state -if so, it renders the contents otherwise we display the error occurred while processing the request. $.ajax({ url: url, jsonpCallback: 'pccd', dataType: 'jsonp', jsonp:…

Continue ReadingSkill History Component in Susi Skill CMS

Getting Response Feedback In SUSI.AI Web Chat

The SUSI.AI Web Chat provides responses for various queries, but the quality of responses it not always the best possible. Machine learning and deep learning algorithms will help us to solve this step by step. In order to implement machine learning, we need feedback mechanisms. The first step in this direction is to provide users with a way to give feedback to responses with a “thumbs up” or “thumbs down”. In this blog, I explain how we fetch the feedback of responses from the server. On asking a query like tell me a quote, Susi responses with following message: Now the user can rate the response by pressing thumbs up or thumbs down button. We store this response on the server. For getting this count of feedback we use the following endpoint: BASE_URL+'/cms/getSkillRating.json?'+'model='+model+'&group='+group+'&skill='+skill; Here: BASE_URL: Base URL of our server: http://api.susi.ai/ model: Model of the skill from which response is fetched. For example “general”. group: The group of the skill from which response is fetched. For example “entertainment”. skill: name of the skill from which response is fetched. For example “quotes”. We make an ajax call to the server to fetch the data: $.ajax({ url: getFeedbackEndPoint, dataType: 'jsonp', crossDomain: true, timeout: 3000, async: false, success: function (data) { console.log(getFeedbackEndPoint) console.log(data); if(data.accepted) { let positiveCount = data.skill_rating.positive; let negativeCount = data.skill_rating.negative; receivedMessage.positiveFeedback = positiveCount; receivedMessage.negativeFeedback = negativeCount; } } In the success function, we receive the data, which is in jsonp format. We parse this to get the desired result and store it in variable positiveCount and negativeCount. An example of data response is : In the client, we can get value corresponding to positive and negative key as follows : let positiveCount = data.skill_rating.positive; let negativeCount = data.skill_rating.negative; This way we can fetch the positive and negative counts corresponding to a particular response. This data can be used in many ways, for example: It can be used to display the number of positive and negative count next to the thumbs: It can be used in machine learning algorithms to improve the response that SUSI.AI provides. Resources: Ajax’s guide on MDN: https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started Testing Link: http://chat.susi.ai/

Continue ReadingGetting Response Feedback In SUSI.AI Web Chat

Adding Manual ISO Controls in Phimpme Android

The Phimpme Android application comes with a well-featured camera to take high resolution photographs. It features an auto mode in the camera as well as a manual mode for users who likes to customise the camera experience according to their own liking. It provides the users to select from the range of ISO values supported by their devices with a manual mode to enhance the images in case the auto mode fails on certain circumstances such as low lighting conditions. In this tutorial, I will be discussing how we achieved this in Phimpme Android with some code snippets and screenshots. To provide the users with an option to select from the range of ISO values, the first thing we need to do is scan the phone for all the supported values of ISO and store it in an arraylist to be used to display later on. This can be done by the snippet provided below: String iso_values = parameters.get("iso-values"); if( iso_values == null ) {  iso_values = parameters.get("iso-mode-values"); // Galaxy Nexus  if( iso_values == null ) {     iso_values = parameters.get("iso-speed-values"); // Micromax A101     if( iso_values == null )        iso_values = parameters.get("nv-picture-iso-values"); // LG dual P990 Every device supports a different set of keyword to provide the list of ISO values. Hence, we have tried to add every possible keywords to extract the values. Some of the keywords used above covers almost 90% of the android devices and gets the set of ISO values successfully. For the devices which supports the ISO values but doesn’t provide the keyword to extract the ISO values, we can provide the standard list of ISO values manually using the code snippet provided below: values.add("200"); values.add("400"); values.add("800"); values.add("1600"); After extracting the set of ISO values, we need to create a list to display to the user and upon selection of the particular ISO value as depicted in the Phimpme camera screenshot below Now to set the selected ISO value, we first need to get the ISO key to set the ISO values as depicted in the code snippet provided below: if( parameters.get(iso_key) == null ) {  iso_key = "iso-speed"; // Micromax A101  if( parameters.get(iso_key) == null ) {     iso_key = "nv-picture-iso"; // LG dual P990     if( parameters.get(iso_key) == null ) {        if ( Build.MODEL.contains("Z00") )           iso_key = "iso"; // Asus Zenfone 2 Z00A and Z008 Getting the key to set the ISO values is similar to getting the key to extract the ISO values from the device. The above listed ISO keys to set the values covers most of the devices. Now after we have got the ISO key, we need to change the camera parameter to reflect the selected change. parameters.set(iso_key, supported_values.selected_value); setCameraParameters(parameters); To get the full source code on how to set the ISO values manually, please refer to the Phimpme Android repository. Resources Stackoverflow - Keywords to extract ISO values from the device: http://stackoverflow.com/questions/2978095/android-camera-api-iso-setting Open camera Android source code: https://sourceforge.net/p/opencamera/code/ci/master/tree/ Blog - Learn more about ISO values in photography: https://photographylife.com/what-is-iso-in-photography

Continue ReadingAdding Manual ISO Controls in Phimpme Android

Handling High Resolution Images in Phimpme Android

In Android, loading heavy and high resolution images is a difficult task. For instance, if we try to load a photo clicked at a resolution four times that of the screen and try to load it in an imageview, it may result in an app’s crash due to the OutOFMemory exception. It happens because at the run time of our application some limited memory is allocated to our application and if we exceed that by loading a high quality images. To make a perfect gallery application, one must take care of all the possible causes for application crashes. In Phimpme Android, we have done this with the help of Glide library with some other tweaks to help catch all possible causes for the OutOfMemory exceptions. In this tutorial, I will be discussing how we have displayed heavy images with the help of Glide library and other tweaks to avoid the above mentioned exception. Step 1: To avoid the OutOFMemory exception, first we have to add the below line of code in the AndroidManifest.xml file. android:largeHeap="true" What this piece of code does is that it increases the amount of heap memory that is allocated at the time of run time of the application. Hence, more heap memory, less chance of running out of memory. Step 2: To load the images into the image view we can make use of the Glide library as it is the most recommended way to do it according to the Google’s  Android developer page to cache bitmaps. The below code helps us to load the image in the imageView using a pager adapter. Glide.with(getContext())           .load(img.getUri())           .asBitmap().format(DecodeFormat.PREFER_RGB_565)           .signature(useCache ? img.getSignature(): new StringSignature(new Date().getTime()+""))           .diskCacheStrategy(DiskCacheStrategy.SOURCE)           .thumbnail(0.5f)           .transform(new RotateTransformation(getContext(), img.getOrientation(), false))           .animate(R.anim.fade_in)           .into(new SimpleTarget<Bitmap>() {               @Override               public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {                   photoView.setImageBitmap(bitmap);               }           }); This is the way we have done it in the Phimpme Android application using the Glide library. We are loading the image as a bitmap and by preferring the bitmap RGB565 as it consumes 50% less memory than the RGB8888 model which may be the type of the original image. Of course the image quality will seem bit less but it is not noticeable until we zoom in to full extent. The next thing we are doing is caching the image in the memory using the below line of code using Glide library. .diskCacheStrategy(DiskCacheStrategy.SOURCE) As caching images offers faster access to the images. It also helps in avoiding the OutOfMemory crashes when we are using a large list of images. Link to cache images without using the Glide library is mentioned in the resources section below. After this, we are loading the image in the PhotoView which is a module we are using in the Phimpme Android application, which extends to the imageView and comes with many zooming images functionalities. This is how we have implemented the loading of images in the gallery view in Phimpme Android application so that it can handle resolution of any sizes without running out of…

Continue ReadingHandling High Resolution Images in Phimpme Android

Implementing Hiding App Bar of SUSI Web Chat Application

In the SUSI Web Chat application we got a requirement to build a responsive app bar for static pages and there was another requirement to  show and hide the app bar when user scrolls. Basically this is how it should work: The app bar should be hidden after user scrolls down to a certain extent. When user scrolls up, It should appear again. First we tried readymade node packages to do this task. But these packages are hard to customize. So we planned to make this feature from the sketch. We used Jquery for this. This is how we built this. First we installed jQuery package using this command. npm install jquery Next we imported it on top of the application like this. import $ from 'jquery' We have discussed about this app bar and how we made it in previous blog post. Our app bar is like this. <header className="nav-down" id="headerSection"> <AppBar className="topAppBar" title={<img src="susi-white.svg" alt="susi-logo" className="siteTitle"/>} style={{backgroundColor:'#0084ff'}} onLeftIconButtonTouchTap={this.handleDrawer} iconElementRight={<TopMenu />} /> </header> We have to use these HTML elements to write jQuery code. But we can’t refer HTML elements before it renders. So we have to define it soon after the render method executes. We can do it using “React LifeCycle” method. We have to add our code into the “componentDidMount()” method. This is how we used jQuery inside the “componentDidMount()” lifeCycle method. Here we assigned the height of the App Bar using "$('header').outerHeight();" componentDidMount(){ var didScroll; var lastScrollTop = 0; var delta = 5; var navbarHeight = $('header').outerHeight(); Here we assigned the height of the app bar to “navbarHeight” variable. $(window).scroll(function(event){ didScroll = true; }); In this part we checked whether the user has scrolled or not. If user scrolled we set the value of “didScroll” to “true”. Now we have to define what to do if user has scrolled. function hasScrolled() { var st = $(window).scrollTop(); if(Math.abs(lastScrollTop - st) <= delta){ return; } Here we get the absolute scrolled height. If the height is less than the delta value we defined, it does not do anything. It just returns. if (st > lastScrollTop && st > navbarHeight){ $('header').removeClass('nav-down').addClass('nav-up'); } else if(st + $(window).height() < $(document).height()) { $('header').removeClass('nav-up').addClass('nav-down'); } lastScrollTop = st; } Here we hide the app bar after user scrolled down more than the height of the app bar. If we need to change the height which app bar should disappear, we just need to add a value to the condition like this. if (st > lastScrollTop && st > navbarHeight + 200){ If the user scrolled down more than that value we change the class name of the element “nav-down” to “nav-up”. And we change the className “nav-up” to “nav-down” when user is scrolling up. We defined CSS classes in the stylesheet to do these things and the animations of action. header { background: #f5b335; height: 40px; position: fixed; top: 0; transition: top 0.5s ease-in-out; width: 100%; } .nav-up { top: -100px; } We have defined the things which we need to do when…

Continue ReadingImplementing Hiding App Bar of SUSI Web Chat Application

Custom UI Implementation for Web Search and RSS actions in SUSI iOS Using Kingfisher for Image Caching

The SUSI Server is an AI powered server which is capable of responding to intelligent answers based on user’s queries. The queries to the susi server are obtained either as a websearch using the application or as an RSS feed. Two of the actions are websearch and RSS. These actions as the name suggests respond to queries based on search results from the web which are rendered in the clients. In order to use use these action types and display them in the SUSI iOS client, we need to first parse the actions looking for these action types and then creating a custom UI for them to display them. To start with, we need to make send the query to the server to receive an intelligent response from the server. This response is parsed into different action types supported by the server and saved into relevant objects. Here, we check the action types by looping through the answers array containing the actions and based on that, we save the data for that action. if type == ActionType.rss.rawValue {    message.actionType = ActionType.rss.rawValue    message.rssData = RSSAction(data: data, actionObject: action) } else if type == ActionType.websearch.rawValue {    message.actionType = ActionType.websearch.rawValue    message.message = action[Client.ChatKeys.Query] as? String ?? "" } Here, we parsed the data response from the server and looked for the rss and websearch action type followed by which we saved the data we received from the server for each of the action types in their own objects. Next, when a message object is created, we insert it into the dataSource item by appending it and use the `insertItems(at: [IndexPath])` method of collection view to insert them into the views at a particular index. Before adding them, we need to create a Custom UI for them. This UI will consist of a Collection View which is scrollable in the horizontal direction inside a CollectionView Cell. To start with this, we create a new class called `WebsearchCollectionView` which will be a `UIView` consisting of a `UICollectionView`. We start by adding a collection view into the UIView inside the `init` method by overriding it. Declare a collection view using flow layout and scroll direction set to `horizontal`. Also, hide the scroll indicators and assign the delegate and datasource to `self`. Now to populate this collection view, we need to specify the number of items that will show up. For this, we make use of the `message` variable declared. We use the `websearchData` in case of websearch action and `rssData` otherwise. Now to specify the number of cells, we use the below method which returns the number of rss or websearch action objects and defaults to 0 such cells. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {     if let rssData = message?.rssData {         return rssData.count     } else if let webData = message?.websearchData {         return webData.count     }     return 0 } We display the title, description and image for each object for which we need to create a UI for the cells. Let’s start by creating…

Continue ReadingCustom UI Implementation for Web Search and RSS actions in SUSI iOS Using Kingfisher for Image Caching

Hotword Recognition in SUSI iOS

Hot word recognition is a feature by which a specific action can be performed each time a specific word is spoken. There is a service called Snowboy which helps us achieve this for various clients (for ex: iOS, Android, Raspberry pi, etc.). It is basically a DNN based hotword recognition toolkit. In this blog, we will learn how to integrate the snowboy hotword detection wrapper in the SUSI iOS client. This service can be used in any open source project but for using it commercially, a commercial license needs to be obtained. Following are the files that need to be added to the project which are provided by the service itself: snowboy-detect.h libsnowboy-detect.a and a trained model file which can be created using their online service: snowboy.kitt.ai. For the sake of this blog, we will be using the hotword “Susi”, the model file can be found here. The way how snowboy works is that speech is recorded for a few seconds and this data is detected with an already trained model by a specific hotword, now if snowboy returns a 1 means word has been successfully detected else wasn’t. We start with creation of a wrapper class in Objective-C which can be found wrapper and the bridging header in case this needs to be added to a Swift project. The wrapper contains methods for setting sensitivity, audio gain and running the detection using the buffer. It is a wrapper class built on top of the snowboy-detect.h header file. Let’s initialize the service and run it. Below are the steps followed to enable hotword recognition and print out whether it successfully detected the hotword or not: Create a ViewController class with extensions AVAudioRecorderDelegate AVAudioPlayerDelegate since we will be recording speech. Import AVFoundation Create a basic layout containing a label which detects whether hotword detected or not and create corresponding `IBOutlet` in the ViewController and a button to trigger the start and stop of recognition. Create the following variables: let WAKE_WORD = "Susi" // hotword used let RESOURCE = Bundle.main.path(forResource: "common", ofType: "res") let MODEL = Bundle.main.path(forResource: "susi", ofType: "umdl") //path where the model file is stored var wrapper: SnowboyWrapper! = nil // wrapper instance for running detection var audioRecorder: AVAudioRecorder! // audio recorder instance var audioPlayer: AVAudioPlayer! var soundFileURL: URL! //stores the URL of the temp reording file var timer: Timer! //timer to fire a function after an interval var isStarted = false // variable to check if audio recorder already started In `viewDidLoad` initialize the wrapper and set sensitivity and audio gain. Recognition best happens when sensitivity is set to `0.5` and audio gain is set to `1.0` according to the docs. override func viewDidLoad() { super.viewDidLoad() wrapper = SnowboyWrapper(resources: RESOURCE, modelStr: MODEL) wrapper.setSensitivity("0.5") wrapper.setAudioGain(1.0) } Create an `IBAction` for the button to start recognition. This action will be used to start or stop the recording in which the action toggles based on the `isStarted` variable. When true, recording is stopped and the timer invalidated else a timer is started…

Continue ReadingHotword Recognition in SUSI iOS

Handling Change of Password of SUSI.AI Account

In this blog, we will talk about a very special case, where the user changes his password to his current one only, in other words, the user enters the same password in both current password and new password. This case is now being handled by SUSI.AI server. Considering the example of SUSI.AI Web Chat, we have following dialog when the user tries to change his/her password: Here the user can add his/her current password and new password. When the new password meets the minimum conditions (minimum 6 characters), then the user can press CHANGE button. We make ajax call to the server with the following endpoint: BASE_URL+'/aaa/changepassword.json?'+ 'changepassword=' + email + '&password=' + this.state.passwordValue + '&newpassword=' + this.state.newPasswordValue + '&access_token='+cookies.get('loggedIn'); Here we have 4 parameters: changepassword: This takes the email of the current user password: This is the password of the current user, which is saved in the state named “passwordValue” newpassword: This is the new password which the user enters access_token: These are access tokens which are fetched from cookies. These are defined on login and are deleted on logout. This is now handled on the server by a file named PasswordChangeService.java. Here we have to check whether the newpassword and password matches or not. In this file, we have a function named serviceImpl with return type ServiceResponse and takes in an argument: Query post (Query is the return type). The query is not the only argument, Please read from the file from resources mentioned below for all the argument. To handle our case we just need to work with the post. We extract the password, newpassword and email as follows: String useremail = post.get("changepassword", null); String password = post.get("password", null); String newpassword = post.get("newpassword",null); So to simply handle the case where password and newpassword matches, we define an if block in java and compare these two parameters as follows: if(password.equals(newpassword)){ result.put("message", "Your current password and new password matches"); result.put("accepted", false); return new ServiceResponse(result); } Here we put the message as “Your current password and new password matches” and make the accepted flag of result JSON as false. After this, we return the ServiceResponse. Now in our web chat client, the ajax call is as follows: $.ajax({ url: changePasswordEndPoint, dataType: 'jsonp', crossDomain: true, timeout: 3000, async: false, statusCode: { 422: function() { let msg = 'Invalid Credentials. Please check your Email or Password.'; let state = this.state; state.msg = msg; this.setState(state); } }, success: function (response) { let msg = response.message+'\n Please login again.'; let state = this.state; state.msg = msg; state.success = true; state.msgOpen = true; this.setState(state); }.bind(this), error: function(jqXHR, textStatus, errorThrown) { let msg = 'Failed. Try Again'; if (status === 'timeout') { msg = 'Please check your internet connection'; } let state = this.state; state.msg = msg; state.msgOpen = true; this.setState(state); }.bind(this) }); In our success method of ajax call,  we receive the JSON response in a variable named response and store this in the state in variable msg and set the state of success equal…

Continue ReadingHandling Change of Password of SUSI.AI Account