Uploading Badges To Google Cloud Badgeyay

Badgeyay is an open source project developed by FOSSASIA community. This project mainly aims for generating badges for technical conferences and events.The project is divided into two parts mainly. Backend is developed in flask and frontend is developed in emberjs. The problem is after the badge generation, the flask server is storing and serving those files. In practise this is not a good convention to do so. This should be handled by secondary hosting server program like gunicorn or nginx. Better approach would be to consume the firebase storage and admin sdk for storing the badges on google cloud. This will also offload storage needs from the flask server and also give a public link over the network to access.

Procedure

  1. Get the file path of the temporary badge generated on the flask server. Currently badges are saved in the directory of the image file uploaded and final badge generated is written in all-badges.pdf`
badgePath = os.getcwd() + ‘/static/temporary/’ + badgeFolder
badgePath + ‘/all-badges.pdf’

 

  1. Create the blob path for the storage. Blob can be understood as the final reference to the location where the contents are saved onto the server. This can be a nested directory structure or simply a filename in root directory.
‘badges/’ + badge_created.id + ‘.pdf’

 

In our case it is the id of the badge that is generated in the badges directory.

  1. Function for uploading the file generated in temporary storage to google cloud storage.
def fileUploader(file_path, blob_path):
  bucket = storage.bucket()
  fileUploaderBlob = bucket.blob(blob_path)
  try:
      with open(file_path, ‘rb’) as file_:
          fileUploaderBlob.upload_from_file(file_)
  except Exception as e:
      print(e)
  fileUploaderBlob.make_public()
  return fileUploaderBlob.public_url

 

It creates a bucket using the firebase admin SDK and then open the file from the file path. After opening the file from the path it writes the data to the cloud storage. After the data is written, the blob is made public and the public access link to the blob is fetched, which then later returned and saved in the local database.

Topics Involved

  • Firebase admin sdk for storage
  • Google cloud storage sdk

Resources

  • Firebase admin sdk documentation – Link
  • Google Cloud Storage SDK Python – Link
  • Blob Management – Link

 

Continue ReadingUploading Badges To Google Cloud Badgeyay

Exporting CSV data through API

A Badge generator like Badgeyay must be able to generate, store and export the user data as and when needed. This blog post is about adding the exporting functionality to badgeyay backend..

Why do we need such an API?

Exporting data is required for a user. A user may want to know the details he/she has uploaded to the system or server. In our case we are dealing with the fact of exporting the CSV data from backend of Badgeyay.

Adding the functionality to backend

Let us see how we implemented this functionality into the backend of the project.

Step 1 : Adding the necessary imports

We first need to import the required dependencies for the route to work

import os
import base64
import uuid
from flask import request, Blueprint, jsonify
from flask import current_app as app
from api.models.file import File
from api.schemas.file import ExportFileSchema
from api.utils.errors import ErrorResponse
from api.schemas.errors import FileNotFound

Step 2 : Adding a route

This step involves adding a separate route that provides us with the exported data from backend.

@router.route(‘/csv/data’, methods=[‘GET’])
def export_data():
input_data = request.args
file = File().query.filter_by(filename=input_data.get(
‘filename’)).first()

if file is None:
return ErrorResponse(FileNotFound(input_data.get(‘filename’)).message, 422, {‘Content-Type’: ‘application/json’}).respond()

export_obj = {
‘filename’: file.filename,
‘filetype’: file.filetype,
‘id’: str(uuid.uuid4()),
‘file_data’: None}

with open(os.path.join(app.config.get(‘BASE_DIR’), ‘static’, ‘uploads’, ‘csv’, export_obj[‘filename’]), “r”) as f:
export_obj[
‘file_data’] = f.read()

export_obj[‘file_data’] = base64.b64encode(export_obj[‘file_data’].encode())

return jsonify(ExportFileSchema().dump(export_obj).data)

Step 2 : Adding a relevant Schema

After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user.

class ExportFileSchema(Schema):
class Meta:
type_ =
‘export-data’
kwargs = {
‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
filename = fields.Str(required=
True, dump_only=True)
filetype = fields.Str(required=
True, dump_only=True)
file_data = fields.Str(required=
True, dump_only=True)

This is the ExportFileSchema that produces the output results of the GET request on the route. This helps us get the data onto the frontend.

Further Improvements

We are working on making badgeyay more comprehensive yet simple. This API endpoint needs to get registered onto the frontend. This can be a further improvement to the project and can be iterated over the next days.

Resources

Continue ReadingExporting CSV data through API

Dated queries in Badgeyay admin

Badgeyay is not just an anonymous badge generator that creates badges according to your needs, but it now has an admin section that allows the admin of the website to control and look over the statistics of the website.

Why do we need such an API?

For an admin, one of the most common functionality is to gather the details of the users or the files being served onto or over the server. Not just that, but the admin must also be aware about the traffic or files on the server in a particular duration of time. So we need an API that can coordinate all the stuff that requires dated queries from the backend database.

Adding the functionality to backend

Let us see how we implemented this functionality into the backend of the project.

Step 1 : Adding a route

This step involves adding a separate route that provides us with the output of the dated badges queries from backend.

@router.route(‘/get_badges_dated’, methods=[‘POST’])
def get_badges_dated():
schema = DatedBadgeSchema()
input_data = request.get_json()
data, err = schema.load(input_data)
if err:
return jsonify(err)
dated_badges = Badges.query.filter(Badges.created_at <= data.get(
‘end_date’)).filter(Badges.created_at >= data.get(‘start_date’))
return jsonify(AllBadges(many=True).dump(dated_badges).data)

This route allows us to get badges produced by any user during a certain duration as a JSON API data object. This object is fed to the frontend to render the badges as cards.

Step 2 : Adding a relevant Schema

After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user.

class DatedBadgeSchema(Schema):
class Meta:
type_ =
‘dated-badges’
kwargs = {
‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
start_date = fields.Date(required=
True)
end_date = fields.Date(required=
True)

class AllBadges(Schema):
class Meta:
type_ =
‘all-badges’
self_view =
‘admin.get_all_badges’
kwargs = {
‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
image = fields.Str(required=
True)
csv = fields.Str(required=
True)
badge_id = fields.Str(required=
True)
text_color = fields.Str(required=
True)
badge_size = fields.Str(required=
True)
created_at = fields.Date(required=
True)
user_id = fields.Relationship(
self_url=
‘/api/upload/get_file’,
self_url_kwargs={
‘file_id’: ‘<id>’},
related_url=
‘/user/register’,
related_url_kwargs={
‘id’: ‘<id>’},
include_resource_linkage=
True,
type_=
‘User’
)

This is the DatedBadge schema that produces the output results of the POST request on the route. And there is the AllBadges schema that produces the output results of the POST request on the route.

Further Improvements

We are working on adding multiple routes and adding modifications to database models and schemas so that the functionality of Badgeyay can be extended to a large extent. This will help us in making this badge generator even better.

Resources

 

Continue ReadingDated queries in Badgeyay admin

Get My Badges from Badgeyay API

Badgeyay is no longer a simple badge generator. It has more cool features than before.

Badgeyay now supports a feature that shows your badges. It is called ‘my-badges’ component. To get this component work, we need to design a backend API to deliver the badges produced by a particular user.

Why do we need such an API?

The main aim of Badgeyay has changed from being a standard and simple badge generator to a complete suite that solves your badge generation and management problem. So to tackle the problem of managing the produced badges per user, we need to define a separate route and schema that delivers the generated badges.

Adding the functionality to backend

Let us see how we implemented this functionality into the backend of the project.

Step 1 : Adding a route

This step involves adding a separate route that provides with the generated output of the badges linked with the user account.

@router.route(‘/get_badges’, methods=[‘GET’])
def get_badges():
input_data = request.args
user = User.getUser(user_id=input_data.get(
‘uid’))
badges = Badges().query.filter_by(creator=user)
return jsonify(UserBadges(many=True).dump(badges).data)

This route allows us to get badges produced by the user as a JSON API data object. This object is fed to the frontend to render the badges as cards.

Step 2 : Adding a relevant Schema

After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user.

class UserBadges(Schema):
class Meta:
type_ =
‘user-badges’
self_view =
‘generateBadges.get_badges’
kwargs = {
‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
image = fields.Str(required=
True)
csv = fields.Str(required=
True)
badge_id = fields.Str(required=
True)
text_color = fields.Str(required=
True)
badge_size = fields.Str(required=
True)
user_id = fields.Relationship(
self_url=
‘/api/upload/get_file’,
self_url_kwargs={
‘file_id’: ‘<id>’},
related_url=
‘/user/register’,
related_url_kwargs={
‘id’: ‘<id>’},
include_resource_linkage=
True,
type_=
‘User’
)

This is the ‘UserBadge’ schema that produces the output results of the GET request on the route.

Finally, once this is done we can fire up a GET request on our deployment to receive results. The command that you need to run is given below.

$ ~ curl -X GET http://localhost:5000/api/get_badges?uid={user_id}

Further Improvements

We are working on adding multiple routes and adding modifications to database models and schemas so that the functionality of Badgeyay can be extended to a large extent. This will help us in making this badge generator even better.

Resources

 

Continue ReadingGet My Badges from Badgeyay API

Custom Colored Images with Badgeyay

Backend functionality of any Badge generator is to generate badges as per the requirements of the user. Currently Badgeyay is capable of generating badges by the following way:

  • Adding or Selecting a Pre-defined Image from the given set
  • Uploading a new image and then using it as a background

Well, badgeyay has been missing a functionality of generating Custom Colored images.

What is meant by Custom Colored Badges?

Currently, there are a set of 7 different kind of pre-defined images to choose from. But let’s say that a user want to choose from the images but doesn’t like any of the color. Therefore we provide the user with an additional option of applying custom background-color for their badges. This allows Badgeyay to deliver a more versatile amount of badges than ever before.

Adding the functionality to backend

Lets see how this functionality has been implemented in the backend of the project.

Step 1 :  Adding a background-color route to backend

Before generating badges, we need to know that what is the color that the user wants on the badge. Therefore we created a route that gathers the color and saves the user-defined.svg into that particular color.

@router.route(‘/background_color’, methods=[‘POST’])
def background_color():
try:
data = request.get_json()[‘data’][‘attributes’]
bg_color = data[‘bg_color’]
except Exception:
return ErrorResponse(PayloadNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

svg2png = SVG2PNG()

bg_color = ‘#’ + str(bg_color)
user_defined_path = svg2png.do_svg2png(1, bg_color)
with open(user_defined_path, “rb”) as image_file:
image_data = base64.b64encode(image_file.read())
os.remove(user_defined_path)

try:
imageName = saveToImage(imageFile=image_data.decode(‘utf-8’), extension=”.png”)
except Exception:
return ErrorResponse(ImageNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

uid = data[‘uid’]
fetch_user = User.getUser(user_id=uid)
if fetch_user is None:
return ErrorResponse(UserNotFound(uid).message, 422, {‘Content-Type’: ‘application/json’}).respond()

file_upload = File(filename=imageName, filetype=’image’, uploader=fetch_user)
file_upload.save_to_db()
return jsonify(ColorImageSchema().dump(file_upload).data)

Step 2: Adding Schema for background-color to backend

To get and save values from and to database, we need to have some layer of abstraction and so we use schemas created using marshmallow_jsonapi

class ColorImageSchema(Schema):
class Meta:
type_ = ‘bg-color’
self_view = ‘fileUploader.background_color’
kwargs = {‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
filename = fields.Str(required=True)
filetype = fields.Str(required=True)
user_id = fields.Relationship(
self_url=’/api/upload/background_color’,
self_url_kwargs={‘file_id’: ‘<id>’},
related_url=’/user/register’,
related_url_kwargs={‘id’: ‘<id>’},
include_resource_linkage=True,
type_=’User’
)

Now we have our schema and route done, So we can move forward with the logic of making badges.

Step 3 : Converting the SVG to PNG and adding custom color

Now we have the user-defined color for the badge background, but we still need a way to apply it to the badges. It is done using the following code below.

def do_svg2png(self, opacity, fill):
“””
Module to convert svg to png
:param `opacity` – Opacity for the output
:param `fill` –  Background fill for the output
“””
filename = os.path.join(self.APP_ROOT, ‘svg’, ‘user_defined.svg’)
tree = parse(open(filename, ‘r’))
element = tree.getroot()
# changing style using XPath.
path = element.xpath(‘//*[@id=”rect4504″]’)[0]
style_detail = path.get(“style”)
style_detail = style_detail.split(“;”)
style_detail[0] = “opacity:” + str(opacity)
style_detail[1] = “fill:” + str(fill)
style_detail = ‘;’.join(style_detail)
path.set(“style”, style_detail)
# changing text using XPath.
path = element.xpath(‘//*[@id=”tspan932″]’)[0]
# Saving in the original XML tree
etree.ElementTree(element).write(filename, pretty_print=True)
print(“done”)
png_name = os.path.join(self.APP_ROOT, ‘static’, ‘uploads’, ‘image’, str(uuid.uuid4())) + “.png”
svg2png(url=filename, write_to=png_name)
return png_name

Finally , we have our badges generating with custom colored background.

Here is a sample image:

Resources

 

Continue ReadingCustom Colored Images with Badgeyay

Implementing Leak Canary in PSLab Android App

This post discusses the issue of memory leaks and how to handle them efficiently and what are the tools available which help developers in managing the memory leaks. After working on PR #824 opened under PSLab – Android repository I have got a greater idea about how to manage the memory efficiently and what are the tools that should be used to ease the work.

What are memory leaks and how it affects the quality of app?

In simple words, memory leaks happen when you hold on to an item for long after its purpose have been served. It is as simple as that. But let us dive in further to understand more about this topic. Programming languages like C and C++ need memory management done by user whereas in higher level languages like Java, Python, etc. low-level memory management and garbage collection is done automatically by the system. But it is due to programming faults that memory leaks happen and so care needs to be taken with higher level languages too in handling memory efficiently.

In Android or say in any OS (operating system), every item has to be destroyed or say deleted or freed from the memory after its purpose is served. But if the reference of this object is passed on to any other object which has a greater time of importance than this, then it will try to hold this object for long and so the garbage collector won’t be able to collect it and so there will be memory leaks in the code. This is how memory leaks occurs inside an app.

Now, the issue of memory leaks is utmost important among developers as due to it, the app becomes slow, laggy, eats up a lot of memory and the app crashes after some time of use which creates a very bad user experience. As the user keeps on using the app, the heap memory also keeps on increasing and due to memory leaks, this heap can’t be freed by the garbage collector. Thus, all these issues contribute to making the threads or processes running inside the app slower and it can result in a lag of time from microseconds to milliseconds too!!

How can you detect these memory leaks?

This blog is mostly for Android developers and so I will use the environment of Android Studio for reference. For controlling memory leaks, Android Studio has a very powerful tool named Monitors. There are individual monitors not only for memory usage but for CPU, GPU, and network usage as well. An example of it is shown in figure 1 below.

Figure 1. Monitor in Android Studio

Now how to observe the graphs that are produced by Monitors to see if there are any memory leaks? The first alarming case is when the memory usage graph constantly increases and doesn’t come down as time passes and even not decreases when you put the app in the background. The tools which are used to undo memory leaks as soon as they are found are:

  1. Allocation Tracker: The allocation tracker comes with an indicator to show the percentage of memory allocated to different types of objects in your app. The developer can have a clear idea about which object is taking what amount of memory and which objects are exceeding the memory limit. But it is itself not enough as the developer needs other tools to dump the extra memory.
  2. Leak Canary Library: It is the most used library by developers to check for memory leaks in an app. This library runs along with app and dumps memory when needed, looks for potential memory leaks  and gives a notification for a memory leak with a clean trace to find the root of the leak with sub-roots attached to it as shown in figure 2 :

Figure 2. Screenshot from Leaks application made by Leak Canary for PSLab app

It is clearly visible from the image that the applications show the root of the memory leak with an indication of how much memory is leaked in the toolbar.

Explanation of leak shown in figure 2 :

In the PSLab app, there is a navigation drawer consisting of all main functionalities in it. It is as shown in figure 3 :

Figure 3. Navigation drawer in PSLab

The memory leak as shown in figure 2 originated in the following steps :

  • It started with ArrayList which is here the list of items as shown in figure 3.
  • After it comes to the ScrollContainer which helps in scrolling this list on small screens.
  • Then comes the Drawer Layout which is the actual layout seen in figure 3 that slides over the main layout which is here the Instruments layout.
  • At last, comes the InputMethodManager which is introduced by Leak Canary library which watches the activity that is being opened.
  • Here, InputMethodManager kept watching on Drawer Layout but after closing the layout too it referenced it which is due to the source code of LeakCanary Library and so memory Leak occurred.

How to stop this leak from occurring ?

A simple way is to add a transparent activity as soon as the layout is closed for a very small time i.e. 500 ms so that the reference watcher gets shifted from the actual layout. This solution is based on the article published on Medium [5].

How to implement Leak Canary in your app?

Below is the step-by-step guide on implementing Leak Canary library in your app to implement a watcher for memory leaks :

    • Add dependencies (App Level) in your project to implement Leak Canary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
      1. debugImplementation – For debug flavor of app
      2. releaseImplementation – For release flavor of app
      3. testImplementation – For testing the current flavor of the app

Add dependencies according to the need for the application.

Add Realm dependencies (Project Level) in your app to create a database which can be used by Leak Canary to maintain and provide crash reports as shown in the figure above.

NOTE: Any database can be used here according to the need of the app

buildscript {
            repositories {
                     jcenter()
                         }
            dependencies {
                classpath "io.realm:realm-gradle-plugin:0.88.2"
           }
       }
 apply plugin: 'realm-android'

App-level dependency :

compile 'io.realm:android-adapters:2.0.0'
  • Add an activity class in your application to construct the Leak Canary for your entire application. In PSLab Android application, it was made as under :
package org.fossasia.pslab;

import android.app.Application;

import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

import io.realm.Realm;

public class PSLabApplication extends Application {

	public RefWatcher refWatcher;

	@Override
	public void onCreate() {
    	super.onCreate();
    	Realm.init(this);

    	initializeLeakCanary();
	}

	private void initializeLeakCanary() {
    	if (LeakCanary.isInAnalyzerProcess(this)) {
        	return;
    	}
    	refWatcher = LeakCanary.install(this);
	}
}

Explanation of the above-implemented code :

  1. First import all the necessary libraries
  2. Realm.init(this) is used to initiate the database as soon as the layout of the Leak Canary is ready to work so that before any crashes, the database is ready to accept the entry
  3. initializeLeakCanary() method first checks if the analyzer is in the process i.e. if the Leak Canary is already initiated so that there’s no need to again initiate it else a reference watcher is initiated with variable refWatcher which looks out for any potential memory leaks

After this, you can provide a watcher with an object to watch by writing :

refWatcher.watch(object);

Now your app is ready to handle any case of memory leaks and thus the developer can find the root of the issue if any and can solve it with ease. The app will now work 94% more efficiently than what it used to be with memory leaks. Thus, a greater user experience can be provided now but in the backend!!

Resources

  1. How to use Leak Canary – Article on Stack Overflow
  2. Everything you need to know about memory leaks – Article on medium.com
  3. Leak Canary: Detect all memory leaks -Another great article on medium.com
  4. https://github.com/square/leakcanary – Actual GitHub repo of Leak Canary library
  5. https://medium.com/@amitshekhar/android-memory-leaks-inputmethodmanager-solved-a6f2fe1d1348 – Medium article on how to solve InputMethodManager related leaks

 

Continue ReadingImplementing Leak Canary in PSLab Android App

Ember Data Integration In Badgeyay Frontend

Badgeyay is an open source utility to develop badges for events and tech conferences. Badgeyay project is divided into two components. Frontend part is designed with ember and backend part is designed with Flask and database as PostgreSQL and Firebase as PaaS.

After refactoring the backend API for generation of badges, now it is time to consume the API in frontend by ember, and the way to consume the api in ember front–end is with the use of in built ember-data library. Ember data behaves in a way similar to server side ORM’s (Object Relational Mappers). It is a very versatile library and can be equipped with variety of backend services. It can be used with REST as well as sockets and other transfer protocols for communication.

For better understanding the working of ember data, let’s see how to use the same to consume the File Upload endpoint in the backend.

Procedure

  1. Enabling CORS on server, to allow cross-domain requests to the API.
from flask_cors import CORS
CORS(app, resources={r"*": {"origins": "*"}})
  1. Creating Adapter for the model in frontend. In our case it is csv-file. In the adapter we need to specify the host and the path, because our backend api is not running on the same port.
import DS from 'ember-data';

const { RESTAdapter } = DS;

export default RESTAdapter.extend({
host : 'http://localhost:5000',
pathForType : () => {
return 'api/upload/file';
}
});
  1. After creating the adapter we need to create the record in the controller of the respective component. The record is like an object of a class, which when pushed to store will make a network request to backend (POST) and fetch the response from the backend. Backend response will provide the id to save in store
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';

export default Controller.extend({
routing : service('-routing'),
actions : {
mutateCSV(csvData) {
let csv_ = this.get('store').createRecord('csv-file', {
csvFile : csvData,
extension : 'csv'
});
csv_.save();
},

mutateText(txtData) {
console.log(txtData);
}
}
});

Model for the csv-file

import DS from 'ember-data';

const { Model, attr } = DS;

export default Model.extend({
csvFile : attr('string'),
extension : attr('string')
});
  1. Next is to create serializers for the model. Serializers gets triggered at two moments, first when the data is sent to the server and second when data is received from the server. Each time an independent function gets executed. As the naming conventions of the functions pretty much explains their role, but for the sake of clarification serialize function gets executed when we send request to the server and normalizeResponse gets executed when we are getting response from the server.
import DS from 'ember-data';

const { JSONAPISerializer } = DS;

export default JSONAPISerializer.extend({

serialize(snapshot, options) {
let json = this._super(...arguments);
json.csvFile = {
'csvFile' : json.data.attributes['csv-file'],
'extension' : json.data.attributes.extension
};

delete json.data;
return json;
},

normalizeResponse(store, primaryModelClass, payload, id, requestType) {
return payload;
}
});
  1. After receiving the response a promise is returned by the push method to save the record in the store and we can see the id is saved in the ember-data object.

Pull Request for the same is at this Link

Topics Involved

Working on the issue involve following topics:

  • Enabling CORS to accept cross-domain requests at server
  • Creating models in ember data
  • Passing action from controller to component
  • Modifying the Params and Response on the network sent by ember-data via serializers

 

Resources

  • Ember data repository – Link
  • Documentation for creating record in ember data – Link
  • API Doc for JSONAPIAdapter – Link
  • API Doc for JSONAPISerializer – Link
  • Property methods for serializer – serialize, normalizeResponse
Continue ReadingEmber Data Integration In Badgeyay Frontend

Implementing Sign up Feature through Email in Badgeyay

Badgeyay project is divided into two parts i.e front-end of Ember JS and back-end with REST-API programmed in Python.

We already have logging In features implemented with the help of Firebase Authentication. A User can login in the Badgeyay with the help of Google, Facebook and Twitter credentials through a single click. Now, the challenging part is to implement the sign up with Email feature in Frontend and Backend to enable the user to signup and Login with the help of Email and Password

In this blog, I will be discussing how I set up Sign up feature in Badgeyay frontend to send the data in backend besides having Oauth logging features in Badgeyay integrated with Firebase in my Pull Request.

The sign up form is already implemented and I have already mentioned in my previous blog. So we need to send the form data to backend to register user so that user can login using the registered credentials. We need an Adapter, Signup action, controller , Signup Data model  and a serializer for doing this task.

Let’s get started and understand the terminologies before implementing the feature.

What is Ember Data ?

It is a data management library for Ember Framework which help to deal with persistent application data.
We will generate Ember data model using Ember CLI in which we will define the data structure we will be requiring to provide to our application for User Signup.

Step 1 : Generate ember data model for signup.

$ ember g model user-signup

 

Step 2: Define the user-signup data model.

import DS from 'ember-data';

const { Model, attr } = DS;

export default Model.extend({
  username : attr('string'),
  email    : attr('string'),
  password : attr('string')
});

 

What are Actions ?

We already have the signup form implemented in frontend. Now we need to provide a action to the form when the user enters the data in form.

If we add the {{action}} helper to any HTML DOM element, when a user clicks the element, the named event will be sent to the template’s corresponding component or controller.

<button class="ui orange submit button" {{ action 'signUp' }}>Sign Up</button>

 

We need to add signUp action in sign-up component and controller.

// Signup Controller 
import Controller from '@ember/controller';

import { inject as service } from '@ember/service';

export default Controller.extend({
  routing : service('-routing'),
  actions : {
    signUp(email, username, password) {
      const _this = this;
      let user_ = this.get('store').createRecord('user-signup', {
        email,
        username,
        password
      });
      user_.save()
        .then(record => {
          _this.transitionToRoute('/');
        })
        .catch(err => {
          console.log(err);
        });
    }
  }
});

// Sign up Component
import Component from '@ember/component';

export default Component.extend({
  init() {
    this._super(...arguments);
  },

  email     : '',
  password  : '',
  isLoading : false,

  actions: {
    signUp(event) {
      event.preventDefault();
      let email = '';
      let password = '';
      let username = '';
      email = this.get('email');
      password = this.get('password');
      username = this.get('username');
      this.get('signUp')(email, username, password);
    }
  },
});

 

What is an Adapter ?

An adapter determines how the data is persisted to a backend data store. We can configure the backend host, URL format and headers for REST API.

Now as we have specific Data Model for User Signup that we will be using for communicating with its backend so we have to create User-Signup Adapter with the help of Ember-CLI.

Step 1: Generate User Signup Adapter by following together.

$ ember generate adapter user-signup

 

Step 2: Extend the Adapter according to User-Signup Model.

import DS from 'ember-data';
import ENV from '../config/environment';

const { APP } = ENV;
const { JSONAPIAdapter } = DS;

export default JSONAPIAdapter.extend({
  host        : APP.backLink,
  pathForType : () => {
    return 'user/register';
  }
});

 

What are Serializers ?

Serializers format the Data sent to and received from the backend store. By default, Ember Data serializes data using the JSON API format.

Now as we have specific Data Model for User Signup that we will be using for communicating with its backend so we have to create User-Signup Serializer with the help Ember-CLI.

Step 1: Generate the User Signup Adapter by following command:

$ ember generate serializer user-signup

 

Step 2: Extend the serializer according to User-Signup Model.

import DS from 'ember-data';

const { JSONAPISerializer } = DS;

export default JSONAPISerializer.extend({

  serialize(snapshot, options) {
    let json = this._super(...arguments);
    return json;
  },

  normalizeResponse(store, primaryModelClass, payload, id, requestType) {
    return payload;
  }
});

 

We have successfully set up the User Signup in the frontend and data is communicated to backend in JSON API v1 specification with the help of serializers and Adapters.

This is how I set up Sign up feature in Badgeyay frontend to send the data in backend besides having Oauth logging features in Badgeyay integrated with Firebase in my Pull Request.

Resources:

  1. Ember Docs – Link
  2. Firebase Docs – Link
  3. Badgeyay Repository – Link
Continue ReadingImplementing Sign up Feature through Email in Badgeyay

Database Listener for User Centric Events

Badgeyay is an open-source utility developed by FOSSASIA to generate badges for conferences and events. The project is separated into two components to ease maintainability. First is the frontend part which is in ember and second part is backend which is in Flask. The choice of database to support backend is PostgreSQL.

Now comes the problem, whenever a user is registered in the database, he should receive  a verification mail, that he is successfully registered on the platform. For this case we have to listen to the database events on User model. This issue has greater extendibility than only sending greeting or verification mail to the user. We can extend this to trigger services that are dependent on user registration, like subscribing the user to some set of services based on the plan he opted while registration and many more.

These type of issues cannot be handled by normal relationship with tables and other entities, there has to be logic in place to support such functionalities. So the challenges for tackling the problem are as follows:

  • Listen to the insert_action in User model
  • Extracting the details necessary for the logic
  • Execute particular logic

Procedure

  1. Attaching insert_action listener to the User model. This function will get triggered whenever an entity is saved in the User model.

<!– HTML generated using hilite.me –>

@db.event.listens_for(User, "after_insert")
def logic(mapper, connection, target): {
......
}
  1. When the function gets triggered, extract the details of the saved user that is necessary for the logic. As currently we are sending greeting mail to the user,we only need the email of the user. Target is the actual saved user passed as argument to the listening function from the library.

<!– HTML generated using hilite.me –>

msg = {}
msg['subject'] = "Welcome to Badgeyay"
msg['receipent'] = target.email
msg['body'] = "It's good to have you onboard with Badgeyay. Welcome to " \
"FOSSASIA Family."
sendMail(msg)
  1. Now the details are passed to sendMail() function for sending mail which uses flask-mail library to send mail to the recipient.
    def sendMail(message):
    if message and message.receipent:
    try:
    msg = Message(
    subject=message.subject,
    sender=app.config['MAIL_USERNAME'], Response(200).generateMessage(
    recipients=[message.receipent],
    body=message.body)
    Mail(app).send(msg)
    except Exception as e:
    return jsonify(
    Response(500).exceptWithMessage(
    str(e),
    'Unable to send the mail'))
    return jsonify(
    Response(200).generateMessage(
    'Mail Sent'))
    else:
    return jsonify(
    Response(403).generateMessage(
    'No data received')) 'No data received'))
    
  2. This will send mail to the user who has been registered to the application.

Similarly we can use separate logics according to the need of the application.

 

The Pull Request for the above functionality is at this Link

Topics Involved

Working on the issue involve following topics:

  • Configuring mail service to allow insecure apps access.
  • Sending mail from the flask-mail to end user
  • Attaching listener to listen for database change
  • Extraction of data from saved object in database sqlalchemy.

Resources

  • Sending Mails Programmatically –  Link
  • Flask Mail Documentation – Link
  • Listening to database events – Link
  • Enabling access to GMAIL to send mails to recipient – Link
Continue ReadingDatabase Listener for User Centric Events

Badgeyay: Integrating EmberJS Frontend with Flask Backend

Badgeyay is a simple badge generator with a simple web UI that generates a printable badge in PDFs. The project had gone through different cycles starting from a Flask server to a CLI application then a python library and now API Interface for generation of badges.

According to latest changes in the project structure, now the frontend and backend are independent components developed in Ember JS and Flask respectively. Now there is a need to connect the frontend to the backend, which means the user should see the response on the same page without refresh, if the badge generated successfully. AJAX would fit right into the spot. Asynchronous Javascript and XML also known as AJAX, will enable us to perform asynchronous operation on the page without refreshing the page.

We can make an API call to the Server running in backend or deployed on heroku, but the server is not suitable for doing CORS(Cross-Origin Resource Sharing), ability to share the resources on server with the client having different domain names, but as the server and the frontend are not hosted on the same host  so there is a need to enable the server to accept CORS request calls.

Now the challenges were:

  • Enabling Flask Server to accept CORS requests.
  • AJAX query for sending request to the Flask server.

Procedure

  1. Giving the form an id and creating an AJAX request to the Flask server (may be localhost or deployed on heroku).
<form id=”form1″ action=”” method=”post” enctype=”multipart/form-data” onsubmit=”return validate()”>

 

When the generate button is clicked, an AJAX request is made to the server to generate badges and at the same time prevent the page from refreshing. In the AJAX request we set the CORS header to allow the domain.

 

<script type=”text/javascript”>
$(document).ready(function () {
$(‘#form1’).submit(function (event) {
event.preventDefault();
$.ajaxSetup({
headers: {“Access-Control-Allow-Origin”: “*”}
});
$.ajax({
url: “http://badgeyay-api.herokuapp.com/api/v1.0/generate_badges”,
data: $(this).serialize(),
type: ‘POST’,
success: function (data) {…},
error: function (error) {…}
})
});
})
</script>

 

  1. Import the library and enable the API endpoint to accept CORS requests.
from flask_cors import CORS
cors = CORS(app, resources={r”/api/*”: {“origins”: “*”}})

 

  1. Add Logic for appending the download link by extracting the download link from the response and replacing the static text in the template with the download link, also changing the download variable to the filename, by stripping the base url from the download link.
if (data[“response”][0][“type”] === “success”) {
$(‘#success’).css(‘visibility’, ‘visible’);
let link = data[“response”][0][“download_link”];
link = link.replace(“backend/app/”, “http://badgeyay-api.herokuapp.com/”);
$(‘#badge-link’).attr(“href”, link);
link = link.replace(“static/badges/”, “”);
$(‘#badge-link’).attr(“download”, link);
}

 

  1. Output the success on the page.
<div id=”success” style=”visibility: hidden;”>
<div class=”flash-success”>Your badges have been created successfully.</div>
<div class=”text-center”>
<a id=”badge-link” href=”http://badgeyay-api.herokuapp.com/static/badges/{{msg}}-badges.pdf”
class=”btn btn-success”
download=”{{msg}}-badges.pdf”>Download as
PDF</a>
</div>
</div>

 

  1. Frontend and Backend now are connected to each other.The Server now accepts CORS requests and response is generated after the user requests from Frontend.

 

The Pull Request with the above changes is on this Link

Topics Involved

Working on this issue (Link)  involves following topics :

  • Enabling Flask Server for CORS
  • Request Headers
  • AJAX request for CORS.

References

Continue ReadingBadgeyay: Integrating EmberJS Frontend with Flask Backend