Migrating Event Ratings of Open Event with Stored Procedures

Many developers know about procedural languages and have used them in some form or another, but this is really an unpopular tool, despite its power. There are many advantages (and few disadvantages) of these languages, which we will learn about soon. Having a right amount of database-stored procedure code with the help of these languages can really enhance the speed and responsiveness of an application. This article will teach us how procedural languages can be utilized in database management and how they were used recently for a bug fix in Open Event Server. PostgreSQL, like any other powerful, relational database management system (RDBMS), provides the functionality to create and use stored procedures. Essentially, a stored procedure is database logic code which is saved on the database server. This code can be executed directly in the database, and can (and is!) often used to shift business logic from the application layer of a software to the database layer. This simple shift often has many advantages - including faster execution (as code executes at a lower stack level) and better security. When firing database queries from the application layer (i.e., the code that programmers write for storing programmable objects, performing business logic and so on), it often happens that parameters from the programming language itself are passed in to SQL, which then generates a complete SQL query. For example, here’s how a novice query might look like: import psycopg2 conn = psycopg2.connect(dbname="oevent", user="john", password="start") cur = conn.cursor() name = "Sam" cur.execute("SELECT * FROM users WHERE name='%s'" % name) # DANGEROUS! This is an extremely “exposed” code that can be exploited for malicious access, with a technique called SQL injection. This technique essentially “injects” malicious code via these passed parameters, like the variable name mentioned in the above code. With having stored procedures for business logic, there is no room for SQL injection. They solve this problem by writing the query beforehand, and having the parameterized data as a different entity. The pre-processed query within the corresponding stored procedure now looks like SELECT * FROM users WHERE name=?   The database driver sends the name of this stored procedure (or, in standard parameterised queries, just the query text itself) and a list of parameters, as distinct separate entities in the protocol. More details on how stored procedures enhance security can be found here. After learning so much about the advantages of stored procedures (which are enabled by procedural languages), let’s write one! Postgres supports multiple languages for writing stored procedures; here we will use PL/pgSQL, which is the most popular choice for Postgres. This procedural language, inspired (heavily) by Oracle’s PL/SQL language, looks very similar to SQL. To use this procedural language, we have to first install it. In Postgres, procedural languages are installed per-database, not server-wide. We can use the popular Postgres client psql for this purpose, or simply the createlang command on the command line: $ createlang plpgsql yourdb   Now let’s create a simple procedure that prints the corresponding grades…

Continue ReadingMigrating Event Ratings of Open Event with Stored Procedures

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,…

Continue ReadingImplementing Event Average Rating with SQLAlchemy

Enforcing Constraints Throughout a Flask Back-End

Recently it was discovered that Open Event Server does not validate attendees’ tickets. Specifically, it was possible to create an arbitrary number of attendees who’d be attending an event on the same ticket! To fix this, a constraint had to be set up across different layers of Open Event Server, which is based on Flask and Postgres. This post will demonstrate how the constraint was added in the server, and these steps should apply in general to any Flask-based server with a relational back-end. First of all, the immediate idea that comes after investigating such an issue, is to add a UNIQUE constraint to the database. For this specific case, the problem was in ticket_holders table of the Open Event database. There was originally no check imposed on the ticket_id and event_id columns. As can be seen in the ticket_holders schema (using the \d+ ticket_holders command), there is no mention of uniqueness on either column. The initial guess was that the combination of ticket_id and event_id should be unique throughout the table to avoid multiple holders attending on the same ticket. However,imposing uniqueness on just the ticket_id column would’ve also worked. So, to be on the safer side, I moved ahead by adding uniqueness on both the columns. To fix this, we need to make changes to the ticket_holder model. So, in the ticket_holder model file, we add a __table_args__ attribute to the TicketHolder class. This attribute represents the various constraints imposed on the ticket_holders table: class TicketHolder(db.Model): __tablename__ = "ticket_holders" __table_args__ = ( db.UniqueConstraint('ticket_id', 'event_id', name='ticket_event'), ) # this is the constraint we add id = db.Column(db.Integer, primary_key=True) firstname = db.Column(db.String, nullable=False) lastname = db.Column(db.String, nullable=False) … … … The TicketHolder class has attributes named ticket_id and event_id, so to add a unique constraint over them, we pass their names to the UniqueConstraint constructor. Also, any suitable name can be given to the constraint, I chose ‘ticket_event’ to simply emphasize the relationship. Now that we’ve edited the database model file, we have to perform a database migration. Before we command the migration, we have to remove the entries that potentially violate the constraint we just imposed. As a temporary fix, I connected to the database and deleted all non-unique rows via plain SQL. For a more consistent fix, I will implement this simple deletion code in the database migration file, if need be. So, once the non-unique rows are gone, we perform the database migration as follows: $ python manage.py db migrate And then, $ python manage.py db upgrade These commands may be different for different projects, but their purpose is the same - to update the database. The upgrade command generates a migration file which looks as follows: from alembic import op import sqlalchemy as sa import sqlalchemy_utils # revision identifiers, used by Alembic. revision = '9d21de792967' down_revision = '194a5a2a44ef' def upgrade(): op.create_unique_constraint('ticket_event', 'ticket_holders', ['ticket_id', 'event_id']) def downgrade(): op.drop_constraint('ticket_event', 'ticket_holders', type_='unique') We can see that the upgrade() function has the command for adding our constraint. Once the database…

Continue ReadingEnforcing Constraints Throughout a Flask Back-End

Adding System Messages on Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues. Event managers can create invitation forms for speakers and build schedules in a drag and drop interface. The event information is stored in a database. The system provides API endpoints to fetch the data, and to modify and update it. The Open Event Server is based on JSON 1.0 Specification and hence build on top of Flask Rest Json API (for building Rest APIs) and Marshmallow (for Schema). In this blog, we will talk about how to add API for accessing the System Messages on Open Event Server. The focus is on its Model updation and it’s Schema creation. Model Updation For the System Messages, we’ll make update model as follows Now, let’s try to understand this Schema. In this feature, we are providing Admin the rights to read email and notification formats used in Open Event application. First of all, there is the need to know that it has three columns notification_status, user_control_status and mail_status of type boolean. Next it has action attribute which is of type String. At last, we have hybrid properties email_message and notification_message which will return the format of email and notification respective to the action string. The hybrid properties depends on _email_message method and _notification_message method. These methods reads the MAILS and NOTIFS dictionaries and return there values corresponding to string of action key of corresponding record. Schema Creation For the System Messages, we’ll make our Schema as follows Now, let’s try to understand this Schema. In this feature, we are providing Admin the rights to read email and notification formats used in Open Event application. First of all, there is the need to know that it has three boolean properties notification_status, user_control_status and mail_status Next it has action attribute which is of type String and it’s value can be validated to have any one of the list provided in choices. At last, it has the String attributes email_message and notification_message which will return the action formats of email and notification concerning the action string provided. So, we saw how System Messages Schema and Model is created / updated to allow Admin users to read it’s values. Resources Documentation | Marshmallow : https://marshmallow-jsonapi.readthedocs.io/en/latest/ Documentation | Flask Rest JSONAPI : http://flask-rest-jsonapi.readthedocs.io/en/latest/

Continue ReadingAdding System Messages on Open Event Server

Adding Dredd Tests for Image Sizes on Open Event Flask Server

In this blog, we will talk about how to add dredd hooks for testing the API of Event Image Sizes and Speaker Image Sizes in Open Event Server. The focus is on adding the factory class and dredd hooks of these APIs using factory-boy python library and Dredd API testing framework. Factory Creation For the Event and Speaker Image Sizes, we’ll make our factory classes EventImageSizeFactory  and SpeakerImageSizeFactory as follows Now, let’s try to understand this class. In this class, we are writing the sample data two records of ImageSizes Model, these records corresponds to Event and Speaker Image Sizes. First of all, we inherit class factory.alchemy.SQLAlchemyModelFactory to build our sample data which for Image Sizes. Class Meta has model and sqlalchemy_session attributes. Model tells the factory class of to which model this factory class push the data to database and sqlalchemy_session is assigned with the current database session. Next, we add the attributes according to the model and Schema of Image Sizes. Adding Dredd Hooks For the ImageSizes, we’ll make our dredd hooks as follows Now, let’s try to understand these tests. In this tests, we check the API by matching the response after adding a record in these API to one which is present at API blueprint. First of all, we use decorator @hooks.before which means we first add a record in the database and then match the response we get from API say /v1/event-image-sizes with the response mentioned at Image Size > Event Image Size Details > Get Event Image Size Details in API blueprint. We create an instance of EventImageSizeFactory which is a record of model Image Sizes. This record is then returned as a response of API /v1/event-image-sizes and matches with the blueprint at Image Size > Event Image Size Details > Get Event Image Size Details Similarly, we have added other dredd tests for PATCH method as well. So, we saw how factory-boy python library and Dredd API testing framework helped us in testing the REST APIs on Open Event Server. Resources Documentation | Dredd API testing framework: http://dredd.org/en/latest/ Documentation | Factory-boy: http://factoryboy.readthedocs.io/en/latest/

Continue ReadingAdding Dredd Tests for Image Sizes on Open Event Flask Server

Adding Event Roles Permission API on Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues. Event managers can create invitation forms for speakers and build schedules in a drag and drop interface. The event information is stored in a database. The system provides API endpoints to fetch the data, and to modify and update it. The Open Event Server is based on JSON 1.0 Specification and hence build on top of Flask Rest Json API (for building Rest APIs) and Marshmallow (for Schema). In this blog, we will talk about how to add API for accessing and updating the events role permissions on Open Event Server. The focus is on Schema creation and it’s API creation. Schema Creation For the Events Role Permission, we’ll make our Schema as follows   Now, let’s try to understand this Schema. In this feature, we are providing Admin the rights to get and update the permission given to a role concerning a service. First of all, we are provide the four fields in this Schema, which are can_create, can_read, can_update and can_delete which are Boolean. All these fields gives us idea whether a user with a role can create, read, update and delete a service or not respectively in the whole system. Next there is a relationship with role which is one of organizer, coorganizer, track_organizer, moderator, registrar or attendee. Next there is a relationship with service which is one of Track, Microlocation, Session, Speaker or Sponsor. API Creation For the Events Role Permissions, we’ll make our API as follows Now, let’s try to understand this API. In this feature, we are providing Admin the rights to get and update the permission given to a role concerning a service. First of all, there is the need to know that this API has two method GET and PATCH. Decorators shows us that only Admin has permissions to access PATCH method for this API i.e. only Admins can modify the events role permissions . In EventsRolePermissionList, we are inheriting ResourceList from Flask Rest JSONAPI which will allow us to get all the records for the model Permission. In EventsRolePermissionDetail, we are inheriting ResourceDetail from Flask Rest JSONAPI which will allow us to get and update attributes of a record of model Permission. In EventsRolePermissionRelationship, we are inheriting ResourceRelationship from Flask Rest JSONAPI which will allow us to get and update relationships of a record of model Permission. So, we saw how Events Role Permission Schema and API is created to allow users to get it’s values and Admin users to modify it’s attributes and relationships. Resources Documentation | Marshmallow : https://marshmallow-jsonapi.readthedocs.io/en/latest/ Documentation | Flask Rest JSONAPI : http://flask-rest-jsonapi.readthedocs.io/en/latest/

Continue ReadingAdding Event Roles Permission API on Open Event Server

Building the API of Speaker Image Size on Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues.It uses the JSON 1.0 Specification and build on top of Flask Rest Json API (for building Rest APIs) and Marshmallow (for Schema). In this blog, we will talk about how to add API for accessing and updating the Speaker Image Size on Open Event Server. The focus is on its API creation. API Creation For the SpeakerImageSizeDetail, we’ll make our Schema as follows Now, let’s try to understand SpeakerImageSizeDetail. In this feature, we are providing Admin the rights to Get and Update the SpeakerImageSizes kwargs['id'] = 2 states that Image Size model has 2 records and 1st record is used for Event Image Size and 2nd record is used for Speaker Image Size. decorators = (api.has_permission('is_admin', methods="PATCH", id="2"),) states that for Speaker Image Size, Update API is accessible to Admins only. methods = ['GET', 'PATCH'] states that this API provides two methods i.e. GET and PATCH. schema = SpeakerImageSizeSchema states that the schema which is used to return the response is Speaker Image Size Schema. data_layer = {'session': db.session, 'model': ImageSizes} states the session and Model used to fetch the records. Resources Documentation | Marshmallow : https://marshmallow-jsonapi.readthedocs.io/en/latest/ Documentation | Flask Rest JSONAPI : http://flask-rest-jsonapi.readthedocs.io/en/latest/

Continue ReadingBuilding the API of Speaker Image Size on Open Event Server

Attendee Form Builder in Open Event Frontend

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. When buying a ticket we ask for certain information from the buyer. Ideally the event organizer should get to choose what information they want to ask from the buyer. This blog post goes over the implementation of the attendee form builder in the Open Event Frontend. Information to Collect The event organizer can choose what details to ask from the order buyer. In order to specify the choices, we present a table with the entries of allowed fields that the organizer can ask for. Moreover there is an option to mark the field as required and hence making it compulsory for the order buyer to add that information in order to buy the tickets. Route The route is mainly responsible for fetching the required custom forms. async model() { let filterOptions = [{ name : 'form', op : 'eq', val : 'attendee' }]; let data = { event: this.modelFor('events.view') }; data.customForms = await data.event.query('customForms', { filter : filterOptions, sort : 'id', 'page[size]' : 50 }); return data; } If they don’t exist then we create them in afterModel hook. We check if the size of the list of custom forms sent from the server is 3 or not. If it is 3 then we create the additional custom forms for the builder. Upon creating an event, the server automatically creates 3 custom forms for the builder. These 3 forms are firstName, lastName and email. afterModel(data) { /** * Create the additional custom forms if only the compulsory forms exist. */ if (data.customForms.length === 3) { let customForms = A(); for (const customForm of data.customForms ? data.customForms.toArray() : []) { customForms.pushObject(customForm); } const createdCustomForms = this.getCustomAttendeeForm(data.event); for (const customForm of createdCustomForms ? createdCustomForms : []) { customForms.pushObject(customForm); } data.customForms = customForms; } } Complete source code for reference can be found here. Component Template The component template for the form builder is supposed to show the forms and other options to the user in a presentable manner. Due to pre-existing components for handling custom forms, the template is extremely simple. We just loop over the list of custom forms and present the event organizer with a table comprising of the forms. Apart from the forms the organizer can specify the order expiry time. Lastly we present a save button in order to save the changes. <form class="ui form {{if isLoading 'loading'}}" {{action 'submit' data on='submit'}} autocomplete="off"> <h3 class="ui dividing header"> <i class="checkmark box icon"></i> <div class="content"> {{t 'Information to Collect'}} </div> </h3> <div class="ui two column stackable grid"> <div class="column"> <table class="ui selectable celled table"> <thead> <tr> {{#if device.isMobile}} <th class="center aligned"> {{t 'Options'}} </th> {{else}} <th class="right aligned"> {{t 'Option'}} </th> <th class="center aligned"> {{t 'Include'}} </th> <th class="center aligned"> {{t 'Require'}} </th> {{/if}} </tr> </thead> <tbody> {{#each data.customForms as |field|}} <tr class="{{if field.isIncluded 'positive'}}"> <td class="{{if device.isMobile 'center' 'right'}} aligned"> <label class="{{if field.isFixed…

Continue ReadingAttendee Form Builder in Open Event Frontend

Redirecting to Previous Route in Ember

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. In order to make the user experience smooth, we redirect the user to their previous route when they successfully login into their account. This blog explains how we have achieved this functionality in the project. Insight We have two different cases to handle in order to solve this problem: The user was in route A and wanted to move to route B. Here route A doesn’t require authorization and route B requires authorization. In this case, we would like to direct the user to the login route and once they are done, redirect them back to route B. The user was in route A and directly entered the login route using the login button. In this case we want to direct them back to the route A after successful login. We use Ember-simple-auth in order to manage authentication in the project. Not only does it make it easy to manage authentication, it also handles the case 1 for us out of the box. So now the simplified problem is to redirect the user back to the previous route if they entered the login route directly using the web address or the login button. Approach If we can somehow store the previous route visited by a user, then we can easily redirect them back once they are logged in. We will add a custom property in the session service called previousRouteName which will store the URL of the previous route visited by the user. We will make use of the willTransition hook in the application.js file. This hook is called everytime the user transitions from one route to another which makes it suitable for us to update the previousRouteName. actions: { willTransition(transition) { transition.then(() => { let params = this._mergeParams(transition.params); let url; // generate doesn't like empty params. if (isEmpty(params)) { url = transition.router.generate(transition.targetName); } else { url = transition.router.generate(transition.targetName, params); } // Do not save the url of the transition to login route. if (!url.includes('login')) { this.set('session.previousRouteName', url); } }); } } _mergeParams is a helper function which makes use of merge function of the Lodash library. /** * Merge all params into one param. * @param params * @return {*} * @private */ _mergeParams(params) { return merge({}, ...values(params)); }, Now we’re done with saving the URL of the previous route. All that remains is to trigger the redirect once the user has successfully logged in. We will use the sessionAuthenticated hook which is triggered everytime the user logs in. sessionAuthenticated() { if (this.get('session.previousRouteName')) { this.transitionTo(this.get('session.previousRouteName')); } else { this._super(...arguments); } }, If the previous route variable is set, we redirect to it otherwise we can the super method and let Ember-simple-auth handle case 1 mentioned earlier for us. References Ember-simple-auth: https://github.com/simplabs/ember-simple-auth Best way to get the current URL in Ember: https://discuss.emberjs.com/t/what-is-the-best-practice-for-save-the-target-path-to-go-to-it-after-registration/8040/16 Preventing and retrying transitions: https://guides.emberjs.com/release/routing/preventing-and-retrying-transitions/

Continue ReadingRedirecting to Previous Route in Ember

My Tickets in Open Event Frontend

The Open-Event-Frontend allows the event organiser to create tickets for his or her event. Other uses can buy these tickets in order to attend the event. The My tickets section lists all the tickets that have been bought by a user. This blog post explains how it has been implemented in the project. Route The My-Tickets list route has three responsibilities: Showing appropriate title according to the current tab. Setting the filter options according to the tab. Fetching the data from the store according to the filter options. The title of the route is decided by the following snippet: titleToken() { switch (this.get('params.ticket_status')) { case 'upcoming': return this.get('l10n').t('Upcoming'); case 'past': return this.get('l10n').t('Past'); case 'saved': return this.get('l10n').t('Saved'); } }, The second and the third requirement is satisfied inside the model hook. We define the filterOptions according to the current tab and then make the request to fetch the data accordingly. The following code snippet is responsible for this: model(params) { this.set('params', params); let filterOptions = [{ name : 'completed-at', op : 'ne', val : null }]; if (params.ticket_status === 'upcoming') { filterOptions.push( { name : 'event', op : 'has', val : { name : 'starts-at', op : 'ge', val : moment().toISOString() } }); } else if (params.ticket_status === 'past') { filterOptions.push( { name : 'event', op : 'has', val : { name : 'ends-at', op : 'lt', val : moment().toISOString() } } ); } return this.get('authManager.currentUser').query('orders', { include : 'event', filter : filterOptions }); } Template The template of the My tickets list is extremely simple. We simply loop over all the orders and use the order-card component to display each of them. The order-card component is discussed in detail later. If there are no orders under the user, we show the appropriate message. <div class="row"> <div class="sixteen wide column"> {{#if model}} {{#each model as |order|}} {{#order-card order=order}} {{/order-card}} <div class="ui hidden divider"></div> {{/each}} {{else}} <div class="ui disabled header">{{t 'No tickets found'}}</div> {{/if}} </div> </div> Order-card Component The order card component is responsible for handling a single order and showing its details in as a card. In order to decide whether the order is a paid order or not, we have defined a computed property inside the order-card.js file. import Component from '@ember/component'; import { computed } from '@ember/object'; import { isEqual } from '@ember/utils'; export default Component.extend({ isFreeOrder: computed('order', function() { const amount = this.get('order.amount'); return amount === null || isEqual(amount, '0'); }) }); The template for the component contains the event logo aligned to the left in the card. We show the event details such as the name, location and start date on the right. Below the event details we show the order details such as the order amount, currency, the identifier and the date and time on which the order was completed. Below is the full code for reference: <div class="event wide ui grid row"> {{#unless device.isMobile}} <div class="ui card three wide computer six wide tablet column"> <a class="image" href="#"> {{widgets/safe-image src=(if order.event.originalImageUrl order.event.originalImageUrl order.event.originalImageUrl)}} </a> </div> {{/unless}}…

Continue ReadingMy Tickets in Open Event Frontend