The Open Event Ecosystem

This post contains data collected and compiled from various sources that include (but not limited to) project readme files, my presentation from FOSSASIA 17, Wikipedia, my head. This aims to be a place for any new contributor to know the basics about the entire Open Event Project. This could also help newcomers choose an Open Event sub-project of their liking and start contributing . The Open Event Project offers event managers a platform to organise all kinds of events including concerts, conferences, summits and regular meet-ups. The components support organisers in all stages from event planning to publishing, marketing and ticket sales. Automated web and mobile apps help attendees to get information easily. There are seven components of the project: Open Event Universal Format - A standard JSON Schema specification for data sharing/transfer/import/export between various components of Open Event. Open Event API Server - The core of the project. The API Server and database. Open Event Frontend - The primary frontend for the Open Event API Server where organisers, speakers and attendees can sign-up and perform various functions. Open Event Organiser App - A cross-platform mobile application for Organisers with ticketing, checking and quick management capabilities. Open Event Android application generator - An android application generator that allows event organisers to generate customised android applications for their events. Open Event Web application generator - A web application generator that allows event organisers to generate customised static easily-hostable web pages for their events. Open Event Data scrappers - A scrapper that allows users to scrape events from popular websites such as eventbrite into the Open Event Universal Format for it to be imported into Open Event. Open Event Universal Format A standard JSON Schema specification for data sharing/transfer/import/export between various components of Open Event. Repository: fossasia/open-event. Open Event API Server The core of the project. The API Server and database. Repository: fossasia/open-event-orga-server. The system exposes a RESTful API to fetch and modify data. It also provides endpoints that allow organisers to import and export event data in a standard compressed file format that includes the event data in JSON (Open Event Universal Format) and binary media files like images and audio. The Open Event API Server comprises of: Flask web framework - Flask is a microframework for python to create web applications. Flask also provided us with a Jinja2 templating engine. PostgreSQL - Our database. PostgreSQL is an open-sourced Object-relational database management system (ORDBMS). We use SQLAlchemy ORM to communicate with the database and perform database operations. Celery - Celery is a Distributed Task Queue. It allows us to run time consuming and/or resource intensive tasks in the background (or) on a separate worker server. We use celery to process event import/export tasks to process email send requests. Redis - Redis is an in-memory data structure store. It's generally used for caching and for message brokering b/w different services due it's insanely fast read-write speeds (since it's an in-memory data store). We use it for caching results of time-consuming less volatile database calls…

Continue ReadingThe Open Event Ecosystem

Generating xCal calendar in python

{ Repost from my personal blog @ https://blog.codezero.xyz/generate-xcal-calendar-in-python } "xCal", is an XML format for iCalendar data. The iCalendar data format (RFC5545) is a widely deployed interchange format for calendaring and scheduling data. A Sample xCal document <?xml version="1.0" encoding="utf-8"?> <iCalendar xmlns:xCal="urn:ietf:params:xml:ns:xcal"> <vcalendar> <version>2.0</version> <prodid>-//Pentabarf//Schedule 1.0//EN</prodid> <x-wr-caldesc>FOSDEM 2016</x-wr-caldesc> <x-wr-calname>Schedule for events at FOSDEM 2016</x-wr-calname> <vevent> <method>PUBLISH</method> <uid>123e4567-e89b-12d3-a456-426655440000</uid> <dtstart>20160131T090000</dtstart> <dtend>20160131T091000</dtend> <duration>00:10:00:00</duration> <summary>Introduction to the SDR Track- Speakers, Topics, Algorithm</summary> <description>&lt;p&gt;The opening talk for the SDR devroom at FOSDEM 2016.&lt;/p&gt;</description> <class>PUBLIC</class> <status>CONFIRMED</status> <categories>Software Defined Radio</categories> <url>https:/fosdem.org/2016/schedule/event/sdrintro/</url> <location>AW1.125</location> <attendee>Martin Braun</attendee> </vevent> </vcalendar> </iCalendar> Each event/session will be in a seperate vevent block. Each speaker/attendee of an event/session will be in an attendee block inside a vevent block. Some important elements are: version - Has the version of the iCalendar data prodid - Contains the name of the application/generator that generated this document x-wr-caldesc - A descriptive name for this calendar x-wr-calname - A description of the calendar The structure and keywords used in xCal are the same as those used in the iCal format. To generate the XML document, we'll be using python's ElementTreeXML API that is part of the Python standard library. We'll be using two main classes of the ElementTree API: Element - used to create a standard node. (Used for the root node) SubElement - used to create a sub element and attache the new node to a parent Let's start with the root iCalendar node and set the required attributes. from xml.etree.ElementTree import Element, SubElement, tostring i_calendar_node = Element('iCalendar') i_calendar_node.set('xmlns:xCal', 'urn:ietf:params:xml:ns:xcal') Now, to add the vcalendar node to the iCalendar node. v_calendar_node = SubElement(i_calendar_node, 'vcalendar') Let's add the other aspects of the calendar to the vcalendar node as separate sub nodes. version_node = SubElement(v_calendar_node, 'version') version_node.text = '2.0' prod_id_node = SubElement(v_calendar_node, 'prodid') prod_id_node.text = '-//fossasia//open-event//EN' cal_desc_node = SubElement(v_calendar_node, 'x-wr-caldesc') cal_desc_node.text = "Calendar" cal_name_node = SubElement(v_calendar_node, 'x-wr-calname') cal_name_node.text = "Schedule for sessions" Now, we have added information about our calendar. Now to add the actual events to the calendar. Each event would be a vevent node, a child of vcalendar node. We can loop through all our available event/sessions and add them to the calendar. for session in sessions: v_event_node = SubElement(v_calendar_node, 'vevent') uid_node = SubElement(v_event_node, 'uid') uid_node.text = str(session.id) dtstart_node = SubElement(v_event_node, 'dtstart') dtstart_node.text = session.start_time.isoformat() dtend_node = SubElement(v_event_node, 'dtend') dtend_node.text = tz.localize(session.end_time).isoformat() duration_node = SubElement(v_event_node, 'duration') duration_node.text = "00:30" summary_node = SubElement(v_event_node, 'summary') summary_node.text = session.title description_node = SubElement(v_event_node, 'description') description_node.text = session.short_abstract class_node = SubElement(v_event_node, 'class') class_node.text = 'PUBLIC' status_node = SubElement(v_event_node, 'status') status_node.text = 'CONFIRMED' categories_node = SubElement(v_event_node, 'categories') categories_node.text = session.session_type.name url_node = SubElement(v_event_node, 'url') url_node.text = "https://some.conf/event/" + str(session.id) location_node = SubElement(v_event_node, 'location') location_node.text = session.microlocation.name for speaker in session.speakers: attendee_node = SubElement(v_event_node, 'attendee') attendee_node.text = speaker.name Please note that all the timings in the XML Document must comply with ISO 8601 and must have the date+time+timezone. Example: 2007-04-05T12:30-02:00. We're still not done yet. We now have the XML document as an Element object. But we'll be needing it as a string to either store…

Continue ReadingGenerating xCal calendar in python

Building the Scheduler UI

{ Repost from my personal blog @ https://blog.codezero.xyz/building-the-scheduler-ui } If you hadn't already noticed, Open Event has got a shiny new feature. A graphical and an Interactive scheduler to organize sessions into their respective rooms and timings. As you can see in the above screenshot, we have a timeline on the left. And a lot of session boxes to it's right. All the boxes are re-sizable and drag-drop-able. The columns represent the different rooms (a.k.a micro-locations). The sessions can be dropped into their respective rooms. Above the timeline, is a toolbar that controls the date. The timeline can be changed for each date by clicking on the respective date button. The Clear overlaps button would automatically check the timeline and remove any sessions that are overlapping each other. The Removed sessions will be moved to the unscheduled sessions pane at the left. The Add new micro-location button can be used to instantly add a new room. A modal dialog would open and the micro-location will be instantly added to the timeline once saved. The Export as iCal allows the organizer to export all the sessions of that event in the popular iCalendar format which can then be imported into various calendar applications. The Export as PNG saves the entire timeline as a PNG image file. Which can then be printed by the organizers or circulated via other means if necessary. Core Dependencies The scheduler makes use of some javascript libraries for the implementation of most of the core functionality Interact.js - For drag-and-drop and resizing Lodash - For array/object manipulations and object cloning jQuery - For DOM Manipulation Moment.js - For date time parsing and calculation Swagger JS - For communicating with our API that is documented according to the swagger specs. Retrieving data via the API The swagger js client is used to obtain the sessions data using the API. The client is asynchronously initialized on page load. The client can be accessed from anywhere using the javascript function initializeSwaggerClient. The swagger initialization function accepts a callback which is called if the client is initialized. If the client is not initialized, the callback is called after that. var swaggerConfigUrl = window.location.protocol + "//" + window.location.host + "/api/v2/swagger.json"; window.swagger_loaded = false; function initializeSwaggerClient(callback) { if (!window.swagger_loaded) { window.api = new SwaggerClient({ url: swaggerConfigUrl, success: function () { window.swagger_loaded = true; if (callback) { callback(); } } }); } else { if (callback) { callback(); } } } For getting all the sessions of an event, we can do, initializeSwaggerClient(function () { api.sessions.get_session_list({event_id: eventId}, function (sessionData) { var sessions = sessionData.obj; // Here we have an array of session objects }); }); In a similar fashion, all the micro-locations of an event can also be loaded. Processing the sessions and micro-locations Each session object is looped through, it's start time and end time are parsed into moment objects, duration is calculated, and it's distance from the top in the timeline is calculated in pixels. The new object with additional information, is stored…

Continue ReadingBuilding the Scheduler UI

Accepting Stripe payments on behalf of a third-party

{ Repost from my personal blog @ https://blog.codezero.xyz/accepting-stripe-payments-on-behalf-of-a-third-party } In Open Event, we allow the organizer of each event to link their Stripe account, so that all ticket payments go directly into their account. To make it simpler for the organizer to setup the link, we have a Connect with stripe button on the event creation form. Clicking on the button, the organizer is greeted with a signup flow similar to Login with Facebook or any other social login. Through this process, we're able to securely and easily obtain the credentials required to accept payments on behalf of the organizer. For this very purpose, stripe provides us with an OAuth interface called as Stripe Connect. Stripe Connect allows us to connect and interact with other stripe accounts through an API. We'll be using Python's requests library for making all the HTTP Requests to the API. You will be needing a stripe account for this. Registering your platform Goto https://dashboard.stripe.com/account/applications/settings and register your platform by filling in all the details. This will provide you with a Client ID that we'll be using when redirect users for OAuth Signup. The OAuth Flow The OAuth flow is similar to most platforms. The user is redirected to an authorization page where they login to their stripe account and authorize your app to access their account The user is then redirected back to a callback URL with an Authorization code The server makes a request to the Token API with the Authorization code to retrieve the access_token, refresh_token and other credentials. Implementing the flow Redirect the user to the Authorization URL. https://connect.stripe.com/oauth/authorize?response_type=code&client_id=ca_8x1ebxrl8eOwOSqRTVLUJkWtcfP92YJE&scope=read_write&redirect_uri=http://localhost/stripe/callback The authorization url accepts the following parameters. client_id - The client ID acquired when registering your platform.required. response_type - Response type. The value is always code. required. redirect_uri - The URL to redirect the customer to after authorization. scope - Can be read_write or read_only. The default is read_only. For analytics purposes, read_only is appropriate; To perform charges on behalf of the connected user, We will need to request read_write scope instead. The user will be taken to stripe authorization page, where the user can login to an existing account or create a new account without breaking the flow. Once the user has authorized the application, he/she is taken back to the Callback URL with the result. Requesting the access token with the authorization code The user is redirected back to the callback URL. If the authorization failed, the callback URL has a query string parameter error with the error name and a parameter error_description with the description of the error. If the authorization was a success, the callback URL has the authorization code in the code query string parameter. import requests data = { 'client_secret': 'CLIENT_SECRET', 'code': 'AUTHORIZATION_CODE', 'grant_type': 'authorization_code' } response = requests.post('https://connect.stripe.com/oauth/token', data=data) The client_secret is also obtained when registering your platform. The codeparameter is the authorization code. On making this request, a json response will be returned. If the request was a success, the following response will be obtained. { "token_type": "bearer", "stripe_publishable_key":…

Continue ReadingAccepting Stripe payments on behalf of a third-party

PayPal Express Checkout in Python

As per the PayPal documentation ... Express Checkout is a fast, easy way for buyers to pay with PayPal. Express Checkout eliminates one of the major causes of checkout abandonment by giving buyers all the transaction details at once, including order details, shipping options, insurance choices, and tax totals. The basic steps for using express checkout to receive one-time payments are: Getting the PayPal API credentials. Making a request to the API with the transaction details to get a token Using the token to send the users to the PayPal payment page Capturing the payment and charging the user after the user completes the payment at PayPal. We will be using PayPal's Classic NVP (Name-value pair) API for implementing this. Getting PayPal API Credentials To begin with, we'll need API Credentials. We'll be using the Signature API credentials which consists of API Username API Password Signature To obtain these, you can follow the steps at Creating and managing NVP/SOAP API credentials - PayPal Developer. You'll be getting two sets of credentials. Sandbox and Live. We'll just stick to the Sandbox for now. Now, we need sandbox test accounts for making and receiving payments. Head over to Creating Sandbox Test Accounts - PayPal Developer and create two sandbox test accounts. One would be the facilitator and one would be the buyer. PayPal NVP Servers All the API actions will take place by making a request to the PayPal server. PayPal has 4 different NVP servers for 4 different purposes. https://api-3t.sandbox.paypal.com/nvp - Sandbox "testing" server for use with API signature credentials. https://api-3t.paypal.com/nvp- PayPal "live" production server for use with API signature credentials. https://api.sandbox.paypal.com/nvp - Sandbox "testing" server for use with API certificate credentials. https://api.paypal.com/nvp - PayPal "live" production server for use with API certificate credentials. We'll be using the Sandbox "testing" server for use with API signature credentials. Creating a transaction and obtaining the token To create a transaction, we'll need to make a request with all the transaction details. We can use Python requests library to easily make the requests. All requests are POST. We'll be calling the SetExpressCheckout method of the NVP API to obtain the token. import requests import urlparse data = { 'USER': credentials['USER'], 'PWD': credentials['PWD'], 'SIGNATURE': credentials['SIGNATURE'], 'SUBJECT': credentials['FACILITATOR_EMAIL'], 'METHOD': 'SetExpressCheckout', 'VERSION': 93, 'PAYMENTREQUEST_0_PAYMENTACTION': 'SALE', 'PAYMENTREQUEST_0_AMT': 100, 'PAYMENTREQUEST_0_CURRENCYCODE': 'USD', 'RETURNURL': 'http://localhost:5000/paypal/return/', 'CANCELURL': 'http://localhost:5000/paypal/cancel/' } response = requests.post('https://api-3t.sandbox.paypal.com/nvp', data=data) token = dict(urlparse.parse_qsl(response.text))['TOKEN'] Here, USER represents your Sandbox API Username. PWD represents your Sanbox API Password. SIGNATURE represents your Sandbox Signature. SUBJECT represents the facilitator's email ID. PAYMENTREQUEST_0_AMT is the total transaction amount. PAYMENTREQUEST_0_CURRENCYCODE is the 3 digit ISO 4217 Currency code. RETURNURL is where the user will be sent to after the transaction CANCELURL is where the user will be sent to if he/she cancels the transaction. A URL-Encoded, Name-value pair response would be obtained. We can decode that into a dict by using Python's urlparse modules. From the response, we're extracting the TOKEN which we will use to generate the payment URL for the user. This token…

Continue ReadingPayPal Express Checkout in Python

Integrating Stripe in the Flask web framework

{ Repost from my personal blog @ https://blog.codezero.xyz/integrating-stripe-in-flask } Stripe is a developer and a user-friendly payment infrastructure provider. Stripe provides easy to use SDKs in different programming languages allowing us to easily collect payments on our website or mobile application. Flask is a web microframework for Python based on Werkzeug, Jinja 2. Flask makes building web applications in python a breeze. Make sure you have your Flask app ready. Let's start with installing the required dependency. The Stripe python SDK. You can get it by running. pip install stripe Don't forget to add the same in your requirements.txt. (if you have one that is.) Now, head over to Stripe: Register and create a new Stripe account to get your test keys. If you don't wish to create an account at this time, you can use the following test keys, but you'll not be able to see the payments in the stripe dashboard. Publishable Key: pk_test_6pRNASCoBOKtIshFeQd4XMUh Secret Key: sk_test_BQokikJOvBiI2HlWgH4olfQ2 We'll need to set the secret key in the SDK. import stripe STRIPE_PUBLISHABLE_KEY = 'pk_test_6pRNASCoBOKtIshFeQd4XMUh' STRIPE_SECRET_KEY = 'sk_test_BQokikJOvBiI2HlWgH4olfQ2' stripe.api_key = STRIPE_SECRET_KEY Let's create a page with a form for us to handle the Stripe payment. <!DOCTYPE html> <html> <head> <title>Pay now</title> </head> <body> <h4>Pay $250.00 by clicking on the button below.</h4> <form action="/payment" method="POST"> <script src="https://checkout.stripe.com/checkout.js" class="stripe-button" data-key="pk_test_6pRNASCoBOKtIshFeQd4XMUh" data-description="A payment for the Hello World project" data-name="HelloWorld.com" data-image="/images/logo/hw_project.png" data-amount="25000"></script> </form> </body> </html> We're using Stripe's Checkout library to get the payment details from the user and process. Also, keep in mind that the checkout library has to be loaded directly from https://checkout.stripe.com/checkout.js. Downloading it and serving locally will not work. The script tag, accepts a lot of parameters. A few important ones are, data-key - The Publishable Key. data-amount - The amount to be charged to the user in the lowest denomination of the currency. (For example, 5 USD should be represented as 500 cents) data-name - The name of your site or company that will be displayed to the user. data-image - The path to an image file (maybe a logo) that you'd like to be displayed to the user. More configuration options can be seen at Stripe: Detailed Checkout Guide. This script would automatically create a Pay with Card button which would open the stripe Checkout lightbox when clicked by the user. Once the payment process is completed the following parameters are submitted to the form's action endpoint (the form inside which this script is located), along with any other elements that were in the form. stripeToken - The ID of the token representing the payment details stripeEmail - The email address the user entered during the Checkout process Along with the Billing address details and Shipping address details if applicable and enabled We'll need to write a Flask method to handle the input that were submitted by Stripe to proceed with the transaction and charge the user. Let's add a new Flask route to respond when submitting the form. @app.route('/payment', methods=['POST']) def payment_proceed(): # Amount in cents amount = 25000…

Continue ReadingIntegrating Stripe in the Flask web framework

Building a logger interface for FlightGear using Python: Part One

{ Repost from my personal blog @ https://blog.codezero.xyz/python-logger-interface-for-flightgear-part-one/ } The FlightGear flight simulator is an open-source, multi-platform, cooperative flight simulator developed as a part of the FlightGear project. I have been using this Flight simulator for a year for Virtual Flight testing, running simulations and measuring flight parameters during various types of maneuvers. I have noticed that, logging the data, (figuring out how to log in the first place) has been quite difficult for users with less technical knowledge in such softwares. Also, the Property Tree of FlightGear is pretty extensive making it difficult to properly traverse the huge tree to get the parameters that are actually required. That's when I got the idea of making a simple, easy to use, user friendly logging interface for FlightGear. I gave it a name 'FlightGear Command Center' and the project was born at github.com/niranjan94/flightgear-cc. After 44 commits, this is what I have now. 1. A simple dashboard to connect to FlightGear, open FlightGear with a default plane, Getting individual parameter values or to log a lot of parameters continuously 2. An interface to choose the parameters to log and the interval The User interface is a web application written in HTML/javascript. The Web application communicates with a python bridge using WebSockets. The python bridge communicates with FlightGear via telnet. The data is logged to a csv file continuously (until the user presses stop) by the bridge once the web application requests it. The interface with FlightGear FlightGear has an internal "telnet" command server which provides us "remote shell" into the running FlightGear process which we can exploit to interactively view or modify any property/variable of the simulation. FlightGear can be instructed to start the server and listen for commands by passing the --telnet=socket,out,60,localhost,5555,udp command line argument while starting FlightGear. (The argument is of format --telnet=medium,direction,speed_in_hertz,localhost,PORT,style.) Communication with that server can be done using any simple telnet interface. But FlightGear also provides us with a small wrapper class that makes retrieving and setting properties using the telnet server even more easier. The wrapper can be obtained from the official repository atsourceforge.net/p/flightgear/flightgear/ci/master/tree/scripts/python/FlightGear.py Using the wrapper is straightforward. Initialize an instance of the class with the hostname and port. The class will then make a connection to the telnet server. from FlightGear import FlightGear flightgear_server = 'localhost' flightgear_server_port = 5555 fg = FlightGear(flightgear_server, flightgear_server_port) The wrapper makes use of python's magic methods __setitem__ and __getitem__ to make it easy for us to read or manipulate the property tree. For example, getting the current altitude of the airplane is as easy as print fg['/position[0]/altitude-ft'] and setting the altitude is as simple as fg['/position[0]/altitude-ft'] = 345.2 But the important thing here is, knowing the path to the data you want in the FlightGear property tree. Most of the commonly used properties are available over at Aircraft properties reference - FlightGear Wiki. Now that we have basic interface between python and FlightGear in place, the next step would be to setup a link between the user interface (a small…

Continue ReadingBuilding a logger interface for FlightGear using Python: Part One

Building interactive elements with HTML and javascript: Interact.js + resizing

{ Repost from my personal blog @ https://blog.codezero.xyz/building-interactive-elements-with-html-and-javascript-interact-js-resizing/ } In a few of the past blog posts, we saw about implementing resizing with HTML and javascript. The functionality was pretty basic with simple resizing. In the last blog post we saw about interact.js. 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. 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 resizing Let's create a simple box using HTML. We'll add a class called resizable to it so that we can reference it to initialize Interact.js <div class="resizable"> Use right/bottom edge to resize </div> We need to create an interact instance. Once the instance is created, we have to call the resizable method on it to add resize support to the div. interact('.resizable') .resizable({ edges: { right: true, bottom: true } }) .on('resizemove', function (event) { }); Inside the resizable method, we can pass configuration options. The edgesconfig key allows us to specify on which all edges, resizing should be allowed. Right now, we have allowed on the right and bottom edges. Similarly we can have resizing support in the top and left edges too. The resizemove event is triggered by interact every time the user tries to resize the div. From the event, we can get the box that is being resized, (i.e) the target by accessing event.target. The event object also provides us event.rect.width and event.rect.height which is the width and height of the div after resizing. We'll not set this as the width of the div so that, the user is able to see the width change. var target = event.target; // update the element's style target.style.width = event.rect.width + 'px'; target.style.height = event.rect.height + 'px'; We can also instruct Interact.js to preserve the aspect ratio of the box by adding an option preserveAspectRatio: true to the configuration object passed to resizable method during initialization. JavaScript interact('.resizable') .resizable({ edges: { right: true, bottom: true } }) .on('resizemove', function (event) { var target = event.target; // update the element's style target.style.width = event.rect.width + 'px'; target.style.height = event.rect.height + 'px'; }); Resizing and drag-drop (with Interact.js) were used to create the Scheduler tool at Open Event. The tool allows event/track organizers to easily arrange the sessions into their respective rooms by drag-drop and also to easily change the timings of the events by resizing the event block. The entire source code of the scheduler can be viewed at app/static/js/admin/event/scheduler.js in the Open Event Organizer server's GitHub repository. Demo: https://jsfiddle.net/xdfocdty/

Continue ReadingBuilding interactive elements with HTML and javascript: Interact.js + resizing

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

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