Using Partial in Handlebars and Reusing Code

Open Event Webapp uses handlebar partials for optimizing code. We can reuse a template using Handlebars partial.

How to use Handlebars partial ?

To use Handlebars partial, we have to follow some easy steps:

Step 1: In the .hbs file containing code, register your partial by using function Handlebars.registerPartial 

Handlebars.registerPartial('myPartial', '{{name}}')

Step 2: Calling the partial

{{> myPartial }}

In Open-Event Webapp we have made partials for common templates like navbar and footer.

1. // Navbar template (navbar.hbs)

  
 <!-- Fixed navbar -->
 <nav class="navbar navbar-default navbar-fixed-top">
  <div class="container">
   <div class="navbar-header navbar-left pull-left">
    <a class="navbar-brand" href="{{ eventurls.main_page_url }}">
    {{#if eventurls.logo_url}}
    <img alt="{{eventurls.name}}" class="logo logo-dark" src="{{  eventurls.logo_url }}">
    {{else}}
    {{ eventurls.name }}
    {{/if}}
    </a>
   </div>
 <div class="navbar-header navbar-right pull-right">
   <ul style="margin-left:20px" class="nav navbar-nav pull-left">
   {{#sociallinks}}
   {{#if show}}
    <li class="pull-left"><a href="{{link}}" style="padding-right:0; padding-left:0;margin-left:15px"><i class="fa fa-lg fa-{{icon}}" aria-hidden="true" title="{{{icon}}}"></i></a></li>
   {{/if}}
   {{/sociallinks}}
   </ul>
 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" style="margin-left:1em;margin-top:1em;">
   <span class="sr-only">Toggle navigation</span>
   <span class="icon-bar"></span>
   <span class="icon-bar"></span>
   <span class="icon-bar"></span>
 </button>
 </div>

 <div class="hidden-lg hidden-md hidden-sm clearfix"></div>
   <div class="collapse navbar-collapse">
    <ul class="nav navbar-nav navbar-right">
     <li class="navlink"><a id="homelink" href="index.html">Home</a>
     {{#if timeList}}
     <li class="navlink">
     <a id="schedulelink"href="schedule.html">
     Schedule</a>
     </li>
     {{/if}}
     {{#if tracks}}
     <li class="navlink">
      <a id="trackslink" href="tracks.html">Tracks</a>
    </li>
  {{/if}}
     {{#if roomsinfo}}
     <li class="navlink">
      <a id="roomslink" href="rooms.html">Rooms</a>   
     </li>
    {{/if}}
    {{#if speakerslist}}
    <li class="navlink">
      <a id="speakerslink" href="speakers.html">Speakers</a>
     </li>
    {{/if}}
   </ul>
     </div>
   </div>
 </nav>
//Compiling Template by providing path

2. const navbar = handlebars.compile(fs.readFileSync(__dirname + '/templates/partials/navbar.hbs').toString('utf-8'));
// Register Partial

3. handlebars.registerPartial('navbar', navbar);

PIL to convert type and quality of image

Image upload is an important part of the server. The images can be in different formats and after applying certain javascript modifications, they can be changed to different formats. For example, when an image is uploaded after cropping in open event organizer server, it is saved in PNG format. But PNG is more than 5 times larger than JPEG image. So when we upload a 150KB image, the image finally reaching the server is around 1MB which is huge. So we need to decide in the server which image format to select in different cases and how to convert them.

Continue reading “PIL to convert type and quality of image”

Handling data in android

So this week I was working with getting some data from the sqlite database in android and someone who was a beginner in android also asked me to help him with the same. I asked him what he knew and he said that even after reading up a lot he wasn’t able to figure out what exactly to do with the data he wants to save and use in his app. I have seen that this is a problem with a lot of people starting to develop android apps. So, I decided to write a blog on how can you handle your data in your android apps.

Most of the android apps need to save data even if only to save some user preferences. So primarily there are 3 ways to save your data :

  1. In form of key values (SharedPreferences)
  2. Reading/Writing to files
  3. Writing to a database

So let’s go step by step. When we need to store just some preferences of the users like if they want notifications or what kind of theme they want : light or dark etc. So basically if we want to store a key value in the persitant storage of the app we can do that using SharedPreferences. To use sharedpreferences, we initialise the sharedpreference object like

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

in oncreate and cache it. Then we just need to add or retrieve what we want using this cached SharedPreferences object. To Add a key value pair :

sharedPreferences.edit().putString("someKey", "someValue").apply();

Also you can put all kinds of stuff here. For example right now we added a string with key “someKey” and Value “someValue”. We can also add Booleans, Floats, Ints, Longs, StringSets etc.

To retrieve the same value we do something like this

sharedPreferences.getString("someKey", "DefaultValue");

Now if you want some logs or some values that can be exported and sent to your server, you should write them to files and maybe read some json inputs etc. as well.

Basically android has a File system similar to other platforms. All android devices have two file storage areas : “Internal” and “external” storage. The difference between them is as follows :

Internal :

  • Always available
  • Files saved here are accesible by only your app
  • When user uninstalls the app, system removes all your app’s files from internal storage

Best to use this when you want to be sure that neither the user nor the other app’s can access your files

External :

  • It’s not always available because user can mount external storage as USB storage and remove it as well
  • It’s readable by anything(Other apps, users etc.)
  • When you uninstall, system removes your app’s files from here only if you save them in the directory from getExternalFilesDir()

Now to read and write files, you need extra permissions

  • android.permission.WRITE_EXTERNAL_STORAGE
  • android.permission.READ_EXTERNAL_STORAGE

So now let’s get down to it. How do I save and read files in my app?

You first initialise the File object

File file = new File(context.getFilesDir(), filename);

This will create a file with filename in the internal storage. For external storage

first check if the storage is available, then just create a file using getExternalStoragePublicDirectory

File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;

This is for writing public files.

Now we move onto the most used part in an android app which is a database.Android has a built in SQLite database package which helps us in writing databases in files with syntax similar to SQL.

You need to add 2 classes which are mandatory and another class which basically helps you get organised. So the first is a Contract. This is where you actually write statements that will be executed later on to initialise or create the tables we want. For this make an a static abstract inner class that implements BaseColums like

public static abstract class Microlocation implements BaseColumns {
    public static final String TABLE_NAME = "microlocation";

    public static final String ID = "id";

    public static final String NAME = "name";

    public static final String LATITUDE = "latitude";

    public static final String LONGITUDE = "longitude";

    public static final String FLOOR = "floor";

    public static final String[] FULL_PROJECTION = {
            ID,
            NAME,
            LATITUDE,
            LONGITUDE,
            FLOOR

    };

    public static final String CREATE_TABLE =
            "CREATE TABLE " + TABLE_NAME
                    + " ("
                    + ID + INT_TYPE + PRIMARY_KEY + COMMA_SEP
                    + NAME + TEXT_TYPE + COMMA_SEP
                    + LATITUDE + REAL_TYPE + COMMA_SEP
                    + LONGITUDE + REAL_TYPE + COMMA_SEP
                    + FLOOR + INT_TYPE
                    + " );";

    public static final String DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;


}

Here we are making static final Strings for column names and then creating a static final String CREATE_TABLE which is basically a statement that creates the table Microlocation with the specified key, columns, data types etc.

After adding this structure for all the tables we want to have in our database, we move on to adding a DbHelper class that extends SQLiteOpenHelper which basically has two Abstract methods called onCreate(SQLiteDatabase db) and onUpgrade(SQLiteDatabase db) which are called when the database is created and database version is changed respectively. We call all our CREATE_TABLE static Strings in onCreate which in turn creates all the tables. Something like this :

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(DbContract.Speakers.CREATE_TABLE);
    db.execSQL(DbContract.Sponsors.CREATE_TABLE);
    db.execSQL(DbContract.Sessions.CREATE_TABLE);
    db.execSQL(DbContract.Tracks.CREATE_TABLE);
    db.execSQL(DbContract.Sessionsspeakers.CREATE_TABLE);
    db.execSQL(DbContract.Event.CREATE_TABLE);
    db.execSQL(DbContract.Microlocation.CREATE_TABLE);
    db.execSQL(DbContract.Versions.CREATE_TABLE);
    db.execSQL(DbContract.Bookmarks.CREATE_TABLE);
    db.execSQL(DbContract.EventDates.CREATE_TABLE);
}

You can also call DELETE_TABLE Strings in onUpgrade and the call onCreate again if you like but it’s not compulsory.

Now that you’re database is initialised, let’s add some records into it. For example I have to add a new Micrlocation I’d create a method in my data model where I’ll add a basic structure for the query and then format it with the values for a particular object of the model. Something, like this

public String generateSql() {
    String insertQuery = "INSERT INTO %s VALUES ('%d', %s, '%f', '%f', '%d');";
    return String.format(Locale.ENGLISH,
            insertQuery,
            DbContract.Microlocation.TABLE_NAME,
            id,
            DatabaseUtils.sqlEscapeString(StringUtils.optionalString(name)),
            latitude,
            longitude,
            floor);
}

and then I’d execute the string returned by the call

String query = model.generateSql();

by this

public void insertQuery(String query, DbHelper mDbHelper) {
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
    db.beginTransaction();
    db.execSQL(query);
  
    db.setTransactionSuccessful();
    db.endTransaction();
}

Where db is just a SQLiteDatabase instance.

Now that we have records we want to retrieve them according to usage and for that we create helper methods. This is an example of the retrieving all the microlocations added to the database in ASCENDING order of NAME

public ArrayList<org.fossasia.openevent.data.Microlocation> getMicrolocationsList(SQLiteDatabase mDb) {
    String sortOrder = DbContract.Microlocation.NAME + ASCENDING;
    Cursor cursor = mDb.query(
            DbContract.Microlocation.TABLE_NAME,
            DbContract.Microlocation.FULL_PROJECTION,
            null,
            null,
            null,
            null,
            sortOrder
    );

    ArrayList<org.fossasia.openevent.data.Microlocation> microlocations = new ArrayList<>();
    org.fossasia.openevent.data.Microlocation microlocation;

    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        microlocation = new org.fossasia.openevent.data.Microlocation(
                cursor.getInt(cursor.getColumnIndex(DbContract.Microlocation.ID)),
                cursor.getString(cursor.getColumnIndex(DbContract.Microlocation.NAME)),
                cursor.getFloat(cursor.getColumnIndex(DbContract.Microlocation.LATITUDE)),
                cursor.getFloat(cursor.getColumnIndex(DbContract.Microlocation.LONGITUDE)),
                cursor.getInt(cursor.getColumnIndex(DbContract.Microlocation.FLOOR))
        );
        microlocations.add(microlocation);
        cursor.moveToNext();
    }
    cursor.close();
    return microlocations;
}

First we create a cursor and then just iterate of the cursor to get microlocation objects and add them to an Arralist and return the Arraylist to the calling method.

So This are most of the things that are there to handling data in Android. Should be sufficient to get you started.

Sorry for the long post but the content couldn’t be made any smaller but I hope you gain something from this post. You can checkout implementations I have followed for the Open event project in the github repo https://github.com/fossasia/open-event-android. You can also write to me anytime on FB, Twitter, Email etc. and I’ll be happy to answer any queries. Adios!

References : 1) developers.android.com

2) https://github.com/fossasia/open-event-android

Multiple Tickets: Back-end

In my previous post I talked about approach for Multiple Ticket feature’s user-interface [Link]. In this post I’ll discuss about Flask back-end used for saving multiple tickets.

HTML Fields Naming

Since the number of Tickets a user creates is unknown to the server, details of tickets were needed to be sent as an array of values. So the server would accept the list of values and iterate over them. To send data as an array the naming had to include brackets. Below are some input fields used in tickets:

<tr>
    <td>
        <input type="hidden" name="tickets[type]">
        <input type="text" name="tickets[name]" class="form-control" placeholder="Ticket Name" required="required" data-uniqueticket="true">
        <div class="help-block with-errors"></div>
    </td>
    <td>
        <input type="number" min="0" name="tickets[price]" class="form-control"  placeholder="$" value="">
    </td>
    <td>
        <input type="number" min="0" name="tickets[quantity]" class="form-control" placeholder="100" value="{{ quantity }}">
    </td>
    <!-- Other fields -->
</tr>

At the server

When the POST request reaches the server, any of the above fields (say tickets[name]) would be available as a list. The Flask Request object includes a form dictionary that contains all the POST parameters sent with the request. This dictionary is an ImmutableMultiDict object, which has a getlist method to get array of elements.

For instance in our case, we can get tickets[name] using:

@expose('/create', methods=('POST', 'GET'))
def create_view(self):
    if request.method == 'POST':
        ticket_names = request.form.getlist('tickets[name]')

    # other stuff

The ticket_names variable would contain the list of all the Ticket names sent with the request. So for example if the user created three tickets at the client-side, the form would possibly look like:

<form method="post">
  <!-- Ticket One -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name One">
  <!-- Ticket Two -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name Two">
  <!-- Ticket Three -->
  <input type="text" name="tickets[name]" class="form-control" value="Ticket Name Three">

</form>

After a successful POST request to the server, ticket_names should contain ['Ticket Name One', 'Ticket Name Two', 'Ticket Name Three'].

Other fields, like tickets[type], tickets[price], etc. can all be extracted from the Request object.

Checkbox Fields

A problem arose when a checkbox field was needed for every ticket. In my case, a “Hide Ticket” option was needed to let the user decide if he wants the ticket to be shown at the public Events page.

Screenshot from 2016-08-13 12:39:29

The problem with checkboxes is that, for a checkbox of a particular name attribute, if it is not selected, POST parameters of the request made by the client will not contain the checkbox input field parameter. So if I define an input field as a checkbox with the following naming convention, and make a POST request to the server, the server will receive blah[] parameter only if the input element had been checked.

<input type="checkbox" name="blah[]" >

This creates a problem for “Hide ticket” checkboxes. For instance, at the client-side the user creates three tickets with the first and last tickets having their checkboxes selected, the server would get an array of two.

<form>
  <!-- Ticket One -->
  <input type="checkbox" name="tickets[hide]" checked>
  <!-- Ticket Two -->
  <input type="checkbox" name="tickets[hide]">
  <!-- Ticket Three -->
  <input type="checkbox" name="tickets[hide]" checked>

</form>
ticket_hide_opts = request.form.getlist('tickets[hide]')

ticket_hide_opts would be an array of length two. And there is no way to tell what ticket had its “Hide ticket” option checked. So for the hide checkbox field I had to define input elements with unique names to extract them at the server.

There is also a hack to overcome the unchecked-checkbox problem. It is by using a hidden field with the same name as the checkbox. You can read about it here: http://www.alexandrejoseph.com/blog/2015-03-03-flask-unchecked-checkbox-value.html.

Implementing Payment and Tax System for Open-Event

So I implemented the payment system and tax system for the payment part in the ticketing system. The first step was making a list of available countries and currency options for the system. So I created and added the following list:

PAYMENT_COUNTRIES = {
    'United States',
    'Argentina',
    'Australia',
    'Austria',
    'Belgium',
    'Brazil',
    'Canada',
    'Cyprus',
    'Czech Republic',
    'Denmark',
    'Estonia',
    'Finland',
    'France',
    'Germany',
    'Greece',
    'Hong Kong',
    'Hungary',
    'Ireland',
    'Israel',
    'Italy',
    'Japan',
    'Latvia',
    'Lithuania',
    'Luxemborg',
    'Malaysia',
    'Malta',
    'Mexico',
    'Netherlands',
    'New Zealand',
    'Norway',
    'Philippines',
    'Poland',
    'Portugal',
    'Singapore',
    'Slovakia',
    'Slovenia',
    'Spain',
    'Sweden',
    'Switzerland',
    'Taiwan',
    'United Kingdom',
}

PAYMENT_CURRENCIES = {
    'ARS Argentine Peso $',
    'AUD Australian Dollars A$',
    'BRL Brazilian Real R$',
    'CAD Canadian Dollars C$',
    'CZK Czech Koruna Kč',
    'DKR Danish Krone Dkr',
    'EUR Euros €',
    'HKD Hong Kong Dollar HK$',
    'HUF Hungarian Forint Ft',
    'ILS Israeli Shekels ₪',
    'JPY Japanese Yen ¥',
    'MYR Malaysian Ringgits RM',
    'MXN Mexican Pesos Mex$',
    'NZD New Zealand Dollar NZ$',
    'NOK Norwegian Krone Nkr',
    'PHP Philippine Pesos ₱',
    'PLN Polish Zloty zł',
    'GBP Pounds Sterling £',
    'SGD Singapore Dollar SG$',
    'SEK Swedish Krona Skr',
    'CHF Swiss Franc Fr',
    'TWD Taiwan New Dollars NT$',
    'THB Thai baht ฿',
    'USD U.S. Dollars $',
}

This is the list of currently supported countries and currencies. Thus the user can choose from the above list in the following step on the first page of event creation:

1

If the user chooses a Paid ticket or a Donation ticket then he/she has to compulsorily choose a country and a currency for the event. Next in line is the system of payments – the way in which the organizer wants payments to be made for his/her event. They include the option of Online Payments and Offline Payments. The organizer has to tick the checkbox in order to enable the payment option. On enabling the PayPal and Stripe checkboxes he/she is represented with the following:

2

On enabling PayPal option the organizer has to enter the PayPal email and for Stripe he has to connect it with Stripe account.

And the final step is the addition of tax for the event. The organizer can choose whether he/she wants to enable tax for the event or not:

3

On choosing Yes he is presented with the tax form:

4

If the organizer wants to send invoices then on enabling invoices another form is displayed with details pertaining to Business Address, Registered Name etc….

5

Finally we have two options that whether we want to display the tax as separate fee or include in the price of tickets.

Multiple Tickets: User Interface

An Event can have multiple tickets for different purposes. For instance an Arts Exhibition can have multiple Galleries. The Organizer might be interested in assigning a ticket (let’s assume paid) for each Gallery. The user can then buy tickets for the Galleries that he wishes to attend. The feature that Multiple Tickets really provide is exclusiveness. Let’s say Gallery1 has a shorter area (by land) than others. Obviously the Organizer would want fewer people to be present there than other Galleries. To do this, he can create a separate ticket for Gallery1 and specify a shorter sales period. He can also reduce the Maximum number of order that a user can make (max_order). If we would have implemented single ticket per event, this wouldn’t have been possible.

Tickets at Wizard

To handle multiple tickets at the wizard, proper naming of input tags was required. Since the number of tickets that can be created by the user was unknown to the server we had to send ticket field values as lists. Also at the client-side a way was required to let users create multiple tickets.

User Interface

A ticket can be of three types: Free, Paid and Donation. Out of these, only the Paid tickets need a Price. The Tickets holder could be a simple table, with every ticket being a table row. This became more complex afterwards, when more details about the ticket needed to be displayed. A ticket would then be two table rows with one of them (details) hidden.

Ticket holder can be a simple bootstrap table:

<table class="table tickets-table">
    <thead>
        <tr>
            <th>Ticket Name</th>
            <th>Price</th>
            <th>Quantity</th>
            <th>Options</th>
        </tr>
    </thead>
    <tbody>
      <!-- Ticket -->
      <tr>
        <!-- Main info -->
      </tr>
      <tr>
        <!-- More details (initially hidden) -->
      </tr>
      <!-- /Ticket -->
    </tbody>
</table>

To make ticket creation interactive, three buttons were needed to create the above three tickets. The type-name doesn’t not necessarily have to be shown to the user. It could be specified with the Price. For Paid ticket, the Price input element would be a number. For Free and Donation tickets, a Price input element wasn’t required. We could specify an element displaying one of the two types: Free or Donation.

Here’s the holder table with a Free Ticket and a Donation Ticket:

Screenshot from 2016-08-09 16:51:06

Since only the Price field is changing in the three types of tickets, I decided to create a template ticket outside of the form and create a JavaScript function to create one of the tickets by cloning the template.

A Free Ticket with its edit options opened up. You can see other details about the ticket in the second table row.

Screenshot from 2016-08-09 16:52:14

This is a simplified version of the template. I’ve removed common bootstrap elements (grid system) including some other fields.

<div id="ticket-template">
<tr>
    <td>
        <input type="hidden" name="tickets[type]">
        <input type="text" name="tickets[name]" class="form-control" placeholder="Ticket Name" required="required" data-uniqueticket="true">
        <div class="help-block with-errors"></div>
    </td>
    <td>
        <!-- Ticket Price -->
    </td>
    <td>
        <input type="number" min="0" name="tickets[quantity]" class="form-control" placeholder="100" value="{{ quantity }}">
    </td>
    <td>
        <div class="btn-group">
            <a class="btn btn-info edit-ticket-button" data-toggle="tooltip" title="Settings">
                <i class="glyphicon glyphicon-cog"></i>
            </a>
            <a class="btn btn-info remove-ticket-button" data-toggle="tooltip" title="Remove">
                <i class="glyphicon glyphicon-trash"></i>
            </a>
        </div>
    </td>
</tr>
<tr>
    <td colspan="4">
        <div class="row" style="display: none;">
            <!-- Other fields including Description, Sales Start and End time,
              Min and Max Orders, etc.
            -->
        </div>
    </td>
</tr>
</div>

Like I said, the Price element of ticket will make the type obvious for the user, so a type field does not need to be displayed. But the type field is required by the server. You can see it specified as hidden in the template.

The function to create a Ticket according to the type:

I’ve commented snippets to make it easy to understand.

function createTicket(type) {
    /* Clone ticket from template */
    var $tmpl = $("#ticket-template").children().clone();

    var $ticket = $($tmpl[0]).attr("id", "ticket_" + String(ticketsCount));
    var $ticketMore = $($tmpl[1]).attr("id", "ticket-more_" + String(ticketsCount));

    /* Bind datepicker and timepicker to dates and times */
    $ticketMore.find("input.date").datepicker();
    $ticketMore.find("input.time").timepicker({
        'showDuration': true,
        'timeFormat': 'H:i',
        'scrollDefault': 'now'
    });

    /* Bind iCheck to checkboxes */
    $ticketMore.find("input.checkbox.flat").iCheck({
        checkboxClass: 'icheckbox_flat-green',
        radioClass: 'iradio_flat-green'
    });

    /* Bind events to Edit (settings) and Remove buttons */
    var $ticketEdit = $ticket.find(".edit-ticket-button");
    $ticketEdit.tooltip();
    $ticketEdit.on("click", function () {
        $ticketMore.toggle("slow");
        $ticketMore.children().children(".row").slideToggle("slow");
    });

    var $ticketRemove = $ticket.find(".remove-ticket-button");
    $ticketRemove.tooltip();
    $ticketRemove.on("click", function () {
        var confirmRemove = confirm("Are you sure you want to remove the Ticket?");
        if (confirmRemove) {
            $ticket.remove();
            $ticketMore.remove();
        }
    });

    /* Set Ticket Type field */
    $ticket.children("td:nth-child(1)").children().first().val(type);

    /* Set Ticket Price field */
    var html = null;
    if (type === "free") {
        html = '';
    } else if (type === "paid") {
        html = '';
    } else if (type === "donation") {
        html = '';
    }
    $ticket.children("td:nth-child(2)").html(html);

    /* Append ticket to table */
    $ticket.hide();
    $ticketMore.children().children(".row").hide();
    $ticketsTable.append($ticket, $ticketMore);
    $ticket.show("slow");

    ticketsCount += 1;
  }

The flow is simple. Clone the template, bind events to various elements, specify type and price fields and then append to the ticket holder table.

Screenshot from 2016-08-09 17:00:59

We use the Datepicker and Timepicker JavaScript libraries for date and time elements. So fields using these widgets need to have methods called on the elements. Also, we use iCheck for checkboxes and radio buttons. Apart from these, the Edit-Ticket and Remove-Ticket buttons also need event handlers. Edit-Ticket button toggles the Ticket Details segment (second tr of a ticket). Remove-Ticket deletes the ticket. After the Price and Type fields are set, the ticket is appended to the holder table with slow animation.