Rewrites

Simple rewrites are done in admin panel, and for more complicated cases you can always write a rewriter function.

Using admin panel

Navigate to Settings > Rewrites section, initially it should be empty.

Create a new rewrite rule.

Regexp is a mask itself, Fields are GET/POST fields to be replaced with matching brackets from Regexp.

You can set either Page (plus optionally Controller mode) or Controller + Controller mode.

If you set Page, it will apply rewrite and then execute page, returning data as if it was just a direct page invokation.

In below example, navigating to '/blog/by-id/1234/' is equivalent to navigating to '/blog/?id=1234&mode=view'

When Page is not set, an appropriate Controller is called and it's output is directly returned to client.

Below example shows how to add API mappings. When calling '/api/accounting/list_invoices/', system will execute controller ApiAccounting.list_invoices and return results which should (hopefully) be a correctly formatted JSON.

Making complicated rewrites using function

You must add a rewrite function in site configuration. Of course, that can be one-liner, calling a larger function from project folder itself.

Generally, you do whatever you want here.

config/sites-enabled/mysite.js
exports.site={
    code:"mysite.com",
    title: " - mysite",
    adminpanel_title: "MYSITE",
    names: ["mysite.com","www.mysite.com"],
    database: { login:"", database:"", password:"" },

    // CUSTOM REWRITER CALL
    custom_rewriter: function(rr) { return rr.F("Rewriter","custom"); },


    load: [
        "functions/Rewriter.js",
    ],
    paths: {
        basepath: "/www/sites/mysite.com/",
    },
    previews: [ [24,24], [48,48], [128,128], [400,300], [640,480], [800,600], [220,150], [200,300], [75,75], [500,500], [990,400] ],
    default_l10n_id:1,
    language: "en",
    show_errors: 1
};

code/functions/Rewriter.js
var fs=require("fs");

// A complicated case, featuring REMOTE IP check, arguments sanitizing, language check and checking if site was payed

var ALLOWED_OFFICE_IPS={
    "192.168.0.10":1,
    "192.168.0.20":1,
};
exports.functions=[{
    _type:"functions",
    _section:"Rewriter",

    sanitize_rec:function(a,obj,k) {
        if (typeof a==="string") {
            if (a.match(/<script[^>]*>/i)) {
                if (obj && SANITIZE_CLEAR[rr.site.EXPORTNAME] && SANITIZE_CLEAR[rr.site.EXPORTNAME][k]) { obj[k]=undefined; return; }
                if (obj && SANITIZE_CLEAR["*"] && SANITIZE_CLEAR["*"][k]) { obj[k]=undefined; return; }
                throw new Error("Sanitizer error - <script> detected!");
            }
            var tmp=a.match(/(on(abort|after|animati|before|blur|canplay|change|click|context|copy|cut|dblclick|drag|drag|drop|error|focus|fullscreen|hashchange|key|load|message|mouse|offline|online|play|popstate|progress|reset|scroll|search|seek|select|show|stalled|storage|submit|suspend|timeupdate|toggle|touch|transition|unload|volumechange|waiting|wheel)\w{0,12})\s*=/i);
            if (tmp) {
                if (obj && SANITIZE_CLEAR[rr.site.EXPORTNAME] && SANITIZE_CLEAR[rr.site.EXPORTNAME][k]) { obj[k]=undefined; return; }
                if (obj && SANITIZE_CLEAR["*"] && SANITIZE_CLEAR["*"][k]) { obj[k]=undefined; return; }
                throw new Error("Sanitizer error - "+tmp[1]+" detected!");
            }
            if (a.match(/\s+href\s*=\s*"\s*javascript/i)) {
                if (obj && SANITIZE_CLEAR[rr.site.EXPORTNAME] && SANITIZE_CLEAR[rr.site.EXPORTNAME][k]) { obj[k]=undefined; return; }
                if (obj && SANITIZE_CLEAR["*"] && SANITIZE_CLEAR["*"][k]) { obj[k]=undefined; return; }
                throw new Error("Sanitizer error - href=javascript detected");
            }
            return a.replace(/<script[^>]*>/gi,"");
        }
        if (typeof a!=="object") return a;
        if (a.constructor===Array) {
            for (var i=0;i<a.length;i++) {
                a[i]=sanitize_rec(a[i],a,i);
            }
        } else {
            for (var k in a) {
                a[k]=sanitize_rec(a[k],a,k);
            }
        }
        return a;
    },

    ip_allowed: function() {
        return ALLOWED_OFFICE_IPS[system.env.REMOTE_ADDR];
    },

    set_language: function() {
        // TODO check GET/POST arguments, cookies and Accept-Language to set this.use_language
        this.use_language=this.fields._language||"en";
    },

    custom: function() {
        // Generally, you do whatever you want here.
        // If, upon function call end, this.action is defined, a regular page invokation will be done
        // If this.action is empty, a this.prerun_output will be returned directly.
        if (this.action=="/get/content_of_etc_passwd/") {
            var f=new fs.File("/etc/passwd");
            f.open("r");
            this.prerun_output=f.read();
            f.close();
            this.action=undefined;
            return;
        }
        if (!this.F("Rewriter","ip_allowed")) this.F("Rewriter","sanitize_rec",this.fields);
        this.F("Rewriter","set_language");
        if (this.site.not_payed && !this.F("Rewriter","ip_allowed")) return this.action="/site-disabled/";// 
        
    },
}];