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

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