COOKIES! This blog uses cookies!
I am completely out of control of cookies here, otherwise I would have disabled them (it is controlled by the platform).
If you don't like cookies and being tracked please leave this blog immediately.

Wednesday, 21 January 2015

A good manual on software versioning

Semantic Versioning: http://semver.org/

Briefly:

Given a version number MAJOR.MINOR.PATCH, increment the:
  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

Wednesday, 14 January 2015

Alfresco Javascript webscript Debuggers

Just found that there are actually two of them:

One for the Alfresco repository debugging:
/alfresco/service/api/javascript/debugger
(may be http://127.0.0.1:8080/alfresco/service/api/javascript/debugger)

And one for the Alfresco share debugging:
/share/page/api/javascript/debugger
(may be http://127.0.0.1:8081/share/page/api/javascript/debugger)

Webscript indexes accordingly are:
/alfresco/service/index
(http://127.0.0.1:8080/alfresco/service/index)

and

/share/service/index
(http://127.0.0.1:8081/share/service/index)


Debuggers sometimes won't catch webscripts evaluated: you may need to clean up the project and do "clear dependency caches" and "refresh web scripts" on webscript indexes service pages.

Tuesday, 4 November 2014

JWT usage example

Good, easy to understand JSON web token (JWT) usage example, which does not contain much unrelated stuff:
https://github.com/auth0/angular-token-auth

Article with explanation:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/

Listings just in case if it suddenly disappear:

auth.server.js
var express = require('express');
var bodyParser = require('body-parser');

var jwt = require('jsonwebtoken');  //https://npmjs.org/package/node-jsonwebtoken
var expressJwt = require('express-jwt'); //https://npmjs.org/package/express-jwt


var secret = 'this is the secret secret secret 12356';

var app = express();

// We are going to protect /api routes with JWT
app.use('/api', expressJwt({secret: secret}));

app.use(bodyParser.json());
app.use('/', express.static(__dirname + '/'));

app.use(function(err, req, res, next){
  if (err.constructor.name === 'UnauthorizedError') {
    res.status(401).send('Unauthorized');
  }
});

app.post('/authenticate', function (req, res) {
  //TODO validate req.body.username and req.body.password
  //if is invalid, return 401
  if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
    res.status(401).send('Wrong user or password');
    return;
  }

  var profile = {
    first_name: 'John',
    last_name: 'Doe',
    email: 'john@doe.com',
    id: 123
  };

  // We are sending the profile inside the token
  var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });

  res.json({ token: token });
});

app.get('/api/restricted', function (req, res) {
  console.log('user ' + req.user.email + ' is calling /api/restricted');
  res.json({
    name: 'foo'
  });
});

app.listen(8080, function () {
  console.log('listening on http://localhost:8080');
});


auth.client.js
var myApp = angular.module('myApp', []);

//this is used to parse the profile
function url_base64_decode(str) {
  var output = str.replace('-', '+').replace('_', '/');
  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw 'Illegal base64url string!';
  }
  return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
}

myApp.controller('UserCtrl', function ($scope, $http, $window) {
  $scope.user = {username: 'john.doe', password: 'foobar'};
  $scope.isAuthenticated = false;
  $scope.welcome = '';
  $scope.message = '';

  $scope.submit = function () {
    $http
      .post('/authenticate', $scope.user)
      .success(function (data, status, headers, config) {
        $window.sessionStorage.token = data.token;
        $scope.isAuthenticated = true;
        var encodedProfile = data.token.split('.')[1];
        var profile = JSON.parse(url_base64_decode(encodedProfile));
        $scope.welcome = 'Welcome ' + profile.first_name + ' ' + profile.last_name;
      })
      .error(function (data, status, headers, config) {
        // Erase the token if the user fails to log in
        delete $window.sessionStorage.token;
        $scope.isAuthenticated = false;

        // Handle login errors here
        $scope.error = 'Error: Invalid user or password';
        $scope.welcome = '';
      });
  };

  $scope.logout = function () {
    $scope.welcome = '';
    $scope.message = '';
    $scope.isAuthenticated = false;
    delete $window.sessionStorage.token;
  };

  $scope.callRestricted = function () {
    $http({url: '/api/restricted', method: 'GET'})
    .success(function (data, status, headers, config) {
      $scope.message = $scope.message + ' ' + data.name; // Should log 'foo'
    })
    .error(function (data, status, headers, config) {
      alert(data);
    });
  };

});

myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
  return {
    request: function (config) {
      config.headers = config.headers || {};
      if ($window.sessionStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
      }
      return config;
    },
    responseError: function (rejection) {
      if (rejection.status === 401) {
        // handle the case where the user is not authenticated
      }
      return $q.reject(rejection);
    }
  };
});

myApp.config(function ($httpProvider) {
  $httpProvider.interceptors.push('authInterceptor');
});


index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Angular Authentication</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
    <script src="./auth.client.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="UserCtrl">
      <span ng-show="isAuthenticated">{{welcome}}</span>
      <form ng-show="!isAuthenticated" ng-submit="submit()">
        <input ng-model="user.username" type="text" name="user" placeholder="Username" />
        <input ng-model="user.password" type="password" name="pass" placeholder="Password" />
        <input type="submit" value="Login" />
      </form>
      <div>{{error}}</div>
      <div ng-show="isAuthenticated">
        <a ng-click="callRestricted()" href="">Shh, this is private!</a>
        <br>
        <div>{{message}}</div>
        <a ng-click="logout()" href="">Logout</a>
      </div>
    </div>
  </body>
</html>


package.json
{
  "name": "angular-token-auth",
  "version": "0.1.0",
  "dependencies": {
    "body-parser": "^1.9.0",
    "express": "~4.9.0",
    "express-jwt": "~0.2.1",
    "jsonwebtoken": "~0.4.0"
  },
  "description": "Example of Token-based authentication in [AngularJS](http://angularjs.org) with [Express](http://expressjs.com).",
  "main": "auth.server.js",
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/auth0/angular-token-auth.git"
  },
  "keywords": [
    "angular",
    "auth",
    "jwt",
    "express"
  ],
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0/angular-token-auth/issues"
  },
  "homepage": "https://github.com/auth0/angular-token-auth"
}

Wednesday, 24 September 2014

Combine several Q objects programmatically with OR in Django ORM

Say we have dictionary coming from outside (from JSON, for example, containing some data to be used as OR clauses). It is possible to use __or__ to combine them programmatically.

from django.db import models
from operator import __or__ as OR
from django.db.models import Q

#... some code ...
clauses = [{'property':'name__exact','value':'andrew'},{'property':'name__icontains','value':'z'}, ... ]
or_params = []
for or_param in clauses:
    if 'value' in or_param.keys() and 'property' in or_param.keys():
        or_params.append(Q(**dict([(or_param['property'], or_param['value'])])))

Model.objects.filter(reduce(OR, or_params))

Many thanks to Calvin for right keywords

Wednesday, 10 September 2014

Sencha: Catch all events of Observable

Very useful pattern to catch all events of Observable object in Sencha:
Ext.util.Observable.capture(object, function(){
    console.log(arguments);
});


This object might be Store, View, or whatever using Observable mixin. This may be useful to learn how the object work or to catch events before any other on/addListener listeners.

Arguments may wary but it contains at least two objects:
0: {String} always event name
1: {Object} object itself

This may contain other arguments such as Action, changed Model (for Store), String name of the action caused event, Array of changed fields (for Model and Store)

Store usage:
Ext.util.Observable.capture(store, function(){
    if (arguments[0]=='update') {
        /*eventName,store,record,operation,modifiedFields*/
        // Your fancy code here
        store.suspendEvent('update');
    }
});

Saturday, 6 September 2014

Reading XLSX on android 4 (Post 3)

!!!UPDATE:
All this hacking is getting redundant with Android Build Tools 21+ and Android 5, please see this post for details: http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html
-----------------


More on reading XLSX on Android.

I renamed "javax" namespace to "aavax" in StAX sources and recompiled it. After that I replaced all strings 'javax/xml/stream', 'javax/xml/namespace' and 'javax.xml.strings' occurrences in other binaries(including ooxml-schemas) to appropriate strings with "aavax". Now it works without necessity to use --core-library option!

Two previous posts:
http://blog.kondratev.pro/2014/08/reading-xlsx-on-android.html
http://blog.kondratev.pro/2014/09/further-to-my-post-from-yesterday-on.html

You can review demo project here:
https://github.com/andruhon/AndroidReadXLSX

You can download ported XSSX here:
https://github.com/andruhon/AndroidReadXLSX/tree/master/libs

Donate / help
I don't ask for a donation, but you can join me on the LinkedIN and endorse my Java and Android skills if you find this hack useful:
https://nz.linkedin.com/pub/andrei-kondratev/51/445/635

Tuesday, 2 September 2014

Reading XLSX on android 4 (Post 2)

!!!UPDATE:
All this hacking is getting redundant with Android Build Tools 21+ and Android 5, please see this post for details: http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html
-----------------

Further to my post from Saturday on reading XLSX on Android:

I shrunk dom4j, poi, poi-ooxml and xmlbeans into one jar with proguard. All classes not necessary for reading Excel files are seems to be removed. Proguard config follows:

-injars      {my IN jars mentioned above}
-outjars     poi-min.jar

-libraryjars {my dir with schemas}
-libraryjars {path to /jre/lib}
-libraryjars {path to /jdk/lib}

-dontoptimize
-dontobfuscate
-ignorewarnings

-keep class org.apache.poi.xssf.** { *; }
-keep class org.apache.poi.ss.** { *; }
-keep class org.apache.poi.hssf.** { *; }
-keep class org.apache.xmlbeans.** { *; }

It works fine for reading and writing both XLS and XLSX files.

Next post on XLSX:
http://blog.kondratev.pro/2014/09/reading-xlsx-on-android-3.html

Previous post on XLSX:
http://blog.kondratev.pro/2014/08/reading-xlsx-on-android.html