Make Flask Fast and Reliable – Simple Steps

Flask is a microframework for Python, which is mostly used in web-backend development.There are projects in FOSSASIA that are using flask for development purposes such as Open Event Server, Query Server, Badgeyay. Optimization is indeed one of the most important steps for a successful software product. So, in this post some few off- the-hook tricks will be shown which will make your flask-app more fast and reliable.

Flask-Compress

  1. Flask-Compress is a python package which basically provides de-facto lossless compression  to your Flask application.
  2. Enough with the theory, now let’s understand the coding part:
    1. First install the module

2. Then for a basic setup

3.That’s it! All it takes is just few lines of code to make your flask app optimized .To know more about the module check out flask-compress module.

Requirements Directory

  1. A common practice amongst different FOSSASIA  projects which involves dividing requirements.txt files for development,testing as well as production.
  2. Basically when projects either use TRAVIS CI for testing or are deployed to Cloud Services like Heroku, there are some modules which are not really required at some places.  For example: gunicorn is only required for deployment purposes and not for development.
  3. So how about we have a separate directory wherein different .txt files are created for different purposes.
  4. Below is the image of file directory structure followed for requirements in badgeyay project.

  1. As you can see different .txt files are created for different purposes
    1. dev.txt – for development
    2. prod.txt – for production(i.e. deployment)
    3. test.txt – for testing.

Resources

Continue ReadingMake Flask Fast and Reliable – Simple Steps

How to Store Mobile Settings in the Server from SUSI Web Chat Settings Page

While we are adding new features and capabilities to SUSI Web Chat application, we wanted to provide settings changing capability to SUSI users. SUSI team decided to maintain a settings page to give that capability to users.

This is how it’s interface looks like now.

In this blog post I’m going to add another setting category to our setting page. This one is for  saving mobile phone number and dial code in the server.

UI Development:

First we need to  add new category to settings page and it should be invisible when user is not logged in. Anonymous users should not get mobile phone category in settings page.

     let menuItems = cookies.get('loggedIn') ?
            <div>
                <div className="settings-list">
                    <Menu
                        onItemTouchTap={this.loadSettings}
                        selectedMenuItemStyle={blueThemeColor}
                        style={{ width: '100%' }}
                        value={this.state.selectedSetting}
                    >
                       <MenuItem value='Mobile' className="setting-item" leftIcon={<MobileIcon />}>Mobile<ChevronRight className="right-chevron" /></MenuItem>
                        <hr className="break-line" />
                    </Menu>
                </div>
            </div>

 

Next we have to show settings UI when user clicks on the category name.

 if (this.state.selectedSetting === 'Mobile' && cookies.get('loggedIn')) {}
                currentSetting = (
  <Translate text="Country/region : " />
                            <DropDownMenu maxHeight={300}
               value={this.state.countryCode?this.state.countryCode:'US'}

 

Show US if the state does not deines the country code

                                onChange={this.handleCountryChange}>
                                {countries}
                            </DropDownMenu>
<Translate text="Phone number : " />
                            <TextField name="selectedCountry"
                            disabled={true}
                            value={countryData.countries[this.state.countryCode?this.state.countryCode:'US'].countryCallingCodes[0] }
                         	/>
                            <TextField name="serverUrl"
                                onChange={this.handleTelephoneNoChange}
                                value={this.state.phoneNo }
 />
)}

 

Then we need to get list of country names and country dial codes to show in the above drop down. We used country-data node module for that.

To install country-data module use this  command.

npm install --save country-data

 

We have used it in the settings page as below.

import countryData from 'country-data';
    	countryData.countries.all.sort(function(a, b) {
            if(a.name < b.name){ return -1};
            if(a.name > b.name){ return 1};
            return 0;
        });
        let countries = countryData.countries.all.map((country, i) => {
         	return (<MenuItem value={countryData.countries.all[i].alpha2} key={i} primaryText={ countryData.countries.all[i].name+' '+ countryData.countries.all[i].countryCallingCodes[0] } />);
        });

 

First we sort the country data list from it’s name. After that we made a list of “”s from this list of data.
Then we have to check whether the user changed or added the phone number and region (dial code).
It handles by this function mentioned above. ( onChange={this.handleCountryChange}> and
onChange={this.handleTelephoneNoChange} )

    handleCountryChange = (event, index, value) => {
        this.setState({'countryCode': value });
    }

 

Then we have to get the phone number using below function.

    handleTelephoneNoChange = (event, value) => {
        this.setState({'phoneNo': value});
    }

 

Next we have to update the function that triggers when user clicks the save button.

    handleSubmit = () => {
        let newCountryCode = !this.state.countryCode?
        this.intialSettings.countryCode:this.state.countryCode;
        let newCountryDialCode = !this.state.countryDialCode?
        this.intialSettings.countryDialCode:this.state.countryDialCode;
        let newPhoneNo = this.state.phoneNo;
        let vals = {
            countryCode: newCountryCode,
            countryDialCode: newCountryDialCode,
            phoneNo: newPhoneNo
}
let settings = Object.assign({}, vals);
cookies.set('settings', settings);
 this.implementSettings(vals);
 }

 

This code snippet stores Country Code, Country Dial code and phone no in the server.
Now we have to update the Store. Here we are going to change UserPreferencesStore “UserPreferencesStore” .
First we have to setup default values for things we are going to store.

let _defaults = {
	  CountryCode: 'US',
   	  CountryDialCode: '+1',
   	  PhoneNo: ''
}

 

Finally we have to update the dispatchToken to change and get these new data

UserPreferencesStore.dispatchToken = ChatAppDispatcher.register(action => {
   switch (action.type) {
       case ActionTypes.SETTINGS_CHANGED: {
           let settings = action.settings;
           if(settings.hasOwnProperty('theme')){
                   _defaults.Theme = settings.theme;
           }
           if(settings.hasOwnProperty('countryDialCode')){
               _defaults.countryDialCode = settings.countryDialCode;
           }
           if(settings.hasOwnProperty('phoneNo')){
               _defaults.phoneNo = settings.phoneNo;
           }
           if(settings.hasOwnProperty('countryCode')){
               _defaults.countryCode = settings.countryCode;
           }
           UserPreferencesStore.emitChange();
           break;
}
}

 

Finally application is ready to store and update Mobile phone number and region code in the server.

Resources:

Continue ReadingHow to Store Mobile Settings in the Server from SUSI Web Chat Settings Page

SUSI.AI Chrome Bot and Web Speech: Integrating Speech Synthesis and Recognition

Susi Chrome Bot is a Chrome extension which is used to communicate with Susi AI. The advantage of having chrome extensions is that they are very accessible for the user to perform certain tasks which sometimes needs the user to move to another tab/site.

In this blog post, we will be going through the process of integrating the web speech API to SUSI Chromebot.

Web Speech API

Web Speech API enables web apps to be able to use voice data. The Web Speech API has two components:

Speech Recognition:  Speech recognition gives web apps the ability to recognize voice data from an audio source. Speech recognition provides the speech-to-text service.

Speech Synthesis: Speech synthesis provides the text-to-speech services for the web apps.

Integrating speech synthesis and speech recognition in SUSI Chromebot

Chrome provides the webkitSpeechRecognition() interface which we will use for our speech recognition tasks.

var recognition = new webkitSpeechRecognition();

 

Now, we have a speech recognition instance recognition. Let us define necessary checks for error detection and resetting the recognizer.

var recognizing;

function reset() {
recognizing = false;
}

recognition.onerror = function(e){
console.log(e.error);
};

recognition.onend = function(){
reset();
};

 

We now define the toggleStartStop() function that will check if recognition is already being performed in which case it will stop recognition and reset the recognizer, otherwise, it will start recognition.

function toggleStartStop() {
    if (recognizing) {
      recognition.stop();
      reset();
    } else {
      recognition.start();
      recognizing = true;
    }
}

 

We can then attach an event listener to a mic button which calls the toggleStartStop() function to start or stop our speech recognition.

mic.addEventListener("click", function () {
    toggleStartStop();
});

 

Finally, when the speech recognizer has some results it calls the onresult event handler. We’ll use this event handler to catch the results returned.

recognition.onresult = function (event) {
    for (var i = event.resultIndex; i < event.results.length; ++i) {
      if (event.results[i].isFinal) {
        textarea.value = event.results[i][0].transcript;
        submitForm();
      }
    }
};

 

The above code snipped tests for the results produced by the speech recognizer and if it’s the final result then it sets textarea value with the result of speech recognition and then we submit that to the backend.

One problem that we might face is the extension not being able to access the microphone. This can be resolved by asking for microphone access from an external tab/window/iframe. For SUSI Chromebot this is being done using an external tab. Pressing on the settings icon makes a new tab which then asks for microphone access from the user. This needs to be done only once, so that does not cause a lot of trouble.

setting.addEventListener("click", function () {
chrome.tabs.create({
url: chrome.runtime.getURL("options.html")
});
});navigator.webkitGetUserMedia({
audio: true
}, function(stream) {
stream.stop();
}, function () {
console.log('no access');
});

 

In contrast to speech recognition, speech synthesis is very easy to implement.

function speakOutput(msg){
    var voiceMsg = new SpeechSynthesisUtterance(msg);
    window.speechSynthesis.speak(voiceMsg);
}

 

This function takes a message as input, declares a new SpeechSynthesisUtterance instance and then calls the speak method to convert the text message to voice.

There are many properties and attributes that come with this speech recognition and synthesis interface. This blog post only introduces the very basics.

Resources

 

Continue ReadingSUSI.AI Chrome Bot and Web Speech: Integrating Speech Synthesis and Recognition
Read more about the article FOSSASIA Summit 2018 Singapore – Call for Speakers
Too big Crowd for only One Photo / One of Many Group Photos by Michael Cannon

FOSSASIA Summit 2018 Singapore – Call for Speakers

The FOSSASIA Open Tech Summit is Asia’s leading Open Technology conference for developers, companies, and IT professionals. The event will take place from Thursday, 22nd – Sunday, 25th March at the Lifelong Learning Institute in Singapore.

During four days developers, technologists, scientists, and entrepreneurs convene to collaborate, share information and learn about the latest in open technologies, including Artificial Intelligence software, DevOps, Cloud Computing, Linux, Science, Hardware and more. The theme of this year’s event is “Towards the Open Conversational Web“.

For our feature event we are looking for speaker submissions about Open Source for the following areas:

  • Artificial Intelligence, Algorithms, Search Engines, Cognitive Experts
  • Open Design, Hardware, Imaging
  • Science, Tech and Education
  • Kernel and Platform
  • Database
  • Cloud, Container, DevOps
  • Internet Society and Community
  • Open Event Solutions
  • Security and Privacy
  • Open Source in Business
  • Blockchain

There will be special events celebrating the 20th anniversary of the Open Source Initiative and its impact in Open Source business. An exhibition space is available for company and project stands.

Submission Guidelines

Please propose your session as early as possible and include a description of your session proposal that is as complete as possible. The description is of particular importance for the selection. Once accepted, speakers will receive a code for a speakers ticket. Speakers will receive a free speakers ticket and two standard tickets for their partner or friends. Sessions are accepted on an ongoing basis.

Submission Link: 2018.fossasia.org/speaker-registration

Dates & Deadlines

Please send us your proposal as soon as possible via the FOSSASIA Summit speaker registration.

Deadline for submissions: December 27th, 2017

Late submissions: Later submissions are possible, but early submissions have priority

Notification of acceptance: On an ongoing basis

Schedule Announced: January 20, 2018

FOSSASIA Open Tech Summit: March 22nd – 25th, 2018

Sessions and Tracks

Talks and Workshops

Talk slots are 20 minutes long plus 5-10 minutes for questions and answers. The idea is, that participants will use the sessions to get an idea of the work of others and are able to follow up in more detail in break-out areas, where they discuss more and start to work together. Speakers can also sign up for either a 1-hour long or a 2-hours workshop sessions. Longer sessions are possible in principle. Please tell us the proposed length of your session at the time of submission.

Lightning talks

You have some interesting ideas but do not want to submit a full talk? We suggest you go for a lightning talk which is a 5 minutes slot to present your idea or project. You are welcome to continue the discussion in breakout areas. There are tables and chairs to serve your get-togethers.

Stands and assemblies

We offer spaces in our exhibition area for companies, projects, installations, team gatherings and other fun activities. We are curious to know what you would like to make, bring or show. Please add details in the submission form.

Developer Rooms/Track Hosts

Get in touch early if you plan to organize a developer room at the event. FOSSASIA is also looking for team members who are interested to co-host and moderate tracks. Please sign up to become a host here.

Publication

Audio and video recordings of the lectures will be published in various formats under the Creative Commons Attribution 4.0 International (CC BY 4.0) license. This license allows commercial use by media institutions as part of their reporting. If you do not wish for material from your lecture to be published or streamed, please let us know in your submission.

Sponsorship & Contact

If you would like to sponsor FOSSASIA or have any questions, please contact us via office@fossasia.org.

Suggested Topics

  • Artificial Intelligence (SUSI.AI, Algorithms, Cognitive Expert Systems AI on a Chip)
  • Hardware (Architectures, Maker Culture, Small Devices)
  • 20 years Impact of Open Source in Business
  • DevOps (Continuous Delivery, Lean IT, Moving at Cloud-speed)
  • Networking (Software Defined Networking, OpenFlow, Satellite Communication)
  • Security (Coding, Configuration, Testing, Malware)
  • Cloud & Microservices (Containers – Libraries, Runtimes, Composition; Kubernetes; Docker, Distributed Services)
  • Databases (Location-aware and Mapping, Replication and Clustering, Data Warehousing, NoSQL)
  • Science and Applications (Pocket Science Lab, Neurotech, Biohacking, Science Education)
  • Business Development (Open Source Business Models, Startups, Kickstarter Campaigns)
  • Internet of Everything (Smart Home, Medical Systems, Environmental Systems)
  • Internet Society and Culture (Collaborative Development, Community, Advocacy, Government, Governance, Legal)​
  • Kernel Development and Linux On The Desktop (Meilix, Light Linux systems, Custom Linux Generator)
  • Open Design and Libre Art (Open Source Design)
  • Open Event (Event Management systems, Ticketing solutions, Scheduling, Event File Formats)

Links

Speaker Registration and Proposal Submission:
2018.fossasia.org/speaker-registration

FOSSASIA Summit: 2018.fossasia.org

FOSSASIA Summit 2017: Event Wrap-Up

FOSSASIA Photos: flickr.com/photos/fossasia/

FOSSASIA Videos: Youtube FOSSASIA

FOSSASIA on Twitter: twitter.com/fossasia

Continue ReadingFOSSASIA Summit 2018 Singapore – Call for Speakers

Using Inkscape to create SVG Files for Background of Event Badges in Badgeyay

Inkscape is a free and open-source vector graphics editor. I used it in the FOSSASIA Badgeyay repository whose main purpose is to create badges for the event created using open-event. Badges were created in Scalable Vector Graphics (SVG) because of its advantages over JPEG, png etc. such as: scalability, Search Engine Optimization (SEO) friendly, easy editing ability (as it gets saved in an XML format) and resolution independence.

My task (issue #20) was to create the background in SVG format so that it can be edited using XML file. Aim was to create the background in such a way so that we just have to find and replace the color code to see the color change in the image/background. Following background was to be reproduced in SVG format using Inkscape whose color can be edited using a text editor.

badge

This was achieved using Inkscape (as suggested in the issue itself) which let us create an SVG file. I created 2 layers, 1 for plain background, and the other containing the triangles of Voronoi Diagram. General steps are included in this awesome video tutorial – AbstractBackground.

I found this quite helpful in understanding the interface of Inkscape. After following this tutorial, I had to do changes as follows:

  • Layer 1 rectangle was made using mesh, giving 4 different colors at corners. I set these colors as grey with different opacity/alpha factor.
  • Then just like in the video, I created a small circular object, set it to ‘path to object’, made duplicates of them, scattered them on the rectangle of 1st layer.
  • Used extensions menu to use ‘voronoi diagram‘, and then applied this to the selected circles.
  • Then I removed these circles, ungrouped all the triangles formed , changed their color, just by picking with the background (which was grey — with different opacities!). Grouped them together again, removed the lines which were separating the triangles by setting stroke to none.
  • Now all one have to do is change the color of 1st layer’ rectangle, and the final image/background will get changed .

This change of color can be changed using a text editor too. I just had to find layer 1 rectangle in the XML tree, replace the ‘fill’ attribute with the required color code.

This was achieved using INKSCAPE.

badge background

Now using text editor (here Sublime Text 3) , find layer 1, and change ‘fill’ value of rect with say ‘37C871’.

 <g
      inkscape:label="Layer 1"
      inkscape:groupmode="layer"
      id="layer1"
      style="display:inline;opacity:1">
     <rect
        id="rect4504"
        width="141.3569"
        height="200.82413"
        x="-63.25676"
        y="-14.052279"
        style="opacity:1;fill:#37C871;fill-opacity:1;stroke:url(#linearGradient2561);stroke-width:0.57644272" />
   </g>

changed badge background color
Then again opening the svg file, gives us the output as :

Results can be seen in my Pull request #152 which eventually got merged.

Using the similar background and adding logo of FOSSASIA on the top, also adding editable Headings like ‘VIP’, ‘BUSINESS PASS’  was done further in #PR167.

If you want to contribute to FOSSASIA/badgeyay, you can create an issue here.

Resources:

Continue ReadingUsing Inkscape to create SVG Files for Background of Event Badges in Badgeyay

How App Social Links are specified in Open Event Frontend

This blog article will illustrate how the various social links are specified in the the footer of Open Event Frontend, using the settings API. Open Event Frontend, offers high flexibility to the admins regarding the settings of the App, and hence the media links are not hard coded, and can be changed easily via the admin settings panel.

The primary end point of Open Event API with which we are concerned with for fetching the settings  for the app is

GET /v1/settings

The model for settings has the following fields which concern the social links.

 googleUrl              : attr('string'),
 githubUrl              : attr('string'),
 twitterUrl             : attr('string')

Next we define them as segmented URL(s) so that they can make use of the link input widget.

segmentedTwitterUrl    : computedSegmentedLink.bind(this)('twitterUrl'),
 segmentedGoogleUrl     : computedSegmentedLink.bind(this)('googleUrl'),
 segmentedGithubUrl     : computedSegmentedLink.bind(this)('githubUrl'),

Now it is required for us to fetch the data from the API, by making the corresponding call to the API. Since the footer is present in every single page of the app, it is necessary that we make the call from the application route itself. Hence we add the following to the application route modal.

socialLinks: this.get('store').queryRecord('setting', {
})

Next we need to iterate over these social links, and add them to the footer as per their availability.So we will do so by first passing the model to the footer component, and then iterating over it in footer.hbs

{{footer-main socialLinks=model.socialLinks footerPages=footerPages}}


And thus we have passed the socialLinks portion of the model, under the alias socialLinks.Next, we iterate over them and each time check, if the link exists before rendering it.

<div class="three wide column">
     <div class="ui inverted link list">
       <strong class="item">{{t 'Connect with us'}}</strong>
       {{#if socialLinks.supportUrl}}
         <a class="item" href="{{socialLinks.supportUrl}}" target="_blank" rel="noopener noreferrer">
           <i class="info icon"></i> {{t 'Support'}}
         </a>
       {{/if}}
       {{#if socialLinks.facebookUrl}}
         <a class="item" href="{{socialLinks.facebookUrl}}" target="_blank" rel="noopener noreferrer">
           <i class="facebook f icon"></i> {{t 'Facebook'}}
         </a>
       {{/if}}
       {{#if socialLinks.youtubeUrl}}
         <a class="item" href="{{socialLinks.youtubeUrl}}" target="_blank" rel="noopener noreferrer">
           <i class="youtube icon"></i> {{t 'Youtube'}}
         </a>
       {{/if}}
       {{#if socialLinks.googleUrl}}
         <a class="item" href="{{socialLinks.googleUrl}}" target="_blank" rel="noopener noreferrer">
           <i class="google plus icon"></i> {{t 'Google +'}}
         </a>
       {{/if}}
     </div>
   </div>

Thus all the links in the app are easily manageable, from the admin settings menu, without the need of hard coding them. This approach also, makes it easy to preserve the configuration in a central location.

Resources

Continue ReadingHow App Social Links are specified in Open Event Frontend

Implementing Session and Speaker Creation From Event Panel In Open Event Frontend

Open-Event Front-end uses Ember data for handling Open Event Orga API which abides by JSON API specs. It allows the user to manage the event using the event panel of that event. This panel lets us create or update sessions & speakers. Each speaker must be associated with a session, therefore we save the session before saving the speaker.
In this blog we will see how to Implement the session & speaker creation via event panel. Lets see how we implemented it?

Passing the session & speaker models to the form
On the session & speaker creation page we need to render the forms using the custom form API and create new speaker and session entity. We create a speaker object here and we pass in the relationships for event and the user to it, likewise we create the session object and pass the event relationship to it.

These objects along with form which contains all the fields of the custom form, tracks which is a list of all the tracks & sessionTypes which is a list of all the session types of the event is passed in the model.

return RSVP.hash({
  event : eventDetails,
  form  : eventDetails.query('customForms', {
    'page[size]' : 50,
    sort         : 'id'
  }),
  session: this.get('store').createRecord('session', {
    event: eventDetails
  }),
  speaker: this.get('store').createRecord('speaker', {
    event : eventDetails,
    user  : this.get('authManager.currentUser')
  }),
  tracks       : eventDetails.query('tracks', {}),
  sessionTypes : eventDetails.query('sessionTypes', {})
});

We bind the speaker & session object to the template which has contains the session-speaker component for form validation. The request is only made if the form gets validated.

Saving the data

In Open Event API each speaker must be associated with a session, i.e we must define a session relationship for the speaker. To accomplish this we first save the session into the server and once it has been successfully saved we pass the session as a relation to the speaker object.

this.get('model.session').save()
  .then(session => {
    let speaker = this.get('model.speaker');
    speaker.set('session', session);
    speaker.save()
      .then(() => {
        this.get('notify').success(this.l10n.t('Your session has been saved'));
        this.transitionToRoute('events.view.sessions', this.get('model.event.id'));
      });
  })

We save the objects using the save method. After the speakers and sessions are save successfully we notify the user by showing a success message via the notify service.

Thank you for reading the blog, you can check the source code for the example here.

Resources

Continue ReadingImplementing Session and Speaker Creation From Event Panel In Open Event Frontend

Store User’s Personal Information with SUSI

In this blog, I discuss how SUSI.AI stores personal information of it’s users. This personal information is mostly about usernames/links to different websites like LinkedIn, GitHub, Facebook, Google/Gmail etc. To store such details, we have a dedicated API. Endpoint is :

https://api.susi.ai/aaa/storePersonalInfo.json

In this API/Servlet, storing the details and getting the details, both the aspects are covered. At the time of making the API call, user has an option either to ask the server for a list of available store names along with their values or request the server to store the value for a particular store name. If a store name already exists and a client makes a call with new/updated value, The servlet will update the value for that particular store name.

The reason you are looking at minimal user role as USER is quite obvious, i.e. these details correspond to a particular user. Hence neither we want someone writing such information anonymously nor we want this information to be visible to anonymous user until allowed by the user.

In the next steps, we start evaluating the API call made by the client. We look at the combination of the parameters present in the request. If the request is to fetch list of available stores, server first checks if Accounting object even has a JSONObject for “stores” or not. If not found, it sends an error message “No personal information is added yet.” and error code 420. Prior to all these steps, server first generates an accounting object for the user. If found, details are encoded as JSONObject’s parameter. Look at the code below to understand things fairly.

Accounting accounting = DAO.getAccounting(authorization.getIdentity());
        if(post.get("fetchDetails", false)) {
            if(accounting.getJSON().has("stores")){
                JSONObject jsonObject = accounting.getJSON().getJSONObject("stores");
                json.put("stores", jsonObject);
                json.put("accepted", true);
                json.put("message", "details fetched successfully.");
                return new ServiceResponse(json);
            } else {
                throw new APIException(420, "No personal information is added yet.");
            }
        }

If the request was not to fetch the list of available stores, It means client wants server to save a new field or update a previous value for that of a store name. A combination of If-else evaluates whether the call even contains required parameters.

if (post.get(“storeName”, null) == null) {
throw new APIException(422, “Bad store name encountered!”);
}

String storeName = post.get(“storeName”, null);
if (post.get(“value”, null) == null) {
throw new APIException(422, “Bad store name value encountered!”);
}

If request contains all the required data, then store name & value are extracted as key-value pair from the request.

In the next steps, since the server is expected to store list of the store names for a particular user, First the identity is gathered from the already present authorization object in “serviceImpl” method. If the server finds a “null” identity, It throws an error with error code 400 and error message “Specified User Setting not found, ensure you are logged in”.

Else, server first checks if a JSONObject with key “stores” exists or not. If not, It will create an object and will put the key value pair in the new JSONObject. Otherwise it would anyways do so.

Since these details are for a particular account (i.e. for a particular user), these are placed in the Accounting.json file. For better knowledge, Look at the code snippet below.

if (accounting.getJSON().has("stores")) {
                accounting.getJSON().getJSONObject("stores").put(storeName, value);
            } else {
                JSONObject jsonObject = new JSONObject(true);
                jsonObject.put(storeName, value);
                accounting.getJSON().put("stores", jsonObject);
            }

            json.put("accepted", true);
            json.put("message", "You successfully updated your account information!");
            return new ServiceResponse(json);

Additional Resources :

Continue ReadingStore User’s Personal Information with SUSI

Enhancing SUSI Desktop to Display a Loading Animation and Auto-Hide Menu Bar by Default

SUSI Desktop is a cross platform desktop application based on electron which presently uses chat.susi.ai as a submodule and allows the users to interact with susi right from their desktop. The benefits of using chat.susi.ai as a submodule is that it inherits all the features that the webapp offers and thus serves them in a nicely build native application.

Display a loading animation during DOM load.

Electron apps should give a native feel, rather than feeling like they are just rendering some DOM, it would be great if we display a loading animation while the web content is actually loading, as depicted in the gif below is how I implemented that.
Electron provides a nice, easy to use API for handling BrowserWindow, WebContent events. I read through the official docs and came up with a simple solution for this, as depicted in the below snippet.

onload = function () {
	const webview = document.querySelector('webview');
	const loading = document.querySelector('#loading');

	function onStopLoad() {
		loading.classList.add('hide');
	}

	function onStartLoad() {
		loading.classList.remove('hide');
	}

	webview.addEventListener('did-stop-loading', onStopLoad);
	webview.addEventListener('did-start-loading', onStartLoad);
};

Hiding menu bar as default

Menu bars are useful, but are annoying since they take up space in main window, so I hid them by default and users can toggle their display on pressing the Alt key at any point of time, I used the autoHideMenuBar property of BrowserWindow class while creating an object to achieve this.

const win = new BrowserWindow({
	
	show: false,
	autoHideMenuBar: true
});

Resources

1. More information about BrowserWindow class in the official documentation at electron.atom.io.
2. Follow a quick tutorial to kickstart creating apps with electron at https://www.youtube.com/watch?v=jKzBJAowmGg.
3. SUSI Desktop repository at https://github.com/fossasia/susi_desktop.

Continue ReadingEnhancing SUSI Desktop to Display a Loading Animation and Auto-Hide Menu Bar by Default

Using Browser Storage In SUSI Firefox Add-On

Browser storage API enables extensions to store and retrieve data, and listen for changes to the stored item. In SUSI Firefox add-on the browser storage is implemented to store the chat history in the browser memory. This allows the extension to maintain persistence when the popup is closed or opened. This article gives a brief idea about how to implement browser storage using SUSI Firefox add-on as a use case.

Adding Permission

To use this API you need to include the “storage” permission in your manifest.json file.

“permissions”: [
 “storage”
]

Adding this in the manifest.json file will grant your extension the permission to use the storage API

Properties of Storage

There are three properties of storage which allows the developer to use different types of storage areas. One can choose a suitable property to meet the requirements.

  1. Storage.sync – Represents the sync storage area. Data stored in sync storage are synced by the browser and are available across all instances of that browser (even on different devices) that the user is logged in. Note – Currently storage.sync is supported by modern browsers and recent versions of Firefox. Please refer the documentation for more details.
  2. Storage.local – Represents the local storage area. Items in local storage are local to the machine the extension was installed on.
  3. Storage.managed – Represents the managed storage area. Items in managed storage are set by the domain administrator and are read-only for the extension. Trying to modify this namespace results in an error.

In SUSI Firefox add-on Storage.sync is being used to leverage the benefit of storage sync across all instances of the browser. So the chat history and settings are synced across the browsers logged in by the user.

Storing Data

browser.storage.<storageType>.set(keys)  – This function allows one or more item to be stored in the browser storage. If there in key-value already existing then the value will be updated to the new value supplied in the function. The function returns a promise.

Note – <storageType> will be one of the writable storage types — storage.sync or storage.local

This is a snippet taken from SUSI Firefox add-on where the theme value from settings page is being stored in the browser storage.

if(response.settings.theme){
browser.storage.sync.set({
theme: response.settings.theme
});
}

Retrieving Data

browser.storage.<storageType>.get(keys)  – Retrieves one or more items from the storage area. A key or array of keys is used to identify the item(s) to be retrieved from storage. If an empty string, object or array is passed, an empty object will be retrieved. If you pass null, or an undefined value, the entire storage contents will be retrieved. The function returns a promise.

Note – <storageType> will be one of the writable storage types — storage.sync or storage.local

This is a snippet taken from SUSI Firefox add-on where the settings preferences are being persisted by retrieving setting values from storage.

var buffer = browser.storage.sync.get(null);
buffer.then(function(res){
if(res["theme"]){
if(res["theme"]=="dark"){
$("#theme").val("dark");
}
else{
$("#theme").val("light");
}
}
if(res["loggedUser"]){
loginForm.style.display="none";
logoutButton.style.display="block";
}
else{
loginForm.style.display="block";
logoutButton.style.display="none";
}

});

Null values are being passed in the get function.

Key Points To Remember

  • Storage API is asynchronous. For all storage related transaction, you will need to manage the promises. So it is to carry out any kind of memory related action by using then() method to avoid spurious results
  • Values are scoped to the extension, not to a specific domain (i.e. the same set of key/value pairs are available to all scripts in the background context and content scripts). So the values can be used across different scripts and it acts like a common data store for the scripts.
  • The values stored can be any JSON-ifiable value, not just String. This includes Array and Object, but only when their contents can be represented as JSON, which does not include DOM nodes.

Resources

Continue ReadingUsing Browser Storage In SUSI Firefox Add-On