Adding revisioning to SQLAlchemy Models

{ Repost from my personal blog @ https://blog.codezero.xyz/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. That is where revisioning comes into picture.

We use SQLAlchemy as the database toolkit and ORM. So, we wanted a versioning tool that would work well with our existing setup. That’s when I came across SQLAlchemy-Continuum – a versioning extension for SQLAlchemy.

Installation

The installation of the module is just like any other python library. (don’t forget to add it to your requirements.txt file, if you have one)

pip install SQLAlchemy-Continuum
Setup

Now, it’s time to enable SQLAlchemy-Continuum for the required models.

Let’s consider an Event model.

import sqlalchemy as sa

class Event(Base):
    __tablename__ = 'events'
    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)

We need to do three things to enable SQLAlchemy-Continuum.

  1. Call make_versioned() before the model(s) is/are defined.
  2. Add __versioned__ = {} to all the models that we want to be versioned
  3. Call configure_mappers from SQLAlchemy after declaring all the models.
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()

SQLAlchemy-Continuum creates two tables:

  1. events_version which stores the version history for the Event model linked to the transaction table via a foreign key
  2. transaction which stores information about each transaction (like the user who performed the transaction, transaction datetime, etc)

SQLAlchemy-Continuum also adds listeners to Event to record all create, update, delete actions.

Usage

All the CRUD (Create, read, update, delete) operations can be done as usual. SQLAlchemy-Continuum takes care of creating a version record for each CUD operation. The versions can be easily accessed using the versions property that is now available in the Event model.

event = Event(name="FOSSASIA 2017", description="Open source conference in asia")
session.add(event)  # Event added to transaction
session.commit() # Transaction comitted and event recored created

# This would have created the first version record which can be accessed
event.versions[0].name == "FOSSASIA 2017"

# Lets make some changes to the recored.
event.name = "FOSSASIA 2016"
session.add(event)
session.commit()

# This would have created the second version record which can be accessed
event.versions[1].name == "FOSSASIA 2016"

# The first version record still remains and can be accessed
event.versions[0].name == "FOSSASIA 2017"

So, that’s how basic versioning can be implemented in SQLAlchemy using SQLAlchemy-Continuum.

Continue ReadingAdding revisioning to SQLAlchemy Models

Building interactive elements with HTML and javascript: Resizing

{ Repost from my personal blog @ https://blog.codezero.xyz/building-interactive-elements-with-html-and-javascript-resizing }

Unlike draggable, HTML/js does not provide us with a direct spec for allowing users to graphically resize HTML DOM elements. So, we’ll be using mouse events and pointer locations to achieve the ability of resizing.

We’ll start with a box div.

<div id="box">  
    <div>Resize me !</div>
</div>  

A little bit of CSS magic to make it look a little bit better and square.

#box {
    position: relative;
    width: 130px;
    height: 130px;
    background-color: #2196F3;
    color: white;
    display:flex;
    justify-content:center;
    align-items:center;
    border-radius: 10px;
}

Now, we need a handle element. The user will be using this handle element to drag and resize the box.

<div id="box">  
    <div>Resize me !</div>
    <div id="handle">
    </div>
</div>  

Now, we just have an invisible div. Let’s give it some color, make it square. We also have to position it at one corner of the box.

#handle {
    background-color: #727272;
    width: 10px;
    height: 10px;
    cursor: se-resize;
    position:absolute;
    right: 0;
    bottom: 0;
}

The parent div#box has the CSS property position: relative and by setting div#handle the property position:absolute, we have the ability to position the handle absolutely with respect to its parent.

Also, note the cursor: se-resize property. This instructs the browser to set the cursor to the resize cursor () when the user is over it.

Now, it’s upto to javascript to take over. :wink:

var resizeHandle = document.getElementById('handle');  
var box = document.getElementById('box');  

For resizing, the user would click on the handle and drag it. So, we need to start resizing the moment the user presses and holds on the handle. Let’s setup a function to listen for the mousedown event.

resizeHandle.addEventListener('mousedown', initialiseResize, false);  

the initialiseResize function should do two things:

  1. Resize the box every time the mouse pointer moves.
  2. Listen for mouseup event so that the event listeners can be removed as soon as the user is done resizing.
function initialiseResize(e) {  
    window.addEventListener('mousemove', startResizing, false);
    window.addEventListener('mouseup', stopResizing, false);
}
function startResizing(e) {  
    // Do resize here
}
function stopResizing(e) {  
    window.removeEventListener('mousemove', startResizing, false);
    window.removeEventListener('mouseup', stopResizing, false);
}

To resize the box according to the user’s mouse pointer movements, we’ll be taking the current x and y coordinates of the mouse pointer (in pixels) and change the box’s height and width accordingly.

function startResizing(e) {  
   box.style.width = (e.clientX) + 'px';
   box.style.height = (e.clientY) + 'px';
}

e.clientX gives the mouse pointer’s X coordinate and e.clientY gives the mouse pointer’s Y coordinate

Now, this works. But this would only work as expected if the box is placed in the top-left corner of the page. We’ll have to compensate for the box’s left and top offsets. (position from the left and top edges of the page)

function startResizing(e) {  
   box.style.width = (e.clientX - box.offsetLeft) + 'px';
   box.style.height = (e.clientY - box.offsetTop) + 'px';
}

There you go :smile: We can now resize the box !

https://jsfiddle.net/niranjan94/w8k1ffju/embedded

Continue ReadingBuilding interactive elements with HTML and javascript: Resizing

Building interactive elements with HTML and javascript: Drag and Drop

{ Repost from my personal blog @ https://blog.codezero.xyz/building-interactive-elements-with-html-and-javascript-drag-and-drop }

Traditionally, all interactions in a website has been mostly via form inputs or clicking on links/button. The introduction of native Drag-and-drop as a part of the HTML5 spec, opened developers to a new way of Graphical input. So, how could this be implemented ?

Making any HTML element draggable is as simple as adding draggable="true" as an attribute.

<div id="a-draggable-div" draggable=true>  
    <h4>Drag me</h4>
</div>  

This will allow the user to drag div#a-draggable-div. Next, we need to designate a dropzone, into which the user can drop the div.

<div id="dropzone" ondragover="onDragOver(event)">  
</div>  
function onDragOver(e) {  
    // This function is called everytime 
    // an element is dragged over div#dropzone
    var dropzone = ev.target;

}

Now, the user will be able to drag the element. But, nothing will happen when the user drops it into the dropzone. We’ll need to define and handle that event. HTML5 provides ondrop attribute to bind to the drop event.

When the user drops the div into the drop zone, we’ll have to move the div from it’s original position into the drop zone. This has to be done in the drop event.

<div id="dropzone"  
ondrop="onDrop(event)"  
ondragover="onDragOver(event)"> </div>  
function onDrop(e) {  
    e.preventDefault();
    var draggableDiv = document.getElementById("a-draggable-div");
    draggableDiv.setAttribute("draggable", "false");
    e.target.appendChild(draggableDiv);
}

So, when the user drops the div into the drop zone, we’re disabling the draggable property of the div and appending it into the drop zone.

This is a very basic drag and drop implementation. It gets the job done. But, HTML5 provides us with more events to make the user’s experience even better 1.

Event Description
drag Fired when an element or text selection is being dragged.
dragend Fired when a drag operation is being ended (for example, by releasing a mouse button or hitting the escape key).
dragenter Fired when a dragged element or text selection enters a valid drop target.
dragexit Fired when an element is no longer the drag operation’s immediate selection target.
dragleave Fired when a dragged element or text selection leaves a valid drop target.
dragover Fired when an element or text selection is being dragged over a valid drop target
dragstart Fired when the user starts dragging an element or text selection.
drop Fired when an element or text selection is dropped on a valid drop target.

With these events a little bit of css magic a more user friendly experience can be created like highlighting the drop zones when the user starts to drag an element or changing the element’s text based on its state.

Demo:

https://jsfiddle.net/niranjan94/tkbcv3md/16/embedded/

External Resources:
Continue ReadingBuilding interactive elements with HTML and javascript: Drag and Drop

Open Event: Planning the Scheduler UI

{ Repost from my personal bloghttps://blog.codezero.xyz/planning-the-scheduler-ui/ }

In the first phase of the GSoC coding period, Saptak Sengupta and myself have been working on the Scheduler UI.

The Scheduler UI would allow the organizers to graphically schedule/manage the sessions in their conference/event.

Event-Organizer by Josh Greco has been a major inspiration for the timeline design. The css styles have been borrowed from that project.

After some research, we have decided to use the interact.js javascript library for implementing drag-drop and resizing functionality to the project and lodash for array/collection manipulations and for some useful utility functions.

The following tasks have been formulated:

  • Drag-and-drop interface to add session blocks into a timeline
  • Resize sessions to change time
  • load live data from the server using the API
  • Handle session clashes within a track properly
  • Add Track button that opens up a modal to add a track.
  • Search option for unscheduled sessions
  • Save each session change/update using the API
  • Option to Export timeline as pdf
  • Option to export timeline/calendar as iCal

An umbrella issue (#349) has been created in the open-event-orga-serverrespository to track the progress. There will be a separate issue created for each task when that task is being worked upon and the same would be referred to in the umbrella issue.

We are targeting GSOC 2016: Milestone 4 (Due by June 12, 2016) to finish the Scheduler UI and we are confident that we’ll be able to reach our target. *fingers-crossed* :sweat_smile:

To know more about the Scheduler UI, read Enhancing the Open Event Server: Scheduler UI.

Continue ReadingOpen Event: Planning the Scheduler UI

Enhancing the Open Event Server: Scheduler UI

{ Repost from my personal blog @ https://blog.codezero.xyz/enhancing-open-event-scheduler-one/ }

The community bonding period went pretty well. Worked on the OpenTechSummit 2016‘s website. Fixed a few issues. Got to know the team. :smile:

Now comes the coding period which started yesterday (23rd May 2016).
In the first phase, I (Niranjan Rajendran) will be primarily working on creating a Scheduler tool for each event. Saptak Sengupta and myself will be working on this.

The Scheduler would allow the organizers to graphically schedule/manage the sessions in their conference/event. The proposed features for the Scheduler are:

  1. Drag-and-drop sessions into tracks on a timeline.
  2. Change the timings of the sessions by resizing the sessions’ element on the timeline.
  3. Create a new event by dragging a time period on the timeline.
  4. Create new tracks.
  5. Switch between timelines of the different days of the event.
  6. Load existing sessions from the database into the timeline.
  7. Print the timeline or convert it into a PDF file.
  8. Export the schedule in different formats such as iCalendar.

The scheduler UI would not be practical on small screens (Mobile phones) and would be hard to use. So, we will be thinking of some alternative – a simpler interface for smaller screens.

Continue ReadingEnhancing the Open Event Server: Scheduler UI