Thursday, November 3, 2016

Not receiving Google OAuth refresh token

The refresh_token is only provided on the first authorization from the user. Subsequent authorizations, such as the kind you make while testing an OAuth2 integration, will not return the refresh_token again.

Go to your account security settings: 
https://security.google.com/settings/security/permissions?pli=1.

Then click "Revoke Access" next to your app.
The next OAuth2 request you make will return a refresh_token.

You need "access_type=offline" & "approval_prompt=force" in all cases when you want the refresh_token.

List of google apps connected to my google account:

Using OAuth 2.0 for Google Client-side Web Applications


http://pritomkumar.blogspot.com/2016/11/php-send-email-using-google-oauth2.html
1. Obtain OAuth 2.0 credentials from the Google API Console.
First visit to https://console.developers.google.com/ and follow the steps:
Click the "Credentials" as below image:


Now click on "Create credentials" right most part of button and then you can see a dropdown menu as below image:


Now click on "OAuth client ID"
It will show a page like and select "Web application" as below image and provide "Name" and "Authorized redirect URIs" as described and click "Create":



NB: it can say you to create a project, then create a project by click the button.

It will take you to the OAuth client page where you can see "Client ID" & "Client Secret" which would be need later.




You can enable any of your service from google account from list below for specific project:




All google products listed here:
https://developers.google.com/products/

2. Now its time to connect to google via OAuth (Its PHP code snippet):
You have to define your scope first:
$scope = "https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/gmail.readonly";
$auth_url = "https://accounts.google.com/o/oauth2/v2/auth";
$client_id = "YOUR CLIENT ID FROM GOOGLE";
$redirect_uri = "http://localhost/tappi/";

$forward_url = $auth_url."?scope=".$scope."&redirect_uri=".urlencode($redirect_uri)."&response_type=code&client_id=".urlencode($client_id);
header("Location: ".$url);

It will redirect you to the following page (if not logged in, login then):




Now click "Allow" button direct you to url you provided when creating application with a code in get parameter
Now you can get access token using the code received.
Full example code below:


<?php
session_start();
init();

if(token() != null) {
    echo "<a href='".$_SESSION["redirect_uri"]."'>Home</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?refresh_token=true'>Refresh token</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?profile=true'>Profile</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?logout=true'>Logout</a><br/><br/>\n\n";
}

if(isset($_GET["logout"])) {
    flushToken();
    echo "Logged out<br/>";
    echo "<a href='".$_SESSION["redirect_uri"]."'>Start new session</a>";
    die();
}
else if(isset($_GET["refresh_token"])) {
    refreshToken();
    header("Location: ".$_SESSION["redirect_uri"]);
}
else if(isset($_GET["profile"])) {
    viewProfile();
}
else if(token() != null) {
    echo "<pre>";print_r(token());echo "</pre>";
}
else if(isset($_GET["code"])) {
    $post = "code=".urlencode($_GET["code"])."&client_id=".urlencode($_SESSION["client_id"]);
    $post .= "&client_secret=".urlencode($_SESSION["client_secret"]);
    $post .="&redirect_uri=".urlencode($_SESSION["redirect_uri"]);
    $post .= "&grant_type=authorization_code";
    $result = json_decode(runCurl($_SESSION["token_url"], $post));
    storeToken($result);
    if(isset($result->refresh_token)) {
        file_put_contents("rt-".getUserID().".txt", $result->refresh_token);
    }
    file_put_contents("active.txt", getUserID());
    file_put_contents("access_token.txt", $result->access_token);
    header("Location: " . $_SESSION["redirect_uri"]);
}
else {
    $url = $_SESSION["auth_url"]."?scope=".urlencode($_SESSION["scope"]).
        "&redirect_uri=".urlencode($_SESSION["redirect_uri"]).
        "&response_type=code&client_id=".urlencode($_SESSION["client_id"])."&access_type=offline";
    echo "<a href='".$url."'>Authorize with Google</a>";
}

function refreshToken() {
    $post = "client_id=".urlencode($_SESSION["client_id"]);
    $post .= "&client_secret=".urlencode($_SESSION["client_secret"]);
    $post .= "&redirect_uri=".urlencode($_SESSION["redirect_uri"]);
    $post .= "&grant_type=refresh_token&refresh_token=".urlencode(getRefreshToken());
    $result = json_decode(runCurl($_SESSION["token_url"], $post));
    file_put_contents("access_token.txt", $result->access_token);
    storeToken($result);
}

function getRefreshToken() {
    $active = file_get_contents("active.txt");
    return file_get_contents("rt-".$active.".txt");
}

function flushToken() {
    file_put_contents("auth.txt", "");
    $_SESSION["redirected"] = null;
}

function token() {
    $text = file_exists("auth.txt") ? file_get_contents("auth.txt") : null;
    if($text != null && strlen($text) > 0) {
        return json_decode($text);
    }
    return null;
}

function storeToken($o) {
    file_put_contents("auth.txt", json_encode($o));
}

function init() {
    $_SESSION["auth_url"] = "https://accounts.google.com/o/oauth2/v2/auth";
    $_SESSION["token_url"] = "https://accounts.google.com/o/oauth2/token";
    $_SESSION["client_id"] = "892386593019-xxxxxxxxxinht701m7kn0gkoj964r2.apps.googleusercontent.com";
    $_SESSION["client_secret"] = "bVQ_xT0ZxxxxxxxxxxvV9zRV3";
    $_SESSION["redirect_uri"] = "http://localhost/tappi/google.php";
    $_SESSION["scope"] = "https://www.googleapis.com/auth/userinfo.profile"; /* User profile */
    $_SESSION["scope"] .= " https://www.googleapis.com/auth/userinfo.email"; /* User email address */
    $_SESSION["scope"] .= " https://www.googleapis.com/auth/gmail.readonly"; /* Read mail */
    $_SESSION["scope"] .= " https://www.googleapis.com/auth/gmail.send"; /* Send email */
}

function getUserID() {
    $fromSession = valueFromSession("google_user_id");
    if($fromSession) {
        return $fromSession;
    }
    else {
        $apiUrl = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
        $apiUrl .= "&access_token=".token()->access_token;
        $result = json_decode(runCurl($apiUrl));
        $_SESSION["google_user_id"] = $result->id;
        return $_SESSION["google_user_id"];
    }
}

function valueFromSession($name) {
    if(isset($_SESSION[$name])) {
        return $_SESSION[$name];
    }
    return null;
}

function viewProfile() {
    $apiUrl = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
    $apiUrl .= "&access_token=".token()->access_token;
    $result = json_decode(runCurl($apiUrl));
    echo "<pre>";
    print_r($result);
    echo "</pre>";
}

function runCurl($url, $post = null, $headers = null) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, $post == null ? 0 : 1);
    if($post != null) {
        curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
    }
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSLVERSION, 1);
    if($headers != null) {
        curl_setopt($curl, CURLOPT_HEADER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    }
    $response = curl_exec($curl);
    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);
    if($http_code >= 400) {
        echo "Error executing request to Office365 api with error code=$http_code<br/><br/>\n\n";
        echo "<pre>"; print_r($response); echo "</pre>";
        die();
    }
    return $response;
}
?>



Monday, October 10, 2016

Grails application: Create an common structure for domain class as artifact for common functionality when create new domain class

Create a groovy file under directory 'src/groovy/templates/artifacts' with name 'DomainClass.groovy" with following contents.

NB: Class name is significant here.

And then when you create an domain class, the new domain class structure will be as like this.


@artifact.package@

class @artifact.name@ {
    Long id
    String name
    String displayName
    String description

    Date created
    Date updated

    static constraints = {
        name(blank: false, minSize: 1, maxSize: 255)
        displayName(nullable: true, minSize: 1, maxSize: 255)
        description(nullable: true, maxSize: 500)
    }
}


And another example for your controller then groovy file name must be 'Controller.groovy' with following contents


@artifact.package@
import com.pkm.GeneralExceptionHandler
import com.pkm.services.DataReadService

class @artifact.name@ implements GeneralExceptionHandler {
    DataReadService dataReadService

    def index() {

    }
}


And when you create any Controller that would be look like as follows


package com.pkm

import com.pkm.GeneralExceptionHandler
import com.pkm.services.DataReadService

class PkmController implements GeneralExceptionHandler {
    DataReadService dataReadService

    def index() {

    }
}

Wednesday, October 5, 2016

Get all columns from all MySQL tables


SELECT * FROM information_schema.columns
WHERE table_schema = 'database_name'
ORDER BY table_name, ordinal_position

How to reset a particular form field using jQuery

Full code snippet

<head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<form style="margin: 50px;">
    <div>
        <input type='text' value='Default value' class="check_overall_change" style='width:206px'/>
        <button type='button'>Reset</button>
    </div>

    <div>
        <input type='checkbox' name='checkbox' value='1' class="check_overall_change"/> #1
        <input type='checkbox' name='checkbox' value='2' checked class="check_overall_change"/> #2
        <input type='checkbox' name='checkbox' value='3' class="check_overall_change"/> #3
        <button type='button' style='margin-left:78px'>Reset</button>
    </div>

    <div>
        <select style='width:206px' class="check_overall_change">
            <option value='1'>1</option>
            <option value='2'>2</option>
            <option value='3' selected>3</option>
        </select>
        <button type='button'>Reset</button>
    </div>

    <div>
        <select multiple style='width:206px' class="check_overall_change">
            <option value='1'>1</option>
            <option value='2' selected>2</option>
            <option value='3'>3</option>
            <option value='4' selected>4</option>
        </select>
        <button type='button'>Reset</button>
    </div>
    <div class="log"></div>
</form>
</body>
<script type="text/javascript">
    var baseConfig = getOverallValue(), log = $(".log");

    $(".check_overall_change").on("change", function () {
        checkFormValueChanged();
    })

    $(".check_overall_change[type='text']").on("keyup", function () {
        checkFormValueChanged();
    })

    function checkFormValueChanged() {
        if(baseConfig != getOverallValue()) {
            log.html("<h3>Value changed</h3>");
        }
        else {
            log.html("<h3>Value not changed</h3>");
        }
    }

    function resetForm() {
        var thiz = $(this), input = thiz.closest("div").find(":input:not(button)");
        if(input.is("select")) {
            var values = [];
            var options = input.find("option");
            for(var index = 0; index < options.length; index++) {
                if(options[index].defaultSelected) {
                    values.push($(options[index]).val())
                }
            }
            input.val(values);
        }
        else if(input[0].type == 'checkbox') {
            for(var index = 0; index < input.length; index++) {
                if(input[index].defaultChecked) {
                    $(input[index]).prop("checked", "checked");
                }
                else {
                    $(input[index]).prop("checked", null);
                }
            }
        }
        else {
            input.val(input[0].defaultValue)
        }
        checkFormValueChanged();
    }

    function getOverallValue() {
        var values = "";
        $(".check_overall_change").each(function (index, element) {
            element = $(element);
            if(element[0].type == 'checkbox') {
                values += element.is(":checked") + "-";
            }
            else {
                values += element.val() + "-";
            }
        })
        return values;
    }

    $("button").bind("click", resetForm);
</script>

And finally jsFiddle link to test yourself

Click here to test yourself at jsFiddle

Monday, September 26, 2016

File Change Listener Implementation Using Java


package com.pritom.kumar;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;

/**
 * Created by pritom on 25/09/2016.
 */
public class ChangeFileListener {
    public static void main(String[] args) throws Exception {
        startWatch("C:/tmp");
    }

    public static void startWatch(String location) {
        try {
            Path directory = Paths.get(location);
            println("Start listening directory: [" + location + "]");
            final WatchService watchService = directory.getFileSystem().newWatchService();
            directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);

            while (true) {
                final WatchKey watchKey = watchService.take();
                handleWatchTriggered(location, watchKey);
                boolean valid = watchKey.reset();
                if (!valid) {
                    throw new Exception("Watcher failed for listen [" + location + "]");
                }
            }
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void handleWatchTriggered(String location, WatchKey watchKey) throws Exception {
        List<WatchEvent<?>> watchEventList = watchKey.pollEvents();
        for (WatchEvent watchEvent : watchEventList) {
            if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
                println("Created: [" + watchEvent.context().toString() + "]");
                File fileCreated = new File(location + "/" + watchEvent.context().toString());
            }
            else if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
                println("Deleted: [" + watchEvent.context().toString() + "]");
            }
            else if (watchEvent.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                println("Modified: [" + watchEvent.context().toString() + "]");
            }
        }
    }

    public static void println(Object o) {
        System.out.println("" + o);
    }
}