Creating a Widget for your Android App

Having a widget for your app, not only helps it to stand out among its alternatives but also provides user information on the go without having to open the app. Keeping this thought in mind, I decided to make a widget for my GSoC project. Let's go through the steps involved. Step 1: Creating a new widget from Android Studio. Open up your project for which you need a widget and navigate to the project’s Java source. Create a new sub-package there named widget. Right click on the newly created sub-package and select the New->Widget option from there. Follow the instructions on the next screen. Most of the fields here are pretty much self explanatory. After doing this and running the app in your device, you will be able to see a widget for your app in the widget picker.   Just kidding, this was the easy part, off to more harder things now! Step 2: Populating the widget with data. Now, there can be 2 broad type of widgets Information Widgets and Collection Widgets. Information widgets are simple widgets that are used to display an information that changes with time, for example Weather Widget or a Clock Widget. Whereas, collection widgets are widgets which display a collection of data, for example the GMail widget is a collection widget. These are relatively complex and harder than the Information Widgets. In this post, we will focus on making a Collection Widget. For Collection widgets, we need two layout files, one for the widget and one for each item in the widget collection. Go ahead and create the two layout files. The wizard automatically generates the widget_layout.xml for you, you just need to edit it up. stock_layout.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:id="@+id/widget_toolbar" android:layout_height="?android:attr/actionBarSize" android:background="@color/colorPrimary"> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" android:src="@drawable/stock_up" android:contentDescription="@string/stock_widget" /> <ImageView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" android:src="@drawable/stock_down" android:contentDescription="@string/stock_widget" /> <TextView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginStart="32dp" android:gravity="center_vertical" android:text="@string/your_stocks" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" android:layout_marginLeft="32dp" /> </LinearLayout> <ListView android:id="@+id/widget_listView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/backGround"></ListView> </LinearLayout> list_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="72dp" android:gravity="center_vertical" android:orientation="horizontal" android:paddingLeft="16dp" android:paddingRight="16dp" > <TextView android:id="@+id/stock_symbol" style="@style/StockSymbolTextStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="start|center_vertical" tools:text="List Item" /> </LinearLayout> Next up, having a look at the modified files, we can see that the Widget creation wizard added some stuff into out AndroidManifest.xml and created a new java file. Upon taking a closer look at the manifest, we can see that the widget’s java class has been registered as a <receiver/> Next, opening up the NewAppWidget.java, we will see that it extends AppWidgetProvider and some methods are already overridden for you. Time to edit up this file to reference to the layouts we have just created. import android.annotation.TargetApi; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.os.Build; import android.support.annotation.NonNull; import android.widget.RemoteViews; /** * Implementation of App Widget functionality. */ public class StockWidgetProvider extends AppWidgetProvider { private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { // Construct the RemoteViews object which defines the view of out widget RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); // Instruct the widget manager to update…

Continue ReadingCreating a Widget for your Android App

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

Getting fired up with Firebase Database

As you might've noticed, in my Open Event Android Project, we are asking the user to enter his/her details and then using these details at the backend for generating the app according to his/her needs. One thing to wonder is how did we transmit the details from webpage to the server. Well, this is where Firebase comes to the rescue one more time! If you’ve read my previous post on Firebase Storage, you might have started to appreciate what an awesometastic service Firebase is. So without any further adieu, lets get started with this. Step 1 : Add your project to Firebase from the console.   Click on the Blue button Step 2 : Add Firebase to your webapp Open the project, you’ve just created and click on the bright red button that says, “ Add Firebase to your web app”   Copy the contents from here and paste it after your HTML code. Step 3 : Next up, navigate to the Database section in your console and move to the Rules tab.   For now, let us edit the rules to allow anyone to read and write to the database.   Almost all set up now. Step 4 : Modify the HTML to allow entering data by the user This looks something like this : Now let us setup our javascript to extract this data and store this in Firebase Database. We are almost finished with uploading the data to the database. Enter data inside the fields and press submit. If everything went well, you will be able to see the newly entered data inside your database. Now on to retrieving this data on the server. Our backend runs on a python script, so we have a library known as python-firebase which helps us easily fetch the data stored in the Firebase database. The code for it goes like this The data will be returned in JSON format, so you can manipulate and store it as you wish. Well, that’s it! You now know how to store and retrieve data to and from Firebase. It makes the work a lot simpler as there is no Database schema or tables that need to be defined, firebase handles this on its own. I hope that you found this tutorial helpful, and if you have any doubts regarding this feel free to comment down below, I would love to help you out. Cheers.

Continue ReadingGetting fired up with Firebase Database

Push your apk to your GitHub repository from Travis

In this post I’ll guide you on how to directly upload the compiled .apk from travis to your GitHub repository. Why do we need this? Well, assume that you need to provide an app to your testers after each commit on the repository, so instead of manually copying and emailing them the app, we can setup travis to upload the file to our repository where the testers can fetch it from. So, lets get to it! Step 1 : Link Travis to your GitHub Account. Open up https://travis-ci.org. Click on the green button in the top right corner that says “Sign in with GitHub” < Step 2 : Add your existing repository to Travis Click the “+” button next to your Travis Dashboard located on the left. < Choose the project that you want to setup Travis from the next page Toggle the switch for the project that you want to integrate Click the cog here and add an Environment Variable named GITHUB_API_KEY. Proceed by adding your Personal Authentication Token there. Read up here on how to get the Token.  < Great, we are pretty much done here. Let us move to the project repository that we just integrated and create a new file in the root of repository by clicking on the “Create new file” on the repo’s page. Name it .travis.yml and add the following commands over there language: android jdk: - oraclejdk8 android: components: - tools - build-tools-24.0.0 - android-24 - extra-android-support - extra-google-google_play_services - extra-android-m2repository - extra-google-m2repository - addon-google_apis-google-24 before_install: - chmod +x gradlew - export JAVA8_HOME=/usr/lib/jvm/java-8-oracle - export JAVA_HOME=$JAVA8_HOME after_success: - chmod +x ./upload-gh-pages.sh - ./upload-apk.sh script: - ./gradlew build Next, create a bash file in the root of your repository using the same method and name it upload-apk.sh #create a new directory that will contain out generated apk mkdir $HOME/buildApk/ #copy generated apk from build folder to the folder just created cp -R app/build/outputs/apk/app-debug.apk $HOME/android/ #go to home and setup git cd $HOME git config --global user.email "useremail@domain.com" git config --global user.name "Your Name" #clone the repository in the buildApk folder git clone --quiet --branch=master https://user-name:$GITHUB_API_KEY@github.com/user-name/repo-name master > /dev/null #go into directory and copy data we're interested cd master cp -Rf $HOME/android/* . #add, commit and push files git add -f . git remote rm origin git remote add origin https://user-name:$GITHUB_API_KEY@github.com/user-name/repo-name.git git add -f . git commit -m "Travis build $TRAVIS_BUILD_NUMBER pushed" git push -fq origin master > /dev/null echo -e "Donen" Once you have done this, commit and push these files, a Travis build will be initiated in few seconds. You can see it ongoing in your Dashboard at https://travis-ci.org/. After the build has completed, you will can see an app-debug.apk in your Repository. IMPORTANT NOTE : You might be wondering as to why did I write [skip ci] in the commit message. Well the reason for that is, Travis starts a new build as soon as it detects a commit made on the master branch of your repository. So once the apk is uploaded, that will trigger…

Continue ReadingPush your apk to your GitHub repository from Travis

Ideas on using Celery with Flask for background tasks

Simply put, Celery is a background task runner. It can run time-intensive tasks in the background so that your application can focus on the stuff that matters the most. In context of a Flask application, the stuff that matters the most is listening to HTTP requests and returning response. By default, Flask runs on a single-thread. Now if a request is executed that takes several seconds to run, then it will block all other incoming requests as it is single-threaded. This will be a very bad-experience for the user who is using the product. So here we can use Celery to move time-hogging part of that request to the background. I would like to let you know that by “background”, Celery means another process. Celery starts worker processes for the running application and these workers receive work from the main application. Celery requires a broker to be used. Broker is nothing but a database that stores results of a celery task and provides a shared interface between main process and worker processes. The output of the work done by the workers is stored in the Broker. The main application can then access these results from the Broker. Using Celery to set background tasks in your application is as simple as follows - @celery.task def background_task(*args, **kwargs): # do stuff # more stuff Now the function background_task becomes function-able as a background task. To execute it as a background task, run - task = background_task.delay(*args, **kwargs) print task.state # task current state (PENDING, SUCCESS, FAILURE) Till now this may look nice and easy but it can cause lots of problems. This is because the background tasks run in different processes than the main application. So the state of the worker application differs from the real application. One common problem because of this is the lack of request context. Since a celery task runs in a different process, so the request context is not available. Therefore the request headers, cookies and everything else is not available when the task actually runs. I too faced this problem and solved it using an excellent snippet I found on the Internet. """ Celery task wrapper to set request context vars and global vars when a task is executed Based on http://xion.io/post/code/celery-include-flask-request-context.html """ from celery import Task from flask import has_request_context, make_response, request, g from app import app # the flask app __all__ = ['RequestContextTask'] class RequestContextTask(Task): """Base class for tasks that originate from Flask request handlers and carry over most of the request context data. This has an advantage of being able to access all the usual information that the HTTP request has and use them within the task. Pontential use cases include e.g. formatting URLs for external use in emails sent by tasks. """ abstract = True #: Name of the additional parameter passed to tasks #: that contains information about the original Flask request context. CONTEXT_ARG_NAME = '_flask_request_context' GLOBALS_ARG_NAME = '_flask_global_proxy' GLOBAL_KEYS = ['user'] def __call__(self, *args, **kwargs): """Execute task code with given…

Continue ReadingIdeas on using Celery with Flask for background tasks

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

Set up Firebase to upload user files

If you’ve read my previous post on uploading files to server, you might have noticed that it was not an easy task to achieve. There is way too much boilerplate code for uploading a single file, and it will be much more complex in case we plan to upload multiple files, which I need to do for my project. So what’s the solution to this? ENTER FIREBASE! Yeah, you read it right, Firebase once again to the rescue! I came to know that firebase allows user to store and access the files easily to the built in storage. Enough chatter for now, lets get to code! Step 1 : Add your project to Firebase from the console. Click on the Blue button Step 2 : Add Firebase to your webapp Open the project, you’ve just created and click on the bright red button that says, “ Add Firebase to your web app” Copy the contents from here and paste it after your HTML code. Step 3 : Open the “Storage” tab from the navigation drawer and navigate to the rules tab over there. We need to set up specific rules as to who all can upload and read files to the storage bucket. For testing purposes, I’ve allowed everyone to read and write to my storage, but that shouldn’t be the case for your production app Step 4 : Add code for uploading your files. First create a document selection widget and an upload button in your website’s index.html. <tr> <td valign=”top”> <label for=”icon”>Zip File</label> </td> <td valign=”top”> <input accept=”.zip” type=”file” id=”uploadZip” name=”icon”> </td> </tr> Next, create a button to initiate the upload <tr> <td colspan=”5" style=”text-align:center”> <button type=”submit”>Upload Zip</button> </td> </tr> Next up, inside the JavaScript, add a submitlistener for the submit button and call preventDefault inside it to prevent the form from doing the default action. var form = document.querySelector(“form”); form.addEventListener(“submit”, function(event) { event.preventDefault(); Next up, get a reference to the upload location from your firebase storage bucket. var timestamp = Number(new Date()); var storageRef = firebase.storage().ref(timestamp.toString()); Next, get the upload button from its ID and add its contents to a variable named file_data. var $ = jQuery; var file_data = $(‘#uploadZip’).prop(‘files’)[0]; Now upload that file to firebase. storageRef.put(file_data); If everything went as expected, you’ll be able to see the uploaded files onto your firebase console.   So, you can really appreciate the awesomeness of Firebase by now. It has replaced the work done by over 50+ lines of code (spread around AJAX calls, PHP Scripts and JavaScript methods) by a single method call. I would urge you to go through the documentation for more clarity on this. https://firebase.google.com/docs/storage/ Well, that was it for now. Next time, I’ll tell you how to retrieve the files back from the storage and add user’s details to Firebase Database.(Yeah, no need for Tables and SQL anymore!) Cheers. :D

Continue ReadingSet up Firebase to upload user files

Uploading a file to a server via PHP

Uploading a file to a server via PHP If you have been following my posts about my GSoC project, you would be knowing that we are making an app generator which will allow users to easily generate an android app for any event that they plan to host. So, the next thing that we wanted in our app was to allow the users to upload a zip containing the json files (in case they don’t have an API, from where app can fetch data from) and then upload it to the server where we can use these files during the app compilation. Steps below will tell you , how we achieved it : Changes to HTML First thing that we needed to do was add a file upload element to out HTML page that would allow only .zip files to be uploaded. It was pretty simple one liner code which goes as follows <tr> <td valign=”top”> <label for=”sessions”>Zip containing .json files</label> </td> <td valign=”top”> <input accept=”.zip” type=”file” id=”uploadZip” name=”sessions”> </td> </tr> PHP script to upload file on to the server Next, we needed a server sided script (I used PHP) which would upload the zip provided by the user on to the server and store it to a unique location for each user. The code for that was, <?php if ( 0 < $_FILES[‘file’][‘error’] ) { echo ‘Error: ‘ . $_FILES[‘file’][‘error’] . ‘<br>’; } else { move_uploaded_file($_FILES[‘file’][‘tmp_name’],“/var/www/html/uploads/upload.zip”); } ?> So what is happening here is basically the input arg. is first checked whether it is null or not null. If it is null, and error is thrown back to the user, else the file is renamed and uploaded to the uploads folder in the server’s public directory. Changes to the JavaScript This was the part that needed most of the changes to be done, we first had to store the file that is to be uploaded in the form data, and then make and AJAX call to the php file located on the server. var file_data = $(‘#uploadZip’).prop(‘files’)[0]; var form_data = new FormData(); form_data.append(‘file’, file_data); $.ajax( { url: ‘/upload.php’, // point to server-side PHP script cache: false, contentType: false, processData: false, data: form_data, type: ‘post’, success: function(php_script_response){ ajaxCall1(); } //Chain up another AJAX call for further operations }); So, that’s almost it! Some server sided changes were also required like allowing the web user to execute the upload.php script and making the uploads directory writable by the web user. Well, does it work? Um, yeah it does. There are a few issues with concurrent users which we are still debugging, but apart from that it works like a charm! Here you can see a folder created by each user based on his/her timestamp And here you can see the file that was uploaded y him/her Lastly our webapp (Looks stunning right?) So, that was all for this week, hope to see you again next time. Cheers and all the best :)

Continue ReadingUploading a file to a server via PHP

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