Modul:AccountUtl

Vorlagenprogrammierung Diskussionen Lua Test Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Dies ist die (produktive) Mutterversion eines global benutzten Lua-Moduls.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Versionsbezeichnung auf WikiData: 2026-04-15

local AccountUtl = { suite  = "AccountUtl",
                     serial = "2026-04-15",
                     item   = 139309150 }
--[=[
Utilities for user accounts.
isAnon()
isIP()
isTemp()
isUser()
isValid()
scope()
signer()
]=]
local Failsafe = AccountUtl



function isIP( account )
    -- Check whether username is matching IPv4 scheme
    -- Precondition:
    --    account  -- string, starting with nonzero digit
    -- Postcondition:
    --    Returns boolean
    local sub  = "([12]?[0-9]?[0-9])"
    local seek = string.format( "^%s%%.%s%%.%s%%.%s$",
                                sub, sub, sub, sub )
    local p1, p2, p3, p4 = account:match( seek )
    if p1 and p2 and p3 and p4 then
        local function legal( a )
                  if a:sub( 1, 1 ):find( "[1-9]" )  and
                     tonumber( a )  <  256 then
                      return true
                  end
              end -- legal()
        r = legal( p1 )  and
            legal( p2 )  and
            legal( p3 )  and
            legal( p4 )
    end
    return r or false
end -- isIP()



function isTemp( account )
    -- Check whether username is matching temporary scheme
    -- Precondition:
    --    account  -- string, starting with "~"
    -- Postcondition:
    --    Returns boolean
    local seek = "^~(20[2-9]%d)%-([1-9]%d%d%d[%d%-]*)$"
    local y, s = account:match( seek )
    if y then
        y = tonumber( y )
        if y >= 2024 then
            local g
            s = s .. "-"
            g = s:match( "^(%d+)%-" )
            if tonumber( g ) >= 1500 then
                if s:match( "^%d+%-$" ) then
                    r = true
                elseif g:len() == 5 then
                    s = s:sub( 7 )
                    g = s:match( "^(%d+)%-" )
                    if g then
                        local n = g:len()
                        if n <= 5 then
                            if s:match( "^%d+%-$" ) then
                                r = true
                            elseif n == 5 then
                                s = s:sub( 7 )
                                if s:match( "^%d+%-$" ) then
                                    r = true
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    return r or false
end -- isTemp()



function isAnon( account )
    -- Check whether username is matching IP or temporary scheme
    -- Precondition:
    --    account  -- string
    -- Postcondition:
    --    Returns boolean
    local s1 = account:sub( 1, 1 )
    local r
    if s1 == "~" then
        r = isTemp( account )
    elseif s1:find( "[1-9]" ) then
        r = isIP( account )
    end
    return r or false
end -- isAnon()



function noIP( account )
    -- Check whether lookalike username is not matching IPv4 scheme
    -- Precondition:
    --    account  -- string, starting with digit
    -- Postcondition:
    --    Returns boolean, if not an IP
    local sub  = "(%d%d?%d?)"
    local seek = string.format( "^%s%%.%s%%.%s%%.%s$",
                                sub, sub, sub, sub )
    local p1, p2, p3, p4 = account:match( seek )
    local r
    if p1 and p2 and p3 and p4 then
        local function lapsus( a )
                  if tonumber( a )  >=  256 then
                      return true
                  end
              end -- lapsus()
        r = lapsus( p1 )  or
            lapsus( p2 )  or
            lapsus( p3 )  or
            lapsus( p4 )
    else
        r = true
    end
    return r
end -- noIP()



function isUser( account )
    -- Check whether username might be any valid account
    -- Precondition:
    --    account  -- string
    -- Postcondition:
    --    Returns boolean
    local r
    if isAnon( account ) then
        r = true
    elseif account:sub( 1, 1 ):find( "%d" ) then
        r = noIP( account )
    elseif account:sub( 1, 2 ) ~= "~2" then
        r = true
    end
    return r or false
end -- isUser()


AccountUtl.isAnon = function ( account )
    -- Check whether username is matching IP or temporary scheme
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns boolean
    local s = AccountUtl.signer( account )
    local r
    if s then
        r = isAnon( s )
    end
    return r or false
end -- AccountUtl.isAnon()



AccountUtl.isIP = function ( account )
    -- Check whether username is matching IPv4 scheme
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns boolean
    local s = AccountUtl.signer( account )
    local r
    if s then
        if s:sub( 1, 1 ):find( "[1-9]" ) then
            r = isIP( s )
        end
    end
    return r or false
end -- AccountUtl.isIP()



AccountUtl.isTemp = function ( account )
    -- Check whether username is matching temporary scheme
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns boolean
    local s = AccountUtl.signer( account )
    local r
    if s then
        if s:sub( 1, 1 )  ==  "~" then
            local seek = "^~(20[2-9]%d)%-([1-9]%d%d%d[%d%-]*)$"
            local y
            y, s = s:match( seek )
            if y then
                y = tonumber( y )
                if y >= 2024 then
                    local g
                    s = s .. "-"
                    g = s:match( "^(%d+)%-" )
                    if tonumber( g ) >= 1500 then
                        if s:match( "^%d+%-$" ) then
                            r = true
                        elseif g:len() == 5 then
                            s = s:sub( 7 )
                            g = s:match( "^(%d+)%-" )
                            if g then
                                local n = g:len()
                                if n <= 5 then
                                    if s:match( "^%d+%-$" ) then
                                        r = true
                                    elseif n == 5 then
                                        s = s:sub( 7 )
                                        if s:match( "^%d+%-$" ) then
                                            r = true
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    return r or false
end -- AccountUtl.isTemp()



AccountUtl.isUser = function ( account )
    -- Check whether username might be any valid account
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns boolean
    local r
    if AccountUtl.signer( account ) then
        r = true
    end
    return r or false
end -- AccountUtl.isUser()



AccountUtl.isValid = function ( account )
    -- Check whether username can be used as nick for registration
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns boolean
    local s = AccountUtl.signer( account )
    local r
    if s then
        if not isAnon( s ) then
            if s:sub( 1, 1 ):find( "%d" ) then
                r = noIP( s )
            else
                r = true
            end
        end
    end
    return r or false
end -- AccountUtl.isValid()



AccountUtl.scope = function ( account )
    -- Identify the type of a presumed account name
    -- Precondition:
    --    account  -- string, or nil derived from current page
    -- Postcondition:
    --    Returns string, or false
    --            "R"  -- registered
    --            "I"  -- IP
    --            "T"  -- temporary
    local s = AccountUtl.signer( account )
    local r
    if s then
        local s1 = s:sub( 1, 1 )
        r = "R"
        if s1 == "~" then
            if isTemp( s ) then
                r = "T"
            elseif s:sub( 2, 2 ) == "2" then
                r = false
            end
        elseif s1:find( "[1-9]" ) then
            if isIP( s ) then
                r = "I"
            elseif noIP( s ) then
                r = false
            end
        end
    end
    return r or false
end -- AccountUtl.scope()



AccountUtl.signer = function ( adjust )
    -- Normalize username string, or derive from page
    -- Precondition:
    --    adjust  -- string, or not
    -- Postcondition:
    --    Returns normalized string of a username, or not
    local r = adjust
    local scan
    if type( r ) == "string" then
        if r:find( "&", 1, true ) then
            r = mw.text.decode( r )
            if r:find( "&#?[%a]+;" ) then
                r = mw.text.decode( r, true )
            end
        end
        scan = string.format( "[_%%s%c]+", 0x0A )
        r    = mw.ustring.gsub( r, scan, " " )
        r    = mw.text.trim( r )
        if r == "" then
            r = false
        elseif r:find( ":", 2, true ) then
            local s1, s2 = mw.ustring.match( r, "^([^:]+):(.+)$" )
            if s1 then
                local o = mw.site.namespaces[ s1 ]
                if o then
                    local n = o.id
                    if n == 2  or  n == 3 then
                        r = mw.text.trim( s2 )
                        n = r:find( "/", 1, true )
                        if n then
                            if n == 1 then
                                r = false
                            else
                                r = mw.text.trim( r:sub( 1,  n - 1 ) )
                            end
                        end
                    end
                end
            end
        end
    end
    if type( r ) == "string" then
        if mw.ustring.len( r )  >  255 then
            r = false
            -- mw:Manual:$wgMaxNameChars   MW 1.2...1.4: 32
        else
            scan = "[@#<>|%[%]%{%}:/]"
            -- mw:Manual:$wgInvalidUsernameCharacters
            if mw.ustring.find( r, scan )  or
               not isUser( r ) then
                r = false
            end
        end
    else
        local t = mw.title.getCurrentTitle()
        if t.namespace == 2  or  t.namespace == 3 then
            r = t.rootText
            if isUser( r ) then
                if mw.ustring.find( r, "@<>:" )  or
                   mw.ustring.len( r )  >  255 then
                    r = false
                end
            else
                r = false
            end
        else
            r = false
        end
    end
    return r
end -- AccountUtl.signer()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version
    --                         or wikidata|item|~|@ or false
    -- Postcondition:
    --     Returns  string  -- with queried version/item, also if problem
    --              false   -- if appropriate
    -- 2024-03-01
    local since  = atleast
    local last   = ( since == "~" )
    local linked = ( since == "@" )
    local link   = ( since == "item" )
    local r
    if last  or  link  or  linked  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local suited = string.format( "Q%d", item )
            if link then
                r = suited
            else
                local entity = mw.wikibase.getEntity( suited )
                if type( entity ) == "table" then
                    local seek = Failsafe.serialProperty or "P348"
                    local vsn  = entity:formatPropertyValues( seek )
                    if type( vsn ) == "table"  and
                       type( vsn.value ) == "string"  and
                       vsn.value ~= "" then
                        if last  and  vsn.value == Failsafe.serial then
                            r = false
                        elseif linked then
                            if mw.title.getCurrentTitle().prefixedText
                               ==  mw.wikibase.getSitelink( suited ) then
                                r = false
                            else
                                r = suited
                            end
                        else
                            r = vsn.value
                        end
                    end
                end
            end
        elseif link then
            r = false
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }

function is( access, frame )
    return AccountUtl[ access ]( frame.args[ 1 ] )  and "1"  or  ""
end -- is()

function p.isAnon( frame )
    return is( "isAnon", frame )
end -- p.isAnon

function p.isIP( frame )
    return is( "isIP", frame )
end -- p.isIP

function p.isTemp( frame )
    return is( "isTemp", frame )
end -- p.isTemp

function p.isUser( frame )
    return is( "isUser", frame )
end -- p.isUser

function p.isValid( frame )
    return is( "isValid", frame )
end -- p.isValid

function p.scope( frame )
    return AccountUtl.scope( frame.args[ 1 ] )
end -- p.scope

function p.signer( frame )
    return AccountUtl.signer( frame.args[ 1 ] )
end -- p.signer

p.failsafe = function ( frame )
    -- Versioning interface
    local s = type( frame )
    local since
    if s == "table" then
        since = frame.args[ 1 ]
    elseif s == "string" then
        since = frame
    end
    if since then
        since = mw.text.trim( since )
        if since == "" then
            since = false
        end
    end
    return Failsafe.failsafe( since )  or  ""
end -- p.failsafe

setmetatable( p,  { __call = function ( func, ... )
                                 setmetatable( p, nil )
                                 return Failsafe
                             end } )

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.