How Settings of SUSI Android App Are Saved on Server

The SUSI Android allows users to specify whether they want to use the action button of soft keyboard as carriage return or else send action. The user can use SUSI.AI on different client like Android , iOS, Web. To give user uniform experience, we need to save user settings on the server so that if the user makes any change in setting in any chat client then that it changes in other chat clients too. So every chat client must store user specific data on the server to make sure that all chat clients access this data and maintain the same state for that particular user and must accordingly push and pull user data from and to the server to update the state of the app.

We used special key to store setting information on server. For eg.

Setting Key Value Use
Enter As Send enter_send true/false true means pressing enter key send message and false means pressing enter key adds new line.
Mic Input mic_input true/false true means default input method is speech but supports keyboard input too. false means the only input method is keyboard input.
Speech Always speech_always true/false true means we get speech output irrespective of input type.
Speech Output speech_output true/false true means we get speech output in case of speech input and false means we don’t get speech output.
Theme theme dark/light dark means theme is dark and light means theme is light

How setting is stored to server

Whenever user settings are changed, the client updates the changed settings on the server so that the state is maintained across all chat clients. When user change setting, we send three parameters to the server ‘key’, ‘value’ and ‘token’. For eg. let ‘Enter As Send’ is set to false. When user changes it from false to true, we immediately update it on the server. Here key will be ‘enter_send’ and value will be ‘true’.

The endpoint used to add or update User Settings is :

BASE_URL+’/aaa/changeUserSettings.json?key=SETTING_NAME&value=SETTING_VALUE&access_token=ACCESS_TOKEN’

SETTING_NAME’ is the key of the corresponding setting, ‘SETTING_VALUE’ is it’s updated value and ‘ACCESS_TOKEN’ is used to find correct user account. We used the retrofit library for network call.

settingResponseCall = ClientBuilder().susiApi .changeSettingResponse(key, value,  PrefManager.getToken())

If the user successfully updated the setting on the server then server reply with message ‘You successfully changed settings of your account!’

How setting is retrieved from server

We retrieve setting from the server when user login. The endpoint used to fetch User Settings is

BASE_URL+’/aaa/listUserSettings.json?access_token=ACCESS_TOKEN’

It requires “ACCESS_TOKEN” to retrieve setting data for a particular user. When user login, we use getUserSetting method to retrieve setting data from the server. PrefManager.getToken() is used to get “ACCESS_TOKEN”.

userSettingResponseCall = ClientBuilder().susiApi .getUserSetting(PrefManager.getToken())

We use userSettingResponseCall to get a response of ‘UserSetting’ type using which we can retrieve different setting from the server. ‘UserSetting’ contain ‘Session’ and ‘Settings’ and ‘Settings’ contain the value of all settings. We save the value of all settings on the server in string format, so after retrieving settings we convert them into the required format. For eg. ‘Enter As Send’ value is of boolean format, so after retrieving we convert it to boolean format.

var settings: Settings ?= response.body().settings

utilModel.setEnterSend((settings?.enterSend.toString()).toBoolean())

Reference

Continue ReadingHow Settings of SUSI Android App Are Saved on Server

Using NodeJS modules of Loklak Scraper in Android

Loklak Scraper JS implements scrapers of social media websites so that they can be used in other platforms, like Android or in a native Java project. This way there will be only a single source of scraper, as a result it will be easier to update the scrapers in response to the change in websites. This blog explains how Loklak Wok Android, a peer for Loklak Server on Android platform uses the Twitter JS scraper to scrape tweets.

LiquidCore is a library available for android that can be used to run standard NodeJS modules. But Twitter scraper can’t be used directly, due to the following problems:

  • 3rd party NodeJS libraries are used to implement the scraper, like cheerio and request-promise-native and LiquidCore doesn’t support 3rd party libraries.
  • The scrapers are written in ES6, as of now LiquidCore uses NodeJS 6.10.2, which doesn’t support ES6 completely.

So, if 3rd party NodeJS libraries can be included in our scraper code and ES6 can be converted to ES5, LiquidCore can easily execute Twitter scraper.

3rd party NodeJS libraries can be bundled into Twitter scraper using Webpack and ES6 can be transpiled to ES5 using Babel.

The required dependencies can be installed using:

$npm install --save-dev webpack
$npm install --save-dev babel-core babel-loader babel-preset-es2015

Bundling and Transpiling

Webpack does bundling based on the configurations provided in webpack.config.js, present in root directory of project.

var fs = require('fs');

function listScrapers() {
   var src = "./scrapers/"
   var files = {};
   fs.readdirSync(src).forEach(function(data) {
       var entryName = data.substr(0, data.indexOf("."));
       files[entryName] = src+data;
   });
   return files;
}

module.exports = {
 entry: listScrapers(),
 target: "node",
 module: {
     loaders: [
         {
             loader: "babel-loader",
             test: /\.js?$/,
             query: {
                 presets: ["es2015"],
             }
         },
     ]
 },
 output: {
   path: __dirname + '/build',
   filename: '[name].js',
   libraryTarget: 'var',
   library: '[name]',
 }
};

 

Now let’s break the config file, the function listScrapers returns a JSONObject with key as name of scraper and value as relative location of scraper, ex:

{
   twitter: "./scrapers/twitter.js",
   github: "./scrapers/github.js"
   // same goes for other scrapers
}

The parameters in module.exports as described in the documentation of webpack for multiple inputs and to use the generated output externally:

  • entry: Since a bundle file is required for each scraper we provide the  the JSONObject returned by listScrapers function. The multiple entry points provided generate multiple bundled files.
  • target: As the bundled files are to be used in NodeJS platform,  “node” is set here.
  • module: Using webpack the code can be directly transpiled while bundling, the end users don’t need to run separate commands for transpiling. module contains babel configurations for transpiling.
  • output: options here customize the compilation of webpack
    • path: Location where bundled files are kept after compilation, “__dirname” means the current directory i.e. root directory of the project.
    • filename: Name of bundled file, “[name]“ here refers to the key of JSONObject provided in entry i.e. key of JSONObect returned from listScrapers. Example for Twitter scraper, the filename of bundled file will be “twitter.js”.
    • libraryTarget: by default the functions or methods inside bundled files can’t be used externally – can’t be imported. By providing the “var” the functions in bundled module can be accessed.
    • library: the name of the library.

Now, time to do the compilation work:

$ ./node_modules/.bin/webpack

The bundled files can be found in build directory. But, the generated bundled files are large files – around 77,000 lines. Large files are not encouraged for production purposes. So, a “-p” flag is used to generate bundled files for production – around 400 lines.

$ ./node_modules/.bin/webpack -p

Using LiquidCore to execute bundled files

The generated bundled file can be copied to the raw directory in res (resources directory in Android). Now, events are emitted from Activity/Fragment and in response to those events the scraping function is invoked in the bundled JS file, present in raw directory, the vice-versa is also possible.

So, we handle some events in our JS file and send some events to the android Activity/Fragment. The event handling and event creating code in JS file:

var query = "";
LiquidCore.on("queryEvent", function(msg) {
  query = msg.query;
});

LiquidCore.on("fetchTweets", function() {
  var twitterScraper = new twitter();
  twitterScraper.getTweets(query, function(data) {
    LiquidCore.emit("getTweets", {"query": query, "statuses": data});
  });
});

LiquidCore.emit('start');

 

First a “start” event is emitted from JS file, which is consumed in TweetHarvestingFragment by getScrapedTweet method using startEventListener.

EventListener startEventListener = (service, event, payload) -> {
   JSONObject jsonObject = new JSONObject();
   try {
       jsonObject.put("query", query);
       service.emit(LC_QUERY_EVENT, jsonObject); // value of LC_QUERY_EMIT is  "queryEvent"
   } catch (JSONException e) {
       Log.e(LOG_TAG, e.toString());
   }
   service.emit(LC_FETCH_TWEETS_EVENT); //value of  LC_FETCH_TWEETS_EVENT is  "fetchTweets"
};

 

The startEventListener then emits “queryEvent” with a JSONObject that contains the query to search tweets for scraping. This event is consumed in JS file by:

var query = "";
LiquidCore.on("queryEvent", function(msg) {
  query = msg.query;
});

 

After “queryEvent”, “fetchTweets” event is emitted from fragment, which is handled in JS file by:

LiquidCore.on("fetchTweets", function() {
  var twitterScraper = new twitter(); // scraping object is created
  twitterScraper.getTweets(query, function(data) { // function that scrapes twitter
    LiquidCore.emit("getTweets", {"query": query, "statuses": data});
  });
});

 

Once the scraped data is obtained, it is sent back to fragment by emitting “getTweets” event from JS file, “{“query”: query, “statuses”: data}” contains scraped data. This event is consumed in android by getTweetsEventListener.

EventListener getTweetsEventListener = (service, event, payload) -> { // payload contains scraped data
   Push push = mGson.fromJson(payload.toString(), Push.class);
   emitter.onNext(push);
};

 

LiquidCore creates a NodeJS instance to execute the bundled JS file. The NodeJS instance is called MicroService in LiquidCore terminology. For all this event handling to work, the NodeJS instance is created inside the method with a ServiceStartListner where all EventListener are added.

MicroService.ServiceStartListener serviceStartListener = (service -> {
   service.addEventListener(LC_START_EVENT, startEventListener);
   service.addEventListener(LC_GET_TWEETS_EVENT, getTweetsEventListener);
});
URI uri = URI.create("android.resource://org.loklak.android.wok/raw/twitter"); // Note .js is not used
MicroService microService = new MicroService(getActivity(), uri, serviceStartListener);
microService.start();

Resources

Continue ReadingUsing NodeJS modules of Loklak Scraper in Android

How to Show Preview of Any Link in SUSI Android App

Sometimes in a chat app like Whatsapp, messenger we find that scrolling over a link, shows a preview of the link. Android-Link-Preview is an open source library which can be used to show the preview of a link. This library is developed by Leonardo Cardoso. This library makes preview from an url using all the information such as title, relevant texts and images. TextCrawler is the main class of this library. As the name suggests this class is used to crawl given link and grab relevant information. In this blog, I will show you how I used this library in SUSI Android to show the preview of the link.

How to include this library in your project

To use android-link-preview in our project we must add the dependency of the library in build.gradle(project) file

repositories {
  maven { url https://github.com/leonardocardoso/mvn-repo/raw/master/maven-deploy’   }
}

and build.gradle(module) file.

dependencies {
   compile org.jsoup:jsoup:1.8.3 // required
   compile com.leocardz:link-preview:1.2.1@aar
}

Now import these packages in class where you want to use link preview.

import com.leocardz.link.preview.library.LinkPreviewCallback;

import com.leocardz.link.preview.library.SourceContent;

import com.leocardz.link.preview.library.TextCrawler;

As the name suggests LinkpreviewCallback is a callback which has two important methods onPre() and onPos(). onPre() method called when library starts crawling the web to find relevant information and onPos() method called when crawling finished. This library uses SourceContent class to save and retrieve data.

LinkPreviewCallback linkPreviewCallback = new LinkPreviewCallback() {

@Override

public void onPre() { }

@Override

public void onPos(final SourceContent sourceContent, boolean b) {}

}

TextCrawler class is the main class which use makePreview() method to start web crawling.

makePreview() method needs two parameters

  • linkPreviewCallback : Instance of LinkPreviewCallback class.
  • Link : Link of web page to crawl.
TextCrawler textCrawler = new TextCrawler();

textCrawler.makePreview(linkPreviewCallback, link);

So when we call makePreview method, this library starts crawling the web. But before that, it checks if given link is URL of any image or not. If given link is URL of any image, then there is no need of crawling the web because we can’t find any other information from that link, but if it is not url of any image then it starts crawling the web. All websites are written in HTML. It uses jsoup library to parse HTML documents and extract useful data from that web page. After that it store different information separately i.e it store ‘title’, ‘description’ and ‘image url’ separately using setTitle(), setDescription() and setImage() methods of SourceContent class respectively.

sourceContent.setTitle(metaTags.get(“title”));

When it finishes all these tasks, it call onPos() method of LinkPreview class to inform that it has done its task and now we can use stored data using getTitle(), getDescription() and getImage() methods inside onPos() method.

sourceContent.getTitle();

Example :

We are using Android-link-preview in our SUSI Android app

Reference

Continue ReadingHow to Show Preview of Any Link in SUSI Android App

Implementing a Collapsible Responsive App Bar of SUSI Web Chat

In the SUSI Web Chat application we wanted to make few static pages such as: Overview, Terms, Support, Docs, Blog, Team, Settings and About. The idea was to show them in app bar. Requirements were  to have the capability to collapse on small viewports and to use Material UI components. In this blog post I’m going to elaborate how we built the responsive app bar Using Material UI components.

First we added usual Material UI app bar component  like this.

             <header className="nav-down" id="headerSection">
             <AppBar
               className="topAppBar"
title={<a href={this.state.baseUrl} ><img src="susi-white.svg" alt="susi-logo"  className="siteTitle"/></a>}
               style={{backgroundColor:'#0084ff'}}
               onLeftIconButtonTouchTap={this.handleDrawer}
               iconElementRight={<TopMenu />}
             />
             </header>

We added SUSI logo instead of the text title using below code snippet and linked it to the home page like this.

title={<a href={this.state.baseUrl} ><img src="susi-white.svg" alt="susi-logo"  className="siteTitle"/></a>}

We have defined “this.state.baseUrl” in constructor and it gets the base url of the web application.

this.state = {
       openDrawer: false, 
baseUrl: window.location.protocol + '//' + window.location.host + '/'
       };

We need to open the right drawer when we click on the button on top left corner. So we have to define two methods to open and close drawer as below.

   handleDrawer = () => this.setState({openDrawer: !this.state.openDrawer});
   handleDrawerClose = () => this.setState({openDrawer: false});

Now we have to add components that we need to show on the right side of the app bar. We connect those elements to the app bar like this. “iconElementRight={}”

We defined “TopMenu” Items like this.

   const TopMenu = (props) => (
   <div>
     <div className="top-menu">
     <FlatButton label="Overview"  href="/overview" style={{color:'#fff'}} className="topMenu-item"/>
     <FlatButton label="Team"  href="/team" style={{color:'#fff'}} className="topMenu-item"/>
     </div>

We added FlatButtons to place links to other static pages. After all we needed a FlatButton that gives IconMenu to show login and signup options.

     <IconMenu {...props} iconButtonElement={
         <IconButton iconStyle={{color:'#fff'}} ><MoreVertIcon /></IconButton>
     }>
     <MenuItem primaryText="Chat" containerElement={<Link to="/logout" />}
                   rightIcon={<Chat/>}/>
     </IconMenu>
   </div>
   );

After adding all these correctly you will see this kind of an app bar in your application.

Now our app bar is ready. But it does not collapse on small viewports.
So we planned to hide flat buttons on small sized screens and show the menu button. For that we used media queries.

@media only screen and (max-width: 800px){
   .topMenu-item{ display: none !important;  }
   .topAppBar button{ display: block  !important; }
}

This is how we built the responsive app bar using Material UI components. You can check the preview from this url. If you are willing to contribute to SUSI Web Chat here is the GitHub repository.

Resources:

  • Material UI Components: http://www.material-ui.com/#/components/
  • Learn More about media queries: https://www.w3schools.com/css/css_rwd_mediaqueries.asp
Continue ReadingImplementing a Collapsible Responsive App Bar of SUSI Web Chat

Characteristization of Transistors Using PSLab

Transistors are one of the key building blocks of all electronics. They are fundamentally three-terminal semiconductor devices, with the terminals being labelled as the Emitter(E), Base(B), and Collector(C). These active components are found everywhere in electronics, and all of the complex processors that power everything from cellphones to aircraft employ millions of these devices in switching and amplification roles. In this blog post, we shall use the PSLab to explore some of the fundamental properties of transistors, and their various applications.

Transistor as an amplifier

In the schematic shown, we shall try to use an NPN transistor to amplify a small signal.

A small amplitude oscillation generated by W1 with the amplitude knob turned down to a very low level is used as the input. Since transistors do not handle bipolar signals, we have mixed a constant DC voltage generated PV3 to shift this small signal into the positive domain.

The fluctuating potential difference incident at the base of the transistor creates a corresponding current flow between the Base and Emitter.

By the fundamental property of transistors, this influences the path resistance between the Collector(C) and the Emitter(E) , and the resultant amplified voltage output can be monitored at the junction between the 1K resistor and the collector.

We have used CH1 to monitor the input voltage, and CH2 for the output

In a more applied scenario, we can implement the second schematic in order to create an audio amplifier. Instead of using W1 as the input signal, a speaker is used as a microphone. When a sound signal is incident on the speaker, its membrane oscillates, and as a result , the coil attached to it also does the same. Since this coil is placed in a magnetic field , its oscillations result in a change in the magnetic flux passing through, and this change causes a voltage(EMF) induced at its output. We then use our transistor amplifier to amplify this small EMF

Figure 2 : A Transistor being used to apply a gain of 81.5x to a small amplitude sine wave. The input waveform (green) is shown on a +/-500mV full scale and the output waveform is shown on a +/-8V scale in order to be able to view both. However, due to the difference in scales, the actual difference in amplitudes is 16 times more than what is visible.
Common Emitter Characteristics
Schematic Diagram

Any introductory course on transistors includes a diagram similar to the one shown , and a description about how for any base current, the collector current eventually saturates, and that this saturation level is proportional to the base current itself.

With the PSLab’s transistor CE characterization app, we can set up this experiment, and verify this for ourselves using an NPN transistor. The results shown were gathered using a 2N2222 transistor

In the schematic , the base current is determined by the voltage source PV2, and a high value series resistor of 200 KOhms . We use an analog input CH3 to monitor the voltage present at the Base of the transistor in order to calculate the total base current.

Base current = V/R = (PV2 – CH3) / 200e3

Now that we have set a particular base current, PV1 is used to sequentially increase the voltage across the collector and emitter of the transistor. A current limiting resistor of 1K Ohm is used, and CH1 is used to monitor the voltage drop across the transistor.

Collector current = V/R = (PV1 – CH1) / 1e3

Plotting the behaviour of the collector current with respect to the collector voltage gives us the familiar current voltage characteristics of a transistor.

Figure 3: Common emitter characteristics of an NPN transistor (2N2222) for various base currents

We can now alter the base current by changing PV2, and verify that the saturation current for the collector is indeed a function of it.

Resources

 

Continue ReadingCharacteristization of Transistors Using PSLab

Implementing Settings API on Open Event Frontend to View and Update Admin Settings

This blog article will illustrate how the admin settings are displayed and updated on the admin settings page in Open Event Frontend, using the settings API. It will also illustrate the use of the notification service to display corresponding notifications on whether the update operation is successful or not. Our discussion primarily will involve the admin/settings/index route to illustrate the process, all other admin settings route work exactly the same way.

The primary end point of Open Event API with which we are concerned with for fetching tickets for an event is

GET /v1/settings

Since there are multiple  routes under admin/settings  including admin/settings/index, and they all will share the same setting model, it is efficient to make the call for Event on the settings route, rather than repeating it for each sub route, so the model for settings route is:

model() {
 return this.store.queryRecord(setting, {});
}

It is important to note that, we need not specify the model for index route or in fact for any of the sub routes of settings.  This is because it is the default behaviour of ember that if the model for a route is not found, it will automatically look for it in the parent  route.  

And hence all that is needed to be done to make the model available in the system settings form  is to pass it while calling the form component.

<div class="ui basic {{if isLoading 'loading' ''}} segment">
 {{forms/admin/settings/system-form save='updateSettings' settings=model}}
</div>

Thus the model properties will be available in the form via settings alias. Next, we need to bind the value property  of the input fields to the corresponding model properties.  Here is a sample snippet on so as to how to achieve that, for the full code please refer to the codebase or the resources below.

<div class="field">
 {{ui-radio label=(t 'Development') current=settings.appEnvironment name='environment' value='development' onChange=(action (mut settings.appEnvironment))}}
</div>
<div class="field">
 {{ui-radio label=(t 'Staging') current=settings.appEnvironment name='environment' value='staging'}}
</div>
<div class="field">
 {{ui-radio label=(t 'Production') current=settings.appEnvironment name='environment' value='production'}}
</div>
<div class="field">
 <label>
   {{t 'App Name'}}
 </label>
 {{input type='text' name='app_name' value=settings.appName}}
</div>
<div class="field">
 <label>
   {{t 'Tagline'}}
 </label>
 {{input type='text' name='tag_line' value=settings.tagline}}
</div>

In the example above, appName, tagLine and appEnvironment are binded to the actual properties in the model. After the required changes have been done, the user next submits the form which triggers the submit action. If the validation is successful, the action updateSettings residing in the controller of the route is triggered, this is where the primary operations happen.

updateSettings() {
 this.set('isLoading', true);
 let settings = this.get('model');
 settings.save()
   .then(() => {
     this.set('isLoading', false);
     this.notify.success(this.l10n.t('Settings have been saved successfully.'));
   })
   .catch(()=> {
     this.set('isLoading', false);
     this.notify.error(this.l10n.t('An unexpected error has occured. Settings not saved.'));
   });
}

The controller action first sets the isLoading property to true. This adds the semantic UI class loading to the segment containing the form, and it and so the form goes in the loading state, to let the user know the requests is being processed. Then the save()  call occurs and this makes a PATCH request to the API to update the values stored inside the database. And if the PATCH request is successful, the .then() clause executes, which in addition to setting the isLoading as false.

However, in case there is an unexpected error and the PATCH request fails, the .catch() executes. After setting isLoading to false, it notifies the user of the error via an error notification.

Resources

Continue ReadingImplementing Settings API on Open Event Frontend to View and Update Admin Settings

Mailing Attachments Using Terminal in Open Event Android

The latest version of Open Event Android App Generator, v2 lacked the feature of mailing the generated APK to the email ID that is entered at the start of the app generation process. This also included mailing the error logs in case of APK failure.

This is an important feature for app generator because the process of app generation is a time taking one. The users have to wait for the app to be generated so that they can download the generated APK. To avoid this, the generator can automatically email the APK as soon as it is generated.

I took up this issue a few days back and started working on it. I started with thinking about the ways through which it will be implemented. This required some discussions with the mentors and co-developers. We finalised on the following ways:

  • Using Sendgrid
  • Using SMTP

I will be discussing the implementation of both of them in this blog. The code for APK mailing starts with the function call Notification.send in generator.py

if completed and apk_path and not error:
   Notification.send(
       to=self.creator_email,
       subject='Your android application for %s has been generated ' % self.event_name,
       message='Hi,<br><br>'
               'Your android application for the \'%s\' event has been generated. '
               'And apk file has been attached along with this email.<br><br>'
               'Thanks,<br>'
               'Open Event App Generator' % self.event_name,
       file_attachment=apk_path,
       via_api=self.via_api
   )
else:
   Notification.send(
       to=self.creator_email,
       subject='Your android application for %s could not generated ' % self.event_name,
       message='Hi,<br><br> '
               'Your android application for the \'%s\' event could not generated. '
               'The error message has been provided below.<br><br>'
               '<code>%s</code><br><br>'
               'Thanks,<br>'
               'Open Event App Generator' % (self.event_name, str(error) if error else ''),
       file_attachment=apk_path,
       via_api=self.via_api
   )

This leads me to the class Notification.py. It has three functions:-

1. send(to, subject, message, file_attachment, via_api)
2. send_mail_via_smtp(payload):
3. send_email_via_sendgrid(payload):

As the name suggests, the first function:

send(to, subject, message, file_attachment, via_api)

mainly decides which service (out of smtp and sendgrid) should be used to send the email, on the basis of the input parameters (especially, the ‘EMAIL_SERVICE’ parameter that has to be set in config.py).
The function looks like as follows:

send(to, subject, message, file_attachment, via_api)

It is in the send() that the other two functions are called. If the email_service is smtp, it calls the Notification.send_mail_via_smtp(payload). Otherwise, the Notification.send_email_via_sendgrid(payload) is called.
The sendgrid function is pretty straightforward:

@staticmethod
def send_email_via_sendgrid(payload):

   key = current_app.config['SENDGRID_KEY']
   if not key:
       logger.info('Sendgrid key not defined')
       return
   headers = {
       "Authorization": ("Bearer " + key)
   }
   requests.post(
       "https://api.sendgrid.com/api/mail.send.json",
       data=payload,
       headers=headers
   )

It requires a personalised sendgrid key which is accessed from the config.py file. Apart from that it handles some errors by giving logs in celery tasks. The main line in the function that initiates the email is a POST request made using the python library ‘requests’. The request is made as follows:

 requests.post(
       "https://api.sendgrid.com/api/mail.send.json",
       data=payload,
       headers=headers
   )

The send_mail_via_smtp(payload): function looks for some configurations before sending the mail:

@staticmethod
def send_mail_via_smtp(payload):
   """
   Send email via SMTP
   :param config:
   :param payload:
   :return:
   """
   smtp_encryption = current_app.config['SMTP_ENCRYPTION']
   if smtp_encryption == 'tls':
       smtp_encryption = 'required'
   elif smtp_encryption == 'ssl':
       smtp_encryption = 'ssl'
   elif smtp_encryption == 'tls_optional':
       smtp_encryption = 'optional'
   else:
       smtp_encryption = 'none'
   config = {
       'host': current_app.config['SMTP_HOST'],
       'username': current_app.config['SMTP_USERNAME'],
       'password': current_app.config['SMTP_PASSWORD'],
       'encryption': smtp_encryption,
       'port': current_app.config['SMTP_PORT'],
   }
   mailer_config = {
       'transport': {
           'use': 'smtp',
           'host': config['host'],
           'username': config['username'],
           'password': config['password'],
           'tls': config['encryption'],
           'port': config['port']
       }
   }

   mailer = Mailer(mailer_config)
   mailer.start()
   message = Message(author=payload['from'], to=payload['to'])
   message.subject = payload['subject']
   message.plain = strip_tags(payload['message'])
   message.rich = payload['message']
   message.attach(payload['attachment'])
   mailer.send(message)
   mailer.stop()

It is using the Marrow Mailer Python library to email with attachments(APK). This Python library can be installed using
pip install marrow.mailer
To use Marrow Mailer you instantiate a marrow.mailer.Mailer object with the configuration, then pass Message instances to the Mailer instance’s send() method.

You can refer to the following guides for more information about sending emails through command line:
https://github.com/marrow/mailer is the official repo of Marrow Mailer repository.
https://pypi.python.org/pypi/marrow.mailer
More detailled information on sending emails using Sendgrid can be found here https://www.daveperrett.com/articles/2013/03/19/setting-up-sendmail-with-sendgrid-on-ubuntu/

Continue ReadingMailing Attachments Using Terminal in Open Event Android

Making Custom Change Listeners in PSLab Android

In this post we are going to learn how to make custom change listeners. There are many use cases for custom change listeners like if you want to initiate some action when some variable’s value is changed. In PSLab android app, this was required during initialisation of PSLab hardware device, it takes about 3-4 seconds to initialise the device which includes reading calibration data from device and process it. So before starting the initialisation process, app notifies user with the message, “Initialising Wait …” and after initialisation is done, user is notified with the message “Initialisation Completed”.

There might be other ways to accomplish this but I found making a custom change listener for boolean and trigger notifying user action on change of boolean value to be most organised way to do it.

Another way I can think of is to pass the fragment reference to the class  constructor for which the object is to be made. And Views need to be made public for access from that object to change status after some work is done.

Let’s look at an example, we would change status in a fragment after some task in object instantiation is completed.

Implementation

Class with variable on which custom change listener is required:
Create a class and declare a variable for which you want to listen the value change to trigger some action. In this example we have created a InitializationVariable class and defined a boolean variable named initialised.

Define an interface inside the class and that’s where the trick lies. When you set/change the value of the variable through a function setVariable(boolean value) in this case, note that we are triggering the interface method too.

public class InitializationVariable {

   public boolean initialised = false;
   private onValueChangeListener valueChangeListener;

   public boolean isInitialised() {
       return initialised;
   }

   public void setVariable(boolean value) {
       initialised = value;
       if (valueChangeListener != null) valueChangeListener.onChange();
   }

   public onValueChangeListener getValueChangeListener() {
       return valueChangeListener;
   }

   public void setValueChangeListener(onValueChangeListener valueChangeListener) {
       this.valueChangeListener = valueChangeListener;
   }

   public interface onValueChangeListener {
       void onChange();
   }

}

Create an object of above class in activity/fragment:
Create an object to the class we just made and attach onValueChangeListener to it. This example shows how it’s used in PSLab Android, you can use it anywhere but remember to access view elements from a valid context.

public static InitializationVariable booleanVariable;
public class HomeFragment extends Fragment {

   @BindView(R.id.tv_initialisation_status)
   TextView tvInitializationStatus;

   public static InitializationVariable booleanVariable;// object whose value change is noted

   public static HomeFragment newInstance() {
       HomeFragment homeFragment = new HomeFragment();
       return homeFragment;
   }

   @Nullable
   @Override
   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
       View view = inflater.inflate(R.layout.home_fragment, container, false);
       unbinder = ButterKnife.bind(this, view);
       return view;
   }

   @Override
   public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
       super.onViewCreated(view, savedInstanceState);

       booleanVariable.setValueChangeListener(new InitializationVariable.onValueChangeListener() {
           @Override
           public void onChange() {
               if (booleanVariable.isInitialised())
                   tvInitializationStatus.setText("Initialsation Completed");
               else
                   tvInitializationStatus.setText("Initialising Wait ...");
           }
       });
  }
}

Now whenever booleanVariable.setVariable(value) is called, it triggers the onValueChangeListener where you can manage the action you wanted to do on value change.
This is similar to how other listeners are implemented .You implement an interface and call those interface methods on some value change and classes which implement those interface have overridden methods which handle the action after change.

Hopefully this post gives you an insight about how change listeners are implemented.

Note: This post was specific to PSLab Android App, you can create custom change listener on any variable in any class and perform action on value of the variable getting changed.

Resources

Continue ReadingMaking Custom Change Listeners in PSLab Android

Opening Local HTML Files in PSLab Android App

The PSLab Android App allows users to perform experiments using the PSLab device. The experience to perform an experiment should resemble the generic way to perform the experiment. So we associated an Experiment Doc file which the user can refer to while performing experiment. Just like a regular lab manual, the experiment doc contains the AIM, THEORY & FORMULAS, SCHEMATIC, OUTPUT, etc. In the PSLab Desktop App, since there was already a provision for using HTML docs and so I  avoided reinventing the wheel and used those html files as it is.

    

The problem we faced was how to open a bunch of HTML files with their corresponding CSS, JS files in Android’s webView.

There are two ways it can be done:

  • Host the experiment docs on a server and make a request from the android app for the specific experiment doc like Diode I-V, Zener I-V, etc.
  • Put the folder containing all html, CSS, js files in assets folder and request for the HTML doc files locally.

The PSLab developer team went with the second option as the availability of  Internet  is necessary for the performing experiment if we follow the first option and so to avoid this dependence on the Internet, we went with the second option and stored HTML docs locally in assets folder.

Implementation

  • Put the folder containing all the HTML, CSS, JS files in the assets folder in your android project. In this case the folder is DOC_HTML.

  • Define the WebView in xml and take the webView’s reference in your activity/fragment
    In xml
<WebView
   android:id="@+id/perform_experiment_wv"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />

In activity/fragment

webView = (WebView) view.findViewById(R.id.perform_experiment_wv);
  • Load the url in webView in the format as shown below
webView.loadUrl("file:///android_asset/DOC_HTML/apps/" + htmlFile);

“file:///” acts as resource identifier, so file:///android_asset/ actually points to “pslab-android/app/src/main/assets/”.
From the assets directory, we can a provide route to any HTML file. Here I put all HTML files in apps folder and used the string variable “htmlFile” to point to the specific html file.

Similarly html files stored in the external storage can also be accessed but there are some cases you need to handle. For example,if external storage is mounted, you can’t request the html file from external storage.

To request html files from external storage, make sure that you have the following permission in your AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();

Relative to baseDir you can specify the path from your html files, like

baseDir + “DOC_HTML/apps” + htmlFile

Conclusion

Putting HTML files in the assets folder and requesting it by webView’s loadURL() method is the best but there are various drawbacks of using this method like the increase in size of the apk. In our case, the normal apk size was 3MB but after adding the html doc folder it increased to 7MB. It increased by almost an additional size of the html folder added in assets. As it’s written, in the android’s project overview guide, the assets folder contains files that should be compiled into an .apk file as-is.

Resources

Continue ReadingOpening Local HTML Files in PSLab Android App

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: 'callback',
            crossDomain: true,
            success: function(data) {
                data = data.commits;
                let array = [];
                for(let i=0;i<data.length;i++){
                    array.push(data[i]);
                }
{tableData.map((row, index) => (
  <TableRow key={index}>
    <TableRowColumn>{row.commitID}</TableRowColumn>
    <TableRowColumn>{row.commit_message}</TableRowColumn>
    <TableRowColumn>{row.author}</TableRowColumn>
   </TableRow>
))}

Test the final output  on http://skills.susi.ai/browseHistory or http://localhost:3000/browseHistory , select the model, group , language and skill and get the history of that skill.


Next time when you need drop down list or tables to organize your data, do check out https://github.com/callemall/material-ui for examples, which can help in providing good outlines to you apps. For contributions to susi_skill_cms, join our chat channel  on gitter: https://gitter.im/fossasia/susi_server and browse https://github.com/fossasia/susi_skill_cms for complete code.

Resources

Continue ReadingSkill History Component in Susi Skill CMS