Cross Origin Resource Sharing - jordy33/turbogears_tutorial GitHub Wiki

The following code will be running at https://mercury.dudewhereismy.mx

Insert the following in root.py

    @expose('myprojectname.templates.tabs')
    def tabs(self):
        return dict(uno="")

Create tabs.mak and insert the following:

<!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta charset="utf-8" />

   <link href="${tg.url('/css/bootstrap.min.css')}" rel="stylesheet">
    <link href="${tg.url('/css/font-awesome.min.css')}" rel="stylesheet" />
    <link href="${tg.url('/css/datepicker3.css')}" rel="stylesheet" />
    <link href="${tg.url('/css/styles3.css')}" rel="stylesheet">
	<link href="https://fonts.googleapis.com/css?family=Montserrat:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
    <!-- jquery and alert -->
    <script src="${tg.url('/js/jquery-1.11.1.min.js')}"></script>
    <script src="${tg.url('/js/alert.js')}"></script>
	<!--[if lt IE 9]>
	<script src="${tg.url('/js/html5/html5shiv.js')}"></script>
	<script src="${tg.url('/js/html5/respond.min.js')}"></script>
	<![endif]-->
    <!-- extgrid -->


    <!-- jqgrid -->
    <script src="${tg.url('/js/jqgrid/jquery.jqgrid.min.js')}"></script>
    <script src="${tg.url('/js/jqgrid/i18n/grid.locale-es.js')}"></script>
    <!-- Font Size -->
    <link rel="stylesheet" href="${tg.url('/css/jqgrid/ui.jqgrid.css')}">
    <!-- Custom Theme Roller -->
    <!-- Important: Bootstrap must be first to avoid over raid jquery-ui  -->
    <script src="${tg.url('/js/bootstrap.min.js')}"></script>

    <script src="${tg.url('/js/jquery-ui.js')}"></script>
    <script src="${tg.url('/js/jquery-validation-1.17.0/dist/jquery.validate.js')}"></script>

    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css" type="text/css"/>
    <!-- end jqgrid -->
    <script src="${tg.url('/js/mqtt/mqttws31.js')}" type="text/javascript"></script>
    <!-- notifications grid -->
    <!-- moment for UTC to local dates -->
    <script src="${tg.url('/js/moment/moment.js')}"></script>


    <script src="js/lumino/chart.min.js"></script>
	<script src="js/lumino/chart-data.js"></script>
	<script src="js/lumino/easypiechart.js"></script>
	<script src="js/lumino/easypiechart-data.js"></script>
	<script src="js/lumino/bootstrap-datepicker.js"></script>
	<script src="js/lumino/custom.js"></script>
        <script type="text/javascript">

            $(document).ready(function () {

            });
            var username = 'manager';
            var password = 'managepass';

            function make_base_auth(user, password) {
                var tok = user + ':' + password;
                var hash = btoa(tok);
                return "Basic " + hash;
                }
            function doAjax(pageName) {

                $.ajax({
                    url:pageName ,
                    error: function () {
                        $('#info').html('<p>An error has occurred</p>');
                    },
                    beforeSend: function(xhr){
                xhr.setRequestHeader("Content-Type","application/json");
                xhr.setRequestHeader("Accept","application/json");
                xhr.setRequestHeader( "Authorization", make_base_auth(username,password));

        },
                    dataType: 'html',
                    success: function (data, rq) {
                        $("#fragment0").html(data);
                    },
                    type: 'GET'
                });
            }
        </script>
    </head>
    <body>
        <div class="container">
            <h2>Dynamic Tabs</h2>
            <button onclick="doAjax('https://venus.dudewhereismy.mx/validate/jqgrid')">Login</button>
            <br>
            <ul class="nav nav-tabs">
                <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
                <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
                <li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
                <li><a data-toggle="tab" href="#menu3">Menu 3</a></li>
            </ul>

            <div class="tab-content">
                <div id="home" class="tab-pane fade in active">
                  <div id="fragment0"></div>
                </div>
                <div id="menu1" class="tab-pane fade">
                  <h3>Menu 1</h3>
                  <div id="fragment1"></div>
                </div>
                <div id="menu2" class="tab-pane fade">
                  <h3>Menu 2</h3>
                  <div id="fragment1"></div>
                </div>
                <div id="menu3" class="tab-pane fade">
                  <h3>Menu 3</h3>
                  <p>Eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>
                </div>
            </div>
        </div>
    </body>
</html>

The following code will be running at https://venus.dudewhereismy.mx

The site must run with basic auth

Create a controller named validate.py insert the following:

# -*- coding: utf-8 -*-
"""The base Controller API."""
from tg.decorators import expose
from pythonvenus.lib.base import BaseController
from pythonvenus.controllers.jqgrid import jqgridDataGrabber
from pythonvenus.model.tables import Trackers

__all__ = ['ValidateController']
from tg import predicates

class ValidateController(BaseController):
    allow_only = predicates.not_anonymous()

    @expose('pythonvenus.templates.jqgrid')
    def jqgrid(self):
        return dict()

    @expose('json')
    def loadTest2(self, **kw):
        filter = []
        return jqgridDataGrabber(Trackers, 'id', filter, kw).loadGrid()

    @expose('json')
    def updateTest2(self, **kw):
        filter = []
        return jqgridDataGrabber(Trackers, 'id', filter, kw).updateGrid()

At top of root.py insert:

from pythonvenus.controllers.validate import ValidateController

At the class RootController(BaseController): insert:

    validate = ValidateController()

Create jqgrid.mak and insert the following:

<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/free-jqgrid/4.8.0/js/i18n/grid.locale-es.js"></script>
  <script src="https://cdn.jsdelivr.net/free-jqgrid/4.8.0/js/jquery.jqgrid.min.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/free-jqgrid/4.8.0/css/ui.jqgrid.css">
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css" type="text/css"/>
    <meta charset="utf-8" />
    <title>jqGrid Loading Data - Million Rows from a REST service</title>
</head>
<body>
    <table style="width:100%;overflow:auto;">
    <table id="jqGridTable" class="scroll" cellpadding="0" cellspacing="0"></table>
    <div id="listPagerTables" class="scroll" style="text-align:center;"></div>
    <div id="listPsetcols" class="scroll" style="text-align:center;"></div>
    </table>
<script type="text/javascript">
        $(document).ready(

        function () {
            var username = 'manager';
            var password = 'managepass';

            function make_base_auth(user, password) {
                var tok = user + ':' + password;
                var hash = btoa(tok);
                return "Basic " + hash;
                }
            $.ajaxSetup({
                headers : {
                    'Authorization' : make_base_auth(username,password)
                }
            });
            var grid_name = '#jqGridTable';
            var grid_pager= '#listPagerTables';
            var update_url='https://venus.dudewhereismy.mx/validate/updateTest2';
            var load_url='https://venus.dudewhereismy.mx/validate/loadTest2/';
            var header_container='Test 2';
            var addParams = {left: 0,width: window.innerWidth-600,top: 20,height: 200,url: update_url, closeAfterAdd: true,closeAfterEdit: true,closeAfterSearch:true}
            var editParams = {left: 0,width: window.innerWidth-400,top: 20,height: 200,url: update_url,closeAfterAdd: true,closeAfterEdit: true,closeAfterSearch:true,modal: true,
                    width: "500",
                    editfunc: function (rowid) {
                    alert('The "Edit" button was clicked with rowid=' + rowid);
                    }
                };
            var deleteParams = {left: 0,width: window.innerWidth-700,top: 20,height: 130,url: update_url,closeAfterAdd: true,closeAfterEdit: true,closeAfterSearch:true}
            var viewParams = {left: 0,width: window.innerWidth-700,top: 20,height: 130,url: update_url,closeAfterAdd: true,closeAfterEdit: true,closeAfterSearch:true}
            var searchParams = {top: 20,height: 130,width: "500",closeAfterAdd: true,closeAfterEdit: true,closeAfterSearch:true,url: update_url,modal: true, };
            var grid = jQuery(grid_name);
            grid.jqGrid({
                url: load_url,
                datatype: 'json',
                mtype: 'GET',
                colNames: ['id', 'imei','ticket','nombre'],
                colModel: [
                    {name: 'id',index: 'id', width: 5,align: 'left',key:true,hidden: true, editable: true,edittype: 'text',editrules: {required: false}},
                    {name: 'imei',index: 'imei', width: 30, align: 'right',hidden: false,editable: true, edittype: 'text',editrules: {required: false}},
                    {name: 'ticket',index: 'ticket', width: 30, align: 'right',hidden: false,editable: true, edittype: 'text',editrules: {required: false}},
                    {name: 'name',index: 'name', width: 30, align: 'right',hidden: false,editable: true, edittype: 'text',editrules: {required: false}},
                ],
                pager: jQuery(grid_pager),
                rowNum: 10,
                rowList: [10, 50, 100],
                sortname: 'imei',
                sortorder: "desc",
                autowidth: true,
                shrinkToFit: true,
                viewrecords: true,
                height: 250,
                caption: header_container,


            });
            grid.jqGrid('navGrid',grid_pager,{edit:true,add:true,del:true, search:true},
                            editParams,
                            addParams,
                            deleteParams,
                            searchParams,
                            viewParams);
        });
        $.extend($.jgrid.nav,{alerttop:1});
    </script>


</body>
</html>

The following configuration is performed at the load balancer

Edit /etc/haproxy/haproxy.cfg and insert the following:

global
  log         127.0.0.1 syslog
  maxconn     1000
  user        haproxy
  group       haproxy
  daemon
  tune.ssl.default-dh-param 4096
  ssl-default-bind-options no-sslv3 no-tls-tickets
  ssl-default-bind-ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH


defaults
  log  global
  mode  http
  option  httplog
  option  dontlognull
  option  http-server-close
  option  forwardfor except 127.0.0.0/8
  option  redispatch
  option  contstats
  retries  3
  timeout  http-request 10s
  timeout  queue 1m
  timeout  connect 10s
  timeout  client 1m
  timeout  server 1m
  timeout  check 10s

###########################################
#
# HAProxy Stats page
#
###########################################
listen stats
  bind *:9090
  mode  http
  maxconn  10
  stats  enable
  stats  hide-version
  stats  realm Haproxy\ Statistics
  stats  uri /
  stats  auth admin:GPSc0ntr0l1

###########################################
#
# Front end for all
#
###########################################
frontend ALL
  bind   *:80
  bind   *:443 ssl crt /etc/haproxy/certs/dudewhereismy.mx.pem
  mode   http
######
# rewrite URL
######
#http-request set-var(txn.host_header) req.hdr(Host),lower
#acl is_domain1 var(txn.host_header) -m beg mercury.dudewhereismy.mx
#http-request set-header Host venus.dudewhereismy.mx if is_domain1
#http-request set-uri  /pathtoapp/%[capture.req.uri] if is_domain1

#####
# Add CORS headers when Origin header is present
    capture request header origin len 128
    http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
    rspadd Access-Control-Allow-Headers:\ Origin,\ X-Requested-With,\ Content-Type,\ Accept  if { capture.req.hdr(0) -m found }
  # Define path for lets encrypt
  acl is_letsencrypt path_beg -i /.well-known/acme-challenge/
  use_backend letsencrypt if is_letsencrypt

  # Define hosts
  acl host_sun hdr(host) -i sun.dudewhereismy.mx
  acl host_earth hdr(host) -i earth.dudewhereismy.mx
  acl host_pluto hdr(host) -i pluto.dudewhereismy.mx
  acl host_mercury hdr(host) -i mercury.dudewhereismy.mx
  acl host_venus hdr(host) -i venus.dudewhereismy.mx
  acl is_options method OPTIONS  
  use_backend venus_cors_headers if METH_OPTIONS host_venus
  use_backend earth_cors_headers if METH_OPTIONS host_earth
  # Direct hosts to backend
  use_backend sun if host_sun
  use_backend earth if host_earth
  use_backend pluto if host_pluto
  use_backend mercury if host_mercury
  use_backend venus if host_venus

  # Redirect port 80 to 443
  # But do not redirect letsencrypt since it checks port 80 and not 443
  redirect scheme https code 301 if !{ ssl_fc } !is_letsencrypt

###########################################
#
# Back end letsencrypt
#
###########################################
backend letsencrypt
  server letsencrypt 127.0.0.1:54321

###########################################
#
# Back end for foo
#
###########################################

backend sun
  rspadd Access-Control-Allow-Origin:\ *
  rspadd Access-Control-Max-Age:\ 31536000
  balance         roundrobin
  option          httpchk GET /check
  http-check      expect rstring ^UP$
  default-server  inter 10s fall 3 rise 2
  server          sun1 127.0.0.1:8080 check

backend earth
  rspadd Access-Control-Max-Age:\ 31536000
  rspadd Access-Control-Allow-Credentials:\ true
  rspadd Access-Control-Allow-Methods:\ GET,\ HEAD,\ OPTIONS,\ POST,\ PUT
  rspadd Access-Control-Allow-Headers:\ Origin,\ Accept,\ X-Requested-With,\ Content-Type,\ Access-Control-Request-Method,\ Access-Control-Request-Headers,\ Authorization
  balance         roundrobin
  option          httpchk GET /check
  http-check      expect rstring ^UP$
  default-server  inter 10s fall 3 rise 2
  server          earth1 127.0.0.1:8082 check

backend pluto
  rspadd Access-Control-Allow-Origin:\ *
  rspadd Access-Control-Max-Age:\ 31536000
  balance         roundrobin
  option          httpchk GET /check
  http-check      expect rstring ^UP$
  default-server  inter 10s fall 3 rise 2
  server          pluto1 127.0.0.1:8084 check

backend mercury
  balance         roundrobin
  option          httpchk GET /check
  http-check      expect rstring ^UP$
  default-server  inter 10s fall 3 rise 2
  server          mercury1 127.0.0.1:8086 check
  server          mercury2 127.0.0.1:8087 check

backend venus
  rspadd Access-Control-Max-Age:\ 31536000
  rspadd Access-Control-Allow-Credentials:\ true
  rspadd Access-Control-Allow-Methods:\ GET,\ HEAD,\ OPTIONS,\ POST,\ PUT
  rspadd Access-Control-Allow-Headers:\ Origin,\ Accept,\ X-Requested-With,\ Content-Type,\ Access-Control-Request-Method,\ Access-Control-Request-Headers,\ Authorization
  balance         roundrobin
  option          httpchk GET /check
  http-check      expect rstring ^UP$
  default-server  inter 10s fall 3 rise 2
  server          venus1 127.0.0.1:8088 check


backend venus_cors_headers
errorfile 503 /root/venus.http 

backend earth_cors_headers
errorfile 503 /root/earth.http 

At the haproxy server at /root insert earth.http with the following:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://sun.dudewhereismy.mx
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Max-Age: 31536000
Access-Control-Allow-Credentials: true
Content-Length: 0
Cache-Control: private

At the haproxy server at /root insert mercury.http with the following:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://sun.dudewhereismy.mx 
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,PATCH,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Max-Age: 31536000
Access-Control-Allow-Credentials: true
Content-Length: 0
Cache-Control: private

Test the code:

https://mercury.dudewhereismy.mx/tabs
⚠️ **GitHub.com Fallback** ⚠️