Save rich text docs in github (github integration)

Right now, I’m terrified of building too much inside fibery because there’s no way out. There’s a csv export, or copy pasting each doc individually. Both inadequate solutions for peace of mind.

I see there’s some github integration but I don’t think this applies to content in rich text docs.

If we could associate all rich text docs in a space to a github repo, using the hooks they allow for integration… BOOM, we would have a backup of the content inside fibery (at least text; I understand there’s a lot more that would need far more sophisticated solutions).

Is this even remotely possible? Thanks!

Hello, Jose.

The workspace export feature was implemented precisely with the “peace of mind” goal. It gives you a hard copy of your data in a workspace. No need to copy paste anything.

GitHub integration syncs stuff from GitHub to Fibery, so different direction.

2 Likes

:rotating_light: Only CSV. No Markdown (no Rich text field & no Comments field)

That’s the problem. I want to use fibery as mostly an internal wiki. No markdown is a show stopper

Hmm, you can export the whole workspace with all markdown files and all databases as csv tables.

This only applies to exports from table view.
As @mdubakov says

I agree with what the team said about exporting. That said, if you’re looking specifically to push you rich text documents to github, here’s a script that does so which can be used as part of an automation (I have a button that uses this to push the current version of a file to github). It assumes that your entity has a text field called “Github SHA”. One kind of annoying thing is that it names the file according to the entity id, but it’s workable:

// Developer reference is at api.fibery.io/#action-buttons

var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

function InvalidCharacterError(message) {
    this.message = message;
}
InvalidCharacterError.prototype = new Error();
InvalidCharacterError.prototype.name = 'InvalidCharacterError';

// encoder
// [https://gist.github.com/999166] by [https://github.com/nignag]
function btoa(input) {
    var str = String(input);
    for (
        // initialize result and counter
        var block, charCode, idx = 0, map = chars, output = '';
        // if the next str index does not exist:
        //   change the mapping table to "="
        //   check if d has no fractional digits
        str.charAt(idx | 0) || (map = '=', idx % 1);
        // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
        output += map.charAt(63 & block >> 8 - idx % 1 * 8)
    ) {
        charCode = str.charCodeAt(idx += 3 / 4);
        if (charCode > 0xFF) {
            throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
        }
        block = block << 8 | charCode;
    }
    return output;
}

// Fibery API is used to retrieve and update entities
const fibery = context.getService('fibery');

// HTTP allows to send requests to external services
const http = context.getService('http');

// affected entities are stored in args.currentEntities;
// to support batch actions they always come in an array
for (const entity of args.currentEntities) {

    var desc = await fibery.getDocumentContent(entity.Description.Secret);

    var url = "https://api.github.com/repos/[your username here]/[your repo name here]/contents/" + entity["Id"] + ".md"

    var response = await http.putAsync(url, {
        body: {
            message: "Update " + entity.Name,
            content: btoa(desc),
            sha: entity["Github SHA"]
        },
        headers: {
            'Accept': 'application/vnd.github.v3+json',
            'Authorization': 'token [github token here]',
            'User-Agent': '[github username here]'
        }
    });
    console.log(response);

    // to update an entity provide an object with the new values
    await fibery.updateEntity(entity.type, entity.id, {
    'Github SHA': response["content"]["sha"]
    });
}

You can also pull the current version of the file from github using this script:

var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

function InvalidCharacterError(message) {
    this.message = message;
}
InvalidCharacterError.prototype = new Error();
InvalidCharacterError.prototype.name = 'InvalidCharacterError';

// encoder
// [https://gist.github.com/999166] by [https://github.com/nignag]
function btoa(input) {
    var str = String(input);
    for (
        // initialize result and counter
        var block, charCode, idx = 0, map = chars, output = '';
        // if the next str index does not exist:
        //   change the mapping table to "="
        //   check if d has no fractional digits
        str.charAt(idx | 0) || (map = '=', idx % 1);
        // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
        output += map.charAt(63 & block >> 8 - idx % 1 * 8)
    ) {
        charCode = str.charCodeAt(idx += 3 / 4);
        if (charCode > 0xFF) {
            throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
        }
        block = block << 8 | charCode;
    }
    return output;
}

// decoder
// [https://gist.github.com/1020396] by [https://github.com/atk]
function atob(input) {
    var str = (String(input)).replace(/[=]+$/, ''); // #31: ExtendScript bad parse of /=
    if (str.length % 4 === 1) {
        throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
    }
    for (
        // initialize result and counters
        var bc = 0, bs, buffer, idx = 0, output = '';
        // get next character
        buffer = str.charAt(idx++); // eslint-disable-line no-cond-assign
        // character found in table? initialize bit storage and add its ascii value;
        ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
            // and if not first of each 4 characters,
            // convert the first 8 bits to one ascii character
            bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
    ) {
        // try to find character in table (0-63, not found => -1)
        buffer = chars.indexOf(buffer);
    }
    return output;
}

function atob_newlines(input) {
    var lines = String(input).split("\n");
    var result = "";
    console.log(lines);
    for (var i = 0; i < lines.length; i++) {
        console.log(lines[i]);
        result += atob(lines[i]);
    }
    return result;
}

// Fibery API is used to retrieve and update entities
const fibery = context.getService('fibery');

// HTTP allows to send requests to external services
const http = context.getService('http');

// affected entities are stored in args.currentEntities;
// to support batch actions they always come in an array
for (const entity of args.currentEntities) {

    var url = "https://api.github.com/repos/[owner of your repo]/[your repo name]/contents/" + entity["Id"] + ".md";
    var response = await http.getAsync(url, {
        headers: {
            'Accept': 'application/vnd.github.v3+json',
            'Authorization': 'token [your github token]',
            'User-Agent': '[your github username]'
        }
    });
    response = JSON.parse(response);

    // to update an entity provide an object with the new values
    await fibery.setDocumentContent(entity.Description.Secret, atob_newlines(response["content"]));
    await fibery.updateEntity(entity.type, entity.id, {
        "Github SHA": response["sha"]
    });
}