Google Maps Api

OpenEvent uses it everywhere. Let me explain it. The first problem that we faced was user current location. We wanted to get location based on geolocation method then display this results on the map. To get geolocation we use HTML5. Take a look on geolocate() function   function geolocate() {        if (navigator.geolocation) {            navigator.geolocation.getCurrentPosition(function (position) {            }        }    }   From variable position you can get longitude and latitude params. These values allow us to move marker on the map on right position and get the name of user current location. Based on these data we are able to find the closest events and display it in a distance order. To get information about city or country location you have to execute a simple GET request to google MAPS. In that case you need:   curl http://maps.googleapis.com/maps/api/geocode/json?latlng=17.0112,15.06   above result returns json file where you can find name of location: Nguigmi, Niger   Then, we faced a new challenge- we had to choose which map would be better for OpenEvent - Open Street Map or Google Maps. Finally we have chosen google maps because it wa more comfortable for our team.   OpenEvent simple searching engine is based on latitude and longitude params. So we transform all requests which contain city or country names to longitude and latitude params using Google Api. It allows us to avoid having problems with different locations’ names which occur in different nationalities.  

Continue ReadingGoogle Maps Api

Adding Client Side validation to Login and Registration Forms

Its very important to have a client side validation apart from a server side validation. The server side validation only helps the developers but not the clients. Thus it was necessary to add a client side validation to the Login page and its other components so that the users  would be comfortable in this. I had never before done this and was looking at how to achieve this using jQuery or JavaScript when I cam to know that we were already using an amazing validation tool : Bootstrap Validator It just involves wrapping the form in the html with the validator plugin and all the checks are automatically carried out by it.   As you can see in the above image, we have just added a data-toggle="validator" line to the form which automatically wraps the form with the plugin. The above form is the Create New Password form which checks whether the new password and the password entered again are matching or not. If not then the line , data-match="#new_password" checks it with the password in the new_password field and gives an error on the page to the client defined by the following, data-error="Passwords do not match Thus adding such checks to the form becomes very simple rather than using jQuery for it. Similarly it was important to add validation to the Register page. <input type="email" name="email" class="form-control" id="email" placeholder="Email" data-remote="{{ url_for('admin.check_duplicate_email') }}" data-remote-error="Email Address already exists" required=""> This is the validation for the email field. Apart from checking whether the text entered by the user is an email id or not it was also important to check whether the email entered by the user exists in the database or not. data-remote="{{ url_for('admin.check_duplicate_email') This line calls a view function to check whether the email entered by the user is duplicate or unique. Here is the function This function takes the email value from the request.args and then performs a simple check in the db to check for duplicate email. If the user doesnt exist then the validator receives a simple string "200 OK". If the error is 404 then it gives the error defined by, data-remote-error="Email Address already exists" However this error only for the data-remote part. If the error is something else then it is handled by , class="help-block with-errors" Thus without the hassle of using Ajax and JQuery we can easily add validation to the forms using Bootstrap Validator.

Continue ReadingAdding Client Side validation to Login and Registration Forms

Update Fields with Array Input

Screenshot from 2016-07-15 17:57:58.png

There are certain fields in form where instead of a single value, we need an array of values to be stored. This are fields under the same category but having multiple elements, e.g., Tracks, Session Types, Microlocations, Sponsors, Social Links and similar such fields. Now as we know the way of doing this using simple html is provide the <input> tag with property “name” as “<field_name>[]”. So suppose we want to save the names of the mutliple tracks, we will have something like this
Screenshot from 2016-07-15 18:02:09.png

But the problem begins when you want to update name of a particular element (in this case Track). How to do it? Should we delete and create entries again? That doesn’t sound too good, does it? So what should we do? Let’s see….

(more…)

Continue ReadingUpdate Fields with Array Input

Permission Decorators

A follow-up to one of my previous posts: Organizer Server Permissions System. I recently had a requirement to create permission decorators for use in our REST APIs. There had to be separate decorators for Event and Services. Event Permission Decorators Understanding Event permissions is simple: Any user can create an event. But access to an event is restricted to users that have Event specific Roles (e.g. Organizer, Co-organizer, etc) for that event. The creator of an event is its Organizer, so he immediately gets access to that event. You can read about these roles in the aforementioned post. So for Events, create operation does not require any permissions, but read/update/delete operations needed a decorator. This decorator would restrict access to users with event roles. def can_access(func): """Check if User can Read/Update/Delete an Event. This is done by checking if the User has a Role in an Event. """ @wraps(func) def wrapper(*args, **kwargs): user = UserModel.query.get(login.current_user.id) event_id = kwargs.get('event_id') if not event_id: raise ServerError() # Check if event exists get_object_or_404(EventModel, event_id) if user.has_role(event_id): return func(*args, **kwargs) else: raise PermissionDeniedError() return wrapper The has_role(event_id) method of the User class determines if the user has a Role in an event. # User Model class def has_role(self, event_id): """Checks if user has any of the Roles at an Event. """ uer = UsersEventsRoles.query.filter_by(user=self, event_id=event_id).first() if uer is None: return False else: return True Reading one particular event (/events/:id [GET]) can be restricted to users, but a GET request to fetch all the events (/events [GET]) should only be available to staff (Admin and Super Admin). So a separate decorator to restrict access to Staff members was needed. def staff_only(func): @wraps(func) def wrapper(*args, **kwargs): user = UserModel.query.get(login.current_user.id) if user.is_staff: return func(*args, **kwargs) else: raise PermissionDeniedError() return wrapper Service Permission Decorators Service Permissions for a user are defined using Event Roles. What Role a user has in an Event determines what Services he has access to in that Event. Access here means permission to Create, Read, Update and Delete services. The User model class has four methods to determine the permissions for a Service in an event. user.can_create(service, event_id) user.can_read(service, event_id) user.can_update(service, event_id) user.can_delete(service, event_id) So four decorators were needed to put alongside POST, GET, PUT and DELETE method handlers. I've pasted snippet for the can_update decorator. The rest are similar but with their respective permission methods for User class object. def can_update(DAO): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): user = UserModel.query.get(login.current_user.id) event_id = kwargs.get('event_id') if not event_id: raise ServerError() # Check if event exists get_object_or_404(EventModel, event_id) service_class = DAO.model if user.can_update(service_class, event_id): return func(*args, **kwargs) else: raise PermissionDeniedError() return wrapper return decorator This decorator is a little different than can_access event decorator in a way that it takes an argument, DAO. DAO is Data Access Object. A DAO includes a database Model and methods to create, read, update and delete object of that model. The db model for a DAO would be the Service class for the object. You can look that the model class…

Continue ReadingPermission Decorators

Building interactive elements with HTML and javascript: Interact.js + drag-drop

{ Repost from my personal blog @ https://blog.codezero.xyz/building-interactive-elements-with-html-and-javascript-interact-js-drag-drop } In a few of the past blog posts, we saw about implementing drag-drop andresizing with HTML and javascript. The functionality was pretty basic with a simple drag-and-drop and resizing. That is where, a javascript library called as interact.js comes in. interact.js is a lightweight, standalone JavaScript module for handling single-pointer and multi-touch drags and gestures with powerful features including inertia and snapping. With Interact.js, building interactive elements is like a eating a piece of your favorite cake - that easy ! Getting started with Interact.js You have multiple option to include the library in your project. You can use bower to install (bower install interact) (or) npm (npm install interact.js) (or) You could directly include the library from a CDN (https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.6/interact.min.js). Implementing a simple draggable Let's start with some basic markup. We'll be using the draggable class to enable interact.js on this element. <div id="box-one" class="draggable"> <p> I am the first Box </p> </div> <div id="box-two" class="draggable"> <p> I am the second Box </p> </div> The first step in using interact.js is to create an interact instance. Which you can create by using interact('<the selector>'). Once the instance is created, you'll have to call the draggable method on it to enable drag. Draggable accepts a javascript object with some configuration options and some pretty useful callbacks. // target elements with the "draggable" class interact('.draggable') .draggable({ // enable inertial throwing inertia: true, // keep the element within the area of it's parent restrict: { restriction: "parent", endOnly: true, elementRect: { top: 0, left: 0, bottom: 1, right: 1 } }, // enable autoScroll autoScroll: true, // call this function on every dragmove event onmove: dragMoveListener, }); function dragMoveListener (event) { var target = event.target, // keep the dragged position in the data-x/data-y attributes x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx, y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy; // translate the element target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)'; // update the posiion attributes target.setAttribute('data-x', x); target.setAttribute('data-y', y); } Here we use the onmove event to move the box according to the dx and dyprovided by interact when the element is dragged. Implementing a simple drag-drop Now to the above draggable, we'll add a drop zone into which the two draggable boxes can be dropped. <div id="dropzone" class="dropzone">You can drop the boxes here</div> Similar to a draggable, we first create an interact instance. Then we call the dropzone method on to tell interact that, that div is to be considered as a dropzone. The dropzone method accepts a json object with configuration options and callbacks. // enable draggables to be dropped into this interact('.dropzone').dropzone({ // Require a 50% element overlap for a drop to be possible overlap: 0.50, // listen for drop related events: ondropactivate: function (event) { // add active dropzone feedback event.target.classList.add('drop-active'); }, ondragenter: function (event) { var draggableElement = event.relatedTarget, dropzoneElement = event.target; // feedback the possibility of a drop dropzoneElement.classList.add('drop-target'); }, ondragleave: function…

Continue ReadingBuilding interactive elements with HTML and javascript: Interact.js + drag-drop

Shell hacks

Custom Shell Working with database models needs a lot of use of the flask shell. You can access it with: python manage.py shell The default shell is quite unintuitive. It doesn't pretty print the outputs and has no support for auto-completion. I've installed IPython that takes care of that. But still working with models means writing a lot of import statements. Plus if there was some change in the code related to the app, then the shell had to restarted again so the changes could be loaded. Meaning writing the import statements again. We were using Flask-Script and I wanted to run a custom shell that imports all the required modules, models and helper functions, so I don't have to write them over and over. Some of them were as long as: from open_event.models.users_events_roles import UsersEventsRoles So I created a custom shell command with different context that overrides the default shell provided by the Flask-Script Manager. It was pretty easy with Flask-Script. One thing I had to keep in mind is that it needed to be in a different file than manage.py. Since manage.py was committed to source repo, changes to it would be tracked. So I needed a different file that could be excluded from the source repo. I created an smg.py that imported the Manager from the open_event module and overrides the shell command. from flask_script import Shell from open_event import manager from open_event.models.user import User from open_event.models.event import Event from open_event.helpers.data import save_to_db, delete_from_db def _make_context(): return dict( uq=User.query, eq=Event.query, su=User.query.get(1), User=User, Event=Event, savetodb=save_to_db, deletefromdb=delete_from_db ) if __name__ == "__main__": manager.add_command('shell', Shell(make_context=_make_context)) manager.run() Place this smg.py file in the same directory as manage.py, so you can access it with python smg.py shell. The code is pretty simple to understand. We import the Shell class from flask_script, create its object with our context and then add it to the manager as a command. _make_context contains what I usually like to have in my shell. It must always return a dictionary. The keys of this dictionary would be available as statements inside the shell with their values specified here. This helps a lot. Most of the time I would be working with the super_admin user, and I would need its User object from time to time. The super_admin user is always going to be the first user (User object with id 1). So instead of from open_event.models.user import User; su = User.query.get(1) I could just use the su variable. Models like User and Event are also readily available (so are their base queries). This is the default context that I always keep, but many times you need more models than the ones specified here. Like when I was working with the permissions system. from open_event.models.users_events_roles import UsersEventsRoles from open_event.models.service import Service from open_event.models.role import Role def _make_context(): return dict( # usual stuff UER=UsersEventsRoles, Service=Service, Role=Role ) You can even write a script that fetches all the database models (instance of sqlalchemy Model class) and then add them to the _make_context…

Continue ReadingShell hacks

Responsive UI: Testing & Reporting

Few days back I wrote a blog about how to make a website responsive. But how do you exactly check for responsiveness of a website? Well, you can do it using your browser itself. Both Mozilla Firefox and Google Chrome provides responsive mode for testing responsiveness of websites for standard resolutions and also to drag and check for any resolution. Open Event Organizer’s Server has quite some responsive issues, so I would tell about reporting the issues as well.

(more…)

Continue ReadingResponsive UI: Testing & Reporting

Implementing revisioning feature in Open Event

{ Repost from my personal blog @ https://blog.codezero.xyz/implementing-revisioning-feature-in-open-event } As I said in my previous blog post about Adding revisioning to SQLAlchemy Models, In an application like Open Event, where a single piece of information can be edited by multiple users, it's always good to know who changed what. One should also be able to revert to a previous version if needed. Let's have a quick run through on how we can enable SQLAlchemy-Continuum on our project. Install the library SQLAlchemy-Continuum with pip Add __versioned__ = {} to all the models that need to be versioned. Call make_versioned() before the models are defined Call configure_mappers from SQLAlchemy after declaring all the models. Example: import sqlalchemy as sa from sqlalchemy_continuum import make_versioned # Must be called before defining all the models make_versioned() class Event(Base): __tablename__ = 'events' __versioned__ = {} # Must be added to all models that are to be versioned id = sa.Column(sa.Integer, primary_key=True, autoincrement=True) name = sa.Column(sa.String) start_time = sa.Column(db.DateTime, nullable=False) end_time = sa.Column(db.DateTime, nullable=False) description = db.Column(db.Text) schedule_published_on = db.Column(db.DateTime) # Must be called after defining all the models sa.orm.configure_mappers() We have SQLAlchemy-Continuum enabled now. You can do all the read/write operations as usual. (No change there). Now, for the part where we give the users an option to view/restore revisions. The inspiration for this, comes from wordpress's wonderful revisioning functionality. The layout is well designed. The differences are shown in an easy-to-read form. The slider on top makes it intuitive to move b/w revisions. We have a Restore this Revision button on the top-right to switch to that revision. A similar layout is what we would like to achieve in Open Event. A slider to switch b/w sessions A pop-over infobox on the slider to show who made that change A button to switch to that selected revision. The colored-differences shown in side-by-side manner. To make all this a bit easier, SQLAlchemy-Continuum provides us with some nifty methods. count_versions is a method that allows us to know the number of revisions a record has. event = session.query(Event).get(1) count = count_versions(event) # number of versions of that event Next one is pretty cool. All the version objects have a property called as changeset which holds a dict of changed fields in that version. event = Event(name=u'FOSSASIA 2016', description=u'FOSS Conference in Asia') session.add(article) session.commit(article) version = event.versions[0] # first version version.changeset # { # 'id': [None, 1], # 'name': [None, u'FOSSASIA 2016'], # 'description': [None, u'FOSS Conference in Asia'] # } event.name = u'FOSSASIA 2017' session.commit() version = article.versions[1] # second version version.changeset # { # 'name': [u'FOSSASIA 2016', u'FOSSASIA 2017'], # } As you can see, dict holds the fields that changed and the content the changed (before and after). And this is what we'll be using for generating those pretty diffs that the guys and girls over at wordpress.com have done. And for this we'll be using two things. A library named diff-match-patch. It is a library from Google which offers robust algorithms to perform the…

Continue ReadingImplementing revisioning feature in Open Event

Sending Email using Sendgrid API

sendgrid1

One of the important features while creating server side code for some website/ web application is sending emails. But how do we send emails. There are different ways and packages using which you can setup SMTP ports and send emails. So why specifically sendgrid? Because along with SMTP relay, sendgrid also allows you to send emails using its Web API which makes work much easier. Here, we will discuss about using Web API.

(more…)

Continue ReadingSending Email using Sendgrid API

Organizer Server Permissions System

This post discusses about the Organizer Server Permissions System and how it has been implemented using database models. The Organizer Server Permissions System includes Roles, and Services that these roles can access. Roles can broadly be classified into Event-specific Roles and System-wide Roles. System-Wide Roles System-wide roles can be considered a part of the staff maintaining the platform. We define two such roles: Admin and Super Admin. The Super Admin is the highest level user with permissions to access system logs, manage event-specific roles, etc. System-wide roles are the easiest to implement. Since they're directly related to a user we can add them as class variables in the User models. class User(db.Model): # other stuff is_admin = db.Column(db.Boolean, default=False) is_super_admin = db.Column(db.Boolean, default=False) @property def is_staff(self): return self.is_admin or self.is_super_admin Staff groups Admin and Super Admin roles. So to check if a user is a part of the staff (an admin or a super admin), the is_staff property can directly be used. user.is_staff Event-Specific Roles An Event itself can contain many entities like Tracks, Sponsors, Sessions, etc. Our goal was to define permissions for Roles to access these entities. We grouped these entities and put them under "Services". Services are nothing but database models associated with an event, that need to have restricted access for the Roles. We define the following Services for an Event: Track Session Speaker Sponsor Microlocation Each of these services can either be created, read, updated or deleted. And depending on the Role a user has been assigned for a particular event, he or she can perform such operations. There are four Event-Specific Roles: Organizer Co-organizer Track Organizer Moderator As soon as the user creates an event, he is assigned the role of an Organizer, giving him access to all the services for that event. An Organizer can perform any operation on any of the services. A Co-organizer also has access to all the services but can only update them. A Track Organizer can just read and update already created Tracks. The Moderator can only read Tracks. Although the initial distribution of permissions is kept as above, the Super Admin can (has permissions to) edit them later. To implement permissions for Event specific roles, three new database models were required: Role, Service and Permission. Role and Service would contain the above mentioned Roles and Services respectively. Permission would contain a Role column, a Service column and four other columns specifying what operation (create/read/update/delete) that Role is allowed to perform on the Service. The final objective was to define these methods for the User class: user.can_create(service, event_id) user.can_read(service, event_id) user.can_update(service, event_id) user.can_delete(service, event_id) Before this we needed a table specifying what Event Roles have been created for an event, and which users have been assigned these roles. The `UsersEventsRoles` model maintained this relationship. We also needed to check if a user has been assigned a particular role for an event. For this I created a method for each of the roles. # Event-specific Roles ORGANIZER = 'organizer'…

Continue ReadingOrganizer Server Permissions System