Implementing Event Average Rating with SQLAlchemy

While implementing Open Event Server version 2, we decided to have a better way of ranking events by their quality. To define the “quality” of events, the programmers decided to accumulate the feedbacks of specific events and take the average of the ratings involved. Thus, the average rating of an event proves to be a good (enough) measure of its quality. While there are many ways to implement aggregate relationships in an app, here I demonstrate a rather modern methodology which insists on storing such aggregates once they’re computed.

Since there is always a space-time/computation tradeoff in software development, this task was no exception. At first, the straightforward idea that came to my mind was to query the Postgres database every time a request for average rating was made. This sounds simple, but with hundreds of events stored on a server, and potentially thousands of users querying for events, this seemed to be a computationally expensive approach. It was costly because the average rating aggregate would be computed for each request, and there could potentially be thousands of such concurrent requests. Therefore, a better idea is to compute the aggregate once, store it in the database (compromising space in the tradeoff mentioned above, but saving a large amount of computation at the same time), and update only when a change is made. In our specific case, the update should happen only when a new rating is added, a rating is deleted or an existing rating is modified. Since the advantages outnumbered the disadvantages, this was the strategy to be implemented.

The first step in implementing average rating was to modify the database model of events accordingly. For this, I performed the necessary imports in the events’ database model file:

from sqlalchemy_utils import aggregated
from app.models.feedback import Feedback

Now comes the tricky part. We want an average_rating column in the events table, that contains the mean rating of events. The values in this column should be updated every time a change is made to the feedbacks table. To perform this sort of functionality, the best, raw tool is a Postgres trigger. A trigger should be created that is fired after every update to the feedbacks table, which should update the average rating values in the events table. Here’s how the raw code of such a trigger looks like:

create or replace function UpdateAverageRating() returns trigger AS
$$
BEGIN
UPDATE events SET average_rating=(
SELECT avg(rating) FROM feedbacks
WHERE event_id=NEW.event_id
GROUP BY event_id
)

WHERE id = NEW.event_id
END
$$
language plpgsql

Fortunately, the translation of such a trigger into SQLAlchemy-speak is not only easy, but also very elegant. The imports I showed above already set the context for this translation.

The event model class looks like the following:

class Event(db.Model):
    """Event object table"""
    __tablename__ = 'events'
    __versioned__ = {
'exclude': ['schedule_published_on', 'created_at']
}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String)
    name = db.Column(db.String, nullable=False)
    external_event_url = db.Column(db.String)

    

    

    

The list of attributes continues, and to the end of this list, we now add a decorated method:




xcal_url = db.Column(db.String)
is_sponsors_enabled = db.Column(db.Boolean, default=False)
discount_code_id = db.Column(db.Integer, db.ForeignKey(
'discount_codes.id', ondelete='CASCADE'))

@aggregated('feedbacks', db.Column(db.Float))
def average_rating(self):
    return db.func.avg(Feedback.rating)

That’s it with the translation – this slick, decorated method can be thought of as a bridge between Python and the trigger shown earlier that’s usually implemented in the database itself. Once this method is added, we save the model file and perform a database migration:

$ python manage.py db migrate

This generates a migration file associated with our changes. This file shows the following alembic migration code:

"""empty message

Revision ID: 1471fe0d04ee
Revises: 49f3a33f5437
Create Date: 2018-06-08 19:32:47.485543

"""

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '1471fe0d04ee'
down_revision = '49f3a33f5437'


def upgrade():
    op.add_column('events', sa.Column('average_rating', sa.Float(), nullable=True))
    op.add_column('events_version', sa.Column('average_rating', sa.Float(), autoincrement=False, nullable=True))

def downgrade():
    op.drop_column('events_version', 'average_rating')
    op.drop_column('events', 'average_rating')

Now that the file is generated, we upgrade our database state by utilizing this migration file:

$ python manage.py db upgrade

And here are the successful migration logs that immediately follow the upgrade command:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade 49f3a33f5437 -> 1471fe0d04ee, empty message

 

This completes the implementation of the average rating attribute of events. We can use the same technique to implement other attributes in our server, like sum, and minimum, just to name a couple. We saw how SQLAlchemy so elegantly manages to map all the mapping from Python code to database commands. This is just one of the plethora of advantages of using database object-relational-mappers (ORMs), and Open Event Server utilizes them to full extent.

Resources:

Continue ReadingImplementing Event Average Rating with SQLAlchemy

Implementing Badgename Update Functionality

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

Badgeyay has many features related to enhancement in generation of badges. It gives choice of uploading data entries i.e by CSV or manually. There are options available for choosing Badge Background and font specifications. Now the next important thing from User perspective is that there should be a feature in My badges panel where user can see all badges & other details  and should be able to edit them if he want to, so moving forward with this feature I have implemented Badge Name update functionality in the frontend.

In this blog, I will be discussing how I implemented Update Badge Name functionality in my Pull Request so that the User can change his Badge Name  at any point of time in my badges panel.

Let’s get started and understand it step by step.

Step 1:

Create Badge Name component with Ember CLI.

$ ember g component badge-name

 

Step 2:

Make changes in Handlebar of Badge Name. We will be using semantic UI form for making the changes in Handlebars.

<form class="ui form" {{action 'updateBadgeName' on="change"}}>
    
class="ui icon input"> class="pen square icon"> {{input type="text" value=badge.badge_name }}
</form>

 

We have used action on submitting the Form for changing and updating the Badgename in Database.

Step 3:

We will now define the action in badge name JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
import Ember from 'ember';
const { inject } = Ember;
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  notifications : inject.service('notification-messages'),
  actions       : {
    updateBadgeName() {
      this.get('sendBadgeName')(this.get('badge'));
    },
    didRender() {
      this.$('.ui.form')
        .form({
          inline : true,
          delay  : false,
          fields : {
            Name: {
              identifier : 'Name',
              rules      : [
                {
                  type   : 'empty',
                  prompt : 'Please enter a valid Badge Name'
                }
              ]
            }
          }
        });
    }
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
  routing       : service('-routing'),
  notifications : service('notification-messages'),
  actions       : {
    updateBadgeName(badge) {
      badge.save()
        .then(() => this.get('notifications').success('Badge Name Successfully Updated!', {
          autoClear     : true,
          clearDuration : 1500
        }));
    }
  }
});

 

Now, I am done with doing all the changes in Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • My Badges Panel

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk

 

Continue ReadingImplementing Badgename Update Functionality

Implementing Different Alignment for Different Line

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

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing different text alignment  for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented different text alignment for Different Line in Badgeyay Backend in my Pull Request.

To implement different text alignment for Different Line feature,  first, the component in SVG that is determining the text alignment 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 type for the badge is text-align and its default value is set to start(right alignment). 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 text-align value from the frontend.
  • Using the same for the text-align in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to text-align property provided by the User in the Frontend.

 def change_text_align(self,
                          filename,
                          badge_size,
                          paper_size,
                          align_1, // Values from Frontend
                          align_2,
                          align_3,
                          align_4,
                          align_5):

        """
            Module to change Text Alignment of each badge line
                :param `filename` - svg file to modify.
                :param `align_1` - Text Alignment to be applied on first line
                :param `align_2` - Text Alignment to be applied on Second line
                :param `align_3` - Text Alignment to be applied on Third line
                :param `align_4` - Text Alignment to be applied on Fourth line
                :param `align_5` - Text Alignment to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        align = [1, align_1, align_2, align_3, align_4, align_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'text-align':
                        style_detail[ind] = "text-align:" + align[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("text-align", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
 // Fill the text-align argument of the selected object by changing the value of text-align.
                    text_style_detail[-1] = "text-align:" + align[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Text Alignment Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different text-align embedded.

Now, we are done with implementation of different text alignment  for Different Line in Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Alignment for Different Line

Implementing Different Font Type for Different Line

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

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font types for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font types for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font type for Different Line feature,  first, the component in SVG 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 type for the badge is font-family and its default value is set to sans-serif. 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-type value from the frontend.
  • Using the same for the font-type in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font type provided by the User in the Frontend.

  def change_font_family(self,
                           filename,
                           badge_size,
                           paper_size,
                           Font_1, // Values from Frontend
                           Font_2, 
                           font_3,
                           font_4,
                           font_5):

        """
            Module to change Font Family of each badge lines
                :param `filename` - svg file to modify.
                :param `font_1` - Family to be applied on first line
                :param `font_2` - Family to be applied on Second line
                :param `font_3` - Family to be applied on Third line
                :param `font_4` - Family to be applied on Fourth line
                :param `font_5` - Family to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font = [1, font_1, font_2, font_3, font_4, font_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
               //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-family':
                        style_detail[ind] = "font-family:" + font[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-family", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
  // Fill the font family argument of the selected object by changing the value of font-family.
                    text_style_detail[-1] = "font-family:" + font[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Family Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different font type embedded.

Now, we are done with implementation of Different Font type for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Font Type for Different Line

Implementing Different Font Size for Different Line

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

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font sizes for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font Size for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font Size for Different Line feature,  first, the component in SVG that is determining the font size 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-size value from the frontend.
  • Using the same for the font-size in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font Size provided by the User in the Frontend.

def change_font_size(self,
                         filename,
                         badge_size,
                         paper_size,
                         Font_size_1, // Values from Frontend
                         font_size_2,
                         font_size_3,
                         font_size_4,
                         font_size_5):

        """
   Module to change size of each badge lines
   :param `filename` - svg file to modify.
   :param `font_size_1` - Size to be applied on first line
   :param `font_size_2` - Size to be applied on Second line
   :param `font_size_3` - Size to be applied on Third line
   :param `font_size_4` - Size to be applied on Fourth line
   :param `font_size_5` - Size to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font_size = [1, font_size_1, font_size_2, font_size_3, font_size_4, font_size_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                 //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)                 path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-size':
                        style_detail[ind] = "font-size:" + font_size[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-size", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
   // Fill the font size argument of the selected object by changing the value of font-size.
                    text_style_detail[-1] = "font-size:" + font_size[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Size Saved!")

 

 

After all the changes, the Updated SVG is used for Badge Generation with different font size embedded

Now, we are done with implementation of Different Font Size for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link

Pull Request Link – Link

Continue ReadingImplementing Different Font Size for Different Line

Implementing Password Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Password functionality in my Pull Request so that the User can change his Password at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User Password component with help of ember cli.

Step 2:

Make changes in Handlebar of User Password. We will be using semantic UI form for making the changes in Handlebars.

<h2 class="ui header">Password</h2>
<h5 class="ui dividing header">Change your password.</h5>
<form class="ui form" {{action 'updateUserPassword' on="submit"}}>
    
class="field"> New Password
class="fields">
class="ten wide field"> {{input type="password" id="newPassword" name=newPassword value=user.password}}
</div> </div>
class="field"> Verify Password
class="fields">
class="ten wide field"> {{input type="password" id="newPasswordVerify" name=newPasswordVerify placeholder="Re-enter Password"}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0"> Save Changes </button> </form>

 

We have used action on submitting the Form for changing and updating the Password in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserPassword() {
      let password = this.get('newPassword');
      this.get('sendUserPassword')(password);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          newPassword: {
            identifier : 'newPassword',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a password'
              },
              {
                type   : 'minLength[6]',
                prompt : 'Your password must have at least {ruleValue} characters'
              }
            ]
          },
          newPasswordVerify: {
            identifier : 'newPasswordVerify',
            rules      : [
              {
                type   : 'match[newPassword]',
                prompt : 'Passwords do not match'
              }
            ]
          }
        }
      });
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

.......
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
...............
   updateUserPassword() {
      this.get('user').save()
        .then(() => this.get('notify').success('Password Successfully Updated!'))
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if Password changes in params, It should change the password and send the response with the updated user schema.

api/controllers/registerUser.py
...............
   if 'password' in data.keys():
        user.password = data['password']
        update_firebase_password(user.id, user.password)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • User password Panel

Now, we are done with implementation of Update password Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing Password Update Functionality

Implementing User-name Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and the most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Username functionality in my Pull Request so that the User can change his username at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User account component with help of ember cli.

$ ember g component user-component/user-account

 

Step 2:

Make changes in Handlebar of User Account. We will be using semantic UI form for making the changes in Handlebars.

// user-account.hbs

<h2 class="ui dividing header">Account</h2>
<form class="ui form" {{action 'updateUserName' on="submit"}}>
    
class="ui field"> Username
class="ui fields">
class="ten wide field"> {{input type="text" id="profileName" name=profileName value=user.username}}
</div> </div>
class="ui field"> Email
class="ui fields">
class="ten wide disabled field"> {{input type="email" name=email value=user.email}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0" >Save Changes</button> </form>

 

We have used action on submitting the Form for changing and updating the username in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserName() {
      let profileName = this.get('profileName');
      this.get('sendUserName')(profileName);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          username: {
            identifier : 'profileName',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a valid username'
              }
            ]
          }
        }
      });
}});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

…….
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
…………...
   updateUserName(profileName) {
      const _this = this;
      const user = this.get('store').peekAll('user');
      user.forEach(user_ => {
        _this.set('uid', user_.get('id'));
      });
      _this.get('user').save();
      _this.get('notify').success('Username Successfully Updated!');
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if username is change in params, It should change the username and send the response with the updated username.

api/controllers/registerUser.py
…………...
   if 'username' in data.keys():
        user.username = data['username']
        update_firebase_username(user.id, user.username)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

User Account Panel

Now, we are done with implementation of Update Username Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing User-name Update Functionality

Forgot Password Service in Badgeyay

Badgeyay is an open source badge generator service for generating badges developed by FOSSASIA community for technical events and conferences. The project is divided into two components mainly frontend and backend. After creating the user registration functionality in application, if the user forgets the credentials for the login, then there must be a way to recreate the credentials using a secure channel. This is only valid for the users signed up through email login as for the case of OAuth they must have access to their ID on respective social platform. The main challenges in resetting password for the user is to provide a secure channel. So the problem can be breakdown into following issues:

  • Creating a token for reset action
  • Sending that token via mail to user
  • Verifying that token on the server and giving access
  • Changing the credentials  of the user

Procedure

  1. Generating token for the request to change credentials for the user. The token will be an expiry token and will be expired in the mentioned duration. So the token is valid for only a limited period of time and will prevent fraudulent requests.
def pwd_reset_token():
  data = request.get_json()[‘data’][‘attributes’]
  if ’email’ not in data.keys():
      print(‘Email not found’)
  email = data[’email’]
  user = User.getUser(email=email)
  if not user:
      return ErrorResponse(UserNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()
  expire = datetime.datetime.utcnow() + datetime.timedelta(seconds=900)
  token = jwt.encode({
      ‘id’: user.id,
      ‘exp’: expire
  }, app.config.get(‘SECRET_KEY’))
  resetObj = ResetPasswordToken(user.id, token.decode(‘UTF-8’))
  resetObj.save_to_db()
  return jsonify(TokenSchema().dump(resetObj).data)

Model for ResetPasswordToken

class ResetPasswordToken(db.Model):

  __tablename__ = ‘Reset Password Token’

  id = db.Column(db.String, primary_key=True)
  token = db.Column(db.String, nullable=False)

  def __init__(self, uid, token):
      self.id = uid
      self.token = token

  def save_to_db(self):
      try:
          db.session.add(self)
          db.session.commit()
      except Exception as e:
          db.session.rollback()
          db.session.flush()
          print(e)

 

  1. Sending the password reset link via mail to the user. The link will contain the token (expiry token) that will be used to validate the request. For the case we will be using Firebase Cloud functions as an HTTP Trigger.
exports.sendResetMail = functions.https.onRequest((req, res) => {
let token = req.query[‘token’];
let email = req.query[’email’];
res.setHeader(‘Content-Type’, ‘application/json’);
sendResetMail(token, email)
  .then(() => {
    console.log(‘Reset mail sent to’, email);
    res.json({ data: { attributes: { status: 200 }, id: token, type: ‘reset-mails’ } });
    return 0;
  })
  .catch(err => {
    console.error(err);
    res.json({ data: { attributes: { status: 500 }, id: token, type: ‘reset-mails’ } });
    return -1;
  });
});

function sendResetMail(token, email) {
const mailOptions = {
  from: `${APP_NAME}<noreply@firebase.com>`,
  to: email,
};

mailOptions.subject = `Password reset link`;
mailOptions.html = ‘<p>Hey ‘ + email + ‘! Here is your password reset <a href=\” + PASSWORD_RESET_LINK
  + token + ‘\’>Link</a><p>’;
return mailTransport.sendMail(mailOptions);
}

 

  1. Verifying the token on the server side to validate the user request
def validate_reset_token():
  args = request.args
  if ‘token’ in args.keys():
      token = args.get(‘token’)
  resp = {‘id’: token}
  try:
      jwt.decode(token, app.config[‘SECRET_KEY’])
      resp[‘valid’] = True
      return jsonify(ValidTokenSchema().dump(resp).data)
  except Exception as e:
      resp[‘valid’] = False
      print(e)
      return jsonify(ValidTokenSchema().dump(resp).data)

 

  1. After user has access to change the credentials, then user can send a POST request to backend through a form shown in UI to change its password.
def changePwd():
  try:
      data = request.get_json()[‘data’][‘attributes’]
  except Exception as e:
      print(e)
      return ErrorResponse(PayloadNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  token = data[‘token’]
  try:
      decoded_res = jwt.decode(token, app.config[‘SECRET_KEY’])
  except Exception as e:
      print(e)
      return ErrorResponse(SignatureExpired().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  user = User.getUser(user_id=decoded_res[‘id’])

  if ‘pwd’ not in data.keys():
      return ErrorResponse(PasswordNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

  pwd = data[‘pwd’]
  oldPwd = user.password
  user.password = generate_password_hash(pwd)
  user.save_to_db()

  resp = {‘id’: token}
  if update_firebase_password(user.id, pwd):
      resp[‘status’] = ‘Changed’
      return jsonify(ResetPasswordOperation().dump(resp).data)
  else:
      print(‘Firebase not uploaded’)
      user.password = oldPwd
      user.save_to_db()
      resp[‘status’] = ‘Not Changed’
      return jsonify(ResetPasswordOperation().dump(resp).data)

 

  1. After this the password of the user will be changed and allowed to login through new credentials.

Link to PRs:

  • PR for forgot password reset form – #1
  • PR for implementing forgot password on firebase side – #2
  • PR for password reset mail functionality – #3

Resources

  • HTTP Trigger Cloud functions – Link
  • Nodemailer message configuration – Link
  • Ember Data Guide – Link

 

Continue ReadingForgot Password Service in Badgeyay

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

Using external UART modules to debug PSLab operations

Pocket Science Lab by FOSSASIA is a compact tool that can be used for circuit analytics and debugging. To make things more interesting, this device can be accessed via the user interface using an Android app or also a desktop app. Both these apps use the UART protocol (Universal Asynchronous Receiver-Transmitter) to transmit commands to the PSLab device from mobile phone or PC and receive commands vice versa. The peculiar thing about hardware is that the developer cannot simply log data just like developing and debugging a software program. He needs some kind of an external mechanism or a tool to visualize those data packets travelling through the wires.

Figure 1: UART Interface in PSLab

PSLab has a UART interface extracted out simply for this reason and also to connect external sensors that use the UART protocol. With this, a developer who is debugging any of the Android app or the desktop app can view the command and data packets transmitted between the device and the user end application.

This  requires some additional components. UART interface has two communication related pins: Rx(Receiver) and Tx(Transmitter). We will need to monitor both these pin signals for input and output data packets. It should be kept in mind that PSLab is using 3.3V signals. This voltage level is important to mention here because if someone uses 5V signals on these pins, it will damage the main IC. There are FTDI modules available in market. FTDI stands for Future Technology Devices International which is a company name and their main product is this USB transceiver chip. These chips play a major role in electronic industry due to product reliability and multiple voltage support. PSLab uses 3.3V USB Tx Rx pins and modules other than FTDI wouldn’t support it.

Figure 2: FTDI Module from SparkFun

The module shown in Fig.2 is a FTDI module which you can simply plug in to computer and have a serial monitor interface. There are cheaper versions in shopping websites like eBay or Alibaba and they will also work fine. Both Tx and Rx pins will require two of these modules and connectivity is as follows;

PSLab [Rx Pin] → FTDI Module 1 [Rx Pin]
PSLab [Tx Pin] → FTDI Module 2 [Rx Pin]

This might look strange because everywhere we see a UART module is connected Rx → Tx and Tx → Rx. Notice that our idea is to monitor data packets. Not communicate with PSLab device directly. We want to see if our mobile phone Android app is sending correct commands to PSLab device or not and if PSLab device is transmitting back the expected result or not. This method helped a lot when debugging resistance measurement application in PSLab Android app.

Monitoring these UART data packets can be done simply using a serial monitor. You can either download and install some already built serial monitors or you can simply write a python script as follows which does the trick.

import serial

ser = serial.Serial(
    port='/dev/ttyUSB1',
    baudrate=1000000000
)

ser.isOpen()
while 1 :
    data = ''
    while ser.inWaiting() > 0:
        data += ser.read(1)

    if data != '':
        print ">>" + data

Once you are getting commands and responses, it will look like debugging a software using console.

References:

  1. PySerial Library : http://pyserial.readthedocs.io/en/latest/shortintro.html
  2. UART Protocol : https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter
  3. FTDI : https://en.wikipedia.org/wiki/FTDI
Continue ReadingUsing external UART modules to debug PSLab operations