The Road to Success in Google Summer of Code 2017

It’s the best time when GCI students can get the overview experience of GSoC and all the aspiring participant can get themselves into different projects of FOSSASIA.

I’m a Junior year undergraduate student pursuing B.Tech in Electrical Engineering from Indian Institute of Technology Patna. This summer, I spent coding in Google Summer of Code with FOSSASIA organization. It feels great to be an open-source enthusiast, and Google as a sponsor make it as icing on the cake. People can learn new things here and meet new people.

I came to know about GSoC through my senior colleagues who got selected in GSoC in the year 2016. It was around September 2016 and I was in 2nd year of my college. At that time, last year, result of GSoC was declared.

What is GSoC?

Consider GSoC as a big bowl which has lots of small balls and those small balls are open-source organizations. Google basically acts as a sponsor for the open-source organizations. A timeline is proposed according to the applied organization and then student select their favorite organization and start to contribute to it. Believe me, it’s not only computer science branch specific, anyone can take part in it and there is no minimum CPI requirement. I consider myself to be one of the examples who have an electrical branch with not so good academic performance yet successfully being part of GSoC 2017.

How to select an organization?

This is the most important step and it takes time. I wandered around 100 organizations to find where my interest actually lies. But now, I’ll describe how to sort this and find your organization a little quicker. Take a pen and paper (kindly don’t use notepad of pc) and write down your field of interest in computer science. Number every point in decreasing order of your interest. Then for each respective field write down its basic pre-requisites. Visit GSoC website, go to organization tab and there is a slide for searching working field of the organization. Select only one organization, dig out its website, see the previous project and its application. If nothing fits you, repeat the same with another organization. And if that organization interests you, then look for a project of that organization. First of all, look at that application of the project, and give that application a try and must give a feedback to the organization. Then try to find that what languages, modules, etc that project used to work and how the project works. Don’t worry if nothing goes into your mind. Find out the developers mailing list, their chat channel, their code base area. And ask developers out there for help.

First Love It:

Open-Source, it’s a different world which exists on Earth. All organizations are open-source and all their codes are open and free to view. Find things that interests you the most and start to love the work. If you don’t understand a code, learn things by doing and asking. Most of the times we don’t get favorable responses, in such times we need to carry on and have patience for the best to happen.

My Favourite part:

GSoC has been my dream since the day I came to know about it. It’s only through this that one gets a chance to explore open-source softwares, and organizations get a chance to hire on board developers. This is the great initiative taken by Google which brings hope for the developers to increase the use of open-source. This is one of the ways through which one can look into the codes of the developers and help them out and even also get helped.

GSoC is the platform through which one can implement lots of new things, meet new people, develop new softwares and see the world around in a different way. That’s what happened with me, it’s just at the end of the first phase, my love towards open-source increased exponentially. Now I see every problem in my life as a way to solve it through the open-source. Rather it’s part of arranging an event or designing an invitation, I am encouraged to use open-source tools to help me out. It becomes very easy to distribute data and convey information through open-source, so the people can reach to you much easier.

You always see a thing according to your perspective and it’s always the best but the open-source gives it a view through the perspective of the world and gets the best from them through a compilation of all the sources. One can give ideas, their views, find something that other can’t even see and increase its karma through contribution. And all these things have been made possible through GOOGLE only. I became such that I can donate the rest of my life working for open-source. GSoC is responsible for including the open-source contribution in my daily life. It made me feel really bad if my Github profile page has 0 contributions at the end of the day. Open Source opens door to another world.

Challenging part:

To conclude, I would say that GSoC made me love the challenge. I became such that the things that come easily to me don’t taste good to me at all. Specifically, GSoC’s most challenging part is to get into it that is to get selected. I still can’t believe that I was selected. Now onwards it’s just fun and learning. Each and every day, I encountered several issues, bugs, etc but just before going to bed at night, there were things which collectively made me feel that whether the bug has been solved or not, but I was able to break the upper most covering of that conch shell. And such things increases the motivation and light up the enthusiasm to tackle the problem. Open-Source not only taught me to control different snapshots of software but also of time. I learn to manage different works of day efficiently and it includes the contribution in open-source as part of my daily life.

Advice to students:

The only problem new developers have is to get started. I’ll advise them to close their eyes and dive into it without thinking whether they would be able to complete this task or not. Believe me, you will gradually find that whether the task is completed or not but you are much above the condition than you were at the time of beginning the task.

Just learn by doing the things.

Make mistakes and enlist them as “things that will not work” so one may read it and avoid it.

GSoC Project link:
Final Code Submission:

Handling Data Requests in Open Event Organizer Android App

Open Event Organizer is a client side application of Open Event API Server created for event organizers and entry managers. The app maintains a local database and syncs it with the server when required. I will be talking about handling data requests in the app in this blog.

The app uses ReactiveX for all the background tasks including data accessing. When a user requests any data, there are two possible ways the app can perform. The one where app fetches the data directly from the local database maintained and another where it requests data from the server. The app has to decide one of the ways. In the Organizer app, AbstractObservableBuilder class takes care of this. The relevant code is:

final class AbstractObservableBuilder<T> {

   private final IUtilModel utilModel;
   private boolean reload;
   private Observable<T> diskObservable;
   private Observable<T> networkObservable;


   private Callable<Observable<T>> getReloadCallable() {
       return () -> {
           if (reload)
               return Observable.empty();
               return diskObservable
                   .doOnNext(item -> Timber.d("Loaded %s From Disk on Thread %s",
                       item.getClass(), Thread.currentThread().getName()));

   private Observable<T> getConnectionObservable() {
       if (utilModel.isConnected())
           return networkObservable
               .doOnNext(item -> Timber.d("Loaded %s From Network on Thread %s",
                   item.getClass(), Thread.currentThread().getName()));
           return Observable.error(new Throwable(Constants.NO_NETWORK));

   private <V> ObservableTransformer<V, V> applySchedulers() {
       return observable -> observable

   public Observable<T> build() {
       if (diskObservable == null || networkObservable == null)
           throw new IllegalStateException("Network or Disk observable not provided");

       return Observable
               .flatMap(items -> diskObservable.toList())
               .flattenAsObservable(items -> items)


DiskObservable is a data request to the local database and networkObservable is a data request to the server. The build function decides which one to use and returns a correct observable accordingly. The class object takes a boolean field reload which is used to decide which observable to subscribe. If reload is true, that means the user wants data from the server, hence networkObservable is returned to subscribe. Also switchIfEmpty in the build method checks whether the data fetched using diskObservable is empty, if found empty it switches the observable to the networkObservable to subscribe.

This class object is used for every data access in the app. For example, this is a code snippet of the gettEvents method in EventRepository class.

public Observable<Event> getEvents(boolean reload) {
   Observable<Event> diskObservable = Observable.defer(() ->

   Observable<Event> networkObservable = Observable.defer(() ->
           .flatMapIterable(events -> events));

   return new AbstractObservableBuilder<Event>(utilModel)


1. Documentation of ReactiveX API
2. Github repository link of RxJava – Reactive Extension for JVM

Keeping Order of tickets in Event Wizard in Sync with API on Open Event Frontend

This blog article will illustrate how the various tickets are stored and displayed in order the event organiser decides  on  Open Event Frontend and also, how they are kept in sync with the backend.

First we will take a look at how the user is able to control the order of the tickets using the ticket widget.

{{#each tickets as |ticket index|}}
  {{widgets/forms/ticket-input ticket=ticket
  canMoveUp=(not-eq index 0)
  canMoveDown=(not-eq ticket.position (dec
  moveTicketUp=(action 'moveTicket' ticket 'up')
  moveTicketDown=(action 'moveTicket' ticket 'down')
  removeTicket=(confirm 'Are you sure you  wish to delete this 
  ticket ?' (action 'removeTicket' ticket))}}

The canMoveUp and canMoveDown are dynamic properties and are dependent upon the current positions of the tickets in the tickets array.  These properties define whether the up or down arraow or both should be visible alongside the ticket to trigger the moveTicket action.

There is an attribute called position in the ticket model which is responsible for storing the position of the ticket on the backend. Hence it is necessary that the list of the ticket available should always be ordered by position. However, it should be kept in mind, that even if the position attribute of the tickers is changed, it will not actually change the indices of the ticket records in the array fetched from the API. And since we want the ticker order in sync with the backend, i.e. user shouldn’t have to refresh to see the changes in ticket order, we are going to return the tickets via a computed function which sorts them in the required order.

tickets: computed('', '', function() {
   return this.get('').sortBy('position').filterBy('isDeleted', false);

The sortBy method ensures that the tickets are always ordered and this computed property thus watches the position of each of the tickets to look out for any changes. Now we can finally define the moveTicket action to enable modification of position for tickets.

moveTicket(ticket, direction) {
     const index = ticket.get('position');
     const otherTicket = this.get('').find(otherTicket => otherTicket.get('position') === (direction === 'up' ? (index - 1) : (index + 1)));
     otherTicket.set('position', index);
     ticket.set('position', direction === 'up' ? (index - 1) : (index + 1));

The moveTicket action takes two arguments, ticket and direction. It temporarily stores the position of the current ticket and the position of the ticket which needs to be swapped with the current ticket.Based on the direction the positions are swapped. Since the position of each of the tickets is being watched by the tickets computed array, the change in order becomes apparent immediately.

Now when the User will trigger the save request, the positions of each of the tickets will be updated via a PATCH or POST (if the ticket is new) request.

Also, the positions of all the tickets maybe affected while adding a new ticket or deleting an existing one. In case of a new ticket, the position of the new ticket should be initialised while creating it and it should be below all the other tickets.

addTicket(type, position) {
     const salesStartDateTime = moment();
     const salesEndDateTime = this.get('data.event.startsAt');
     this.get('').pushObject('ticket', {
       salesStartsAt : salesStartDateTime,
       salesEndsAt   : salesEndDateTime

Deleting a ticket requires updating positions of all the tickets below the deleted ticket. All of the positions need to be shifted one place up.

removeTicket(deleteTicket) {
     const index = deleteTicket.get('position');
     this.get('').forEach(ticket => {
       if (ticket.get('position') > index) {
         ticket.set('position', ticket.get('position') - 1);

The tickets whose position is to be updated are filtered by comparison of their position from the position of the deleted ticket.


Implementing Order Statistics API on Tickets Route in Open Event Frontend

The order statistics API endpoints are used to display the statistics related to tickets, orders, and sales. It contains the details about the total number of orders, the total number of tickets sold and the amount of the sales. It also gives the detailed information about the pending, expired, placed and completed orders, tickets, and sales.

This article will illustrate how the order statistics can be displayed using the Order Statistics API in Open Event Frontend. The primary end point of Open Event API with which we are concerned with for statistics is

GET /v1/events/{event_identifier}/order-statistics

First, we need to create a model for the order statistics, which will have the fields corresponding to the API, so we proceed with the ember CLI command:

ember g model order-statistics-tickets

Next, we need to define the model according to the requirements. The model needs to extend the base model class. The code for the model looks like this:

import attr from 'ember-data/attr';
import ModelBase from 'open-event-frontend/models/base';

export default ModelBase.extend({
  orders  : attr(),
  tickets : attr(),
  sales   : attr()

As we need to display the statistics related to orders, tickets, and sales so we have their respective variables inside the model which will fetch and store the details from the API.

Now, after creating a model, we need to make an API call to get the details. This can be done using the following:

return this.modelFor('events.view').query('orderStatistics', {});

Since the tickets route is nested inside the event.view route so, first we are getting the model for event.view route and then we’re querying order statistics from the model.

The complete code can be seen here.

Now, we need to call the model inside the template file to display the details. To fetch the total orders we can write like this



In a similar way, the total sales can be displayed like this.



And total tickets can be displayed like this



If we want to fetch other details like the pending sales or completed orders then the only thing we need to replace is the total attribute. In place of total, we can add any other attribute depending on the requirement. The complete code of the template can be seen here.

The UI for the order statistics on the tickets route looks like this.

Fig. 1: The user interface for displaying the statistics

The complete source code can be seen here.


Implementing Pages API in Open Event Frontend

The pages endpoints are used to create static pages which such as about page or any other page that doesn’t need to be updated frequently and only a specific content is to be shown. This article will illustrate how the pages can be added or removed from the /admin/content/pages route using the pages API in Open Event Frontend. The primary end point of Open Event API with which we are concerned with for pages is

GET /v1/pages

First, we need to create a model for the pages, which will have the fields corresponding to the API, so we proceed with the ember CLI command:

ember g model page

Next, we need to define the model according to the requirements. The model needs to extend the base model class. The code for the page model looks like this:

import attr from 'ember-data/attr';
import ModelBase from 'open-event-frontend/models/base';

export default ModelBase.extend({
  name        : attr('string'),
  title       : attr('string'),
  url         : attr('string'),
  description : attr('string'),
  language    : attr('string'),
  index       : attr('number', { defaultValue: 0 }),
  place       : attr('string')

As the page will have name, title, url which will tell the URL of the page, the language, the description, index and the place of the page where it has to be which can be either a footer or an event.

The complete code for the model can be seen here.

Now, after creating a model, we need to make an API call to get and post the pages created. This can be done using the following:

return this.get('store').findAll('page');

The above line will check the store and find all the pages which have been cached in and if there is no record found then it will make an API call and cache the records in the store so that when called it can return it immediately.

Since in the case of pages we have multiple options like creating a new page, updating a new page, deleting an existing page etc. For creating and updating the page we have a form which has the fields required by the API to create the page.  The UI of the form looks like this.

Fig. 1: The user interface of the form used to create the page.

Fig. 2: The user interface of the form used to update and delete the already existing page

The code for the above form can be seen here.

Now, if we click the items which are present in the sidebar on the left, it enables us to edit and update the page by displaying the information stored in the form and then the details be later updated on the server by clicking the Update button. If we want to delete the form we can do so using the delete button which first shows a pop up to confirm whether we actually want to delete it or not. The code for displaying the delete confirmation pop up looks like this.

<button class="ui red button" 
{{action (confirm (t 'Are you sure you would like to delete this page?') (action 'deletePage' data))}}>
{{t 'Delete'}}</button>


The code to delete the page looks like this

deletePage(data) {
    if (!this.get('isCreate')) {
      this.set('isFormOpen', false);

In the above piece of code, we’re checking whether the form is in create mode or update mode and if it’s in create mode then we can destroy the record and then close the form.

The UI for the pop up looks like this.

Fig.3: The user interface for delete confirmation pop up

The code for the entire process of page creation to deletion can be checked here

To conclude, this is how we efficiently do the process of page creation, updating and deletion using the Open-Event-Orga pages API  ensuring that there is no unnecessary API call to fetch the data and no code duplication.


Using Android Palette with Glide in Open Event Organizer Android App

Open Event Organizer is an Android Application for the Event Organizers and Entry Managers. The core feature of the App is to scan a QR code from the ticket to validate an attendee’s check in. Other features of the App are to display an overview of sales, ticket management and basic editing in the Event Details. Open Event API Server acts as a backend for this App. The App uses Navigation Drawer for navigation in the App. The side drawer contains menus, event name, event start date and event image in the header. Event name and date is shown just below the event image in a palette. For a better visibility Android Palette is used which extracts prominent colors from images. The App uses Glide to handle image loading hence GlidePalette library is used for palette generation which integrates Android Palette with Glide. I will be talking about the implementation of GlidePalette in the App in this blog.

The App uses Data Binding so the image URLs are directly passed to the XML views in the layouts and the image loading logic is implemented in the BindingAdapter class. The image loading code looks like:



So as to implement palette generation for event detail label, it has to be implemented with the event image loading. GlideApp takes request listener which implements methods on success and failure where palette can be generated using the bitmap loaded. With GlidePalette most of this part is covered in the library itself. It provides GlidePalette class which is a sub class of GlideApp request listener which is passed to the GlideApp using the method listener. In the App, BindingAdapter has a method named bindImageWithPalette which takes a view container, image url, a placeholder drawable and the ids of imageview and palette. The relevant code is:

@BindingAdapter(value = {"paletteImageUrl", "placeholder", "imageId", "paletteId"}, requireAll = false)
public static void bindImageWithPalette(View container, String url, Drawable drawable, int imageId, int paletteId) {
   ImageView imageView = (ImageView) container.findViewById(imageId);
   ViewGroup palette = (ViewGroup) container.findViewById(paletteId);

   if (TextUtils.isEmpty(url)) {
       if (drawable != null)
       for (int i = 0; i < palette.getChildCount(); i++) {
           View child = palette.getChildAt(i);
           if (child instanceof TextView)
               ((TextView) child).setTextColor(Color.WHITE);
   GlidePalette<Drawable> glidePalette = GlidePalette.with(url)

   for (int i = 0; i < palette.getChildCount(); i++) {
       View child = palette.getChildAt(i);
       if (child instanceof TextView)
               .intoTextColor((TextView) child, GlidePalette.Swatch.TITLE_TEXT_COLOR);
   setGlideImage(imageView, url, drawable, null, glidePalette);


The code is pretty obvious. The method checks passed URL for nullability. If null, it sets the placeholder drawable to the image view and default colors to the text views and the palette. The GlidePalette object is generated using the initializer method with which takes the image URL. The request is passed to the method setGlideImage which loads the image and passes the GlidePalette to the GlideApp as a listener. Accordingly, the palette is generated and the colors are set to the label and text views accordingly. The container view in the XML layout looks like:

   app:paletteImageUrl="@{ event.largeImageUrl }"
   app:placeholder="@{ @drawable/header }"
   app:imageId="@{ }"
   app:paletteId="@{ }">


1. Documentation for Glide Image Loading Library
2. GlidePalette Github Repository
3. Android Palette Official Documentation

Making App Name Configurable for Open Event Organizer App

Open Event Organizer is a client side android application of Open Event API server created for event organizers and entry managers. The application provides a way to configure the app name via environment variable app_name. This allows the user to change the app name just by setting the environment variable app_name to the new name. I will be talking about its implementation in the application in this blog.

Generally, in an android application, the app name is stored as a static string resource and set in the manifest file by referencing to it. In the Organizer application, the app name variable is defined in the app’s gradle file. It is assigned to the value of environment variable app_name and the default value is assigned if the variable is null. The relevant code in the manifest file is:

def app_name = System.getenv('app_name') ?: "eventyay organizer"


The default value of app_name is kept, eventyay organizer. This is the app name when the user doesn’t set environment variable app_name. To reference the variable from the gradle file into the manifest, manifestPlaceholders are defined in the gradle’s defaultConfig. It is a map of key value pairs. The relevant code is:

defaultConfig {
   manifestPlaceholders = [appName: app_name]


This makes appName available for use in the app manifest. In the manifest file, app name is assigned to the appName set in the gradle.



By this, the application name is made configurable from the environment variable.

1. ManifestPlaceholders documentation
2. Stackoverflow answer about getting environment variable in gradle

Adding Number of Sessions Label in Open Event Android App

The Open Event Android project has a fragment for showing tracks of the event. The Tracks Fragment shows the list of all the Tracks with title and TextDrawable. But currently it is not showing how many sessions particular track has. Adding TextView with rounded corner and colored background showing number of sessions for track gives great UI. In this post I explain how to add TextView with rounded corner and how to use Plurals in Android.

1. Create Drawable for background

Firstly create track_rounded_corner.xml Shape Drawable which will be used as a background of the TextView. The <shape> element must be the root element of Shape drawable. The android:shape attribute defines the type of the shape. It can be rectangle, ring, oval, line. In our case we will use rectangle.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android=""

    <corners android:radius="360dp" />

        android:top="2dp" />


Here the <corners> element creates rounded corners for the shape with the specified value of radius attribute. This tag is only applied when the shape is a rectangle. The <padding> element adds padding to the containing view. You can modify the value of the padding as per your need. You can feel shape with appropriate color using <solid> as we are setting color dynamically we will not set color here.

2. Add TextView and set Drawable

Now add TextView in the track list item which will contain number of sessions text. Set  track_rounded_corner.xml drawable we created before as background of this TextView using background attribute.



Set color and text size according to your need. Here don’t add padding in the TextView because we have already added padding in the Drawable. Adding padding in the TextView will override the value specified in the drawable.

3.  Create TextView object in ViewHolder

Now create TextView object noOfSessions and bind it with using ButterKnife.bind() method.

public class TrackViewHolder extends RecyclerView.ViewHolder {

    TextView noOfSessions;

    private Track track;

    public TrackViewHolder(View itemView, Context context) {
        ButterKnife.bind(this, itemView);

    public void bindTrack(Track track) {
        this.track = track;


Here TrackViewHolder is a RecycleriewHolder for the TracksListAdapter. The bindTrack() method of this view holder is used to bind Track with ViewHolder.

4.  Add Quantity Strings (Plurals) for Sessions

Now we want to set the value of TextView. Here if the number of sessions of the track is zero or more than one then we need to set text  “0 sessions” or “2 sessions”. If the track has only one session than we need to set text “1 session” to make text meaningful. In android we have Quantity Strings which can be used to make this task easy.

    <!--Quantity Strings(Plurals) for sessions-->
    <plurals name="sessions">
        <item quantity="zero">No sessions</item>
        <item quantity="one">1 session</item>
        <item quantity="other">%d sessions</item>


Using this plurals resource we can get appropriate string for specified quantity like “zero”, “one” and  “other” will return “No sessions”, “1 session”, and “2 sessions”. accordingly. 2 can be any value other than 0 and 1.

Now let’s set background color and test for the text view.

int trackColor = Color.parseColor(track.getColor());
int sessions = track.getSessions().size();

noOfSessions.getBackground().setColorFilter(trackColor, PorterDuff.Mode.SRC_ATOP);
                sessions, sessions));


Here we are setting background color of textview using getbackground().setColorFilter() method. To set appropriate text we are using getQuantityString() method which takes plural resource and quantity(in our case no of sessions) as parameters.

Now we are all set. Run the app it will look like this.


Adding TextView with rounded corner and colored background in the App gives great UI and UX. To know more about Rounded corner TextView and Quantity Strings follow the links given below.

Using ThreeTenABP for Time Zone Handling in Open Event Android

The Open Event Android project helps event organizers to organize the event and generate Apps (apk format) for their events/conferences by providing API endpoint or zip generated using Open Event server. For any Event App it is very important that it handles time zone properly. In Open Event Android App there is an option to change time zone setting. The user can view date and time of the event and sessions in Event Timezone and Local time zone in the App. ThreeTenABP provides a backport of the Java SE 8 date-time classes to Java SE 6 and 7. In this blog post I explain how to use ThreeTenABP for time zone handling in Android.

Add dependency

To use ThreeTenABP in your application you have to add the dependency in your app module’s build.gradle file.

dependencies {
      compile    'com.jakewharton.threetenabp:threetenabp:1.0.5'
      testCompile   'org.threeten:threetenbp:1.3.6'

Initialize ThreeTenABP

Now in the onCreate() method of the Application class initialize ThreeTenABP.


Create getZoneId() method

Firstly create getZoneId() method which will return ZoneId according to user preference. This method will be used for formatting and parsing dates Here showLocal is user preference. If showLocal is true then this function will return Default local ZoneId otherwise ZoneId of the Event.

private static ZoneId geZoneId() {
        if (showLocal || Utils.isEmpty(getEventTimeZone()))
            return ZoneId.systemDefault();
            return ZoneId.of(getEventTimeZone());

Here  getEventTimeZone() method returns time zone string of the Event.

ThreeTenABP has mainly two classes representing date and time both.

  • ZonedDateTime : ‘2011-12-03T10:15:30+01:00[Europe/Paris]’
  • LocalDateTime : ‘2011-12-03T10:15:30’

ZonedDateTime contains timezone information at the end. LocalDateTime doesn’t contain timezone.

Create method for parsing and formating

Now create getDate() method which will take isoDateString and will return ZonedDateTime object.

public static ZonedDateTime getDate(@NonNull String isoDateString) {
        return ZonedDateTime.parse(isoDateString).withZoneSameInstant(getZoneId());;


Create formatDate() method which takes two arguments first is format string and second is isoDateString. This method will return a formatted string.

public static String formatDate(@NonNull String format, @NonNull String isoDateString) {
        return DateTimeFormatter.ofPattern(format).format(getDate(isoDateString));

Use methods

Now we are ready to format and parse isoDateString. Let’s take an example. Let “2017-11-09T23:08:56+08:00” is isoDateString. We can parse this isoDateString using getDate() method which will return ZonedDateTime object.


String isoDateString = "2017-11-09T23:08:56+08:00";

ZonedDateTime dateInEventTimeZone = DateConverter.getDate(isoDateString);

dateInEventTimeZone.toString();  //2017-11-09T23:08:56+08:00[Asia/Singapore]

ZonedDateTime dateInLocalTimeZone = DateConverter.getDate(dateInLocalTimeZone);

dateInLocalTimeZone.toString();  //2017-11-09T20:38:56+05:30[Asia/Kolkata]



String date = "2017-03-17T14:00:00+08:00";
String formattedString = formatDate("dd MM YYYY hh:mm:ss a", date));

formattedString // "17 03 2017 02:00:00 PM"


As you can see, ThreeTenABP makes Time Zone handling so easy. It has also support for default formatters and methods. To learn more about ThreeTenABP follow the links given below.

Implementing Notifications in Open Event Server

In FOSSASIA’s Open Event Server project, along with emails, almost all actions have necessary user notifications as well. So, when a new session is created or a session is accepted by the event organisers, along with the email, a user notification is also sent. Though showing the user notification is mainly implemented in the frontend site but the content to be shown and on which action to show is strictly decided by the server project.

A notification essentially helps an user to get the necessary information while staying in the platform itself and not needing to go to check his/her email for every action he performs. So unlike email which acts as a backup for the informations, notification is more of an instant thing.


The Notifications API is mostly like all other JSON API endpoints in the open event project. However in Notifications API we do not allow any to send a POST request. The admin of the server is able to send a GET a request to view all the notifications that are there in the system while a user can only view his/her notification. As of PATCH we allow only the user to edit his/her notification to mark it as read or not read. Following is the schema for the API:

class NotificationSchema(Schema):
    API Schema for Notification Model

    class Meta:
        Meta class for Notification API schema
        type_ = 'notification'
        self_view = 'v1.notification_detail'
        self_view_kwargs = {'id': '<id>'}
        self_view_many = 'v1.microlocation_list_post'
        inflect = dasherize

    id = fields.Str(dump_only=True)
    title = fields.Str(allow_none=True, dump_only=True)
    message = fields.Str(allow_none=True, dump_only=True)
    received_at = fields.DateTime(dump_only=True)
    accept = fields.Str(allow_none=True, dump_only=True)
    is_read = fields.Boolean()
    user = Relationship(attribute='user',
                        self_view_kwargs={'id': '<id>'},
                        related_view_kwargs={'notification_id': '<id>'},

The main things that are shown in the notification from the frontend are the
title and message. The title is the text that is shown without expanding the entire notification that gives an overview about the message in case you don’t want to read the entire message. The message however provides the entire detail that is associated with the action performed. The user relationship stores which user the particular notification is related with. It is a one-to-one relationship where one notification can only belong to one user. However one user can have multiple notifications. Another important attribute is the is_read attribute. This is the only attribute that is allowed to be changed. By default, when we make an entry in the database, is_read is set to FALSE. Once an user has read the notification, a request is sent from the frontend to change is_read to TRUE.

The different actions for which we send notification are stored in the models/ file as global variables.

USER_CHANGE_EMAIL = "User email"'
NEW_SESSION = 'New Session Proposal'
PASSWORD_CHANGE = 'Change Password'
EVENT_ROLE = 'Event Role Invitation'
TICKET_PURCHASED = 'Ticket(s) Purchased'
TICKET_PURCHASED_ATTENDEE = 'Ticket(s) purchased to Attendee    '
EVENT_EXPORTED = 'Event Exported'
EVENT_EXPORT_FAIL = 'Event Export Failed'
EVENT_IMPORTED = 'Event Imported'

HTML Templates

The notification title and message that is stored in the database and later served via the Notification API is created using some string formatting HTML templates. We firstly import all the global variables that represent the various actions from the notification model. Then we declare a global dict type variable named NOTIFS which stores all title and messages to be stored in the notification table.

        'title': u'New session proposal for {event_name}',
        'message': u"""The event <strong>{event_name}</strong> has received
             a new session proposal.<br><br>
            <a href='{link}' class='btn btn-info btn-sm'>View Session</a>""",
        'recipient': 'Organizer',

This is an example of the contents stored inside the dict. For every action, there is a dict with attributes
title, message and recipient. Title contains the brief overview of the entire notification whereas message contains a more vivid description with proper links. Recipient contains the one who receives the notification. So for example in the above code snippet, it is a notification for a new session created. The notification goes to the organizer. The title and message contains named placeholders which are later replaced by particular values using python’s .format() function.

Notification Helper

Notification helper module contains two main parts :-

  1. A parent function which saves the notification to the table related to the user to whom the notification belongs.
  2. Individual notification helper functions that are used by the APIs to save notification after various actions are performed.

Parent Function

def send_notification(user, action, title, message):
    if not current_app.config['TESTING']:
        notification = Notification(,
        save_to_db(notification, msg="Notification saved")
        record_activity('notification_event', user=user, action=action, title=title)

() is the parent function which takes as parameters user, action, title and message and stores them in the notification table in the database. The user is the one to whom the notification belongs to, action represents the particular action in an API which triggered the notification. Title and message are the contents that are shown in the frontend in the form of a notification. The frontend can implement it as a dropdown notification like facebook or a desktop notification like gitter or whatsapp. After the notification is saved we also update the activity table with the action that a notification has been saved for a user with the following action and title. Later, the Notification API mentioned in the very beginning of the blog uses this data that is being stored now and serves it as a JSON response.

Individual Functions

Apart from this, we have individual functions that uses the parent function to store notifications particular to a particular actions. For example, we have a send_notif_new_session_organizer() function which is used to save notification for all the organizers of an event that a new session has been added to their particular event. This function is called when a POST request is made in the Sessions API and the data is saved successfully. The function is executed for all the organizers of the event for which the session has been created.

def send_notif_new_session_organizer(user, event_name, link):
    message_settings = MessageSettings.query.filter_by(action=NEW_SESSION).first()
    if not message_settings or message_settings.notification_status == 1:
        notif = NOTIFS[NEW_SESSION]
        action = NEW_SESSION
        title = notif['title'].format(event_name=event_name)
        message = notif['message'].format(event_name=event_name, link=link)

        send_notification(user, action, title, message)

In the above function, we take in 3 parameters, user, event_name and link. The value of the user parameter is used to link the notification to that particular user. Event_name and link are used in the title and message of the notification that is saved in the database. Firstly in the function we check if there is certain message setting which tells that the user doesn’t want to receive notifications related to new sessions being created. If not, we proceed. We get the title and message strings from the NOTIFS dict from the file.

After that, using string formatting we get the actual message. For example,

u'New session proposal for {event_name}'.format(‘FOSSASIA’)

would give us a resulting string of the form:

u'New session proposal for FOSSASIA'

After this, we use this variables and send them as parameters to the send_notification() parent function to save the notification properly.