Implementing Database Migrations to 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 have integrated PostgreSQL as the object-relational database in Badgeyay and we are using SQLAlchemy SQL Toolkit and Object Relational Mapper tools for working with databases and Python. As we have Flask microframework for Python, so we are having Flask-SQLAlchemy as an extension for Flask that adds support for SQLAlchemy to work with the ORM.

One of the challenging jobs is to manage changes we make to the models and propagate these changes in the database. For this purpose, I have added Added Migrations to Flask SQLAlchemy for handling database changes using the Flask-Migrate extension.

In this blog, I will be discussing how I added Migrations to Flask SQLAlchemy for handling Database changes using the Flask-Migrate extension in my Pull Request.

First, Let’s understand Database Models, Migrations, and Flask Migrate extension. Then we will move onto adding migrations using Flask-Migrate. Let’s get started and understand it step by step.

What are Database Models?

A Database model defines the logical design and structure of a database which includes the relationships and constraints that determine how data can be stored and accessed. Presently, we are having a User and file Models in the project.

What are Migrations?

Database migration is a process, which usually includes assessment, database schema conversion. Migrations enable us to manipulate modifications we make to the models and propagate these adjustments in the database. For example, if later on, we make a change to a field in one of the models, all we will want to do is create and do a migration, and the database will replicate the change.

What is Flask Migrate?

Flask-Migrate is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations are made available through the Flask command-line interface or through the Flask-Script extension.

Now let’s add support for migration in Badgeyay.

Step 1 :

pip install flask-migrate

 

Step 2 :

We will need to edit run.py and it will look like this :

import os
from flask import Flask
from flask_migrate import Migrate  // Imported Flask Migrate

from api.db import db
from api.config import config

......

db.init_app(app)
migrate = Migrate(app, db) // It will allow us to run migrations
......

@app.before_first_request
def create_tables():
    db.create_all()

if __name__ == '__main__':
    app.run()

 

Step 3 :

Creation of Migration Directory.

 export FLASK_APP=run.py
 flask db init

 

This will create Migration Directory in the backend API folder.

└── migrations
    ├── README
    ├── alembic.ini
    ├── env.py
    ├── script.py.mako
    └── versions

 

Step 4 :

We will do our first Migration by the following command.

flask db migrate

 

Step 5 :

We will apply the migrations by the following command.

flask db upgrade

 

Now we are all done with setting up Migrations to Flask SQLAlchemy for handling database changes in the badgeyay repository. We can verify the Migration by checking the database tables in the Database.

This is how I have added Migrations to Flask SQLAlchemy for handling Database changes using the Flask-Migrate extension in my Pull Request.

Resources:

  • PostgreSQL Docs    – Link
  • Flask Migrate Docs  – Link
  • SQLAlchemy Docs  – Link
  • Flask SQLAlchemy Docs – Link
Continue ReadingImplementing Database Migrations to 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

Variable Font Size Badgeyay

Badgeyay is a simple badge generator that aims for promoting an open-source tool for generation of badges in PDF format. The project has options to choose from predefined set of images or upload a background image. User can choose from set of fonts and color of the same. But now Badgeyay also has option to choose custom font-size in generation of badges.

To implement font size feature,  first, the component that is determining the font of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font size for the badge is font-size and its default value is set to 31.25 px. If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the font value from the frontend.
  • Using the same for the font-config.
  • Changing the built svg accordingly.

Procedure

  1. Firstly frontend component has to be changed to incorporate a slider to give input for the variable font size. So a range input is inserted with range from 15 px to 45 px and default as 30 px. The size_print label gets changed dynamically to show the value selected from the range slider.
<li>
<input type="radio" name="fontsize" id="font-size-picker"> Choose font size
</li>
<section id="font-size-input" style="display:none;">
<label for="inputFile" id="size_print"></label>
<div>
<input type="range" id="font-size" max=45 min=15 step=5 value=30  class="form-control" name="font_size">
</div>
</section>
  1. After adding the component, form script is changed to add toggle behaviour to the button. For adding the toggling behaviour in the component, checkbox is used and the value of the label is updated dynamically as the slider value is changed.
$("#size_print").text($("#font-size").val() + " px");

      $("#font-size-picker").click(function () {

          if ($(this).is(":checked")) {

              $("#font-size-input").css("display", "block");

          } else {

              $("#font-size-input").css("display", "none");

          }

      });

      $("#font-size").on('input', function () {

          $("#size_print").text($(this).val() + " px");

      });
  1. After completing the work on the frontend, it is necessary to modify the backend too. The method for choosing custom font has to be refactored. It now checks whether the custom font is set or font size variable is set, and creates a config file for fonts which after use gets deleted.
font_config = {}
   # custom font is specified
   if custom_font != '':
       font_config['font'] = custom_font
   if font_size != '':
       font_config['font_size'] = font_size
   if custom_font != '' or font_size != '':
       json_str = json.dumps(font_config)
       print(json_str)
       f = open(os.path.join(app.config['UPLOAD_FOLDER'], 'fonts.json'), "w+")
       f.write(json_str)
       f.close()
  1. The generator class is modified as well to accommodate the changes, by adding a new class attribute called font_size. We find the keys in the dict object loaded from the file and assign the same to class attribute.
if 'font_size' in self.DATA.keys():
               self.font_size = self.DATA['font_size']
  1. Make the necessary change in the svg, so that font size change can be represented in the generated PDF. Replace the old font size with the new font size specified.
if self.font_size:
           content = content.replace("font-size:31.25px",
                                     "font-size:" + str(self.font_size) + "px")
  1. After all the changes, badge generated will have a different font size.

The Pull request for the above change is at this Link

Topics Involved

Working on this Issue (Link) involve following topics:

  • SVG Label manipulation
  • Sending data from Ember frontend to Backend.
  • Javascript for the toggle radio button.

References

  • Extracting map information from the SVG (Link)
  • Python Documentation for class (Link)
  • About Github Pages- (Link)
  • Ajax Serialize method to serialize the form contents – (Link)
Continue ReadingVariable Font Size Badgeyay

Refactoring and Remodeling Badgeyay API

When we build a full scale production application, we make sure that everything is modeled correctly and accordingly to the need of the code. The code must be properly maintained as well as designed in such a way that it is less prone to errors and bugs.

Badgeyay is also targeting to be a full production application, and in order to achieve it we first need to re-factor the code and model it using a strong yet maintainable structure.

What is the current state of Badgeyay?

Currently Badgeyay is divided into two sub folders.

\badgeyay
    \frontend
    \backend
    .
    .

It is backed by two folders, viz backend and frontend. The ‘backend’ folder handles the API that the service is currently running. The ‘frontend’ folder houses the Ember based frontend logic of the application.

Improvements to Badgeyay Backend

We have worked on improving Backend for Badgeyay. Instead of traditional methods, i.e. current method, of API development; We employ a far better approach of using Flask Blueprint as a method of refactoring the API.

The new backend API resides inside the following structure.

\badgeyay
    \backend
        \blueprint
            \api

The API folder currently holds the new API being formatted from scratch using

  • Flask Blueprint
  • Flask Utilities like jsonify, response etc

The new structure of Badgeyay Backend will follow the following structure

api
    \config
    \controllers
    \helpers
    \models
    \utils
    db.py
    run.py

The folders and their use cases are given below

  • \config
    • Contain all the configuration files
    • Configurations about URLs, PostgreSQL etc
  • \controllers
    • This will contain the controllers for our API
    • Controllers will be the house to our routes for APIs
  • \helpers
    • Helpers folder will contain the files directly related to API
  • \models
    • Models folder contains the Schemas for PostgreSQL
    • Classes like User etc will be stored in here
  • \utils
    • Utils will contain the helper functions or classes
    • This classes or functions are not directly connected to the APIs
  • db.py
    • Main python file for Flask SQLAlchemy
  • run.py
    • This is the main entry point.
    • Running this file will run the entire Flask Blueprint API

How does it help?

  • It helps in making the backend more solid.
  • It helps in easy understanding of application with maintained workflow.
  • Since we will be adding a variety of features during Google Summer of Code 2018 therefore we need to have a well structured API with well defined paths for every file being used inside it.
  • It will help in easy maintaining for any maintainer on this project.
  • Development of the API will be faster in this way, since everything is divided into sub parts therefore many people can work on many different possibilities on the same time.

Further Improvements

Since this structure has been setup correctly in Badgeyay now, so we can work on adding separate routes and different functionalities can be added simultaneously.

It ensures faster development of the project.

Resources

Continue ReadingRefactoring and Remodeling Badgeyay API

Auto Deployment of Badgeyay Backend by Heroku Pipeline

Badgeyay project is now divided into two parts i.e front-end of Ember JS and back-end with REST-API programmed in Python. One of the challenging job is that, it should support the uncoupled architecture. Now, we have to integrate Heroku deployed API with Github which should auto deploy every Pull Request made to the Development Branch and help in easing the Pull Request review process.

In this blog, I’ll be discussing how I have configured Heroku Pipeline to auto deploy every Pull request made to the Development Branch and help in easing the Pull Request review process  in Badgeyay in my Pull Request.
First, Let’s understand Heroku Pipeline and its features. Then we will move onto configuring the Pipeline file to run auto deploy PR.. Let’s get started and understand it step by step.

What is Heroku Pipeline ?

A pipeline is a group of Heroku apps that share the same codebase. Each app in a pipeline represents one of the following steps in a continuous delivery workflow:

  • Review
  • Development
  • Staging
  • Production

A common Heroku continuous delivery workflow has the following steps:

  • A developer creates a pull request to make a change to the codebase.
  • Heroku automatically creates a review app for the pull request, allowing    developers to test the change.
  • When the change is ready, it’s merged into the codebase Default branch.
  • The Default branch is automatically deployed to staging for further testing.
  • When it’s ready, the staging app is promoted to production, where the change is available to end users of the app.

In badgeyay, I have used Review App and Development App steps for auto deployment of Pull Request.

Pre – requisites:

  • You should have admin rights of the Github Repository.
  • You should be the owner of the Heroku deployed app.
  • For creating a Review App , Below mentioned files are needed to be in the root of the project repository to trigger the Heroku Build.

1. App.json

{
    "name": "BadgeYay-API",
    "description": "A fully functional REST API for badges generator using flask",
    "repository": "https://github.com/fossasia/badgeyay/backend/",
    "keywords": [
        "badgeyay",
        "fossasia",
        "flask"
    ],
    "buildpacks": [
        {
            "url": "heroku/python"
        }
    ]
}
2. Procfile

web: gunicorn --pythonpath backend/app/ main:app

 

Now, I have fulfilled all the prerequisites needed for integrating Github repository to Heroku Deployed Badgeyay API. Let’s move to Heroku Dashboard of the Badgeyay API and implement auto deployment of every Pull Request.

Step 1 :

Open the heroku Deployed App on the dashboard. Yow will see following tabs in top of the dashboard.

Step 2 :

Click on Deploy and first create a new pipeline by giving a name to it and choose a stage for the pipeline.

Step 3 :

  • Choose a Deployment Method. For the badgeyay project, I have  integrated Github for auto deployment of PR.
  • Select the repository and connect with it.
  • You will receive a pop-up which will ensure that repository is connected to Heroku.

Step 4 :
Enable automatic deploys for the Github repository.

Step 5 :

Now after adding the pipeline, present app get nested under the pipeline. Click on the pipeline name on the top and now we have a pipeline dashboard like this :

Step 6:

Now for auto deployment of PR, enable Review Apps by filling the required information like this :

Step 7:

Verify by creating a test PR after following every above mentioned steps.

 

Now we are all done with setting up auto deployment of every pull request to badgeyay repository.

This is how I have configured Heroku Pipeline to auto deploy every Pull request made to the Development Branch and help in easing the Pull Request review process.

About Author :

I have been contributing in open source organization FOSSASIA, where I’m working on a project called BadgeYaY. It is a badge generator with a simple web UI to add data and generate printable badges in PDF.

Resources:

  • Heroku Pipelines Article – Link
Continue ReadingAuto Deployment of Badgeyay Backend by Heroku Pipeline

FOSSASIA Internship Program 2018

Are you interested to participate in the development of Open Source projects in a summer internship? Build up your developer profile with FOSSASIA and spend your summer coding on an open source project.  Contribute to SUSI.AIOpen EventBadgeyayYaydoc, Meilix or PSLab and join us at a workshop week and Jugaadfest in India. Please find the details below and submit your application to our form. Be sure to check out FOSSASIA’s program guidelines.

1. Program Details

  • Sign up on our dedicated form at fossasia.org/internship (Interns need to become members of the org and sign up on its social channels)
  • Internships are 3 months with monthly evaluations
  • plus preparation onboarding after acceptance
  • Eligible are contributors above 18 years of age. Any contributor is eligible including students, professionals, university staff etc. Prefered are contributors who have participated in the community previously.
  • Benefits of the program include Shirts, Swag, certificates. All participants who pass the final evaluation will be eligible to participate in a workshop week and Jugaadfest in September 2018 in Hyderabad. Travel grants and accommodation will be provided.
  • The program is intended as a full-time program. However, if contributors would like to participate who have a day job, they can still join and pass the program if they fulfill all program requirements. All contributors who pass the program will be able to receive funding for workshops and Jugaadfest participation.

2. Timeline

  • Application period ongoing until May 12
  • Acceptance ongoing until May 12
  • Start of pre-period:  May
  • Start of Internship: 1st June
  • Evaluation 1: July
  • Evaluation 2: August
  • Evaluation 3: September
  • End of Internship:  September, 2018
  • Issuing of Certificates: September 2018
  • FOSSASIA Workshop Week /Jugaadfest: September/October

3. Deliverables

  • Daily scrum email to project mailing list answering three questions: What did I do yesterday? What is my plan for today? Is there anything preventing me from achieving my goals, e.g. blockers?
  • Work according to pull requests and issues (submit code on Github and match it with issues)
  • Daily code submissions (software, hardware)
  • Documentation: Text, YouTube videos
  • 1 technical blog post a month with details on solving a problem in a FOSSASIA project (Monthly – 1: by Monday of second week)
  • Design items (in open formats, e.g. XCF, SVG, EPS)

4. Participating Projects

5. Best Practices

Please follow best practices as defined here: https://blog.fossasia.org/open-source-developer-guide-and-best-practices-at-fossasia/

6. Participant Benefits/Support

Participants will receive Swag, certificates and travel support to the FOSSASIA Workshop week and Jugaadfest.

  • Evaluation 1: July, 2018: Successful Participants receive a FOSSASIA Tshirt (sent out together with bag in evaluation 2)
  • Evaluation 2: August: Successful Participants receive a beautiful FOSSASIA bag
  • Evaluation 3: September: Successful Participants receive the following support to participate in the FOSSASIA India Workshop Week and Jugaadfest:
    • 100 SGD travel support from within India and 200 SGD support if coming from outside India
    • One week accommodation in Hyderabad (organized by FOSSASIA)
    • Catering during workshops
Continue ReadingFOSSASIA Internship Program 2018

Unit Tests for REST-API in Python Web Application

Badgeyay backend is now shifted to REST-API and to test functions used in REST-API, we need some testing technology which will test each and every function used in the API. For our purposes, we chose the popular unit tests Python test suite.

In this blog, I’ll be discussing how I have written unit tests to test Badgeyay  REST-API.

First, let’s understand what is unittests and why we have chosen it. Then we will move onto writing API tests for Badgeyay. These tests have a generic structure and thus the code I mention would work in other REST API testing scenarios, often with little to no modifications.

Let’s get started and understand API testing step by step.

What is Unittests?

Unitests is a Python unit testing framework which supports test automation, sharing of setup and shutdown code for tests, aggregation of tests into collections, and independence of the tests from the reporting framework. The unittest module provides classes that make it easy to support these qualities for a set of tests.

Why Unittests?

We get two primary benefits from unit testing, with a majority of the value going to the first:

  • Guides your design to be loosely coupled and well fleshed out. If doing test driven development, it limits the code you write to only what is needed and helps you to evolve that code in small steps.
  • Provides fast automated regression for re-factors and small changes to the code.
  • Unit testing also gives you living documentation about how small pieces of the system work.

We should always strive to write comprehensive tests that cover the working code pretty well.

Now, here is glimpse of how  I wrote unit tests for testing code in the REST-API backend of Badgeyay. Using unittests python package and requests modules, we can test REST API in test automation.

Below is the code snippet for which I have written unit tests in one of my pull requests.

def output(response_type, message, download_link):
    if download_link == '':
        response = [
            {
                'type': response_type,
                'message': message
            }
        ]
    else:
        response = [
            {
                'type': response_type,
                'message': message,
                'download_link': download_link
            }
        ]
    return jsonify({'response': response})

 

To test this function, I basically created a mock object which could simulate the behavior of real objects in a controlled way, so in this case a mock object may simulate the behavior of the output function and return something like an JSON response without hitting the real REST API. Now the next challenge is to parse the JSON response and feed the specific value of the response JSON to the Python automation script. So Python reads the JSON as a dictionary object and it really simplifies the way JSON needs to be parsed and used.

And here’s the content of the backend/tests/test_basic.py file.

 #!/usr/bin/env python3
"""Tests for Basic Functions"""
import sys
import json
import unittest

sys.path.append("../..")
from app.main import *


class TestFunctions(unittest.TestCase):
      """Test case for the client methods."""
    def setup(self):
        app.app.config['TESTING'] = True
        self.app = app.app.test_client()
      # Test of Output function
    def test_output(self):
        with app.test_request_context():
            # mock object
            out = output('error', 'Test Error', 'local_host')
            # Passing the mock object
            response = [
                {
                    'type': 'error',
                    'message': 'Test Error',
                    'download_link': 'local_host'
                }
            ]
            data = json.loads(out.get_data(as_text=True))
            # Assert response
            self.assertEqual(data['response'], response)


if __name__ == '__main__':
    unittest.main()

 

And finally, we can verify that everything works by running nosetests .

This is how I wrote unit tests in BadgeYaY repository. You can find more of work here.

Resources:

  • The Purpose of Unit Testing – Link
  • Unit testing framework – Link
Continue ReadingUnit Tests for REST-API in Python Web Application

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

Parallelizing Builds In Travis CI

Badgeyay project is now divided into two parts i.e front-end of emberJS and back-end with REST-API programmed in Python. Now, one of the challenging job is that, it should support the uncoupled architecture. It should therefore run tests for the front-end and backend i.e, of two different languages on isolated instances by making use of the isolated parallel builds.

In this blog, I’ll be discussing how I have configured Travis CI to run the tests parallely in isolated parallel builds in Badgeyay in my Pull Request.

First let’s understand what is Parallel Travis CI build and why we need it. Then we will move onto configuring the travis.yml file to run tests parallely. Let’s get started and understand it step by step.

Why Parallel Travis CI Build?

The integration test suites tend to test more complex situations through the whole stack which incorporates front-end and back-end, they likewise have a tendency to be the slowest part, requiring various minutes to run, here and there even up to 30 minutes. To accelerate a test suite like that, we can split it up into a few sections utilizing Travis build matrix feature. Travis will decide the build matrix based on environment variables and schedule two builds to run.

Now our objective is clear that we have to configure travis.yml to build parallel-y. Our project requires two buildpacks, Python and node_js, running the build jobs for both them would speed up things by a considerable amount.It seems be possible now to run several languages in one .travis.yml file using the matrix:include feature.

Below is the code snippet of the travis.yml file  for the Badgeyay project in order to run build jobs in a parallel fashion.

sudo: required
dist: trusty

# check different combinations of build flags which is able to divide builds into “jobs”.
matrix:

# Helps to run different languages in one .travis.yml file
include:

# First Job in Python.
- language: python3

apt:
packages:
- python-dev

python:
- 3.5
cache:
directories:
- $HOME/backend/.pip-cache/

before_install:
- sudo apt-get -qq update
- sudo apt-get -y install python3-pip
- sudo apt-get install python-virtualenv

install:
- virtualenv  -p python3 ../flask_env
- source ../flask_env/bin/activate
- pip3 install -r backend/requirements/test.txt --cache-dir

before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 3

script:
- python backend/app/main.py >> log.txt 2>&1  &
- python backend/app/main.py > /dev/null &
- py.test --cov ../  ./backend/app/tests/test_api.py

after_success:
- bash <(curl -s https://codecov.io/bash)

# Second Job in node js.
- language: node_js
node_js:
- "6"

addons:
chrome: stable

cache:
directories:
- $HOME/frontend/.npm

env:
global:
# See https://git.io/vdao3 for details.
- JOBS=1

before_install:
- cd frontend
- npm install
- npm install -g ember-cli
- npm i eslint-plugin-ember@latest --save-dev
- npm config set spin false

script:
- npm run lint:js
- npm test

 

Now, as we have added travis.yml and pushed it to the project repo. Here is the screenshot of passing Travis CI after parallel build jobs.

The related PR of this work is https://github.com/fossasia/badgeyay/pull/512

Resources :

Travis CI documentation – Link

Continue ReadingParallelizing Builds In Travis CI

Badgeyay: Custom Fonts in generation of badges

Badgeyay is an open source project of FOSSASIA. The main idea for this project is to provide an open-source alternative for badge generation process for any event. It can generate badges according to a predefined config or we can also submit our own custom config for the generation of the badges. We can use custom background, text and other things. One thing that is not present is the choice for choosing a custom font for the badge. I have made a contribution for adding this functionality with selection of some common fonts in the code.

Procedure

  1. Add a Button in index.html for the choice of the font and also preview them at the same time. 
    <label>Choose your font</label>
    <ul style=“list-style-type:none”>
     <li>
        <input type=“radio” name=“fontsource” id=“custfont”> Use Custom font
                        </li>
                        <section id=“custom-font” style=“display: none;”>
        <label for=“inputFile”>Select from following fonts</label>
        <div class=“btn-group”>
           <button type=“button” class=“btn btn-default dropdown-toggle” data-toggle=“dropdown” aria-haspopup=“true” aria-expanded=“false”>
              <span class=“placeholder2”>Select a font</span>
              <span class=“glyphicon glyphicon-chevron-down”></span>
           </button>
           <ul class=“dropdown-menu”>
              {% for i in custom_fonts %}
              <li class=“font-options” style=“font-family:'{{i}}'” data-item=“{{i}}”>{{i}}</li>
              {% endfor %}
           </ul>
        </div>
     </section>
     <input type=“hidden” name=“custfont” value=“”>
    </ul>

     

     

  2. Add javascript for the toggle in the check button and CSS for the Font option button.
.$(“.font-options”).click(function () {
  var i = $(this).data(“item”);
  $(“.placeholder2”).text(i);
  $(“input[name=’custfont’]”).val(i);
});

 

.font-options {
border-bottom: 1px solid darkgray;
padding: 9px;
}

 

  1. Font list is passed in the index page.
CUSTOM_FONTS = [‘monospace’, ‘sans-serif’, ‘sans’, ‘Courier 10 Pitch’, ‘Source Code Pro’]

 

render_template(‘index.html’, default_background=default_background, custom_fonts=CUSTOM_FONTS)

 

  1. Config file for font has been created, so that it can be used by different files.
custom_font = request.form[‘custfont’]
# Custom font is selected for the text
if custom_font != :
  json_str = json.dumps({
      ‘font’: custom_font
  })
  f = open(os.path.join(app.config[‘UPLOAD_FOLDER’], ‘fonts.json’), “w+”)
  f.write(json_str)
  f.close()

 

  1. Font preference is taken from the file at the time of generation of the badge (once only for all the badges in a single run).
font_choice = None
if os.path.isfile(os.path.join(UPLOAD_FOLDER, ‘fonts.json’)):
  DATA = json.load(open(os.path.join(UPLOAD_FOLDER, “fonts.json”)))
  font_choice = DATA[‘font’]

 

  1. Changes in the SVG are made according to the preference for the PDF generation. If the user wants a custom font then it updates the svg using the config else not.
content = CONTENT
if font_choice:
  content = content.replace(“font-family:sans-serif”,
                            “font-family:” + font_choice)
  content = content.replace(“inkscape-font-specification:sans-serif”,
                            “inkscape-font-specification:” + font_choice)
  content = content.replace(“font-family:ubuntu”,
                            “font-family:” + font_choice)
  content = content.replace(“inkscape-font-specification:ubuntu”,
                            “inkscape-font-specification:” + font_choice)

 

  1. Finally the Updated SVG is used for Badge Generation with custom fonts embedded.

Resources

Resources utilised for adding this functionality

  • Fonts in SVG – Link
  • Embed fonts in Inkscape SVG – Link
  • Embed fonts in PDF and SVG – Link

 

Continue ReadingBadgeyay: Custom Fonts in generation of badges