Jump to content

ICT:FinalConfig - ASSET - automatic numbering

From Costa Sano MediaWiki
Revision as of 21:30, 13 February 2026 by Mngr (talk | contribs) (Created page with "= DigitalAsset Numbering Engine (Architecture + Lua + JavaScript) = Document revision: {{#time:Y-m-d|{{REVISIONTIMESTAMP}}}} by {{REVISIONUSER}} This page explains the architecture and implementation of the automatic numbering system for the DigitalAsset entity. It contains: * The conceptual workflow * The Lua module (Module:DigitalAssetID) * The JavaScript logic (MediaWiki:DigitalAsset.js) * Notes on integration with Page Forms This page is for study and understandi...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

DigitalAsset Numbering Engine (Architecture + Lua + JavaScript)

Document revision: 2026-02-13 by Mngr

This page explains the architecture and implementation of the automatic numbering system for the DigitalAsset entity. It contains:

  • The conceptual workflow
  • The Lua module (Module:DigitalAssetID)
  • The JavaScript logic (MediaWiki:DigitalAsset.js)
  • Notes on integration with Page Forms

This page is for study and understanding before implementation.


1. Conceptual Workflow

The identifier of a DigitalAsset follows the pattern:

<ChapterCode>-<ContextCode>-<SequenceNumber>

Where:

  • ChapterCode comes from the selected Chapter
  • ContextCode comes from either Place OR Organisation
  • SequenceNumber is a 4‑digit counter starting at 0001 for each (Chapter, Context) pair

The identifier becomes:

  • the page name of the DigitalAsset
  • the file name of the uploaded file (with extension)
  • an immutable archival reference

The user workflow:

  1. User selects Chapter
  2. User selects Place OR Organisation (mutually exclusive)
  3. Lua module computes next sequence number + identifier
  4. JavaScript fills the form fields and locks identifier
  5. User uploads a file → JS renames it to the identifier
  6. Save → file upload + Cargo store + page creation

2. Lua Module: Module:DigitalAssetID

This module performs:

  • Exclusivity checks
  • Fetching Chapter.code
  • Fetching Place.code or Organisation.code
  • Querying Cargo for existing sequence numbers
  • Computing next sequence number
  • Formatting the identifier
  • Returning JSON to JavaScript
-- Module:DigitalAssetID
local p = {}

local cargo = mw.ext.cargo

-- Helper: zero-pad sequence number
local function pad(num)
    return string.format("%04d", tonumber(num))
end

-- Main function: compute identifier
function p.generate(frame)
    local args = frame.args
    local chapterPage = args.chapter_id
    local placePage = args.place_id
    local orgPage = args.organisation_id

    -- 1. Enforce exclusivity
    if (placePage ~= "" and orgPage ~= "") then
        return mw.text.jsonEncode({
            error = "Select either a Place OR an Organisation, not both."
        })
    end

    if (placePage == "" and orgPage == "") then
        return mw.text.jsonEncode({
            error = "You must select a Place OR an Organisation."
        })
    end

    -- 2. Fetch Chapter code
    local chapterRes = cargo.query(
        "ResearchChapters",
        "code",
        { where = string.format("_pageName='%s'", chapterPage) }
    )

    if not chapterRes[1] then
        return mw.text.jsonEncode({ error = "Invalid chapter selected." })
    end

    local chapterCode = chapterRes[1].code

    -- 3. Fetch context code (Place or Organisation)
    local contextCode = nil
    local contextTable = nil
    local contextPage = nil

    if placePage ~= "" then
        contextTable = "Places"
        contextPage = placePage
    else
        contextTable = "Organisations"
        contextPage = orgPage
    end

    local ctxRes = cargo.query(
        contextTable,
        "code",
        { where = string.format("_pageName='%s'", contextPage) }
    )

    if not ctxRes[1] then
        return mw.text.jsonEncode({ error = "Invalid context selected." })
    end

    contextCode = ctxRes[1].code

    -- 4. Determine next sequence number
    local existing = cargo.query(
        "DigitalAssets",
        "sequence_number",
        {
            where = string.format(
                "chapter_id='%s' AND (place_id='%s' OR organisation_id='%s')",
                chapterPage, placePage, orgPage
            ),
            orderBy = "sequence_number DESC",
            limit = 1
        }
    )

    local nextSeq = 1
    if existing[1] and existing[1].sequence_number then
        nextSeq = tonumber(existing[1].sequence_number) + 1
    end

    -- 5. Format identifier
    local identifier = string.format(
        "%s-%s-%s",
        chapterCode,
        contextCode,
        pad(nextSeq)
    )

    -- 6. Return result
    return mw.text.jsonEncode({
        identifier = identifier,
        sequence_number = nextSeq
    })
end

return p

3. JavaScript: MediaWiki:DigitalAsset.js

This script:

  • Watches for changes in Chapter / Place / Organisation
  • Enforces exclusivity
  • Calls the Lua module
  • Fills identifier + sequence number
  • Locks identifier
  • Renames uploaded file
  • Overrides page name before submission
/* MediaWiki:DigitalAsset.js */

$(document).ready(function () {

    function getField(name) {
        return $("[name='DigitalAsset[" + name + "]']");
    }

    function generateIdentifier() {
        const chapter = getField("chapter_id").val();
        const place = getField("place_id").val();
        const org = getField("organisation_id").val();

        // Exclusivity check
        if (place && org) {
            alert("Select either a Place OR an Organisation, not both.");
            return;
        }

        if (!chapter || (!place && !org)) {
            return; // Not enough info yet
        }

        // Call Lua module
        new mw.Api().get({
            action: "scribunto-console",
            title: "Module:DigitalAssetID",
            question: "return require('Module:DigitalAssetID').generate{chapter_id='" +
                chapter + "', place_id='" + place + "', organisation_id='" + org + "'}"
        }).done(function (data) {

            const result = JSON.parse(data.return);

            if (result.error) {
                alert(result.error);
                return;
            }

            // Fill fields
            getField("identifier").val(result.identifier).prop("readonly", true);
            getField("sequence_number").val(result.sequence_number);

            // Override page name
            $("input[name='pfFormPageName']").val(result.identifier);

            // Override file name on upload
            $("input[type='file']").on("change", function () {
                const file = this.files[0];
                if (!file) return;

                const ext = file.name.split('.').pop();
                const newName = result.identifier + "." + ext;

                $(this).attr("data-filename", newName);
            });
        });
    }

    // Trigger generation when fields change
    getField("chapter_id").change(generateIdentifier);
    getField("place_id").change(generateIdentifier);
    getField("organisation_id").change(generateIdentifier);
});

4. Integration Notes

  • The Lua module must be saved as: Module:DigitalAssetID
  • The JavaScript must be saved as: MediaWiki:DigitalAsset.js
  • The Page Form must load the JS via:
  {{#tag:html|<script src="/wiki/MediaWiki:DigitalAsset.js"></script>|}}
  
  • The identifier and sequence_number fields must exist in the form
  • The identifier field must be editable initially but locked by JS
  • The file upload field must be named file_id

5. Status

This page is a study and preparation document. Implementation will follow after validation and testing.